#include "uthash.h" #include "namespace.h" typedef struct namespace_t { ns_pfx pfx; // Namespace prefix. char * ns; // Fully qualified NS. UT_hash_handle hh; // UTHash handle. } Namespace; typedef struct namespace_index_t { Namespace * ns; // Pointer to a NS struct. UT_hash_handle hh; // UTHash handle. } NSIndex; typedef struct ns_map_t { Namespace * pn; // Prefix to namespace. NSIndex * np; // Namespace to prefix. } NSMap; NSMap * LSUP_nsmap_new (void) { NSMap *map; CALLOC_GUARD (map, NULL); return map; } void LSUP_nsmap_free (NSMap *map) { if (UNLIKELY (!map)) return; Namespace *entry, *tmp; HASH_ITER (hh, map->pn, entry, tmp) { HASH_DEL (map->pn, entry); free (entry->ns); free (entry); } NSIndex *idx_entry, *idx_tmp; HASH_ITER (hh, map->np, idx_entry, idx_tmp) { HASH_DEL (map->np, idx_entry); free (idx_entry); } free (map); } LSUP_rc LSUP_nsmap_add (NSMap *map, const ns_pfx pfx, const char *nsstr) { // Main entry (pn) // Delete any found record. // Main and index are deleted independently because the pair may be // different. Namespace *entry = NULL; HASH_FIND_STR (map->pn, pfx, entry); if (entry) { HASH_DEL (map->pn, entry); free (entry->ns); free (entry); } // Add. MALLOC_GUARD (entry, LSUP_MEM_ERR); entry->ns = strdup (nsstr); strcpy (entry->pfx, pfx); HASH_ADD_STR (map->pn, pfx, entry); // Index. // Delete any found record. NSIndex *idx_entry = NULL; HASH_FIND_STR (map->np, nsstr, idx_entry); if (idx_entry) { HASH_DEL (map->np, idx_entry); free (idx_entry); } // Add. MALLOC_GUARD (idx_entry, LSUP_MEM_ERR); //idx_entry = malloc (sizeof (*idx_entry)); //if (UNLIKELY (!entry)) return LSUP_MEM_ERR; idx_entry->ns = entry; HASH_ADD_KEYPTR (hh, map->np, entry->ns, strlen (nsstr), idx_entry); return LSUP_OK; } LSUP_rc LSUP_nsmap_remove (NSMap *map, const ns_pfx pfx) { Namespace *entry = NULL; NSIndex *idx_entry = NULL; HASH_FIND_STR (map->pn, pfx, entry); if (entry) { HASH_FIND_STR (map->np, entry->ns, idx_entry); if (idx_entry) { HASH_DEL (map->np, idx_entry); free (idx_entry); } HASH_DEL (map->pn, entry); free (entry->ns); free (entry); return LSUP_OK; } return LSUP_NOACTION; } const char * LSUP_nsmap_get (const NSMap *map, const ns_pfx pfx) { Namespace *entry = NULL; HASH_FIND_STR (map->pn, pfx, entry); return (entry) ? entry->ns : NULL; } LSUP_rc LSUP_nsmap_normalize_uri ( const NSMap *map, const char *pfx_uri, char **fq_uri_p) { char *fq_uri = NULL; size_t pfx_len = strcspn (pfx_uri, ":"); if (pfx_len >= PFX_LEN) pfx_len = PFX_LEN - 1; ns_pfx pfx; strncpy (pfx, pfx_uri, pfx_len); pfx[pfx_len] = 0; Namespace *entry; for (entry = map->pn; entry != NULL; entry = entry->hh.next) { if (strncmp (entry->pfx, pfx_uri, strlen (entry->pfx)) == 0) break; } if (entry) { // -1 for :, +1 for terminator. size_t fq_size = strlen (entry->ns) + strlen (pfx_uri) - pfx_len; fq_uri = malloc (fq_size); if (UNLIKELY (! (fq_uri))) return LSUP_MEM_ERR; strcpy (fq_uri, entry->ns); strcat (fq_uri, pfx_uri + pfx_len + 1); } else fq_uri = strdup (pfx_uri); *fq_uri_p = fq_uri; return LSUP_OK; } LSUP_rc LSUP_nsmap_denormalize_uri ( const NSMap *map, const char *fq_uri, char **pfx_uri_p) { char *pfx_uri = NULL; NSIndex *entry; for (entry = map->np; entry != NULL; entry = entry->hh.next) { if (memcmp (entry->ns->ns, fq_uri, strlen (entry->ns->ns)) == 0) break; } if (entry) { pfx_uri = malloc ( strlen (entry->ns->pfx) + strlen (fq_uri) - strlen (entry->ns->ns) + 2); // one for terminating \x00, one for the colon. if (UNLIKELY (! (pfx_uri))) return LSUP_MEM_ERR; sprintf ( pfx_uri, "%s:%s", entry->ns->pfx, fq_uri + strlen (entry->ns->ns)); } else pfx_uri = strdup (fq_uri); *pfx_uri_p = pfx_uri; return LSUP_OK; } const char *** LSUP_nsmap_dump (const NSMap *map) { size_t i = 0; Namespace *cur; for (cur = map->pn; cur != NULL; cur = cur->hh.next) i++; const char ***data = malloc (2 * (i + 1) * sizeof (char *)); if (UNLIKELY (!data)) return NULL; for (size_t j = 0; j < i; j++) { data[j] = malloc (2 * sizeof (char *)); if (UNLIKELY (!data[j])) return NULL; } i = 0; for (cur = map->pn; cur != NULL; cur = cur->hh.next) { data[i][0] = (const char *)cur->pfx; data[i++][1] = (const char *)cur->ns; } data[i] = NULL; // Sentinel return data; }