eval.c revision 7004
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 1737004Sache */ 1747004Sache /* Make sure m4 output is NOT interrupted */ 1757004Sache 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. 1851590Srgrimes * 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 2231590Srgrimes * 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 */ 3591590Srgrimes exit((argc > 2) ? atoi(argv[2]) : 0); 3601590Srgrimes break; 3611590Srgrimes 3621590Srgrimes case DEFNTYPE: 3631590Srgrimes if (argc > 2) 3641590Srgrimes for (n = 2; n < argc; n++) 3651590Srgrimes dodefn(argv[n]); 3661590Srgrimes break; 3671590Srgrimes 3681590Srgrimes default: 3691590Srgrimes oops("%s: major botch.", "eval"); 3701590Srgrimes break; 3711590Srgrimes } 3721590Srgrimes} 3731590Srgrimes 3741590Srgrimeschar *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */ 3751590Srgrimes 3761590Srgrimes/* 3771590Srgrimes * expand - user-defined macro expansion 3781590Srgrimes */ 3791590Srgrimesvoid 3801590Srgrimesexpand(argv, argc) 3811590Srgrimesregister char *argv[]; 3821590Srgrimesregister int argc; 3831590Srgrimes{ 3845165Sache register unsigned char *t; 3855165Sache register unsigned char *p; 3861590Srgrimes register int n; 3871590Srgrimes register int argno; 3881590Srgrimes 3891590Srgrimes t = argv[0]; /* defn string as a whole */ 3901590Srgrimes p = t; 3911590Srgrimes while (*p) 3921590Srgrimes p++; 3931590Srgrimes p--; /* last character of defn */ 3941590Srgrimes while (p > t) { 3951590Srgrimes if (*(p - 1) != ARGFLAG) 3961590Srgrimes putback(*p); 3971590Srgrimes else { 3981590Srgrimes switch (*p) { 3991590Srgrimes 4001590Srgrimes case '#': 4011590Srgrimes pbnum(argc - 2); 4021590Srgrimes break; 4031590Srgrimes case '0': 4041590Srgrimes case '1': 4051590Srgrimes case '2': 4061590Srgrimes case '3': 4071590Srgrimes case '4': 4081590Srgrimes case '5': 4091590Srgrimes case '6': 4101590Srgrimes case '7': 4111590Srgrimes case '8': 4121590Srgrimes case '9': 4131590Srgrimes if ((argno = *p - '0') < argc - 1) 4141590Srgrimes pbstr(argv[argno + 1]); 4151590Srgrimes break; 4161590Srgrimes case '*': 4171590Srgrimes for (n = argc - 1; n > 2; n--) { 4181590Srgrimes pbstr(argv[n]); 4191590Srgrimes putback(','); 4201590Srgrimes } 4211590Srgrimes pbstr(argv[2]); 4221590Srgrimes break; 4231590Srgrimes default: 4241590Srgrimes putback(*p); 4251590Srgrimes putback('$'); 4261590Srgrimes break; 4271590Srgrimes } 4281590Srgrimes p--; 4291590Srgrimes } 4301590Srgrimes p--; 4311590Srgrimes } 4321590Srgrimes if (p == t) /* do last character */ 4331590Srgrimes putback(*p); 4341590Srgrimes} 4351590Srgrimes 4361590Srgrimes/* 4371590Srgrimes * dodefine - install definition in the table 4381590Srgrimes */ 4391590Srgrimesvoid 4401590Srgrimesdodefine(name, defn) 4411590Srgrimesregister char *name; 4421590Srgrimesregister char *defn; 4431590Srgrimes{ 4441590Srgrimes register ndptr p; 4451590Srgrimes 4461590Srgrimes if (!*name) 4471590Srgrimes oops("null definition."); 4481590Srgrimes if (STREQ(name, defn)) 4491590Srgrimes oops("%s: recursive definition.", name); 4501590Srgrimes if ((p = lookup(name)) == nil) 4511590Srgrimes p = addent(name); 4521590Srgrimes else if (p->defn != null) 4531590Srgrimes free((char *) p->defn); 4541590Srgrimes if (!*defn) 4551590Srgrimes p->defn = null; 4561590Srgrimes else 4571590Srgrimes p->defn = xstrdup(defn); 4581590Srgrimes p->type = MACRTYPE; 4591590Srgrimes} 4601590Srgrimes 4611590Srgrimes/* 4621590Srgrimes * dodefn - push back a quoted definition of 4631590Srgrimes * the given name. 4641590Srgrimes */ 4651590Srgrimesvoid 4661590Srgrimesdodefn(name) 4671590Srgrimeschar *name; 4681590Srgrimes{ 4691590Srgrimes register ndptr p; 4701590Srgrimes 4711590Srgrimes if ((p = lookup(name)) != nil && p->defn != null) { 4721590Srgrimes putback(rquote); 4731590Srgrimes pbstr(p->defn); 4741590Srgrimes putback(lquote); 4751590Srgrimes } 4761590Srgrimes} 4771590Srgrimes 4781590Srgrimes/* 4791590Srgrimes * dopushdef - install a definition in the hash table 4801590Srgrimes * without removing a previous definition. Since 4811590Srgrimes * each new entry is entered in *front* of the 4821590Srgrimes * hash bucket, it hides a previous definition from 4831590Srgrimes * lookup. 4841590Srgrimes */ 4851590Srgrimesvoid 4861590Srgrimesdopushdef(name, defn) 4871590Srgrimesregister char *name; 4881590Srgrimesregister char *defn; 4891590Srgrimes{ 4901590Srgrimes register ndptr p; 4911590Srgrimes 4921590Srgrimes if (!*name) 4931590Srgrimes oops("null definition"); 4941590Srgrimes if (STREQ(name, defn)) 4951590Srgrimes oops("%s: recursive definition.", name); 4961590Srgrimes p = addent(name); 4971590Srgrimes if (!*defn) 4981590Srgrimes p->defn = null; 4991590Srgrimes else 5001590Srgrimes p->defn = xstrdup(defn); 5011590Srgrimes p->type = MACRTYPE; 5021590Srgrimes} 5031590Srgrimes 5041590Srgrimes/* 5051590Srgrimes * dodumpdef - dump the specified definitions in the hash 5061590Srgrimes * table to stderr. If nothing is specified, the entire 5071590Srgrimes * hash table is dumped. 5081590Srgrimes */ 5091590Srgrimesvoid 5101590Srgrimesdodump(argv, argc) 5111590Srgrimesregister char *argv[]; 5121590Srgrimesregister int argc; 5131590Srgrimes{ 5141590Srgrimes register int n; 5151590Srgrimes ndptr p; 5161590Srgrimes 5171590Srgrimes if (argc > 2) { 5181590Srgrimes for (n = 2; n < argc; n++) 5191590Srgrimes if ((p = lookup(argv[n])) != nil) 5201590Srgrimes fprintf(stderr, dumpfmt, p->name, 5211590Srgrimes p->defn); 5221590Srgrimes } 5231590Srgrimes else { 5241590Srgrimes for (n = 0; n < HASHSIZE; n++) 5251590Srgrimes for (p = hashtab[n]; p != nil; p = p->nxtptr) 5261590Srgrimes fprintf(stderr, dumpfmt, p->name, 5271590Srgrimes p->defn); 5281590Srgrimes } 5291590Srgrimes} 5301590Srgrimes 5311590Srgrimes/* 5321590Srgrimes * doifelse - select one of two alternatives - loop. 5331590Srgrimes */ 5341590Srgrimesvoid 5351590Srgrimesdoifelse(argv, argc) 5361590Srgrimesregister char *argv[]; 5371590Srgrimesregister int argc; 5381590Srgrimes{ 5391590Srgrimes cycle { 5401590Srgrimes if (STREQ(argv[2], argv[3])) 5411590Srgrimes pbstr(argv[4]); 5421590Srgrimes else if (argc == 6) 5431590Srgrimes pbstr(argv[5]); 5441590Srgrimes else if (argc > 6) { 5451590Srgrimes argv += 3; 5461590Srgrimes argc -= 3; 5471590Srgrimes continue; 5481590Srgrimes } 5491590Srgrimes break; 5501590Srgrimes } 5511590Srgrimes} 5521590Srgrimes 5531590Srgrimes/* 5541590Srgrimes * doinclude - include a given file. 5551590Srgrimes */ 5561590Srgrimesint 5571590Srgrimesdoincl(ifile) 5581590Srgrimeschar *ifile; 5591590Srgrimes{ 5601590Srgrimes if (ilevel + 1 == MAXINP) 5611590Srgrimes oops("too many include files."); 5621590Srgrimes if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) { 5631590Srgrimes ilevel++; 5641590Srgrimes bbase[ilevel] = bufbase = bp; 5651590Srgrimes return (1); 5661590Srgrimes } 5671590Srgrimes else 5681590Srgrimes return (0); 5691590Srgrimes} 5701590Srgrimes 5711590Srgrimes#ifdef EXTENDED 5721590Srgrimes/* 5731590Srgrimes * dopaste - include a given file without any 5741590Srgrimes * macro processing. 5751590Srgrimes */ 5761590Srgrimesint 5771590Srgrimesdopaste(pfile) 5781590Srgrimeschar *pfile; 5791590Srgrimes{ 5801590Srgrimes FILE *pf; 5811590Srgrimes register int c; 5821590Srgrimes 5831590Srgrimes if ((pf = fopen(pfile, "r")) != NULL) { 5841590Srgrimes while ((c = getc(pf)) != EOF) 5851590Srgrimes putc(c, active); 5861590Srgrimes (void) fclose(pf); 5871590Srgrimes return (1); 5881590Srgrimes } 5891590Srgrimes else 5901590Srgrimes return (0); 5911590Srgrimes} 5921590Srgrimes#endif 5931590Srgrimes 5941590Srgrimes/* 5951590Srgrimes * dochq - change quote characters 5961590Srgrimes */ 5971590Srgrimesvoid 5981590Srgrimesdochq(argv, argc) 5991590Srgrimesregister char *argv[]; 6001590Srgrimesregister int argc; 6011590Srgrimes{ 6021590Srgrimes if (argc > 2) { 6031590Srgrimes if (*argv[2]) 6041590Srgrimes lquote = *argv[2]; 6051590Srgrimes if (argc > 3) { 6061590Srgrimes if (*argv[3]) 6071590Srgrimes rquote = *argv[3]; 6081590Srgrimes } 6091590Srgrimes else 6101590Srgrimes rquote = lquote; 6111590Srgrimes } 6121590Srgrimes else { 6131590Srgrimes lquote = LQUOTE; 6141590Srgrimes rquote = RQUOTE; 6151590Srgrimes } 6161590Srgrimes} 6171590Srgrimes 6181590Srgrimes/* 6191590Srgrimes * dochc - change comment characters 6201590Srgrimes */ 6211590Srgrimesvoid 6221590Srgrimesdochc(argv, argc) 6231590Srgrimesregister char *argv[]; 6241590Srgrimesregister int argc; 6251590Srgrimes{ 6261590Srgrimes if (argc > 2) { 6271590Srgrimes if (*argv[2]) 6281590Srgrimes scommt = *argv[2]; 6291590Srgrimes if (argc > 3) { 6301590Srgrimes if (*argv[3]) 6311590Srgrimes ecommt = *argv[3]; 6321590Srgrimes } 6331590Srgrimes else 6341590Srgrimes ecommt = ECOMMT; 6351590Srgrimes } 6361590Srgrimes else { 6371590Srgrimes scommt = SCOMMT; 6381590Srgrimes ecommt = ECOMMT; 6391590Srgrimes } 6401590Srgrimes} 6411590Srgrimes 6421590Srgrimes/* 6431590Srgrimes * dodivert - divert the output to a temporary file 6441590Srgrimes */ 6451590Srgrimesvoid 6461590Srgrimesdodiv(n) 6471590Srgrimesregister int n; 6481590Srgrimes{ 6491590Srgrimes if (n < 0 || n >= MAXOUT) 6501590Srgrimes n = 0; /* bitbucket */ 6511590Srgrimes if (outfile[n] == NULL) { 6521590Srgrimes m4temp[UNIQUE] = n + '0'; 6531590Srgrimes if ((outfile[n] = fopen(m4temp, "w")) == NULL) 6541590Srgrimes oops("%s: cannot divert.", m4temp); 6551590Srgrimes } 6561590Srgrimes oindex = n; 6571590Srgrimes active = outfile[n]; 6581590Srgrimes} 6591590Srgrimes 6601590Srgrimes/* 6611590Srgrimes * doundivert - undivert a specified output, or all 6621590Srgrimes * other outputs, in numerical order. 6631590Srgrimes */ 6641590Srgrimesvoid 6651590Srgrimesdoundiv(argv, argc) 6661590Srgrimesregister char *argv[]; 6671590Srgrimesregister int argc; 6681590Srgrimes{ 6691590Srgrimes register int ind; 6701590Srgrimes register int n; 6711590Srgrimes 6721590Srgrimes if (argc > 2) { 6731590Srgrimes for (ind = 2; ind < argc; ind++) { 6741590Srgrimes n = atoi(argv[ind]); 6751590Srgrimes if (n > 0 && n < MAXOUT && outfile[n] != NULL) 6761590Srgrimes getdiv(n); 6771590Srgrimes 6781590Srgrimes } 6791590Srgrimes } 6801590Srgrimes else 6811590Srgrimes for (n = 1; n < MAXOUT; n++) 6821590Srgrimes if (outfile[n] != NULL) 6831590Srgrimes getdiv(n); 6841590Srgrimes} 6851590Srgrimes 6861590Srgrimes/* 6871590Srgrimes * dosub - select substring 6881590Srgrimes */ 6891590Srgrimesvoid 6901590Srgrimesdosub(argv, argc) 6911590Srgrimesregister char *argv[]; 6921590Srgrimesregister int argc; 6931590Srgrimes{ 6945165Sache register unsigned char *ap, *fc, *k; 6951590Srgrimes register int nc; 6961590Srgrimes 6971590Srgrimes if (argc < 5) 6981590Srgrimes nc = MAXTOK; 6991590Srgrimes else 7001590Srgrimes#ifdef EXPR 7011590Srgrimes nc = expr(argv[4]); 7021590Srgrimes#else 7031590Srgrimes nc = atoi(argv[4]); 7041590Srgrimes#endif 7051590Srgrimes ap = argv[2]; /* target string */ 7061590Srgrimes#ifdef EXPR 7071590Srgrimes fc = ap + expr(argv[3]); /* first char */ 7081590Srgrimes#else 7091590Srgrimes fc = ap + atoi(argv[3]); /* first char */ 7101590Srgrimes#endif 7111590Srgrimes if (fc >= ap && fc < ap + strlen(ap)) 7121590Srgrimes for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--) 7131590Srgrimes putback(*k); 7141590Srgrimes} 7151590Srgrimes 7161590Srgrimes/* 7171590Srgrimes * map: 7181590Srgrimes * map every character of s1 that is specified in from 7191590Srgrimes * into s3 and replace in s. (source s1 remains untouched) 7201590Srgrimes * 7211590Srgrimes * This is a standard implementation of map(s,from,to) function of ICON 7221590Srgrimes * language. Within mapvec, we replace every character of "from" with 7231590Srgrimes * the corresponding character in "to". If "to" is shorter than "from", 7241590Srgrimes * than the corresponding entries are null, which means that those 7251590Srgrimes * characters dissapear altogether. Furthermore, imagine 7261590Srgrimes * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, 7271590Srgrimes * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' 7281590Srgrimes * ultimately maps to `*'. In order to achieve this effect in an efficient 7291590Srgrimes * manner (i.e. without multiple passes over the destination string), we 7301590Srgrimes * loop over mapvec, starting with the initial source character. if the 7311590Srgrimes * character value (dch) in this location is different than the source 7321590Srgrimes * character (sch), sch becomes dch, once again to index into mapvec, until 7331590Srgrimes * the character value stabilizes (i.e. sch = dch, in other words 7341590Srgrimes * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary 7351590Srgrimes * character, it will stabilize, since mapvec[0] == 0 at all times. At the 7361590Srgrimes * end, we restore mapvec* back to normal where mapvec[n] == n for 7371590Srgrimes * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is 7381590Srgrimes * about 5 times faster than any algorithm that makes multiple passes over 7391590Srgrimes * destination string. 7401590Srgrimes */ 7411590Srgrimesvoid 7421590Srgrimesmap(dest, src, from, to) 7431590Srgrimesregister char *dest; 7441590Srgrimesregister char *src; 7451590Srgrimesregister char *from; 7461590Srgrimesregister char *to; 7471590Srgrimes{ 7481590Srgrimes register char *tmp; 7491590Srgrimes register char sch, dch; 7501590Srgrimes static char mapvec[128] = { 7511590Srgrimes 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 7521590Srgrimes 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 7531590Srgrimes 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 7541590Srgrimes 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 7551590Srgrimes 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 7561590Srgrimes 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 7571590Srgrimes 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 7581590Srgrimes 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 7591590Srgrimes 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 7601590Srgrimes 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 7611590Srgrimes 120, 121, 122, 123, 124, 125, 126, 127 7621590Srgrimes }; 7631590Srgrimes 7641590Srgrimes if (*src) { 7651590Srgrimes tmp = from; 7661590Srgrimes /* 7671590Srgrimes * create a mapping between "from" and 7681590Srgrimes * "to" 7691590Srgrimes */ 7701590Srgrimes while (*from) 7711590Srgrimes mapvec[*from++] = (*to) ? *to++ : (char) 0; 7721590Srgrimes 7731590Srgrimes while (*src) { 7741590Srgrimes sch = *src++; 7751590Srgrimes dch = mapvec[sch]; 7761590Srgrimes while (dch != sch) { 7771590Srgrimes sch = dch; 7781590Srgrimes dch = mapvec[sch]; 7791590Srgrimes } 7801590Srgrimes if (*dest = dch) 7811590Srgrimes dest++; 7821590Srgrimes } 7831590Srgrimes /* 7841590Srgrimes * restore all the changed characters 7851590Srgrimes */ 7861590Srgrimes while (*tmp) { 7871590Srgrimes mapvec[*tmp] = *tmp; 7881590Srgrimes tmp++; 7891590Srgrimes } 7901590Srgrimes } 7911590Srgrimes *dest = (char) 0; 7921590Srgrimes} 793