OpenDNSSEC-enforcer
1.3.8
|
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 }