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