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