|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T s
Length: 16141 (0x3f0d)
Types: TextFile
Names: »string.c«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
└─⟦2fafebccf⟧ »EurOpenD3/mail/smail3.1.19.tar.Z«
└─⟦bcd2bc73f⟧
└─⟦this⟧ »src/string.c«
/* @(#)string.c 3.33 11/27/88 16:26:40 */
/*
* 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();
\f
/*
* 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;
}
\f
/*
* 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;
}
\f
/*
* 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;
}
}
\f
/*
* 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 */
}