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