home *** CD-ROM | disk | FTP | other *** search
/ back2roots/padua / padua.7z / padua / uucp / auucp+-1.02 / fuucp_plus_src.lzh / sendmail / string.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-11-21  |  15.8 KB  |  710 lines

  1. /* @(#)string.c    3.33 11/27/88 16:26:40 */
  2.  
  3. /*
  4.  *    Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
  5.  * 
  6.  * See the file COPYING, distributed with smail, for restriction
  7.  * and warranty information.
  8.  */
  9.  
  10. /*
  11.  * strings.c:
  12.  *    miscellaneous string operations
  13.  *
  14.  *    external functions:  strcmpic, strncmpic, strip, strcolon,
  15.  *                 is_string_in_list, strerrno, strsysexit,
  16.  *                 str_printf, xprintf, dprintf, c_atol, base62,
  17.  *                 read_line, str_cat, vfprintf, ivaltol
  18.  */
  19. #include <stdio.h>
  20. #include <ctype.h>
  21. #include "defs.h"
  22. #ifndef STANDALONE
  23. # include <varargs.h>
  24. # include "smail.h"
  25. # include "dys.h"
  26. # ifndef DEPEND
  27. #  include "extern.h"
  28. #  include "exitcodes.h"
  29. # endif
  30. #else /* STANDALONE */
  31. extern char lowcase[];            /* lower case conversion table */
  32. extern char upcase[];            /* upper case conversion table */
  33. #endif /* STANDALONE */
  34.  
  35. /* functions local to this file */
  36. static char *bltoa();
  37. static void str_printf_va();
  38.  
  39.  
  40. /*
  41.  * strcmpic - case independent strcmp function
  42.  */
  43. int
  44. strcmpic(s1, s2)
  45.     register char *s1, *s2;        /* strings to be compared */
  46. {
  47.     register int c1, c2;        /* temp */
  48.  
  49.     while (*s1 && *s2) {
  50. #ifdef USE_ASCII
  51.     if ((c1 = tolower(*s1++)) != (c2 = tolower(*s2++))) {
  52.         return c1-c2;
  53.     }
  54. #else /* USE_ASCII */
  55.     if (isupper(c1 = *s1++)) {
  56.         c1 = tolower(c1);
  57.     }
  58.     if (isupper(c2 = *s2++)) {
  59.         c2 = tolower(c2);
  60.     }
  61.     if (c1 != c2) {
  62.         return c1-c2;        /* strings are not equal */
  63.     }
  64. #endif /* USE_ASCII */
  65.     }
  66.  
  67.     /*
  68.      * one or both chars must be `\0'.  If only one is `\0', then
  69.      * the other string is longer.
  70.      */
  71.     return (int)((*s1)-(*s2));
  72. }
  73.  
  74. /*
  75.  * strcmpic - case independent strcmp function
  76.  */
  77. int
  78. strncmpic(s1, s2, n)
  79.     register char *s1, *s2;        /* strings to compare */
  80.     int n;                /* compare up to this many chars */
  81. {
  82.     register int c1, c2;        /* temp */
  83.     register int cnt = n;        /* count of chars so far compared */
  84.  
  85.     while (*s1 && *s2 && cnt > 0) {
  86. #ifdef USE_ASCII
  87.     if ((c1 = tolower(*s1++)) != (c2 = tolower(*s2++))) {
  88.         return c1-c2;
  89.     }
  90. #else /* USE_ASCII */
  91.     if (isupper(c1 = *s1++)) {
  92.         c1 = tolower(c1);
  93.     }
  94.     if (isupper(c2 = *s2++)) {
  95.         c2 = tolower(c2);
  96.     }
  97.     if (c1 != c2) {
  98.         return c1-c2;        /* strings are not equal */
  99.     }
  100. #endif /* USE_ASCII */
  101.     cnt--;                /* count this character */
  102.     }
  103.  
  104.     /*
  105.      * If we ran out of chars, then the string segments are equal, otherwise
  106.      * one or both strings must have ended. In this case the subtraction
  107.      * will show which one is shorter, if any.
  108.      */
  109.     return cnt ? (int)((*s1)-(*s2)) : 0;
  110. }
  111.  
  112.  
  113. /*
  114.  * strip - strip quotes and escaped characters
  115.  */
  116. int
  117. strip(addr)
  118.     register char *addr;        /* strip this address */
  119. {
  120.     int was_stripped = FALSE;        /* TRUE if any stripping was done */
  121.     register char *p = addr;        /* write pointer to addr */
  122.     register int c;            /* read char in addr */
  123.  
  124.     while (c = *addr++) {
  125.     if (c == '\\') {        /* skip to char after \ */
  126.         *p++ = *addr++;
  127.         was_stripped = TRUE;
  128.     } else if (c == '"') {        /* don't copy quote char */
  129.         was_stripped = TRUE;
  130.     } else {
  131.         *p++ = c;
  132.     }
  133.     }
  134.     *p++ = '\0';            /* end of string */
  135.  
  136.     return was_stripped;
  137. }
  138.  
  139. /*
  140.  * strcolon - step through string parts separated by colons
  141.  *
  142.  * when called with a string, return a copy of the first part of
  143.  * the string up to, but excluding the first `:'.  When called with
  144.  * NULL return a copy of the next part of the previously passed string,
  145.  * with each part separated by a colon `:'.
  146.  *
  147.  * return NULL if no more parts are left.
  148.  *
  149.  * strcolon is typically used in a loop on ':' separated names such as:
  150.  *
  151.  *    for (p = strcolon(names); p; p = strcolon((char *)NULL)) {
  152.  *        ... do something with the name p ...
  153.  *    }
  154.  *
  155.  * the malloc region returned is reused, so if you wish to keep a string
  156.  * around, you will need to copy it.
  157.  */
  158. char *
  159. strcolon(s)
  160.     register char *s;            /* string or NULL */
  161. {
  162.     static char *next = NULL;        /* pointer to next ':' */
  163.     static char *region = NULL;        /* region used to store result */
  164.     static int alloc = 0;        /* alloc size of region */
  165.  
  166.     if (!s) {
  167.     s = next;
  168.     if (s == NULL) {
  169.         return NULL;
  170.     }
  171.     }
  172.     next = index(s, ':');
  173.     if (next) {
  174.     register int len = next - s;
  175.  
  176.     if (len >= alloc) {
  177.         if (region == NULL) {
  178.         region = xmalloc(alloc = len + 1);
  179.         } else {
  180.         region = xrealloc(region, alloc = len + 1);
  181.         }
  182.     }
  183.     (void) memcpy(region, s, next - s);
  184.     region[next - s] = '\0';
  185.     next++;
  186.     return region;
  187.     }
  188.     return s;
  189. }
  190.  
  191. /*
  192.  * is_string_in_list - return true if string is in colon-separated list
  193.  *
  194.  * given a string and a colon separated list of strings, return TRUE
  195.  * if the given string is in the list, else FALSE.  Case is not
  196.  * significant in comparisons.
  197.  */
  198. int
  199. is_string_in_list(string, list)
  200.     register char *string;        /* string to look for */
  201.     char *list;                /* list of strings */
  202. {
  203.     register char *s;
  204.  
  205.     for (s = strcolon(list); s; s = strcolon((char *)NULL)) {
  206.     if (EQIC(string, s)) {
  207.         return TRUE;
  208.     }
  209.     }
  210.  
  211.     return FALSE;
  212. }
  213.  
  214.  
  215. /*
  216.  * strerrno -  return a string representing the error stored in errno.
  217.  */
  218. char *
  219. strerrno()
  220. {
  221.     static char misc_err[50];        /* used when sprintf must be used */
  222.     extern char *sys_errlist[];        /* list of error strings */
  223.     extern int sys_nerr;        /* number of entries in sys_errlist */
  224.  
  225.     if (errno > sys_nerr || errno < 0) {
  226.     /* there is no entry for it in sys_errlist, build one */
  227.     (void) sprintf(misc_err, "Unknown errno (%d)", errno);
  228.     return misc_err;
  229.     } else {
  230.     /* there is an entry in sys_errlist, use it */
  231.     return sys_errlist[errno];
  232.     }
  233. }
  234.  
  235. /*
  236.  * strsysexit - return a string corresponding to an exit code.
  237.  */
  238. char *
  239. strsysexit(exitcode)
  240.     int exitcode;
  241. {
  242.     static char buf[50];        /* buffer for generating message */
  243.  
  244.     switch (exitcode) {
  245.     case EX_USAGE:
  246.     return "EX_USAGE";
  247.     case EX_DATAERR:
  248.     return "EX_DATAERR";
  249.     case EX_NOINPUT:
  250.     return "EX_NOINPUT";
  251.     case EX_NOUSER:
  252.     return "EX_NOUSER";
  253.     case EX_NOHOST:
  254.     return "EX_NOHOST";
  255.     case EX_UNAVAILABLE:
  256.     return "EX_UNAVAILABLE";
  257.     case EX_SOFTWARE:
  258.     return "EX_SOFTWARE";
  259.     case EX_OSERR:
  260.     return "EX_OSERR";
  261.     case EX_OSFILE:
  262.     return "EX_OSFILE";
  263.     case EX_CANTCREAT:
  264.     return "EX_CANTCREAT";
  265.     case EX_IOERR:
  266.     return "EX_IOERR";
  267.     case EX_TEMPFAIL:
  268.     return "EX_TEMPFAIL";
  269.     case EX_PROTOCOL:
  270.     return "EX_PROTOCOL";
  271.     case EX_NOPERM:
  272.     return "EX_NOPERM";
  273.     default:
  274.     (void) sprintf(buf, "EX_%d", exitcode);
  275.     return buf;
  276.     }
  277. }
  278.  
  279.  
  280. /*
  281.  * str_printf - highly simplified printf to a dynamic string
  282.  * str_printf_va - ditto, but taking a va_list parameter
  283.  *
  284.  * note that we only support %s, %d, %o, %x and %c.  Also support
  285.  * a %N which inserts a null byte.
  286.  */
  287. /*VARARGS*/
  288. void
  289. str_printf(sp, fmt, va_alist)
  290.     struct str *sp;            /* append to this string */
  291.     char *fmt;                /* printf-style format string  */
  292.     va_dcl
  293. {
  294.     va_list ap;                /* placeholder for varargs */
  295.  
  296.     va_start(ap);
  297.     str_printf_va(sp, fmt, ap);
  298.     va_end(ap);
  299. }
  300.  
  301. static void
  302. str_printf_va(sp, fmt, ap)
  303.     register struct str *sp;        /* append to this string */
  304.     register char *fmt;            /* printf-style format string */
  305.     va_list ap;                /* placeholder for varargs */
  306. {
  307.     register int c;            /* current char in fmt */
  308.     register int islong;                /* to handle %ld */
  309.     long n;                             /* temp */
  310.     char *s;                /* temp */
  311.  
  312.     /*
  313.      * loop on the format string copying into the string sp
  314.      */
  315.     while (c = *fmt++) {
  316.     if (c != '%') {
  317.         STR_NEXT(sp, c);
  318.     } else {
  319.         if (islong = (*fmt == 'l'))
  320.         fmt++;
  321.         switch (c = *fmt++) {
  322.         case '\0':
  323.         STR_NEXT(sp, '%');
  324.         --fmt;
  325.         break;
  326.         case 's':
  327.         if (s = va_arg(ap, char *)) {
  328.             STR_CAT(sp, s);
  329.         } else {
  330.             STR_CAT(sp, "(null)");
  331.         }
  332.         break;
  333.         case 'c':
  334.         STR_NEXT(sp, va_arg(ap, int));
  335.         break;
  336.         case 'o':
  337.         n = islong ? va_arg(ap,long) : (long)va_arg(ap,unsigned);
  338.         STR_CAT(sp, bltoa(8, n));
  339.         break;
  340.         case 'x':
  341.         n = islong ? va_arg(ap,long) : (long)va_arg(ap,unsigned);
  342.         STR_CAT(sp, bltoa(16, n));
  343.         break;
  344.         case 'u':
  345.         n = islong ? va_arg(ap,long) : (long)va_arg(ap,unsigned);
  346.         STR_CAT(sp, bltoa(10, n));
  347.         break;
  348.         case 'd':
  349.         n = islong ? va_arg(ap,long) : (long)va_arg(ap,int);
  350.         if (n < 0) {
  351.             STR_NEXT(sp, '-');
  352.             n = -n;
  353.         }
  354.         STR_CAT(sp, bltoa(10, n));
  355.         break;
  356.         case 'N':            /* how to insert a nul byte */
  357.         STR_NEXT(sp, '\0');
  358.         case '%':
  359.         STR_NEXT(sp, '%');
  360.         break;
  361.         default:
  362.         break;
  363.         }
  364.     }
  365.     }
  366. }
  367.  
  368. /*
  369.  * bltoa - convert long integer to string representation in given base
  370.  *
  371.  * standard bug about pointing to static data.
  372.  */
  373. static char *
  374. bltoa(base, n)
  375.     register unsigned base;        /* base for conversion */
  376.     register long     n;                /* number to convert */
  377. {
  378.     static char buf[BITS_PER_INT + 1];    /* plenty big */
  379.     register char *p = buf + sizeof(buf); /* start at end and move backward */
  380.     register int i;
  381.  
  382.     *--p = '\0';            /* terminate string */
  383.     if (n == 0) {
  384.     /* special case, 0 is just "0" */
  385.     *--p = '0';
  386.     return p;
  387.     }
  388.     /* get more significant digits until no more are required */
  389.     while (n > 0) {
  390.     /* allow for bases up to 16 */
  391.     i = n % base;
  392.     n /= base;
  393.     *--p = "0123456789abcdef"[i];
  394.     }
  395.     return p;
  396. }
  397.  
  398. /*
  399.  * xprintf - str_print to a region, returning pointer to region
  400.  */
  401. /*VARARGS1*/
  402. char *
  403. xprintf(fmt, va_alist)
  404.     char *fmt;                /* str_printf-style format string */
  405.     va_dcl
  406. {
  407.     struct str str;
  408.     va_list ap;
  409.  
  410.     STR_INIT(&str);
  411.     va_start(ap);
  412.     str_printf_va(&str, fmt, ap);
  413.     va_end(ap);
  414.     STR_NEXT(&str, '\0');
  415.     STR_DONE(&str);
  416.     return str.p;
  417. }
  418.  
  419. /*
  420.  * dprintf - debugging printf to a file
  421.  *
  422.  * This allows the DEBUGx() macros to explicitly follow the convention that
  423.  * printing a NULL string pointer displays "(null)".  The System V
  424.  * printf() does not follow this convention, and thus cannot be used.
  425.  */
  426. /*VARARGS2*/
  427. int
  428. dprintf(file, fmt, va_alist)
  429.     FILE *file;
  430.     char *fmt;
  431.     va_dcl
  432. {
  433.     static struct str str;
  434.     static int inited = FALSE;
  435.     va_list ap;
  436.  
  437.     if (! inited) {
  438.     STR_INIT(&str);
  439.     } else {
  440.     str.i = 0;
  441.     }
  442.     va_start(ap);
  443.     str_printf_va(&str, fmt, ap);
  444.     va_end(ap);
  445.     STR_NEXT(&str, '\0');
  446.  
  447.     return fputs(str.p, file);
  448. }
  449.  
  450. /*
  451.  * c_atol - convert an ascii string to a long, C-style.
  452.  *
  453.  * Handle the forms  [+-]?0[0-7]* [+-]?0x[0-9a-f]* and [+-]?[1-9][0-9]*.
  454.  * an optional suffix of one of the letters:  k, K, or M is allowed, as
  455.  * a multplier by 1024 or 1048576.  If the string given is malformed,
  456.  * error will be set to an error message.
  457.  */
  458. long
  459. c_atol(input, error)
  460.     register char *input;        /* input string */
  461.     char **error;            /* return error message here */
  462. {
  463.     char *input_string = input;
  464.     long val = 0;
  465.     int sign = 1;
  466.     int digval;
  467.     int base = 10;
  468.  
  469.     /* handle a leading sign character */
  470.     if (*input == '-') {
  471.     sign = -1;
  472.     input++;
  473.     } else if (*input == '+') {
  474.     input++;
  475.     }
  476.  
  477.     /* what is the base */
  478.     if (*input == '0') {
  479.     input++;
  480.     base = 8;
  481.     if (*input == 'x' || *input == 'X') {
  482.         base = 16;
  483.         input++;
  484.     }
  485.     }
  486.  
  487.     /* decode the number */
  488.     while (*input) {
  489.     if (isdigit(*input)) {
  490.         digval = *input++ - '0';
  491.     } else {
  492.         if (islower(*input)) {
  493.         digval = *input++ - 'a' + 10;
  494.         } else if (isupper(*input)) {
  495.         digval = *input++ - 'A' + 10;
  496.         } else {
  497.         break;
  498.         }
  499.     }
  500.     if (digval >= base) {
  501.         --input;
  502.         break;
  503.     }
  504.     val = val*base + digval;
  505.     }
  506.  
  507.     /* set the correct sign */
  508.     val *= sign;
  509.  
  510.     /* is there an optional multiplier? */
  511.     if (*input == 'k' || *input == 'K') {
  512.     input++;
  513.     val *= 1024;
  514.     }
  515.     if (*input == 'M') {
  516.     input++;
  517.     val *= 1024 * 1024;
  518.     }
  519.  
  520.     /* there should be nothing left of the input string at this point */
  521.     if (*input) {
  522.     *error = xprintf("invalid number: %s", input_string);
  523.     }
  524.     return val;
  525. }
  526.  
  527. /*
  528.  * base62 - convert a long integer into ASCII base 62
  529.  *
  530.  * uses upper and lowercase letters, plus numbers.
  531.  * always returns a string of exactly 6 characters, plus a null byte.
  532.  *
  533.  * returns a static area which is reused for each call.
  534.  */
  535. char *
  536. base62(val)
  537.     unsigned long val;
  538. {
  539.     static char base62_chars[] =
  540.     "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  541.     static char buf[7];
  542.     register char *p = buf + sizeof(buf) - 1;
  543.  
  544.     *p = '\0';
  545.     while (p > buf) {
  546.     *--p = base62_chars[val % 62];
  547.     val /= 62;
  548.     }
  549.  
  550.     return buf;
  551. }
  552.  
  553. #ifdef notused
  554. /*
  555.  * read_line - read a line from an input stream and return a pointer to it
  556.  *
  557.  * Any trailing newline is stripped from the returned string.
  558.  *
  559.  * returns a static area which may be reused after subsequent calls.
  560.  */
  561. char *
  562. read_line(f)
  563.     register FILE *f;
  564. {
  565.     static int inited = FALSE;
  566.     static struct str line;
  567.     register int c;
  568.  
  569.     if (! inited) {
  570.     inited = TRUE;
  571.     STR_INIT(&line);
  572.     } else {
  573.     line.i = 0;
  574.     }
  575.     while ((c = getc(f)) != '\n' && c != EOF) {
  576.     STR_NEXT(&line, c);
  577.     }
  578.     STR_NEXT(&line, '\0');
  579.     return line.p;
  580. }
  581. #endif    /* notused */
  582.  
  583. /*
  584.  * str_cat - concatenate a C string onto the end of dynamic string
  585.  *
  586.  * Concatenate a string onto the end of a dynamic string region,
  587.  * growing the region as necessary.
  588.  */
  589. void
  590. str_cat(sp, s)
  591.     register struct str *sp;
  592.     char *s;
  593. {
  594.     register unsigned l;        /* maximum chars needed */
  595.  
  596.     l = (unsigned)strlen(s);
  597.     if (l + sp->i > sp->a) {
  598.     /*
  599.      * need to expand the region:
  600.      * bump up to a sufficiently large region which is a multiple
  601.      * of STR_BUMP (except for a pointer).  Allow at least 10 free
  602.      * chars in the region, for future expansion.
  603.      */
  604.     sp->a = (sp->i + l + STR_BUMP + 10) & (~(STR_BUMP-1)) - sizeof(long);
  605.     sp->p = xrealloc(sp->p, sp->a);
  606.     }
  607.     /* copy string to the end of the region */
  608.     (void) memcpy(sp->p + sp->i, s, l);
  609.     sp->i += l;
  610. }
  611.  
  612. #ifndef HAVE_VFPRINTF
  613. /*
  614.  * vfprintf - a hacked version of vfprintf() for sites that don't have it
  615.  *
  616.  * XXX - will _doprnt() work here?
  617.  */
  618. int
  619. vfprintf(file, fmt, ap)
  620.     FILE *file;
  621.     char *fmt;
  622.     va_list ap;
  623. {
  624.     int a,b,c,d,e,f,g, h;
  625.  
  626.     a = va_arg(ap, int);
  627.     b = va_arg(ap, int);
  628.     c = va_arg(ap, int);
  629.     d = va_arg(ap, int);
  630.     e = va_arg(ap, int);
  631.     f = va_arg(ap, int);
  632.     g = va_arg(ap, int);
  633.     h = va_arg(ap, int);
  634.  
  635.     return fprintf(file, fmt, a,b,c,d,e,f,g,h);
  636. }
  637. #endif    /* HAVE_VFPRINTF */
  638.  
  639. /*
  640.  * ivaltol - convert time interval string into a long integer
  641.  *
  642.  * Take a string defining an interval and convert it into seconds.  An
  643.  * interval is the sum of seconds desribed by terms formed from a
  644.  * decimal integer and a suffix.  The suffix gives a multiplier for
  645.  * the term and can be one of 'y' (years), 'w' (weeks), 'd' (days),
  646.  * 'h' (hours), 'm' (minutes) or 's' (seconds).  If the last term does
  647.  * not have a suffix, 's' is assumed.  For example, an interval string
  648.  * of "1h10m3s" would represent one hour, ten minutes and 30 seconds
  649.  * and would be converted to the equivalent number of seconds.
  650.  *
  651.  * A negative integer is returned for illegal intervals.
  652.  *
  653.  * Note:  interval values are only useful if they fit within an
  654.  *      unsigned integer, so callers of this routine should do range
  655.  *      checking to make sure the value returned is not too large.
  656.  */
  657. long
  658. ivaltol(s)
  659.     register char *s;            /* string containing queue interval */
  660. {
  661.     long ret = 0;            /* return value */
  662.     long cur = 0;            /* value of current part */
  663.     char *ss = s;            /* saved value of s */
  664.  
  665.     while (*s) {
  666.     switch (*s++) {
  667.     case '0': case '1': case '2': case '3': case '4':
  668.     case '5': case '6': case '7': case '8': case '9':
  669.         cur = cur * 10 + s[-1] - '0';
  670.         break;
  671.  
  672.     case 'y':            /* years = 365.24 days */
  673.         ret += (cur * 60*60*24*365) + (cur * 60*60*24*24)/100;
  674.         cur = 0;
  675.         break;
  676.  
  677.     case 'w':            /* weeks */
  678.         ret += cur * 60*60*24*7;
  679.         cur = 0;
  680.         break;
  681.  
  682.     case 'd':            /* days */
  683.         ret += cur * 60*60*24;
  684.         cur = 0;
  685.         break;
  686.  
  687.     case 'h':            /* hours */
  688.         ret += cur * 60*60;
  689.         cur = 0;
  690.         break;
  691.  
  692.     case 'm':
  693.         ret += cur * 60;        /* minutes */
  694.         cur = 0;
  695.         break;
  696.  
  697.     case 's':
  698.         ret += cur;            /* seconds */
  699.         cur = 0;
  700.         break;
  701.  
  702.     default:
  703.         return -1L;
  704.     }
  705.     }
  706.  
  707.     return ret + cur;            /* all done */
  708. }
  709.  
  710.