/* * Returns the unit to which an identifier maps in a particular unit-system. * * Arguments: * systemMap NULL or pointer to the system-map. If NULL, then * NULL will be returned. * system Pointer to the unit-system. * id Pointer to the identifier. * Returns: * NULL Failure. "ut_get_status()" will be: * UT_BAD_ARG "system" is NULL or "id" is NULL. * else Pointer to the unit in "system" with the identifier "id". * Should be passed to ut_free() when no longer needed. */ static ut_unit* getUnitById( const SystemMap* const systemMap, const ut_system* const system, const char* const id) { ut_unit* unit = NULL; /* failure */ if (system == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("getUnitById(): NULL unit-system argument"); } else if (id == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("getUnitById(): NULL identifier argument"); } else if (systemMap != NULL) { IdToUnitMap** const idToUnit = (IdToUnitMap**)smFind(systemMap, system); if (idToUnit != NULL) { const UnitAndId* uai = itumFind(*idToUnit, id); if (uai != NULL) unit = ut_clone(uai->unit); } } /* valid arguments */ return unit; }
/* * 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; }
/* * 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; }
/* * Returns the identifier in a given encoding to which a unit associated with * a unit-system maps. * * Arguments: * systemMap Pointer to the system-to-unit-to-id map. * unit Pointer to the unit whose identifier should be returned. * encoding The desired encoding of the identifier. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "unit" was NULL. * else Pointer to the identifier in the given encoding * associated with "unit". */ static const char* getId( SystemMap* const systemMap, const ut_unit* const unit, const ut_encoding encoding) { const char* id = NULL; /* failure */ if (unit == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("NULL unit argument"); } else { UnitToIdMap** const unitToId = (UnitToIdMap**)smFind(systemMap, ut_get_system(unit)); if (unitToId != NULL) { UnitAndId* mapEntry = encoding == UT_LATIN1 ? utimFindLatin1ByUnit(*unitToId, unit) : encoding == UT_UTF8 ? utimFindUtf8ByUnit(*unitToId, unit) : utimFindAsciiByUnit(*unitToId, unit); if (mapEntry != NULL) id = mapEntry->id; } } return id; }
/* * Arguments: * unit The unit. May be freed upon return. * id The identifier (name or symbol). May be freed upon return. * Returns: * NULL Failure. "ut_get_status()" will be * UT_BAD_ARG "unit" or "id" is NULL. * UT_OS Operating-system failure. See "errno". * else Pointer to the new unit-and-identifier. */ UnitAndId* uaiNew( const ut_unit* const unit, const char* const id) { UnitAndId* entry = NULL; /* failure */ if (id == NULL || unit == NULL) { ut_set_status(UT_BAD_ARG); ut_handle_error_message("uaiNew(): NULL argument"); } else { entry = malloc(sizeof(UnitAndId)); if (entry == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("Couldn't allocate %lu-byte data-structure", sizeof(UnitAndId)); } else { entry->id = strdup(id); if (entry->id == NULL) { ut_set_status(UT_OS); ut_handle_error_message(strerror(errno)); ut_handle_error_message("Couldn't duplicate identifier"); } else { entry->unit = ut_clone(unit); if (entry->unit == NULL) { assert(ut_get_status() != UT_SUCCESS); free(entry->id); } } if (ut_get_status() != UT_SUCCESS) { free(entry); entry = NULL; } } } return entry; }
/* * 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; }
void R_ut_init(const int *print_warning_on_failure) { ut_status stat; ut_set_error_message_handler((ut_error_message_handler) Rvprintf); if (sys != NULL) { ut_free_system(sys); } ut_set_error_message_handler(ut_ignore); sys = ut_read_xml(NULL); ut_set_error_message_handler((ut_error_message_handler) Rvprintf); if (sys == NULL) { stat = ut_get_status(); if (*print_warning_on_failure) ut_handle_error_message("Warning in R_ut_init: %s\n", ut_status_strings[stat]); return; } enc = UT_UTF8; return; }