home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / s / stex2-18.zip / SeeTeX / libtex / split.c < prev    next >
C/C++ Source or Header  |  1990-07-10  |  5KB  |  227 lines

  1. /*
  2.  * Copyright (c) 1987, 1989 University of Maryland
  3.  * Department of Computer Science.  All rights reserved.
  4.  * Permission to copy for any purpose is hereby granted
  5.  * so long as this copyright notice remains intact.
  6.  */
  7.  
  8. #ifndef lint
  9. static char rcsid[] = "$Header: /usr/src/local/tex/local/mctex/lib/RCS/split.c,v 3.1 89/08/22 21:59:36 chris Exp $";
  10. #endif
  11.  
  12. #include <ctype.h>
  13.  
  14. /*
  15.  * Split a line into an array of words.  This is destructive of
  16.  * the original line; the word pointers point to places within
  17.  * that line.
  18.  *
  19.  * The pound-sign character `#', at the beginning of the line or
  20.  * after white space, marks the end of the line.
  21.  *
  22.  * Return the number of words made, or -1 for overflow.
  23.  */
  24.  
  25. /*
  26.  * The lexical states are much like `sh's, except that we also do
  27.  * C-style backslash-escapes.
  28.  */
  29. enum lexstate {
  30.     S_BLANK,        /* outside a word */
  31.     S_WORD,            /* inside a word, no quoting */
  32.     S_SQUOTE,        /* inside a single quote */
  33.     S_DQUOTE,        /* inside a double quote */
  34.     S_BKSL0,        /* last char was \ */
  35.     S_BKSL1,        /* last chars were \, [0-7] */
  36.     S_BKSL2            /* last chars were \, [0-7][0-7] */
  37. };
  38.  
  39. int
  40. split(s, w, nw)
  41.     register char *s, **w;
  42.     int nw;
  43. {
  44.     register int c;
  45.     register char *canon = s;
  46.     register int wleft = nw;
  47.     enum lexstate state, prebkstate;
  48.  
  49.     /*
  50.      * Start out in the `blank' state (outside a word).  Handle
  51.      * quotes and things.  Backslashes are handled by saving the
  52.      * `pre-backslash' state, doing the backslash, and restoring
  53.      * that state at the end of the backslash sequence.
  54.      */
  55.     state = S_BLANK;
  56.     while ((c = *s++) != 0) {
  57. reswitch:
  58.         switch (state) {
  59.  
  60.         /*
  61.          * Blanks: spaces stay in blank state; '#' ends the line;
  62.          * anything else starts a word.  However, quotes may put
  63.          * us into quote states, rather than word states.
  64.          */
  65.         case S_BLANK:
  66.             if (isspace(c))
  67.                 continue;
  68.             if (c == '#')
  69.                 goto stopped_by_comment;
  70.             if (--wleft < 0)
  71.                 return (-1);
  72.             *w++ = canon;
  73.             state = S_WORD;
  74.             /* FALLTHROUGH */
  75.  
  76.         /*
  77.          * In a word.  Spaces take us out (and end the
  78.          * current word).  Quotes, however, put us into
  79.          * quote states.
  80.          */
  81.         case S_WORD:
  82.             if (isspace(c)) {
  83.                 *canon++ = 0;
  84.                 state = S_BLANK;
  85.                 break;
  86.             }
  87.             if (c == '\'') {
  88.                 state = S_SQUOTE;
  89.                 break;
  90.             }
  91.             if (c == '"') {
  92.                 state = S_DQUOTE;
  93.                 break;
  94.             }
  95.             if (c == '\\') {
  96.                 prebkstate = S_WORD;
  97.                 state = S_BKSL0;
  98.                 break;
  99.             }
  100.             *canon++ = c;
  101.             break;
  102.  
  103.         /*
  104.          * Inside a single quote, the only special character
  105.          * is another single quote.  This matches the Bourne
  106.          * shell quoting convention exactly.
  107.          */
  108.         case S_SQUOTE:
  109.             if (c == '\'')
  110.                 state = S_WORD;
  111.             else
  112.                 *canon++ = c;
  113.             break;
  114.  
  115.         /*
  116.          * Inside a double quote, double quotes get us out,
  117.          * but backslashes must be interpreted.
  118.          */
  119.         case S_DQUOTE:
  120.             if (c == '\\') {
  121.                 prebkstate = S_DQUOTE;
  122.                 state = S_BKSL0;
  123.             } else if (c == '"')
  124.                 state = S_WORD;
  125.             else
  126.                 *canon++ = c;
  127.             break;
  128.  
  129.         /*
  130.          * If we are handling a backslash, we will either
  131.          * restore the state, or go to BKSL1 state.  In
  132.          * the latter case, do not advance the canonicalisation
  133.          * pointer, since we might have more octal digits
  134.          * to insert.
  135.          */
  136.         case S_BKSL0:
  137.             state = prebkstate;    /* probably */
  138.             switch (c) {
  139.  
  140.             case 'b':
  141.                 *canon++ = '\b';
  142.                 break;
  143.  
  144.             case 'f':
  145.                 *canon++ = '\f';
  146.                 break;
  147.  
  148.             case 'n':
  149.                 *canon++ = '\n';
  150.                 break;
  151.  
  152.             case 'r':
  153.                 *canon++ = '\r';
  154.                 break;
  155.  
  156.             case 't':
  157.                 *canon++ = '\t';
  158.                 break;
  159.  
  160.             case '0': case '1': case '2': case '3':
  161.             case '4': case '5': case '6': case '7':
  162.                 *canon = c - '0';
  163.                 state = S_BKSL1;
  164.                 break;
  165.  
  166.             default:
  167.                 *canon++ = c;
  168.                 break;
  169.             }
  170.             break;
  171.  
  172.  
  173.         /*
  174.          * In BKSL1, we have seen backslash and one octal
  175.          * digit.  There may be more (in which case just
  176.          * count them on in), or there might be something
  177.          * that requires we restore the state and try again.
  178.          */
  179.         case S_BKSL1:
  180.             switch (c) {
  181.  
  182.             case '0': case '1': case '2': case '3':
  183.             case '4': case '5': case '6': case '7':
  184.                 *canon <<= 3;
  185.                 *canon |= c - '0';
  186.                 state = S_BKSL2;
  187.                 break;
  188.  
  189.             default:
  190.                 canon++;
  191.                 state = prebkstate;
  192.                 goto reswitch;
  193.             }
  194.             break;
  195.  
  196.         /*
  197.          * BKSL2 is like BKSL1, except that it cannot
  198.          * help but restore the original state, since
  199.          * there are no four-character octal sequences.
  200.          */
  201.         case S_BKSL2:
  202.             state = prebkstate;    /* assuredly */
  203.             switch (c) {
  204.  
  205.             case '0': case '1': case '2': case '3':
  206.             case '4': case '5': case '6': case '7':
  207.                 *canon <<= 3;
  208.                 *canon++ |= c - '0';
  209.                 break;
  210.  
  211.             default:
  212.                 canon++;
  213.                 goto reswitch;
  214.             }
  215.             break;
  216.         }
  217.     }
  218. stopped_by_comment:
  219. #ifdef notdef
  220.     if (state != S_WORD && state != S_BLANK)
  221.         error(0, 0, "warning: unclosed quote");
  222. #endif
  223.     if (state != S_BLANK)
  224.         *canon = 0;
  225.     return (nw - wleft);
  226. }
  227.