home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / m4 / serv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-20  |  13.3 KB  |  471 lines

  1. /*
  2.  * Copyright (c) 1989 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Ozan Yigit.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. static char sccsid[] = "@(#)serv.c    5.3 (Berkeley) 2/26/91";
  39. #endif /* not lint */
  40.  
  41. /*
  42.  * serv.c
  43.  * Facility: m4 macro processor
  44.  * by: oz
  45.  */
  46.  
  47. #include <stdio.h>
  48. #include <stdlib.h>
  49. #include <string.h>
  50. #include "mdef.h"
  51. #include "extr.h" 
  52. #include "pathnames.h"
  53.  
  54. extern ndptr lookup();
  55. extern ndptr addent();
  56.  
  57. char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef   */
  58.  
  59. /*
  60.  * expand - user-defined macro expansion
  61.  *
  62.  */
  63. expand(argv, argc)
  64. register char *argv[];
  65. register int argc;
  66. {
  67.         register char *t;
  68.         register char *p;
  69.         register int  n;
  70.         register int  argno;
  71.  
  72.         t = argv[0];    /* defn string as a whole */
  73.         p = t;
  74.         while (*p)
  75.                 p++;
  76.         p--;            /* last character of defn */
  77.         while (p > t) {
  78.                 if (*(p-1) != ARGFLAG)
  79.                         putback(*p);
  80.                 else {
  81.                         switch (*p) {
  82.  
  83.                         case '#':
  84.                                 pbnum(argc-2);
  85.                                 break;
  86.                         case '0':
  87.                         case '1':
  88.                         case '2':
  89.                         case '3':
  90.                         case '4':
  91.                         case '5':
  92.                         case '6':
  93.                         case '7':
  94.                         case '8':
  95.                         case '9':
  96.                                 if ((argno = *p - '0') < argc-1)
  97.                                         pbstr(argv[argno+1]);
  98.                                 break;
  99.                         case '*':
  100.                                 for (n = argc - 1; n > 2; n--) {
  101.                                         pbstr(argv[n]);
  102.                                         putback(',');
  103.                                 }
  104.                                 pbstr(argv[2]);
  105.                                 break;
  106.                         default :
  107.                                 putback(*p);
  108.                                 break;
  109.                         }
  110.                         p--;
  111.                 }
  112.                 p--;
  113.         }
  114.         if (p == t)         /* do last character */
  115.                 putback(*p);
  116. }
  117.  
  118. /*
  119.  * dodefine - install definition in the table
  120.  *
  121.  */
  122. dodefine(name, defn)
  123. register char *name;
  124. register char *defn;
  125. {
  126.         register ndptr p;
  127.  
  128.         if (!*name)
  129.                 error("m4: null definition.");
  130.         if (strcmp(name, defn) == 0)
  131.                 error("m4: recursive definition.");
  132.         if ((p = lookup(name)) == nil)
  133.                 p = addent(name);
  134.         else if (p->defn != null)
  135.                 free(p->defn);
  136.         if (!*defn)
  137.                 p->defn = null;
  138.         else
  139.                 p->defn = strdup(defn);
  140.         p->type = MACRTYPE;
  141. }
  142.  
  143. /*
  144.  * dodefn - push back a quoted definition of
  145.  *      the given name.
  146.  */
  147.  
  148. dodefn(name)
  149. char *name;
  150. {
  151.         register ndptr p;
  152.  
  153.         if ((p = lookup(name)) != nil && p->defn != null) {
  154.                 putback(rquote);
  155.                 pbstr(p->defn);
  156.                 putback(lquote);
  157.         }
  158. }
  159.      
  160. /*
  161.  * dopushdef - install a definition in the hash table
  162.  *      without removing a previous definition. Since
  163.  *      each new entry is entered in *front* of the
  164.  *      hash bucket, it hides a previous definition from
  165.  *      lookup.
  166.  */
  167. dopushdef(name, defn)
  168. register char *name;
  169. register char *defn;
  170. {
  171.         register ndptr p;
  172.  
  173.         if (!*name)
  174.                 error("m4: null definition");
  175.         if (strcmp(name, defn) == 0)
  176.                 error("m4: recursive definition.");
  177.         p = addent(name);
  178.         if (!*defn)
  179.                 p->defn = null;
  180.         else
  181.                 p->defn = strdup(defn);
  182.         p->type = MACRTYPE;
  183. }
  184.  
  185. /*
  186.  * dodumpdef - dump the specified definitions in the hash
  187.  *      table to stderr. If nothing is specified, the entire
  188.  *      hash table is dumped.
  189.  *
  190.  */
  191. dodump(argv, argc)
  192. register char *argv[];
  193. register int argc;
  194. {
  195.         register int n;
  196.         ndptr p;
  197.  
  198.         if (argc > 2) {
  199.                 for (n = 2; n < argc; n++)
  200.                         if ((p = lookup(argv[n])) != nil)
  201.                                 fprintf(stderr, dumpfmt, p->name,
  202.                                 p->defn);
  203.         }
  204.         else {
  205.                 for (n = 0; n < HASHSIZE; n++)
  206.                         for (p = hashtab[n]; p != nil; p = p->nxtptr)
  207.                                 fprintf(stderr, dumpfmt, p->name,
  208.                                 p->defn);
  209.         }
  210. }
  211.  
  212. /*
  213.  * doifelse - select one of two alternatives - loop.
  214.  *
  215.  */
  216. doifelse(argv,argc)
  217. register char *argv[];
  218. register int argc;
  219. {
  220.         cycle {
  221.                 if (strcmp(argv[2], argv[3]) == 0)
  222.                         pbstr(argv[4]);
  223.                 else if (argc == 6)
  224.                         pbstr(argv[5]);
  225.                 else if (argc > 6) {
  226.                         argv += 3;
  227.                         argc -= 3;
  228.                         continue;
  229.                 }
  230.                 break;
  231.         }
  232. }
  233.  
  234. /*
  235.  * doinclude - include a given file.
  236.  *
  237.  */
  238. doincl(ifile)
  239. char *ifile;
  240. {
  241.         if (ilevel+1 == MAXINP)
  242.                 error("m4: too many include files.");
  243.         if ((infile[ilevel+1] = fopen(ifile, "r")) != NULL) {
  244.                 ilevel++;
  245.                 return (1);
  246.         }
  247.         else
  248.                 return (0);
  249. }
  250.  
  251. #ifdef EXTENDED
  252. /*
  253.  * dopaste - include a given file without any
  254.  *           macro processing.
  255.  */
  256. dopaste(pfile)
  257. char *pfile;
  258. {
  259.         FILE *pf;
  260.         register int c;
  261.  
  262.         if ((pf = fopen(pfile, "r")) != NULL) {
  263.                 while((c = getc(pf)) != EOF)
  264.                         putc(c, active);
  265.                 (void) fclose(pf);
  266.                 return(1);
  267.         }
  268.         else
  269.                 return(0);
  270. }
  271. #endif
  272.  
  273. /*
  274.  * dochq - change quote characters
  275.  *
  276.  */
  277. dochq(argv, argc)
  278. register char *argv[];
  279. register int argc;
  280. {
  281.         if (argc > 2) {
  282.                 if (*argv[2])
  283.                         lquote = *argv[2];
  284.                 if (argc > 3) {
  285.                         if (*argv[3])
  286.                                 rquote = *argv[3];
  287.                 }
  288.                 else
  289.                         rquote = lquote;
  290.         }
  291.         else {
  292.                 lquote = LQUOTE;
  293.                 rquote = RQUOTE;
  294.         }
  295. }
  296.  
  297. /*
  298.  * dochc - change comment characters
  299.  *
  300.  */
  301. dochc(argv, argc)
  302. register char *argv[];
  303. register int argc;
  304. {
  305.         if (argc > 2) {
  306.                 if (*argv[2])
  307.                         scommt = *argv[2];
  308.                 if (argc > 3) {
  309.                         if (*argv[3])
  310.                                 ecommt = *argv[3];
  311.                 }
  312.                 else
  313.                         ecommt = ECOMMT;
  314.         }
  315.         else {
  316.                 scommt = SCOMMT;
  317.                 ecommt = ECOMMT;
  318.         }
  319. }
  320.  
  321. /*
  322.  * dodivert - divert the output to a temporary file
  323.  *
  324.  */
  325. dodiv(n)
  326. register int n;
  327. {
  328.         if (n < 0 || n >= MAXOUT)
  329.                 n = 0;                  /* bitbucket */
  330.         if (outfile[n] == NULL) {
  331.                 m4temp[UNIQUE] = n + '0';
  332.                 if ((outfile[n] = fopen(m4temp, "w")) == NULL)
  333.                         error("m4: cannot divert.");
  334.         }
  335.         oindex = n;
  336.         active = outfile[n];
  337. }
  338.  
  339. /*
  340.  * doundivert - undivert a specified output, or all
  341.  *              other outputs, in numerical order.
  342.  */
  343. doundiv(argv, argc)
  344. register char *argv[];
  345. register int argc;
  346. {
  347.         register int ind;
  348.         register int n;
  349.  
  350.         if (argc > 2) {
  351.                 for (ind = 2; ind < argc; ind++) {
  352.                         n = atoi(argv[ind]);
  353.                         if (n > 0 && n < MAXOUT && outfile[n] != NULL)
  354.                                 getdiv(n);
  355.  
  356.                 }
  357.         }
  358.         else
  359.                 for (n = 1; n < MAXOUT; n++)
  360.                         if (outfile[n] != NULL)
  361.                                 getdiv(n);
  362. }
  363.  
  364. /*
  365.  * dosub - select substring
  366.  *
  367.  */
  368. dosub (argv, argc)
  369. register char *argv[];
  370. register int  argc;
  371. {
  372.         register char *ap, *fc, *k;
  373.         register int nc;
  374.  
  375.         if (argc < 5)
  376.                 nc = MAXTOK;
  377.         else
  378. #ifdef EXPR
  379.                 nc = expr(argv[4]);
  380. #else
  381.         nc = atoi(argv[4]);
  382. #endif
  383.         ap = argv[2];                   /* target string */
  384. #ifdef EXPR
  385.         fc = ap + expr(argv[3]);        /* first char */
  386. #else
  387.         fc = ap + atoi(argv[3]);        /* first char */
  388. #endif
  389.         if (fc >= ap && fc < ap+strlen(ap))
  390.                 for (k = fc+min(nc,strlen(fc))-1; k >= fc; k--)
  391.                         putback(*k);
  392. }
  393.  
  394. /*
  395.  * map:
  396.  * map every character of s1 that is specified in from
  397.  * into s3 and replace in s. (source s1 remains untouched)
  398.  *
  399.  * This is a standard implementation of map(s,from,to) function of ICON 
  400.  * language. Within mapvec, we replace every character of "from" with 
  401.  * the corresponding character in "to". If "to" is shorter than "from", 
  402.  * than the corresponding entries are null, which means that those 
  403.  * characters dissapear altogether. Furthermore, imagine 
  404.  * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, 
  405.  * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' 
  406.  * ultimately maps to `*'. In order to achieve this effect in an efficient 
  407.  * manner (i.e. without multiple passes over the destination string), we 
  408.  * loop over mapvec, starting with the initial source character. if the 
  409.  * character value (dch) in this location is different than the source 
  410.  * character (sch), sch becomes dch, once again to index into mapvec, until 
  411.  * the character value stabilizes (i.e. sch = dch, in other words 
  412.  * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary 
  413.  * character, it will stabilize, since mapvec[0] == 0 at all times. At the 
  414.  * end, we restore mapvec* back to normal where mapvec[n] == n for 
  415.  * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is 
  416.  * about 5 times faster than any algorithm that makes multiple passes over 
  417.  * destination string.
  418.  *
  419.  */
  420.      
  421. map(dest,src,from,to)
  422. register char *dest;
  423. register char *src;
  424. register char *from;
  425. register char *to;
  426. {
  427.         register char *tmp;
  428.         register char sch, dch;
  429.         static char mapvec[128] = {
  430.                 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
  431.                 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
  432.                 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
  433.                 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
  434.                 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
  435.                 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
  436.                 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
  437.                 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
  438.                 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
  439.                 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
  440.                 120, 121, 122, 123, 124, 125, 126, 127
  441.         };
  442.  
  443.         if (*src) {
  444.                 tmp = from;
  445.     /*
  446.      * create a mapping between "from" and "to"
  447.      */
  448.                 while (*from)
  449.                         mapvec[*from++] = (*to) ? *to++ : (char) 0;
  450.      
  451.                 while (*src) {
  452.                         sch = *src++;
  453.                         dch = mapvec[sch];
  454.                         while (dch != sch) {
  455.                                 sch = dch;
  456.                                 dch = mapvec[sch];
  457.                         }
  458.                         if (*dest = dch)
  459.                                 dest++;
  460.                 }
  461.     /*
  462.      * restore all the changed characters
  463.      */
  464.                 while (*tmp) {
  465.                         mapvec[*tmp] = *tmp;
  466.                         tmp++;
  467.                 }
  468.         }
  469.         *dest = (char) 0;
  470. }
  471.