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