eval.c revision 1.9 1 1.9 cgd /* $NetBSD: eval.c,v 1.9 1997/02/08 23:50:40 cgd Exp $ */
2 1.4 tls
3 1.1 cgd /*
4 1.2 glass * Copyright (c) 1989, 1993
5 1.2 glass * The Regents of the University of California. All rights reserved.
6 1.1 cgd *
7 1.1 cgd * This code is derived from software contributed to Berkeley by
8 1.2 glass * Ozan Yigit at York University.
9 1.1 cgd *
10 1.1 cgd * Redistribution and use in source and binary forms, with or without
11 1.1 cgd * modification, are permitted provided that the following conditions
12 1.1 cgd * are met:
13 1.1 cgd * 1. Redistributions of source code must retain the above copyright
14 1.1 cgd * notice, this list of conditions and the following disclaimer.
15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 cgd * notice, this list of conditions and the following disclaimer in the
17 1.1 cgd * documentation and/or other materials provided with the distribution.
18 1.1 cgd * 3. All advertising materials mentioning features or use of this software
19 1.1 cgd * must display the following acknowledgement:
20 1.1 cgd * This product includes software developed by the University of
21 1.1 cgd * California, Berkeley and its contributors.
22 1.1 cgd * 4. Neither the name of the University nor the names of its contributors
23 1.1 cgd * may be used to endorse or promote products derived from this software
24 1.1 cgd * without specific prior written permission.
25 1.1 cgd *
26 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 1.1 cgd * SUCH DAMAGE.
37 1.1 cgd */
38 1.1 cgd
39 1.1 cgd #ifndef lint
40 1.4 tls #if 0
41 1.4 tls static char sccsid[] = "@(#)eval.c 8.2 (Berkeley) 4/27/95";
42 1.4 tls #else
43 1.9 cgd static char rcsid[] = "$NetBSD: eval.c,v 1.9 1997/02/08 23:50:40 cgd Exp $";
44 1.4 tls #endif
45 1.1 cgd #endif /* not lint */
46 1.1 cgd
47 1.1 cgd /*
48 1.1 cgd * eval.c
49 1.1 cgd * Facility: m4 macro processor
50 1.1 cgd * by: oz
51 1.1 cgd */
52 1.1 cgd
53 1.2 glass #include <sys/types.h>
54 1.2 glass #include <errno.h>
55 1.1 cgd #include <unistd.h>
56 1.1 cgd #include <stdio.h>
57 1.1 cgd #include <stdlib.h>
58 1.1 cgd #include <string.h>
59 1.1 cgd #include "mdef.h"
60 1.2 glass #include "stdd.h"
61 1.2 glass #include "extern.h"
62 1.2 glass #include "pathnames.h"
63 1.1 cgd
64 1.1 cgd /*
65 1.1 cgd * eval - evaluate built-in macros.
66 1.1 cgd * argc - number of elements in argv.
67 1.1 cgd * argv - element vector :
68 1.1 cgd * argv[0] = definition of a user
69 1.1 cgd * macro or nil if built-in.
70 1.1 cgd * argv[1] = name of the macro or
71 1.1 cgd * built-in.
72 1.1 cgd * argv[2] = parameters to user-defined
73 1.1 cgd * . macro or built-in.
74 1.1 cgd * .
75 1.1 cgd *
76 1.1 cgd * Note that the minimum value for argc is 3. A call in the form
77 1.1 cgd * of macro-or-builtin() will result in:
78 1.1 cgd * argv[0] = nullstr
79 1.1 cgd * argv[1] = macro-or-builtin
80 1.1 cgd * argv[2] = nullstr
81 1.1 cgd */
82 1.1 cgd
83 1.2 glass void
84 1.2 glass eval(argv, argc, td)
85 1.1 cgd register char *argv[];
86 1.1 cgd register int argc;
87 1.2 glass register int td;
88 1.1 cgd {
89 1.1 cgd register int c, n;
90 1.2 glass static int sysval = 0;
91 1.1 cgd
92 1.1 cgd #ifdef DEBUG
93 1.1 cgd printf("argc = %d\n", argc);
94 1.1 cgd for (n = 0; n < argc; n++)
95 1.1 cgd printf("argv[%d] = %s\n", n, argv[n]);
96 1.1 cgd #endif
97 1.2 glass /*
98 1.2 glass * if argc == 3 and argv[2] is null, then we
99 1.2 glass * have macro-or-builtin() type call. We adjust
100 1.2 glass * argc to avoid further checking..
101 1.2 glass */
102 1.1 cgd if (argc == 3 && !*(argv[2]))
103 1.1 cgd argc--;
104 1.1 cgd
105 1.1 cgd switch (td & ~STATIC) {
106 1.1 cgd
107 1.1 cgd case DEFITYPE:
108 1.1 cgd if (argc > 2)
109 1.1 cgd dodefine(argv[2], (argc > 3) ? argv[3] : null);
110 1.1 cgd break;
111 1.1 cgd
112 1.1 cgd case PUSDTYPE:
113 1.1 cgd if (argc > 2)
114 1.1 cgd dopushdef(argv[2], (argc > 3) ? argv[3] : null);
115 1.1 cgd break;
116 1.1 cgd
117 1.1 cgd case DUMPTYPE:
118 1.1 cgd dodump(argv, argc);
119 1.1 cgd break;
120 1.1 cgd
121 1.1 cgd case EXPRTYPE:
122 1.2 glass /*
123 1.2 glass * doexpr - evaluate arithmetic
124 1.2 glass * expression
125 1.2 glass */
126 1.1 cgd if (argc > 2)
127 1.1 cgd pbnum(expr(argv[2]));
128 1.1 cgd break;
129 1.1 cgd
130 1.1 cgd case IFELTYPE:
131 1.1 cgd if (argc > 4)
132 1.1 cgd doifelse(argv, argc);
133 1.1 cgd break;
134 1.1 cgd
135 1.1 cgd case IFDFTYPE:
136 1.2 glass /*
137 1.2 glass * doifdef - select one of two
138 1.2 glass * alternatives based on the existence of
139 1.2 glass * another definition
140 1.2 glass */
141 1.1 cgd if (argc > 3) {
142 1.1 cgd if (lookup(argv[2]) != nil)
143 1.1 cgd pbstr(argv[3]);
144 1.1 cgd else if (argc > 4)
145 1.1 cgd pbstr(argv[4]);
146 1.1 cgd }
147 1.1 cgd break;
148 1.1 cgd
149 1.1 cgd case LENGTYPE:
150 1.2 glass /*
151 1.2 glass * dolen - find the length of the
152 1.2 glass * argument
153 1.2 glass */
154 1.1 cgd if (argc > 2)
155 1.1 cgd pbnum((argc > 2) ? strlen(argv[2]) : 0);
156 1.1 cgd break;
157 1.1 cgd
158 1.1 cgd case INCRTYPE:
159 1.2 glass /*
160 1.2 glass * doincr - increment the value of the
161 1.2 glass * argument
162 1.2 glass */
163 1.1 cgd if (argc > 2)
164 1.1 cgd pbnum(atoi(argv[2]) + 1);
165 1.1 cgd break;
166 1.1 cgd
167 1.1 cgd case DECRTYPE:
168 1.2 glass /*
169 1.2 glass * dodecr - decrement the value of the
170 1.2 glass * argument
171 1.2 glass */
172 1.1 cgd if (argc > 2)
173 1.1 cgd pbnum(atoi(argv[2]) - 1);
174 1.1 cgd break;
175 1.1 cgd
176 1.1 cgd case SYSCTYPE:
177 1.2 glass /*
178 1.2 glass * dosys - execute system command
179 1.2 glass */
180 1.1 cgd if (argc > 2)
181 1.1 cgd sysval = system(argv[2]);
182 1.1 cgd break;
183 1.1 cgd
184 1.1 cgd case SYSVTYPE:
185 1.2 glass /*
186 1.2 glass * dosysval - return value of the last
187 1.2 glass * system call.
188 1.2 glass *
189 1.2 glass */
190 1.1 cgd pbnum(sysval);
191 1.1 cgd break;
192 1.1 cgd
193 1.1 cgd case INCLTYPE:
194 1.1 cgd if (argc > 2)
195 1.2 glass if (!doincl(argv[2]))
196 1.2 glass oops("%s: %s", argv[2], strerror(errno));
197 1.1 cgd break;
198 1.1 cgd
199 1.1 cgd case SINCTYPE:
200 1.1 cgd if (argc > 2)
201 1.1 cgd (void) doincl(argv[2]);
202 1.1 cgd break;
203 1.1 cgd #ifdef EXTENDED
204 1.1 cgd case PASTTYPE:
205 1.1 cgd if (argc > 2)
206 1.2 glass if (!dopaste(argv[2]))
207 1.2 glass oops("%s: %s", argv[2], strerror(errno));
208 1.1 cgd break;
209 1.1 cgd
210 1.1 cgd case SPASTYPE:
211 1.1 cgd if (argc > 2)
212 1.1 cgd (void) dopaste(argv[2]);
213 1.1 cgd break;
214 1.1 cgd #endif
215 1.1 cgd case CHNQTYPE:
216 1.1 cgd dochq(argv, argc);
217 1.1 cgd break;
218 1.1 cgd
219 1.1 cgd case CHNCTYPE:
220 1.1 cgd dochc(argv, argc);
221 1.1 cgd break;
222 1.1 cgd
223 1.1 cgd case SUBSTYPE:
224 1.2 glass /*
225 1.2 glass * dosub - select substring
226 1.2 glass *
227 1.2 glass */
228 1.1 cgd if (argc > 3)
229 1.2 glass dosub(argv, argc);
230 1.1 cgd break;
231 1.1 cgd
232 1.1 cgd case SHIFTYPE:
233 1.2 glass /*
234 1.2 glass * doshift - push back all arguments
235 1.2 glass * except the first one (i.e. skip
236 1.2 glass * argv[2])
237 1.2 glass */
238 1.1 cgd if (argc > 3) {
239 1.5 pk int k;
240 1.2 glass for (n = argc - 1; n > 3; n--) {
241 1.9 cgd pbstr(rquote);
242 1.1 cgd pbstr(argv[n]);
243 1.9 cgd pbstr(lquote);
244 1.7 pk putback(COMMA);
245 1.1 cgd }
246 1.9 cgd pbstr(rquote);
247 1.1 cgd pbstr(argv[3]);
248 1.9 cgd pbstr(lquote);
249 1.1 cgd }
250 1.1 cgd break;
251 1.1 cgd
252 1.1 cgd case DIVRTYPE:
253 1.1 cgd if (argc > 2 && (n = atoi(argv[2])) != 0)
254 1.1 cgd dodiv(n);
255 1.1 cgd else {
256 1.1 cgd active = stdout;
257 1.1 cgd oindex = 0;
258 1.1 cgd }
259 1.1 cgd break;
260 1.1 cgd
261 1.1 cgd case UNDVTYPE:
262 1.1 cgd doundiv(argv, argc);
263 1.1 cgd break;
264 1.1 cgd
265 1.1 cgd case DIVNTYPE:
266 1.2 glass /*
267 1.2 glass * dodivnum - return the number of
268 1.2 glass * current output diversion
269 1.2 glass */
270 1.1 cgd pbnum(oindex);
271 1.1 cgd break;
272 1.1 cgd
273 1.1 cgd case UNDFTYPE:
274 1.2 glass /*
275 1.2 glass * doundefine - undefine a previously
276 1.2 glass * defined macro(s) or m4 keyword(s).
277 1.2 glass */
278 1.1 cgd if (argc > 2)
279 1.1 cgd for (n = 2; n < argc; n++)
280 1.1 cgd remhash(argv[n], ALL);
281 1.1 cgd break;
282 1.1 cgd
283 1.1 cgd case POPDTYPE:
284 1.2 glass /*
285 1.2 glass * dopopdef - remove the topmost
286 1.2 glass * definitions of macro(s) or m4
287 1.2 glass * keyword(s).
288 1.2 glass */
289 1.1 cgd if (argc > 2)
290 1.1 cgd for (n = 2; n < argc; n++)
291 1.1 cgd remhash(argv[n], TOP);
292 1.1 cgd break;
293 1.1 cgd
294 1.1 cgd case MKTMTYPE:
295 1.2 glass /*
296 1.2 glass * dotemp - create a temporary file
297 1.2 glass */
298 1.1 cgd if (argc > 2)
299 1.1 cgd pbstr(mktemp(argv[2]));
300 1.1 cgd break;
301 1.1 cgd
302 1.1 cgd case TRNLTYPE:
303 1.2 glass /*
304 1.2 glass * dotranslit - replace all characters in
305 1.2 glass * the source string that appears in the
306 1.2 glass * "from" string with the corresponding
307 1.2 glass * characters in the "to" string.
308 1.2 glass */
309 1.1 cgd if (argc > 3) {
310 1.1 cgd char temp[MAXTOK];
311 1.1 cgd if (argc > 4)
312 1.1 cgd map(temp, argv[2], argv[3], argv[4]);
313 1.1 cgd else
314 1.1 cgd map(temp, argv[2], argv[3], null);
315 1.1 cgd pbstr(temp);
316 1.1 cgd }
317 1.2 glass else if (argc > 2)
318 1.1 cgd pbstr(argv[2]);
319 1.1 cgd break;
320 1.1 cgd
321 1.1 cgd case INDXTYPE:
322 1.2 glass /*
323 1.2 glass * doindex - find the index of the second
324 1.2 glass * argument string in the first argument
325 1.2 glass * string. -1 if not present.
326 1.2 glass */
327 1.1 cgd pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
328 1.1 cgd break;
329 1.1 cgd
330 1.1 cgd case ERRPTYPE:
331 1.2 glass /*
332 1.2 glass * doerrp - print the arguments to stderr
333 1.2 glass * file
334 1.2 glass */
335 1.1 cgd if (argc > 2) {
336 1.1 cgd for (n = 2; n < argc; n++)
337 1.2 glass fprintf(stderr, "%s ", argv[n]);
338 1.1 cgd fprintf(stderr, "\n");
339 1.1 cgd }
340 1.1 cgd break;
341 1.1 cgd
342 1.1 cgd case DNLNTYPE:
343 1.2 glass /*
344 1.2 glass * dodnl - eat-up-to and including
345 1.2 glass * newline
346 1.2 glass */
347 1.1 cgd while ((c = gpbc()) != '\n' && c != EOF)
348 1.1 cgd ;
349 1.1 cgd break;
350 1.1 cgd
351 1.1 cgd case M4WRTYPE:
352 1.2 glass /*
353 1.2 glass * dom4wrap - set up for
354 1.2 glass * wrap-up/wind-down activity
355 1.2 glass */
356 1.2 glass m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
357 1.1 cgd break;
358 1.1 cgd
359 1.1 cgd case EXITTYPE:
360 1.2 glass /*
361 1.2 glass * doexit - immediate exit from m4.
362 1.2 glass */
363 1.3 mycroft killdiv();
364 1.1 cgd exit((argc > 2) ? atoi(argv[2]) : 0);
365 1.1 cgd break;
366 1.1 cgd
367 1.1 cgd case DEFNTYPE:
368 1.1 cgd if (argc > 2)
369 1.1 cgd for (n = 2; n < argc; n++)
370 1.1 cgd dodefn(argv[n]);
371 1.1 cgd break;
372 1.1 cgd
373 1.1 cgd default:
374 1.2 glass oops("%s: major botch.", "eval");
375 1.1 cgd break;
376 1.1 cgd }
377 1.2 glass }
378 1.2 glass
379 1.2 glass char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */
380 1.2 glass
381 1.2 glass /*
382 1.2 glass * expand - user-defined macro expansion
383 1.2 glass */
384 1.2 glass void
385 1.2 glass expand(argv, argc)
386 1.2 glass register char *argv[];
387 1.2 glass register int argc;
388 1.2 glass {
389 1.2 glass register char *t;
390 1.2 glass register char *p;
391 1.2 glass register int n;
392 1.2 glass register int argno;
393 1.2 glass
394 1.2 glass t = argv[0]; /* defn string as a whole */
395 1.2 glass p = t;
396 1.2 glass while (*p)
397 1.2 glass p++;
398 1.2 glass p--; /* last character of defn */
399 1.2 glass while (p > t) {
400 1.2 glass if (*(p - 1) != ARGFLAG)
401 1.2 glass putback(*p);
402 1.2 glass else {
403 1.2 glass switch (*p) {
404 1.2 glass
405 1.2 glass case '#':
406 1.2 glass pbnum(argc - 2);
407 1.2 glass break;
408 1.2 glass case '0':
409 1.2 glass case '1':
410 1.2 glass case '2':
411 1.2 glass case '3':
412 1.2 glass case '4':
413 1.2 glass case '5':
414 1.2 glass case '6':
415 1.2 glass case '7':
416 1.2 glass case '8':
417 1.2 glass case '9':
418 1.2 glass if ((argno = *p - '0') < argc - 1)
419 1.2 glass pbstr(argv[argno + 1]);
420 1.2 glass break;
421 1.2 glass case '*':
422 1.2 glass for (n = argc - 1; n > 2; n--) {
423 1.2 glass pbstr(argv[n]);
424 1.7 pk putback(COMMA);
425 1.2 glass }
426 1.2 glass pbstr(argv[2]);
427 1.2 glass break;
428 1.6 pk case '@':
429 1.6 pk for (n = argc - 1; n > 2; n--) {
430 1.6 pk pbstr(rquote);
431 1.6 pk pbstr(argv[n]);
432 1.6 pk pbstr(lquote);
433 1.7 pk putback(COMMA);
434 1.6 pk }
435 1.6 pk pbstr(rquote);
436 1.6 pk pbstr(argv[2]);
437 1.6 pk pbstr(lquote);
438 1.6 pk break;
439 1.2 glass default:
440 1.2 glass putback(*p);
441 1.2 glass putback('$');
442 1.2 glass break;
443 1.2 glass }
444 1.2 glass p--;
445 1.2 glass }
446 1.2 glass p--;
447 1.2 glass }
448 1.2 glass if (p == t) /* do last character */
449 1.2 glass putback(*p);
450 1.2 glass }
451 1.2 glass
452 1.2 glass /*
453 1.2 glass * dodefine - install definition in the table
454 1.2 glass */
455 1.2 glass void
456 1.2 glass dodefine(name, defn)
457 1.2 glass register char *name;
458 1.2 glass register char *defn;
459 1.2 glass {
460 1.2 glass register ndptr p;
461 1.2 glass
462 1.2 glass if (!*name)
463 1.2 glass oops("null definition.");
464 1.2 glass if (STREQ(name, defn))
465 1.2 glass oops("%s: recursive definition.", name);
466 1.2 glass if ((p = lookup(name)) == nil)
467 1.2 glass p = addent(name);
468 1.2 glass else if (p->defn != null)
469 1.2 glass free((char *) p->defn);
470 1.2 glass if (!*defn)
471 1.2 glass p->defn = null;
472 1.2 glass else
473 1.2 glass p->defn = xstrdup(defn);
474 1.2 glass p->type = MACRTYPE;
475 1.2 glass }
476 1.2 glass
477 1.2 glass /*
478 1.2 glass * dodefn - push back a quoted definition of
479 1.2 glass * the given name.
480 1.2 glass */
481 1.2 glass void
482 1.2 glass dodefn(name)
483 1.2 glass char *name;
484 1.2 glass {
485 1.2 glass register ndptr p;
486 1.2 glass
487 1.2 glass if ((p = lookup(name)) != nil && p->defn != null) {
488 1.9 cgd pbstr(rquote);
489 1.2 glass pbstr(p->defn);
490 1.9 cgd pbstr(lquote);
491 1.2 glass }
492 1.2 glass }
493 1.2 glass
494 1.2 glass /*
495 1.2 glass * dopushdef - install a definition in the hash table
496 1.2 glass * without removing a previous definition. Since
497 1.2 glass * each new entry is entered in *front* of the
498 1.2 glass * hash bucket, it hides a previous definition from
499 1.2 glass * lookup.
500 1.2 glass */
501 1.2 glass void
502 1.2 glass dopushdef(name, defn)
503 1.2 glass register char *name;
504 1.2 glass register char *defn;
505 1.2 glass {
506 1.2 glass register ndptr p;
507 1.2 glass
508 1.2 glass if (!*name)
509 1.2 glass oops("null definition");
510 1.2 glass if (STREQ(name, defn))
511 1.2 glass oops("%s: recursive definition.", name);
512 1.2 glass p = addent(name);
513 1.2 glass if (!*defn)
514 1.2 glass p->defn = null;
515 1.2 glass else
516 1.2 glass p->defn = xstrdup(defn);
517 1.2 glass p->type = MACRTYPE;
518 1.2 glass }
519 1.2 glass
520 1.2 glass /*
521 1.2 glass * dodumpdef - dump the specified definitions in the hash
522 1.2 glass * table to stderr. If nothing is specified, the entire
523 1.2 glass * hash table is dumped.
524 1.2 glass */
525 1.2 glass void
526 1.2 glass dodump(argv, argc)
527 1.2 glass register char *argv[];
528 1.2 glass register int argc;
529 1.2 glass {
530 1.2 glass register int n;
531 1.2 glass ndptr p;
532 1.2 glass
533 1.2 glass if (argc > 2) {
534 1.2 glass for (n = 2; n < argc; n++)
535 1.2 glass if ((p = lookup(argv[n])) != nil)
536 1.2 glass fprintf(stderr, dumpfmt, p->name,
537 1.2 glass p->defn);
538 1.2 glass }
539 1.2 glass else {
540 1.2 glass for (n = 0; n < HASHSIZE; n++)
541 1.2 glass for (p = hashtab[n]; p != nil; p = p->nxtptr)
542 1.2 glass fprintf(stderr, dumpfmt, p->name,
543 1.2 glass p->defn);
544 1.2 glass }
545 1.2 glass }
546 1.2 glass
547 1.2 glass /*
548 1.2 glass * doifelse - select one of two alternatives - loop.
549 1.2 glass */
550 1.2 glass void
551 1.2 glass doifelse(argv, argc)
552 1.2 glass register char *argv[];
553 1.2 glass register int argc;
554 1.2 glass {
555 1.2 glass cycle {
556 1.2 glass if (STREQ(argv[2], argv[3]))
557 1.2 glass pbstr(argv[4]);
558 1.2 glass else if (argc == 6)
559 1.2 glass pbstr(argv[5]);
560 1.2 glass else if (argc > 6) {
561 1.2 glass argv += 3;
562 1.2 glass argc -= 3;
563 1.2 glass continue;
564 1.2 glass }
565 1.2 glass break;
566 1.2 glass }
567 1.2 glass }
568 1.2 glass
569 1.2 glass /*
570 1.2 glass * doinclude - include a given file.
571 1.2 glass */
572 1.2 glass int
573 1.2 glass doincl(ifile)
574 1.2 glass char *ifile;
575 1.2 glass {
576 1.2 glass if (ilevel + 1 == MAXINP)
577 1.2 glass oops("too many include files.");
578 1.2 glass if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) {
579 1.2 glass ilevel++;
580 1.2 glass bbase[ilevel] = bufbase = bp;
581 1.2 glass return (1);
582 1.2 glass }
583 1.2 glass else
584 1.2 glass return (0);
585 1.2 glass }
586 1.2 glass
587 1.2 glass #ifdef EXTENDED
588 1.2 glass /*
589 1.2 glass * dopaste - include a given file without any
590 1.2 glass * macro processing.
591 1.2 glass */
592 1.2 glass int
593 1.2 glass dopaste(pfile)
594 1.2 glass char *pfile;
595 1.2 glass {
596 1.2 glass FILE *pf;
597 1.2 glass register int c;
598 1.2 glass
599 1.2 glass if ((pf = fopen(pfile, "r")) != NULL) {
600 1.2 glass while ((c = getc(pf)) != EOF)
601 1.2 glass putc(c, active);
602 1.2 glass (void) fclose(pf);
603 1.2 glass return (1);
604 1.2 glass }
605 1.2 glass else
606 1.2 glass return (0);
607 1.2 glass }
608 1.2 glass #endif
609 1.2 glass
610 1.2 glass /*
611 1.2 glass * dochq - change quote characters
612 1.2 glass */
613 1.2 glass void
614 1.2 glass dochq(argv, argc)
615 1.2 glass register char *argv[];
616 1.2 glass register int argc;
617 1.2 glass {
618 1.2 glass if (argc > 2) {
619 1.2 glass if (*argv[2])
620 1.5 pk strncpy(lquote, argv[2], MAXCCHARS);
621 1.2 glass if (argc > 3) {
622 1.2 glass if (*argv[3])
623 1.5 pk strncpy(rquote, argv[3], MAXCCHARS);
624 1.2 glass }
625 1.2 glass else
626 1.5 pk strcpy(rquote, lquote);
627 1.2 glass }
628 1.2 glass else {
629 1.5 pk lquote[0] = LQUOTE, lquote[1] = '\0';
630 1.5 pk rquote[0] = RQUOTE, rquote[1] = '\0';
631 1.2 glass }
632 1.2 glass }
633 1.2 glass
634 1.2 glass /*
635 1.2 glass * dochc - change comment characters
636 1.2 glass */
637 1.2 glass void
638 1.2 glass dochc(argv, argc)
639 1.2 glass register char *argv[];
640 1.2 glass register int argc;
641 1.2 glass {
642 1.2 glass if (argc > 2) {
643 1.2 glass if (*argv[2])
644 1.5 pk strncpy(scommt, argv[2], MAXCCHARS);
645 1.2 glass if (argc > 3) {
646 1.2 glass if (*argv[3])
647 1.5 pk strncpy(ecommt, argv[3], MAXCCHARS);
648 1.2 glass }
649 1.2 glass else
650 1.5 pk ecommt[0] = ECOMMT, ecommt[1] = '\0';
651 1.2 glass }
652 1.2 glass else {
653 1.5 pk scommt[0] = SCOMMT, scommt[1] = '\0';
654 1.5 pk ecommt[0] = ECOMMT, ecommt[1] = '\0';
655 1.2 glass }
656 1.2 glass }
657 1.2 glass
658 1.2 glass /*
659 1.2 glass * dodivert - divert the output to a temporary file
660 1.2 glass */
661 1.2 glass void
662 1.2 glass dodiv(n)
663 1.2 glass register int n;
664 1.2 glass {
665 1.9 cgd int tempfilenum;
666 1.9 cgd
667 1.9 cgd /*
668 1.9 cgd * direct output to the appropriate temporary file (the bit
669 1.9 cgd * bucket, if out of range).
670 1.9 cgd */
671 1.9 cgd tempfilenum = (n < 0 || n >= MAXOUT) ? 0 : n;
672 1.9 cgd
673 1.9 cgd if (outfile[tempfilenum] == NULL) {
674 1.9 cgd m4temp[UNIQUE] = tempfilenum + '0';
675 1.9 cgd if ((outfile[tempfilenum] = fopen(m4temp, "w")) == NULL)
676 1.2 glass oops("%s: cannot divert.", m4temp);
677 1.2 glass }
678 1.2 glass oindex = n;
679 1.9 cgd active = outfile[tempfilenum];
680 1.2 glass }
681 1.2 glass
682 1.2 glass /*
683 1.2 glass * doundivert - undivert a specified output, or all
684 1.2 glass * other outputs, in numerical order.
685 1.2 glass */
686 1.2 glass void
687 1.2 glass doundiv(argv, argc)
688 1.2 glass register char *argv[];
689 1.2 glass register int argc;
690 1.2 glass {
691 1.2 glass register int ind;
692 1.2 glass register int n;
693 1.2 glass
694 1.2 glass if (argc > 2) {
695 1.2 glass for (ind = 2; ind < argc; ind++) {
696 1.2 glass n = atoi(argv[ind]);
697 1.2 glass if (n > 0 && n < MAXOUT && outfile[n] != NULL)
698 1.2 glass getdiv(n);
699 1.2 glass
700 1.2 glass }
701 1.2 glass }
702 1.2 glass else
703 1.2 glass for (n = 1; n < MAXOUT; n++)
704 1.2 glass if (outfile[n] != NULL)
705 1.2 glass getdiv(n);
706 1.2 glass }
707 1.2 glass
708 1.2 glass /*
709 1.2 glass * dosub - select substring
710 1.2 glass */
711 1.2 glass void
712 1.2 glass dosub(argv, argc)
713 1.2 glass register char *argv[];
714 1.2 glass register int argc;
715 1.2 glass {
716 1.2 glass register char *ap, *fc, *k;
717 1.2 glass register int nc;
718 1.2 glass
719 1.2 glass if (argc < 5)
720 1.2 glass nc = MAXTOK;
721 1.2 glass else
722 1.2 glass #ifdef EXPR
723 1.2 glass nc = expr(argv[4]);
724 1.2 glass #else
725 1.2 glass nc = atoi(argv[4]);
726 1.2 glass #endif
727 1.2 glass ap = argv[2]; /* target string */
728 1.2 glass #ifdef EXPR
729 1.2 glass fc = ap + expr(argv[3]); /* first char */
730 1.2 glass #else
731 1.2 glass fc = ap + atoi(argv[3]); /* first char */
732 1.2 glass #endif
733 1.2 glass if (fc >= ap && fc < ap + strlen(ap))
734 1.2 glass for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
735 1.2 glass putback(*k);
736 1.2 glass }
737 1.2 glass
738 1.2 glass /*
739 1.2 glass * map:
740 1.2 glass * map every character of s1 that is specified in from
741 1.2 glass * into s3 and replace in s. (source s1 remains untouched)
742 1.2 glass *
743 1.2 glass * This is a standard implementation of map(s,from,to) function of ICON
744 1.2 glass * language. Within mapvec, we replace every character of "from" with
745 1.2 glass * the corresponding character in "to". If "to" is shorter than "from",
746 1.2 glass * than the corresponding entries are null, which means that those
747 1.2 glass * characters dissapear altogether. Furthermore, imagine
748 1.2 glass * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
749 1.2 glass * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
750 1.2 glass * ultimately maps to `*'. In order to achieve this effect in an efficient
751 1.2 glass * manner (i.e. without multiple passes over the destination string), we
752 1.2 glass * loop over mapvec, starting with the initial source character. if the
753 1.2 glass * character value (dch) in this location is different than the source
754 1.2 glass * character (sch), sch becomes dch, once again to index into mapvec, until
755 1.2 glass * the character value stabilizes (i.e. sch = dch, in other words
756 1.2 glass * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
757 1.2 glass * character, it will stabilize, since mapvec[0] == 0 at all times. At the
758 1.2 glass * end, we restore mapvec* back to normal where mapvec[n] == n for
759 1.2 glass * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
760 1.2 glass * about 5 times faster than any algorithm that makes multiple passes over
761 1.2 glass * destination string.
762 1.2 glass */
763 1.2 glass void
764 1.2 glass map(dest, src, from, to)
765 1.2 glass register char *dest;
766 1.2 glass register char *src;
767 1.2 glass register char *from;
768 1.2 glass register char *to;
769 1.2 glass {
770 1.2 glass register char *tmp;
771 1.2 glass register char sch, dch;
772 1.2 glass static char mapvec[128] = {
773 1.2 glass 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
774 1.2 glass 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
775 1.2 glass 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
776 1.2 glass 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
777 1.2 glass 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
778 1.2 glass 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
779 1.2 glass 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
780 1.2 glass 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
781 1.2 glass 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
782 1.2 glass 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
783 1.2 glass 120, 121, 122, 123, 124, 125, 126, 127
784 1.2 glass };
785 1.2 glass
786 1.2 glass if (*src) {
787 1.2 glass tmp = from;
788 1.2 glass /*
789 1.2 glass * create a mapping between "from" and
790 1.2 glass * "to"
791 1.2 glass */
792 1.2 glass while (*from)
793 1.2 glass mapvec[*from++] = (*to) ? *to++ : (char) 0;
794 1.2 glass
795 1.2 glass while (*src) {
796 1.2 glass sch = *src++;
797 1.2 glass dch = mapvec[sch];
798 1.2 glass while (dch != sch) {
799 1.2 glass sch = dch;
800 1.2 glass dch = mapvec[sch];
801 1.2 glass }
802 1.2 glass if (*dest = dch)
803 1.2 glass dest++;
804 1.2 glass }
805 1.2 glass /*
806 1.2 glass * restore all the changed characters
807 1.2 glass */
808 1.2 glass while (*tmp) {
809 1.2 glass mapvec[*tmp] = *tmp;
810 1.2 glass tmp++;
811 1.2 glass }
812 1.2 glass }
813 1.2 glass *dest = (char) 0;
814 1.1 cgd }
815