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