/* * Adds an entry to a unit-to-identifier map. * * Arguments: * map Pointer to unit-to-identifier map. * unit The unit. May be freed upon return. * id The identifier. May be freed upon return. * encoding The ostensible encoding of "id". * Returns: * UT_BAD_ARG "id" is inconsistent with "encoding". * UT_OS Operating-system error. See "errno". * UT_EXISTS "unit" already maps to a different identifier. * UT_SUCCESS Success. */ static ut_status utimAdd( UnitToIdMap* const map, const ut_unit* unit, const char* const id, ut_encoding encoding) { ut_status status; assert(map != NULL); assert(unit != NULL); assert(id != NULL); if (adjustEncoding(&encoding, id)) { status = UT_BAD_ARG; ut_set_status(status); ut_handle_error_message("Identifier not in given encoding"); } else { UnitAndId* targetEntry = uaiNew(unit, id); if (targetEntry != NULL) { void** rootp = selectTree(map, encoding); UnitAndId** treeEntry = tsearch(targetEntry, rootp, compareUnits); if (treeEntry == NULL) { status = UT_OS; ut_set_status(status); ut_handle_error_message(strerror(errno)); ut_handle_error_message("Couldn't add search-tree entry"); uaiFree(targetEntry); } else { if (strcmp((*treeEntry)->id, id) != 0) { status = UT_EXISTS; ut_set_status(status); ut_handle_error_message("Unit already maps to \"%s\"", (*treeEntry)->id); } else { status = UT_SUCCESS; } if (targetEntry != *treeEntry) uaiFree(targetEntry); } } /* "targetEntry" allocated */ } /* valid arguments */ return status; }
/* * Removes an entry from a unit-to-identifier map. * * Arguments: * map Pointer to the unit-to-identifier map. * unit The unit. May be freed upon return. * encoding The encoding to be removed. * Returns: * UT_SUCCESS Success. */ static ut_status utimRemove( UnitToIdMap* const map, const ut_unit* unit, ut_encoding encoding) { ut_status status; UnitAndId targetEntry; UnitAndId** treeEntry; assert(map != NULL); assert(unit != NULL); targetEntry.unit = (ut_unit*)unit; treeEntry = tfind(&targetEntry, selectTree(map, encoding), compareUnits); if (treeEntry == NULL || *treeEntry == NULL) { status = UT_SUCCESS; } else { UnitAndId* uai = *treeEntry; (void)tdelete(uai, selectTree(map, encoding), compareUnits); uaiFree(uai); } return status; }
/* * Adds an entry to an identifier-to-unit map. * * Arguments: * map The database. * id The identifier. May be freed upon return. * unit The unit. May be freed upon return. * Returns: * UT_OS Operating-system error. See "errno". * UT_EXISTS "id" already maps to a different unit. * UT_SUCCESS Success. */ static ut_status itumAdd( IdToUnitMap* map, const char* const id, const ut_unit* const unit) { ut_status status; UnitAndId* targetEntry; assert(map != NULL); assert(id != NULL); assert(unit != NULL); targetEntry = uaiNew(unit, id); if (targetEntry == NULL) { status = ut_get_status(); } else { UnitAndId** treeEntry = tsearch(targetEntry, &map->tree, map->compare); if (treeEntry == NULL) { uaiFree(targetEntry); status = UT_OS; } else { if (ut_compare((*treeEntry)->unit, unit) == 0) { status = UT_SUCCESS; } else { status = UT_EXISTS; ut_set_status(status); ut_handle_error_message( "\"%s\" already maps to existing but different unit", id); } if (targetEntry != *treeEntry) uaiFree(targetEntry); } /* found entry */ } /* "targetEntry" allocated */ return status; }
/* * Finds an entry with a UTF-8 identifier corresponding to a unit. * * Arguments: * map The unit-to-identifier map. * unit The unit to be used as the key in the search. * Returns: * NULL The map doesn't contain an entry corresponding to "unit" whose * identifier is in UTF-8. * else Pointer to the entry corresponding to "unit" whose identifier is * in UTF-8 (and might, actually, be in ASCII). */ static UnitAndId* utimFindUtf8ByUnit( UnitToIdMap* const map, const ut_unit* const unit) { UnitAndId targetEntry; UnitAndId** treeEntry = NULL; /* failure */ targetEntry.unit = (ut_unit*)unit; treeEntry = tfind(&targetEntry, &map->utf8, compareUnits); if (treeEntry == NULL) { treeEntry = tfind(&targetEntry, &map->latin1, compareUnits); if (treeEntry == NULL) { treeEntry = tfind(&targetEntry, &map->ascii, compareUnits); } else { /* * Create the UTF-8 version of the Latin-1 identifier and add it to * the UTF-8 unit-to-id map so that it will be found next time. */ char* const id = latin1ToUtf8((*treeEntry)->id); if (id == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message( "Couldn't convert identifier from ISO-8859-1 to UTF-8"); treeEntry = NULL; } else { UnitAndId* newEntry = uaiNew(unit, id); if (newEntry != NULL) { treeEntry = tsearch(newEntry, &map->utf8, compareUnits); if (treeEntry == NULL) { uaiFree(newEntry); ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message( "Couldn't add unit-and-identifier to search-tree"); } } free(id); } /* UTF-8 identifier created */ } /* found Latin-1 identifier */ } /* no UTF-8 identifier */ return treeEntry == NULL ? NULL : *treeEntry; }
/* * Frees an identifier-to-unit map. All entries are freed. * * Arguments: * map Pointer to the identifier-to-unit map. * Returns: */ static void itumFree( IdToUnitMap* map) { if (map != NULL) { while (map->tree != NULL) { UnitAndId* uai = *(UnitAndId**)map->tree; (void)tdelete(uai, &map->tree, map->compare); uaiFree(uai); } free(map); } /* valid arguments */ }
/* * Frees a unit-to-identifier map. All entries in all encodings are freed. * * Arguments: * map Pointer to the map to be freed. */ static void utimFree( UnitToIdMap* map) { if (map != NULL) { ut_encoding encodings[] = {UT_ASCII, UT_LATIN1, UT_UTF8}; int i; for (i = 0; i < sizeof(encodings)/sizeof(encodings[0]); ++i) { void** rootp = selectTree(map, encodings[i]); while (*rootp != NULL) { UnitAndId* uai = **(UnitAndId***)rootp; (void)tdelete(uai, rootp, compareUnits); uaiFree(uai); } } free(map); } }
/* * Removes an entry to an identifier-to-unit map. * * Arguments: * map The database. * id The identifier. May be freed upon return. * Returns: * UT_SUCCESS Success. */ static ut_status itumRemove( IdToUnitMap* map, const char* const id) { UnitAndId targetEntry; UnitAndId** treeEntry; assert(map != NULL); assert(id != NULL); targetEntry.id = (char*)id; treeEntry = tfind(&targetEntry, &map->tree, map->compare); if (treeEntry != NULL) { UnitAndId* uai = *treeEntry; (void)tdelete(uai, &map->tree, map->compare); uaiFree(uai); } return UT_SUCCESS; }