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 >
Text File  |  1990-07-04  |  10KB  |  459 lines

  1. /* strings.c Copyright(1988) Dan Heller */
  2.  
  3. #include "mush.h"
  4.  
  5. /*
  6.  * reverse a string.  Useful for uucp-style address comparisons.
  7.  */
  8. char *
  9. reverse(s)
  10. char s[];
  11. {
  12.     int n = strlen(s), m;
  13.     char c;
  14.  
  15.     if (n < 1)
  16.     return 0;
  17.     if (n & 1)
  18.     n = n/2 + 1, m = n - 2;
  19.     else
  20.     n /= 2, m = n - 1;
  21.     for ( ; m >= 0; m--, n++)
  22.     c = s[n], s[n] = s[m], s[m] = c;
  23.     return s;
  24. }
  25.  
  26. /*
  27.  * lose the newline character, trailing whitespace, and return the end of p
  28.  * test for '\n' separately since some _ctype_[] arrays may not have the
  29.  * _S bit set for the newline character.  see <ctype.h> for more info.
  30.  */
  31. char *
  32. no_newln(p)
  33. register char *p;
  34. {
  35.     register char *p2 = p + strlen(p);    /* point it to the null terminator */
  36.  
  37.     while (p2 > p && *--p2 == '\n' || isspace(*p2))
  38.     *p2 = 0;  /* get rid of newline and trailing spaces */
  39.     return p2;
  40. }
  41.  
  42. /* find any character in s1 that's in s2; return pointer to char in s1. */
  43. char *
  44. any(s1, s2)
  45. register char *s1, *s2;
  46. {
  47.     register char *p;
  48.     if (!s1 || !*s1 || !s2 || !*s2)
  49.     return NULL;
  50.     for( ; *s1; s1++) {
  51.     for(p = s2; *p; p++)
  52.         if (*p == *s1)
  53.         return s1;
  54.     }
  55.     return NULL;
  56. }
  57.  
  58. /* check two lists of strings each of which contain substrings.
  59.  * Each substring is delimited by any char in "delimiters"
  60.  * return true if any elements in list1 are on list2.
  61.  * thus:
  62.  * string1 = "foo, bar, baz"
  63.  * string2 = "foobar, baz, etc"
  64.  * delimiters = ", \t"
  65.  * example returns 1 because "baz" exists in both lists
  66.  * NOTE: case is ignored.
  67.  */
  68. chk_two_lists(list1, list2, delimiters)
  69. register char *list1, *list2, *delimiters;
  70. {
  71.     register char *p, c;
  72.     register int found = 0;
  73.  
  74.     if (!list1 || !list2)
  75.     return 0;
  76.  
  77.     if (p = any(list1, delimiters)) {
  78.     if (p > list1) {
  79.         c = *p; *p = 0;
  80.         /* Check list2 against the first word of list1.
  81.          * Swap places of list2 and list1 to step through list2.
  82.          */
  83.         found = chk_two_lists(list2, list1, delimiters);
  84.         *p = c;
  85.     }
  86.     if (found)
  87.         return 1;
  88.     for (p++; *p && index(delimiters, *p); p++)
  89.         ;
  90.     if (!*p)
  91.         return 0;
  92.     } else if (!any(list2, delimiters))
  93.     /* Do the trivial case of single words */
  94.     return !lcase_strncmp(list1, list2, -1);
  95.     else
  96.     p = list1;
  97.  
  98.     /* Either only list2 has delims or the first word of list1
  99.      * did not match anything in list2.  Check list2 against the
  100.      * rest of list1.  This could be more efficient by using a
  101.      * different function to avoid repeating the any() calls.
  102.      */
  103.     return chk_two_lists(list2, p, delimiters);
  104. }
  105.  
  106. bzero(addr, size)
  107. register char *addr;
  108. register int size;
  109. {
  110.     while (size-- > 0)
  111.     addr[size] = 0;
  112. }
  113.  
  114. /* do an atoi() on the string passed and return in "val" the decimal value.
  115.  * the function returns a pointer to the location in the string that is not
  116.  * a digit.
  117.  */
  118. char *
  119. my_atoi(p, val)
  120. register char *p;
  121. register int *val;
  122. {
  123.     int positive = 1;
  124.  
  125.     if (!p)
  126.     return NULL;
  127.     *val = 0;
  128.     if (*p == '-')
  129.     positive = -1, p++;
  130.     while (isdigit(*p))
  131.     *val = (*val) * 10 + *p++ - '0';
  132.     *val *= positive;
  133.     return p;
  134. }
  135.  
  136. /* strcmp ignoring case */
  137. lcase_strncmp(str1, str2, n)
  138. register char *str1, *str2;
  139. {
  140.     while (*str1 && *str2 && --n != 0)
  141.     if (lower(*str1) != lower(*str2))
  142.         break;
  143.     else
  144.         str1++, str2++;
  145.     return lower(*str1) - lower(*str2);
  146. }
  147.  
  148. /* strcpy converting everything to lower case (arbitrary) to ignore cases */
  149. char *
  150. lcase_strcpy(dst, src)
  151. register char *dst, *src;
  152. {
  153.     register char *s = dst;
  154.  
  155.     /* "lower" is a macro, don't increment its argument! */
  156.     while (*dst++ = lower(*src))
  157.     src++;
  158.     return s;
  159. }
  160.  
  161. /* this strcpy returns number of bytes copied */
  162. Strcpy(dst, src)
  163. register char *dst, *src;
  164. {
  165.     register int n = 0;
  166.     if (!dst || !src)
  167.     return 0;
  168.     while (*dst++ = *src++)
  169.     n++;
  170.     return n;
  171. }
  172.  
  173. char *
  174. savestr(s)
  175. register char *s;
  176. {
  177.     register char *p;
  178.  
  179.     if (!s)
  180.     s = "";
  181.     if (!(p = malloc((unsigned) (strlen(s) + 1)))) {
  182.     error("out of memory saving %s", s);
  183.     return NULL;
  184.     }
  185.     return strcpy(p, s);
  186. }
  187.  
  188. /* copy a vector of strings into one string -- return the end of the string */
  189. char *
  190. argv_to_string(p, argv)
  191. register char *p, **argv;
  192. {
  193.     register int i;
  194.     register char *ptr = p;
  195.  
  196.     *p = 0;
  197.     if (!argv[0])
  198.     return "";
  199.     for (i = 0; argv[i]; i++)
  200.     ptr += strlen(sprintf(ptr, "%s ", argv[i]));
  201.     *--ptr = 0;   /* get rid of the last space */
  202.     return ptr;
  203. }
  204.  
  205. char *
  206. itoa(n)
  207. {
  208.     static char buf[10];
  209.     return sprintf(buf, "%d", n);
  210. }
  211.  
  212. /*
  213.  * There are two different kinds of sprintf() --those that return char * and
  214.  * those that return int.  System-V returns int (the length of the resulting
  215.  * string).  BSD has historically returned a pointer to the resulting string
  216.  * instead. Mush was originally written under BSD, so the usage has always
  217.  * been to assume the char * method.  Because the system-v method is far more
  218.  * useful, mush should some day change to use that method, but until then,
  219.  * this routine was written to allow all the unix'es to appear the same to
  220.  * the programmer regardless of which sprintf is actually used.  The "latest"
  221.  * version of 4.3BSD (as of Fall 1988) has changed its format to go from the
  222.  * historical BSD method to the sys-v method.  It is no longer possible to
  223.  * simply #ifdef this routine for sys-v --it is now required to use this
  224.  * routine regardless of which sprintf is notice to your machine.  However,
  225.  * if you know your system's sprintf returns a char *, you can remove the
  226.  * define in strings.h
  227.  */
  228. #include <varargs.h>
  229. /*VARARGS*/
  230. /*ARGSUSED*/
  231. char *
  232. Sprintf(va_alist)
  233. va_dcl
  234. {
  235.     char *buf, *fmt;
  236.     va_list ap;
  237.  
  238.     va_start(ap);
  239.     buf = va_arg(ap, char *);
  240.     fmt = va_arg(ap, char *);
  241. #ifdef VPRINTF
  242.     (void) vsprintf(buf, fmt, ap);
  243. #else
  244.     {
  245.     FILE foo;
  246.     foo._cnt = BUFSIZ;
  247.     foo._base = foo._ptr = buf; /* may have to be cast (unsigned char *) */
  248.     foo._flag = _IOWRT+_IOSTRG;
  249.     (void) _doprnt(fmt, ap, &foo);
  250.     *foo._ptr = '\0'; /* plant terminating null character */
  251.     }
  252. #endif /* VPRINTF */
  253.     va_end(ap);
  254.     return buf;
  255. }
  256.  
  257. void
  258. print_argv(argv)
  259. char **argv;
  260. {
  261.     while (*argv)
  262.     if (debug)
  263.         wprint("(%s) ", *argv++);
  264.     else
  265.         wprint("%s ", *argv++);
  266.     wprint("\n");
  267. }
  268.  
  269. /*
  270.  * putstring -- put a string into a file.  Expand \t's into tabs and \n's
  271.  * into newlines.  Append a \n and fflush(fp);
  272.  */
  273. void
  274. putstring(p, fp)
  275. register char *p;
  276. register FILE *fp;
  277. {
  278.     for ( ; *p; ++p)
  279.     if (*p != '\\')
  280.         (void) fputc(*p, fp);
  281.     else
  282.         switch(*++p) {
  283.         case 'n': (void) fputc('\n', fp);
  284.         when 't': (void) fputc('\t', fp);
  285.         otherwise: (void) fputc(*p, fp);
  286.         }
  287.     (void) fputc('\n', fp);
  288.     (void) fflush(fp);
  289. }
  290.  
  291. #define chtoi(c)    ((int)(c) - (int)'0')
  292.  
  293. /* m_xlate(str) converts strings of chars which contain ascii representations
  294.  *  of control characters appearing in str into the literal characters they
  295.  *  represent.  The usual curses-mode character expansions (\Cx -> control-x)
  296.  *  are honored, as are most C escapes.  Unrecognized portions are unchanged.
  297.  */
  298. char *
  299. m_xlate (str)
  300. register char *str;
  301. {
  302.     register char *r, *s, *t;
  303.     int dv, nd;
  304.  
  305.     /*
  306.      * r will receive the new string, s will track the old one,
  307.      *  and t will step through escape sequences
  308.      * This allows the translation to be done in place
  309.      */
  310.     r = s = str;
  311.     while (s && *s) {
  312.     if (*s == '\\') {
  313.         t = s + 1;
  314.         /*
  315.          * After each case below, t should point to the character
  316.          *  following the escape sequence
  317.          */
  318.         switch(*t) {
  319.         case '\0' :
  320.             /*
  321.              * Hmmm ... a backslash followed by the string
  322.              *  terminator.  Copy the backslash ONLY.
  323.              */
  324.             *r++ = *s++;
  325.             break;
  326.         case '0' :
  327.         case '1' :
  328.         case '2' :
  329.         case '3' :
  330.         case '4' :
  331.         case '5' :
  332.         case '6' :
  333.         case '7' :
  334.             /*
  335.              * Convert up to 3 octal digits to their ascii value
  336.              */
  337.             dv = chtoi(*t++);
  338.             for (nd = 0; (isdigit(*t) && (nd < 2)); nd++)
  339.             if (chtoi(*t) < 8)
  340.                 dv = (8 * dv) + chtoi(*t++);
  341.             else
  342.                 break;
  343.             if (dv < 256 && dv > 0)
  344.             /* Valid octal number escaped */
  345.             *r++ = (char)dv;
  346.             else
  347.             /* Invalid octal number, so copy unchanged */
  348.             while (s < t)
  349.                 *r++ = *s++;
  350.             break;
  351.         case 'b' :
  352.             *r++ = '\b';
  353.             t++;
  354.             break;
  355.         case 'C' :
  356.             t++;
  357.             if (*t == '?')
  358.             *r++ = '\177';
  359.             else if (*t == '~')
  360.             *r++ = '\036';
  361.             else if (*t == '/')
  362.             *r++ = '\037';
  363.             else if (isalpha(*t) || *t > '\132' && *t < '\140')
  364.             *r++ = *t & 037;
  365.             else
  366.             while (s <= t) *r++ = *s++;
  367.             t++;
  368.             break;
  369.         case 'E' :
  370.             *r++ = '\033';
  371.             t++;
  372.             break;
  373.         case 'f' :
  374.             *r++ = '\f';
  375.             t++;
  376.             break;
  377.         case 'n' :
  378.             *r++ = '\n';
  379.             t++;
  380.             break;
  381.         case 'r' :
  382.             *r++ = '\r';
  383.             t++;
  384.             break;
  385.         case 't' :
  386.             *r++ = '\t';
  387.             t++;
  388.             break;
  389.         case '\\' :
  390.             *r++ = *t++;
  391.             break;
  392.         default :
  393.             /*
  394.              * Not recognized, so copy both characters
  395.              */
  396.             *r++ = *s++;
  397.             *r++ = *s++;
  398.             break;
  399.         }
  400.         /*
  401.          * Now make sure s also points to the character after the
  402.          *  escape sequence, by comparing to t
  403.          */
  404.         if (t > s)
  405.         s = t;
  406.     } else
  407.         *r++ = *s++;
  408.     }
  409.     *r = '\0';
  410.     return str;
  411. }
  412.  
  413. /*
  414.  * Convert control characters to ascii format (reverse effect of m_xlate()).
  415.  */
  416. char *
  417. ctrl_strcpy(s_out, s_in, bind_format)
  418. register char *s_out, *s_in;
  419. {
  420. #if !defined(M_XENIX) || (defined(M_XENIX) && !defined(CURSES))
  421.     extern char *_unctrl[];
  422. #endif /* !M_XENIX || M_XENIX && !CURSES */
  423.     char *start = s_out;
  424.  
  425.     for (; *s_in; s_in++)
  426.     if (*s_in == '\n')
  427.         *s_out++ = '\\', *s_out++ = 'n';
  428.     else if (*s_in == '\r')
  429.         *s_out++ = '\\', *s_out++ = 'r';
  430.     else if (*s_in == '\t')
  431.         *s_out++ = '\\', *s_out++ = 't';
  432.     else if (*s_in == ESC)
  433.         *s_out++ = '\\', *s_out++ = 'E';
  434.     else if (iscntrl(*s_in)) {
  435.         if (bind_format)
  436.         *s_out++ = '\\', *s_out++ = 'C';
  437.         else
  438.         *s_out++ = '^';
  439.         *s_out++ = _unctrl[*s_in][1];
  440.     } else
  441.         *s_out++ = *s_in;
  442.     *s_out = 0;
  443.     return start;
  444. }
  445.  
  446. /*
  447.  * This routine returns a pointer to the file portion of a path/file name.
  448.  */
  449. char *
  450. basename(path)
  451. register char *path;
  452. {
  453.     char *file;
  454.  
  455.     if (file = rindex(path, '/'))
  456.     return ++file;
  457.     return path;
  458. }
  459.