1 /*
2 ** Copyright (C) 2001-2020 by Carnegie Mellon University.
3 **
4 ** @OPENSOURCE_LICENSE_START@
5 ** See license information in ../../LICENSE.txt
6 ** @OPENSOURCE_LICENSE_END@
7 */
8 
9 /*
10 **  sku-string.c
11 **
12 **  A collection of utility routines to manipulate strings
13 **
14 */
15 
16 #include <silk/silk.h>
17 
18 RCSIDENT("$SiLK: sku-string.c ef14e54179be 2020-04-14 21:57:45Z mthomas $");
19 
20 #include <silk/utils.h>
21 #include <silk/skipaddr.h>
22 #include <silk/skvector.h>
23 #include <silk/rwrec.h>
24 
25 #ifndef USE_GETADDRINFO
26 #  ifdef SK_HAVE_GETADDRINFO
27 #    define USE_GETADDRINFO 1
28 #  else
29 #    define USE_GETADDRINFO 0
30 #  endif
31 #endif
32 #if !USE_GETADDRINFO && SK_ENABLE_INET6_NETWORKING
33 #  undef SK_ENABLE_INET6_NETWORKING
34 #  define SK_ENABLE_INET6_NETWORKING 0
35 #endif
36 
37 
38 #define STRING_PARSE_MIN_YEAR   1970
39 #define STRING_PARSE_MAX_YEAR   2039
40 #define STRING_PARSE_MIN_EPOCH  (1 << 29)       /* Mon Jan  5 18:48:32 1987 */
41 #define STRING_PARSE_MAX_EPOCH  ((1u << 31)-1)  /* Tue Jan 19 03:14:07 2038 */
42 
43 
44 static const struct signal_name2num_st {
45     const char *name;
46     int         number;
47 } signal_name2num[] = {
48 #ifdef SIGABRT
49     {"ABRT",    SIGABRT},
50 #endif
51 #ifdef SIGALRM
52     {"ALRM",    SIGALRM},
53 #endif
54 #ifdef SIGBUS
55     {"BUS",     SIGBUS},
56 #endif
57 #ifdef SIGCANCEL
58     {"CANCEL",  SIGCANCEL},
59 #endif
60 #ifdef SIGCHLD
61     {"CHLD",    SIGCHLD},
62 #endif
63 #ifdef SIGCLD
64     {"CLD",     SIGCLD},
65 #endif
66 #ifdef SIGCONT
67     {"CONT",    SIGCONT},
68 #endif
69 #ifdef SIGEMT
70     {"EMT",     SIGEMT},
71 #endif
72 #ifdef SIGEXIT
73     {"EXIT",    SIGEXIT},
74 #endif
75 #ifdef SIGFPE
76     {"FPE",     SIGFPE},
77 #endif
78 #ifdef SIGFREEZE
79     {"FREEZE",  SIGFREEZE},
80 #endif
81 #ifdef SIGHUP
82     {"HUP",     SIGHUP},
83 #endif
84 #ifdef SIGILL
85     {"ILL",     SIGILL},
86 #endif
87 #ifdef SIGINFO
88     {"INFO",    SIGINFO},
89 #endif
90 #ifdef SIGINT
91     {"INT",     SIGINT},
92 #endif
93 #ifdef SIGIO
94     {"IO",      SIGIO},
95 #endif
96 #ifdef SIGIOT
97     {"IOT",     SIGIOT},
98 #endif
99 #ifdef SIGKILL
100     {"KILL",    SIGKILL},
101 #endif
102 #ifdef SIGLOST
103     {"LOST",    SIGLOST},
104 #endif
105 #ifdef SIGPIPE
106     {"PIPE",    SIGPIPE},
107 #endif
108 #ifdef SIGPOLL
109     {"POLL",    SIGPOLL},
110 #endif
111 #ifdef SIGPROF
112     {"PROF",    SIGPROF},
113 #endif
114 #ifdef SIGPWR
115     {"PWR",     SIGPWR},
116 #endif
117 #ifdef SIGQUIT
118     {"QUIT",    SIGQUIT},
119 #endif
120 #ifdef SIGSEGV
121     {"SEGV",    SIGSEGV},
122 #endif
123 #ifdef SIGSTKFLT
124     {"STKFLT",  SIGSTKFLT},
125 #endif
126 #ifdef SIGSTOP
127     {"STOP",    SIGSTOP},
128 #endif
129 #ifdef SIGSYS
130     {"SYS",     SIGSYS},
131 #endif
132 #ifdef SIGTERM
133     {"TERM",    SIGTERM},
134 #endif
135 #ifdef SIGTHAW
136     {"THAW",    SIGTHAW},
137 #endif
138 #ifdef SIGTRAP
139     {"TRAP",    SIGTRAP},
140 #endif
141 #ifdef SIGTSTP
142     {"TSTP",    SIGTSTP},
143 #endif
144 #ifdef SIGTTIN
145     {"TTIN",    SIGTTIN},
146 #endif
147 #ifdef SIGTTOU
148     {"TTOU",    SIGTTOU},
149 #endif
150 #ifdef SIGUNUSED
151     {"UNUSED",  SIGUNUSED},
152 #endif
153 #ifdef SIGURG
154     {"URG",     SIGURG},
155 #endif
156 #ifdef SIGUSR1
157     {"USR1",    SIGUSR1},
158 #endif
159 #ifdef SIGUSR2
160     {"USR2",    SIGUSR2},
161 #endif
162 #ifdef SIGVTALRM
163     {"VTALRM",  SIGVTALRM},
164 #endif
165 #ifdef SIGWAITING
166     {"WAITING", SIGWAITING},
167 #endif
168 #ifdef SIGWINCH
169     {"WINCH",   SIGWINCH},
170 #endif
171 #ifdef SIGXCPU
172     {"XCPU",    SIGXCPU},
173 #endif
174 #ifdef SIGXFSZ
175     {"XFSZ",    SIGXFSZ},
176 #endif
177 #ifdef SIGXRES
178     {"XRES",    SIGXRES},
179 #endif
180     {"",        0}
181 };
182 
183 static const int signal_name2num_count =
184     ((sizeof(signal_name2num)/sizeof(struct signal_name2num_st)) - 1);
185 
186 
187 /* Structure used when parsing a comma-separated list of numbers and ranges */
188 typedef struct sk_number_parser_st {
189     const char *sp;
190     const char *end_chars;
191     int         base;
192     uint32_t    min;
193     uint32_t    max;
194 } sk_number_parser_t;
195 
196 /* Values used by numberListParser*() to indicate success.  Error
197  * values are given by silk_utils_errcode_t. */
198 typedef enum {
199     /* Indicates numberListParserInit() initialized successfully */
200     SK_NUM_PARSER_OK = 0,
201 
202     /* Indicates numberListParserNext() parsed a single number and
203      * an optional trailing comma, e.g. "3" or "5," */
204     SK_NUM_PARSER_NUMBER,
205 
206     /* Indicates numberListParserNext() parsed a range and an
207      * optional trailing comma, e.g., "3-4" or "5-6," */
208     SK_NUM_PARSER_RANGE,
209 
210     /* Indicates numberListParserNext() parsed an open-ended range
211      * and an optional trailing comma, e.g., "3-" or "5-,".  Ranges
212      * with open-beginnings (e.g., "-7") are not allowed. */
213     SK_NUM_PARSER_RANGE_OPENMAX,
214 
215     /* Indicates numberListParserInit() or
216      * numberListParserNext() reached the end of the number list;
217      * that is, current character is NUL, or whitespace, or a
218      * character specified in the end_chars. */
219     SK_NUM_PARSER_END_OF_STRING
220 } sk_number_parser_result_t;
221 
222 
223 /*
224  *  pos = numberParserCurrentChar(p);
225  *
226  *    Returns the beginning of the token that the parser was parsing
227  *    when it encountered the error.
228  */
229 #define numberParserCurrentChar(parser) ((parser)->sp)
230 
231 
232 /*
233  *   The following macros, variables, and functions are used to set
234  *   error messages encountered when parsing something, and they work
235  *   with the silk_utils_errcode_t enumeration defined in utils.h.
236  *
237  *   The parseError() function stores an error message in the
238  *   parse_error_buf[] array, where we maintain the most recent error
239  *   for each error code.
240  *
241  *   The caller can access the messages in the array with the
242  *   skStringParseStrerror() function.
243  */
244 
245 /* this should be same magnitude as the last error code specified in
246  * silk_utils_errcode_t */
247 #define PARSE_ERRORCODE_COUNT  ((silk_utils_errcode_t)13)
248 
249 /* convert silk_utils_errcode_t 'errcode' to a positive index used to
250  * index into parse_error_buf[] and parse_error_default[].  Value with
251  * largest magnitude becomes 0; the "succcess" value of 0 becomes
252  * PARSE_ERRORCODE_COUNT. */
253 #define PARSE_ERRORCODE_TO_INDEX(errcode)       \
254     (((errcode) < -PARSE_ERRORCODE_COUNT)       \
255      ? (-1)                                     \
256      : ((errcode) + PARSE_ERRORCODE_COUNT))
257 
258 /* return default error message for silk_utils_errcode_t 'errcode' */
259 #define PARSE_ERRORCODE_MSG(errcode)                            \
260     (((errcode) < -PARSE_ERRORCODE_COUNT || (errcode) > 0)      \
261      ? ""                                                       \
262      : parse_error_default[PARSE_ERRORCODE_TO_INDEX(errcode)])
263 
264 /* hold the most recent error for each silk_utils_errcode_t */
265 static char parse_error_buf[PARSE_ERRORCODE_COUNT+1][2048];
266 
267 /* these are in reverse order of how they appear in the definition of
268  * silk_utils_errcode_t */
269 static const char *parse_error_default[PARSE_ERRORCODE_COUNT+1] = {
270     "Could not resolve hostname or port",   /* SKUTILS_ERR_RESOLVE */
271     "Value is above maximum",               /* SKUTILS_ERR_MAXIMUM */
272     "Value is below minimum",               /* SKUTILS_ERR_MINIMUM */
273     "Miscellaneous error",                  /* SKUTILS_ERR_OTHER */
274     "Out of memory",                        /* SKUTILS_ERR_ALLOC */
275     "Too many fields provided",             /* SKUTILS_ERR_TOO_MANY_FIELDS */
276     "Unexpected end-of-input",              /* SKUTILS_ERR_SHORT */
277     "Range is invalid (min > max)",         /* SKUTILS_ERR_BAD_RANGE */
278     "Value underflows the parser",          /* SKUTILS_ERR_UNDERFLOW */
279     "Value overflows the parser",           /* SKUTILS_ERR_OVERFLOW */
280     "Unexpected character",                 /* SKUTILS_ERR_BAD_CHAR */
281     "Input is empty or all whitespace",     /* SKUTILS_ERR_EMPTY */
282     "Invalid input to function",            /* SKUTILS_ERR_INVALID */
283     "Command successful"                    /* SKUTILS_OK */
284 };
285 
286 
287 #ifdef TEST_PRINTF_FORMATS
288 #  define parseError(errcode, ...) printf(__VA_ARGS__)
289 #  define PE_NULL  "ERROR"
290 #else
291 #  define PE_NULL  NULL
292 static int
293 parseError(
294     silk_utils_errcode_t    errcode,
295     const char             *fmt,
296     ...)
297     SK_CHECK_PRINTF(2, 3);
298 
299 static int
parseError(silk_utils_errcode_t errcode,const char * fmt,...)300 parseError(
301     silk_utils_errcode_t    errcode,
302     const char             *fmt,
303     ...)
304 {
305     va_list args;
306     int idx;
307     char *buf;
308 
309     idx = PARSE_ERRORCODE_TO_INDEX(errcode);
310 
311     if (idx < 0 || idx > PARSE_ERRORCODE_COUNT) {
312         return errcode;
313     }
314     buf = parse_error_buf[idx];
315 
316     if (fmt == PE_NULL) {
317         snprintf(buf, sizeof(parse_error_buf[0]), "%s",
318                  parse_error_default[idx]);
319         buf[sizeof(parse_error_buf[0])-1] = '\0';
320         return errcode;
321     }
322 
323     va_start(args, fmt);
324     vsnprintf(buf, sizeof(parse_error_buf[0]), fmt, args);
325     buf[sizeof(parse_error_buf[0])-1] = '\0';
326     va_end(args);
327     return errcode;
328 }
329 #endif /* TEST_PRINTF_FORMATS */
330 
331 
332 const char *
skStringParseStrerror(int errorcode)333 skStringParseStrerror(
334     int                 errorcode)
335 {
336     static char tmpbuf[2048];
337     int idx = PARSE_ERRORCODE_TO_INDEX(errorcode);
338 
339     if (errorcode > 0) {
340         return "Extra text follows value";
341     }
342     if (idx < 0 || idx > PARSE_ERRORCODE_COUNT) {
343         snprintf(tmpbuf, sizeof(tmpbuf), "Unrecognized error (%d)", errorcode);
344         tmpbuf[sizeof(tmpbuf)-1] = '\0';
345         return tmpbuf;
346     }
347 
348     return parse_error_buf[idx];
349 }
350 
351 
352 /* Convert integer 0 to string "0.0.0.0"; uses static buffer */
353 char *
num2dot(uint32_t ip)354 num2dot(
355     uint32_t            ip)
356 {
357     static char outbuf[SKIPADDR_STRLEN];
358     skipaddr_t ipaddr;
359 
360     skipaddrSetV4(&ipaddr, &ip);
361     return skipaddrString(outbuf, &ipaddr, SKIPADDR_CANONICAL);
362 }
363 
364 
365 /* Convert integer 0 to string "0.0.0.0"; uses caller's buffer */
366 char *
num2dot_r(uint32_t ip,char * outbuf)367 num2dot_r(
368     uint32_t            ip,
369     char               *outbuf)
370 {
371     skipaddr_t ipaddr;
372 
373     skipaddrSetV4(&ipaddr, &ip);
374     return skipaddrString(outbuf, &ipaddr, SKIPADDR_CANONICAL);
375 }
376 
377 
378 /* Convert integer 0 to string "000.000.000.000"; uses static buffer */
379 char *
num2dot0(uint32_t ip)380 num2dot0(
381     uint32_t            ip)
382 {
383     static char outbuf[SKIPADDR_STRLEN];
384     skipaddr_t ipaddr;
385 
386     skipaddrSetV4(&ipaddr, &ip);
387     return skipaddrString(outbuf, &ipaddr,
388                           SKIPADDR_CANONICAL | SKIPADDR_ZEROPAD);
389 }
390 
391 
392 /* Convert integer 0 to string "000.000.000.000"; uses caller's buffer */
393 char *
num2dot0_r(uint32_t ip,char * outbuf)394 num2dot0_r(
395     uint32_t            ip,
396     char               *outbuf)
397 {
398     skipaddr_t ipaddr;
399 
400     skipaddrSetV4(&ipaddr, &ip);
401     return skipaddrString(outbuf, &ipaddr,
402                           SKIPADDR_CANONICAL | SKIPADDR_ZEROPAD);
403 }
404 
405 
406 /* Convert integer to FSRPAUEC string.  Uses caller's buffer. */
407 char *
skTCPFlagsString(uint8_t flags,char * outbuf,unsigned int print_flags)408 skTCPFlagsString(
409     uint8_t             flags,
410     char               *outbuf,
411     unsigned int        print_flags)
412 {
413     static const char characters[] = {'F', 'S', 'R', 'P', 'A', 'U', 'E', 'C'};
414     static const uint8_t bits[] = {FIN_FLAG, SYN_FLAG, RST_FLAG, PSH_FLAG,
415                                    ACK_FLAG, URG_FLAG, ECE_FLAG, CWR_FLAG};
416     int i;
417     char *c = outbuf;
418 
419     for (i = 0; i < 8; i++) {
420         if (flags & bits[i]) {
421             *c = characters[i];
422             ++c;
423         } else if (print_flags & SK_PADDED_FLAGS) {
424             *c = ' ';
425             ++c;
426         }
427     }
428     *c = '\0';
429     return outbuf;
430 }
431 
432 /* Deprecated */
433 char *
tcpflags_string_r(uint8_t flags,char * outbuf)434 tcpflags_string_r(
435     uint8_t             flags,
436     char               *outbuf)
437 {
438     return skTCPFlagsString(flags, outbuf, SK_PADDED_FLAGS);
439 }
440 
441 /* Deprecated */
442 char *
tcpflags_string(uint8_t flags)443 tcpflags_string(
444     uint8_t             flags)
445 {
446     static char flag_string[SK_TCPFLAGS_STRLEN];
447     return skTCPFlagsString(flags, flag_string, SK_PADDED_FLAGS);
448 }
449 
450 
451 /* Convert integer to TCP state string.  Uses caller's buffer. */
452 char *
skTCPStateString(uint8_t state,char * outbuf,unsigned int print_flags)453 skTCPStateString(
454     uint8_t             state,
455     char               *outbuf,
456     unsigned int        print_flags)
457 {
458 #define SKTCPSTATE_NUM_BITS 4
459     static const char characters[] = {'T', 'C', 'F', 'S'};
460     static const uint8_t bits[] = {SK_TCPSTATE_TIMEOUT_KILLED,
461                                    SK_TCPSTATE_TIMEOUT_STARTED,
462                                    SK_TCPSTATE_FIN_FOLLOWED_NOT_ACK,
463                                    SK_TCPSTATE_UNIFORM_PACKET_SIZE};
464     int i;
465     char *c = outbuf;
466 
467     for (i = 0; i < SKTCPSTATE_NUM_BITS; i++) {
468         if (state & bits[i]) {
469             *c = characters[i];
470             ++c;
471         } else if (print_flags & SK_PADDED_FLAGS) {
472             *c = ' ';
473             ++c;
474         }
475     }
476     if (print_flags & SK_PADDED_FLAGS) {
477         for (/*empty*/; i < 8; i++) {
478             *c = ' ';
479             ++c;
480         }
481     }
482     *c = '\0';
483     return outbuf;
484 }
485 
486 
487 /* strip whitespace of line in-place; return length */
488 int
skStrip(char * line)489 skStrip(
490     char               *line)
491 {
492     char *sp, *ep;
493     int len;
494 
495     sp  = line;
496     while ( *sp && isspace((int)*sp) ) {
497         sp++;
498     }
499     /* at first non-space char OR at end of line */
500     if (*sp == '\0') {
501         /* line full of white space. nail at beginning and return with 0 */
502         line[0] = '\0';
503         return 0;
504     }
505 
506     /* figure out where to stop the line */
507     ep = sp + strlen(sp) - 1;
508     while ( isspace((int)*ep) && (ep > sp) ) {
509         ep--;
510     }
511     /* ep at last non-space char. Nail after */
512     ep++;
513     *ep = '\0';
514 
515     len = (int)(ep - sp);
516     if (sp == line) {
517         /* no shifting required */
518         return(len);
519     }
520 
521     memmove(line, sp, len+1);
522     return(len);
523 }
524 
525 
526 /* Down-case 'cp' in place */
527 void
skToLower(char * cp)528 skToLower(
529     char               *cp)
530 {
531     while (*cp) {
532         if (isupper((int)*cp)) {
533             *cp = *cp + 32;
534         }
535         cp++;
536     }
537     return;
538 }
539 
540 
541 /* Up-case 'cp' in place */
542 void
skToUpper(char * cp)543 skToUpper(
544     char               *cp)
545 {
546     while (*cp) {
547         if (islower((int)*cp)) {
548             *cp = *cp - 32;
549         }
550         cp++;
551     }
552     return;
553 }
554 
555 
556 /*
557  *  result = numberListParserInit(&p,input,base,end_chars,minimum,maximum);
558  *
559  *    Fills in the sk_number_parser_t data structure---which should
560  *    have been declared and allocated by the caller---pointed at by
561  *    'p' with state necessary to call numberListParserNext().
562  *
563  *    The caller must not modify 'input' while the
564  *    numberListParserNext() function is in use.
565  *
566  *    'end_chars' should be NULL or a string listing characters to be
567  *    considered, in addition to whitespace, as end-of-input markers.
568  *
569  *    'mimimum' and 'maximum' define the allowable range for numbers
570  *    in the list.
571  *
572  *    On success, SK_NUM_PARSER_OK is returned.  If the string is
573  *    empty or begins with a character listed in 'end_chars',
574  *    SK_NUM_PARSER_END_OF_STRING is returned.  Otherwise, this
575  *    function returns a silk_utils_errcode_t value.
576  */
577 static int
numberListParserInit(sk_number_parser_t * parser,const char * input,int base,const char * end_chars,uint32_t minimum,uint32_t maximum)578 numberListParserInit(
579     sk_number_parser_t *parser,
580     const char         *input,
581     int                 base,
582     const char         *end_chars,
583     uint32_t            minimum,
584     uint32_t            maximum)
585 {
586     /* check input */
587     assert(parser);
588     assert(input);
589     assert(base == 10 || base == 16);
590 
591     if (maximum == 0) {
592         maximum = UINT32_MAX;
593     } else if (minimum > maximum) {
594         return parseError(SKUTILS_ERR_INVALID,
595                           ("Range maximum (%" PRIu32 ") is less than"
596                            " range minimum (%" PRIu32 ")"),
597                           maximum, minimum);
598     }
599 
600     if (*input == '\0') {
601         return SK_NUM_PARSER_END_OF_STRING;
602     }
603     if (isspace((int)*input)) {
604         return SK_NUM_PARSER_END_OF_STRING;
605     }
606     if (end_chars && (strchr(end_chars, *input))) {
607         return SK_NUM_PARSER_END_OF_STRING;
608     }
609 
610     if (base == 10 && !isdigit((int)*input)) {
611         return parseError(SKUTILS_ERR_BAD_CHAR, "%s at '%c'",
612                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *input);
613     } else if (base == 16 && !isxdigit((int)*input)) {
614         return parseError(SKUTILS_ERR_BAD_CHAR, "%s at '%c'",
615                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *input);
616     }
617 
618     parser->min = minimum;
619     parser->max = maximum;
620     parser->sp = input;
621     parser->end_chars = end_chars;
622     parser->base = base;
623     return SK_NUM_PARSER_OK;
624 }
625 
626 
627 /*
628  *  result = numberListParserNext(&out_val, &out_length, p);
629  *
630  *    Parse the next number or range in the 'input' that was used to
631  *    initialize the sk_number_parser_t 'p'.
632  *
633  *    If the next token is a single number ("3,"), its value is stored
634  *    in 'out_val', 1 is stored in 'out_length', and
635  *    SK_NUM_PARSER_NUMBER is returned.
636  *
637  *    If the next token is a range ("2-4,"), the starting value (2) is
638  *    stored in 'out_val', the number of elements in the range (3) is
639  *    stored in 'out_length', and SK_NUM_PARSER_RANGE is returned.
640  *
641  *    When there are no more tokens in 'input',
642  *    SK_NUM_PARSER_END_OF_STRING is returned.
643  *
644  *    Any other return value indicates an error.
645  */
646 static int
numberListParserNext(uint64_t * range_length,uint32_t * value,sk_number_parser_t * parser)647 numberListParserNext(
648     uint64_t           *range_length,
649     uint32_t           *value,
650     sk_number_parser_t *parser)
651 {
652     unsigned long n = 0;
653     const char *sp;
654     char *ep;
655     int rv;
656 
657     /* check input */
658     assert(parser);
659     assert(value);
660     assert(range_length);
661 
662     /* initialize vars */
663     *value = 0;
664     *range_length = 0;
665     sp = parser->sp;
666 
667     /* are we at end of list? */
668     if (*sp == '\0') {
669         return SK_NUM_PARSER_END_OF_STRING;
670     }
671     if (isspace((int)*sp)) {
672         return SK_NUM_PARSER_END_OF_STRING;
673     }
674     if (parser->end_chars && (strchr(parser->end_chars, *sp))) {
675         return SK_NUM_PARSER_END_OF_STRING;
676     }
677 
678     while (*sp) {
679         /* parse the number */
680         errno = 0;
681         n = strtoul(sp, &ep, parser->base);
682         if (sp == ep) {
683             rv = parseError(SKUTILS_ERR_BAD_CHAR, "%s at '%c'",
684                             PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *sp);
685             goto END;
686         }
687         if (n == ULONG_MAX && errno == ERANGE) {
688             rv = parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
689             goto END;
690         }
691         if (n < parser->min) {
692             rv = parseError(SKUTILS_ERR_MINIMUM, "%s of %" PRIu32,
693                             PARSE_ERRORCODE_MSG(SKUTILS_ERR_MINIMUM),
694                             parser->min);
695             goto END;
696         }
697         if (n > parser->max) {
698             rv = parseError(SKUTILS_ERR_MAXIMUM, "%s of %" PRIu32,
699                             PARSE_ERRORCODE_MSG(SKUTILS_ERR_MAXIMUM),
700                             parser->max);
701             goto END;
702         }
703 
704         /* parsed the number; move pointer to next token */
705         sp = ep;
706 
707         /* see if we are parsing a range; if so, store the first
708          * number (lower limit) and loop through the while again in
709          * order to parse the second number (upper limit). */
710         if (*sp != '-') {
711             break;
712         } else if (*range_length != 0) {
713             /* second pass through the while loop yet we're looking at
714              * another hyphen.  We've got something like "1-2-".  An
715              * error */
716             rv = parseError(SKUTILS_ERR_BAD_CHAR, "%s at '%c'",
717                             PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *sp);
718             goto END;
719         } else {
720             /* first pass, we just parsed lower limit */
721             ++sp;
722             if ((parser->base == 10 && isdigit((int)*sp))
723                 || (parser->base == 16 && isxdigit((int)*sp)))
724             {
725                 /* looks like a good range; store the value we just
726                  * parsed, set range_length so we know we're in a
727                  * range, and loop again */
728                 *value = n;
729                 *range_length = 1;
730                 continue;
731             } else if (*sp == '\0' || *sp == ',') {
732                 /* open-ended range, store current value, use
733                  * range_length to denote open-ended range, set n to
734                  * the max */
735                 *value = n;
736                 *range_length = 2;
737                 n = parser->max;
738                 break;
739             } else {
740                 rv = parseError(SKUTILS_ERR_BAD_CHAR, "%s at '%c'",
741                                 PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
742                                 *sp);
743                 goto END;
744             }
745         }
746     }
747 
748     /* we've parsed a number or a range */
749     if (*range_length == 0) {
750         /* single number */
751         *value = n;
752         *range_length = 1;
753         rv =  SK_NUM_PARSER_NUMBER;
754     } else if (*range_length == 2) {
755         *range_length = (n - *value + 1);
756         rv = SK_NUM_PARSER_RANGE_OPENMAX;
757     } else if (n == *value) {
758         /* range of 3-3; treat as single number */
759         rv =  SK_NUM_PARSER_NUMBER;
760     } else if (n < *value) {
761         rv = parseError(SKUTILS_ERR_BAD_RANGE,
762                         ("%s (%" PRIu32 "-%lu)"),
763                         PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_RANGE),
764                         *value, n);
765         goto END;
766     } else {
767         *range_length = (n - *value + 1);
768         rv =  SK_NUM_PARSER_RANGE;
769     }
770 
771     /* move forward to the start of the next number. */
772     while (*sp) {
773         if (isspace((int)*sp)) {
774             /* this marks the end of the number list */
775             break;
776         }
777         if (parser->end_chars && (strchr(parser->end_chars, *sp))) {
778             /* this also marks the end of the number list */
779             break;
780         }
781         if ((parser->base == 10 && isdigit((int)*sp))
782             || (parser->base == 16 && isxdigit((int)*sp)))
783         {
784             /* this is what we expect*/
785             break;
786         }
787         if (*sp == ',') {
788             /* duplicate comma is allowed */
789             ++sp;
790             continue;
791         }
792         if (*sp == '-') {
793             /* error */
794             rv = parseError(SKUTILS_ERR_BAD_CHAR, "%s at '%c'",
795                             PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
796                             *sp);
797             goto END;
798         }
799 
800         /* error */
801         rv = parseError(SKUTILS_ERR_BAD_CHAR, "%s at '%c'",
802                         PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
803                         *sp);
804         goto END;
805     }
806 
807   END:
808     /* store our current location */
809     parser->sp = sp;
810     return rv;
811 }
812 
813 
814 /* parse string "4,3,2-6" to array {4,3,2,3,4,5,6}.  See header for details */
815 int
skStringParseNumberList(uint32_t ** number_list,uint32_t * number_count,const char * input,uint32_t min_value,uint32_t max_value,uint32_t max_number_count)816 skStringParseNumberList(
817     uint32_t          **number_list,
818     uint32_t           *number_count,
819     const char         *input,
820     uint32_t            min_value,
821     uint32_t            max_value,
822     uint32_t            max_number_count)
823 {
824     uint64_t range_length;
825     uint64_t i;
826     uint32_t range_start;
827     uint32_t *out_array_list = NULL; /* returned array */
828     uint32_t out_count = 0; /* returned count */
829     uint32_t array_size;
830     sk_number_parser_t parser;
831     const char *sp;
832     int rv = SKUTILS_OK;
833 
834     /* check input */
835     assert(number_list);
836     assert(number_count);
837     if (input == NULL) {
838         return parseError(SKUTILS_ERR_INVALID, PE_NULL);
839     }
840 
841     /* eat leading whitespace */
842     sp = input;
843     while (*sp && isspace((int)*sp)) {
844         ++sp;
845     }
846     if ('\0' == *sp) {
847         /* whitespace only or empty string */
848         return parseError(SKUTILS_ERR_EMPTY, PE_NULL);
849     }
850 
851     rv = numberListParserInit(&parser, sp, 10, NULL, min_value, max_value);
852     if (rv != SK_NUM_PARSER_OK) {
853         return rv;
854     }
855 
856     /* If no max count was given, assume the user is only allowed to
857      * choose each item one time, and set the max_number_count to the
858      * number of items. */
859     if (max_number_count == 0) {
860         if (max_value != 0) {
861             max_number_count = 1 + max_value - min_value;
862         } else {
863             /* something big */
864             max_number_count = (1 << 24);
865         }
866     }
867 
868     /* Create the array to hold the list of values.  If
869      * max_number_count is greater than 256, use half of it as the
870      * initial size; otherwise, create an array of max_number_count
871      * entries. */
872     if (max_number_count <= 256) {
873         array_size = max_number_count;
874     } else {
875         array_size = max_number_count / 2;
876     }
877     out_array_list = (uint32_t*)calloc(array_size, sizeof(uint32_t));
878     if (!out_array_list) {
879         rv = parseError(SKUTILS_ERR_ALLOC, PE_NULL);
880         goto ERROR;
881     }
882 
883     while ((rv = numberListParserNext(&range_length, &range_start, &parser))
884            != SK_NUM_PARSER_END_OF_STRING)
885     {
886         if (rv < 0) {
887             goto ERROR;
888         }
889         switch ((sk_number_parser_result_t)rv) {
890           case SK_NUM_PARSER_OK:
891           case SK_NUM_PARSER_END_OF_STRING:
892             /* these should not occur */
893             skAbortBadCase(rv);
894 
895           case SK_NUM_PARSER_RANGE_OPENMAX:
896             rv = parseError(SKUTILS_ERR_BAD_CHAR,
897                             ("Range is missing its upper limit"
898                              " (open-ended ranges are not supported)"));
899             goto ERROR;
900 
901           case SK_NUM_PARSER_NUMBER:
902           case SK_NUM_PARSER_RANGE:
903             /* check number of fields user gave */
904             if ((out_count + range_length) > max_number_count) {
905                 rv = parseError(SKUTILS_ERR_TOO_MANY_FIELDS,
906                                 ("Too many fields (%" PRIu64 ") provided;"
907                                  " only %" PRIu32 " fields allowed"),
908                                 (range_length + out_count), max_number_count);
909                 goto ERROR;
910             }
911 
912             /* check if we need to grow array?  If so, realloc the array
913              * to double its size and memset the new section to 0. */
914             while ((out_count + range_length) > array_size) {
915                 size_t old_size = array_size;
916                 uint32_t *old_array = out_array_list;
917                 array_size *= 2;
918                 if (array_size > max_number_count) {
919                     array_size = max_number_count;
920                 }
921                 out_array_list = (uint32_t*)realloc(
922                     out_array_list, array_size * sizeof(uint32_t));
923                 if (!out_array_list) {
924                     out_array_list = old_array;
925                     rv = parseError(SKUTILS_ERR_ALLOC, PE_NULL);
926                     goto ERROR;
927                 }
928                 memset((out_array_list+old_size), 0,
929                        (array_size-old_size) * sizeof(uint32_t));
930             }
931 
932             /* add the entries */
933             for (i = 0; i < range_length; ++i, ++range_start, ++out_count) {
934                 out_array_list[out_count] = range_start;
935             }
936             break;
937         }
938     }
939 
940     assert(rv == SK_NUM_PARSER_END_OF_STRING);
941     rv = SKUTILS_OK;
942 
943     /* handle any whitespace at end of string */
944     sp = numberParserCurrentChar(&parser);
945     while (isspace((int)*sp)) {
946         ++sp;
947     }
948     if (*sp != '\0') {
949         rv = parseError(SKUTILS_ERR_BAD_CHAR,
950                         "%s--embedded whitespace found in input",
951                         PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR));
952         goto ERROR;
953     }
954 
955     *number_count = out_count;
956     *number_list = out_array_list;
957     return rv;
958 
959   ERROR:
960     if (out_array_list) {
961         free(out_array_list);
962     }
963     *number_count = 0;
964     return rv;
965 }
966 
967 
968 /* parse string "4,3,2-6" to skbitmap.  See header for details */
969 int
skStringParseNumberListToBitmap(sk_bitmap_t * out_bitmap,const char * input)970 skStringParseNumberListToBitmap(
971     sk_bitmap_t        *out_bitmap,
972     const char         *input)
973 {
974     uint64_t range_length;
975     uint64_t i;
976     uint32_t value;
977     uint32_t bitmap_size;
978     sk_number_parser_t parser;
979     const char *sp;
980     int rv;
981 
982     memset(&parser, 0, sizeof(parser));
983 
984     /* check input */
985     assert(out_bitmap);
986     if (input == NULL) {
987         return parseError(SKUTILS_ERR_INVALID, PE_NULL);
988     }
989 
990     /* check bitmap size */
991     bitmap_size = skBitmapGetSize(out_bitmap);
992     if (bitmap_size < 1) {
993         /* bitmap too small */
994         return parseError(SKUTILS_ERR_INVALID, "Bitmap is too small");
995     }
996 
997     /* eat leading whitespace */
998     sp = input;
999     while (*sp && isspace((int)*sp)) {
1000         ++sp;
1001     }
1002     if ('\0' == *sp) {
1003         /* whitespace only or empty string */
1004         return parseError(SKUTILS_ERR_EMPTY, PE_NULL);
1005     }
1006 
1007     rv = numberListParserInit(&parser, sp, 10, NULL, 0, bitmap_size-1);
1008     if (rv != SK_NUM_PARSER_OK) {
1009         return rv;
1010     }
1011 
1012     while ((rv = numberListParserNext(&range_length, &value, &parser))
1013            != SK_NUM_PARSER_END_OF_STRING)
1014     {
1015         if (rv < 0) {
1016             return rv;
1017         }
1018         switch ((sk_number_parser_result_t)rv) {
1019           case SK_NUM_PARSER_NUMBER:
1020           case SK_NUM_PARSER_RANGE:
1021           case SK_NUM_PARSER_RANGE_OPENMAX:
1022             /* add the entries */
1023             for (i = 0; i < range_length; ++i, ++value) {
1024                 skBitmapSetBit(out_bitmap, value);
1025             }
1026             break;
1027 
1028           case SK_NUM_PARSER_OK:
1029           case SK_NUM_PARSER_END_OF_STRING:
1030             /* impossible */
1031             skAbortBadCase(rv);
1032         }
1033     }
1034 
1035     assert(rv == SK_NUM_PARSER_END_OF_STRING);
1036 
1037     /* handle any whitespace at end of string */
1038     sp = numberParserCurrentChar(&parser);
1039     while (isspace((int)*sp)) {
1040         ++sp;
1041     }
1042     if (*sp != '\0') {
1043         return parseError(SKUTILS_ERR_BAD_CHAR,
1044                           "%s--embedded whitespace found in input",
1045                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR));
1046     }
1047 
1048     return SKUTILS_OK;
1049 }
1050 
1051 
1052 /*
1053  *  status = parseIPv4(&ip_value, ip_string);
1054  *
1055  *    A helper function for skStringParseIP().
1056  *
1057  *    Parse the IPv4 address at 'ip_string' and put the result--in
1058  *    native byte order--into the memory pointed at by 'ip_value'.
1059  *    Return a negative (silk_utils_errcode_t) value on error;
1060  *    otherwise return a positive value specifying the number of
1061  *    characters that were parsed.
1062  */
1063 static int
parseIPv4(uint32_t * ip,const char * ip_string)1064 parseIPv4(
1065     uint32_t           *ip,
1066     const char         *ip_string)
1067 {
1068     unsigned long final = 0;
1069     unsigned long val;
1070     const char *sp = ip_string;
1071     char *ep;
1072     int i;
1073 
1074     *ip = 0;
1075 
1076     /* number that begins with '-' is not unsigned */
1077     if ('-' == *sp) {
1078         return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1079                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1080                           *sp);
1081     }
1082 
1083     for (i = 3; i >= 0; --i) {
1084         /* parse the number */
1085         errno = 0;
1086         val = strtoul(sp, &ep, 10);
1087         if (sp == ep) {
1088             /* parse error */
1089             return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1090                               PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *sp);
1091         }
1092         if (val == ULONG_MAX && errno == ERANGE) {
1093             /* overflow */
1094             if (i == 3) {
1095                 /* entire value is too large */
1096                 return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
1097             }
1098             /* octet value is too large */
1099             return parseError(SKUTILS_ERR_OVERFLOW,
1100                               "IP octet %d is too large", (4 - i));
1101         }
1102         if (val > UINT8_MAX) {
1103             if (i == 3 && *ep != '.') {
1104                 /* treat as a single integer */
1105 #if (SK_SIZEOF_LONG > 4)
1106                 if (val > UINT32_MAX) {
1107                     return parseError(SKUTILS_ERR_MAXIMUM,
1108                                       "Integer too large for IPv4: %lu", val);
1109                 }
1110 #endif
1111                 sp = ep;
1112                 final = val;
1113                 break;
1114             }
1115             /* value too big for octet */
1116             return parseError(SKUTILS_ERR_MAXIMUM,
1117                               "IP octet %d is too large: %lu", (4 - i), val);
1118         }
1119 
1120         sp = ep;
1121         if (*sp != '.') {
1122             if (i == 3) {
1123                 /* treat as a single integer */
1124                 assert(val <= UINT8_MAX);
1125                 final = val;
1126                 break;
1127             }
1128             if (i != 0) {
1129                 if (*sp == '\0') {
1130                     return parseError(SKUTILS_ERR_SHORT, PE_NULL);
1131                 }
1132                 /* need a '.' between octets */
1133                 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1134                                   PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1135                                   *sp);
1136             }
1137             /* else i == 0 and we've finished parsing */
1138         } else if (i == 0) {
1139             /* found a trailing '.' */
1140             return parseError(SKUTILS_ERR_BAD_CHAR,
1141                               "Found '%c' after fourth octet", *sp);
1142         } else {
1143             /* move to start of next octet */
1144             ++sp;
1145             if (!isdigit((int)*sp)) {
1146                 /* error: only '.' and digits are allowed */
1147                 if (*sp == '\0') {
1148                     return parseError(SKUTILS_ERR_SHORT, PE_NULL);
1149                 }
1150                 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1151                                   PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1152                                   *sp);
1153             }
1154         }
1155 
1156         final |= val << (8 * i);
1157     }
1158 
1159     *ip = (uint32_t)final;
1160     return (sp - ip_string);
1161 }
1162 
1163 #if SK_ENABLE_IPV6
1164 /*
1165  *  status = parseIPv6(&ipaddr, ip_string);
1166  *
1167  *    A helper function for skStringParseIP().
1168  *
1169  *    Parse the IPv6 address at 'ip_string' and put the result--in
1170  *    native byte order--into the memory pointed at by 'ip_value'.
1171  *    Return a negative (silk_utils_errcode_t) value on error;
1172  *    otherwise return a positive value specifying the number of
1173  *    characters that were parsed.
1174  */
1175 static int
parseIPv6(skipaddr_t * ipaddr,const char * ip_string)1176 parseIPv6(
1177     skipaddr_t         *ipaddr,
1178     const char         *ip_string)
1179 {
1180     uint8_t ipv6[16];
1181     unsigned int double_colon = UINT_MAX;
1182     unsigned long val;
1183     unsigned int i;
1184     const char *sp = ip_string;
1185     char *ep;
1186 
1187     /* handle a "::" at the start of the address */
1188     if (':' == *sp) {
1189         if (':' != *(sp + 1)) {
1190             /* address cannot begin with single ':' */
1191             return parseError(SKUTILS_ERR_BAD_CHAR,
1192                               "IP address cannot begin with single ':'");
1193         }
1194         if (':' == *(sp + 2)) {
1195             /* triple colon */
1196             return parseError(SKUTILS_ERR_BAD_CHAR,
1197                               "Unexpected character :::");
1198         }
1199         double_colon = 0;
1200         sp += 2;
1201     }
1202 
1203     for (i = 0; i < 8; ++i) {
1204         /* expecting a base-16 number */
1205         if (!isxdigit((int)*sp)) {
1206             if (double_colon != UINT_MAX) {
1207                 /* treat as end of string */
1208                 break;
1209             }
1210             if (*sp == '\0') {
1211                 return parseError(SKUTILS_ERR_SHORT,
1212                                   "Too few IP sections given");
1213             }
1214             return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1215                               PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1216                               *sp);
1217         }
1218 
1219         /* parse the number */
1220         errno = 0;
1221         val = strtoul(sp, &ep, 16);
1222         if (sp == ep) {
1223             if (double_colon != UINT_MAX) {
1224                 /* treat as end of string */
1225                 break;
1226             }
1227             /* parse error */
1228             return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1229                               PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1230                               *sp);
1231         }
1232         if (val == ULONG_MAX && errno == ERANGE) {
1233             /* overflow */
1234             return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
1235         }
1236         if (val > UINT16_MAX) {
1237             /* value too big for octet */
1238             return parseError(SKUTILS_ERR_MAXIMUM,
1239                               "Value in IP section %u is too large",
1240                               i + 1);
1241         }
1242 
1243         /* if a dot follows the number we just parsed, treat that
1244          * number as the start of an embedded IPv4 address. */
1245         if (*ep == '.') {
1246             unsigned int j;
1247             uint32_t ipv4;
1248             int rv;
1249 
1250             if (i > 6) {
1251                 return parseError(SKUTILS_ERR_BAD_CHAR,
1252                                   ("Too many sections before"
1253                                    " embedded IPv4"));
1254             }
1255             /* IPv4 address */
1256             rv = parseIPv4(&ipv4, sp);
1257             if (rv < 0) {
1258                 return rv;
1259             }
1260 
1261             for (j = 0; j < 4; ++j) {
1262                 ipv6[2*i+j] = ((ipv4 >> (8 * (3 - j))) & 0xFF);
1263             }
1264             sp += rv;
1265             i += 2;
1266             if (*sp == ':') {
1267                 /* Must not have more IPv6 after the IPv4 addr */
1268                 return parseError(SKUTILS_ERR_BAD_CHAR,
1269                                   "Found '%c' after final section", *sp);
1270             }
1271             break;
1272         }
1273 
1274         ipv6[2*i] = ((val >> 8) & 0xFF);
1275         ipv6[2*i+1] = (val & 0xFF);
1276         sp = ep;
1277 
1278         /* handle section separator */
1279         if (*sp != ':') {
1280             if (i != 7) {
1281                 if (double_colon != UINT_MAX) {
1282                     /* treat as end of string */
1283                     ++i;
1284                     break;
1285                 }
1286                 if (*sp == '\0') {
1287                     return parseError(SKUTILS_ERR_SHORT,
1288                                       "Too few IP sections given");
1289                 }
1290                 /* need a ':' between sections */
1291                 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1292                                   PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1293                                   *sp);
1294             }
1295             /* else i == 7 and we've finished parsing */
1296         } else if (i == 7) {
1297             return parseError(SKUTILS_ERR_BAD_CHAR,
1298                               "Found '%c' after final section", *sp);
1299         } else {
1300             /* move to start of next section */
1301             ++sp;
1302             if (':' == *sp) {
1303                 if (double_colon != UINT_MAX) {
1304                     /* parse error */
1305                     return parseError(SKUTILS_ERR_BAD_CHAR,
1306                                       "Only one :: instance allowed");
1307                 }
1308                 if (':' == *(sp + 1)) {
1309                     /* triple colon */
1310                     return parseError(SKUTILS_ERR_BAD_CHAR,
1311                                       "Unexpected character :::");
1312                 }
1313                 double_colon = i + 1;
1314                 ++sp;
1315             } else if (*sp == '\0') {
1316                 return parseError(SKUTILS_ERR_SHORT,
1317                                   "Expecting IP section value after ':'");
1318             } else if (!isxdigit((int)*sp)) {
1319                 /* number must follow lone ':' */
1320                 return
1321                     parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1322                                PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1323                                *sp);
1324             }
1325         }
1326     }
1327 
1328     if (double_colon != UINT_MAX) {
1329         if (i == 8) {
1330             /* error */
1331             return parseError(SKUTILS_ERR_BAD_CHAR,
1332                               "Cannot have '::' in IP with 8 sections");
1333         }
1334         memmove(&ipv6[2*(8+double_colon-i)], &ipv6[2*double_colon],
1335                 2*(i-double_colon));
1336         memset(&ipv6[2*double_colon], 0, 2*(8-i));
1337     } else if (i != 8) {
1338         /* error */
1339         return parseError(SKUTILS_ERR_SHORT,
1340                           "Only %u/8 IP sections specified", i);
1341     }
1342 
1343     skipaddrSetV6(ipaddr, ipv6);
1344     return (sp - ip_string);
1345 }
1346 #endif /* SK_ENABLE_IPV6 */
1347 
1348 /* Parse a string as an IPv4 or IPv6 address.  If the string is a
1349  * single integer, treat is an an IPv4 address. */
1350 int
skStringParseIP(skipaddr_t * out_val,const char * ip_string)1351 skStringParseIP(
1352     skipaddr_t         *out_val,
1353     const char         *ip_string)
1354 {
1355     const char *sp;
1356     const char *dot;
1357     const char *colon;
1358     int rv;
1359 
1360     /* verify input */
1361     if (!ip_string) {
1362         return parseError(SKUTILS_ERR_INVALID, PE_NULL);
1363     }
1364 
1365     /* skip leading whitespace */
1366     sp = ip_string;
1367     while (isspace((int)*sp)) {
1368         ++sp;
1369     }
1370     if ('\0' == *sp) {
1371         /* whitespace only or empty string */
1372         return parseError(SKUTILS_ERR_EMPTY, PE_NULL);
1373     }
1374 
1375     /* determine if IPv4 or IPv6 */
1376     dot = strchr(sp, '.');
1377     colon = strchr(sp, ':');
1378     if (colon == NULL) {
1379         /* no ':', so must be IPv4 or an integer */
1380     } else if (dot == NULL) {
1381         /* no '.', so must be IPv6 */
1382     } else if ((dot - sp) < (colon - sp)) {
1383         /* dot appears first, assume IPv4 */
1384         colon = NULL;
1385     } else {
1386         /* colon appears first, assume IPv6 */
1387         dot = NULL;
1388     }
1389 
1390     /* parse the address */
1391     if (NULL == colon) {
1392         /* an IPv4 address */
1393         uint32_t ipv4;
1394 
1395         rv = parseIPv4(&ipv4, sp);
1396         if (rv < 0) {
1397             return rv;
1398         }
1399         skipaddrSetV4(out_val, &ipv4);
1400     } else
1401 #if SK_ENABLE_IPV6
1402     {
1403         /* an IPv6 address */
1404         rv = parseIPv6(out_val, sp);
1405         if (rv < 0) {
1406             return rv;
1407         }
1408     }
1409 #else  /* SK_ENABLE_IPV6 */
1410     {
1411         /* an IPv6 address but no IPv6 support */
1412         return parseError(SKUTILS_ERR_BAD_CHAR,
1413                           "%s ':'--IPv6 addresses not supported",
1414                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR));
1415     }
1416 #endif  /* #else of #if SK_ENABLE_IPV6 */
1417 
1418     sp += rv;
1419 
1420     /* ignore trailing whitespace, but only if we reach the end of the
1421      * string.  cache the current position. */
1422     rv = (sp - ip_string);
1423     while (isspace((int)*sp)) {
1424         ++sp;
1425     }
1426 
1427     if ('\0' != *sp) {
1428         /* text after IP, return the cached position */
1429         return rv;
1430     }
1431     return SKUTILS_OK;
1432 }
1433 
1434 
1435 int
skStringParseIPWildcard(skIPWildcard_t * ipwild,const char * ip_string)1436 skStringParseIPWildcard(
1437     skIPWildcard_t     *ipwild,
1438     const char         *ip_string)
1439 {
1440     /* number of octets (or hexadectets for IPv6) */
1441     uint32_t num_blocks = 4;
1442     /* number of bits per octet/hexadectet */
1443     uint32_t block_size = 8;
1444     /* max value for any octet/hexadectet */
1445     uint32_t block_max_value = ((1 << block_size) - 1);
1446     /* base to use for parsing octet/hexadectet values */
1447     int block_base;
1448     /* character string between octets/hexadectets */
1449     const char *block_sep;
1450     uint64_t i;
1451     uint32_t range_start = 0;
1452     uint64_t range_length = 0;
1453     unsigned long val = 0;
1454     uint32_t block = 0;
1455     uint32_t double_colon = UINT32_MAX;
1456     sk_number_parser_t parser;
1457     skipaddr_t ipaddr;
1458     uint32_t cidr = 0;
1459     const char *sp;
1460     int rv;
1461 #if SK_ENABLE_IPV6
1462     const char *v4_in_v6 = NULL;
1463 #endif
1464 
1465     /* try to parse as an ordinary IP address */
1466     rv = skStringParseIP(&ipaddr, ip_string);
1467 
1468     /* return if we get any error other than BAD_CHAR */
1469     if (rv < 0 && rv != SKUTILS_ERR_BAD_CHAR) {
1470         return rv;
1471     }
1472 
1473     /* If rv > 0, we parsed an IP but there is extra text.  We could
1474      * be looking at the slash for CIDR notation or at a list for the
1475      * final block; e.g., "0.0.0.1-100" or "0.0.0.1,2".  If we are on
1476      * the slash, reset rv to SKUTILS_OK; otherwise, if we are looking
1477      * at anything other than ',' or '-', return error.  For IPv6, we
1478      * may be looking at "0::x". */
1479     if (rv > 0) {
1480         sp = &ip_string[rv];
1481         if (*sp == '/') {
1482             ++sp;
1483             if (*sp == '\0') {
1484                 return parseError(SKUTILS_ERR_BAD_CHAR,
1485                                   "%s '%c'--expected CIDR after slash",
1486                                   PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1487                                   *sp);
1488             }
1489             if (!isdigit((int)*sp)) {
1490                 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1491                                   PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1492                                   *sp);
1493             }
1494 
1495             /* parse the CIDR value */
1496             rv = skStringParseUint32(&cidr, sp, 1,
1497                                      (skipaddrIsV6(&ipaddr) ? 128 : 32));
1498             if (rv != 0) {
1499                 if (rv < 0) {
1500                     return rv;
1501                 }
1502                 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1503                                   PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1504                                   sp[rv]);
1505             }
1506         } else if (isspace((int)*sp)) {
1507             return parseError(SKUTILS_ERR_BAD_CHAR,
1508                               "%s '%c' embedded whitespace is not allowed",
1509                               PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1510                               *sp);
1511 #if SK_ENABLE_IPV6
1512         } else if (skipaddrIsV6(&ipaddr) && (*sp == 'x' || *sp == 'X')) {
1513             /* try to parse as wildcard */
1514 #endif /* SK_ENABLE_IPV6 */
1515         } else if (*sp != '-' && *sp != ',') {
1516             return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1517                               PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1518                               *sp);
1519         }
1520     }
1521 
1522     /* clear the ipwildcard */
1523     skIPWildcardClear(ipwild);
1524 
1525     if (rv == SKUTILS_OK) {
1526 #if SK_ENABLE_IPV6
1527         if (skipaddrIsV6(&ipaddr)) {
1528             uint8_t ip6[16];
1529 
1530             skipaddrGetV6(&ipaddr, &ip6);
1531             ipwild->num_blocks = 8;
1532 
1533             num_blocks = 8;
1534             block_size = 16;
1535             block_max_value = (1 << block_size) - 1;
1536 
1537             /* set each block as if no CIDR */
1538             for (block = 0; block < num_blocks; ++block) {
1539                 val = (ip6[2*block] << 8 | ip6[1+2*block]);
1540                 ipwild->m_blocks[block][_BMAP_INDEX(val)] = _BMAP_OFFSET(val);
1541                 ipwild->m_min[block] = val;
1542                 ipwild->m_max[block] = val;
1543             }
1544         } else
1545 #endif /* SK_ENABLE_IPV6 */
1546         {
1547             ipwild->num_blocks = 4;
1548 
1549             /* set each block as if no CIDR */
1550             for (block = 0; block < num_blocks; ++block) {
1551                 val = (block_max_value
1552                        & (skipaddrGetV4(&ipaddr)
1553                           >> ((num_blocks - block - 1) * block_size)));
1554                 ipwild->m_blocks[block][_BMAP_INDEX(val)] = _BMAP_OFFSET(val);
1555                 ipwild->m_min[block] = val;
1556                 ipwild->m_max[block] = val;
1557             }
1558         }
1559 
1560         if (cidr == 0 || cidr == (num_blocks * block_size)) {
1561             return SKUTILS_OK;
1562         }
1563 
1564         for (block = 0; block < num_blocks; ++block) {
1565             if (cidr <= (block_size * block)) {
1566                 /* this block is all ones */
1567                 memset(ipwild->m_blocks[block], 0xFF,
1568                        sizeof(ipwild->m_blocks[0]));
1569                 ipwild->m_min[block] = 0;
1570                 ipwild->m_max[block] = block_max_value;
1571             } else if (cidr < (block_size * (1 + block))) {
1572                 /* partial effect on this block */
1573                 range_length = 1 << ((block_size * (1 + block)) - cidr);
1574                 val = (ipwild->m_min[block] & ~(range_length - 1));
1575                 ipwild->m_min[block] = val;
1576                 for (i = 0; i < range_length; ++i, ++val) {
1577                     ipwild->m_blocks[block][_BMAP_INDEX(val)]
1578                         |= _BMAP_OFFSET(val);
1579                 }
1580                 ipwild->m_max[block] = val - 1;
1581             }
1582             /* else (cidr >= (block_size*(1+block))) and no effect */
1583         }
1584         return SKUTILS_OK;
1585     }
1586 
1587     /* Parse the input ip from the beginning */
1588     sp = ip_string;
1589 
1590     /* ignore leading whitespace */
1591     while (isspace((int)*sp)) {
1592         ++sp;
1593     }
1594 
1595     if (strchr(sp, ':')) {
1596 #if !SK_ENABLE_IPV6
1597         return parseError(SKUTILS_ERR_BAD_CHAR,
1598                           "%s '%c'--IPv6 addresses not supported",
1599                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1600                           *sp);
1601 #else
1602         ipwild->num_blocks = 8;
1603         block_sep = ":";
1604         num_blocks = 8;
1605         block_size = 16;
1606         block_base = 16;
1607 
1608         /* check for a v4 section, for example "::ffff:x.x.x.x".  if
1609          * we find a '.', move backward to find the ':' and as
1610          * v4_in_v6 to the character following the ':'. */
1611         v4_in_v6 = strchr(sp, '.');
1612         if (v4_in_v6) {
1613             while (v4_in_v6 > sp) {
1614                 if (*(v4_in_v6 - 1) == ':') {
1615                     break;
1616                 }
1617                 --v4_in_v6;
1618             }
1619             if (v4_in_v6 == sp) {
1620                 /* must have something with ':' following '.' */
1621                 return parseError(SKUTILS_ERR_BAD_CHAR,
1622                                   "Found ':' after '.' in IPv6 address");
1623             }
1624         }
1625 #endif /* SK_ENABLE_IPV6 */
1626     } else {
1627         block_sep = ".";
1628         ipwild->num_blocks = 4;
1629         num_blocks = 4;
1630         block_size = 8;
1631         block_base = 10;
1632     }
1633     block_max_value = (1 << block_size) - 1;
1634 
1635     for (block = 0; block < num_blocks; ++block) {
1636         if (*sp == ':') {
1637             ++sp;
1638             if (*sp == ':') {
1639                 if (double_colon != UINT32_MAX) {
1640                     /* parse error */
1641                     return parseError(SKUTILS_ERR_BAD_CHAR,
1642                                       "Only one :: instance allowed");
1643                 }
1644                 ++sp;
1645                 double_colon = block;
1646             } else if (block == 0) {
1647                 /* address cannot begin with single ':' */
1648                 return parseError(SKUTILS_ERR_BAD_CHAR,
1649                                   "IP address cannot begin with single ':'");
1650             } else if (*sp == '\0') {
1651                 return parseError(SKUTILS_ERR_SHORT,
1652                                   "Expecting IP block value after ':'");
1653             }
1654         } else if (*sp == '.') {
1655             assert(block_base == 10);
1656             if (block == 0) {
1657                 return parseError(SKUTILS_ERR_BAD_CHAR,
1658                                   "%s--found leading separator '%c'",
1659                                   PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1660                                   *sp);
1661             }
1662             ++sp;
1663         } else if (*sp == '\0') {
1664             if (double_colon != UINT32_MAX) {
1665                 /* treat as end of the IP */
1666                 break;
1667             }
1668             return parseError(SKUTILS_ERR_SHORT,
1669                               "Too few IP blocks given");
1670         } else if (block != 0) {
1671             return parseError(SKUTILS_ERR_BAD_CHAR,
1672                               "%s '%c' expecting '%s' between IP blocks",
1673                               PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *sp,
1674                               block_sep);
1675         }
1676 
1677 #if SK_ENABLE_IPV6
1678         /* determine if we are at beginning of an embedded IPv4 address */
1679         if (sp == v4_in_v6) {
1680             skIPWildcard_t ipwv4;
1681             uint32_t j, k;
1682 
1683             /* verify we don't have too many IPv6 sections */
1684             if (block > 6) {
1685                 return parseError(SKUTILS_ERR_BAD_CHAR,
1686                                   "Too many sections before embedded IPv4");
1687             }
1688 
1689             /* parse the remaining part of the address as IPv4 wildcard */
1690             rv = skStringParseIPWildcard(&ipwv4, sp);
1691             if (rv < 0) {
1692                 return rv;
1693             }
1694 
1695             /* move sp to the end of the string */
1696             sp += strlen(sp);
1697 
1698             /* take the ipv4 wildcard and map it into ipv6 */
1699             for (i = 0; i < 4; i += 2, ++block) {
1700                 ipwild->m_min[block] = (ipwv4.m_min[i]<<8) | ipwv4.m_min[i+1];
1701                 ipwild->m_max[block] = (ipwv4.m_max[i]<<8) | ipwv4.m_max[i+1];
1702 
1703                 /* shortcut the "x.x" case */
1704                 if ((ipwild->m_min[block] == 0)
1705                     && (ipwild->m_min[block] == 0xFFFF))
1706                 {
1707                     memset(ipwild->m_blocks[block], 0xFF,
1708                            sizeof(ipwild->m_blocks[0]));
1709                     if (memcmp(ipwild->m_blocks[block],
1710                                ipwv4.m_blocks[i],
1711                                sizeof(ipwild->m_blocks[0]))
1712                         && memcmp(ipwild->m_blocks[block],
1713                                ipwv4.m_blocks[i+1],
1714                                sizeof(ipwild->m_blocks[0])))
1715                     {
1716                         continue;
1717                     } else {
1718                         memset(ipwild->m_blocks[block], 0,
1719                                sizeof(ipwild->m_blocks[0]));
1720                     }
1721                 }
1722 
1723                 for (j = ipwv4.m_min[i]; j <= ipwv4.m_max[i]; ++j) {
1724                     for (k = ipwv4.m_min[i+1]; k <= ipwv4.m_max[i+1]; ++k) {
1725                         if (_IPWILD_BLOCK_IS_SET(&ipwv4, i, j)
1726                             && _IPWILD_BLOCK_IS_SET(&ipwv4, i+1, k))
1727                         {
1728                             ipwild->m_blocks[block][_BMAP_INDEX((j << 8) | k)]
1729                                 |= _BMAP_OFFSET((j << 8) | k);
1730                         }
1731                     }
1732                 }
1733             }
1734 
1735             /* done */
1736             break;
1737         }
1738 #endif /* SK_ENABLE_IPV6 */
1739 
1740         if (*sp == 'x' || *sp == 'X') {
1741             /* all ones */
1742             memset(ipwild->m_blocks[block], 0xFF, sizeof(ipwild->m_blocks[0]));
1743             ipwild->m_min[block] = 0;
1744             ipwild->m_max[block] = block_max_value;
1745             ++sp;
1746             continue;
1747         }
1748 
1749         rv = numberListParserInit(&parser, sp, block_base, block_sep,
1750                                   0, block_max_value);
1751         if (rv != SK_NUM_PARSER_OK) {
1752             if (rv != SK_NUM_PARSER_END_OF_STRING) {
1753                 return rv;
1754             }
1755             if (*sp == *block_sep) {
1756                 return parseError(SKUTILS_ERR_BAD_CHAR,
1757                                   "%s--found double '%c'",
1758                                   PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1759                                   *sp);
1760             }
1761             if (double_colon == block) {
1762                 /* treat as end of string */
1763                 break;
1764             }
1765             if (isspace((int)*sp)) {
1766                 return parseError(SKUTILS_ERR_BAD_CHAR,
1767                                   "%s--embedded whitespace found in input",
1768                                   PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR));
1769             }
1770             return parseError(SKUTILS_ERR_SHORT, "Too few blocks given");
1771         }
1772 
1773         while ((rv = numberListParserNext(&range_length, &range_start,&parser))
1774                != SK_NUM_PARSER_END_OF_STRING)
1775         {
1776             switch (rv) {
1777               case SK_NUM_PARSER_OK:
1778                 /* this should not occur */
1779                 skAbortBadCase(rv);
1780 
1781               case SK_NUM_PARSER_RANGE_OPENMAX:
1782                 return parseError(SKUTILS_ERR_BAD_CHAR,
1783                                   ("Range is missing its upper limit"
1784                                    " (open-ended ranges are not supported)"));
1785 
1786               case SK_NUM_PARSER_NUMBER:
1787               case SK_NUM_PARSER_RANGE:
1788                 /* add the entries */
1789                 if (range_start < ipwild->m_min[block]) {
1790                     ipwild->m_min[block] = range_start;
1791                 }
1792                 for (i = 0; i < range_length; ++i, ++range_start) {
1793                     ipwild->m_blocks[block][_BMAP_INDEX(range_start)]
1794                         |= _BMAP_OFFSET(range_start);
1795                 }
1796                 --range_start;
1797                 if (range_start > ipwild->m_max[block]) {
1798                     ipwild->m_max[block] = range_start;
1799                 }
1800                 break;
1801 
1802               case SKUTILS_ERR_BAD_CHAR:
1803               default:
1804                 return rv;
1805             }
1806         }
1807 
1808         sp = numberParserCurrentChar(&parser);
1809     }
1810 
1811     if (double_colon != UINT32_MAX) {
1812         if (block == num_blocks) {
1813             /* error */
1814             return parseError(SKUTILS_ERR_BAD_CHAR,
1815                               "Cannot have '::' in IP with 8 blocks");
1816         }
1817         memmove(&ipwild->m_min[8 + double_colon - block],
1818                 &ipwild->m_min[double_colon],
1819                 sizeof(ipwild->m_min[0]) * (block - double_colon));
1820         memmove(&ipwild->m_max[8 + double_colon - block],
1821                 &ipwild->m_max[double_colon],
1822                 sizeof(ipwild->m_max[0]) * (block - double_colon));
1823         memmove(ipwild->m_blocks[8 + double_colon - block],
1824                 ipwild->m_blocks[double_colon],
1825                 sizeof(ipwild->m_blocks[0]) * (block - double_colon));
1826         for (i = double_colon; i < (8 + double_colon - block); ++i) {
1827             memset(ipwild->m_blocks[i], 0, sizeof(ipwild->m_blocks[0]));
1828             ipwild->m_blocks[i][_BMAP_INDEX(0)] = _BMAP_OFFSET(0);
1829             ipwild->m_min[i] = 0;
1830             ipwild->m_max[i] = 0;
1831         }
1832     } else if (block != num_blocks) {
1833         /* error */
1834         return parseError(SKUTILS_ERR_SHORT,
1835                           ("Only %" PRIu32 "/%" PRIu32 " IP blocks specified"),
1836                           block, num_blocks);
1837     }
1838 
1839     /* ignore trailing whitespace */
1840     while (isspace((int)*sp)) {
1841         ++sp;
1842     }
1843     if (*sp != '\0') {
1844         return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1845                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *sp);
1846     }
1847 
1848     return SKUTILS_OK;
1849 }
1850 
1851 
1852 /* parse an IP with an optional CIDR designation */
1853 int
skStringParseCIDR(skipaddr_t * out_val,uint32_t * out_cidr,const char * ip_string)1854 skStringParseCIDR(
1855     skipaddr_t         *out_val,
1856     uint32_t           *out_cidr,
1857     const char         *ip_string)
1858 {
1859     const char *sp;
1860     int rv;
1861 
1862     /* try to parse as an ordinary IP address */
1863     rv = skStringParseIP(out_val, ip_string);
1864 
1865     /* return if we get an error */
1866     if (rv < 0) {
1867         return rv;
1868     }
1869 
1870     /* check if we only got the IP address */
1871     if (rv == 0) {
1872         *out_cidr = (skipaddrIsV6(out_val) ? 128 : 32);
1873         return SKUTILS_OK;
1874     }
1875 
1876     /* When rv > 0, we parsed an IP but there is extra text,
1877      * presumably '/' for the CIDR designation.  Error if it isn't. */
1878     sp = &ip_string[rv];
1879     if (*sp != '/') {
1880         return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1881                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *sp);
1882     }
1883 
1884     ++sp;
1885     if (*sp == '\0') {
1886         return parseError(SKUTILS_ERR_BAD_CHAR,
1887                           "%s '%c'--expected CIDR after slash",
1888                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1889                           *sp);
1890     }
1891 
1892     /* parse the CIDR value */
1893     rv = skStringParseUint32(out_cidr, sp, 1,
1894                              (skipaddrIsV6(out_val) ? 128 : 32));
1895     if (rv > 0) {
1896         return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
1897                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1898                           sp[rv]);
1899     }
1900 
1901     return rv;
1902 }
1903 
1904 
1905 int
skStringParseHostPortPair(sk_sockaddr_array_t ** sockaddr,const char * host_port,uint8_t flags)1906 skStringParseHostPortPair(
1907     sk_sockaddr_array_t   **sockaddr,
1908     const char             *host_port,
1909     uint8_t                 flags)
1910 {
1911     sk_sockaddr_array_t *sa;
1912     const char *sp = host_port;
1913     const char *cp;
1914     const char *ep;
1915     const char *colon;
1916     const char *port;
1917     char *host;
1918     uint32_t port_val = 0;
1919     sk_sockaddr_t addr;
1920     int two_colons;
1921     int rv;
1922 
1923     if (NULL == sockaddr || NULL == host_port
1924         || ((flags & (PORT_REQUIRED | PORT_PROHIBITED)) ==
1925             (PORT_REQUIRED | PORT_PROHIBITED))
1926         || ((flags & (HOST_REQUIRED | HOST_PROHIBITED)) ==
1927             (HOST_REQUIRED | HOST_PROHIBITED))
1928         || ((flags & (IPV6_REQUIRED | IPV6_PROHIBITED)) ==
1929             (IPV6_REQUIRED | IPV6_PROHIBITED))
1930         || ((flags & (HOST_PROHIBITED | PORT_PROHIBITED)) ==
1931             (HOST_PROHIBITED | PORT_PROHIBITED)))
1932     {
1933         return parseError(SKUTILS_ERR_INVALID,
1934                           "Programmer error: Invalid flag combination");
1935     }
1936 
1937 #if !SK_ENABLE_INET6_NETWORKING
1938     if (flags & IPV6_REQUIRED) {
1939         return parseError(SKUTILS_ERR_INVALID,
1940                           ("IPv6 address required yet"
1941                            " IPv6 addresses not supported"));
1942     }
1943 #endif  /* !SK_ENABLE_INET6_NETWORKING */
1944 
1945     /* ignore leading whitespace */
1946     while (*sp && isspace((int)*sp)) {
1947         ++sp;
1948     }
1949     if ('\0' == *sp) {
1950         /* whitespace only or empty string */
1951         return parseError(SKUTILS_ERR_EMPTY, PE_NULL);
1952     }
1953 
1954     /* move 'ep' forward to next whitespace char or to end of string */
1955     ep = sp + 1;
1956     while (*ep && !isspace((int)*ep)) {
1957         ++ep;
1958     }
1959     if ('\0' != *ep) {
1960         /* found whitespace; ensure it is only trailing whitespace and
1961          * not embedded whitespace */
1962         cp = ep;
1963         while (*cp && isspace((int)*cp)) {
1964             ++cp;
1965         }
1966         if ('\0' != *cp) {
1967             return parseError(SKUTILS_ERR_BAD_CHAR,
1968                               "%s--embedded whitespace found in input",
1969                               PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR));
1970         }
1971     }
1972 
1973     /* get possible host:port separator ':', which could be part of an
1974      * IPv6 address if there is no port */
1975     colon = strrchr(sp, ':');
1976     two_colons = (colon && colon != strchr(sp, ':'));
1977 
1978     /* set 'ep' to end of the host portion of input */
1979     if ('[' == *sp) {
1980         cp = strrchr(sp, ']');
1981         if (cp == NULL) {
1982             return parseError(SKUTILS_ERR_BAD_CHAR,
1983                               "Cannot find closing ']' character");
1984         }
1985         /* character after ']' must be end of string or the ':' that
1986          * separates the host from the port */
1987         if ((cp + 1 != ep) && (cp + 1 != colon)) {
1988             return parseError(SKUTILS_ERR_BAD_CHAR,
1989                               "%s--unexpected character after ']': %c",
1990                               PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
1991                               *(cp+1));
1992         }
1993         if (colon && (colon < cp)) {
1994             /* if final ':' occurs before ']', assume function was
1995              * passed an IPv6 address with no port */
1996             colon = NULL;
1997         }
1998         ++sp;
1999         ep = cp;
2000 
2001     } else if (two_colons) {
2002         /* assume we have an IPv6 address not contained in [...] */
2003         colon = NULL;
2004 
2005     } else if (colon) {
2006         ep = colon;
2007     }
2008 
2009     /* Check to see if the presumed host is actually a port */
2010     if (colon == NULL && (sp + strspn(sp, "0123456789") == ep)) {
2011         if (flags & HOST_REQUIRED) {
2012             return parseError(SKUTILS_ERR_OTHER,
2013                               "Expected a host name or IP address");
2014         }
2015         colon = sp - 1;          /* -1 due to increment below */
2016         ep = sp;
2017     }
2018 
2019     /* Parse the port */
2020     if (colon) {
2021         port = colon + 1;
2022         if (flags & PORT_PROHIBITED) {
2023             return parseError(SKUTILS_ERR_OTHER,
2024                               "Expected a host name or IP only");
2025         }
2026 
2027         rv = skStringParseUint32(&port_val, port, 0, UINT16_MAX);
2028         if (rv < 0) {
2029             /* bad parse */
2030             if (SKUTILS_ERR_EMPTY == rv) {
2031                 return parseError(SKUTILS_ERR_SHORT, "Missing port value");
2032             }
2033             return parseError((silk_utils_errcode_t)rv,
2034                               "Error parsing port: %s",
2035                               PARSE_ERRORCODE_MSG(rv));
2036         }
2037         if (rv > 0) {
2038             /* text after port */
2039             return parseError(SKUTILS_ERR_BAD_CHAR,
2040                               "Error parsing port: Unexpected text after port");
2041         }
2042     } else if (flags & PORT_REQUIRED) {
2043         return parseError(SKUTILS_ERR_OTHER,
2044                           "Cannot find port and port is required");
2045     } else {
2046         port = NULL;
2047     }
2048 
2049     if (ep == sp) {
2050         /* no host */
2051         host = NULL;
2052     } else if (flags & HOST_PROHIBITED) {
2053         return parseError(SKUTILS_ERR_OTHER,
2054                           "Found a host name when host was prohibited");
2055     } else {
2056         /* copy the hostname or IP so we can lop off the port */
2057         host = (char*)malloc((ep - sp + 1u) * sizeof(char));
2058         if (NULL == host) {
2059             return parseError(SKUTILS_ERR_ALLOC, PE_NULL);
2060         }
2061         memcpy(host, sp, (ep - sp + 1u) * sizeof(char));
2062         host[ep - sp] = '\0';
2063     }
2064 
2065     /* fill an sk_vector_t with sk_sockaddr_t structures that are
2066      * obtained by using either getaddrinfo() to parse the host:port
2067      * pair or gethostbyname() to parse the host */
2068     {
2069         sk_vector_t *vec;
2070 #if USE_GETADDRINFO
2071         const char *resolv_constraint = "";
2072         struct addrinfo *addrinfo;
2073         struct addrinfo *current;
2074         struct addrinfo hints;
2075         char port_buf[7];
2076         char *port_str;
2077 
2078         memset(&hints, 0, sizeof(hints));
2079         if (!SK_ENABLE_INET6_NETWORKING || (flags & IPV6_PROHIBITED)) {
2080             resolv_constraint = " as an IPv4 address";
2081             hints.ai_family = AF_INET;
2082         } else if (flags & IPV6_REQUIRED) {
2083             resolv_constraint = " as an IPv6 address";
2084             hints.ai_family = AF_INET6;
2085         } else {
2086             hints.ai_family = AF_UNSPEC;
2087         }
2088         if (host == NULL) {
2089             hints.ai_flags = AI_PASSIVE;
2090         }
2091         /* hints.ai_flags |= AI_ADDRCONFIG; */
2092         if (port == NULL) {
2093             port_str = NULL;
2094         } else {
2095             snprintf(port_buf, sizeof(port_buf), "%" PRIu32, port_val);
2096             port_str = port_buf;
2097         }
2098 
2099         /* The following is a lie, but a white one.  We need a
2100          * non-zero socktype in order for Solaris to agree with
2101          * numeric ports that aren't in the /etc/services file. */
2102         hints.ai_socktype = SOCK_STREAM;
2103 
2104         rv = getaddrinfo(host, port_str, &hints, &addrinfo);
2105         if (rv != 0) {
2106             if (host) {
2107                 rv = parseError(SKUTILS_ERR_RESOLVE,
2108                                 "Unable to resolve '%s'%s: %s",
2109                                 host, resolv_constraint, gai_strerror(rv));
2110                 free(host);
2111             } else {
2112                 rv = parseError(SKUTILS_ERR_RESOLVE,
2113                                 "Could not register passive port %s: %s",
2114                                 port_str, gai_strerror(rv));
2115             }
2116             return rv;
2117         }
2118 
2119         vec = skVectorNew(sizeof(addr));
2120         if (vec == NULL) {
2121             freeaddrinfo(addrinfo);
2122             if (host) {
2123                 free(host);
2124             }
2125             return parseError(SKUTILS_ERR_ALLOC, PE_NULL);
2126         }
2127 
2128         current = addrinfo;
2129         while (current) {
2130             switch (current->ai_addr->sa_family) {
2131 #if SK_ENABLE_INET6_NETWORKING
2132               case AF_INET6:
2133                 addr.v6 = *(struct sockaddr_in6 *)(current->ai_addr);
2134                 break;
2135 #endif  /* SK_ENABLE_INET6_NETWORKING */
2136               case AF_INET:
2137                 addr.v4 = *(struct sockaddr_in *)(current->ai_addr);
2138                 break;
2139               default:
2140                 current = current->ai_next;
2141                 continue;
2142             }
2143             rv = skVectorAppendValue(vec, &addr);
2144             if (rv != 0) {
2145                 skVectorDestroy(vec);
2146                 if (host) {
2147                     free(host);
2148                 }
2149                 freeaddrinfo(addrinfo);
2150                 return parseError(SKUTILS_ERR_ALLOC, PE_NULL);
2151             }
2152             current = current->ai_next;
2153         }
2154         freeaddrinfo(addrinfo);
2155 
2156 #else  /* #if !USE_GETADDRINFO */
2157         vec = skVectorNew(sizeof(addr));
2158         if (vec == NULL) {
2159             return parseError(SKUTILS_ERR_ALLOC, PE_NULL);
2160         }
2161         memset(&addr, 0, sizeof(addr));
2162         addr.v4.sin_family = AF_INET;
2163         addr.v4.sin_port = htons((uint16_t)port_val);
2164         if (!host) {
2165             addr.v4.sin_addr.s_addr = htonl(INADDR_ANY);
2166             rv = skVectorAppendValue(vec, &addr);
2167             if (rv != 0) {
2168                 skVectorDestroy(vec);
2169                 return parseError(SKUTILS_ERR_ALLOC, PE_NULL);
2170             }
2171         } else {
2172             struct hostent *he;
2173             char **current;
2174 
2175             he = gethostbyname(host);
2176             if (he == NULL || (he->h_addrtype != AF_INET)) {
2177                 rv = parseError(SKUTILS_ERR_RESOLVE,
2178                                 "Unable to resolve '%s' as an IPv4 address",
2179                                 host);
2180                 free(host);
2181                 skVectorDestroy(vec);
2182                 return rv;
2183             }
2184 
2185             current = he->h_addr_list;
2186             while (*current) {
2187                 memcpy(&addr.v4.sin_addr, *current, he->h_length);
2188                 rv = skVectorAppendValue(vec, &addr);
2189                 if (rv != 0) {
2190                     free(host);
2191                     skVectorDestroy(vec);
2192                     return parseError(SKUTILS_ERR_ALLOC, PE_NULL);
2193                 }
2194                 current++;
2195             }
2196         }
2197 #endif  /* USE_GETADDRINFO */
2198 
2199         sa = (sk_sockaddr_array_t*)calloc(1, sizeof(sk_sockaddr_array_t));
2200         if (sa == NULL) {
2201             free(host);
2202             skVectorDestroy(vec);
2203             return parseError(SKUTILS_ERR_ALLOC, PE_NULL);
2204         }
2205         sa->name = host;
2206 
2207         sa->num_addrs = skVectorGetCount(vec);
2208         sa->addrs = (sk_sockaddr_t*)skVectorToArrayAlloc(vec);
2209         skVectorDestroy(vec);
2210         if (sa->addrs == NULL) {
2211             skSockaddrArrayDestroy(sa);
2212             return parseError(SKUTILS_ERR_ALLOC, PE_NULL);
2213         }
2214 
2215         if (host || (flags & HOST_PROHIBITED)) {
2216             /* grab the value that was provided */
2217             sa->host_port_pair = strdup(host_port);
2218             if (!sa->host_port_pair) {
2219                 skSockaddrArrayDestroy(sa);
2220                 return parseError(SKUTILS_ERR_ALLOC, PE_NULL);
2221             }
2222         } else {
2223             const size_t buf_size = 12;
2224             sa->host_port_pair = (char *)malloc(buf_size * sizeof(char));
2225             if (!sa->host_port_pair) {
2226                 skSockaddrArrayDestroy(sa);
2227                 return parseError(SKUTILS_ERR_ALLOC, PE_NULL);
2228             }
2229             if (flags & IPV6_PROHIBITED) {
2230                 rv = snprintf(sa->host_port_pair,buf_size, "*:%u", port_val);
2231             } else {
2232                 rv = snprintf(sa->host_port_pair,buf_size, "[*]:%u", port_val);
2233             }
2234             if ((size_t)rv > buf_size) {
2235                 skAbort();
2236             }
2237         }
2238 
2239         *sockaddr = sa;
2240     }
2241 
2242     return SKUTILS_OK;
2243 }
2244 
2245 
2246 /*
2247  *    Helper function for skStringParseDatetime() to handle parsing of
2248  *    the fractional seconds.
2249  *
2250  *    Fractional seconds begin in 'start_char'.  'end_char' is set to
2251  *    the character following the fractional seconds, and 'end_char'
2252  *    must be provided.  The fractional seconds are stored in the
2253  *    value referenced by 'msec'.  Return SKUTILS_OK or a negative
2254  *    skutils-parse-error value.
2255  */
2256 static int
parseDatetimeFractionalSeconds(const char * start_char,char ** end_char,long * msec)2257 parseDatetimeFractionalSeconds(
2258     const char         *start_char,
2259     char              **end_char,
2260     long               *msec)
2261 {
2262     long val;
2263     size_t num_digits;
2264 
2265     if (!isdigit((int)*start_char)) {
2266         return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
2267                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
2268                           *start_char);
2269     }
2270     /* parse the value */
2271     errno = 0;
2272     val = strtol(start_char, end_char, 10);
2273     num_digits = (*end_char - start_char);
2274     if (0 == num_digits) {
2275         return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
2276                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
2277                           *start_char);
2278     }
2279     if (val == LONG_MAX && errno == ERANGE) {
2280         return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
2281     }
2282     if (val < 0) {
2283         return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
2284     }
2285     /* multiply or divide as needed given the number of digits parsed */
2286     switch (num_digits) {
2287       case 0:  skAbortBadCase(num_digits);
2288       case 1:  *msec = val * 100; break;
2289       case 2:  *msec = val * 10; break;
2290       case 3:  *msec = val; break;
2291       case 4:  *msec = val / 10; break;
2292       case 5:  *msec = val / 100; break;
2293       case 6:  *msec = val / 1000; break;
2294       case 7:  *msec = val / 10000; break;
2295       case 8:  *msec = val / 100000; break;
2296       case 9:  *msec = val / 1000000; break;
2297       case 10: *msec = val / 10000000; break;
2298       case 11: *msec = val / 100000000; break;
2299       case 12:
2300       default:
2301         val /= 1000000000;
2302         for ( ; num_digits > 12; --num_digits) {
2303             val /= 10;
2304         }
2305         *msec = val;
2306         break;
2307     }
2308     return SKUTILS_OK;
2309 }
2310 
2311 
2312 /*  time string to struct sktime_st; see utils.h for details */
2313 int
skStringParseDatetime(sktime_t * date_val,const char * date_string,unsigned int * out_flags)2314 skStringParseDatetime(
2315     sktime_t           *date_val,
2316     const char         *date_string,
2317     unsigned int       *out_flags)
2318 {
2319     const unsigned int min_precision = SK_PARSED_DATETIME_DAY;
2320     struct tm ts;
2321     time_t t;
2322     const char *sp;
2323     char *ep;
2324     const char delim[] = {'\0', '/', '/', ':', ':', ':', '.'};
2325     long val;
2326     long msec = 0;
2327     unsigned int i;
2328     int rv;
2329 
2330     /* check inputs */
2331     assert(date_val);
2332     if (NULL == date_string) {
2333         return parseError(SKUTILS_ERR_INVALID, PE_NULL);
2334     }
2335 
2336     /* initialize */
2337     sp = date_string;
2338     memset(&ts, 0, sizeof(struct tm));
2339 
2340     /* use "unknown" value for Daylight Saving Time flag */
2341     ts.tm_isdst = -1;
2342 
2343     /* ignore leading whitespace */
2344     while (*sp && isspace((int)*sp)) {
2345         ++sp;
2346     }
2347     if ('\0' == *sp) {
2348         /* whitespace only or empty string */
2349         return parseError(SKUTILS_ERR_EMPTY, PE_NULL);
2350     }
2351 
2352     /* if the date contains only digits and a decimal point(s) and is
2353      * at least 9 digits long, treat it as an epoch time */
2354     if (strspn(sp, ".0123456789") > 8) {
2355         long epoch;
2356 
2357         /* parse the seconds */
2358         errno = 0;
2359         val = strtol(sp, &ep, 10);
2360         if (sp == ep) {
2361             return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
2362                               PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *sp);
2363         }
2364         if (val == LONG_MAX && errno == ERANGE) {
2365             return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
2366         }
2367         if (val < 0) {
2368             return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
2369         }
2370 
2371         /* make sure value is in range */
2372         if ((val < STRING_PARSE_MIN_EPOCH)
2373             || ((unsigned long)val > STRING_PARSE_MAX_EPOCH))
2374         {
2375             return parseError(((val < STRING_PARSE_MIN_EPOCH)
2376                                ? SKUTILS_ERR_MINIMUM
2377                                : SKUTILS_ERR_MAXIMUM),
2378                               ("Epoch value (%ld) out of range:"
2379                                " use %d <= epoch <= %u"),
2380                               val,
2381                               STRING_PARSE_MIN_EPOCH, STRING_PARSE_MAX_EPOCH);
2382         }
2383 
2384         epoch = val;
2385         if ('.' == *ep && isdigit((int)*(ep+1))) {
2386             /* parse fractional seconds */
2387             sp = ep + 1;
2388             rv = parseDatetimeFractionalSeconds(sp, &ep, &msec);
2389             if (rv) {
2390                 return rv;
2391             }
2392         }
2393 
2394         /* handle the end of the string, to see if we are attempting
2395          * to parse something as epoch that we shouldn't */
2396         if (*ep != '\0' && !isspace((int)*ep)) {
2397             return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
2398                               PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *ep);
2399         }
2400 
2401         /* ignore trailing whitespace */
2402         sp = ep;
2403         while (*sp && isspace((int)*sp)) {
2404             ++sp;
2405         }
2406         if ('\0' != *sp) {
2407             return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
2408                               PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *sp);
2409         }
2410         if (out_flags) {
2411             if (strchr(date_string, '.')) {
2412                 *out_flags = SK_PARSED_DATETIME_FRACSEC;
2413             } else if (0 == epoch % 3600) {
2414                 /* at least hour precision */
2415                 if (0 == epoch % 86400) {
2416                     *out_flags = SK_PARSED_DATETIME_DAY;
2417                 } else {
2418                     *out_flags = SK_PARSED_DATETIME_HOUR;
2419                 }
2420             } else if (0 == epoch % 60) {
2421                 *out_flags = SK_PARSED_DATETIME_MINUTE;
2422             } else {
2423                 *out_flags = SK_PARSED_DATETIME_SECOND;
2424             }
2425             *out_flags |= SK_PARSED_DATETIME_EPOCH;
2426         }
2427         *date_val = sktimeCreate(epoch, msec);
2428         return SKUTILS_OK;
2429     }
2430 
2431     /* 'i' is the part of the date we have successfully parsed;
2432      * 1=year, 2=month, 3=day, 4=hour, 5=min, 6=sec, 7=msec */
2433     i = 0;
2434     while (*sp && (i < (sizeof(delim)/sizeof(char)))) {
2435         /* this will catch things like double ':' in the string */
2436         if ( !isdigit((int)*sp)) {
2437             return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
2438                               PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *sp);
2439         }
2440 
2441         if (6 == i) {
2442             rv = parseDatetimeFractionalSeconds(sp, &ep, &msec);
2443             if (rv) {
2444                 return rv;
2445             }
2446         } else {
2447             /* parse the digit */
2448             errno = 0;
2449             val = strtol(sp, &ep, 10);
2450 
2451             if (sp == ep) {
2452                 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
2453                                   PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
2454                                   *sp);
2455             }
2456             if (val == LONG_MAX && errno == ERANGE) {
2457                 return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
2458             }
2459             if (val < 0) {
2460                 return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
2461             }
2462         }
2463 
2464         /* check that value is valid given what we are parsing */
2465         switch (i) {
2466           case 0: /* year */
2467             if (val < STRING_PARSE_MIN_YEAR || val > STRING_PARSE_MAX_YEAR) {
2468                 return parseError(((val < STRING_PARSE_MIN_YEAR)
2469                                    ? SKUTILS_ERR_MINIMUM
2470                                    : SKUTILS_ERR_MAXIMUM),
2471                                   ("Year value (%ld) out of range:"
2472                                    " use %d <= year <= %d"),
2473                                   val, STRING_PARSE_MIN_YEAR,
2474                                   STRING_PARSE_MAX_YEAR);
2475             }
2476             ts.tm_year = val - 1900;
2477             break;
2478           case 1: /* month */
2479             if (val < 1 || val > 12) {
2480                 return parseError(((val < 1)
2481                                    ? SKUTILS_ERR_MINIMUM
2482                                    : SKUTILS_ERR_MAXIMUM),
2483                                   ("Month value (%ld) out of range:"
2484                                    " use %d <= month <= %d"),
2485                                   val, 1, 12);
2486             }
2487             ts.tm_mon = val - 1;
2488             break;
2489           case 2: /* day */
2490             if (val < 1
2491                 || val > skGetMaxDayInMonth((1900 + ts.tm_year),
2492                                             (1 + ts.tm_mon)))
2493             {
2494                 return parseError(((val < 1)
2495                                    ? SKUTILS_ERR_MINIMUM
2496                                    : SKUTILS_ERR_MAXIMUM),
2497                                   ("Day value (%ld) out of range:"
2498                                    " use %d <= day <= %d"),
2499                                   val, 1,
2500                                   skGetMaxDayInMonth((1900 + ts.tm_year),
2501                                                      (1 + ts.tm_mon)));
2502             }
2503             ts.tm_mday = val;
2504             break;
2505           case 3: /* hour */
2506             if (val > 23) {
2507                 return parseError(SKUTILS_ERR_MAXIMUM,
2508                                   ("Hour value (%ld) out of range:"
2509                                    " use %d <= hour <= %d"),
2510                                   val, 0, 23);
2511             }
2512             ts.tm_hour = val;
2513             break;
2514           case 4: /* minute */
2515             if (val > 59) {
2516                 return parseError(SKUTILS_ERR_MAXIMUM,
2517                                   ("Minute value (%ld) out of range:"
2518                                    " use %d <= minute <= %d"),
2519                                   val, 0, 59);
2520             }
2521             ts.tm_min = val;
2522             break;
2523           case 5: /* second */
2524             if (val > 59) {
2525                 return parseError(SKUTILS_ERR_MAXIMUM,
2526                                   ("Second value (%ld) out of range:"
2527                                    " use %d <= second <= %d"),
2528                                   val, 0, 59);
2529             }
2530             ts.tm_sec = val;
2531             break;
2532           case 6: /* fractional seconds; handled above */
2533             break;
2534           default:
2535             /* should never get here */
2536             skAbortBadCase(i);
2537         }
2538 
2539         /* we parsed the number; move to the delimiter */
2540         ++i;
2541         sp = ep;
2542 
2543         /* check for whitespace or end of string */
2544         if (('\0' == *sp) || isspace((int)*sp)) {
2545             break;
2546         }
2547 
2548         /* check that delimiter is what we expect; if so move over it
2549          * to next character */
2550         if (delim[i]) {
2551             if (*sp == delim[i]) {
2552                 ++sp;
2553             } else if (i == 3 && (*sp == 'T')) {
2554                 /* allow a ':' or a 'T' to separate the day and hour */
2555                 ++sp;
2556             } else {
2557                 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
2558                                   PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
2559                                   *sp);
2560             }
2561         }
2562     }
2563 
2564     /* space is allowed at end of string; eat it */
2565     ep = (char*)sp;
2566     while (*sp && isspace((int)*sp)) {
2567         ++sp;
2568     }
2569 
2570     /* check for junk at end of string; if so, report error at 'ep' */
2571     if ('\0' != *sp) {
2572         return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
2573                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *ep);
2574     }
2575 
2576     /* if the caller wants to know the last state parsed, we update
2577      * their variable. */
2578     if (out_flags != NULL) {
2579         *out_flags = i;
2580     }
2581 
2582     /* need at least year/month/day */
2583     if (i < min_precision) {
2584         return parseError(SKUTILS_ERR_SHORT,
2585                           "Date '%s' does not have at least day precision",
2586                           date_string);
2587     }
2588 
2589     /* convert the time */
2590 #if  SK_ENABLE_LOCALTIME
2591     t = mktime(&ts);
2592 #else
2593     t = timegm(&ts);
2594 #endif
2595     if (t == (time_t)-1) {
2596         return -1;
2597     }
2598 
2599     *date_val = sktimeCreate(t, msec);
2600     return SKUTILS_OK;
2601 }
2602 
2603 
2604 /* parses string of the form DATETIME[-DATETIME], where DATETIME is
2605  * parsed by skStringParseDatetime().  see header for details. */
2606 int
skStringParseDatetimeRange(sktime_t * start,sktime_t * end,const char * s_datetime,unsigned int * start_precision,unsigned int * end_precision)2607 skStringParseDatetimeRange(
2608     sktime_t           *start,
2609     sktime_t           *end,
2610     const char         *s_datetime,
2611     unsigned int       *start_precision,
2612     unsigned int       *end_precision)
2613 {
2614     char *s_start_time;
2615     char *s_end_time;
2616     int rv = 0;
2617 
2618     /* check inputs */
2619     assert(start);
2620     assert(end);
2621     if (s_datetime == NULL) {
2622         return parseError(SKUTILS_ERR_INVALID, PE_NULL);
2623     }
2624 
2625     /* copy the string, since we are going to modify it */
2626     s_start_time = strdup(s_datetime);
2627     if (!s_start_time) {
2628         return parseError(SKUTILS_ERR_ALLOC, PE_NULL);
2629     }
2630 
2631     /* search for dash.  if dash does not exist, parse entire string
2632      * as start date.  if dash does exist, parse string on left as
2633      * start date and string on right as end date.
2634      */
2635     s_end_time = strchr(s_start_time, '-');
2636     if (s_end_time != NULL) {
2637         /* change the dash to a NUL to create two separate strings */
2638         *s_end_time = '\0';
2639         /* set the s_end_time pointer to be the char after the dash */
2640         ++s_end_time;
2641         /* treat missing end-time as infinity */
2642         if (*s_end_time == '\0') {
2643             s_end_time = NULL;
2644         }
2645     }
2646 
2647     /* parse start */
2648     rv = skStringParseDatetime(start, s_start_time, start_precision);
2649     if (s_end_time == NULL) {
2650         *end = INT64_MAX;
2651     } else if (rv == 0) {
2652         rv = skStringParseDatetime(end, s_end_time, end_precision);
2653     }
2654 
2655     free(s_start_time);
2656 
2657     /* check error conditions and return error if necessary */
2658     if (rv) {
2659         return rv;
2660     }
2661 
2662     if (*end < *start) {
2663         return parseError(SKUTILS_ERR_BAD_RANGE, PE_NULL);
2664     }
2665 
2666     return SKUTILS_OK;
2667 }
2668 
2669 
2670 /* set 'ceiling_time' to the greatest value that does not change the
2671  * 'precision' of 't'.  see header for details. */
2672 int
skDatetimeCeiling(sktime_t * ceiling_time,const sktime_t * t,unsigned int precision)2673 skDatetimeCeiling(
2674     sktime_t           *ceiling_time,
2675     const sktime_t     *t,
2676     unsigned int        precision)
2677 {
2678     struct tm ts;
2679     struct tm *rv;
2680     time_t t_sec;
2681 
2682     assert(t);
2683     assert(ceiling_time);
2684 
2685     if ((precision
2686          & ~(SK_PARSED_DATETIME_MASK_PRECISION | SK_PARSED_DATETIME_EPOCH))
2687         || (0 == precision))
2688     {
2689         return -1;
2690     }
2691     precision &= SK_PARSED_DATETIME_MASK_PRECISION;
2692 
2693     t_sec = (time_t)sktimeGetSeconds(*t);
2694 
2695 #if  SK_ENABLE_LOCALTIME
2696     rv = localtime_r(&t_sec, &ts);
2697 #else
2698     rv = gmtime_r(&t_sec, &ts);
2699 #endif
2700     if (NULL == rv) {
2701         return -1;
2702     }
2703 
2704     /* 'precision' is what we know; we need to set everything that is
2705      * "finer" than that value. */
2706     switch (precision) {
2707       case SK_PARSED_DATETIME_YEAR: /* know year, set month */
2708         ts.tm_mon = 11;
2709         /* FALLTHROUGH */
2710 
2711       case SK_PARSED_DATETIME_MONTH: /* know month, set month-day */
2712         ts.tm_mday = skGetMaxDayInMonth((1900 + ts.tm_year), (1 + ts.tm_mon));
2713         /* FALLTHROUGH */
2714 
2715       case SK_PARSED_DATETIME_DAY: /* know month-day, set hour */
2716         ts.tm_hour = 23;
2717         /* FALLTHROUGH */
2718 
2719       case SK_PARSED_DATETIME_HOUR: /* know hour, set min */
2720         ts.tm_min = 59;
2721         /* FALLTHROUGH */
2722 
2723       case SK_PARSED_DATETIME_MINUTE: /* know min, set sec */
2724         ts.tm_sec = 59;
2725         break;
2726 
2727       case SK_PARSED_DATETIME_SECOND:
2728         /* know sec, just set fractional-seconds */
2729         *ceiling_time = sktimeCreate(t_sec, 999);
2730         return 0;
2731 
2732       case SK_PARSED_DATETIME_FRACSEC:
2733         /* already at max precision, just return what we were given */
2734         *ceiling_time = *t;
2735         return 0;
2736 
2737       default:
2738         skAbortBadCase(precision);
2739     }
2740 
2741     /* we have reports of the following causing problems on some
2742      * versions of Solaris, but we cannot re-create... */
2743     ts.tm_isdst = -1;
2744 
2745     /* convert the time */
2746 #if  SK_ENABLE_LOCALTIME
2747     t_sec = mktime(&ts);
2748 #else
2749     t_sec = timegm(&ts);
2750 #endif
2751     if (t_sec == (time_t)-1) {
2752         return -1;
2753     }
2754 
2755     /* convert seconds to milliseconds */
2756     *ceiling_time = sktimeCreate(t_sec, 999);
2757 
2758     return 0;
2759 }
2760 
2761 
2762 /* set 'floor_time' to the lowest value that does not change the
2763  * 'precision' of 't'.  see header for details. */
2764 int
skDatetimeFloor(sktime_t * floor_time,const sktime_t * t,unsigned int precision)2765 skDatetimeFloor(
2766     sktime_t           *floor_time,
2767     const sktime_t     *t,
2768     unsigned int        precision)
2769 {
2770     struct tm ts;
2771     struct tm *rv;
2772     time_t t_sec;
2773 
2774     assert(t);
2775     assert(floor_time);
2776 
2777     if ((precision
2778          & ~(SK_PARSED_DATETIME_MASK_PRECISION | SK_PARSED_DATETIME_EPOCH))
2779         || (0 == precision))
2780     {
2781         return -1;
2782     }
2783     precision &= SK_PARSED_DATETIME_MASK_PRECISION;
2784 
2785     t_sec = (time_t)sktimeGetSeconds(*t);
2786 
2787 #if  SK_ENABLE_LOCALTIME
2788     rv = localtime_r(&t_sec, &ts);
2789 #else
2790     rv = gmtime_r(&t_sec, &ts);
2791 #endif
2792     if (NULL == rv) {
2793         return -1;
2794     }
2795 
2796     /* 'precision' is what we know; we need to clear everything that is
2797      * "finer" than that value. */
2798     switch (precision) {
2799       case SK_PARSED_DATETIME_YEAR: /* know year, set month */
2800         ts.tm_mon = 0;
2801         /* FALLTHROUGH */
2802 
2803       case SK_PARSED_DATETIME_MONTH: /* know month, set month-day */
2804         ts.tm_mday = 1;
2805         /* FALLTHROUGH */
2806 
2807       case SK_PARSED_DATETIME_DAY: /* know month-day, set hour */
2808         ts.tm_hour = 0;
2809         /* FALLTHROUGH */
2810 
2811       case SK_PARSED_DATETIME_HOUR: /* know hour, set min */
2812         ts.tm_min = 0;
2813         /* FALLTHROUGH */
2814 
2815       case SK_PARSED_DATETIME_MINUTE: /* know min, set sec */
2816         ts.tm_sec = 0;
2817         break;
2818 
2819       case SK_PARSED_DATETIME_SECOND:
2820         /* know sec, just set fractional-seconds */
2821         *floor_time = sktimeCreate(t_sec, 0);
2822         return 0;
2823 
2824       case SK_PARSED_DATETIME_FRACSEC:
2825         /* already at max precision, just return what we were given */
2826         *floor_time = *t;
2827         return 0;
2828 
2829       default:
2830         skAbortBadCase(precision);
2831     }
2832 
2833     /* we have reports of the following causing problems on some
2834      * versions of Solaris, but we cannot re-create... */
2835     ts.tm_isdst = -1;
2836 
2837     /* convert the time */
2838 #if  SK_ENABLE_LOCALTIME
2839     t_sec = mktime(&ts);
2840 #else
2841     t_sec = timegm(&ts);
2842 #endif
2843     if (t_sec == (time_t)-1) {
2844         return -1;
2845     }
2846 
2847     /* convert seconds to milliseconds */
2848     *floor_time = sktimeCreate(t_sec, 0);
2849 
2850     return 0;
2851 }
2852 
2853 
2854 /* parse string as TCP flags.  see header for details. */
2855 int
skStringParseTCPFlags(uint8_t * result,const char * flag_string)2856 skStringParseTCPFlags(
2857     uint8_t            *result,
2858     const char         *flag_string)
2859 {
2860     const char *cp = flag_string;
2861 
2862     /* check inputs */
2863     assert(result);
2864     if (flag_string == NULL) {
2865         return parseError(SKUTILS_ERR_INVALID, PE_NULL);
2866     }
2867 
2868     /* parse each character, unless it is a terminating NULL or an
2869      * illegal character.
2870      */
2871     *result = 0;
2872     while (*cp) {
2873         switch (*cp) {
2874           case 'f':
2875           case 'F':
2876             TCP_FLAG_SET_FLAG(*result, FIN_FLAG);
2877             break;
2878           case 's':
2879           case 'S':
2880             TCP_FLAG_SET_FLAG(*result, SYN_FLAG);
2881             break;
2882           case 'r':
2883           case 'R':
2884             TCP_FLAG_SET_FLAG(*result, RST_FLAG);
2885             break;
2886           case 'p':
2887           case 'P':
2888             TCP_FLAG_SET_FLAG(*result, PSH_FLAG);
2889             break;
2890           case 'a':
2891           case 'A':
2892             TCP_FLAG_SET_FLAG(*result, ACK_FLAG);
2893             break;
2894           case 'u':
2895           case 'U':
2896             TCP_FLAG_SET_FLAG(*result, URG_FLAG);
2897             break;
2898           case 'e':
2899           case 'E':
2900             TCP_FLAG_SET_FLAG(*result, ECE_FLAG);
2901             break;
2902           case 'c':
2903           case 'C':
2904             TCP_FLAG_SET_FLAG(*result, CWR_FLAG);
2905             break;
2906           case ' ':
2907             break;
2908           default:
2909             if (!isspace((int)*cp)) {
2910                 /* reached illegal, non-space character */
2911                 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
2912                                   PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
2913                                   *cp);
2914             }
2915             break;
2916         }
2917         ++cp;
2918     }
2919 
2920     return SKUTILS_OK;
2921 }
2922 
2923 
2924 /* parse flag definition in the form high/mask.  see header for
2925  * details. */
2926 int
skStringParseTCPFlagsHighMask(uint8_t * high,uint8_t * mask,const char * flag_string)2927 skStringParseTCPFlagsHighMask(
2928     uint8_t            *high,
2929     uint8_t            *mask,
2930     const char         *flag_string)
2931 {
2932     const char *cp = flag_string;
2933     uint8_t *result;
2934 
2935     /* check inputs */
2936     assert(high);
2937     assert(mask);
2938     if (flag_string == NULL) {
2939         return parseError(SKUTILS_ERR_INVALID, PE_NULL);
2940     }
2941 
2942     *high = 0;
2943     *mask = 0;
2944     result = high;
2945 
2946     /* parse each character, unless it is a terminating NULL or an
2947      * illegal character.
2948      */
2949     while (*cp) {
2950         switch (*cp) {
2951           case 'f':
2952           case 'F':
2953             TCP_FLAG_SET_FLAG(*result, FIN_FLAG);
2954             break;
2955           case 's':
2956           case 'S':
2957             TCP_FLAG_SET_FLAG(*result, SYN_FLAG);
2958             break;
2959           case 'r':
2960           case 'R':
2961             TCP_FLAG_SET_FLAG(*result, RST_FLAG);
2962             break;
2963           case 'p':
2964           case 'P':
2965             TCP_FLAG_SET_FLAG(*result, PSH_FLAG);
2966             break;
2967           case 'a':
2968           case 'A':
2969             TCP_FLAG_SET_FLAG(*result, ACK_FLAG);
2970             break;
2971           case 'u':
2972           case 'U':
2973             TCP_FLAG_SET_FLAG(*result, URG_FLAG);
2974             break;
2975           case 'e':
2976           case 'E':
2977             TCP_FLAG_SET_FLAG(*result, ECE_FLAG);
2978             break;
2979           case 'c':
2980           case 'C':
2981             TCP_FLAG_SET_FLAG(*result, CWR_FLAG);
2982             break;
2983           case '/':
2984             if (result == mask) {
2985                 /* double slash */
2986                 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
2987                                   PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
2988                                   *cp);
2989             }
2990             result = mask;
2991             break;
2992           case ' ':
2993             break;
2994           default:
2995             if (!isspace((int)*cp)) {
2996                 /* reached illegal, non-space character */
2997                 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
2998                                   PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
2999                                   *cp);
3000             }
3001             break;
3002         }
3003         ++cp;
3004     }
3005 
3006     /* check if we reached end of string before '/' character was found */
3007     if (result == high) {
3008         if (*high == 0) {
3009             return parseError(SKUTILS_ERR_EMPTY, PE_NULL);
3010         }
3011         return parseError(SKUTILS_ERR_SHORT, "Missing '/' character");
3012     }
3013 
3014     if (*mask == 0) {
3015         return parseError(SKUTILS_ERR_SHORT, "Missing masks flags value");
3016     }
3017 
3018     /* make sure high is a proper subset of mask */
3019     if ((*high & *mask) != *high) {
3020         return parseError(SKUTILS_ERR_BAD_RANGE,
3021                           "High flags is not subset of mask flags");
3022     }
3023 
3024     /* success */
3025     return SKUTILS_OK;
3026 }
3027 
3028 
3029 /* parse string as TCP state flags.  see header for details. */
3030 int
skStringParseTCPState(uint8_t * result,const char * flag_string)3031 skStringParseTCPState(
3032     uint8_t            *result,
3033     const char         *flag_string)
3034 {
3035     const char *cp = flag_string;
3036 
3037     /* check inputs */
3038     assert(result);
3039     if (flag_string == NULL) {
3040         return parseError(SKUTILS_ERR_INVALID, PE_NULL);
3041     }
3042 
3043     /* parse each character, unless it is a terminating NULL or an
3044      * illegal character.
3045      */
3046     *result = 0;
3047     while (*cp) {
3048         switch (*cp) {
3049           case 't':
3050           case 'T':
3051             *result |= SK_TCPSTATE_TIMEOUT_KILLED;
3052             break;
3053           case 'c':
3054           case 'C':
3055             *result |= SK_TCPSTATE_TIMEOUT_STARTED;
3056             break;
3057           case 'f':
3058           case 'F':
3059             *result |= SK_TCPSTATE_FIN_FOLLOWED_NOT_ACK;
3060             break;
3061           case 's':
3062           case 'S':
3063             *result |= SK_TCPSTATE_UNIFORM_PACKET_SIZE;
3064             break;
3065           case ' ':
3066             break;
3067           default:
3068             if (!isspace((int)*cp)) {
3069                 /* reached illegal, non-space character */
3070                 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
3071                                   PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
3072                                   *cp);
3073             }
3074             break;
3075         }
3076         ++cp;
3077     }
3078 
3079     return SKUTILS_OK;
3080 }
3081 
3082 
3083 /* parse TCP state flag definition in the form high/mask.  see header
3084  * for details. */
3085 int
skStringParseTCPStateHighMask(uint8_t * high,uint8_t * mask,const char * flag_string)3086 skStringParseTCPStateHighMask(
3087     uint8_t            *high,
3088     uint8_t            *mask,
3089     const char         *flag_string)
3090 {
3091     const char *cp = flag_string;
3092     uint8_t *result;
3093 
3094     /* check inputs */
3095     assert(high);
3096     assert(mask);
3097     if (flag_string == NULL) {
3098         return parseError(SKUTILS_ERR_INVALID, PE_NULL);
3099     }
3100 
3101     *high = 0;
3102     *mask = 0;
3103     result = high;
3104 
3105     /* parse each character, unless it is a terminating NULL or an
3106      * illegal character.
3107      */
3108     while (*cp) {
3109         switch (*cp) {
3110           case 't':
3111           case 'T':
3112             *result |= SK_TCPSTATE_TIMEOUT_KILLED;
3113             break;
3114           case 'c':
3115           case 'C':
3116             *result |= SK_TCPSTATE_TIMEOUT_STARTED;
3117             break;
3118           case 'f':
3119           case 'F':
3120             *result |= SK_TCPSTATE_FIN_FOLLOWED_NOT_ACK;
3121             break;
3122           case 's':
3123           case 'S':
3124             *result |= SK_TCPSTATE_UNIFORM_PACKET_SIZE;
3125             break;
3126           case '/':
3127             if (result == mask) {
3128                 /* double slash */
3129                 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
3130                                   PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
3131                                   *cp);
3132             }
3133             result = mask;
3134             break;
3135           case ' ':
3136             break;
3137           default:
3138             if (!isspace((int)*cp)) {
3139                 /* reached illegal, non-space character */
3140                 return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
3141                                   PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
3142                                   *cp);
3143             }
3144             break;
3145         }
3146         ++cp;
3147     }
3148 
3149     /* check if we reached end of string before '/' character was found */
3150     if (result == high) {
3151         if (*high == 0) {
3152             return parseError(SKUTILS_ERR_EMPTY, PE_NULL);
3153         }
3154         return parseError(SKUTILS_ERR_SHORT, "Missing '/' character");
3155     }
3156 
3157     if (*mask == 0) {
3158         return parseError(SKUTILS_ERR_SHORT,
3159                           "Missing masks state flags value");
3160     }
3161 
3162     /* make sure high is a proper subset of mask */
3163     if ((*high & *mask) != *high) {
3164         return parseError(SKUTILS_ERR_BAD_RANGE,
3165                           ("High state flags is not subset"
3166                            " of mask state flags"));
3167     }
3168 
3169     /* success */
3170     return SKUTILS_OK;
3171 }
3172 
3173 
3174 /* parse string as uint32_t.  see header for details */
3175 int
skStringParseUint32(uint32_t * result_val,const char * int_string,uint32_t min_val,uint32_t max_val)3176 skStringParseUint32(
3177     uint32_t           *result_val,
3178     const char         *int_string,
3179     uint32_t            min_val,
3180     uint32_t            max_val)
3181 {
3182     uint64_t tmp = UINT64_MAX;
3183     int rv;
3184 
3185     rv = skStringParseUint64(&tmp, int_string, min_val,
3186                              ((max_val == 0) ? UINT32_MAX : max_val));
3187     if (rv >= 0 || rv == SKUTILS_ERR_MINIMUM || rv == SKUTILS_ERR_MAXIMUM){
3188         if (tmp > UINT32_MAX) {
3189             return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
3190         }
3191         *result_val = UINT32_MAX & (uint32_t)tmp;
3192     }
3193     return rv;
3194 }
3195 
3196 
3197 /* parse string as uint64_t.  see header for details */
3198 int
skStringParseUint64(uint64_t * result_val,const char * int_string,uint64_t min_val,uint64_t max_val)3199 skStringParseUint64(
3200     uint64_t           *result_val,
3201     const char         *int_string,
3202     uint64_t            min_val,
3203     uint64_t            max_val)
3204 {
3205     const char *sp;
3206     char *ep;
3207 #if (SK_SIZEOF_LONG >= 8)
3208 #define  U64_OVERFLOW ULONG_MAX
3209     unsigned long val;
3210 #else
3211 #define  U64_OVERFLOW ULLONG_MAX
3212     unsigned long long val;
3213 #endif
3214 
3215     /* check inputs */
3216     assert(result_val);
3217     assert(max_val == 0 || min_val <= max_val);
3218     if (!int_string) {
3219         return parseError(SKUTILS_ERR_INVALID, PE_NULL);
3220     }
3221 
3222     sp = int_string;
3223 
3224     /* ignore leading whitespace */
3225     while (*sp && isspace((int)*sp)) {
3226         ++sp;
3227     }
3228     if ('\0' == *sp) {
3229         /* whitespace only or empty string */
3230         return parseError(SKUTILS_ERR_EMPTY, PE_NULL);
3231     }
3232 
3233     /* number that begins with '-' is not unsigned */
3234     if ('-' == *sp) {
3235         return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
3236                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
3237                           *sp);
3238     }
3239 
3240     /* parse the string */
3241     errno = 0;
3242 #if (SK_SIZEOF_LONG >= 8)
3243     val = strtoul(sp, &ep, 10);
3244 #else
3245     val = strtoull(sp, &ep, 10);
3246 #endif
3247     if (sp == ep) {
3248         /* parse error */
3249         return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
3250                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
3251                           *sp);
3252     }
3253     if (val == U64_OVERFLOW && errno == ERANGE) {
3254         /* overflow */
3255         return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
3256     }
3257 #if (U64_OVERFLOW > UINT64_MAX)
3258     if (val > UINT64_MAX) {
3259         /* too big */
3260         return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
3261     }
3262 #endif
3263 
3264     *result_val = (uint64_t)val;
3265     if (*result_val < min_val) {
3266         /* too small */
3267         return parseError(SKUTILS_ERR_MINIMUM, ("%s of %" PRIu64),
3268                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_MINIMUM),
3269                           min_val);
3270     }
3271     if (max_val > 0 && *result_val > max_val) {
3272         /* too big */
3273         return parseError(SKUTILS_ERR_MAXIMUM, ("%s of %" PRIu64),
3274                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_MAXIMUM),
3275                           max_val);
3276     }
3277 
3278     /* ignore trailing whitespace, but only if we reach the end of the
3279      * string. */
3280     sp = ep;
3281     while (*sp && isspace((int)*sp)) {
3282         ++sp;
3283     }
3284     if ('\0' != *sp) {
3285         /* junk at end, return position of 'ep' */
3286         return ep - int_string;
3287     }
3288 
3289     return 0;
3290 }
3291 
3292 
3293 int
skStringParseHumanUint64(uint64_t * result_val,const char * int_string,unsigned int parse_flags)3294 skStringParseHumanUint64(
3295     uint64_t           *result_val,
3296     const char         *int_string,
3297     unsigned int        parse_flags)
3298 {
3299     const char *sp;             /* Current parse position */
3300     const char *tp;             /* Temporary pointer */
3301     const char *hv;             /* Index into sk_human_value_list */
3302     char *ep;                   /* End of parsed number */
3303     int val_index;
3304     double tmp_val;
3305     struct {
3306         const char  c;
3307         double      si;
3308         double      trad;
3309     } sk_human_values[] = {
3310         {'k', 1.0e3,           1024.0},
3311         {'m', 1.0e6,        1048576.0},
3312         {'g', 1.0e9,     1073741824.0},
3313         {'t', 1.0e12, 1099511627776.0}
3314     };
3315     const char sk_human_value_list[] = "kmgt";
3316 
3317     /* check inputs */
3318     assert(result_val);
3319     if (!int_string) {
3320         return parseError(SKUTILS_ERR_INVALID, PE_NULL);
3321     }
3322 
3323     /* allow parse_flags of 0 to be default */
3324     if (parse_flags == 0) {
3325         parse_flags = SK_HUMAN_NORMAL;
3326     }
3327 
3328     sp = int_string;
3329 
3330     /* ignore leading whitespace */
3331     while (*sp && isspace((int)*sp)) {
3332         ++sp;
3333     }
3334     if ('\0' == *sp) {
3335         /* whitespace only or empty string */
3336         return parseError(SKUTILS_ERR_EMPTY, PE_NULL);
3337     }
3338 
3339     /* parse the string */
3340     errno = 0;
3341     tmp_val = strtod(sp, &ep);
3342     if (sp == ep) {
3343         /* parse error */
3344         return parseError(SKUTILS_ERR_BAD_CHAR, PE_NULL);
3345     }
3346     if (errno == ERANGE) {
3347         if (tmp_val == HUGE_VAL || tmp_val == -HUGE_VAL) {
3348             /* overflow */
3349             return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
3350         }
3351         return parseError(SKUTILS_ERR_UNDERFLOW, PE_NULL);
3352     }
3353     if (tmp_val < 0) {
3354         /* underflow */
3355         return parseError(SKUTILS_ERR_UNDERFLOW, PE_NULL);
3356     }
3357     if (isnan(tmp_val)) {
3358         /* NAN */
3359         return parseError(SKUTILS_ERR_BAD_CHAR, PE_NULL);
3360     }
3361 
3362     tp = sp = ep;
3363 
3364     /* Possibly eat trailing whitespace (Parse with tp because it
3365      * might be space at the end (no suffix) when we are not supposed
3366      * to parse that.) */
3367     if ((parse_flags & SK_HUMAN_MID_WS)
3368         || !(parse_flags & SK_HUMAN_END_NO_WS))
3369     {
3370         while (*tp && isspace((int)*tp)) {
3371             ++tp;
3372         }
3373     }
3374 
3375     /* No suffix? */
3376     if ('\0' == *tp) {
3377         if (!(parse_flags & SK_HUMAN_END_NO_WS)) {
3378             /* If there was no suffix, and we are supposed to parse
3379              * trailing whitespace, set pointer to the end. */
3380             sp = tp;
3381         }
3382         goto parsed;
3383     }
3384 
3385     /* Spaces before suffix allowed? */
3386     if ((tp != sp) && !(parse_flags & SK_HUMAN_MID_WS)) {
3387         /* If there is a suffix, and white space in the middle is
3388          * illegal, treat the suffix as junk at the end of the
3389          * input. */
3390         sp = tp;
3391         goto parsed;
3392     }
3393 
3394     /* Possible suffix */
3395     hv = strchr(sk_human_value_list, tolower((int)*tp));
3396     if (hv != NULL) {
3397         /* Valid suffix found, set the parse pointer to the end of it */
3398         sp = tp + 1;
3399 
3400         /* Find suffix information */
3401         val_index = hv - sk_human_value_list;
3402         assert((int)sk_human_values[val_index].c == tolower((int)*tp));
3403 
3404         /* Use suffix value */
3405         if (((parse_flags & SK_HUMAN_LOWER_SI) && islower((int)*tp)) ||
3406             ((parse_flags & SK_HUMAN_UPPER_SI) && isupper((int)*tp)))
3407         {
3408             tmp_val *= sk_human_values[val_index].si;
3409         } else {
3410             tmp_val *= sk_human_values[val_index].trad;
3411         }
3412 
3413         /* eat trailing whitespace */
3414         if (!(parse_flags & SK_HUMAN_END_NO_WS)) {
3415             while (*sp && isspace((int)*sp)) {
3416                 ++sp;
3417             }
3418         }
3419     } else if (!(parse_flags & SK_HUMAN_END_NO_WS)) {
3420         /* No valid suffix, but we allow trailing spaces. */
3421         sp = tp;
3422     }
3423 
3424   parsed:
3425     if (tmp_val > UINT64_MAX) {
3426         /* overflow */
3427         return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
3428     }
3429 
3430     *result_val = (uint64_t)tmp_val;
3431 
3432     if ('\0' != *sp) {
3433         /* junk at end */
3434         return 1 + (sp - int_string);
3435     }
3436 
3437     return 0;
3438 }
3439 
3440 
3441 int
skStringParseRange32(uint32_t * range_lower,uint32_t * range_upper,const char * range_string,uint32_t min_val,uint32_t max_val,unsigned int flags)3442 skStringParseRange32(
3443     uint32_t           *range_lower,
3444     uint32_t           *range_upper,
3445     const char         *range_string,
3446     uint32_t            min_val,
3447     uint32_t            max_val,
3448     unsigned int        flags)
3449 {
3450     uint64_t tmp_lower = 0;
3451     uint64_t tmp_upper = 0;
3452     int rv;
3453 
3454     rv = skStringParseRange64(&tmp_lower, &tmp_upper, range_string, min_val,
3455                              ((max_val == 0) ? UINT32_MAX : max_val), flags);
3456 
3457     /* these return codes indicate that at least one value was set */
3458     if (rv >= 0 || rv == SKUTILS_ERR_BAD_RANGE
3459         || rv == SKUTILS_ERR_MINIMUM || rv == SKUTILS_ERR_MAXIMUM)
3460     {
3461         /* return overflow error if appropriate */
3462         if ((tmp_lower > UINT32_MAX) || (tmp_upper > UINT32_MAX)) {
3463             return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
3464         }
3465         /* convert numbers back to uint32 */
3466         *range_lower = UINT32_MAX & (uint32_t)tmp_lower;
3467         *range_upper = UINT32_MAX & (uint32_t)tmp_upper;
3468     }
3469     return rv;
3470 }
3471 
3472 
3473 /* parse a single number '3' or a single range '3-5' */
3474 int
skStringParseRange64(uint64_t * range_lower,uint64_t * range_upper,const char * range_string,uint64_t min_val,uint64_t max_val,unsigned int flags)3475 skStringParseRange64(
3476     uint64_t           *range_lower,
3477     uint64_t           *range_upper,
3478     const char         *range_string,
3479     uint64_t            min_val,
3480     uint64_t            max_val,
3481     unsigned int        flags)
3482 {
3483     const char *cp;
3484     int rv;
3485 
3486     assert(range_lower);
3487     assert(range_upper);
3488     assert(range_string);
3489 
3490     /* parse first part of range; rv, if positive, will be location of
3491      * the first non-digit following the value---should be a hyphen */
3492     rv = skStringParseUint64(range_lower, range_string, min_val, max_val);
3493     if (rv < 0) {
3494         /* an error */
3495         return rv;
3496     }
3497 
3498     if (rv == 0) {
3499         /* got a single value */
3500         if (flags & SKUTILS_RANGE_NO_SINGLE) {
3501             /* missing upper half */
3502             return parseError(SKUTILS_ERR_SHORT,
3503                               ("Range is missing hyphen"
3504                                " (single value is not supported)"));
3505         }
3506         /* single value ok; set upper and return */
3507         if (flags & SKUTILS_RANGE_MAX_SINGLE) {
3508             /* a missing range_upper is always the maximum */
3509             *range_upper = ((max_val == 0) ? UINT64_MAX : max_val);
3510         } else {
3511             /* set range_upper to the same value as lower */
3512             *range_upper = *range_lower;
3513         }
3514         return SKUTILS_OK;
3515     }
3516 
3517     /* get the character where parsing stopped---hopefully a hyphen */
3518     cp = &(range_string[rv]);
3519 
3520     /* check for the hyphen */
3521     if (*cp != '-') {
3522         /* stopped on non-hyphen */
3523         return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
3524                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *cp);
3525     }
3526 
3527     /* goto start of upper bound */
3528     ++cp;
3529     ++rv;
3530 
3531     /* make certain character after '-' is a digit */
3532     if (!isdigit((int)*cp)) {
3533         /* check for open-ended range, permit whitespace between '-'
3534          * and end-of-string */
3535         while (isspace((int)*cp)) {
3536             ++cp;
3537         }
3538         if (*cp == '\0') {
3539             if (flags & SKUTILS_RANGE_NO_OPEN) {
3540                 /* missing upper half */
3541                 return parseError(SKUTILS_ERR_SHORT,
3542                                   ("Range is missing its upper limit"
3543                                    " (open-ended ranges are not supported)"));
3544             }
3545             /* set upper bound to maximum allowed value */
3546             *range_upper = ((max_val == 0) ? UINT64_MAX : max_val);
3547             return SKUTILS_OK;
3548         }
3549         /* got some junk char or embedded whitespace */
3550         return parseError(SKUTILS_ERR_BAD_CHAR,
3551                           "%s '%c'",
3552                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
3553                           range_string[rv]);
3554     }
3555 
3556     /* parse upper part of range */
3557     rv = skStringParseUint64(range_upper, cp, min_val, max_val);
3558     if (rv < 0) {
3559         /* parse error */
3560         return rv;
3561     }
3562     if (rv > 0) {
3563         /* extra chars after range */
3564         return parseError(SKUTILS_ERR_BAD_CHAR,
3565                           "%s '%c'",
3566                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), cp[rv]);
3567     }
3568 
3569     if (*range_upper < *range_lower) {
3570         return parseError(SKUTILS_ERR_BAD_RANGE, PE_NULL);
3571     }
3572 
3573     return SKUTILS_OK;
3574 }
3575 
3576 
3577 /* parse string as a double.  see header for details */
3578 int
skStringParseDouble(double * result_val,const char * dbl_string,double min_val,double max_val)3579 skStringParseDouble(
3580     double             *result_val,
3581     const char         *dbl_string,
3582     double              min_val,
3583     double              max_val)
3584 {
3585     const char *sp;
3586     char *ep;
3587     double val;
3588 
3589     /* check inputs */
3590     assert(result_val);
3591     assert(max_val == 0 || min_val <= max_val);
3592     if (!dbl_string) {
3593         return parseError(SKUTILS_ERR_INVALID, PE_NULL);
3594     }
3595 
3596     sp = dbl_string;
3597 
3598     /* ignore leading whitespace */
3599     while (*sp && isspace((int)*sp)) {
3600         ++sp;
3601     }
3602     if ('\0' == *sp) {
3603         /* whitespace only or empty string */
3604         return parseError(SKUTILS_ERR_EMPTY, PE_NULL);
3605     }
3606 
3607     /* parse the string */
3608     errno = 0;
3609     val = strtod(sp, &ep);
3610     if (sp == ep) {
3611         /* parse error */
3612         return parseError(SKUTILS_ERR_BAD_CHAR, PE_NULL);
3613     }
3614     if (errno == ERANGE) {
3615         if (val == 0) {
3616             /* underflow */
3617             return parseError(SKUTILS_ERR_UNDERFLOW, PE_NULL);
3618         }
3619         /* overflow */
3620         assert(val == HUGE_VAL || val == -HUGE_VAL);
3621         return parseError(SKUTILS_ERR_OVERFLOW, PE_NULL);
3622     }
3623     if (isnan(val)) {
3624         /* NAN */
3625         return parseError(SKUTILS_ERR_BAD_CHAR, PE_NULL);
3626     }
3627 
3628     *result_val = val;
3629     if (*result_val < min_val) {
3630         /* too small */
3631         return parseError(SKUTILS_ERR_MINIMUM, "%s of %f",
3632                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_MINIMUM),
3633                           min_val);
3634     }
3635     if (max_val > 0.0 && *result_val > max_val) {
3636         /* too big */
3637         return parseError(SKUTILS_ERR_MAXIMUM, "%s of %f",
3638                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_MAXIMUM),
3639                           max_val);
3640     }
3641 
3642     /* ignore trailing whitespace, but only if we reach the end of the
3643      * string. */
3644     sp = ep;
3645     while (*sp && isspace((int)*sp)) {
3646         ++sp;
3647     }
3648     if ('\0' != *sp) {
3649         /* junk at end, return position of 'ep' */
3650         return ep - dbl_string;
3651     }
3652 
3653     return 0;
3654 }
3655 
3656 
3657 /* parse string as a range of doubles.  see header for details */
3658 int
skStringParseDoubleRange(double * range_lower,double * range_upper,const char * range_string,double min_val,double max_val,unsigned int flags)3659 skStringParseDoubleRange(
3660     double             *range_lower,
3661     double             *range_upper,
3662     const char         *range_string,
3663     double              min_val,
3664     double              max_val,
3665     unsigned int        flags)
3666 {
3667     const char *cp;
3668     int rv;
3669 
3670     /* parse first part of range; rv, if positive, will be location of
3671      * the first non-digit following the value---should be a hyphen */
3672     rv = skStringParseDouble(range_lower, range_string, min_val, max_val);
3673     if (rv < 0) {
3674         /* an error */
3675         return rv;
3676     }
3677 
3678     if (rv == 0) {
3679         /* got a single value */
3680         if (flags & SKUTILS_RANGE_NO_SINGLE) {
3681             /* missing upper half */
3682             return parseError(SKUTILS_ERR_SHORT,
3683                               ("Range is missing hyphen"
3684                                " (single value is not supported)"));
3685         }
3686         /* single value ok.  set range_upper to the same value and
3687          * return */
3688         *range_upper = *range_lower;
3689         return SKUTILS_OK;
3690     }
3691 
3692     /* get the character where parsing stopped---hopefully a hyphen */
3693     cp = &(range_string[rv]);
3694 
3695     /* check for the hyphen */
3696     if (*cp != '-') {
3697         /* stopped on non-hyphen */
3698         return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
3699                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *cp);
3700     }
3701 
3702     /* goto start of upper bound */
3703     ++cp;
3704     ++rv;
3705 
3706     /* if *cp is on a '+' or '-', make certain the following character
3707      * is a digit.  Otherwise, make certain we're on a digit, or
3708      * handle an open-ended range. */
3709     if (*cp == '+' || *cp == '-') {
3710         if (!isdigit((int) *(cp + 1))) {
3711             return parseError(SKUTILS_ERR_BAD_CHAR,
3712                               "%s '%c'",
3713                               PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
3714                               range_string[rv]);
3715         }
3716 
3717     } else if (!isdigit((int)*cp)) {
3718         /* check for open-ended range, permit whitespace between '-'
3719          * and end-of-string */
3720         while (isspace((int)*cp)) {
3721             ++cp;
3722         }
3723         if (*cp == '\0') {
3724             if (flags & SKUTILS_RANGE_NO_OPEN) {
3725                 /* missing upper half */
3726                 return parseError(SKUTILS_ERR_SHORT,
3727                                   ("Range is missing its upper limit"
3728                                    " (open-ended ranges are not supported)"));
3729             }
3730             /* set upper bound to maximum allowed value */
3731             *range_upper = ((max_val == 0.0) ? HUGE_VAL : max_val);
3732             return SKUTILS_OK;
3733         }
3734         /* got some junk char or embedded whitespace */
3735         return parseError(SKUTILS_ERR_BAD_CHAR,
3736                           "%s '%c'",
3737                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR),
3738                           range_string[rv]);
3739     }
3740 
3741     /* parse upper part of range */
3742     rv = skStringParseDouble(range_upper, cp, min_val, max_val);
3743     if (rv < 0) {
3744         /* parse error */
3745         return rv;
3746     }
3747     if (rv > 0) {
3748         /* extra chars after range */
3749         return parseError(SKUTILS_ERR_BAD_CHAR,
3750                           "%s '%c'",
3751                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), cp[rv]);
3752     }
3753 
3754     if (*range_upper < *range_lower) {
3755         return parseError(SKUTILS_ERR_BAD_RANGE, PE_NULL);
3756     }
3757 
3758     return SKUTILS_OK;
3759 }
3760 
3761 
3762 const char *
skSignalToName(int signal_num)3763 skSignalToName(
3764     int                 signal_num)
3765 {
3766     int i;
3767 
3768     for (i = 0; i < signal_name2num_count; ++i) {
3769         if (signal_num == signal_name2num[i].number) {
3770             return signal_name2num[i].name;
3771         }
3772     }
3773     return "?";
3774 }
3775 
3776 
3777 int
skStringParseSignal(int * signal_num,const char * signal_name)3778 skStringParseSignal(
3779     int                *signal_num,
3780     const char         *signal_name)
3781 {
3782     char buf[16];
3783     const char *sp = signal_name;
3784     const char *ep;
3785     int i;
3786 
3787     /* check inputs */
3788     assert(signal_num);
3789     if (signal_name == NULL) {
3790         return parseError(SKUTILS_ERR_INVALID, PE_NULL);
3791     }
3792 
3793     /* ignore leading whitespace */
3794     while (*sp && isspace((int)*sp)) {
3795         ++sp;
3796     }
3797     if ('\0' == *sp) {
3798         /* whitespace only or empty string */
3799         return parseError(SKUTILS_ERR_EMPTY, PE_NULL);
3800     }
3801 
3802     /* if it looks like a number, treat it as such */
3803     if (isdigit((int)*sp)) {
3804         uint32_t tmp32 = 0;
3805         int max_sig = 0;
3806         int rv;
3807 
3808         for (i = 0; i < signal_name2num_count; ++i) {
3809             if (max_sig < signal_name2num[i].number) {
3810                 max_sig = signal_name2num[i].number;
3811             }
3812         }
3813 
3814         rv = skStringParseUint32(&tmp32, signal_name, 1, max_sig);
3815         /* should we search for 'tmp32' in signal_name2num[] to
3816          * determine whether it is a usable value? */
3817         *signal_num = (int)tmp32;
3818         return rv;
3819     }
3820 
3821     /* skip leading "SIG" prefix, if any */
3822     if (0 == strncmp("SIG", sp, 3)) {
3823         sp += 3;
3824     }
3825 
3826     /* find end of signal name.  if extra text follows name, copy name
3827      * into 'buf'. */
3828     ep = sp;
3829     while (isalnum((int)*ep)) {
3830         ++ep;
3831     }
3832     if (ep == sp) {
3833         return parseError(SKUTILS_ERR_BAD_CHAR, "%s '%c'",
3834                           PARSE_ERRORCODE_MSG(SKUTILS_ERR_BAD_CHAR), *sp);
3835     }
3836     if ('\0' != *ep) {
3837         if ((ep - sp) > (int)(sizeof(buf) - 1)) {
3838             /* name too long */
3839             return parseError(SKUTILS_ERR_BAD_CHAR,
3840                               "Value too long to be valid signal name");
3841         }
3842         strncpy(buf, sp, sizeof(buf));
3843         buf[ep - sp] = '\0';
3844         sp = buf;
3845     }
3846 
3847     /* linear search to find a match */
3848     for (i = 0; i < signal_name2num_count; ++i) {
3849         if (0 == strcasecmp(sp, signal_name2num[i].name)) {
3850             /* found a match */
3851             *signal_num = signal_name2num[i].number;
3852             while (isspace((int)*ep)) {
3853                 ++ep;
3854             }
3855             if ('\0' == *ep) {
3856                 return 0;
3857             }
3858             return (ep - signal_name);
3859         }
3860     }
3861 
3862     return parseError(SKUTILS_ERR_BAD_CHAR, "Unknown signal name '%s'", sp);
3863 }
3864 
3865 
3866 /*
3867 ** Local Variables:
3868 ** mode:c
3869 ** indent-tabs-mode:nil
3870 ** c-basic-offset:4
3871 ** End:
3872 */
3873