eval.c revision 24901
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1989, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * This code is derived from software contributed to Berkeley by 61590Srgrimes * Ozan Yigit at York University. 71590Srgrimes * 81590Srgrimes * Redistribution and use in source and binary forms, with or without 91590Srgrimes * modification, are permitted provided that the following conditions 101590Srgrimes * are met: 111590Srgrimes * 1. Redistributions of source code must retain the above copyright 121590Srgrimes * notice, this list of conditions and the following disclaimer. 131590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141590Srgrimes * notice, this list of conditions and the following disclaimer in the 151590Srgrimes * documentation and/or other materials provided with the distribution. 161590Srgrimes * 3. All advertising materials mentioning features or use of this software 171590Srgrimes * must display the following acknowledgement: 181590Srgrimes * This product includes software developed by the University of 191590Srgrimes * California, Berkeley and its contributors. 201590Srgrimes * 4. Neither the name of the University nor the names of its contributors 211590Srgrimes * may be used to endorse or promote products derived from this software 221590Srgrimes * without specific prior written permission. 231590Srgrimes * 241590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341590Srgrimes * SUCH DAMAGE. 351590Srgrimes */ 361590Srgrimes 371590Srgrimes#ifndef lint 381590Srgrimesstatic char sccsid[] = "@(#)eval.c 8.1 (Berkeley) 6/6/93"; 391590Srgrimes#endif /* not lint */ 401590Srgrimes 411590Srgrimes/* 421590Srgrimes * eval.c 431590Srgrimes * Facility: m4 macro processor 441590Srgrimes * by: oz 451590Srgrimes */ 461590Srgrimes 471590Srgrimes#include <sys/types.h> 481590Srgrimes#include <errno.h> 491590Srgrimes#include <unistd.h> 501590Srgrimes#include <stdio.h> 511590Srgrimes#include <stdlib.h> 521590Srgrimes#include <string.h> 531590Srgrimes#include "mdef.h" 541590Srgrimes#include "stdd.h" 551590Srgrimes#include "extern.h" 561590Srgrimes#include "pathnames.h" 571590Srgrimes 581590Srgrimes/* 591590Srgrimes * eval - evaluate built-in macros. 601590Srgrimes * argc - number of elements in argv. 611590Srgrimes * argv - element vector : 621590Srgrimes * argv[0] = definition of a user 631590Srgrimes * macro or nil if built-in. 641590Srgrimes * argv[1] = name of the macro or 651590Srgrimes * built-in. 661590Srgrimes * argv[2] = parameters to user-defined 671590Srgrimes * . macro or built-in. 681590Srgrimes * . 691590Srgrimes * 701590Srgrimes * Note that the minimum value for argc is 3. A call in the form 711590Srgrimes * of macro-or-builtin() will result in: 721590Srgrimes * argv[0] = nullstr 731590Srgrimes * argv[1] = macro-or-builtin 741590Srgrimes * argv[2] = nullstr 751590Srgrimes */ 761590Srgrimes 771590Srgrimesvoid 781590Srgrimeseval(argv, argc, td) 791590Srgrimesregister char *argv[]; 801590Srgrimesregister int argc; 811590Srgrimesregister int td; 821590Srgrimes{ 831590Srgrimes register int c, n; 841590Srgrimes static int sysval = 0; 851590Srgrimes 861590Srgrimes#ifdef DEBUG 871590Srgrimes printf("argc = %d\n", argc); 881590Srgrimes for (n = 0; n < argc; n++) 891590Srgrimes printf("argv[%d] = %s\n", n, argv[n]); 901590Srgrimes#endif 911590Srgrimes /* 921590Srgrimes * if argc == 3 and argv[2] is null, then we 931590Srgrimes * have macro-or-builtin() type call. We adjust 941590Srgrimes * argc to avoid further checking.. 951590Srgrimes */ 961590Srgrimes if (argc == 3 && !*(argv[2])) 971590Srgrimes argc--; 981590Srgrimes 991590Srgrimes switch (td & ~STATIC) { 1001590Srgrimes 1011590Srgrimes case DEFITYPE: 1021590Srgrimes if (argc > 2) 1031590Srgrimes dodefine(argv[2], (argc > 3) ? argv[3] : null); 1041590Srgrimes break; 1051590Srgrimes 1061590Srgrimes case PUSDTYPE: 1071590Srgrimes if (argc > 2) 1081590Srgrimes dopushdef(argv[2], (argc > 3) ? argv[3] : null); 1091590Srgrimes break; 1101590Srgrimes 1111590Srgrimes case DUMPTYPE: 1121590Srgrimes dodump(argv, argc); 1131590Srgrimes break; 1141590Srgrimes 1151590Srgrimes case EXPRTYPE: 1161590Srgrimes /* 1171590Srgrimes * doexpr - evaluate arithmetic 1181590Srgrimes * expression 1191590Srgrimes */ 1201590Srgrimes if (argc > 2) 1211590Srgrimes pbnum(expr(argv[2])); 1221590Srgrimes break; 1231590Srgrimes 1241590Srgrimes case IFELTYPE: 1251590Srgrimes if (argc > 4) 1261590Srgrimes doifelse(argv, argc); 1271590Srgrimes break; 1281590Srgrimes 1291590Srgrimes case IFDFTYPE: 1301590Srgrimes /* 1311590Srgrimes * doifdef - select one of two 1321590Srgrimes * alternatives based on the existence of 1331590Srgrimes * another definition 1341590Srgrimes */ 1351590Srgrimes if (argc > 3) { 1361590Srgrimes if (lookup(argv[2]) != nil) 1371590Srgrimes pbstr(argv[3]); 1381590Srgrimes else if (argc > 4) 1391590Srgrimes pbstr(argv[4]); 1401590Srgrimes } 1411590Srgrimes break; 1421590Srgrimes 1431590Srgrimes case LENGTYPE: 1441590Srgrimes /* 1451590Srgrimes * dolen - find the length of the 1461590Srgrimes * argument 1471590Srgrimes */ 1481590Srgrimes if (argc > 2) 1491590Srgrimes pbnum((argc > 2) ? strlen(argv[2]) : 0); 1501590Srgrimes break; 1511590Srgrimes 1521590Srgrimes case INCRTYPE: 1531590Srgrimes /* 1541590Srgrimes * doincr - increment the value of the 1551590Srgrimes * argument 1561590Srgrimes */ 1571590Srgrimes if (argc > 2) 1581590Srgrimes pbnum(atoi(argv[2]) + 1); 1591590Srgrimes break; 1601590Srgrimes 1611590Srgrimes case DECRTYPE: 1621590Srgrimes /* 1631590Srgrimes * dodecr - decrement the value of the 1641590Srgrimes * argument 1651590Srgrimes */ 1661590Srgrimes if (argc > 2) 1671590Srgrimes pbnum(atoi(argv[2]) - 1); 1681590Srgrimes break; 1691590Srgrimes 1701590Srgrimes case SYSCTYPE: 1711590Srgrimes /* 1721590Srgrimes * dosys - execute system command 1738874Srgrimes */ 1748874Srgrimes /* Make sure m4 output is NOT interrupted */ 1758874Srgrimes fflush(stdout); 1767004Sache fflush(stderr); 1771590Srgrimes if (argc > 2) 1781590Srgrimes sysval = system(argv[2]); 1791590Srgrimes break; 1801590Srgrimes 1811590Srgrimes case SYSVTYPE: 1821590Srgrimes /* 1831590Srgrimes * dosysval - return value of the last 1841590Srgrimes * system call. 1858874Srgrimes * 1861590Srgrimes */ 1871590Srgrimes pbnum(sysval); 1881590Srgrimes break; 1891590Srgrimes 1901590Srgrimes case INCLTYPE: 1911590Srgrimes if (argc > 2) 1921590Srgrimes if (!doincl(argv[2])) 1931590Srgrimes oops("%s: %s", argv[2], strerror(errno)); 1941590Srgrimes break; 1951590Srgrimes 1961590Srgrimes case SINCTYPE: 1971590Srgrimes if (argc > 2) 1981590Srgrimes (void) doincl(argv[2]); 1991590Srgrimes break; 2001590Srgrimes#ifdef EXTENDED 2011590Srgrimes case PASTTYPE: 2021590Srgrimes if (argc > 2) 2031590Srgrimes if (!dopaste(argv[2])) 2041590Srgrimes oops("%s: %s", argv[2], strerror(errno)); 2051590Srgrimes break; 2061590Srgrimes 2071590Srgrimes case SPASTYPE: 2081590Srgrimes if (argc > 2) 2091590Srgrimes (void) dopaste(argv[2]); 2101590Srgrimes break; 2111590Srgrimes#endif 2121590Srgrimes case CHNQTYPE: 2131590Srgrimes dochq(argv, argc); 2141590Srgrimes break; 2151590Srgrimes 2161590Srgrimes case CHNCTYPE: 2171590Srgrimes dochc(argv, argc); 2181590Srgrimes break; 2191590Srgrimes 2201590Srgrimes case SUBSTYPE: 2211590Srgrimes /* 2221590Srgrimes * dosub - select substring 2238874Srgrimes * 2241590Srgrimes */ 2251590Srgrimes if (argc > 3) 2261590Srgrimes dosub(argv, argc); 2271590Srgrimes break; 2281590Srgrimes 2291590Srgrimes case SHIFTYPE: 2301590Srgrimes /* 2311590Srgrimes * doshift - push back all arguments 2321590Srgrimes * except the first one (i.e. skip 2331590Srgrimes * argv[2]) 2341590Srgrimes */ 2351590Srgrimes if (argc > 3) { 2361590Srgrimes for (n = argc - 1; n > 3; n--) { 2371590Srgrimes putback(rquote); 2381590Srgrimes pbstr(argv[n]); 2391590Srgrimes putback(lquote); 2401590Srgrimes putback(','); 2411590Srgrimes } 2421590Srgrimes putback(rquote); 2431590Srgrimes pbstr(argv[3]); 2441590Srgrimes putback(lquote); 2451590Srgrimes } 2461590Srgrimes break; 2471590Srgrimes 2481590Srgrimes case DIVRTYPE: 2491590Srgrimes if (argc > 2 && (n = atoi(argv[2])) != 0) 2501590Srgrimes dodiv(n); 2511590Srgrimes else { 2521590Srgrimes active = stdout; 2531590Srgrimes oindex = 0; 2541590Srgrimes } 2551590Srgrimes break; 2561590Srgrimes 2571590Srgrimes case UNDVTYPE: 2581590Srgrimes doundiv(argv, argc); 2591590Srgrimes break; 2601590Srgrimes 2611590Srgrimes case DIVNTYPE: 2621590Srgrimes /* 2631590Srgrimes * dodivnum - return the number of 2641590Srgrimes * current output diversion 2651590Srgrimes */ 2661590Srgrimes pbnum(oindex); 2671590Srgrimes break; 2681590Srgrimes 2691590Srgrimes case UNDFTYPE: 2701590Srgrimes /* 2711590Srgrimes * doundefine - undefine a previously 2721590Srgrimes * defined macro(s) or m4 keyword(s). 2731590Srgrimes */ 2741590Srgrimes if (argc > 2) 2751590Srgrimes for (n = 2; n < argc; n++) 2761590Srgrimes remhash(argv[n], ALL); 2771590Srgrimes break; 2781590Srgrimes 2791590Srgrimes case POPDTYPE: 2801590Srgrimes /* 2811590Srgrimes * dopopdef - remove the topmost 2821590Srgrimes * definitions of macro(s) or m4 2831590Srgrimes * keyword(s). 2841590Srgrimes */ 2851590Srgrimes if (argc > 2) 2861590Srgrimes for (n = 2; n < argc; n++) 2871590Srgrimes remhash(argv[n], TOP); 2881590Srgrimes break; 2891590Srgrimes 2901590Srgrimes case MKTMTYPE: 2911590Srgrimes /* 2921590Srgrimes * dotemp - create a temporary file 2931590Srgrimes */ 2941590Srgrimes if (argc > 2) 2951590Srgrimes pbstr(mktemp(argv[2])); 2961590Srgrimes break; 2971590Srgrimes 2981590Srgrimes case TRNLTYPE: 2991590Srgrimes /* 3001590Srgrimes * dotranslit - replace all characters in 3011590Srgrimes * the source string that appears in the 3021590Srgrimes * "from" string with the corresponding 3031590Srgrimes * characters in the "to" string. 3041590Srgrimes */ 3051590Srgrimes if (argc > 3) { 3061590Srgrimes char temp[MAXTOK]; 3071590Srgrimes if (argc > 4) 3081590Srgrimes map(temp, argv[2], argv[3], argv[4]); 3091590Srgrimes else 3101590Srgrimes map(temp, argv[2], argv[3], null); 3111590Srgrimes pbstr(temp); 3121590Srgrimes } 3131590Srgrimes else if (argc > 2) 3141590Srgrimes pbstr(argv[2]); 3151590Srgrimes break; 3161590Srgrimes 3171590Srgrimes case INDXTYPE: 3181590Srgrimes /* 3191590Srgrimes * doindex - find the index of the second 3201590Srgrimes * argument string in the first argument 3211590Srgrimes * string. -1 if not present. 3221590Srgrimes */ 3231590Srgrimes pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1); 3241590Srgrimes break; 3251590Srgrimes 3261590Srgrimes case ERRPTYPE: 3271590Srgrimes /* 3281590Srgrimes * doerrp - print the arguments to stderr 3291590Srgrimes * file 3301590Srgrimes */ 3311590Srgrimes if (argc > 2) { 3321590Srgrimes for (n = 2; n < argc; n++) 3331590Srgrimes fprintf(stderr, "%s ", argv[n]); 3341590Srgrimes fprintf(stderr, "\n"); 3351590Srgrimes } 3361590Srgrimes break; 3371590Srgrimes 3381590Srgrimes case DNLNTYPE: 3391590Srgrimes /* 3401590Srgrimes * dodnl - eat-up-to and including 3411590Srgrimes * newline 3421590Srgrimes */ 3431590Srgrimes while ((c = gpbc()) != '\n' && c != EOF) 3441590Srgrimes ; 3451590Srgrimes break; 3461590Srgrimes 3471590Srgrimes case M4WRTYPE: 3481590Srgrimes /* 3491590Srgrimes * dom4wrap - set up for 3501590Srgrimes * wrap-up/wind-down activity 3511590Srgrimes */ 3521590Srgrimes m4wraps = (argc > 2) ? xstrdup(argv[2]) : null; 3531590Srgrimes break; 3541590Srgrimes 3551590Srgrimes case EXITTYPE: 3561590Srgrimes /* 3571590Srgrimes * doexit - immediate exit from m4. 3581590Srgrimes */ 3597896Sache killdiv(); 3601590Srgrimes exit((argc > 2) ? atoi(argv[2]) : 0); 3611590Srgrimes break; 3621590Srgrimes 3631590Srgrimes case DEFNTYPE: 3641590Srgrimes if (argc > 2) 3651590Srgrimes for (n = 2; n < argc; n++) 3661590Srgrimes dodefn(argv[n]); 3671590Srgrimes break; 3681590Srgrimes 3691590Srgrimes default: 3701590Srgrimes oops("%s: major botch.", "eval"); 3711590Srgrimes break; 3721590Srgrimes } 3731590Srgrimes} 3741590Srgrimes 3751590Srgrimeschar *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */ 3761590Srgrimes 3771590Srgrimes/* 3781590Srgrimes * expand - user-defined macro expansion 3791590Srgrimes */ 3801590Srgrimesvoid 3811590Srgrimesexpand(argv, argc) 3821590Srgrimesregister char *argv[]; 3831590Srgrimesregister int argc; 3841590Srgrimes{ 3855165Sache register unsigned char *t; 3865165Sache register unsigned char *p; 3871590Srgrimes register int n; 3881590Srgrimes register int argno; 3891590Srgrimes 3901590Srgrimes t = argv[0]; /* defn string as a whole */ 3911590Srgrimes p = t; 3921590Srgrimes while (*p) 3931590Srgrimes p++; 3941590Srgrimes p--; /* last character of defn */ 3951590Srgrimes while (p > t) { 3961590Srgrimes if (*(p - 1) != ARGFLAG) 3971590Srgrimes putback(*p); 3981590Srgrimes else { 3991590Srgrimes switch (*p) { 4001590Srgrimes 4011590Srgrimes case '#': 4021590Srgrimes pbnum(argc - 2); 4031590Srgrimes break; 4041590Srgrimes case '0': 4051590Srgrimes case '1': 4061590Srgrimes case '2': 4071590Srgrimes case '3': 4081590Srgrimes case '4': 4091590Srgrimes case '5': 4101590Srgrimes case '6': 4111590Srgrimes case '7': 4121590Srgrimes case '8': 4131590Srgrimes case '9': 4141590Srgrimes if ((argno = *p - '0') < argc - 1) 4151590Srgrimes pbstr(argv[argno + 1]); 4161590Srgrimes break; 4171590Srgrimes case '*': 4181590Srgrimes for (n = argc - 1; n > 2; n--) { 4191590Srgrimes pbstr(argv[n]); 4201590Srgrimes putback(','); 4211590Srgrimes } 4221590Srgrimes pbstr(argv[2]); 4231590Srgrimes break; 42424901Sjoerg case '@': 42524901Sjoerg for( n = argc - 1; n >= 2; n-- ) 42624901Sjoerg { 42724901Sjoerg putback(rquote); 42824901Sjoerg pbstr(argv[n]); 42924901Sjoerg putback(lquote); 43024901Sjoerg if( n > 2 ) 43124901Sjoerg putback(','); 43224901Sjoerg } 43324901Sjoerg break; 4341590Srgrimes default: 4351590Srgrimes putback(*p); 4361590Srgrimes putback('$'); 4371590Srgrimes break; 4381590Srgrimes } 4391590Srgrimes p--; 4401590Srgrimes } 4411590Srgrimes p--; 4421590Srgrimes } 4431590Srgrimes if (p == t) /* do last character */ 4441590Srgrimes putback(*p); 4451590Srgrimes} 4461590Srgrimes 4471590Srgrimes/* 4481590Srgrimes * dodefine - install definition in the table 4491590Srgrimes */ 4501590Srgrimesvoid 4511590Srgrimesdodefine(name, defn) 4521590Srgrimesregister char *name; 4531590Srgrimesregister char *defn; 4541590Srgrimes{ 4551590Srgrimes register ndptr p; 4561590Srgrimes 4571590Srgrimes if (!*name) 4581590Srgrimes oops("null definition."); 4591590Srgrimes if (STREQ(name, defn)) 4601590Srgrimes oops("%s: recursive definition.", name); 4611590Srgrimes if ((p = lookup(name)) == nil) 4621590Srgrimes p = addent(name); 4631590Srgrimes else if (p->defn != null) 4641590Srgrimes free((char *) p->defn); 4651590Srgrimes if (!*defn) 4661590Srgrimes p->defn = null; 4671590Srgrimes else 4681590Srgrimes p->defn = xstrdup(defn); 4691590Srgrimes p->type = MACRTYPE; 4701590Srgrimes} 4711590Srgrimes 4721590Srgrimes/* 4731590Srgrimes * dodefn - push back a quoted definition of 4741590Srgrimes * the given name. 4751590Srgrimes */ 4761590Srgrimesvoid 4771590Srgrimesdodefn(name) 4781590Srgrimeschar *name; 4791590Srgrimes{ 4801590Srgrimes register ndptr p; 4811590Srgrimes 4821590Srgrimes if ((p = lookup(name)) != nil && p->defn != null) { 4831590Srgrimes putback(rquote); 4841590Srgrimes pbstr(p->defn); 4851590Srgrimes putback(lquote); 4861590Srgrimes } 4871590Srgrimes} 4881590Srgrimes 4891590Srgrimes/* 4901590Srgrimes * dopushdef - install a definition in the hash table 4911590Srgrimes * without removing a previous definition. Since 4921590Srgrimes * each new entry is entered in *front* of the 4931590Srgrimes * hash bucket, it hides a previous definition from 4941590Srgrimes * lookup. 4951590Srgrimes */ 4961590Srgrimesvoid 4971590Srgrimesdopushdef(name, defn) 4981590Srgrimesregister char *name; 4991590Srgrimesregister char *defn; 5001590Srgrimes{ 5011590Srgrimes register ndptr p; 5021590Srgrimes 5031590Srgrimes if (!*name) 5041590Srgrimes oops("null definition"); 5051590Srgrimes if (STREQ(name, defn)) 5061590Srgrimes oops("%s: recursive definition.", name); 5071590Srgrimes p = addent(name); 5081590Srgrimes if (!*defn) 5091590Srgrimes p->defn = null; 5101590Srgrimes else 5111590Srgrimes p->defn = xstrdup(defn); 5121590Srgrimes p->type = MACRTYPE; 5131590Srgrimes} 5141590Srgrimes 5151590Srgrimes/* 5161590Srgrimes * dodumpdef - dump the specified definitions in the hash 5171590Srgrimes * table to stderr. If nothing is specified, the entire 5181590Srgrimes * hash table is dumped. 5191590Srgrimes */ 5201590Srgrimesvoid 5211590Srgrimesdodump(argv, argc) 5221590Srgrimesregister char *argv[]; 5231590Srgrimesregister int argc; 5241590Srgrimes{ 5251590Srgrimes register int n; 5261590Srgrimes ndptr p; 5271590Srgrimes 5281590Srgrimes if (argc > 2) { 5291590Srgrimes for (n = 2; n < argc; n++) 5301590Srgrimes if ((p = lookup(argv[n])) != nil) 5311590Srgrimes fprintf(stderr, dumpfmt, p->name, 5321590Srgrimes p->defn); 5331590Srgrimes } 5341590Srgrimes else { 5351590Srgrimes for (n = 0; n < HASHSIZE; n++) 5361590Srgrimes for (p = hashtab[n]; p != nil; p = p->nxtptr) 5371590Srgrimes fprintf(stderr, dumpfmt, p->name, 5381590Srgrimes p->defn); 5391590Srgrimes } 5401590Srgrimes} 5411590Srgrimes 5421590Srgrimes/* 5431590Srgrimes * doifelse - select one of two alternatives - loop. 5441590Srgrimes */ 5451590Srgrimesvoid 5461590Srgrimesdoifelse(argv, argc) 5471590Srgrimesregister char *argv[]; 5481590Srgrimesregister int argc; 5491590Srgrimes{ 5501590Srgrimes cycle { 5511590Srgrimes if (STREQ(argv[2], argv[3])) 5521590Srgrimes pbstr(argv[4]); 5531590Srgrimes else if (argc == 6) 5541590Srgrimes pbstr(argv[5]); 5551590Srgrimes else if (argc > 6) { 5561590Srgrimes argv += 3; 5571590Srgrimes argc -= 3; 5581590Srgrimes continue; 5591590Srgrimes } 5601590Srgrimes break; 5611590Srgrimes } 5621590Srgrimes} 5631590Srgrimes 5641590Srgrimes/* 5651590Srgrimes * doinclude - include a given file. 5661590Srgrimes */ 5671590Srgrimesint 5681590Srgrimesdoincl(ifile) 5691590Srgrimeschar *ifile; 5701590Srgrimes{ 5711590Srgrimes if (ilevel + 1 == MAXINP) 5721590Srgrimes oops("too many include files."); 5731590Srgrimes if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) { 5741590Srgrimes ilevel++; 5751590Srgrimes bbase[ilevel] = bufbase = bp; 5761590Srgrimes return (1); 5771590Srgrimes } 5781590Srgrimes else 5791590Srgrimes return (0); 5801590Srgrimes} 5811590Srgrimes 5821590Srgrimes#ifdef EXTENDED 5831590Srgrimes/* 5841590Srgrimes * dopaste - include a given file without any 5851590Srgrimes * macro processing. 5861590Srgrimes */ 5871590Srgrimesint 5881590Srgrimesdopaste(pfile) 5891590Srgrimeschar *pfile; 5901590Srgrimes{ 5911590Srgrimes FILE *pf; 5921590Srgrimes register int c; 5931590Srgrimes 5941590Srgrimes if ((pf = fopen(pfile, "r")) != NULL) { 5951590Srgrimes while ((c = getc(pf)) != EOF) 5961590Srgrimes putc(c, active); 5971590Srgrimes (void) fclose(pf); 5981590Srgrimes return (1); 5991590Srgrimes } 6001590Srgrimes else 6011590Srgrimes return (0); 6021590Srgrimes} 6031590Srgrimes#endif 6041590Srgrimes 6051590Srgrimes/* 6061590Srgrimes * dochq - change quote characters 6071590Srgrimes */ 6081590Srgrimesvoid 6091590Srgrimesdochq(argv, argc) 6101590Srgrimesregister char *argv[]; 6111590Srgrimesregister int argc; 6121590Srgrimes{ 6131590Srgrimes if (argc > 2) { 6141590Srgrimes if (*argv[2]) 6151590Srgrimes lquote = *argv[2]; 6161590Srgrimes if (argc > 3) { 6171590Srgrimes if (*argv[3]) 6181590Srgrimes rquote = *argv[3]; 6191590Srgrimes } 6201590Srgrimes else 6211590Srgrimes rquote = lquote; 6221590Srgrimes } 6231590Srgrimes else { 6241590Srgrimes lquote = LQUOTE; 6251590Srgrimes rquote = RQUOTE; 6261590Srgrimes } 6271590Srgrimes} 6281590Srgrimes 6291590Srgrimes/* 6301590Srgrimes * dochc - change comment characters 6311590Srgrimes */ 6321590Srgrimesvoid 6331590Srgrimesdochc(argv, argc) 6341590Srgrimesregister char *argv[]; 6351590Srgrimesregister int argc; 6361590Srgrimes{ 6371590Srgrimes if (argc > 2) { 6381590Srgrimes if (*argv[2]) 6391590Srgrimes scommt = *argv[2]; 6401590Srgrimes if (argc > 3) { 6411590Srgrimes if (*argv[3]) 6421590Srgrimes ecommt = *argv[3]; 6431590Srgrimes } 6441590Srgrimes else 6451590Srgrimes ecommt = ECOMMT; 6461590Srgrimes } 6471590Srgrimes else { 6481590Srgrimes scommt = SCOMMT; 6491590Srgrimes ecommt = ECOMMT; 6501590Srgrimes } 6511590Srgrimes} 6521590Srgrimes 6531590Srgrimes/* 6541590Srgrimes * dodivert - divert the output to a temporary file 6551590Srgrimes */ 6561590Srgrimesvoid 6571590Srgrimesdodiv(n) 6581590Srgrimesregister int n; 6591590Srgrimes{ 6601590Srgrimes if (n < 0 || n >= MAXOUT) 6611590Srgrimes n = 0; /* bitbucket */ 6621590Srgrimes if (outfile[n] == NULL) { 6631590Srgrimes m4temp[UNIQUE] = n + '0'; 6641590Srgrimes if ((outfile[n] = fopen(m4temp, "w")) == NULL) 6651590Srgrimes oops("%s: cannot divert.", m4temp); 6661590Srgrimes } 6671590Srgrimes oindex = n; 6681590Srgrimes active = outfile[n]; 6691590Srgrimes} 6701590Srgrimes 6711590Srgrimes/* 6721590Srgrimes * doundivert - undivert a specified output, or all 6731590Srgrimes * other outputs, in numerical order. 6741590Srgrimes */ 6751590Srgrimesvoid 6761590Srgrimesdoundiv(argv, argc) 6771590Srgrimesregister char *argv[]; 6781590Srgrimesregister int argc; 6791590Srgrimes{ 6801590Srgrimes register int ind; 6811590Srgrimes register int n; 6821590Srgrimes 6831590Srgrimes if (argc > 2) { 6841590Srgrimes for (ind = 2; ind < argc; ind++) { 6851590Srgrimes n = atoi(argv[ind]); 6861590Srgrimes if (n > 0 && n < MAXOUT && outfile[n] != NULL) 6871590Srgrimes getdiv(n); 6881590Srgrimes 6891590Srgrimes } 6901590Srgrimes } 6911590Srgrimes else 6921590Srgrimes for (n = 1; n < MAXOUT; n++) 6931590Srgrimes if (outfile[n] != NULL) 6941590Srgrimes getdiv(n); 6951590Srgrimes} 6961590Srgrimes 6971590Srgrimes/* 6981590Srgrimes * dosub - select substring 6991590Srgrimes */ 7001590Srgrimesvoid 7011590Srgrimesdosub(argv, argc) 7021590Srgrimesregister char *argv[]; 7031590Srgrimesregister int argc; 7041590Srgrimes{ 7055165Sache register unsigned char *ap, *fc, *k; 7061590Srgrimes register int nc; 7071590Srgrimes 7081590Srgrimes if (argc < 5) 7091590Srgrimes nc = MAXTOK; 7101590Srgrimes else 7111590Srgrimes#ifdef EXPR 7121590Srgrimes nc = expr(argv[4]); 7131590Srgrimes#else 7141590Srgrimes nc = atoi(argv[4]); 7151590Srgrimes#endif 7161590Srgrimes ap = argv[2]; /* target string */ 7171590Srgrimes#ifdef EXPR 7181590Srgrimes fc = ap + expr(argv[3]); /* first char */ 7191590Srgrimes#else 7201590Srgrimes fc = ap + atoi(argv[3]); /* first char */ 7211590Srgrimes#endif 7221590Srgrimes if (fc >= ap && fc < ap + strlen(ap)) 7231590Srgrimes for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--) 7241590Srgrimes putback(*k); 7251590Srgrimes} 7261590Srgrimes 7271590Srgrimes/* 7281590Srgrimes * map: 7291590Srgrimes * map every character of s1 that is specified in from 7301590Srgrimes * into s3 and replace in s. (source s1 remains untouched) 7311590Srgrimes * 7321590Srgrimes * This is a standard implementation of map(s,from,to) function of ICON 7331590Srgrimes * language. Within mapvec, we replace every character of "from" with 7341590Srgrimes * the corresponding character in "to". If "to" is shorter than "from", 7351590Srgrimes * than the corresponding entries are null, which means that those 7361590Srgrimes * characters dissapear altogether. Furthermore, imagine 7371590Srgrimes * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, 7381590Srgrimes * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' 7391590Srgrimes * ultimately maps to `*'. In order to achieve this effect in an efficient 7401590Srgrimes * manner (i.e. without multiple passes over the destination string), we 7411590Srgrimes * loop over mapvec, starting with the initial source character. if the 7421590Srgrimes * character value (dch) in this location is different than the source 7431590Srgrimes * character (sch), sch becomes dch, once again to index into mapvec, until 7441590Srgrimes * the character value stabilizes (i.e. sch = dch, in other words 7451590Srgrimes * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary 7461590Srgrimes * character, it will stabilize, since mapvec[0] == 0 at all times. At the 7471590Srgrimes * end, we restore mapvec* back to normal where mapvec[n] == n for 7481590Srgrimes * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is 7491590Srgrimes * about 5 times faster than any algorithm that makes multiple passes over 7501590Srgrimes * destination string. 7511590Srgrimes */ 7521590Srgrimesvoid 7531590Srgrimesmap(dest, src, from, to) 7541590Srgrimesregister char *dest; 7551590Srgrimesregister char *src; 7561590Srgrimesregister char *from; 7571590Srgrimesregister char *to; 7581590Srgrimes{ 7591590Srgrimes register char *tmp; 7601590Srgrimes register char sch, dch; 7611590Srgrimes static char mapvec[128] = { 7621590Srgrimes 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 7631590Srgrimes 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 7641590Srgrimes 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 7651590Srgrimes 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 7661590Srgrimes 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 7671590Srgrimes 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 7681590Srgrimes 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 7691590Srgrimes 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 7701590Srgrimes 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 7711590Srgrimes 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 7721590Srgrimes 120, 121, 122, 123, 124, 125, 126, 127 7731590Srgrimes }; 7741590Srgrimes 7751590Srgrimes if (*src) { 7761590Srgrimes tmp = from; 7771590Srgrimes /* 7781590Srgrimes * create a mapping between "from" and 7791590Srgrimes * "to" 7801590Srgrimes */ 7811590Srgrimes while (*from) 7821590Srgrimes mapvec[*from++] = (*to) ? *to++ : (char) 0; 7831590Srgrimes 7841590Srgrimes while (*src) { 7851590Srgrimes sch = *src++; 7861590Srgrimes dch = mapvec[sch]; 7871590Srgrimes while (dch != sch) { 7881590Srgrimes sch = dch; 7891590Srgrimes dch = mapvec[sch]; 7901590Srgrimes } 7911590Srgrimes if (*dest = dch) 7921590Srgrimes dest++; 7931590Srgrimes } 7941590Srgrimes /* 7951590Srgrimes * restore all the changed characters 7961590Srgrimes */ 7971590Srgrimes while (*tmp) { 7981590Srgrimes mapvec[*tmp] = *tmp; 7991590Srgrimes tmp++; 8001590Srgrimes } 8011590Srgrimes } 8021590Srgrimes *dest = (char) 0; 8031590Srgrimes} 804