OpenDNSSEC-enforcer  1.3.8
/build/buildd/opendnssec-1.3.8/enforcer/ksm/string_util2.c
Go to the documentation of this file.
00001 /*
00002  * $Id: string_util2.c 4141 2010-10-25 15:26:40Z sion $
00003  *
00004  * Copyright (c) 2008-2009 Nominet UK. All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  *
00015  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00016  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00017  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00018  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
00019  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00020  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00021  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
00023  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00024  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
00025  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026  *
00027  */
00028 
00029 /*+
00030  * string_util2 - Additional String Functions
00031  *
00032  * Description:
00033  *      Additional functions for string processing.  In general, these
00034  *      functions operate on dynamically-allocated strings, but this is
00035  *      not a hard and fast rule.
00036  *
00037  *      They have been put into a separate module so as not to have to modify
00038  *      string_util.c, which was taken from another (open-source) package.
00039 -*/
00040 
00041 #include <ctype.h>
00042 #include <errno.h>
00043 #include <string.h>
00044 #include <stdio.h>
00045 #include <limits.h>
00046 
00047 #include "ksm/ksmdef.h"
00048 #include "ksm/memory.h"
00049 #include "ksm/message.h"
00050 #include "ksm/string_util.h"
00051 #include "ksm/string_util2.h"
00052 
00053 
00054 /*+
00055  * StrAppend - Append String with Reallocation
00056  *
00057  * Description:
00058  *      Appends the given string to a dynamically-allocated string, reallocating
00059  *      the former as needed.
00060  *
00061  *      The function is a no-op if either of its arguments are NULL.
00062  *
00063  * Arguments:
00064  *      char** str1
00065  *          On input this holds the current string.  It is assumed that the
00066  *          string has been dynamically allocated (with malloc or the like).
00067  *          On output, this holds the concatenation of the two strings.
00068  *
00069  *          If, on input, the string is NULL (i.e. *str is NULL, *not* str1 is
00070  *          NULL), a new string is allocated and str2 copied to it.
00071  *
00072  *          On exit, the string can be freed via a call to StrFree.
00073  *
00074  *      const char* str2
00075  *          The string to be appended.
00076 -*/
00077 
00078 void StrAppend(char** str1, const char* str2)
00079 {
00080     int len1;   /* Length of string 1 */
00081     int len2;   /* Length of string 2 */
00082 
00083     if (str1 && str2) {
00084 
00085         /* Something to append and we can append it */
00086 
00087         len2 = strlen(str2);
00088         if (*str1) {
00089             len1 = strlen(*str1);
00090 
00091             /* Allocate space for combined string and concatenate */
00092 
00093             *str1 = MemRealloc(*str1, (len1 + len2 + 1) * sizeof(char));
00094             strcat(*str1, str2);
00095         }
00096         else {
00097 
00098             /* Nothing in string 1, so just duplicate string 2 */
00099 
00100             *str1 = StrStrdup(str2);
00101         }
00102     }
00103 
00104     return;
00105 }
00106 
00107 
00108 /*+
00109  * StrArglistAdd - Add Argument to Arglist
00110  *
00111  * Description:
00112  *      This function (and its companion, StrArglistFree) tackle the problem
00113  *      raised by the fact that tokenising the string with strtok returns
00114  *      the tokens one at a time, yet many functions require a set of tokens in
00115  *      an "arglist" array, as given to main(), i.e.
00116  *
00117  *               +---+       +----+       +-+-+-+-+-
00118  *      arglist: |   |------>|    |------>| | | | |...
00119  *               +---+       +----+       +-+-+-+-+-     +-+-+-+-
00120  *                           |    |--------------------->| | | |...
00121  *                           +----+                      +-+-+-+-
00122  *                           | :  |
00123  *                           | :  |
00124  *                           +----+
00125  *                           |NULL|
00126  *                           +----+
00127  *
00128  *      This function is used to add an argument to a dynamically-created
00129  *      argument list.  It duplicates the string, expands the list, and
00130  *      adds a pointer to the new string.
00131  *
00132  *      Unlike most arglists, this one is always terminated by a NULL element.
00133  *
00134  * Arguments:
00135  *      char*** argv
00136  *          Address of the pointer to the argument list.  The arglist is char**,
00137  *          hence this is char***.  If the arglist (i.e. *argv) is NULL, a new
00138  *          one is created.
00139  *
00140  *      const char* string
00141  *          String to add.
00142 -*/
00143 
00144 void StrArglistAdd(char*** argv, const char* string)
00145 {
00146     char*   copy = NULL;    /* Newly allocated string */
00147     size_t  count = 0;      /* Number of elements in list */
00148 
00149     /* Create the new string */
00150 
00151     copy = StrStrdup(string);
00152 
00153     /* Now extend the list and point to this string */
00154 
00155     if (*argv) {
00156 
00157         /* Work out how many elements are in the list */
00158 
00159         for (count = 0; (*argv)[count]; ++count) {
00160             ;
00161         }
00162 
00163         /*
00164          * There are (count + 1) elements in the list, including the
00165          * trailing NULL.
00166          */
00167 
00168         *argv = MemRealloc(*argv, (count + 2) * sizeof(char*));
00169         (*argv)[count] = copy;
00170         (*argv)[count + 1] = NULL;  /* Realloc doesn't zero memory */
00171     }
00172     else {
00173 
00174         /* List is NULL, so allocate something */
00175 
00176         *argv = MemCalloc(sizeof(char*), 2);
00177         (*argv)[0] = copy;
00178     }
00179 
00180     return;
00181 }
00182 
00183 
00184 
00185 /*+
00186  * StrArglistFree - Free Argument List
00187  *
00188  * Description:
00189  *      Frees the memory allocated to the argument list.
00190  *
00191  * Arguments:
00192  *      char*** arglist (modified)
00193  *          Address of the argument list.  This is freed, as are all strings it
00194  *          points to.
00195  *
00196  *          On exit, this is set to NULL.
00197 -*/
00198 
00199 void StrArglistFree(char*** argv)
00200 {
00201     int i;      /* Index into option list */
00202 
00203     if (*argv) {
00204 
00205         /* Points to a list, so we can start freeing it */
00206 
00207         for (i = 0; (*argv)[i]; ++i) {
00208             if ((*argv)[i]) {
00209                 StrFree((*argv)[i]);
00210             }
00211         }
00212 
00213         /* ... and the list itself */
00214 
00215         MemFree(*argv);
00216     }
00217 
00218     return;
00219 }
00220 
00221 
00222 /*+
00223  * StrArglistCreate - Create Argument List
00224  *
00225  * Description:
00226  *      Creates an argument list from a command line.  It does this by
00227  *      tokenising the command line, using a whitespace characters as the
00228  *      separator.  Multiple contiguous spaces are treated as a single space.
00229  *
00230  * Arguments:
00231  *      const char* string
00232  *          String to split.  If NULL, an empty arglist is returned.
00233  *
00234  * Returns:
00235  *      char**
00236  *          Pointer to the dynamically-created argument list.  This should be
00237  *          freed using StrArglistFree.
00238 -*/
00239 
00240 char** StrArglistCreate(const char* string)
00241 {
00242     char** argv;        /* Returned argument list */
00243     char* copy;         /* Copy of the given string */
00244     char* start;        /* Location of start of string */
00245     char* token;        /* Current token */
00246 
00247     /* Ensure that we have something to return, even if it is an empty list */
00248 
00249     argv = MemCalloc(sizeof(char*), 1);
00250     if (string) {
00251 
00252         /* Duplicate the string so that we can modify it */
00253 
00254         copy = StrStrdup(string);
00255 
00256         /* Convert whitespace to spaces, and trim the string */
00257 
00258         StrWhitespace(copy);
00259         StrTrimR(copy);
00260         start = StrTrimL(copy);
00261 
00262         if (*start) {
00263 
00264             /* String is not all empty, so we can tokenise it */
00265 
00266             token = NULL;
00267             while ((token = strtok(start, " "))) {
00268 
00269                 /* If the token is not the empty string, add to the arglist */
00270 
00271                 if (*token) {
00272                     StrArglistAdd(&argv, token);
00273                 }
00274                 
00275                 /* Zero the pointer for the next call */
00276 
00277                 start = NULL;
00278             }
00279         }
00280 
00281         /* Tidy up */
00282 
00283         StrFree(copy);
00284     }
00285 
00286     return argv;
00287 }
00288 
00289 
00290 /*+
00291  * StrKeywordSearch - Search for Keyword
00292  *
00293  * Description:
00294  *      Searches through a list of keywords for a match and returns the associated
00295  *      value.
00296  *
00297  *      The search is made on leading substrings, i.e. the supplied string is
00298  *      matched with the leading substrings of all values.  If the match is
00299  *      unique, the ID is returned, otherwise an indication that the string
00300  *      was not found or was ambiguous.
00301  *
00302  * Arguments:
00303  *      const char* search
00304  *          Search string.
00305  *
00306  *      STR_KEYWORD_ELEMENT* keywords
00307  *          List of keywords to search.  The list is terminated with an element
00308  *          containing a NULL string.
00309  *
00310  *      int *value
00311  *          Returned value.  This will be undefined if there is no match or if
00312  *          an ambiguous string was returned.
00313  *
00314  * Returns:
00315  *      int
00316  *          0       Success, match found
00317  *          -1      No match found
00318  *          -2      Ambiguous match found
00319 -*/
00320 
00321 int StrKeywordSearch(const char* search, STR_KEYWORD_ELEMENT* keywords, int* value)
00322 {
00323     int i;              /* Index into keyword search */
00324     int status = -1;    /* Returned status, initialized to nothing found */
00325 
00326     if (value == NULL) {
00327         MsgLog(KSM_INVARG, "NULL value");
00328         return -1;
00329     }
00330 
00331     if (keywords && search) {
00332         for (i = 0; keywords[i].string; ++i) {
00333             if (strstr(keywords[i].string, search) == keywords[i].string) {
00334 
00335                 /* Match found of leading substring */
00336 
00337                 if (status == -1) {
00338 
00339                     /* Not found before, so not the fact */
00340 
00341                     *value = keywords[i].value;
00342                     status = 0;
00343 
00344                     /* Break if we have matched the full length of the input */
00345                     if (strlen(search) == strlen(keywords[i].string)) {
00346                         break;
00347                     }
00348                 }
00349                 else {
00350 
00351                     /* Have found before, so mark as ambiguous */
00352 
00353                     status = -2;
00354                     break;
00355                 }
00356             }
00357         }
00358     }
00359     else {
00360         status = -1;        /* No keywords, so no match */
00361     }
00362 
00363     return status;
00364 }
00365 
00366 
00367 /*+
00368  * StrStrtol - Convert String to long
00369  *
00370  * Description:
00371  *      Converts a string to a "long".  It uses strtol, but also passes
00372  *      back a status code to indicate if the conversion was successful.
00373  *
00374  *      This version strips out tabs and whitespace characters.
00375  *
00376  * Arguments:
00377  *      const char* string (input)
00378  *          String to convert.
00379  *
00380  *      long* value (returned)
00381  *          Return value.
00382  *
00383  * Returns:
00384  *      int
00385  *          0   Success
00386  *          1   Conversion failed
00387 -*/
00388 
00389 int StrStrtol(const char* string, long* value)
00390 {
00391     char*   endptr;         /* End of string pointer */
00392     int     status = 1;     /* Assume failure */
00393     char*   copy;           /* Copy of the string */
00394     char*   start;          /* Start of the trimmed string */
00395 
00396     if (value == NULL) {
00397         MsgLog(KSM_INVARG, "NULL value");
00398         return 1;
00399     }
00400     if (string) {
00401         copy = StrStrdup(string);
00402         StrTrimR(copy);             /* Remove trailing spaces */
00403         start = StrTrimL(copy);     /* ... and leading ones */
00404         if (*start) {
00405 
00406             /* String is not NULL, so try a conversion */
00407 
00408             errno = 0;
00409             *value = strtol(start, &endptr, 10);
00410 
00411             /* Only success if all characters converted */
00412 
00413             if (errno == 0) {
00414                 status = (*endptr == '\0') ? 0 : 1;
00415             }
00416             else {
00417                 status = 1;
00418             }
00419         }
00420         StrFree(copy);
00421     }
00422 
00423     return status;
00424 }
00425 
00426 
00427 /*+
00428  * StrStrtoul - Convert String to unsigned long
00429  *
00430  * Description:
00431  *      Converts a string to a "unsigned long".  It uses strtoul, but also
00432  *      passes back a status code to indicate if the conversion was successful.
00433  *
00434  *      This version strips out tabs and whitespace characters.
00435  *
00436  * Arguments:
00437  *      const char* string (input)
00438  *          String to convert.
00439  *
00440  *      unsigned long* value (returned)
00441  *          Return value.
00442  *
00443  * Returns:
00444  *      int
00445  *          0   Success
00446  *          1   Conversion failed
00447 -*/
00448 
00449 int StrStrtoul(const char* string, unsigned long* value)
00450 {
00451     char*   endptr;         /* End of string pointer */
00452     int     status = 1;     /* Assume failure */
00453     char*   copy;           /* Copy of the string */
00454     char*   start;          /* Start of the trimmed string */
00455 
00456     if (value == NULL) {
00457         MsgLog(KSM_INVARG, "NULL value");
00458         return 1;
00459     }
00460     if (string) {
00461         copy = StrStrdup(string);
00462         StrTrimR(copy);             /* Remove trailing spaces */
00463         start = StrTrimL(copy);     /* ... and leading ones */
00464         if (*start) {
00465 
00466             /* String is not NULL, so try a conversion */
00467 
00468             errno = 0;
00469             *value = strtoul(start, &endptr, 10);
00470 
00471             /* Only success if all characters converted */
00472 
00473             if (errno == 0) {
00474                 status = (*endptr == '\0') ? 0 : 1;
00475             }
00476             else {
00477                 status = 1;
00478             }
00479         }
00480         StrFree(copy);
00481     }
00482 
00483     return status;
00484 }
00485 
00486 
00487 /*+
00488  * StrStrtoi - Convert String to int
00489  *
00490  * Description:
00491  *      Converts a string to a "int".
00492  *
00493  *      This version strips out tabs and whitespace characters.
00494  *
00495  * Arguments:
00496  *      const char* string (input)
00497  *          String to convert.
00498  *
00499  *      int* value (returned)
00500  *          Return value.
00501  *
00502  * Returns:
00503  *      int
00504  *          0   Success
00505  *          1   Conversion failed
00506 -*/
00507 
00508 int StrStrtoi(const char* string, int* value)
00509 {
00510     long    longval;    /* "long" to be passed to StrStrtol */
00511     int     status;     /* Status return */
00512 
00513     if (value == NULL) {
00514         MsgLog(KSM_INVARG, "NULL value");
00515         return 1;
00516     }
00517     status = StrStrtol(string, &longval);
00518     if (status == 0) {
00519         if ((longval >= INT_MIN) && (longval <= INT_MAX)) {
00520             *value = (int) longval;
00521         }
00522         else {
00523             status = 1;     /* Integer overflow */
00524         }
00525     }
00526 
00527     return status;
00528 }
00529 
00530 /*+
00531  * StrStrtoui - Convert String to unsigned int
00532  *
00533  * Description:
00534  *      Converts a string to a "unsigned int".
00535  *
00536  *      This version strips out tabs and whitespace characters.
00537  *
00538  * Arguments:
00539  *      const char* string (input)
00540  *          String to convert.
00541  *
00542  *      unsigned int* value (returned)
00543  *          Return value.
00544  *
00545  * Returns:
00546  *      int
00547  *          0   Success
00548  *          1   Conversion failed
00549 -*/
00550 
00551 int StrStrtoui(const char* string, unsigned int* value)
00552 {
00553     unsigned long    longval;    /* "long" to be passed to StrStrtol */
00554     int     status;     /* Status return */
00555 
00556     if (value == NULL) {
00557         MsgLog(KSM_INVARG, "NULL value");
00558         return 1;
00559     }
00560     status = StrStrtoul(string, &longval);
00561     if (status == 0) {
00562         if (longval <= UINT_MAX) {
00563             *value = (unsigned int) longval;
00564         }
00565         else {
00566             status = 1;     /* Integer overflow */
00567         }
00568     }
00569 
00570     return status;
00571 }
00572 
00573 /*+
00574  * StrIsDigits - Check String for All Digits
00575  *
00576  * Description:
00577  *      Checks a string and returns whether the string is all digits (i.e.
00578  *      all ASCII 0 to 9) or not.
00579  *
00580  * Arguments:
00581  *      const char* string
00582  *          String to check.
00583  *
00584  * Returns:
00585  *      int
00586  *          1 (true)    All digits
00587  *          0 (false)   Not all digits.  A NULL or empty string will return 0.
00588 -*/
00589 
00590 int StrIsDigits(const char* string)
00591 {
00592     int     i;          /* Loop counter */
00593     int     numeric;    /* 1 if string is numeric, 0 if not */
00594 
00595     if (string && *string) {
00596 
00597         /* String is not NULL and not empty */
00598 
00599         numeric = 1;
00600         for (i = 0; string[i]; ++i) {
00601             if (! isdigit(string[i])) {
00602                 numeric = 0;
00603                 break;
00604             }
00605         }
00606     }
00607     else {
00608 
00609         /* NULL or empty */
00610 
00611         numeric = 0;
00612     }
00613 
00614     return numeric;
00615 }