OpenDNSSEC-enforcer  1.4.10
string_util2.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008-2009 Nominet UK. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
19  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
21  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
23  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  */
26 
27 /*+
28  * string_util2 - Additional String Functions
29  *
30  * Description:
31  * Additional functions for string processing. In general, these
32  * functions operate on dynamically-allocated strings, but this is
33  * not a hard and fast rule.
34  *
35  * They have been put into a separate module so as not to have to modify
36  * string_util.c, which was taken from another (open-source) package.
37 -*/
38 
39 #include <ctype.h>
40 #include <errno.h>
41 #include <string.h>
42 #include <stdio.h>
43 #include <limits.h>
44 
45 #include "ksm/ksmdef.h"
46 #include "ksm/memory.h"
47 #include "ksm/message.h"
48 #include "ksm/string_util.h"
49 #include "ksm/string_util2.h"
50 
51 
52 /*+
53  * StrAppend - Append String with Reallocation
54  *
55  * Description:
56  * Appends the given string to a dynamically-allocated string, reallocating
57  * the former as needed.
58  *
59  * The function is a no-op if either of its arguments are NULL.
60  *
61  * Arguments:
62  * char** str1
63  * On input this holds the current string. It is assumed that the
64  * string has been dynamically allocated (with malloc or the like).
65  * On output, this holds the concatenation of the two strings.
66  *
67  * If, on input, the string is NULL (i.e. *str is NULL, *not* str1 is
68  * NULL), a new string is allocated and str2 copied to it.
69  *
70  * On exit, the string can be freed via a call to StrFree.
71  *
72  * const char* str2
73  * The string to be appended.
74 -*/
75 
76 void StrAppend(char** str1, const char* str2)
77 {
78  int len1; /* Length of string 1 */
79  int len2; /* Length of string 2 */
80 
81  if (str1 && str2) {
82 
83  /* Something to append and we can append it */
84 
85  len2 = strlen(str2);
86  if (*str1) {
87  len1 = strlen(*str1);
88 
89  /* Allocate space for combined string and concatenate */
90 
91  *str1 = MemRealloc(*str1, (len1 + len2 + 1) * sizeof(char));
92  strcat(*str1, str2);
93  }
94  else {
95 
96  /* Nothing in string 1, so just duplicate string 2 */
97 
98  *str1 = StrStrdup(str2);
99  }
100  }
101 
102  return;
103 }
104 
105 
106 /*+
107  * StrArglistAdd - Add Argument to Arglist
108  *
109  * Description:
110  * This function (and its companion, StrArglistFree) tackle the problem
111  * raised by the fact that tokenising the string with strtok returns
112  * the tokens one at a time, yet many functions require a set of tokens in
113  * an "arglist" array, as given to main(), i.e.
114  *
115  * +---+ +----+ +-+-+-+-+-
116  * arglist: | |------>| |------>| | | | |...
117  * +---+ +----+ +-+-+-+-+- +-+-+-+-
118  * | |--------------------->| | | |...
119  * +----+ +-+-+-+-
120  * | : |
121  * | : |
122  * +----+
123  * |NULL|
124  * +----+
125  *
126  * This function is used to add an argument to a dynamically-created
127  * argument list. It duplicates the string, expands the list, and
128  * adds a pointer to the new string.
129  *
130  * Unlike most arglists, this one is always terminated by a NULL element.
131  *
132  * Arguments:
133  * char*** argv
134  * Address of the pointer to the argument list. The arglist is char**,
135  * hence this is char***. If the arglist (i.e. *argv) is NULL, a new
136  * one is created.
137  *
138  * const char* string
139  * String to add.
140 -*/
141 
142 void StrArglistAdd(char*** argv, const char* string)
143 {
144  char* copy = NULL; /* Newly allocated string */
145  size_t count = 0; /* Number of elements in list */
146 
147  /* Create the new string */
148 
149  copy = StrStrdup(string);
150 
151  /* Now extend the list and point to this string */
152 
153  if (*argv) {
154 
155  /* Work out how many elements are in the list */
156 
157  for (count = 0; (*argv)[count]; ++count) {
158  ;
159  }
160 
161  /*
162  * There are (count + 1) elements in the list, including the
163  * trailing NULL.
164  */
165 
166  *argv = MemRealloc(*argv, (count + 2) * sizeof(char*));
167  (*argv)[count] = copy;
168  (*argv)[count + 1] = NULL; /* Realloc doesn't zero memory */
169  }
170  else {
171 
172  /* List is NULL, so allocate something */
173 
174  *argv = MemCalloc(sizeof(char*), 2);
175  (*argv)[0] = copy;
176  }
177 
178  return;
179 }
180 
181 
182 
183 /*+
184  * StrArglistFree - Free Argument List
185  *
186  * Description:
187  * Frees the memory allocated to the argument list.
188  *
189  * Arguments:
190  * char*** arglist (modified)
191  * Address of the argument list. This is freed, as are all strings it
192  * points to.
193  *
194  * On exit, this is set to NULL.
195 -*/
196 
197 void StrArglistFree(char*** argv)
198 {
199  int i; /* Index into option list */
200 
201  if (*argv) {
202 
203  /* Points to a list, so we can start freeing it */
204 
205  for (i = 0; (*argv)[i]; ++i) {
206  if ((*argv)[i]) {
207  StrFree((*argv)[i]);
208  }
209  }
210 
211  /* ... and the list itself */
212 
213  MemFree(*argv);
214  }
215 
216  return;
217 }
218 
219 
220 /*+
221  * StrArglistCreate - Create Argument List
222  *
223  * Description:
224  * Creates an argument list from a command line. It does this by
225  * tokenising the command line, using a whitespace characters as the
226  * separator. Multiple contiguous spaces are treated as a single space.
227  *
228  * Arguments:
229  * const char* string
230  * String to split. If NULL, an empty arglist is returned.
231  *
232  * Returns:
233  * char**
234  * Pointer to the dynamically-created argument list. This should be
235  * freed using StrArglistFree.
236 -*/
237 
238 char** StrArglistCreate(const char* string)
239 {
240  char** argv; /* Returned argument list */
241  char* copy; /* Copy of the given string */
242  char* start; /* Location of start of string */
243  char* token; /* Current token */
244 
245  /* Ensure that we have something to return, even if it is an empty list */
246 
247  argv = MemCalloc(sizeof(char*), 1);
248  if (string) {
249 
250  /* Duplicate the string so that we can modify it */
251 
252  copy = StrStrdup(string);
253 
254  /* Convert whitespace to spaces, and trim the string */
255 
256  StrWhitespace(copy);
257  StrTrimR(copy);
258  start = StrTrimL(copy);
259 
260  if (*start) {
261 
262  /* String is not all empty, so we can tokenise it */
263 
264  token = NULL;
265  while ((token = strtok(start, " "))) {
266 
267  /* If the token is not the empty string, add to the arglist */
268 
269  if (*token) {
270  StrArglistAdd(&argv, token);
271  }
272 
273  /* Zero the pointer for the next call */
274 
275  start = NULL;
276  }
277  }
278 
279  /* Tidy up */
280 
281  StrFree(copy);
282  }
283 
284  return argv;
285 }
286 
287 
288 /*+
289  * StrKeywordSearch - Search for Keyword
290  *
291  * Description:
292  * Searches through a list of keywords for a match and returns the associated
293  * value.
294  *
295  * The search is made on leading substrings, i.e. the supplied string is
296  * matched with the leading substrings of all values. If the match is
297  * unique, the ID is returned, otherwise an indication that the string
298  * was not found or was ambiguous.
299  *
300  * Arguments:
301  * const char* search
302  * Search string.
303  *
304  * STR_KEYWORD_ELEMENT* keywords
305  * List of keywords to search. The list is terminated with an element
306  * containing a NULL string.
307  *
308  * int *value
309  * Returned value. This will be undefined if there is no match or if
310  * an ambiguous string was returned.
311  *
312  * Returns:
313  * int
314  * 0 Success, match found
315  * -1 No match found
316  * -2 Ambiguous match found
317 -*/
318 
319 int StrKeywordSearch(const char* search, STR_KEYWORD_ELEMENT* keywords, int* value)
320 {
321  int i; /* Index into keyword search */
322  int status = -1; /* Returned status, initialized to nothing found */
323 
324  if (value == NULL) {
325  MsgLog(KSM_INVARG, "NULL value");
326  return -1;
327  }
328 
329  if (keywords && search) {
330  for (i = 0; keywords[i].string; ++i) {
331  if (strstr(keywords[i].string, search) == keywords[i].string) {
332 
333  /* Match found of leading substring */
334 
335  if (status == -1) {
336 
337  /* Not found before, so not the fact */
338 
339  *value = keywords[i].value;
340  status = 0;
341 
342  /* Break if we have matched the full length of the input */
343  if (strlen(search) == strlen(keywords[i].string)) {
344  break;
345  }
346  }
347  else {
348 
349  /* Have found before, so mark as ambiguous */
350 
351  status = -2;
352  break;
353  }
354  }
355  }
356  }
357  else {
358  status = -1; /* No keywords, so no match */
359  }
360 
361  return status;
362 }
363 
364 
365 /*+
366  * StrStrtol - Convert String to long
367  *
368  * Description:
369  * Converts a string to a "long". It uses strtol, but also passes
370  * back a status code to indicate if the conversion was successful.
371  *
372  * This version strips out tabs and whitespace characters.
373  *
374  * Arguments:
375  * const char* string (input)
376  * String to convert.
377  *
378  * long* value (returned)
379  * Return value.
380  *
381  * Returns:
382  * int
383  * 0 Success
384  * 1 Conversion failed
385 -*/
386 
387 int StrStrtol(const char* string, long* value)
388 {
389  char* endptr; /* End of string pointer */
390  int status = 1; /* Assume failure */
391  char* copy; /* Copy of the string */
392  char* start; /* Start of the trimmed string */
393 
394  if (value == NULL) {
395  MsgLog(KSM_INVARG, "NULL value");
396  return 1;
397  }
398  if (string) {
399  copy = StrStrdup(string);
400  StrTrimR(copy); /* Remove trailing spaces */
401  start = StrTrimL(copy); /* ... and leading ones */
402  if (*start) {
403 
404  /* String is not NULL, so try a conversion */
405 
406  errno = 0;
407  *value = strtol(start, &endptr, 10);
408 
409  /* Only success if all characters converted */
410 
411  if (errno == 0) {
412  status = (*endptr == '\0') ? 0 : 1;
413  }
414  else {
415  status = 1;
416  }
417  }
418  StrFree(copy);
419  }
420 
421  return status;
422 }
423 
424 
425 /*+
426  * StrStrtoul - Convert String to unsigned long
427  *
428  * Description:
429  * Converts a string to a "unsigned long". It uses strtoul, but also
430  * passes back a status code to indicate if the conversion was successful.
431  *
432  * This version strips out tabs and whitespace characters.
433  *
434  * Arguments:
435  * const char* string (input)
436  * String to convert.
437  *
438  * unsigned long* value (returned)
439  * Return value.
440  *
441  * Returns:
442  * int
443  * 0 Success
444  * 1 Conversion failed
445 -*/
446 
447 int StrStrtoul(const char* string, unsigned long* value)
448 {
449  char* endptr; /* End of string pointer */
450  int status = 1; /* Assume failure */
451  char* copy; /* Copy of the string */
452  char* start; /* Start of the trimmed string */
453 
454  if (value == NULL) {
455  MsgLog(KSM_INVARG, "NULL value");
456  return 1;
457  }
458  if (string) {
459  copy = StrStrdup(string);
460  StrTrimR(copy); /* Remove trailing spaces */
461  start = StrTrimL(copy); /* ... and leading ones */
462  if (*start) {
463 
464  /* String is not NULL, so try a conversion */
465 
466  errno = 0;
467  *value = strtoul(start, &endptr, 10);
468 
469  /* Only success if all characters converted */
470 
471  if (errno == 0) {
472  status = (*endptr == '\0') ? 0 : 1;
473  }
474  else {
475  status = 1;
476  }
477  }
478  StrFree(copy);
479  }
480 
481  return status;
482 }
483 
484 
485 /*+
486  * StrStrtoi - Convert String to int
487  *
488  * Description:
489  * Converts a string to a "int".
490  *
491  * This version strips out tabs and whitespace characters.
492  *
493  * Arguments:
494  * const char* string (input)
495  * String to convert.
496  *
497  * int* value (returned)
498  * Return value.
499  *
500  * Returns:
501  * int
502  * 0 Success
503  * 1 Conversion failed
504 -*/
505 
506 int StrStrtoi(const char* string, int* value)
507 {
508  long longval; /* "long" to be passed to StrStrtol */
509  int status; /* Status return */
510 
511  if (value == NULL) {
512  MsgLog(KSM_INVARG, "NULL value");
513  return 1;
514  }
515  status = StrStrtol(string, &longval);
516  if (status == 0) {
517  if ((longval >= INT_MIN) && (longval <= INT_MAX)) {
518  *value = (int) longval;
519  }
520  else {
521  status = 1; /* Integer overflow */
522  }
523  }
524 
525  return status;
526 }
527 
528 /*+
529  * StrStrtoui - Convert String to unsigned int
530  *
531  * Description:
532  * Converts a string to a "unsigned int".
533  *
534  * This version strips out tabs and whitespace characters.
535  *
536  * Arguments:
537  * const char* string (input)
538  * String to convert.
539  *
540  * unsigned int* value (returned)
541  * Return value.
542  *
543  * Returns:
544  * int
545  * 0 Success
546  * 1 Conversion failed
547 -*/
548 
549 int StrStrtoui(const char* string, unsigned int* value)
550 {
551  unsigned long longval; /* "long" to be passed to StrStrtol */
552  int status; /* Status return */
553 
554  if (value == NULL) {
555  MsgLog(KSM_INVARG, "NULL value");
556  return 1;
557  }
558  status = StrStrtoul(string, &longval);
559  if (status == 0) {
560  if (longval <= UINT_MAX) {
561  *value = (unsigned int) longval;
562  }
563  else {
564  status = 1; /* Integer overflow */
565  }
566  }
567 
568  return status;
569 }
570 
571 /*+
572  * StrIsDigits - Check String for All Digits
573  *
574  * Description:
575  * Checks a string and returns whether the string is all digits (i.e.
576  * all ASCII 0 to 9) or not.
577  *
578  * Arguments:
579  * const char* string
580  * String to check.
581  *
582  * Returns:
583  * int
584  * 1 (true) All digits
585  * 0 (false) Not all digits. A NULL or empty string will return 0.
586 -*/
587 
588 int StrIsDigits(const char* string)
589 {
590  int i; /* Loop counter */
591  int numeric; /* 1 if string is numeric, 0 if not */
592 
593  if (string && *string) {
594 
595  /* String is not NULL and not empty */
596 
597  numeric = 1;
598  for (i = 0; string[i]; ++i) {
599  if (! isdigit(string[i])) {
600  numeric = 0;
601  break;
602  }
603  }
604  }
605  else {
606 
607  /* NULL or empty */
608 
609  numeric = 0;
610  }
611 
612  return numeric;
613 }
void * MemCalloc(size_t nmemb, size_t size)
Definition: memory.c:68
void StrArglistFree(char ***argv)
Definition: string_util2.c:197
#define StrFree(x)
Definition: string_util.h:66
#define KSM_INVARG
Definition: ksmdef.h:66
void StrWhitespace(char *line)
Definition: string_util.c:94
int MsgLog(int status,...)
Definition: message.c:335
void * MemRealloc(void *ptr, size_t size)
Definition: memory.c:79
#define MemFree(ptr)
Definition: memory.h:48
int StrStrtoul(const char *string, unsigned long *value)
Definition: string_util2.c:447
char * StrStrdup(const char *string)
Definition: string_util.c:124
void StrTrimR(char *text)
Definition: string_util.c:228
int StrIsDigits(const char *string)
Definition: string_util2.c:588
const char * string
Definition: string_util2.h:47
int StrStrtoi(const char *string, int *value)
Definition: string_util2.c:506
int StrKeywordSearch(const char *search, STR_KEYWORD_ELEMENT *keywords, int *value)
Definition: string_util2.c:319
char * StrTrimL(char *text)
Definition: string_util.c:269
void StrArglistAdd(char ***argv, const char *string)
Definition: string_util2.c:142
void StrAppend(char **str1, const char *str2)
Definition: string_util2.c:76
char ** StrArglistCreate(const char *string)
Definition: string_util2.c:238
int StrStrtol(const char *string, long *value)
Definition: string_util2.c:387
int StrStrtoui(const char *string, unsigned int *value)
Definition: string_util2.c:549