source: branches/ithildin-1.1/source/string.c @ 817

Revision 817, 31.3 KB checked in by wd, 4 years ago (diff)

Remove unnecessary variable assignment.

  • Property svn:keywords set to Id Rev
Line 
1/*
2 * string.c: string manipulation functions
3 *
4 * Copyright 2002 the Ithildin Project.
5 * See the COPYING file for more information on licensing and use.
6 *
7 * this file contains a variety of string manipulation functions.  some of them
8 * are libc replacements which were designed to be as fast as possible for the
9 * intended purposes of the software, there are also a load of others which
10 * serve many varied purposes.
11 */
12
13#include <ithildin/stand.h>
14
15IDSTRING(rcsid, "$Id$");
16
17unsigned char tolowertab[256] = {
180,  0x1,  0x2,  0x3,  0x4,  0x5,  0x6,  0x7,  0x8,  0x9,  0xa,  0xb,
190xc,  0xd,  0xe,  0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
200x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,  ' ',  '!',  '"',  '#',
21'$',  '%',  '&', '\'',  '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/',
22'0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',  '8',  '9',  ':',  ';',
23'<',  '=',  '>',  '?',  '@',  'a',  'b',  'c',  'd',  'e',  'f',  'g',
24'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',  'p',  'q',  'r',  's',
25't',  'u',  'v',  'w',  'x',  'y',  'z',  '[', '\\',  ']',  '^',  '_',
26'`',  'a',  'b',  'c',  'd',  'e',  'f',  'g',  'h',  'i',  'j',  'k',
27'l',  'm',  'n',  'o',  'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
28'x',  'y',  'z',  '{',  '|',  '}',  '~', 0x7f, 0x80, 0x81, 0x82, 0x83,
290x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
300x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
310x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
320xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
330xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
340xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb,
350xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
360xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3,
370xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
380xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
390xfc, 0xfd, 0xfe, 0xff
40};
41
42unsigned char touppertab[256] = {
430,  0x1,  0x2,  0x3,  0x4,  0x5,  0x6,  0x7,  0x8,  0x9,  0xa,  0xb,
440xc,  0xd,  0xe,  0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
450x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,  ' ',  '!',  '"',  '#',
46'$',  '%',  '&', '\'',  '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/',
47'0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',  '8',  '9',  ':',  ';',
48'<',  '=',  '>',  '?',  '@',  'A',  'B',  'C',  'D',  'E',  'F',  'G',
49'h',  'I',  'J',  'K',  'L',  'M',  'N',  'O',  'P',  'Q',  'R',  'S',
50't',  'U',  'V',  'W',  'X',  'Y',  'Z',  '[', '\\',  ']',  '^',  '_',
51'`',  'A',  'B',  'C',  'D',  'E',  'F',  'G',  'H',  'I',  'j',  'K',
52'L',  'M',  'N',  'O',  'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',
53'X',  'Y',  'Z',  '{',  '|',  '}',  '~', 0x7f, 0x80, 0x81, 0x82, 0x83,
540x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
550x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
560x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
570xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
580xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
590xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb,
600xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
610xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3,
620xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
630xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
640xfc, 0xfd, 0xfe, 0xff
65};
66
67/* str* functions */
68
69int ith_strcasecmp(const char *one, const char *two) {
70    while (tolower(*one) == tolower(*two++))
71        if (*one++ == '\0')
72            return 0;
73    return (tolower(*one) - tolower(*--two));
74}
75int ith_strncasecmp(const char *one, const char *two, int len) {
76    if (len != 0) {
77        do {
78            if (tolower(*one) != tolower(*two++))
79                return (tolower(*one) - tolower(*--two));
80            if (*one++ == '\0')
81                break;
82        } while (--len != 0);
83    }
84    return 0;
85}
86int ith_strcmp(const char *one, const char *two) {
87    while (*one == *two++)
88        if (*one++ == '\0')
89            return 0;
90    return (*one - *--two);
91}
92int ith_strncmp(const char *one, const char *two, int len) {
93
94    if (len != 0) {
95        do {
96            if (*one != *two++)
97                return (*one - *--two);
98            if (*one++ == '\0')
99                break;
100        } while (--len != 0);
101    }
102    return 0;
103}
104
105char *ith_strcat(char *str, const char *app) {
106    char *s = str;
107
108    while (*s != '\0')
109        s++;
110    while ((*s++ = *app++) != '\0');
111
112    return str;
113}
114
115char *ith_strncat(char *str, const char *app, int len) {
116   
117    if (len != 0) {
118        char *s = str;
119        const char *a = app;
120       
121        while (*s != '\0')
122            s++;
123
124        do {
125            if ((*s = *a++) == '\0')
126                break;
127            s++;
128        } while (--len != 0);
129        *s = '\0';
130    }
131    return str;
132}
133
134char *ith_strchr(const char *str, char ch) {
135   
136    while (1) {
137        if (*str == ch)
138            return (char *)str;
139        if (*str++ == '\0')
140            return NULL;
141    }
142}
143
144char *ith_strrchr(const char *str, char ch) {
145    char *last = NULL;
146    while (1) {
147        if (*str == ch)
148            last = (char *)str;
149        if (*str++ == '\0')
150            return last;
151    }
152}
153
154char *ith_strcpy(char *to, const char *from) {
155    char *ret = to;
156    while ((*to++ = *from++) != '\0');
157    return ret;
158}
159char *ith_strncpy(char *to, const char *from, int len) {
160    if (len != 0) {
161        char *t = to;
162        const char *f = from;
163
164        do {
165            if ((*t++ = *f++) == '\0') {
166                while (--len != 0)
167                    *t++ = '\0';
168                break;
169            }
170        } while (--len != 0);
171    }
172    return to;
173}
174
175char *ith_strdup(const char *str) {
176    size_t len;
177    char *s;
178
179    len = strlen(str) + 1;
180    if ((s = malloc(len)) != NULL)
181        memcpy(s, str, len);
182    return s;
183}
184
185size_t ith_strlen(const char *str) {
186    const char *s = str;
187
188    while (*s)
189        s++;
190
191    return (s - str);
192}
193
194/* this function was (sort of) borrowed from FreeBSD 4's libc.  I've shuffled a
195 * bit around and tried to make it more clear what's going on.  The general
196 * idea is that you can call strsep() with the address of a string to work on,
197 * and a list of delimiting characters.  it will break up the string as it is
198 * called, returning one argument at a time.  it may return an empty argument
199 * which can be detected by checking to see if the return value starts with a
200 * \0 character. */
201char *ith_strsep(char **from, const char *delim) {
202    char *s, *dp, *ret;
203
204    if ((s = *from) == NULL)
205        return NULL;
206
207    ret = s;
208    while (*s != '\0') {
209        /* loop until the end of s, checking against each delimiting character,
210         * if we find a delimiter set **s to '\0' and return our previous token
211         * to the user. */
212        dp = (char *)delim;
213        while (*dp != '\0') {
214            if (*s == *dp) {
215                *s = '\0';
216                *from = s + 1;
217                return ret;
218            }
219            dp++;
220        }
221        s++;
222    }
223    /* end of string case */
224    *from = NULL;
225    return ret;
226}
227
228/* ith_*printf stuff below */
229
230char num[24] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
231    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
232char otoa_tab[8] = { '0', '1', '2', '3', '4', '5', '6', '7' };
233char itoa_tab[10] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'  };
234char xtoa_tab[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 
235          'a', 'b', 'c', 'd', 'e', 'f'  };
236char nullstring[]="(null)";
237
238#undef sprintf
239#undef snprintf
240#undef vsprintf
241#undef vsnprintf
242
243int ith_vsnprintf(char *str, size_t size, const char *pattern, va_list ap) {
244    char *s;
245    char *buf = str;
246    const char *format = pattern;
247    int q = 0, u = 0, x = 0;
248    unsigned long i;
249    uint64_t i64;
250    size_t len = 0;
251    char *tab;
252    int modulo;
253
254    /* if size is 0, just set it to a ridiculous maximum */
255    if (!size)
256        size = 0x7fffffff; /* 2.1 billion or so bytes is a lot ;) */
257
258    while (*format && len < size) {
259        switch (*format) {
260            case '%':
261                format++;
262                switch (*format) {
263                    case 's': /* most popular ;) */
264                        s = va_arg(ap, char *);
265                        if (s == NULL)
266                            s = nullstring;
267                        while (*s && len < size)
268                            buf[len++] = *s++;
269                            format++;
270                            break;
271
272
273                    case 'q':
274                        q = 1;
275                        /* fallthrough */
276                    case 'l':
277                        if (*(format + 1) == 'l') {
278                            q = 1;
279                            format++;
280                        }
281                        format++;
282                        /* fallthrough */
283
284                    case 'd':
285                    case 'D':
286                    case 'i':
287                    case 'o':
288                    case 'O':
289                    case 'p':
290                    case 'u':
291                    case 'U':
292                    case 'x':
293                    case 'X':
294                        if (tolower(*format) == 'o') {
295                            u = 1; /* octal numbers are always unsigned. */
296                            tab = otoa_tab;
297                            modulo = 8;
298                        } else if (tolower(*format) == 'x' ||
299                                *format == 'p') {
300                            x = 1;
301                            u = 1; /* hex numbers are also always unsigned. */
302                            tab = xtoa_tab;
303                            modulo = 16;
304                            if (*format == 'p') {
305                                buf[len++] = '0';
306                                if (len < size)
307                                    buf[len++] = 'x';
308                            }
309                        } else {
310                            tab = itoa_tab;
311                            modulo = 10;
312                            if (tolower(*format) == 'u')
313                                u = 1;
314                        }
315
316                        if (!q) {
317                            i = va_arg(ap, unsigned long);
318                            i64 = i; /* convert to 64 bit */
319                        } else 
320                            i64 = va_arg(ap, uint64_t);
321                        if (!u && !x)
322                            if (i64 & 9223372036854775808ULL) {
323                                buf[len++] = '-'; /* it's negative.. */
324                                i64 = 9223372036854775808ULL -
325                                    (i64 & 9223372036854775808ULL);
326                            }
327                        s = &num[23];
328                        do {
329                            *--s = tab[i64 % modulo];
330                            i64 /= modulo;
331                        } while (i64 != 0);
332                        while (*s && len < size)
333                            buf[len++] = *s++;
334                        format++;
335                        q = u = x = 0;
336                        break;
337
338                    case 'c':
339                        buf[len++] = (char) va_arg(ap, int);
340                        format++;
341                        break;
342                    case '%': /* just an escaped % */
343                        buf[len++] = '%';
344                        format++;
345                        break;
346                    default:
347                        /* yick, unknown type...default to returning what
348                         * our s[n]printf friend would */
349#ifndef HAVE_VSNPRINTF
350                        /* this is a VERY unfortunate case, hopefully it
351                         * won't be run into in the code, but if it is I
352                         * have little sympathy.  snprintf is just one of
353                         * those things modern systems ought to have, in
354                         * any event, simply stick the format in the
355                         * string and move along. (snprintf is also C99 :) */
356                        buf[len++] = '%';
357                        buf[len++] = format++;
358                        break;
359#else
360                        return vsnprintf(str, size, pattern, ap);
361                        break;
362#endif
363                }
364                break;
365            default:
366                buf[len++] = *format++;
367                break;
368        }
369    }
370    buf[len] = 0;
371    return len;
372}
373
374int ith_sprintf(char *str, const char *format, ...) {
375    int ret;
376    va_list vl;
377    va_start(vl, format);
378    ret = ith_vsnprintf(str, 0, format, vl);
379    va_end(vl);
380    return ret;
381}
382
383int ith_snprintf(char *str, size_t size, const char *format, ...) {
384    int ret;
385    va_list vl;
386    va_start(vl, format);
387    ret = ith_vsnprintf(str, size, format, vl);
388    va_end(vl);
389    return ret;
390}
391
392int ith_vsprintf(char *str, const char *format, va_list ap) {
393    int ret;
394    ret = ith_vsnprintf(str, 0, format, ap);
395    return ret;
396}
397
398/* match code! */
399/* instead of setting a maximum call limit, set a maximum depth (12) which
400 * should be more than sane for almost any pattern */
401#define MAX_MATCH_DEPTH 12
402#define mreturn matchdepth--;return
403
404int matchdepth;
405
406/* thanks to lucas for the recursion fixes/optimization! */
407static int _match(const char *wild, const char *string) {
408    if (++matchdepth > MAX_MATCH_DEPTH) {
409        mreturn 0;
410    }
411
412    while (1) {
413        /* Logic: Match * in a string, this is confusing, sort of
414         * if * is the last thing in the wildcard, the match is
415         * definite if we've gotten this far.
416         * otherwise we try and find every occurance of the
417         * the next character in the wildcard within the string
418         * and match from there, calling the function recursively
419         * until some level below us returns positive, in which
420         * case we too return positive.  For strings with lots
421         * of wildcards this gets disgustingly recursive.  */
422        if (!*wild) {
423            mreturn ((*string == '\0') ? 1 : 0);
424        }
425        if (*wild == '*') {
426            wild++;
427            /* swallow all extraneous '*'s after.  */
428            while (*wild == '*')
429                wild++;
430            while (*wild == '?' && *string) {
431                wild++;
432                string++;
433            }
434            if (!*wild) {
435                mreturn 1;
436            }
437            if (*wild == '*')
438                continue;
439            while (*string) {
440                if (touppertab[(unsigned char)*string] ==
441                        touppertab[(unsigned char)*wild] &&
442                        _match((wild+1), (string+1))) {
443                    mreturn 1;
444                }
445                string++;
446            }
447        }
448        if (!*string) {
449            mreturn 0;
450        }
451        if (*wild != '?' && touppertab[(unsigned char)*string] !=
452            touppertab[(unsigned char)*wild]) {
453                mreturn 0;
454        }
455        string++;
456        wild++;
457    }
458    mreturn 0;
459}
460
461int match(const char *wild, const char *string)
462{
463    matchdepth = 0;
464    if (!strcmp(wild, "*"))
465        return 1; /* definite match */
466
467    return _match(wild, string);
468}
469
470#define MAX_HOSTMATCH_DEPTH 32
471
472/* the below behaves almost exactly like my other match function, with the
473* exception that it supports two additional notations which come from
474* regular expressions.  the [abcdef...] notation, (and also special
475* entries, documented elsehwere), and the (opt1,opt2,opt3,...) notation */
476static int _hostmatch(const char *wild, const char *string) {
477    if (++matchdepth > MAX_HOSTMATCH_DEPTH) {
478        mreturn 0;
479    }
480
481    while (1) {
482        /* Logic: Match * in a string, this is confusing, sort of
483         * if * is the last thing in the wildcard, the match is
484         * definite if we've gotten this far.
485         * otherwise we try and find every occurance of the
486         * the next character in the wildcard within the string
487         * and match from there, calling the function recursively
488         * until some level below us returns positive, in which
489         * case we too return positive.  For strings with lots
490         * of wildcards this gets disgustingly recursive.
491         */
492        if (!*wild) {
493            mreturn ((*string == '\0') ? 1 : 0);
494        }
495        if (*wild == '*') {
496            wild++;
497            /* swallow all extraneous '*'s after.  */
498            while (*wild == '*')
499                wild++;
500            while (*wild == '?' && *string) {
501                wild++;
502                string++;
503            }
504            if (!*wild) {
505                mreturn 1;
506            }
507            if (*wild == '*')
508                continue;
509            if (*wild == '(' || *wild == '[') {
510                while (*string) {
511                    if (_hostmatch(wild, string)) {
512                        mreturn 1;
513                    }
514                    string++;
515                }
516            } else {
517                while (*string) {
518                    if (touppertab[(unsigned char)*string] ==
519                            touppertab[(unsigned char)*wild] &&
520                            _hostmatch((wild+1), (string+1))) {
521                        mreturn 1;
522                    }
523                    string++;
524                }
525            }
526        }
527        if (!*string) {
528            mreturn 0;
529        }
530        if (*wild == '[') {
531            const char *end = wild++;
532            /* collator.  support special [:alpha:] and [:number:] semantics,
533             * as well as others. */
534            while (*end) {
535                if (*end == ']')
536                    break;
537                end++;
538            }
539            if (!*end) {
540                mreturn 0;
541            }
542            if (!strncasecmp(wild, ":alpha:", 7)) {
543                if (isalpha(*string))
544                    wild = end + 1;
545                else {
546                    mreturn 0;
547                }
548            } else if (!strncasecmp(wild, ":number:", 8)) {
549                if (isdigit(*string))
550                    wild = end + 1;
551                else {
552                    mreturn 0;
553                }
554            }
555            if (!strncasecmp(wild, ":alnum:", 7)) {
556                if (isalpha(*string) || isdigit(*string))
557                    wild = end + 1;
558                else {
559                    mreturn 0;
560                }
561            } else {
562                while (wild != end) {
563                    if (touppertab[(unsigned char)*wild] ==
564                            touppertab[(unsigned char)*string]) {
565                        wild = end + 1;
566                        break;
567                    }
568                    wild++;
569                }
570                if (wild == end) {
571                    mreturn 0;
572                }
573            }
574            /* if wild != end, we succeeded */
575            string++;
576            continue;
577        }
578        /* regretably (?) we do only literal matching here.  but I'm not sure
579         * if that's a bad thing.... */
580        if (*wild == '(') {
581            const char *end = wild++;
582            const char *ends = wild;
583            while (*end) {
584                if (*end == ')')
585                    break;
586                end++;
587            }
588            if (!*end) {
589                mreturn 0;
590            }
591            /* we have found the end, now find each substring and do compares */
592            while (ends != NULL) {
593                if (*ends == '|' || *ends == ')') {
594                    if (!strncasecmp(wild, string, ends - wild)) {
595                        string += ends - wild;
596                        wild = end + 1;
597                        break;
598                    }
599                    wild = ends + 1; 
600                    if (*ends == ')') {
601                        ends = NULL;
602                        break;
603                    }
604                }
605                ends++;
606            }
607            if (ends == NULL) {
608                mreturn 0;
609            }
610            continue;
611        }
612        if (*wild != '?' && touppertab[(unsigned char)*string] !=
613                touppertab[(unsigned char)*wild]) {
614            mreturn 0;
615        }
616        string++;
617        wild++;
618    }
619    mreturn 0;
620}
621
622int hostmatch(const char *wild, const char *string) {
623    matchdepth = 0;
624
625    /* in case we get a *, return success immediately */
626    if (!strcmp(string, "*"))
627        return 1;
628
629    return _hostmatch(wild, string);
630}
631
632
633/* match an IP using one of:
634 * regular address (v4/v6)
635 * address with significant bits (v4/v6)
636 *
637 * this is unfortunately not a very cheap call, anymore. */
638int ipmatch(const char *wild, const char *str) {
639    unsigned char bwild[IPADDR_SIZE]; /* these two are the bit-forms of the */
640    unsigned char bstr[IPADDR_SIZE];  /* ... two addresses. */
641    unsigned char bitmask[IPADDR_SIZE]; /* we store our bitmap this way because
642                                           of the length of IPv6 addresses. */
643    int family = PF_INET;
644    int alen = 0;
645    char addr[IPADDR_MAXLEN + 1];
646    int imask = 0;
647    int i;
648    char *mask;
649
650    memset(bitmask, 0xff, IPADDR_SIZE);
651    strlcpy(addr, wild, IPADDR_MAXLEN + 1);
652
653    /* strip off the mask portion if it is there */
654    if ((mask = strchr(wild, '/')) != NULL) {
655        /* mask form.  mask specifies significant bits from left to right.
656         * we must make sure to truncate addr at the point where the mask
657         * starts as well, if it starts before IPADDR_MAXLEN. */
658        if (IPADDR_MAXLEN > mask - wild)
659            addr[mask - wild] = '\0';
660        mask++;
661    }
662
663    /* now determine the address family */
664    family = get_address_type(addr);
665    if (family != PF_INET && family != PF_INET6)
666        return 0;
667
668    /* and handle the bitmasking if need-be */
669    if (mask != NULL) {
670        imask = str_conv_int(mask, 0);
671
672        if (family == PF_INET6) {
673            if (imask <= 0)
674                imask = 128;
675            else if (imask > 128)
676                imask = 128;
677        } else {
678            if (imask <= 0)
679                imask = 32;
680            else if (imask > 32)
681                imask = 32;
682        }
683        memset(bitmask, 0, IPADDR_SIZE);
684        /* walk down i, setting bits as necessary. */
685        for (i = imask;i > 0;i -= (i % 8 ? i % 8 : 8))
686            bitmask[(i - 1) / 8] = 0xff << (i % 8 ? (8 - (i % 8)) : 0);
687    }
688
689    /* now copy our addresses into bitmasks.  if either pton fails, assume no
690     * match. */
691    if (inet_pton(family, addr, bwild) != 1)
692        return 0;
693    if (inet_pton(family, str, bstr) != 1)
694        return 0;
695
696    /* now walk along the wild bitstring and the str bitstring and modify them
697     * as per the bitmask string, then do a straight compare. */
698    alen = (family == PF_INET6 ? 16 : 4);
699    for (i = 0;i < alen;i++) {
700        bwild[i] &= bitmask[i];
701        bstr[i] &= bitmask[i];
702
703        if (bwild[i] != bstr[i])
704            return 0;
705    }
706    return 1; /* made it all the way through!  voila. */
707}
708
709/* these are safe string converters used to, effectively, turn strings into
710 * various things.  each is given a default in the case that the string is
711 * mangled or somehow unuseable, so it is safe to use these in assignments no
712 * matter what. */
713
714/* this function takes a string and determines if it is a boolean value
715 * (yes/no, on/off, 1/0).  the second will convert a boolean value to one of
716 * the two values given as the second arguments (pos/neg), so for example:
717 * bool_conv_str(1, "yes", "no") returns "yes" */
718bool str_conv_bool(char *str, bool def) {
719
720    if (str == NULL)
721        return def;
722
723    if (!strcasecmp(str, "yes") || !strcasecmp(str, "on") || atoi(str))
724        return 1;
725    else if (!strcasecmp(str, "no") || !strcasecmp(str, "off") || !atoi(str))
726        return 0;
727
728    return def;
729}
730
731const char *bool_conv_str(bool val, const char *pos, const char *neg) {
732
733    if (val)
734        return pos;
735    else
736        return neg;
737}
738
739/* these two are used to convert from/to a formatted time string.  the string
740 * should be of the format [Xd][Xh][Xm][X][s].  e.g. 3600 is 3600s, or 1h.
741 * either lower or upper case is acceptable. */
742time_t str_conv_time(char *str, int def) {
743    char *s = str;
744    char *s2;
745    time_t ret = 0;
746
747    if (str == NULL)
748        return def;
749
750    s2 = strchr(s, 'd');
751    if (s2 != NULL) {
752        *s2 = '\0';
753        ret += str_conv_int(s, 0) * 86400; /* days */
754        s = s2 + 1;
755    }
756    s2 = strchr(s, 'h');
757    if (s2 != NULL) {
758        *s2 = '\0';
759        ret += str_conv_int(s, 0) * 3600; /* hours */
760        s = s2 + 1;
761    }
762    s2 = strchr(s, 'm');
763    if (s2 != NULL) {
764        *s2 = '\0';
765        ret += str_conv_int(s, 0) * 60; /* minutes */
766        s = s2 + 1;
767    }
768    ret += str_conv_int(s, 0); /* seconds */
769
770    return ret;
771}
772
773char *time_conv_str(time_t itime) {
774    int d, h, m, s;
775    static char rbuf[64];
776    int rlen = 0;
777
778    d = itime / 86400; /* days */
779    itime %= 86400;
780    h = itime / 3600; /* hours */
781    itime %= 3600;
782    m = itime / 60; /* minutes */
783    itime %= 60;
784    s = itime;
785
786    if (d)
787        rlen += sprintf(rbuf + rlen, "%dd", d);
788    if (h)
789        rlen += sprintf(rbuf + rlen, "%dh", h);
790    if (m)
791        rlen += sprintf(rbuf + rlen, "%dm", m);
792    if (s)
793        rlen += sprintf(rbuf + rlen, "%ds", s);
794    if (!rlen) { /* if we haven't added anything, it's 0s */
795        rbuf[0] = '0';
796        rbuf[1] = 's';
797        rbuf[2] = '\0';
798    }
799
800    return rbuf;
801}
802
803/* lastly, wrappers to convert strings to integers and vice versa.  slightly
804 * safer than atoi, but less robust than strtol except that we check strtol
805 * for errors. :) */
806int str_conv_int(char *str, int def) {
807    int ret, esave = errno;
808
809    errno = 0;
810
811    if (str == NULL)
812        return def;
813    ret = strtol(str, NULL, 0);
814
815    if (errno) /* just return their default to them ... */
816        ret = def;
817
818    /* XXX: we trample errno here, so the user doesn't know what went wrong.
819     * :/ */
820    errno = esave;
821
822    return ret;
823}
824
825char *int_conv_str(int number) {
826    static char rbuf[32];
827
828    sprintf(rbuf, "%d", number); /* this is cheating, but it's easier and not
829                                    much slower.. */
830
831    return rbuf;
832}
833
834/*****************************************************************************
835 * baseN encoding/decoding functions                                         *
836 *****************************************************************************/
837/* Tables for base conversion.  We use one kind for everything but base64, and
838 * another to provide RFC1521 compatible base64 mapping. */
839static char base_emap[32] = "0123456789abcdefghijklmnopqrstuv";
840static char base64_emap[64] =
841"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
842
843static char base_dmap[256] = {
844    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
845    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
846    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
847    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
848    -1, -1, -1, -1, -1, -1, -1, -1,  0,  1,
849     2,  3,  4,  5,  6,  7,  8,  9, -1, -1,
850    -1, -1, -1, -1, -1, 10, 11, 12, 13, 14,
851    15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
852    25, 26, 27, 28, 29, 30, 31, -1, -1, -1,
853    -1, -1, -1, -1, -1, -1, -1, 10, 11, 12,
854    13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
855    23, 24, 25, 26, 27, 28, 29, 30, 31, -1
856    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
857    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
858    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
859    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
860    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
861    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
862    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
863    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
864    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
865    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
866    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
867    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
868    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
869    -1, -1, -1, -1, -1, -1
870};
871static char base64_dmap[256] = { /* -2 means skip. */
872    -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, /* skip '\t' */
873    -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, /* skip '\n', '\v', '\f', '\r' */
874    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
875    -1, -1, -2, -1, -1, -1, -1, -1, -1, -1, /* skip ' ' */
876    -1, -1, -1, 62, -1, -1, -1, 63, 52, 53,
877    54, 55, 56, 57, 58, 59, 60, 61, -1, -1,
878    -1, -2, -1, -1, -1,  0,  1,  2,  3,  4, /* skip '=' */
879     5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
880    15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
881    25, -1, -1, -1, -1, -1, -1, 26, 27, 28,
882    29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
883    39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
884    49, 50, 51, -1, -1, -1, -1, -1, -1, -1
885    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
886    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
887    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
888    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
889    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
890    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
891    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
892    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
893    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
894    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
895    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
896    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
897    -1, -1, -1, -1, -1, -1
898};
899
900/* This function encodes a data stream in the specified format into the given
901 * buffer.  It is not always safe to encode into the same buffer, so be careful
902 * to allocate the necessary space!  The function returns the length of the
903 * string, not including the padding NUL byte. */
904size_t str_base_encode(char type, char *dest, char *src, size_t len) {
905    char *map = (type == BASE64_ENCODING ? base64_emap : base_emap);
906    unsigned int chunk = 0;
907    int bits = 0;
908    size_t count = 0;
909
910    while (len > 0) {
911        if (bits < type) {
912            chunk <<= 8;
913            chunk += (unsigned char)*src++;
914            bits += 8;
915            len--;
916        } 
917        while (bits >= type) {
918            *dest++ = map[chunk >> (bits - type)];
919            bits -= type;
920            chunk &= 0xff >> (8 - bits);
921            count++;
922        }
923    }
924    if (bits > 0) {
925        *dest++ = map[chunk << (type - bits)];
926        count++;
927    }
928   
929    *dest = '\0';
930
931    return count;
932}
933
934/* This function decodes the stream 'src' (in the specified encoding) into
935 * 'dest'.  It is always safe to decode into the same string because the result
936 * is always smaller, and will not trample any buffers.  The function returns
937 * 'true' if the conversion was successful, and 'false' otherwise.  The
938 * conversion will not 'fail' on invalid characters, but it will skip them. */
939size_t str_base_decode(char type, char *dest, char *src, size_t len) {
940    char *map = (type == BASE64_ENCODING ? base64_dmap : base_dmap);
941    unsigned int chunk = 0;
942    int bits = 0;
943    size_t count = 0;
944
945    errno = 0;
946    while (len > 0) {
947        if (map[(unsigned char)*src] < 0 ||
948                map[(unsigned char)*src] >= (1 << type)) {
949            src++;
950            len--;
951            if (map[(unsigned char)*src] != -2)
952                errno = EINVAL;
953            continue; /* skip bogus/separator characters */
954        }
955        chunk <<= type;
956        chunk += map[(unsigned char)*src++];
957        bits += type;
958        len--;
959        if (bits >= 8) {
960            *dest++ = chunk >> (bits - 8);
961            chunk ^= 0xff << (bits - 8);
962            bits -= 8;
963            count++;
964        }
965    }
966    if (bits != 0) {
967        *dest++ = chunk;
968        count++;
969    }
970
971    return count;
972}
973
974/* include fmtcheck if we don't have it */
975#ifndef HAVE_FMTCHECK
976#include "contrib/fmtcheck.c"
977#endif
978/* strlcpy and strlcat too */
979#ifndef HAVE_STRLCAT
980#include "contrib/strlcat.c"
981#endif
982#ifndef HAVE_STRLCPY
983#include "contrib/strlcpy.c"
984#endif
985
986/* vi:set ts=8 sts=4 sw=4 tw=76 et: */
Note: See TracBrowser for help on using the repository browser.