This is string.c in view mode; [Download] [Up]
/* @(#)src/string.c 1.2 24 Oct 1990 05:25:28 */ /* * Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll * * See the file COPYING, distributed with smail, for restriction * and warranty information. */ /* * strings.c: * miscellaneous string operations * * external functions: strcmpic, strncmpic, strip, strcolon, * is_string_in_list, strerrno, strsysexit, * str_printf, xprintf, dprintf, c_atol, base62, * read_line, str_cat, vfprintf, ivaltol */ #include <stdio.h> #include <ctype.h> #include "defs.h" #ifndef STANDALONE # include <varargs.h> # include "smail.h" # include "dys.h" # ifndef DEPEND # include "extern.h" # include "exitcodes.h" # endif #else /* STANDALONE */ extern char lowcase[]; /* lower case conversion table */ extern char upcase[]; /* upper case conversion table */ #endif /* STANDALONE */ /* functions local to this file */ static char *bltoa(); static void str_printf_va(); /* * strcmpic - case independent strcmp function */ int strcmpic(s1, s2) register char *s1, *s2; /* strings to be compared */ { register int c1, c2; /* temp */ while (*s1 && *s2) { #ifdef USE_ASCII if ((c1 = tolower(*s1++)) != (c2 = tolower(*s2++))) { return c1-c2; } #else /* USE_ASCII */ if (isupper(c1 = *s1++)) { c1 = tolower(c1); } if (isupper(c2 = *s2++)) { c2 = tolower(c2); } if (c1 != c2) { return c1-c2; /* strings are not equal */ } #endif /* USE_ASCII */ } /* * one or both chars must be `\0'. If only one is `\0', then * the other string is longer. */ return (int)((*s1)-(*s2)); } /* * strcmpic - case independent strcmp function */ int strncmpic(s1, s2, n) register char *s1, *s2; /* strings to compare */ int n; /* compare up to this many chars */ { register int c1, c2; /* temp */ register int cnt = n; /* count of chars so far compared */ while (*s1 && *s2 && cnt > 0) { #ifdef USE_ASCII if ((c1 = tolower(*s1++)) != (c2 = tolower(*s2++))) { return c1-c2; } #else /* USE_ASCII */ if (isupper(c1 = *s1++)) { c1 = tolower(c1); } if (isupper(c2 = *s2++)) { c2 = tolower(c2); } if (c1 != c2) { return c1-c2; /* strings are not equal */ } #endif /* USE_ASCII */ cnt--; /* count this character */ } /* * If we ran out of chars, then the string segments are equal, otherwise * one or both strings must have ended. In this case the subtraction * will show which one is shorter, if any. */ return cnt ? (int)((*s1)-(*s2)) : 0; } /* * strip - strip quotes and escaped characters */ int strip(addr) register char *addr; /* strip this address */ { int was_stripped = FALSE; /* TRUE if any stripping was done */ register char *p = addr; /* write pointer to addr */ register int c; /* read char in addr */ while (c = *addr++) { if (c == '\\') { /* skip to char after \ */ *p++ = *addr++; was_stripped = TRUE; } else if (c == '"') { /* don't copy quote char */ was_stripped = TRUE; } else { *p++ = c; } } *p++ = '\0'; /* end of string */ return was_stripped; } /* * strcolon - step through string parts separated by colons * * when called with a string, return a copy of the first part of * the string up to, but excluding the first `:'. When called with * NULL return a copy of the next part of the previously passed string, * with each part separated by a colon `:'. * * return NULL if no more parts are left. * * strcolon is typically used in a loop on ':' separated names such as: * * for (p = strcolon(names); p; p = strcolon((char *)NULL)) { * ... do something with the name p ... * } * * the malloc region returned is reused, so if you wish to keep a string * around, you will need to copy it. */ char * strcolon(s) register char *s; /* string or NULL */ { static char *next = NULL; /* pointer to next ':' */ static char *region = NULL; /* region used to store result */ static int alloc = 0; /* alloc size of region */ if (!s) { s = next; if (s == NULL) { return NULL; } } next = index(s, ':'); if (next) { register int len = next - s; if (len >= alloc) { if (region == NULL) { region = xmalloc(alloc = len + 1); } else { region = xrealloc(region, alloc = len + 1); } } (void) memcpy(region, s, next - s); region[next - s] = '\0'; next++; return region; } return s; } /* * is_string_in_list - return true if string is in colon-separated list * * given a string and a colon separated list of strings, return TRUE * if the given string is in the list, else FALSE. Case is not * significant in comparisons. */ int is_string_in_list(string, list) register char *string; /* string to look for */ char *list; /* list of strings */ { register char *s; for (s = strcolon(list); s; s = strcolon((char *)NULL)) { if (EQIC(string, s)) { return TRUE; } } return FALSE; } /* * strerrno - return a string representing the error stored in errno. */ char * strerrno() { static char misc_err[50]; /* used when sprintf must be used */ extern char *sys_errlist[]; /* list of error strings */ extern int sys_nerr; /* number of entries in sys_errlist */ if (errno > sys_nerr || errno < 0) { /* there is no entry for it in sys_errlist, build one */ (void) sprintf(misc_err, "Unknown errno (%d)", errno); return misc_err; } else { /* there is an entry in sys_errlist, use it */ return sys_errlist[errno]; } } /* * strsysexit - return a string corresponding to an exit code. */ char * strsysexit(exitcode) int exitcode; { static char buf[50]; /* buffer for generating message */ switch (exitcode) { case EX_USAGE: return "EX_USAGE"; case EX_DATAERR: return "EX_DATAERR"; case EX_NOINPUT: return "EX_NOINPUT"; case EX_NOUSER: return "EX_NOUSER"; case EX_NOHOST: return "EX_NOHOST"; case EX_UNAVAILABLE: return "EX_UNAVAILABLE"; case EX_SOFTWARE: return "EX_SOFTWARE"; case EX_OSERR: return "EX_OSERR"; case EX_OSFILE: return "EX_OSFILE"; case EX_CANTCREAT: return "EX_CANTCREAT"; case EX_IOERR: return "EX_IOERR"; case EX_TEMPFAIL: return "EX_TEMPFAIL"; case EX_PROTOCOL: return "EX_PROTOCOL"; case EX_NOPERM: return "EX_NOPERM"; default: (void) sprintf(buf, "EX_%d", exitcode); return buf; } } /* * str_printf - highly simplified printf to a dynamic string * str_printf_va - ditto, but taking a va_list parameter * * note that we only support %s, %d, %o, %x and %c. Also support * a %N which inserts a null byte. */ /*VARARGS*/ void str_printf(sp, fmt, va_alist) struct str *sp; /* append to this string */ char *fmt; /* printf-style format string */ va_dcl { va_list ap; /* placeholder for varargs */ va_start(ap); str_printf_va(sp, fmt, ap); va_end(ap); } static void str_printf_va(sp, fmt, ap) register struct str *sp; /* append to this string */ register char *fmt; /* printf-style format string */ va_list ap; /* placeholder for varargs */ { register int c; /* current char in fmt */ register int islong; /* to handle %ld */ long n; /* temp */ char *s; /* temp */ /* * loop on the format string copying into the string sp */ while (c = *fmt++) { if (c != '%') { STR_NEXT(sp, c); } else { if (islong = (*fmt == 'l')) fmt++; switch (c = *fmt++) { case '\0': STR_NEXT(sp, '%'); --fmt; break; case 's': if (s = va_arg(ap, char *)) { STR_CAT(sp, s); } else { STR_CAT(sp, "(null)"); } break; case 'c': STR_NEXT(sp, va_arg(ap, int)); break; case 'o': n = islong ? va_arg(ap,long) : (long)va_arg(ap,unsigned); STR_CAT(sp, bltoa(8, n)); break; case 'x': n = islong ? va_arg(ap,long) : (long)va_arg(ap,unsigned); STR_CAT(sp, bltoa(16, n)); break; case 'u': n = islong ? va_arg(ap,long) : (long)va_arg(ap,unsigned); STR_CAT(sp, bltoa(10, n)); break; case 'd': n = islong ? va_arg(ap,long) : (long)va_arg(ap,int); if (n < 0) { STR_NEXT(sp, '-'); n = -n; } STR_CAT(sp, bltoa(10, n)); break; case 'N': /* how to insert a nul byte */ STR_NEXT(sp, '\0'); case '%': STR_NEXT(sp, '%'); break; default: break; } } } } /* * bltoa - convert long integer to string representation in given base * * standard bug about pointing to static data. */ static char * bltoa(base, n) register unsigned base; /* base for conversion */ register long n; /* number to convert */ { static char buf[BITS_PER_INT + 1]; /* plenty big */ register char *p = buf + sizeof(buf); /* start at end and move backward */ register int i; *--p = '\0'; /* terminate string */ if (n == 0) { /* special case, 0 is just "0" */ *--p = '0'; return p; } /* get more significant digits until no more are required */ while (n > 0) { /* allow for bases up to 16 */ i = n % base; n /= base; *--p = "0123456789abcdef"[i]; } return p; } /* * xprintf - str_print to a region, returning pointer to region */ /*VARARGS1*/ char * xprintf(fmt, va_alist) char *fmt; /* str_printf-style format string */ va_dcl { struct str str; va_list ap; STR_INIT(&str); va_start(ap); str_printf_va(&str, fmt, ap); va_end(ap); STR_NEXT(&str, '\0'); STR_DONE(&str); return str.p; } /* * dprintf - debugging printf to a file * * This allows the DEBUGx() macros to explicitly follow the convention that * printing a NULL string pointer displays "(null)". The System V * printf() does not follow this convention, and thus cannot be used. */ /*VARARGS2*/ int dprintf(file, fmt, va_alist) FILE *file; char *fmt; va_dcl { static struct str str; static int inited = FALSE; va_list ap; if (! inited) { STR_INIT(&str); } else { str.i = 0; } va_start(ap); str_printf_va(&str, fmt, ap); va_end(ap); STR_NEXT(&str, '\0'); return fputs(str.p, file); } /* * c_atol - convert an ascii string to a long, C-style. * * Handle the forms [+-]?0[0-7]* [+-]?0x[0-9a-f]* and [+-]?[1-9][0-9]*. * an optional suffix of one of the letters: k, K, or M is allowed, as * a multplier by 1024 or 1048576. If the string given is malformed, * error will be set to an error message. */ long c_atol(input, error) register char *input; /* input string */ char **error; /* return error message here */ { char *input_string = input; long val = 0; int sign = 1; int digval; int base = 10; /* handle a leading sign character */ if (*input == '-') { sign = -1; input++; } else if (*input == '+') { input++; } /* what is the base */ if (*input == '0') { input++; base = 8; if (*input == 'x' || *input == 'X') { base = 16; input++; } } /* decode the number */ while (*input) { if (isdigit(*input)) { digval = *input++ - '0'; } else { if (islower(*input)) { digval = *input++ - 'a' + 10; } else if (isupper(*input)) { digval = *input++ - 'A' + 10; } else { break; } } if (digval >= base) { --input; break; } val = val*base + digval; } /* set the correct sign */ val *= sign; /* is there an optional multiplier? */ if (*input == 'k' || *input == 'K') { input++; val *= 1024; } if (*input == 'M') { input++; val *= 1024 * 1024; } /* there should be nothing left of the input string at this point */ if (*input) { *error = xprintf("invalid number: %s", input_string); } return val; } /* * base62 - convert a long integer into ASCII base 62 * * uses upper and lowercase letters, plus numbers. * always returns a string of exactly 6 characters, plus a null byte. * * returns a static area which is reused for each call. */ char * base62(val) unsigned long val; { static char base62_chars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; static char buf[7]; register char *p = buf + sizeof(buf) - 1; *p = '\0'; while (p > buf) { *--p = base62_chars[val % 62]; val /= 62; } return buf; } #ifdef notused /* * read_line - read a line from an input stream and return a pointer to it * * Any trailing newline is stripped from the returned string. * * returns a static area which may be reused after subsequent calls. */ char * read_line(f) register FILE *f; { static int inited = FALSE; static struct str line; register int c; if (! inited) { inited = TRUE; STR_INIT(&line); } else { line.i = 0; } while ((c = getc(f)) != '\n' && c != EOF) { STR_NEXT(&line, c); } STR_NEXT(&line, '\0'); return line.p; } #endif /* notused */ /* * str_cat - concatenate a C string onto the end of dynamic string * * Concatenate a string onto the end of a dynamic string region, * growing the region as necessary. */ void str_cat(sp, s) register struct str *sp; char *s; { register unsigned l; /* maximum chars needed */ l = (unsigned)strlen(s); if (l + sp->i > sp->a) { /* * need to expand the region: * bump up to a sufficiently large region which is a multiple * of STR_BUMP (except for a pointer). Allow at least 10 free * chars in the region, for future expansion. */ sp->a = (sp->i + l + STR_BUMP + 10) & (~(STR_BUMP-1)) - sizeof(long); sp->p = xrealloc(sp->p, sp->a); } /* copy string to the end of the region */ (void) memcpy(sp->p + sp->i, s, l); sp->i += l; } #ifndef HAVE_VFPRINTF /* * vfprintf - a hacked version of vfprintf() for sites that don't have it * * XXX - will _doprnt() work here? */ int vfprintf(file, fmt, ap) FILE *file; char *fmt; va_list ap; { int a,b,c,d,e,f,g, h; a = va_arg(ap, int); b = va_arg(ap, int); c = va_arg(ap, int); d = va_arg(ap, int); e = va_arg(ap, int); f = va_arg(ap, int); g = va_arg(ap, int); h = va_arg(ap, int); return fprintf(file, fmt, a,b,c,d,e,f,g,h); } #endif /* HAVE_VFPRINTF */ /* * ivaltol - convert time interval string into a long integer * * Take a string defining an interval and convert it into seconds. An * interval is the sum of seconds desribed by terms formed from a * decimal integer and a suffix. The suffix gives a multiplier for * the term and can be one of 'y' (years), 'w' (weeks), 'd' (days), * 'h' (hours), 'm' (minutes) or 's' (seconds). If the last term does * not have a suffix, 's' is assumed. For example, an interval string * of "1h10m3s" would represent one hour, ten minutes and 30 seconds * and would be converted to the equivalent number of seconds. * * A negative integer is returned for illegal intervals. * * Note: interval values are only useful if they fit within an * unsigned integer, so callers of this routine should do range * checking to make sure the value returned is not too large. */ long ivaltol(s) register char *s; /* string containing queue interval */ { long ret = 0; /* return value */ long cur = 0; /* value of current part */ char *ss = s; /* saved value of s */ while (*s) { switch (*s++) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': cur = cur * 10 + s[-1] - '0'; break; case 'y': /* years = 365.24 days */ ret += (cur * 60*60*24*365) + (cur * 60*60*24*24)/100; cur = 0; break; case 'w': /* weeks */ ret += cur * 60*60*24*7; cur = 0; break; case 'd': /* days */ ret += cur * 60*60*24; cur = 0; break; case 'h': /* hours */ ret += cur * 60*60; cur = 0; break; case 'm': ret += cur * 60; /* minutes */ cur = 0; break; case 's': ret += cur; /* seconds */ cur = 0; break; default: return -1L; } } return ret + cur; /* all done */ }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.