"Fossies" - the Fresh Open Source Software Archive

Member "udunits-2.2.28/lib/idToUnitMap.c" (7 Dec 2020, 12687 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 "idToUnitMap.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  * Identifier-to-unit map.
   10  */
   11 
   12 /*LINTLIBRARY*/
   13 
   14 #include "config.h"
   15 
   16 #include "udunits2.h"
   17 #include "unitAndId.h"
   18 #include "systemMap.h"
   19 
   20 #include <assert.h>
   21 #ifdef _MSC_VER
   22 #include "tsearch.h"
   23 #else
   24 #include <search.h>
   25 #endif
   26 
   27 #include <stdlib.h>
   28 
   29 #include <string.h>
   30 #ifndef _MSC_VER
   31 #include <strings.h>
   32 #endif
   33 
   34 typedef struct {
   35     int         (*compare)(const void*, const void*);
   36     void*       tree;
   37 } IdToUnitMap;
   38 
   39 static SystemMap*   systemToNameToUnit;
   40 static SystemMap*   systemToSymbolToUnit;
   41 
   42 
   43 static int
   44 sensitiveCompare(
   45     const void* const   node1,
   46     const void* const   node2)
   47 {
   48     return strcmp(((const UnitAndId*)node1)->id,
   49     ((const UnitAndId*)node2)->id);
   50 }
   51 
   52 
   53 static int
   54 insensitiveCompare(
   55     const void* const   node1,
   56     const void* const   node2)
   57 {
   58     return strcasecmp(((const UnitAndId*)node1)->id,
   59     ((const UnitAndId*)node2)->id);
   60 }
   61 
   62 
   63 static IdToUnitMap*
   64 itumNew(
   65     int     (*compare)(const void*, const void*))
   66 {
   67     IdToUnitMap*    map = (IdToUnitMap*)malloc(sizeof(IdToUnitMap));
   68 
   69     if (map != NULL) {
   70     map->tree = NULL;
   71     map->compare = compare;
   72     }
   73 
   74     return map;
   75 }
   76 
   77 
   78 /*
   79  * Frees an identifier-to-unit map.  All entries are freed.
   80  *
   81  * Arguments:
   82  *  map     Pointer to the identifier-to-unit map.
   83  * Returns:
   84  */
   85 static void
   86 itumFree(
   87     IdToUnitMap*    map)
   88 {
   89     if (map != NULL) {
   90     while (map->tree != NULL) {
   91         UnitAndId*  uai = *(UnitAndId**)map->tree;
   92 
   93         (void)tdelete(uai, &map->tree, map->compare);
   94         uaiFree(uai);
   95     }
   96 
   97     free(map);
   98     }                   /* valid arguments */
   99 }
  100 
  101 
  102 /*
  103  * Adds an entry to an identifier-to-unit map.
  104  *
  105  * Arguments:
  106  *  map     The database.
  107  *  id      The identifier.  May be freed upon return.
  108  *  unit        The unit.  May be freed upon return.
  109  * Returns:
  110  *  UT_OS       Operating-system error.  See "errno".
  111  *  UT_EXISTS   "id" already maps to a different unit.
  112  *  UT_SUCCESS  Success.
  113  */
  114 static ut_status
  115 itumAdd(
  116     IdToUnitMap*        map,
  117     const char* const       id,
  118     const ut_unit* const    unit)
  119 {
  120     ut_status       status;
  121     UnitAndId*      targetEntry;
  122 
  123     assert(map != NULL);
  124     assert(id != NULL);
  125     assert(unit != NULL);
  126 
  127     targetEntry = uaiNew(unit, id);
  128 
  129     if (targetEntry == NULL) {
  130         status = ut_get_status();
  131     }
  132     else {
  133     UnitAndId** treeEntry = tsearch(targetEntry, &map->tree,
  134         map->compare);
  135 
  136     if (treeEntry == NULL) {
  137         uaiFree(targetEntry);
  138         status = UT_OS;
  139     }
  140     else {
  141         if (ut_compare((*treeEntry)->unit, unit) == 0) {
  142         status = UT_SUCCESS;
  143         }
  144         else {
  145         status = UT_EXISTS;
  146                 ut_set_status(status);
  147         ut_handle_error_message(
  148             "\"%s\" already maps to existing but different unit", id);
  149         }
  150 
  151             if (targetEntry != *treeEntry)
  152                 uaiFree(targetEntry);
  153     }               /* found entry */
  154     }                   /* "targetEntry" allocated */
  155 
  156     return status;
  157 }
  158 
  159 
  160 /*
  161  * Removes an entry to an identifier-to-unit map.
  162  *
  163  * Arguments:
  164  *  map     The database.
  165  *  id      The identifier.  May be freed upon return.
  166  * Returns:
  167  *  UT_SUCCESS  Success.
  168  */
  169 static ut_status
  170 itumRemove(
  171     IdToUnitMap*    map,
  172     const char* const   id)
  173 {
  174     UnitAndId       targetEntry;
  175     UnitAndId**     treeEntry;
  176 
  177     assert(map != NULL);
  178     assert(id != NULL);
  179 
  180     targetEntry.id = (char*)id;
  181     treeEntry = tfind(&targetEntry, &map->tree, map->compare);
  182 
  183     if (treeEntry != NULL) {
  184     UnitAndId*  uai = *treeEntry;
  185 
  186     (void)tdelete(uai, &map->tree, map->compare);
  187     uaiFree(uai);
  188     }
  189 
  190     return UT_SUCCESS;
  191 }
  192 
  193 
  194 /*
  195  * Finds the entry in an identifier-to-unit map that corresponds to an
  196  * identifer.
  197  *
  198  * Arguments:
  199  *  map The identifier-to-unit map.
  200  *  id  The identifier to be used as the key in the search.
  201  * Returns:
  202  *  NULL    Failure.  "map" doesn't contain an entry that corresponds
  203  *      to "id".
  204  *  else    Pointer to the entry corresponding to "id".
  205  */
  206 static const UnitAndId*
  207 itumFind(
  208     IdToUnitMap*    map,
  209     const char* const   id)
  210 {
  211     UnitAndId*      entry = NULL;   /* failure */
  212     UnitAndId       targetEntry;
  213     UnitAndId**     treeEntry;
  214 
  215     assert(map != NULL);
  216     assert(id != NULL);
  217 
  218     targetEntry.id = (char*)id;
  219     treeEntry = tfind(&targetEntry, &map->tree, map->compare);
  220 
  221     if (treeEntry != NULL)
  222     entry = *treeEntry;
  223 
  224     return entry;
  225 }
  226 
  227 
  228 /*
  229  * Adds to a particular unit-system a mapping from an identifier to a unit.
  230  *
  231  * Arguments:
  232  *  systemMap   Address of the pointer to the system-map.
  233  *  id      Pointer to the identifier.  May be freed upon return.
  234  *  unit        Pointer to the unit.  May be freed upon return.
  235  *  compare     Pointer to comparison function for unit-identifiers.
  236  * Returns:
  237  *  UT_BAD_ARG  "id" is NULL or "unit" is NULL.
  238  *  UT_OS       Operating-sytem failure.  See "errno".
  239  *  UT_SUCCESS  Success.
  240  */
  241 static ut_status
  242 mapIdToUnit(
  243     SystemMap** const       systemMap,
  244     const char* const       id,
  245     const ut_unit* const    unit,
  246     int             (*compare)(const void*, const void*))
  247 {
  248     ut_status       status = UT_SUCCESS;
  249 
  250     if (id == NULL) {
  251     status = UT_BAD_ARG;
  252     }
  253     else if (unit == NULL) {
  254     status = UT_BAD_ARG;
  255     }
  256     else {
  257     ut_system*  system = ut_get_system(unit);
  258 
  259     if (*systemMap == NULL) {
  260         *systemMap = smNew();
  261 
  262         if (*systemMap == NULL)
  263         status = UT_OS;
  264     }
  265 
  266     if (*systemMap != NULL) {
  267         IdToUnitMap** const idToUnit =
  268         (IdToUnitMap**)smSearch(*systemMap, system);
  269 
  270         if (idToUnit == NULL) {
  271         status = UT_OS;
  272         }
  273         else {
  274         if (*idToUnit == NULL) {
  275             *idToUnit = itumNew(compare);
  276 
  277             if (*idToUnit == NULL)
  278             status = UT_OS;
  279         }
  280 
  281         if (*idToUnit != NULL)
  282             status = itumAdd(*idToUnit, id, unit);
  283         }               /* have system-map entry */
  284     }               /* have system-map */
  285     }                   /* valid arguments */
  286 
  287     return status;
  288 }
  289 
  290 
  291 /*
  292  * Removes the mapping from an identifier to a unit.
  293  *
  294  * Arguments:
  295  *  systemMap   Address of the pointer to the system-map.
  296  *  id      Pointer to the identifier.  May be freed upon return.
  297  *  system      Pointer to the unit-system associated with the mapping.
  298  * Returns:
  299  *  UT_BAD_ARG  "id" is NULL, "system" is NULL, or "compare" is NULL.
  300  *  UT_SUCCESS  Success.
  301  */
  302 static ut_status
  303 unmapId(
  304     SystemMap* const    systemMap,
  305     const char* const   id,
  306     ut_system*      system)
  307 {
  308     ut_status       status;
  309 
  310     if (systemMap == NULL || id == NULL || system == NULL) {
  311     status = UT_BAD_ARG;
  312     }
  313     else {
  314     IdToUnitMap** const idToUnit =
  315         (IdToUnitMap**)smFind(systemMap, system);
  316 
  317     status =
  318         (idToUnit == NULL || *idToUnit == NULL)
  319         ? UT_SUCCESS
  320         : itumRemove(*idToUnit, id);
  321     }                   /* valid arguments */
  322 
  323     return status;
  324 }
  325 
  326 
  327 /*
  328  * Adds a mapping from a name to a unit.
  329  *
  330  * Arguments:
  331  *  name        Pointer to the name to be mapped to "unit".  May be
  332  *          freed upon return.
  333  *      encoding        The character encoding of "name".
  334  *  unit        Pointer to the unit to be mapped-to by "name".  May be
  335  *          freed upon return.
  336  * Returns:
  337  *  UT_BAD_ARG  "name" or "unit" is NULL.
  338  *  UT_OS       Operating-system error.  See "errno".
  339  *  UT_EXISTS   "name" already maps to a different unit.
  340  *  UT_SUCCESS  Success.
  341  */
  342 ut_status
  343 ut_map_name_to_unit(
  344     const char* const       name,
  345     const ut_encoding       encoding,
  346     const ut_unit* const    unit)
  347 {
  348     ut_set_status(
  349     mapIdToUnit(&systemToNameToUnit, name, unit, insensitiveCompare));
  350 
  351     return ut_get_status();
  352 }
  353 
  354 
  355 /*
  356  * Removes a mapping from a name to a unit.  After this function,
  357  * ut_get_unit_by_name(system,name) will no longer return a unit.
  358  *
  359  * Arguments:
  360  *  system      The unit-system to which the unit belongs.
  361  *  name        The name of the unit.
  362  *      encoding        The character encoding of "name".
  363  * Returns:
  364  *  UT_SUCCESS  Success.
  365  *  UT_BAD_ARG  "system" or "name" is NULL.
  366  */
  367 ut_status
  368 ut_unmap_name_to_unit(
  369     ut_system*      system,
  370     const char* const   name,
  371     const ut_encoding   encoding)
  372 {
  373     ut_set_status(unmapId(systemToNameToUnit, name, system));
  374 
  375     return ut_get_status();
  376 }
  377 
  378 
  379 /*
  380  * Adds a mapping from a symbol to a unit.
  381  *
  382  * Arguments:
  383  *  symbol      Pointer to the symbol to be mapped to "unit".  May be
  384  *          freed upon return.
  385  *      encoding        The character encoding of "symbol".
  386  *  unit        Pointer to the unit to be mapped-to by "symbol".  May
  387  *          be freed upon return.
  388  * Returns:
  389  *  UT_BAD_ARG  "symbol" or "unit" is NULL.
  390  *  UT_OS       Operating-system error.  See "errno".
  391  *  UT_EXISTS   "symbol" already maps to a different unit.
  392  *  UT_SUCCESS  Success.
  393  */
  394 ut_status
  395 ut_map_symbol_to_unit(
  396     const char* const       symbol,
  397     const ut_encoding       encoding,
  398     const ut_unit* const    unit)
  399 {
  400     ut_set_status(
  401     mapIdToUnit(&systemToSymbolToUnit, symbol, unit, sensitiveCompare));
  402 
  403     return ut_get_status();
  404 }
  405 
  406 
  407 /*
  408  * Removes a mapping from a symbol to a unit.  After this function,
  409  * ut_get_unit_by_symbol(system,symbol) will no longer return a unit.
  410  *
  411  * Arguments:
  412  *  system      The unit-system to which the unit belongs.
  413  *  symbol      The symbol of the unit.
  414  *      encoding        The character encoding of "symbol".
  415  * Returns:
  416  *  UT_SUCCESS  Success.
  417  *  UT_BAD_ARG  "system" or "symbol" is NULL.
  418  */
  419 ut_status
  420 ut_unmap_symbol_to_unit(
  421     ut_system*      system,
  422     const char* const   symbol,
  423     const ut_encoding   encoding)
  424 {
  425     ut_set_status(unmapId(systemToSymbolToUnit, symbol, system));
  426 
  427     return ut_get_status();
  428 }
  429 
  430 
  431 /*
  432  * Returns the unit to which an identifier maps in a particular unit-system.
  433  *
  434  * Arguments:
  435  *  systemMap   NULL or pointer to the system-map.  If NULL, then
  436  *          NULL will be returned.
  437  *  system      Pointer to the unit-system.
  438  *  id      Pointer to the identifier.
  439  * Returns:
  440  *  NULL    Failure.  "ut_get_status()" will be:
  441  *          UT_BAD_ARG          "system" is NULL or "id" is NULL.
  442  *  else    Pointer to the unit in "system" with the identifier "id".
  443  *      Should be passed to ut_free() when no longer needed.
  444  */
  445 static ut_unit*
  446 getUnitById(
  447     const SystemMap* const  systemMap,
  448     const ut_system* const  system,
  449     const char* const       id)
  450 {
  451     ut_unit*    unit = NULL;        /* failure */
  452 
  453     if (system == NULL) {
  454     ut_set_status(UT_BAD_ARG);
  455     ut_handle_error_message("getUnitById(): NULL unit-system argument");
  456     }
  457     else if (id == NULL) {
  458     ut_set_status(UT_BAD_ARG);
  459     ut_handle_error_message("getUnitById(): NULL identifier argument");
  460     }
  461     else if (systemMap != NULL) {
  462     IdToUnitMap** const idToUnit =
  463         (IdToUnitMap**)smFind(systemMap, system);
  464 
  465     if (idToUnit != NULL) {
  466         const UnitAndId*    uai = itumFind(*idToUnit, id);
  467 
  468         if (uai != NULL)
  469         unit = ut_clone(uai->unit);
  470     }
  471     }                   /* valid arguments */
  472 
  473     return unit;
  474 }
  475 
  476 
  477 /*
  478  * Returns the unit with a given name from a unit-system.  Name comparisons
  479  * are case-insensitive.
  480  *
  481  * Arguments:
  482  *  system  Pointer to the unit-system.
  483  *  name    Pointer to the name of the unit to be returned.
  484  * Returns:
  485  *  NULL    Failure.  "ut_get_status()" will be
  486  *          UT_SUCCESS      "name" doesn't map to a unit of
  487  *                  "system".
  488  *          UT_BAD_ARG      "system" or "name" is NULL.
  489  *  else    Pointer to the unit of the unit-system with the given name.
  490  *      The pointer should be passed to ut_free() when the unit is
  491  *      no longer needed.
  492  */
  493 ut_unit*
  494 ut_get_unit_by_name(
  495     const ut_system* const  system,
  496     const char* const       name)
  497 {
  498     ut_set_status(UT_SUCCESS);
  499 
  500     return getUnitById(systemToNameToUnit, system, name);
  501 }
  502 
  503 
  504 /*
  505  * Returns the unit with a given symbol from a unit-system.  Symbol
  506  * comparisons are case-sensitive.
  507  *
  508  * Arguments:
  509  *  system      Pointer to the unit-system.
  510  *  symbol      Pointer to the symbol associated with the unit to be
  511  *          returned.
  512  * Returns:
  513  *  NULL    Failure.  "ut_get_status()" will be
  514  *          UT_SUCCESS      "symbol" doesn't map to a unit of
  515  *                  "system".
  516  *          UT_BAD_ARG      "system" or "symbol" is NULL.
  517  *  else    Pointer to the unit in the unit-system with the given symbol.
  518  *      The pointer should be passed to ut_free() when the unit is no
  519  *      longer needed.
  520  */
  521 ut_unit*
  522 ut_get_unit_by_symbol(
  523     const ut_system* const  system,
  524     const char* const       symbol)
  525 {
  526     ut_set_status(UT_SUCCESS);
  527 
  528     return getUnitById(systemToSymbolToUnit, system, symbol);
  529 }
  530 
  531 
  532 /*
  533  * Frees resources associated with a unit-system.
  534  *
  535  * Arguments:
  536  *  system      Pointer to the unit-system to have its associated
  537  *          resources freed.
  538  */
  539 void
  540 itumFreeSystem(
  541     ut_system*  system)
  542 {
  543     if (system != NULL) {
  544     SystemMap*  systemMaps[2];
  545     int     i;
  546 
  547     systemMaps[0] = systemToNameToUnit;
  548     systemMaps[1] = systemToSymbolToUnit;
  549 
  550     for (i = 0; i < 2; i++) {
  551         if (systemMaps[i] != NULL) {
  552         IdToUnitMap** const idToUnit =
  553             (IdToUnitMap**)smFind(systemMaps[i], system);
  554 
  555         if (idToUnit != NULL)
  556             itumFree(*idToUnit);
  557 
  558         smRemove(systemMaps[i], system);
  559         }
  560     }
  561     }                   /* valid arguments */
  562 }