home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.freefriends.org
/
ftp.freefriends.org.tar
/
ftp.freefriends.org
/
arnold
/
Source
/
mush.rstevens.tar.gz
/
mush.tar
/
strings.c.orig
< prev
next >
Wrap
Text File
|
1990-07-04
|
10KB
|
459 lines
/* strings.c Copyright(1988) Dan Heller */
#include "mush.h"
/*
* reverse a string. Useful for uucp-style address comparisons.
*/
char *
reverse(s)
char s[];
{
int n = strlen(s), m;
char c;
if (n < 1)
return 0;
if (n & 1)
n = n/2 + 1, m = n - 2;
else
n /= 2, m = n - 1;
for ( ; m >= 0; m--, n++)
c = s[n], s[n] = s[m], s[m] = c;
return s;
}
/*
* lose the newline character, trailing whitespace, and return the end of p
* test for '\n' separately since some _ctype_[] arrays may not have the
* _S bit set for the newline character. see <ctype.h> for more info.
*/
char *
no_newln(p)
register char *p;
{
register char *p2 = p + strlen(p); /* point it to the null terminator */
while (p2 > p && *--p2 == '\n' || isspace(*p2))
*p2 = 0; /* get rid of newline and trailing spaces */
return p2;
}
/* find any character in s1 that's in s2; return pointer to char in s1. */
char *
any(s1, s2)
register char *s1, *s2;
{
register char *p;
if (!s1 || !*s1 || !s2 || !*s2)
return NULL;
for( ; *s1; s1++) {
for(p = s2; *p; p++)
if (*p == *s1)
return s1;
}
return NULL;
}
/* check two lists of strings each of which contain substrings.
* Each substring is delimited by any char in "delimiters"
* return true if any elements in list1 are on list2.
* thus:
* string1 = "foo, bar, baz"
* string2 = "foobar, baz, etc"
* delimiters = ", \t"
* example returns 1 because "baz" exists in both lists
* NOTE: case is ignored.
*/
chk_two_lists(list1, list2, delimiters)
register char *list1, *list2, *delimiters;
{
register char *p, c;
register int found = 0;
if (!list1 || !list2)
return 0;
if (p = any(list1, delimiters)) {
if (p > list1) {
c = *p; *p = 0;
/* Check list2 against the first word of list1.
* Swap places of list2 and list1 to step through list2.
*/
found = chk_two_lists(list2, list1, delimiters);
*p = c;
}
if (found)
return 1;
for (p++; *p && index(delimiters, *p); p++)
;
if (!*p)
return 0;
} else if (!any(list2, delimiters))
/* Do the trivial case of single words */
return !lcase_strncmp(list1, list2, -1);
else
p = list1;
/* Either only list2 has delims or the first word of list1
* did not match anything in list2. Check list2 against the
* rest of list1. This could be more efficient by using a
* different function to avoid repeating the any() calls.
*/
return chk_two_lists(list2, p, delimiters);
}
bzero(addr, size)
register char *addr;
register int size;
{
while (size-- > 0)
addr[size] = 0;
}
/* do an atoi() on the string passed and return in "val" the decimal value.
* the function returns a pointer to the location in the string that is not
* a digit.
*/
char *
my_atoi(p, val)
register char *p;
register int *val;
{
int positive = 1;
if (!p)
return NULL;
*val = 0;
if (*p == '-')
positive = -1, p++;
while (isdigit(*p))
*val = (*val) * 10 + *p++ - '0';
*val *= positive;
return p;
}
/* strcmp ignoring case */
lcase_strncmp(str1, str2, n)
register char *str1, *str2;
{
while (*str1 && *str2 && --n != 0)
if (lower(*str1) != lower(*str2))
break;
else
str1++, str2++;
return lower(*str1) - lower(*str2);
}
/* strcpy converting everything to lower case (arbitrary) to ignore cases */
char *
lcase_strcpy(dst, src)
register char *dst, *src;
{
register char *s = dst;
/* "lower" is a macro, don't increment its argument! */
while (*dst++ = lower(*src))
src++;
return s;
}
/* this strcpy returns number of bytes copied */
Strcpy(dst, src)
register char *dst, *src;
{
register int n = 0;
if (!dst || !src)
return 0;
while (*dst++ = *src++)
n++;
return n;
}
char *
savestr(s)
register char *s;
{
register char *p;
if (!s)
s = "";
if (!(p = malloc((unsigned) (strlen(s) + 1)))) {
error("out of memory saving %s", s);
return NULL;
}
return strcpy(p, s);
}
/* copy a vector of strings into one string -- return the end of the string */
char *
argv_to_string(p, argv)
register char *p, **argv;
{
register int i;
register char *ptr = p;
*p = 0;
if (!argv[0])
return "";
for (i = 0; argv[i]; i++)
ptr += strlen(sprintf(ptr, "%s ", argv[i]));
*--ptr = 0; /* get rid of the last space */
return ptr;
}
char *
itoa(n)
{
static char buf[10];
return sprintf(buf, "%d", n);
}
/*
* There are two different kinds of sprintf() --those that return char * and
* those that return int. System-V returns int (the length of the resulting
* string). BSD has historically returned a pointer to the resulting string
* instead. Mush was originally written under BSD, so the usage has always
* been to assume the char * method. Because the system-v method is far more
* useful, mush should some day change to use that method, but until then,
* this routine was written to allow all the unix'es to appear the same to
* the programmer regardless of which sprintf is actually used. The "latest"
* version of 4.3BSD (as of Fall 1988) has changed its format to go from the
* historical BSD method to the sys-v method. It is no longer possible to
* simply #ifdef this routine for sys-v --it is now required to use this
* routine regardless of which sprintf is notice to your machine. However,
* if you know your system's sprintf returns a char *, you can remove the
* define in strings.h
*/
#include <varargs.h>
/*VARARGS*/
/*ARGSUSED*/
char *
Sprintf(va_alist)
va_dcl
{
char *buf, *fmt;
va_list ap;
va_start(ap);
buf = va_arg(ap, char *);
fmt = va_arg(ap, char *);
#ifdef VPRINTF
(void) vsprintf(buf, fmt, ap);
#else
{
FILE foo;
foo._cnt = BUFSIZ;
foo._base = foo._ptr = buf; /* may have to be cast (unsigned char *) */
foo._flag = _IOWRT+_IOSTRG;
(void) _doprnt(fmt, ap, &foo);
*foo._ptr = '\0'; /* plant terminating null character */
}
#endif /* VPRINTF */
va_end(ap);
return buf;
}
void
print_argv(argv)
char **argv;
{
while (*argv)
if (debug)
wprint("(%s) ", *argv++);
else
wprint("%s ", *argv++);
wprint("\n");
}
/*
* putstring -- put a string into a file. Expand \t's into tabs and \n's
* into newlines. Append a \n and fflush(fp);
*/
void
putstring(p, fp)
register char *p;
register FILE *fp;
{
for ( ; *p; ++p)
if (*p != '\\')
(void) fputc(*p, fp);
else
switch(*++p) {
case 'n': (void) fputc('\n', fp);
when 't': (void) fputc('\t', fp);
otherwise: (void) fputc(*p, fp);
}
(void) fputc('\n', fp);
(void) fflush(fp);
}
#define chtoi(c) ((int)(c) - (int)'0')
/* m_xlate(str) converts strings of chars which contain ascii representations
* of control characters appearing in str into the literal characters they
* represent. The usual curses-mode character expansions (\Cx -> control-x)
* are honored, as are most C escapes. Unrecognized portions are unchanged.
*/
char *
m_xlate (str)
register char *str;
{
register char *r, *s, *t;
int dv, nd;
/*
* r will receive the new string, s will track the old one,
* and t will step through escape sequences
* This allows the translation to be done in place
*/
r = s = str;
while (s && *s) {
if (*s == '\\') {
t = s + 1;
/*
* After each case below, t should point to the character
* following the escape sequence
*/
switch(*t) {
case '\0' :
/*
* Hmmm ... a backslash followed by the string
* terminator. Copy the backslash ONLY.
*/
*r++ = *s++;
break;
case '0' :
case '1' :
case '2' :
case '3' :
case '4' :
case '5' :
case '6' :
case '7' :
/*
* Convert up to 3 octal digits to their ascii value
*/
dv = chtoi(*t++);
for (nd = 0; (isdigit(*t) && (nd < 2)); nd++)
if (chtoi(*t) < 8)
dv = (8 * dv) + chtoi(*t++);
else
break;
if (dv < 256 && dv > 0)
/* Valid octal number escaped */
*r++ = (char)dv;
else
/* Invalid octal number, so copy unchanged */
while (s < t)
*r++ = *s++;
break;
case 'b' :
*r++ = '\b';
t++;
break;
case 'C' :
t++;
if (*t == '?')
*r++ = '\177';
else if (*t == '~')
*r++ = '\036';
else if (*t == '/')
*r++ = '\037';
else if (isalpha(*t) || *t > '\132' && *t < '\140')
*r++ = *t & 037;
else
while (s <= t) *r++ = *s++;
t++;
break;
case 'E' :
*r++ = '\033';
t++;
break;
case 'f' :
*r++ = '\f';
t++;
break;
case 'n' :
*r++ = '\n';
t++;
break;
case 'r' :
*r++ = '\r';
t++;
break;
case 't' :
*r++ = '\t';
t++;
break;
case '\\' :
*r++ = *t++;
break;
default :
/*
* Not recognized, so copy both characters
*/
*r++ = *s++;
*r++ = *s++;
break;
}
/*
* Now make sure s also points to the character after the
* escape sequence, by comparing to t
*/
if (t > s)
s = t;
} else
*r++ = *s++;
}
*r = '\0';
return str;
}
/*
* Convert control characters to ascii format (reverse effect of m_xlate()).
*/
char *
ctrl_strcpy(s_out, s_in, bind_format)
register char *s_out, *s_in;
{
#if !defined(M_XENIX) || (defined(M_XENIX) && !defined(CURSES))
extern char *_unctrl[];
#endif /* !M_XENIX || M_XENIX && !CURSES */
char *start = s_out;
for (; *s_in; s_in++)
if (*s_in == '\n')
*s_out++ = '\\', *s_out++ = 'n';
else if (*s_in == '\r')
*s_out++ = '\\', *s_out++ = 'r';
else if (*s_in == '\t')
*s_out++ = '\\', *s_out++ = 't';
else if (*s_in == ESC)
*s_out++ = '\\', *s_out++ = 'E';
else if (iscntrl(*s_in)) {
if (bind_format)
*s_out++ = '\\', *s_out++ = 'C';
else
*s_out++ = '^';
*s_out++ = _unctrl[*s_in][1];
} else
*s_out++ = *s_in;
*s_out = 0;
return start;
}
/*
* This routine returns a pointer to the file portion of a path/file name.
*/
char *
basename(path)
register char *path;
{
char *file;
if (file = rindex(path, '/'))
return ++file;
return path;
}