"Fossies" - the Fresh Open Source Software Archive

Member "udunits-2.2.28/lib/unitToIdMap.c" (7 Dec 2020, 19599 Bytes) of package /linux/privat/udunits-2.2.28.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "unitToIdMap.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.2.26_vs_2.2.28.

    1 /*
    2  * Copyright 2020 University Corporation for Atmospheric Research
    3  *
    4  * This file is part of the UDUNITS-2 package.  See the file COPYRIGHT
    5  * in the top-level source-directory of the package for copying and
    6  * redistribution conditions.
    7  */
    8 /*
    9  * Unit-to-identifier map.
   10  */
   11 
   12 /*LINTLIBRARY*/
   13 
   14 #include "config.h"
   15 
   16 #include "udunits2.h"
   17 #include "unitAndId.h"
   18 #include "unitToIdMap.h"        /* this module's API */
   19 #include "systemMap.h"
   20 
   21 #include <assert.h>
   22 #include <errno.h>
   23 
   24 #ifdef _MSC_VER
   25 #include "tsearch.h"
   26 #else
   27 #include <search.h>
   28 #endif
   29 
   30 #include <stdlib.h>
   31 
   32 #include <string.h>
   33 
   34 typedef struct {
   35     void*       ascii;
   36     void*       latin1;
   37     void*       utf8;
   38 } UnitToIdMap;
   39 
   40 static SystemMap*   systemToUnitToName = NULL;
   41 static SystemMap*   systemToUnitToSymbol = NULL;
   42 
   43 
   44 /******************************************************************************
   45  * Miscellaneous Functions:
   46  ******************************************************************************/
   47 
   48 /*
   49  * Unconditionally converts an ISO Latin-1 string into a UTF-8 string.
   50  *
   51  * Arguments:
   52  *  latin1String    Pointer to the ISO Latin-1 string.
   53  * Returns:
   54  *  NULL        Failure.  See errno.
   55  *  else        Pointer to the equivalent UTF-8 string.  Should be freed
   56  *          when no longer needed.
   57  */
   58 static char*
   59 latin1ToUtf8(
   60     const char* const   latin1String)
   61 {
   62     int         nchar;
   63     const char*     inp;
   64     char*       outp;
   65     char*       utf8String;
   66 
   67     for (nchar = 0, inp = latin1String; *inp; ++inp, ++nchar)
   68     if ((*inp & 0x80U) != 0)
   69         nchar++;
   70 
   71     utf8String = malloc(nchar+1);
   72 
   73     if (utf8String != NULL) {
   74     for (inp = latin1String, outp = utf8String; *inp; ++inp, ++outp) {
   75         if ((*inp & 0x80U) == 0) {
   76         *outp = *inp;
   77         }
   78         else {
   79         *outp++ = (char)(0xC0U | ((unsigned)*inp >> 6));
   80         *outp = (char)(0x80U | (*inp & 0x3FU));
   81         }
   82     }
   83 
   84     *outp = 0;
   85     }
   86 
   87     return utf8String;
   88 }
   89 
   90 /*
   91  * Adjust a given encoding according to a string.  Because ASCII is a subset of
   92  * ISO Latin-1 and because a UTF-8 encoded string must follow certain rules,
   93  * it's possible for strings to be mis-encoded and for an encoding specification
   94  * to be too restrictive or over-generous.  If the encoding specification is
   95  * ASCII and the given string contains a character with the high-order bit
   96  * set, then the encoding will be changed to ISO Latin-1.  If the encoding
   97  * specification is ISO Latin-1 but the string doesn't contain a character with
   98  * the high-order bit set, then the encoding will be changed to ASCII.  If the
   99  * encoding specification is UTF-8 but the string doesn't follow the UTF-8
  100  * encoding rules, then the function will error-return.
  101  *
  102  * Arguments:
  103  *  encoding    Pointer to the presumptive encoding.  Might be modified
  104  *          on return to reflect the actual, most restrictive,
  105  *          encoding of "string".
  106  *  string      The string to be checked.
  107  * Returns:
  108  *  0       Success.  "*encoding" might be modified.
  109  *  -1      Failure.  "string" doesn't conform to "encoding".
  110  */
  111 static int
  112 adjustEncoding(
  113     ut_encoding* const  encoding,
  114     const char*     string)
  115 {
  116     int     status = 0;     /* success */
  117 
  118     if (*encoding == UT_ASCII) {
  119     for (; *string && ((*string & 0x80U) == 0); string++)
  120         ;
  121 
  122     if (*string != 0)
  123         *encoding = UT_LATIN1;
  124     }
  125     else if (*encoding == UT_LATIN1) {
  126     for (; *string && ((*string & 0x80U) == 0); string++)
  127         ;
  128 
  129     if (*string == 0)
  130         *encoding = UT_ASCII;
  131     }
  132     else if (*encoding == UT_UTF8) {
  133     for (; *string; string++) {
  134         if (*string & 0x80U) {
  135         if ((*string & 0xE0U) == 0xC0U) {
  136             if ((*++string & 0xC0U) != 0x80U)
  137             break;
  138         }
  139         else if ((*string & 0xF0U) == 0xE0U) {
  140             if ((*++string & 0xC0U) != 0x80U)
  141             break;
  142             if ((*++string & 0xC0U) != 0x80U)
  143             break;
  144         }
  145         else if ((*string & 0xF8U) == 0xF0U) {
  146             if ((*++string & 0xC0U) != 0x80U)
  147             break;
  148             if ((*++string & 0xC0U) != 0x80U)
  149             break;
  150             if ((*++string & 0xC0U) != 0x80U)
  151             break;
  152         }
  153         }
  154     }
  155 
  156     if (*string)
  157         status = -1;
  158     }
  159 
  160     return status;
  161 }
  162 
  163 
  164 /******************************************************************************
  165  * Internal Map Functions:
  166  ******************************************************************************/
  167 
  168 static int
  169 compareUnits(
  170     const void* const   entry1,
  171     const void* const   entry2)
  172 {
  173     return ut_compare(((const UnitAndId*)entry1)->unit,
  174     ((const UnitAndId*)entry2)->unit);
  175 }
  176 
  177 
  178 /*
  179  * Selects a unit-and-identifier tree corresponding to a given encoding.
  180  *
  181  * Arguments:
  182  *  map     The unit-to-id map.
  183  *  encoding    The encoding.
  184  * Returns:
  185  *  Pointer to the root of the unit-and-identifier tree in "map" that
  186  *  corresponds to "encoding".
  187  */
  188 static void**
  189 selectTree(
  190     UnitToIdMap* const  unitToIdMap,
  191     const ut_encoding   encoding)
  192 {
  193     return
  194     encoding == UT_ASCII
  195         ? &unitToIdMap->ascii
  196         : encoding == UT_LATIN1
  197         ? &unitToIdMap->latin1
  198         : &unitToIdMap->utf8;
  199 }
  200 
  201 
  202 /*
  203  * Returns a new instance of a unit-to-identifier map.
  204  *
  205  * Returns:
  206  *  NULL    Failure.  See "errno".
  207  *  else    Pointer to a new unit-to-identifier map.
  208  */
  209 static UnitToIdMap*
  210 utimNew(void)
  211 {
  212     UnitToIdMap* const  map = malloc(sizeof(UnitToIdMap));
  213 
  214     if (map != NULL) {
  215     map->ascii = NULL;
  216     map->latin1 = NULL;
  217     map->utf8 = NULL;
  218     }
  219 
  220     return map;
  221 }
  222 
  223 
  224 /*
  225  * Frees a unit-to-identifier map.  All entries in all encodings are freed.
  226  *
  227  * Arguments:
  228  *  map     Pointer to the map to be freed.
  229  */
  230 static void
  231 utimFree(
  232     UnitToIdMap*    map)
  233 {
  234     if (map != NULL) {
  235     ut_encoding encodings[] = {UT_ASCII, UT_LATIN1, UT_UTF8};
  236     int     i;
  237 
  238     for (i = 0; i < sizeof(encodings)/sizeof(encodings[0]); ++i) {
  239         void**  rootp = selectTree(map, encodings[i]);
  240 
  241         while (*rootp != NULL) {
  242         UnitAndId*  uai = **(UnitAndId***)rootp;
  243 
  244         (void)tdelete(uai, rootp, compareUnits);
  245         uaiFree(uai);
  246         }
  247     }
  248 
  249     free(map);
  250     }
  251 }
  252 
  253 
  254 /*
  255  * Adds an entry to a unit-to-identifier map.
  256  *
  257  * Arguments:
  258  *  map     Pointer to unit-to-identifier map.
  259  *  unit        The unit.  May be freed upon return.
  260  *  id      The identifier.  May be freed upon return.
  261  *  encoding    The ostensible encoding of "id".
  262  * Returns:
  263  *  UT_BAD_ARG  "id" is inconsistent with "encoding".
  264  *  UT_OS       Operating-system error.  See "errno".
  265  *  UT_EXISTS   "unit" already maps to a different identifier.
  266  *  UT_SUCCESS  Success.
  267  */
  268 static ut_status
  269 utimAdd(
  270     UnitToIdMap* const  map,
  271     const ut_unit*  unit,
  272     const char* const   id,
  273     ut_encoding     encoding)
  274 {
  275     ut_status       status;
  276 
  277     assert(map != NULL);
  278     assert(unit != NULL);
  279     assert(id != NULL);
  280 
  281     if (adjustEncoding(&encoding, id)) {
  282     status = UT_BAD_ARG;
  283         ut_set_status(status);
  284     ut_handle_error_message("Identifier not in given encoding");
  285     }
  286     else {
  287     UnitAndId*  targetEntry = uaiNew(unit, id);
  288 
  289     if (targetEntry == NULL) {
  290             status = ut_get_status();
  291         }
  292         else {
  293         void**  rootp = selectTree(map, encoding);
  294 
  295         UnitAndId** treeEntry = tsearch(targetEntry, rootp, compareUnits);
  296 
  297         if (treeEntry == NULL) {
  298         status = UT_OS;
  299                 ut_set_status(status);
  300         ut_handle_error_message(strerror(errno));
  301         ut_handle_error_message("Couldn't add search-tree entry");
  302         uaiFree(targetEntry);
  303         }
  304         else {
  305         if (strcmp((*treeEntry)->id, id) != 0) {
  306             status = UT_EXISTS;
  307                     ut_set_status(status);
  308             ut_handle_error_message("Unit already maps to \"%s\"",
  309             (*treeEntry)->id);
  310         }
  311         else {
  312             status = UT_SUCCESS;
  313         }
  314 
  315                 if (targetEntry != *treeEntry)
  316                     uaiFree(targetEntry);
  317         }
  318     }               /* "targetEntry" allocated */
  319     }                   /* valid arguments */
  320 
  321     return status;
  322 }
  323 
  324 
  325 /*
  326  * Removes an entry from a unit-to-identifier map.
  327  *
  328  * Arguments:
  329  *  map     Pointer to the unit-to-identifier map.
  330  *  unit        The unit.  May be freed upon return.
  331  *  encoding    The encoding to be removed.
  332  * Returns:
  333  *  UT_SUCCESS  Success.
  334  */
  335 static ut_status
  336 utimRemove(
  337     UnitToIdMap* const  map,
  338     const ut_unit*  unit,
  339     ut_encoding     encoding)
  340 {
  341     UnitAndId       targetEntry;
  342     UnitAndId**     treeEntry;
  343 
  344     assert(map != NULL);
  345     assert(unit != NULL);
  346 
  347     targetEntry.unit = (ut_unit*)unit;
  348     treeEntry = tfind(&targetEntry, selectTree(map, encoding), compareUnits);
  349 
  350     if (treeEntry != NULL && *treeEntry != NULL) {
  351     UnitAndId*  uai = *treeEntry;
  352 
  353     (void)tdelete(uai, selectTree(map, encoding), compareUnits);
  354     uaiFree(uai);
  355     }
  356 
  357     return UT_SUCCESS;
  358 }
  359 
  360 
  361 /*
  362  * Returns the unit-and-identifier whose ASCII identifier corresponding to a
  363  * unit.
  364  *
  365  * Arguments:
  366  *  map The unit-to-identifier map.
  367  *  unit    The unit to be used as the key in the search.
  368  * Returns:
  369  *  NULL    The map doesn't contain an entry corresponding to "unit" whose
  370  *      identifier is in ASCII.
  371  *  else    Pointer to the entry corresponding to "unit" whose identifier is
  372  *      in ASCII.
  373  */
  374 static UnitAndId*
  375 utimFindAsciiByUnit(
  376     UnitToIdMap* const  map,
  377     const ut_unit* const    unit)
  378 {
  379     UnitAndId   targetEntry;
  380     UnitAndId** treeEntry;
  381 
  382     targetEntry.unit = (ut_unit*)unit;
  383     treeEntry = tfind(&targetEntry, &map->ascii, compareUnits);
  384 
  385     return treeEntry == NULL ? NULL : *treeEntry;
  386 }
  387 
  388 
  389 /*
  390  * Finds a unit-search-entry with a Latin-1 identifier correcponding to a unit.
  391  *
  392  * Arguments:
  393  *  map The unit-to-identifier map.
  394  *  unit    The unit to be used as the key in the search.
  395  * Returns:
  396  *  NULL    The map doesn't contain an entry corresponding to "unit" whose
  397  *      identifier is in Latin-1.
  398  *  else    Pointer to the entry corresponding to "unit" whose identifier is
  399  *      in Latin-1 (and might, actually, be in ASCII).
  400  */
  401 static UnitAndId*
  402 utimFindLatin1ByUnit(
  403     UnitToIdMap* const  map,
  404     const ut_unit* const    unit)
  405 {
  406     UnitAndId   targetEntry;
  407     UnitAndId** treeEntry;
  408 
  409     targetEntry.unit = (ut_unit*)unit;
  410     treeEntry = tfind(&targetEntry, &map->latin1, compareUnits);
  411 
  412     if (treeEntry == NULL)
  413     treeEntry = tfind(&targetEntry, &map->ascii, compareUnits);
  414 
  415     return treeEntry == NULL ? NULL : *treeEntry;
  416 }
  417 
  418 
  419 /*
  420  * Finds an entry with a UTF-8 identifier corresponding to a unit.
  421  *
  422  * Arguments:
  423  *  map The unit-to-identifier map.
  424  *  unit    The unit to be used as the key in the search.
  425  * Returns:
  426  *  NULL    The map doesn't contain an entry corresponding to "unit" whose
  427  *      identifier is in UTF-8.
  428  *  else    Pointer to the entry corresponding to "unit" whose identifier is
  429  *      in UTF-8 (and might, actually, be in ASCII).
  430  */
  431 static UnitAndId*
  432 utimFindUtf8ByUnit(
  433     UnitToIdMap* const          map,
  434     const ut_unit* const    unit)
  435 {
  436     UnitAndId   targetEntry;
  437     UnitAndId** treeEntry = NULL;   /* failure */
  438 
  439     targetEntry.unit = (ut_unit*)unit;
  440     treeEntry = tfind(&targetEntry, &map->utf8, compareUnits);
  441 
  442     if (treeEntry == NULL) {
  443     treeEntry = tfind(&targetEntry, &map->latin1, compareUnits);
  444 
  445     if (treeEntry == NULL) {
  446         treeEntry = tfind(&targetEntry, &map->ascii, compareUnits);
  447     }
  448     else {
  449         /*
  450          * Create the UTF-8 version of the Latin-1 identifier and add it to
  451          * the UTF-8 unit-to-id map so that it will be found next time.
  452          */
  453         char* const id = latin1ToUtf8((*treeEntry)->id);
  454 
  455         if (id == NULL) {
  456         ut_set_status(UT_OS);
  457         ut_handle_error_message(strerror(errno));
  458         ut_handle_error_message(
  459             "Couldn't convert identifier from ISO-8859-1 to UTF-8");
  460         treeEntry = NULL;
  461         }
  462         else {
  463         UnitAndId*  newEntry = uaiNew(unit, id);
  464 
  465         if (newEntry != NULL) {
  466             treeEntry = tsearch(newEntry, &map->utf8, compareUnits);
  467 
  468             if (treeEntry == NULL) {
  469             uaiFree(newEntry);
  470             ut_set_status(UT_OS);
  471             ut_handle_error_message(strerror(errno));
  472             ut_handle_error_message(
  473                             "Couldn't add unit-and-identifier to search-tree");
  474             }
  475         }
  476 
  477         free(id);
  478         }               /* UTF-8 identifier created */
  479     }               /* found Latin-1 identifier */
  480     }                   /* no UTF-8 identifier */
  481 
  482     return treeEntry == NULL ? NULL : *treeEntry;
  483 }
  484 
  485 
  486 /*
  487  * Adds an entry to the unit-to-identifier map associated with a unit-system.
  488  *
  489  * Arguments:
  490  *  sytemMap    Address of the pointer to the
  491  *          system-to-unit-to-identifier map.
  492  *  unit        The unit.  May be freed upon return.
  493  *  id      The identifier.  May be freed upon return.
  494  *  encoding    The ostensible encoding of "id".
  495  * Returns:
  496  *  UT_BAD_ARG  "unit" or "id" is NULL, or "id" is inconsistent with
  497  *                      "encoding".
  498  *  UT_OS       Operating-system error.  See "errno".
  499  *  UT_EXISTS   "unit" already maps to a different identifier.
  500  *  UT_SUCCESS  Success.
  501  */
  502 static ut_status
  503 mapUnitToId(
  504     SystemMap** const       systemMap,
  505     const ut_unit* const    unit,
  506     const char* const       id,
  507     ut_encoding         encoding)
  508 {
  509     ut_status       status;
  510 
  511     assert(systemMap != NULL);
  512 
  513     if (unit == NULL || id == NULL) {
  514     status = UT_BAD_ARG;
  515     }
  516     else {
  517     if (*systemMap == NULL) {
  518         *systemMap = smNew();
  519 
  520         if (*systemMap == NULL)
  521         status = UT_OS;
  522     }
  523 
  524     if (*systemMap != NULL) {
  525         UnitToIdMap** const unitToIdMap =
  526         (UnitToIdMap**)smSearch(*systemMap, ut_get_system(unit));
  527 
  528         if (unitToIdMap == NULL) {
  529         status = UT_OS;
  530         }
  531         else {
  532         if (*unitToIdMap == NULL) {
  533             *unitToIdMap = utimNew();
  534 
  535             if (*unitToIdMap == NULL)
  536             status = UT_OS;
  537         }
  538 
  539         if (*unitToIdMap != NULL)
  540             status = utimAdd(*unitToIdMap, unit, id, encoding);
  541         }
  542     }
  543     }
  544 
  545     return status;
  546 }
  547 
  548 
  549 /*
  550  * Removes an entry from the unit-to-identifier map associated with a
  551  * unit-system.
  552  *
  553  * Arguments:
  554  *  sytemMap    Pointer to the system-to-unit-to-identifier map.
  555  *  unit        The unit.  May be freed upon return.
  556  *  encoding    The ostensible encoding of "id".
  557  * Returns:
  558  *  UT_BAD_ARG  "systemMap" is NULL.
  559  *  UT_BAD_ARG  "unit" is NULL.
  560  *  UT_SUCCESS  Success.
  561  */
  562 static ut_status
  563 unmapUnitToId(
  564     SystemMap* const        systemMap,
  565     const ut_unit* const    unit,
  566     ut_encoding         encoding)
  567 {
  568     ut_status       status;
  569 
  570     if (systemMap == NULL || unit == NULL) {
  571     status = UT_BAD_ARG;
  572     }
  573     else {
  574     UnitToIdMap** const unitToIdMap =
  575         (UnitToIdMap**)smFind(systemMap, ut_get_system(unit));
  576 
  577     status =
  578         (unitToIdMap == NULL || *unitToIdMap == NULL)
  579         ? UT_SUCCESS
  580         : utimRemove(*unitToIdMap, unit, encoding);
  581     }
  582 
  583     return status;
  584 }
  585 
  586 
  587 /*
  588  * Returns the identifier in a given encoding to which a unit associated with
  589  * a unit-system maps.
  590  *
  591  * Arguments:
  592  *  systemMap   Pointer to the system-to-unit-to-id map.
  593  *  unit        Pointer to the unit whose identifier should be returned.
  594  *  encoding    The desired encoding of the identifier.
  595  * Returns:
  596  *  NULL        Failure.  "ut_get_status()" will be
  597  *              UT_BAD_ARG  "unit" was NULL.
  598  *  else        Pointer to the identifier in the given encoding
  599  *          associated with "unit".
  600  */
  601 static const char*
  602 getId(
  603     SystemMap* const    systemMap,
  604     const ut_unit* const    unit,
  605     const ut_encoding   encoding)
  606 {
  607     const char* id = NULL;      /* failure */
  608 
  609     if (unit == NULL) {
  610     ut_set_status(UT_BAD_ARG);
  611     ut_handle_error_message("NULL unit argument");
  612     }
  613     else {
  614     UnitToIdMap** const unitToId =
  615         (UnitToIdMap**)smFind(systemMap, ut_get_system(unit));
  616 
  617     if (unitToId != NULL) {
  618         UnitAndId*  mapEntry =
  619         encoding == UT_LATIN1
  620             ? utimFindLatin1ByUnit(*unitToId, unit)
  621             : encoding == UT_UTF8
  622             ? utimFindUtf8ByUnit(*unitToId, unit)
  623             : utimFindAsciiByUnit(*unitToId, unit);
  624 
  625         if (mapEntry != NULL)
  626         id = mapEntry->id;
  627     }
  628     }
  629 
  630     return id;
  631 }
  632 
  633 
  634 /******************************************************************************
  635  * Public API:
  636  ******************************************************************************/
  637 
  638 
  639 /*
  640  * Adds a mapping from a unit to a name.
  641  *
  642  * Arguments:
  643  *  unit        Pointer to the unit to be mapped to "name".  May be
  644  *          freed upon return.
  645  *  name        Pointer to the name to be mapped-to by "unit".  May be
  646  *          freed upon return.
  647  *  encoding    The encoding of "name".
  648  * Returns:
  649  *  UT_SUCCESS  Success.
  650  *  UT_BAD_ARG  "unit" or "name" is NULL, or "name" is not in the
  651  *                      specified encoding.
  652  *  UT_OS       Operating-system error.  See "errno".
  653  *  UT_EXISTS   "unit" already maps to a name.
  654  */
  655 ut_status
  656 ut_map_unit_to_name(
  657     const ut_unit* const    unit,
  658     const char* const       name,
  659     ut_encoding         encoding)
  660 {
  661     ut_set_status(mapUnitToId(&systemToUnitToName, unit, name, encoding));
  662 
  663     return ut_get_status();
  664 }
  665 
  666 
  667 /*
  668  * Removes a mapping from a unit to a name.
  669  *
  670  * Arguments:
  671  *  unit        Pointer to the unit.  May be freed upon return.
  672  *  encoding    The encoding to be removed.  No other encodings will be
  673  *          removed.
  674  * Returns:
  675  *  UT_BAD_ARG  "unit" is NULL.
  676  *  UT_SUCCESS  Success.
  677  */
  678 ut_status
  679 ut_unmap_unit_to_name(
  680     const ut_unit* const    unit,
  681     ut_encoding         encoding)
  682 {
  683     ut_set_status(unmapUnitToId(systemToUnitToName, unit, encoding));
  684 
  685     return ut_get_status();
  686 }
  687 
  688 
  689 /*
  690  * Adds a mapping from a unit to a symbol.
  691  *
  692  * Arguments:
  693  *  unit        Pointer to the unit to be mapped to "symbol".  May be
  694  *          freed upon return.
  695  *  symbol      Pointer to the symbol to be mapped-to by "unit".  May
  696  *          be freed upon return.
  697  *  encoding    The encoding of "symbol".
  698  * Returns:
  699  *  UT_SUCCESS  Success.
  700  *  UT_BAD_ARG  "unit" or "symbol" is NULL.
  701  *  UT_OS       Operating-system error.  See "errno".
  702  *  UT_EXISTS   "unit" already maps to a symbol.
  703  */
  704 ut_status
  705 ut_map_unit_to_symbol(
  706     const ut_unit*      unit,
  707     const char* const       symbol,
  708     ut_encoding         encoding)
  709 {
  710     ut_set_status(mapUnitToId(&systemToUnitToSymbol, unit, symbol, encoding));
  711 
  712     return ut_get_status();
  713 }
  714 
  715 
  716 /*
  717  * Removes a mapping from a unit to a symbol.
  718  *
  719  * Arguments:
  720  *  unit        Pointer to the unit to be unmapped to a symbol.  May be
  721  *          freed upon return.
  722  *  encoding    The encoding to be removed.  The mappings for "unit" in
  723  *          other encodings will not be removed.
  724  * Returns:
  725  *  UT_SUCCESS  Success.
  726  *  UT_BAD_ARG  "unit" is NULL.
  727  */
  728 ut_status
  729 ut_unmap_unit_to_symbol(
  730     const ut_unit* const    unit,
  731     ut_encoding         encoding)
  732 {
  733     ut_set_status(unmapUnitToId(systemToUnitToSymbol, unit, encoding));
  734 
  735     return ut_get_status();
  736 }
  737 
  738 
  739 /*
  740  * Returns the name in a given encoding to which a unit maps.
  741  *
  742  * Arguments:
  743  *  unit        Pointer to the unit whose name should be returned.
  744  *  encoding    The desired encoding of the name.
  745  * Returns:
  746  *  NULL        Failure.  "ut_get_status()" will be
  747  *              UT_BAD_ARG      "unit" is NULL.
  748  *              UT_SUCCESS      "unit" doesn't map to a name in
  749  *                      in the given encoding.
  750  *  else        Pointer to the name in the given encoding to which
  751  *          "unit" maps.
  752  */
  753 const char*
  754 ut_get_name(
  755     const ut_unit* const    unit,
  756     const ut_encoding   encoding)
  757 {
  758     ut_set_status(UT_SUCCESS);
  759 
  760     return getId(systemToUnitToName, unit, encoding);
  761 }
  762 
  763 
  764 /*
  765  * Returns the symbol in a given encoding to which a unit maps.
  766  *
  767  * Arguments:
  768  *  unit        Pointer to the unit whose symbol should be returned.
  769  *  encoding    The desired encoding of the symbol.
  770  * Returns:
  771  *  NULL        Failure.  "ut_get_status()" will be
  772  *              UT_BAD_ARG      "unit" is NULL.
  773  *              UT_SUCCESS      "unit" doesn't map to a symbol
  774  *                      in the given encoding.
  775  *  else        Pointer to the symbol in the given encoding to which
  776  *          "unit" maps.
  777  */
  778 const char*
  779 ut_get_symbol(
  780     const ut_unit* const    unit,
  781     const ut_encoding   encoding)
  782 {
  783     ut_set_status(UT_SUCCESS);
  784 
  785     return getId(systemToUnitToSymbol, unit, encoding);
  786 }
  787 
  788 
  789 /*
  790  * Frees resources associated with a unit-system.
  791  *
  792  * Arguments:
  793  *  system      Pointer to the unit-system to have its associated
  794  *          resources freed.
  795  */
  796 void
  797 utimFreeSystem(
  798     ut_system*  system)
  799 {
  800     if (system != NULL) {
  801     SystemMap*  systemMaps[2];
  802     int     i;
  803 
  804     systemMaps[0] = systemToUnitToName;
  805     systemMaps[1] = systemToUnitToSymbol;
  806 
  807     for (i = 0; i < 2; i++) {
  808         if (systemMaps[i] != NULL) {
  809         UnitToIdMap** const unitToId =
  810             (UnitToIdMap**)smFind(systemMaps[i], system);
  811 
  812         if (unitToId != NULL)
  813             utimFree(*unitToId);
  814 
  815         smRemove(systemMaps[i], system);
  816         }
  817     }
  818     }
  819 }