home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 4 / FreshFish_May-June1994.bin / bsd / src / tr / tr-amiga / str.c < prev    next >
C/C++ Source or Header  |  1993-09-26  |  8KB  |  345 lines

  1. /*-
  2.  * Copyright (c) 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char sccsid[] = "@(#)str.c    5.3 (Berkeley) 10/27/91";
  36. #endif /* not lint */
  37.  
  38. #include <sys/cdefs.h>
  39. #include <sys/types.h>
  40. #include <errno.h>
  41. #include <stdio.h>
  42. #include <stddef.h>
  43. #include <stdlib.h>
  44. #include <string.h>
  45. #include "extern.h"
  46.  
  47. static int    backslash __P((STR *));
  48. static int    bracket __P((STR *));
  49. static int    c_class __P((const void *, const void *));
  50. static void    genclass __P((STR *));
  51. static void    genequiv __P((STR *));
  52. static int    genrange __P((STR *));
  53. static void    genseq __P((STR *));
  54.  
  55. int
  56. next(s)
  57.     register STR *s;
  58. {
  59.     register int ch;
  60.  
  61.     switch (s->state) {
  62.     case EOS:
  63.         return (0);
  64.     case INFINITE:
  65.         return (1);
  66.     case NORMAL:
  67.         switch (ch = *s->str) {
  68.         case '\0':
  69.             s->state = EOS;
  70.             return (0);
  71.         case '\\':
  72.             s->lastch = backslash(s);
  73.             break;
  74.         case '[':
  75.             if (bracket(s))
  76.                 return (next(s));
  77.             /* FALLTHROUGH */
  78.         default:
  79.             ++s->str;
  80.             s->lastch = ch;
  81.             break;
  82.         }
  83.  
  84.         /* We can start a range at any time. */
  85.         if (s->str[0] == '-' && genrange(s))
  86.             return (next(s));
  87.         return (1);
  88.     case RANGE:
  89.         if (s->cnt-- == 0) {
  90.             s->state = NORMAL;
  91.             return (next(s));
  92.         }
  93.         ++s->lastch;
  94.         return (1);
  95.     case SEQUENCE:
  96.         if (s->cnt-- == 0) {
  97.             s->state = NORMAL;
  98.             return (next(s));
  99.         }
  100.         return (1);
  101.     case SET:
  102.         if ((s->lastch = s->set[s->cnt++]) == OOBCH) {
  103.             s->state = NORMAL;
  104.             return (next(s));
  105.         }
  106.         return (1);
  107.     }
  108.     /* NOTREACHED */
  109. }
  110.  
  111. static int
  112. bracket(s)
  113.     register STR *s;
  114. {
  115.     register char *p;
  116.  
  117.     switch (*++s->str) {
  118.     case ':':                /* "[:class:]" */
  119.         if ((p = strpbrk(s->str + 1, ":]")) == NULL)
  120.             return (0);
  121.         if (p[0] != ':' || p[1] != ']')
  122.             return (0);
  123.         *p = '\0';
  124.         ++s->str;
  125.         genclass(s);
  126.         s->str = p + 2;
  127.         return (1);
  128.     case '=':                /* "[=equiv=]" */
  129.         if ((p = strpbrk(s->str + 1, "=]")) == NULL)
  130.             return (0);
  131.         if (p[0] != '=' || p[1] != ']')
  132.             return (0);
  133.         genequiv(s);
  134.         return (1);
  135.     default:                /* "[\###*]" or "[#*]" */
  136.         if ((p = strpbrk(s->str + 1, "*]")) == NULL)
  137.             return (0);
  138.         if (p[0] != '*' || index(p, ']') == NULL)
  139.             return (0);
  140.         genseq(s);
  141.         return (1);
  142.     }
  143.     /* NOTREACHED */
  144. }
  145.  
  146. int isalnum __P((int)),
  147.     isalpha __P((int)),
  148.     isblank __P((int)),
  149.     isspace __P((int)),
  150.     iscntrl __P((int)),
  151.     isdigit __P((int)),
  152.     isgraph __P((int)),
  153.     islower __P((int)),
  154.     isprint __P((int)),
  155.     ispunct __P((int)),
  156.     isupper __P((int)),
  157.     isxdigit __P((int));
  158.  
  159. typedef struct {
  160.     char *name;
  161.     int (*func) __P((int));
  162.     int *set;
  163. } CLASS;
  164.  
  165. static CLASS classes[] = {
  166.     { "alnum",  isalnum,  },
  167.     { "alpha",  isalpha,  },
  168.     { "blank",  isblank,  },
  169.     { "cntrl",  iscntrl,  },
  170.     { "digit",  isdigit,  },
  171.     { "graph",  isgraph,  },
  172.     { "lower",  islower,  },
  173.     { "print",  isupper,  },
  174.     { "punct",  ispunct,  },
  175.     { "space",  isspace,  },
  176.     { "upper",  isupper,  },
  177.     { "xdigit", isxdigit, },
  178. };
  179.  
  180. static void
  181. genclass(s)
  182.     STR *s;
  183. {
  184.     register int cnt, (*func) __P((int));
  185.     CLASS *cp, tmp;
  186.     int *p;
  187.  
  188.     tmp.name = s->str;
  189.     if ((cp = (CLASS *)bsearch(&tmp, classes, sizeof(classes) /
  190.         sizeof(CLASS), sizeof(CLASS), c_class)) == NULL)
  191.         err("unknown class %s", s->str);
  192.  
  193.     if ((cp->set = p = malloc((NCHARS + 1) * sizeof(int))) == NULL)
  194.         err("%s", strerror(errno));
  195.     bzero(p, (NCHARS + 1) * sizeof(int));
  196.     for (cnt = 0, func = cp->func; cnt < NCHARS; ++cnt)
  197.         if ((func)(cnt))
  198.             *p++ = cnt;
  199.     *p = OOBCH;
  200.  
  201.     s->cnt = 0;
  202.     s->state = SET;
  203.     s->set = cp->set;
  204. }
  205.  
  206. static int
  207. c_class(a, b)
  208.     const void *a, *b;
  209. {
  210.     return (strcmp(((CLASS *)a)->name, ((CLASS *)b)->name));
  211. }
  212.  
  213. /*
  214.  * English doesn't have any equivalence classes, so for now
  215.  * we just syntax check and grab the character.
  216.  */
  217. static void
  218. genequiv(s)
  219.     STR *s;
  220. {
  221.     if (*++s->str == '\\') {
  222.         s->equiv[0] = backslash(s);
  223.         if (*s->str != '=')
  224.             err("misplaced equivalence equals sign");
  225.     } else {
  226.         s->equiv[0] = s->str[0];
  227.         if (s->str[1] != '=')
  228.             err("misplaced equivalence equals sign");
  229.     }
  230.     s->str += 2;
  231.     s->cnt = 0;
  232.     s->state = SET;
  233.     s->set = s->equiv;
  234. }
  235.  
  236. static int
  237. genrange(s)
  238.     STR *s;
  239. {
  240.     int stopval;
  241.     char *savestart;
  242.  
  243.     savestart = s->str;
  244.     stopval = *++s->str == '\\' ? backslash(s) : *s->str;
  245.     if (stopval < s->lastch) {
  246.         s->str = savestart;
  247.         return (0);
  248.     }
  249.     s->cnt = stopval - s->lastch + 1;
  250.     s->state = RANGE;
  251.     --s->lastch;
  252.     return (1);
  253. }
  254.  
  255. static void
  256. genseq(s)
  257.     STR *s;
  258. {
  259.     char *ep;
  260.  
  261.     if (s->which == STRING1)
  262.         err("sequences only valid in string2");
  263.  
  264.     if (*s->str == '\\')
  265.         s->lastch = backslash(s);
  266.     else
  267.         s->lastch = *s->str++;
  268.     if (*s->str != '*')
  269.         err("misplaced sequence asterisk");
  270.  
  271.     switch (*++s->str) {
  272.     case '\\':
  273.         s->cnt = backslash(s);
  274.         break;
  275.     case ']':
  276.         s->cnt = 0;
  277.         ++s->str;
  278.         break;
  279.     default:
  280.         if (isdigit(*s->str)) {
  281.             s->cnt = strtol(s->str, &ep, 0);
  282.             if (*ep == ']') {
  283.                 s->str = ep + 1;
  284.                 break;
  285.             }
  286.         }
  287.         err("illegal sequence count");
  288.         /* NOTREACHED */
  289.     }
  290.  
  291.     s->state = s->cnt ? SEQUENCE : INFINITE;
  292. }
  293.  
  294. /* Use the #defines isXXX() here, DON'T use them above. */
  295. #include <ctype.h>
  296.  
  297. /*
  298.  * Translate \??? into a character.  Up to 3 octal digits, if no digits either
  299.  * an escape code or a literal character.
  300.  */
  301. static int
  302. backslash(s)
  303.     register STR *s;
  304. {
  305.     register int ch, cnt, val;
  306.  
  307.     for (cnt = val = 0;;) {
  308.         ch = *++s->str;
  309.         if (!isascii(ch) || !isdigit(ch))
  310.             break;
  311.         val = val * 8 + ch - '0';
  312.         if (++cnt == 3)
  313.             break;
  314.     }
  315.     if (cnt)
  316.         return (val);
  317.     ++s->str;
  318.     switch (ch) {
  319.         case 'a':            /* escape characters */
  320.             return ('\7');
  321.         case 'b':
  322.             return ('\b');
  323.         case 'f':
  324.             return ('\f');
  325.         case 'n':
  326.             return ('\n');
  327.         case 'r':
  328.             return ('\r');
  329.         case 't':
  330.             return ('\t');
  331.         case 'v':
  332.             return ('\13');
  333.         case '\0':            /*  \" -> \ */
  334.             s->state = EOS;
  335.             return ('\\');
  336.         default:            /* \x" -> x */
  337.             return (ch);
  338.     }
  339. }
  340.  
  341. int isblank (int ch)
  342. {
  343.     return (0);    /* BSD specific?  What is this? */
  344. }
  345.