1352281Sbapt/* $OpenBSD: eval.c,v 1.78 2019/06/28 05:35:34 deraadt Exp $ */ 295060Sjmallett/* $NetBSD: eval.c,v 1.7 1996/11/10 21:21:29 pk Exp $ */ 395060Sjmallett 4331722Seadler/* 51590Srgrimes * Copyright (c) 1989, 1993 61590Srgrimes * The Regents of the University of California. All rights reserved. 71590Srgrimes * 81590Srgrimes * This code is derived from software contributed to Berkeley by 91590Srgrimes * Ozan Yigit at York University. 101590Srgrimes * 111590Srgrimes * Redistribution and use in source and binary forms, with or without 121590Srgrimes * modification, are permitted provided that the following conditions 131590Srgrimes * are met: 141590Srgrimes * 1. Redistributions of source code must retain the above copyright 151590Srgrimes * notice, this list of conditions and the following disclaimer. 161590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 171590Srgrimes * notice, this list of conditions and the following disclaimer in the 181590Srgrimes * documentation and/or other materials provided with the distribution. 19228063Sbapt * 3. Neither the name of the University nor the names of its contributors 201590Srgrimes * may be used to endorse or promote products derived from this software 211590Srgrimes * without specific prior written permission. 221590Srgrimes * 231590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 241590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 251590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 261590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 271590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 281590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 291590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 301590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 311590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 321590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 331590Srgrimes * SUCH DAMAGE. 341590Srgrimes */ 351590Srgrimes 3695060Sjmallett#include <sys/cdefs.h> 3795060Sjmallett__FBSDID("$FreeBSD: stable/11/usr.bin/m4/eval.c 352281 2019-09-13 07:22:09Z bapt $"); 381590Srgrimes 39228063Sbapt 401590Srgrimes/* 411590Srgrimes * eval.c 421590Srgrimes * Facility: m4 macro processor 431590Srgrimes * by: oz 441590Srgrimes */ 451590Srgrimes 461590Srgrimes#include <sys/types.h> 47228063Sbapt#include <err.h> 4895060Sjmallett#include <errno.h> 49228063Sbapt#include <limits.h> 5095060Sjmallett#include <unistd.h> 51291128Sbapt#include <stdio.h> 52228063Sbapt#include <stdint.h> 531590Srgrimes#include <stdlib.h> 5495060Sjmallett#include <stddef.h> 551590Srgrimes#include <string.h> 5695060Sjmallett#include <fcntl.h> 571590Srgrimes#include "mdef.h" 581590Srgrimes#include "stdd.h" 591590Srgrimes#include "extern.h" 601590Srgrimes#include "pathnames.h" 611590Srgrimes 6295060Sjmallettstatic void dodefn(const char *); 6395060Sjmallettstatic void dopushdef(const char *, const char *); 6495060Sjmallettstatic void dodump(const char *[], int); 6595060Sjmallettstatic void dotrace(const char *[], int, int); 6695060Sjmallettstatic void doifelse(const char *[], int); 6795060Sjmallettstatic int doincl(const char *); 6895060Sjmallettstatic int dopaste(const char *); 6995060Sjmallettstatic void dochq(const char *[], int); 7095060Sjmallettstatic void dochc(const char *[], int); 71228063Sbaptstatic void dom4wrap(const char *); 7295060Sjmallettstatic void dodiv(int); 7395060Sjmallettstatic void doundiv(const char *[], int); 7495060Sjmallettstatic void dosub(const char *[], int); 7595060Sjmallettstatic void map(char *, const char *, const char *, const char *); 7695060Sjmallettstatic const char *handledash(char *, char *, const char *); 7795060Sjmallettstatic void expand_builtin(const char *[], int, int); 7895060Sjmallettstatic void expand_macro(const char *[], int); 79228063Sbaptstatic void dump_one_def(const char *, struct macro_definition *); 8095060Sjmallett 8195060Sjmallettunsigned long expansion_id; 8295060Sjmallett 831590Srgrimes/* 8495060Sjmallett * eval - eval all macros and builtins calls 851590Srgrimes * argc - number of elements in argv. 861590Srgrimes * argv - element vector : 871590Srgrimes * argv[0] = definition of a user 88228063Sbapt * macro or NULL if built-in. 891590Srgrimes * argv[1] = name of the macro or 901590Srgrimes * built-in. 911590Srgrimes * argv[2] = parameters to user-defined 921590Srgrimes * . macro or built-in. 931590Srgrimes * . 941590Srgrimes * 9595060Sjmallett * A call in the form of macro-or-builtin() will result in: 961590Srgrimes * argv[0] = nullstr 971590Srgrimes * argv[1] = macro-or-builtin 981590Srgrimes * argv[2] = nullstr 9995060Sjmallett * 10095060Sjmallett * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin 1011590Srgrimes */ 1021590Srgrimesvoid 103228063Sbapteval(const char *argv[], int argc, int td, int is_traced) 1041590Srgrimes{ 105228063Sbapt size_t mark = SIZE_MAX; 10695060Sjmallett 10795060Sjmallett expansion_id++; 108100014Sjmallett if (td & RECDEF) 109228063Sbapt m4errx(1, "expanding recursive definition for %s.", argv[1]); 110228063Sbapt if (is_traced) 11195060Sjmallett mark = trace(argv, argc, infile+ilevel); 11295060Sjmallett if (td == MACRTYPE) 11395060Sjmallett expand_macro(argv, argc); 11495060Sjmallett else 11595060Sjmallett expand_builtin(argv, argc, td); 116228063Sbapt if (mark != SIZE_MAX) 11795060Sjmallett finish_trace(mark); 11895060Sjmallett} 11995060Sjmallett 12095060Sjmallett/* 12195060Sjmallett * expand_builtin - evaluate built-in macros. 12295060Sjmallett */ 12395060Sjmallettvoid 12495887Sjmallettexpand_builtin(const char *argv[], int argc, int td) 12595060Sjmallett{ 12695060Sjmallett int c, n; 127352281Sbapt const char *errstr; 12895060Sjmallett int ac; 1291590Srgrimes static int sysval = 0; 1301590Srgrimes 1311590Srgrimes#ifdef DEBUG 1321590Srgrimes printf("argc = %d\n", argc); 1331590Srgrimes for (n = 0; n < argc; n++) 1341590Srgrimes printf("argv[%d] = %s\n", n, argv[n]); 13595060Sjmallett fflush(stdout); 1361590Srgrimes#endif 13795060Sjmallett 1381590Srgrimes /* 1391590Srgrimes * if argc == 3 and argv[2] is null, then we 1401590Srgrimes * have macro-or-builtin() type call. We adjust 1411590Srgrimes * argc to avoid further checking.. 1421590Srgrimes */ 143228063Sbapt /* we keep the initial value for those built-ins that differentiate 144228063Sbapt * between builtin() and builtin. 145228063Sbapt */ 146228063Sbapt ac = argc; 14795060Sjmallett 148228063Sbapt if (argc == 3 && !*(argv[2]) && !mimic_gnu) 1491590Srgrimes argc--; 1501590Srgrimes 15195060Sjmallett switch (td & TYPEMASK) { 1521590Srgrimes 1531590Srgrimes case DEFITYPE: 1541590Srgrimes if (argc > 2) 1551590Srgrimes dodefine(argv[2], (argc > 3) ? argv[3] : null); 1561590Srgrimes break; 1571590Srgrimes 1581590Srgrimes case PUSDTYPE: 1591590Srgrimes if (argc > 2) 1601590Srgrimes dopushdef(argv[2], (argc > 3) ? argv[3] : null); 1611590Srgrimes break; 1621590Srgrimes 1631590Srgrimes case DUMPTYPE: 1641590Srgrimes dodump(argv, argc); 1651590Srgrimes break; 1661590Srgrimes 16795060Sjmallett case TRACEONTYPE: 16895060Sjmallett dotrace(argv, argc, 1); 16995060Sjmallett break; 17095060Sjmallett 17195060Sjmallett case TRACEOFFTYPE: 17295060Sjmallett dotrace(argv, argc, 0); 17395060Sjmallett break; 17495060Sjmallett 1751590Srgrimes case EXPRTYPE: 1761590Srgrimes /* 1771590Srgrimes * doexpr - evaluate arithmetic 1781590Srgrimes * expression 1791590Srgrimes */ 180228063Sbapt { 181228063Sbapt int base = 10; 182228063Sbapt int maxdigits = 0; 183228063Sbapt const char *errstr; 184228063Sbapt 185228063Sbapt if (argc > 3) { 186228063Sbapt base = strtonum(argv[3], 2, 36, &errstr); 187228063Sbapt if (errstr) { 188352281Sbapt m4errx(1, "expr: base is %s: %s.", 189352281Sbapt errstr, argv[3]); 190228063Sbapt } 191228063Sbapt } 192228063Sbapt if (argc > 4) { 193228063Sbapt maxdigits = strtonum(argv[4], 0, INT_MAX, &errstr); 194228063Sbapt if (errstr) { 195352281Sbapt m4errx(1, "expr: maxdigits is %s: %s.", 196352281Sbapt errstr, argv[4]); 197228063Sbapt } 198228063Sbapt } 1991590Srgrimes if (argc > 2) 200228063Sbapt pbnumbase(expr(argv[2]), base, maxdigits); 2011590Srgrimes break; 202228063Sbapt } 2031590Srgrimes 2041590Srgrimes case IFELTYPE: 205352281Sbapt doifelse(argv, argc); 2061590Srgrimes break; 2071590Srgrimes 2081590Srgrimes case IFDFTYPE: 2091590Srgrimes /* 2101590Srgrimes * doifdef - select one of two 2111590Srgrimes * alternatives based on the existence of 2121590Srgrimes * another definition 2131590Srgrimes */ 2141590Srgrimes if (argc > 3) { 215228063Sbapt if (lookup_macro_definition(argv[2]) != NULL) 2161590Srgrimes pbstr(argv[3]); 2171590Srgrimes else if (argc > 4) 2181590Srgrimes pbstr(argv[4]); 2191590Srgrimes } 2201590Srgrimes break; 2211590Srgrimes 2221590Srgrimes case LENGTYPE: 2231590Srgrimes /* 2241590Srgrimes * dolen - find the length of the 2251590Srgrimes * argument 2261590Srgrimes */ 22777378Sgshapiro pbnum((argc > 2) ? strlen(argv[2]) : 0); 2281590Srgrimes break; 2291590Srgrimes 2301590Srgrimes case INCRTYPE: 2311590Srgrimes /* 2321590Srgrimes * doincr - increment the value of the 2331590Srgrimes * argument 2341590Srgrimes */ 235352281Sbapt if (argc > 2) { 236352281Sbapt n = strtonum(argv[2], INT_MIN, INT_MAX-1, &errstr); 237352281Sbapt if (errstr != NULL) 238352281Sbapt m4errx(1, "incr: argument is %s: %s.", 239352281Sbapt errstr, argv[2]); 240352281Sbapt pbnum(n + 1); 241352281Sbapt } 2421590Srgrimes break; 2431590Srgrimes 2441590Srgrimes case DECRTYPE: 2451590Srgrimes /* 2461590Srgrimes * dodecr - decrement the value of the 2471590Srgrimes * argument 2481590Srgrimes */ 249352281Sbapt if (argc > 2) { 250352281Sbapt n = strtonum(argv[2], INT_MIN+1, INT_MAX, &errstr); 251352281Sbapt if (errstr) 252352281Sbapt m4errx(1, "decr: argument is %s: %s.", 253352281Sbapt errstr, argv[2]); 254352281Sbapt pbnum(n - 1); 255352281Sbapt } 2561590Srgrimes break; 2571590Srgrimes 2581590Srgrimes case SYSCTYPE: 2591590Srgrimes /* 2601590Srgrimes * dosys - execute system command 2618874Srgrimes */ 262114368Stjr if (argc > 2) { 263228063Sbapt fflush(stdout); 2641590Srgrimes sysval = system(argv[2]); 265114368Stjr } 2661590Srgrimes break; 2671590Srgrimes 2681590Srgrimes case SYSVTYPE: 2691590Srgrimes /* 2701590Srgrimes * dosysval - return value of the last 2711590Srgrimes * system call. 272100014Sjmallett * 2731590Srgrimes */ 2741590Srgrimes pbnum(sysval); 2751590Srgrimes break; 2761590Srgrimes 27795060Sjmallett case ESYSCMDTYPE: 27895060Sjmallett if (argc > 2) 27995060Sjmallett doesyscmd(argv[2]); 280228063Sbapt break; 2811590Srgrimes case INCLTYPE: 282269162Sbapt if (argc > 2) { 283228701Sbz if (!doincl(argv[2])) { 284234310Sbapt if (mimic_gnu) { 285228697Sbapt warn("%s at line %lu: include(%s)", 286228697Sbapt CURRENT_NAME, CURRENT_LINE, argv[2]); 287234310Sbapt exit_code = 1; 288352281Sbapt if (fatal_warns) { 289352281Sbapt killdiv(); 290352281Sbapt exit(exit_code); 291352281Sbapt } 292234310Sbapt } else 293228697Sbapt err(1, "%s at line %lu: include(%s)", 294228697Sbapt CURRENT_NAME, CURRENT_LINE, argv[2]); 295228701Sbz } 296269162Sbapt } 2971590Srgrimes break; 2981590Srgrimes 2991590Srgrimes case SINCTYPE: 3001590Srgrimes if (argc > 2) 3011590Srgrimes (void) doincl(argv[2]); 3021590Srgrimes break; 3031590Srgrimes#ifdef EXTENDED 3041590Srgrimes case PASTTYPE: 3051590Srgrimes if (argc > 2) 3061590Srgrimes if (!dopaste(argv[2])) 307228063Sbapt err(1, "%s at line %lu: paste(%s)", 30895060Sjmallett CURRENT_NAME, CURRENT_LINE, argv[2]); 3091590Srgrimes break; 3101590Srgrimes 3111590Srgrimes case SPASTYPE: 3121590Srgrimes if (argc > 2) 3131590Srgrimes (void) dopaste(argv[2]); 3141590Srgrimes break; 315228063Sbapt case FORMATTYPE: 316228063Sbapt doformat(argv, argc); 317228063Sbapt break; 3181590Srgrimes#endif 3191590Srgrimes case CHNQTYPE: 320228063Sbapt dochq(argv, ac); 3211590Srgrimes break; 3221590Srgrimes 3231590Srgrimes case CHNCTYPE: 324228063Sbapt dochc(argv, argc); 3251590Srgrimes break; 3261590Srgrimes 3271590Srgrimes case SUBSTYPE: 3281590Srgrimes /* 3291590Srgrimes * dosub - select substring 330100014Sjmallett * 3311590Srgrimes */ 3321590Srgrimes if (argc > 3) 3331590Srgrimes dosub(argv, argc); 3341590Srgrimes break; 3351590Srgrimes 3361590Srgrimes case SHIFTYPE: 3371590Srgrimes /* 3381590Srgrimes * doshift - push back all arguments 3391590Srgrimes * except the first one (i.e. skip 3401590Srgrimes * argv[2]) 3411590Srgrimes */ 3421590Srgrimes if (argc > 3) { 3431590Srgrimes for (n = argc - 1; n > 3; n--) { 34495060Sjmallett pbstr(rquote); 3451590Srgrimes pbstr(argv[n]); 34695060Sjmallett pbstr(lquote); 347228063Sbapt pushback(COMMA); 3481590Srgrimes } 34995060Sjmallett pbstr(rquote); 3501590Srgrimes pbstr(argv[3]); 35195060Sjmallett pbstr(lquote); 3521590Srgrimes } 3531590Srgrimes break; 3541590Srgrimes 3551590Srgrimes case DIVRTYPE: 356352281Sbapt if (argc > 2) { 357352281Sbapt n = strtonum(argv[2], INT_MIN, INT_MAX, &errstr); 358352281Sbapt if (errstr) 359352281Sbapt m4errx(1, "divert: argument is %s: %s.", 360352281Sbapt errstr, argv[2]); 361352281Sbapt if (n != 0) { 362352281Sbapt dodiv(n); 363352281Sbapt break; 364352281Sbapt } 3651590Srgrimes } 366352281Sbapt active = stdout; 367352281Sbapt oindex = 0; 3681590Srgrimes break; 3691590Srgrimes 3701590Srgrimes case UNDVTYPE: 3711590Srgrimes doundiv(argv, argc); 3721590Srgrimes break; 3731590Srgrimes 3741590Srgrimes case DIVNTYPE: 3751590Srgrimes /* 3761590Srgrimes * dodivnum - return the number of 3771590Srgrimes * current output diversion 3781590Srgrimes */ 3791590Srgrimes pbnum(oindex); 3801590Srgrimes break; 3811590Srgrimes 3821590Srgrimes case UNDFTYPE: 3831590Srgrimes /* 3841590Srgrimes * doundefine - undefine a previously 3851590Srgrimes * defined macro(s) or m4 keyword(s). 3861590Srgrimes */ 3871590Srgrimes if (argc > 2) 3881590Srgrimes for (n = 2; n < argc; n++) 389228063Sbapt macro_undefine(argv[n]); 3901590Srgrimes break; 3911590Srgrimes 3921590Srgrimes case POPDTYPE: 3931590Srgrimes /* 3941590Srgrimes * dopopdef - remove the topmost 3951590Srgrimes * definitions of macro(s) or m4 3961590Srgrimes * keyword(s). 3971590Srgrimes */ 3981590Srgrimes if (argc > 2) 3991590Srgrimes for (n = 2; n < argc; n++) 400228063Sbapt macro_popdef(argv[n]); 4011590Srgrimes break; 4021590Srgrimes 4031590Srgrimes case MKTMTYPE: 4041590Srgrimes /* 4051590Srgrimes * dotemp - create a temporary file 4061590Srgrimes */ 40795060Sjmallett if (argc > 2) { 40895060Sjmallett int fd; 40995060Sjmallett char *temp; 41095060Sjmallett 41195060Sjmallett temp = xstrdup(argv[2]); 412100014Sjmallett 41395060Sjmallett fd = mkstemp(temp); 41495060Sjmallett if (fd == -1) 415100014Sjmallett err(1, 416100014Sjmallett "%s at line %lu: couldn't make temp file %s", 41795060Sjmallett CURRENT_NAME, CURRENT_LINE, argv[2]); 41895060Sjmallett close(fd); 41995060Sjmallett pbstr(temp); 42095060Sjmallett free(temp); 42195060Sjmallett } 4221590Srgrimes break; 4231590Srgrimes 4241590Srgrimes case TRNLTYPE: 4251590Srgrimes /* 4261590Srgrimes * dotranslit - replace all characters in 4271590Srgrimes * the source string that appears in the 4281590Srgrimes * "from" string with the corresponding 4291590Srgrimes * characters in the "to" string. 4301590Srgrimes */ 4311590Srgrimes if (argc > 3) { 43295060Sjmallett char *temp; 43395060Sjmallett 434228063Sbapt temp = xalloc(strlen(argv[2])+1, NULL); 4351590Srgrimes if (argc > 4) 4361590Srgrimes map(temp, argv[2], argv[3], argv[4]); 4371590Srgrimes else 4381590Srgrimes map(temp, argv[2], argv[3], null); 4391590Srgrimes pbstr(temp); 44095060Sjmallett free(temp); 44195060Sjmallett } else if (argc > 2) 4421590Srgrimes pbstr(argv[2]); 4431590Srgrimes break; 4441590Srgrimes 4451590Srgrimes case INDXTYPE: 4461590Srgrimes /* 4471590Srgrimes * doindex - find the index of the second 4481590Srgrimes * argument string in the first argument 4491590Srgrimes * string. -1 if not present. 4501590Srgrimes */ 4511590Srgrimes pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1); 4521590Srgrimes break; 4531590Srgrimes 4541590Srgrimes case ERRPTYPE: 4551590Srgrimes /* 4561590Srgrimes * doerrp - print the arguments to stderr 4571590Srgrimes * file 4581590Srgrimes */ 4591590Srgrimes if (argc > 2) { 4601590Srgrimes for (n = 2; n < argc; n++) 4611590Srgrimes fprintf(stderr, "%s ", argv[n]); 4621590Srgrimes fprintf(stderr, "\n"); 4631590Srgrimes } 4641590Srgrimes break; 4651590Srgrimes 4661590Srgrimes case DNLNTYPE: 4671590Srgrimes /* 4681590Srgrimes * dodnl - eat-up-to and including 4691590Srgrimes * newline 4701590Srgrimes */ 4711590Srgrimes while ((c = gpbc()) != '\n' && c != EOF) 4721590Srgrimes ; 4731590Srgrimes break; 4741590Srgrimes 4751590Srgrimes case M4WRTYPE: 4761590Srgrimes /* 4771590Srgrimes * dom4wrap - set up for 4781590Srgrimes * wrap-up/wind-down activity 4791590Srgrimes */ 480228063Sbapt if (argc > 2) 481228063Sbapt dom4wrap(argv[2]); 4821590Srgrimes break; 4831590Srgrimes 4841590Srgrimes case EXITTYPE: 4851590Srgrimes /* 4861590Srgrimes * doexit - immediate exit from m4. 4871590Srgrimes */ 4887896Sache killdiv(); 4891590Srgrimes exit((argc > 2) ? atoi(argv[2]) : 0); 4901590Srgrimes break; 4911590Srgrimes 4921590Srgrimes case DEFNTYPE: 4931590Srgrimes if (argc > 2) 4941590Srgrimes for (n = 2; n < argc; n++) 4951590Srgrimes dodefn(argv[n]); 4961590Srgrimes break; 4971590Srgrimes 49895060Sjmallett case INDIRTYPE: /* Indirect call */ 49995060Sjmallett if (argc > 2) 50095060Sjmallett doindir(argv, argc); 50138926Ssteve break; 502100014Sjmallett 50395060Sjmallett case BUILTINTYPE: /* Builtins only */ 50495060Sjmallett if (argc > 2) 50595060Sjmallett dobuiltin(argv, argc); 50695060Sjmallett break; 50738926Ssteve 50895060Sjmallett case PATSTYPE: 50995060Sjmallett if (argc > 2) 51095060Sjmallett dopatsubst(argv, argc); 51195060Sjmallett break; 51295060Sjmallett case REGEXPTYPE: 51395060Sjmallett if (argc > 2) 51495060Sjmallett doregexp(argv, argc); 51595060Sjmallett break; 51695060Sjmallett case LINETYPE: 51795060Sjmallett doprintlineno(infile+ilevel); 51895060Sjmallett break; 51995060Sjmallett case FILENAMETYPE: 52095060Sjmallett doprintfilename(infile+ilevel); 52195060Sjmallett break; 52295060Sjmallett case SELFTYPE: 52395060Sjmallett pbstr(rquote); 52495060Sjmallett pbstr(argv[1]); 52595060Sjmallett pbstr(lquote); 52695060Sjmallett break; 5271590Srgrimes default: 528228063Sbapt m4errx(1, "eval: major botch."); 5291590Srgrimes break; 5301590Srgrimes } 5311590Srgrimes} 5321590Srgrimes 5331590Srgrimes/* 53495060Sjmallett * expand_macro - user-defined macro expansion 5351590Srgrimes */ 5361590Srgrimesvoid 53795887Sjmallettexpand_macro(const char *argv[], int argc) 5381590Srgrimes{ 53995060Sjmallett const char *t; 54095060Sjmallett const char *p; 54195060Sjmallett int n; 54295060Sjmallett int argno; 5431590Srgrimes 5441590Srgrimes t = argv[0]; /* defn string as a whole */ 5451590Srgrimes p = t; 5461590Srgrimes while (*p) 5471590Srgrimes p++; 5481590Srgrimes p--; /* last character of defn */ 5491590Srgrimes while (p > t) { 5501590Srgrimes if (*(p - 1) != ARGFLAG) 551228063Sbapt PUSHBACK(*p); 5521590Srgrimes else { 5531590Srgrimes switch (*p) { 5541590Srgrimes 5551590Srgrimes case '#': 5561590Srgrimes pbnum(argc - 2); 5571590Srgrimes break; 5581590Srgrimes case '0': 5591590Srgrimes case '1': 5601590Srgrimes case '2': 5611590Srgrimes case '3': 5621590Srgrimes case '4': 5631590Srgrimes case '5': 5641590Srgrimes case '6': 5651590Srgrimes case '7': 5661590Srgrimes case '8': 5671590Srgrimes case '9': 5681590Srgrimes if ((argno = *p - '0') < argc - 1) 5691590Srgrimes pbstr(argv[argno + 1]); 5701590Srgrimes break; 5711590Srgrimes case '*': 57295060Sjmallett if (argc > 2) { 57395060Sjmallett for (n = argc - 1; n > 2; n--) { 57495060Sjmallett pbstr(argv[n]); 575228063Sbapt pushback(COMMA); 57695060Sjmallett } 57795060Sjmallett pbstr(argv[2]); 578228063Sbapt } 5791590Srgrimes break; 58095060Sjmallett case '@': 58195060Sjmallett if (argc > 2) { 58295060Sjmallett for (n = argc - 1; n > 2; n--) { 58395060Sjmallett pbstr(rquote); 58495060Sjmallett pbstr(argv[n]); 58595060Sjmallett pbstr(lquote); 586228063Sbapt pushback(COMMA); 58795060Sjmallett } 58895060Sjmallett pbstr(rquote); 58995060Sjmallett pbstr(argv[2]); 59095060Sjmallett pbstr(lquote); 59124901Sjoerg } 59295060Sjmallett break; 5931590Srgrimes default: 594228063Sbapt PUSHBACK(*p); 595228063Sbapt PUSHBACK('$'); 5961590Srgrimes break; 5971590Srgrimes } 5981590Srgrimes p--; 5991590Srgrimes } 6001590Srgrimes p--; 6011590Srgrimes } 6021590Srgrimes if (p == t) /* do last character */ 603228063Sbapt PUSHBACK(*p); 6041590Srgrimes} 6051590Srgrimes 606228063Sbapt 6071590Srgrimes/* 6081590Srgrimes * dodefine - install definition in the table 6091590Srgrimes */ 6101590Srgrimesvoid 61195887Sjmallettdodefine(const char *name, const char *defn) 6121590Srgrimes{ 613228063Sbapt if (!*name && !mimic_gnu) 614228063Sbapt m4errx(1, "null definition."); 6151590Srgrimes else 616228063Sbapt macro_define(name, defn); 6171590Srgrimes} 6181590Srgrimes 6191590Srgrimes/* 6201590Srgrimes * dodefn - push back a quoted definition of 6211590Srgrimes * the given name. 6221590Srgrimes */ 62395060Sjmallettstatic void 62495887Sjmallettdodefn(const char *name) 6251590Srgrimes{ 626228063Sbapt struct macro_definition *p; 6271590Srgrimes 628228063Sbapt if ((p = lookup_macro_definition(name)) != NULL) { 629228063Sbapt if ((p->type & TYPEMASK) == MACRTYPE) { 63095060Sjmallett pbstr(rquote); 63195060Sjmallett pbstr(p->defn); 63295060Sjmallett pbstr(lquote); 633228063Sbapt } else { 634228063Sbapt pbstr(p->defn); 63595060Sjmallett pbstr(BUILTIN_MARKER); 63695060Sjmallett } 6371590Srgrimes } 6381590Srgrimes} 6391590Srgrimes 6401590Srgrimes/* 6411590Srgrimes * dopushdef - install a definition in the hash table 6421590Srgrimes * without removing a previous definition. Since 6431590Srgrimes * each new entry is entered in *front* of the 6441590Srgrimes * hash bucket, it hides a previous definition from 6451590Srgrimes * lookup. 6461590Srgrimes */ 64795060Sjmallettstatic void 64895887Sjmallettdopushdef(const char *name, const char *defn) 6491590Srgrimes{ 650228063Sbapt if (!*name && !mimic_gnu) 651228063Sbapt m4errx(1, "null definition."); 6521590Srgrimes else 653228063Sbapt macro_pushdef(name, defn); 6541590Srgrimes} 6551590Srgrimes 6561590Srgrimes/* 65795060Sjmallett * dump_one_def - dump the specified definition. 65895060Sjmallett */ 65995060Sjmallettstatic void 660228063Sbaptdump_one_def(const char *name, struct macro_definition *p) 66195060Sjmallett{ 662228063Sbapt if (!traceout) 663228063Sbapt traceout = stderr; 66495060Sjmallett if (mimic_gnu) { 66595060Sjmallett if ((p->type & TYPEMASK) == MACRTYPE) 666228063Sbapt fprintf(traceout, "%s:\t%s\n", name, p->defn); 66795060Sjmallett else { 668228063Sbapt fprintf(traceout, "%s:\t<%s>\n", name, p->defn); 669228063Sbapt } 67095060Sjmallett } else 671228063Sbapt fprintf(traceout, "`%s'\t`%s'\n", name, p->defn); 67295060Sjmallett} 67395060Sjmallett 67495060Sjmallett/* 6751590Srgrimes * dodumpdef - dump the specified definitions in the hash 6761590Srgrimes * table to stderr. If nothing is specified, the entire 6771590Srgrimes * hash table is dumped. 6781590Srgrimes */ 67995060Sjmallettstatic void 68095887Sjmallettdodump(const char *argv[], int argc) 6811590Srgrimes{ 68295060Sjmallett int n; 683228063Sbapt struct macro_definition *p; 6841590Srgrimes 6851590Srgrimes if (argc > 2) { 6861590Srgrimes for (n = 2; n < argc; n++) 687228063Sbapt if ((p = lookup_macro_definition(argv[n])) != NULL) 688228063Sbapt dump_one_def(argv[n], p); 689228063Sbapt } else 690228063Sbapt macro_for_all(dump_one_def); 6911590Srgrimes} 6921590Srgrimes 6931590Srgrimes/* 69495060Sjmallett * dotrace - mark some macros as traced/untraced depending upon on. 69595060Sjmallett */ 69695060Sjmallettstatic void 69795887Sjmallettdotrace(const char *argv[], int argc, int on) 69895060Sjmallett{ 69995060Sjmallett int n; 70095060Sjmallett 70195060Sjmallett if (argc > 2) { 70295060Sjmallett for (n = 2; n < argc; n++) 70395060Sjmallett mark_traced(argv[n], on); 70495060Sjmallett } else 70595060Sjmallett mark_traced(NULL, on); 70695060Sjmallett} 70795060Sjmallett 70895060Sjmallett/* 7091590Srgrimes * doifelse - select one of two alternatives - loop. 7101590Srgrimes */ 71195060Sjmallettstatic void 71295887Sjmallettdoifelse(const char *argv[], int argc) 7131590Srgrimes{ 714352281Sbapt while (argc > 4) { 715352281Sbapt if (STREQ(argv[2], argv[3])) { 7161590Srgrimes pbstr(argv[4]); 717352281Sbapt break; 718352281Sbapt } else if (argc == 6) { 7191590Srgrimes pbstr(argv[5]); 720352281Sbapt break; 721352281Sbapt } else { 7221590Srgrimes argv += 3; 7231590Srgrimes argc -= 3; 7241590Srgrimes } 7251590Srgrimes } 7261590Srgrimes} 7271590Srgrimes 7281590Srgrimes/* 7291590Srgrimes * doinclude - include a given file. 7301590Srgrimes */ 73195060Sjmallettstatic int 73295887Sjmallettdoincl(const char *ifile) 7331590Srgrimes{ 7341590Srgrimes if (ilevel + 1 == MAXINP) 735228063Sbapt m4errx(1, "too many include files."); 73695060Sjmallett if (fopen_trypath(infile+ilevel+1, ifile) != NULL) { 7371590Srgrimes ilevel++; 7381590Srgrimes bbase[ilevel] = bufbase = bp; 7391590Srgrimes return (1); 74095060Sjmallett } else 7411590Srgrimes return (0); 7421590Srgrimes} 7431590Srgrimes 7441590Srgrimes#ifdef EXTENDED 7451590Srgrimes/* 7461590Srgrimes * dopaste - include a given file without any 7471590Srgrimes * macro processing. 7481590Srgrimes */ 74995060Sjmallettstatic int 75095887Sjmallettdopaste(const char *pfile) 7511590Srgrimes{ 7521590Srgrimes FILE *pf; 75395060Sjmallett int c; 7541590Srgrimes 7551590Srgrimes if ((pf = fopen(pfile, "r")) != NULL) { 756228063Sbapt if (synch_lines) 757228063Sbapt fprintf(active, "#line 1 \"%s\"\n", pfile); 7581590Srgrimes while ((c = getc(pf)) != EOF) 7591590Srgrimes putc(c, active); 7601590Srgrimes (void) fclose(pf); 761228063Sbapt emit_synchline(); 7621590Srgrimes return (1); 76395060Sjmallett } else 7641590Srgrimes return (0); 7651590Srgrimes} 7661590Srgrimes#endif 7671590Srgrimes 768228063Sbapt/* 769228063Sbapt * dochq - change quote characters 770228063Sbapt */ 77195060Sjmallettstatic void 772228063Sbaptdochq(const char *argv[], int ac) 77395060Sjmallett{ 77495060Sjmallett if (ac == 2) { 775228063Sbapt lquote[0] = LQUOTE; lquote[1] = EOS; 776228063Sbapt rquote[0] = RQUOTE; rquote[1] = EOS; 77795060Sjmallett } else { 77895060Sjmallett strlcpy(lquote, argv[2], sizeof(lquote)); 779228063Sbapt if (ac > 3) { 78095060Sjmallett strlcpy(rquote, argv[3], sizeof(rquote)); 781228063Sbapt } else { 782228063Sbapt rquote[0] = ECOMMT; rquote[1] = EOS; 783228063Sbapt } 78495060Sjmallett } 78595060Sjmallett} 78695060Sjmallett 7871590Srgrimes/* 788228063Sbapt * dochc - change comment characters 7891590Srgrimes */ 79095060Sjmallettstatic void 791228063Sbaptdochc(const char *argv[], int argc) 7921590Srgrimes{ 793228063Sbapt/* XXX Note that there is no difference between no argument and a single 794228063Sbapt * empty argument. 795228063Sbapt */ 796228063Sbapt if (argc == 2) { 79795060Sjmallett scommt[0] = EOS; 79895060Sjmallett ecommt[0] = EOS; 79995060Sjmallett } else { 800228063Sbapt strlcpy(scommt, argv[2], sizeof(scommt)); 801228063Sbapt if (argc == 3) { 802228063Sbapt ecommt[0] = ECOMMT; ecommt[1] = EOS; 803228063Sbapt } else { 80495060Sjmallett strlcpy(ecommt, argv[3], sizeof(ecommt)); 805228063Sbapt } 8061590Srgrimes } 8071590Srgrimes} 808228063Sbapt 8091590Srgrimes/* 810228063Sbapt * dom4wrap - expand text at EOF 8111590Srgrimes */ 81295060Sjmallettstatic void 813228063Sbaptdom4wrap(const char *text) 8141590Srgrimes{ 815228063Sbapt if (wrapindex >= maxwraps) { 816228063Sbapt if (maxwraps == 0) 817228063Sbapt maxwraps = 16; 8181590Srgrimes else 819228063Sbapt maxwraps *= 2; 820269162Sbapt m4wraps = xreallocarray(m4wraps, maxwraps, sizeof(*m4wraps), 821228063Sbapt "too many m4wraps"); 8221590Srgrimes } 823228063Sbapt m4wraps[wrapindex++] = xstrdup(text); 8241590Srgrimes} 8251590Srgrimes 8261590Srgrimes/* 8271590Srgrimes * dodivert - divert the output to a temporary file 8281590Srgrimes */ 82995060Sjmallettstatic void 83095887Sjmallettdodiv(int n) 8311590Srgrimes{ 83295060Sjmallett int fd; 83395060Sjmallett 83428386Sjlemon oindex = n; 83595060Sjmallett if (n >= maxout) { 83695060Sjmallett if (mimic_gnu) 83795060Sjmallett resizedivs(n + 10); 83895060Sjmallett else 83995060Sjmallett n = 0; /* bitbucket */ 840228063Sbapt } 84195060Sjmallett 84295060Sjmallett if (n < 0) 8431590Srgrimes n = 0; /* bitbucket */ 8441590Srgrimes if (outfile[n] == NULL) { 84595060Sjmallett char fname[] = _PATH_DIVNAME; 84695060Sjmallett 847352281Sbapt if ((fd = mkstemp(fname)) == -1 || 848269162Sbapt unlink(fname) == -1 || 849269162Sbapt (outfile[n] = fdopen(fd, "w+")) == NULL) 850269162Sbapt err(1, "%s: cannot divert", fname); 8511590Srgrimes } 8521590Srgrimes active = outfile[n]; 8531590Srgrimes} 8541590Srgrimes 8551590Srgrimes/* 8561590Srgrimes * doundivert - undivert a specified output, or all 8571590Srgrimes * other outputs, in numerical order. 8581590Srgrimes */ 85995060Sjmallettstatic void 86095887Sjmallettdoundiv(const char *argv[], int argc) 8611590Srgrimes{ 86295060Sjmallett int ind; 86395060Sjmallett int n; 8641590Srgrimes 8651590Srgrimes if (argc > 2) { 8661590Srgrimes for (ind = 2; ind < argc; ind++) { 867228063Sbapt const char *errstr; 868228063Sbapt n = strtonum(argv[ind], 1, INT_MAX, &errstr); 869228063Sbapt if (errstr) { 870228063Sbapt if (errno == EINVAL && mimic_gnu) 871228063Sbapt getdivfile(argv[ind]); 872228063Sbapt } else { 873228063Sbapt if (n < maxout && outfile[n] != NULL) 874228063Sbapt getdiv(n); 875228063Sbapt } 8761590Srgrimes } 8771590Srgrimes } 8781590Srgrimes else 87995060Sjmallett for (n = 1; n < maxout; n++) 8801590Srgrimes if (outfile[n] != NULL) 8811590Srgrimes getdiv(n); 8821590Srgrimes} 8831590Srgrimes 8841590Srgrimes/* 8851590Srgrimes * dosub - select substring 8861590Srgrimes */ 88795060Sjmallettstatic void 88895887Sjmallettdosub(const char *argv[], int argc) 8891590Srgrimes{ 89095060Sjmallett const char *ap, *fc, *k; 89195060Sjmallett int nc; 8921590Srgrimes 89376822Sgshapiro ap = argv[2]; /* target string */ 89476822Sgshapiro#ifdef EXPR 89576822Sgshapiro fc = ap + expr(argv[3]); /* first char */ 89676822Sgshapiro#else 89776822Sgshapiro fc = ap + atoi(argv[3]); /* first char */ 89876822Sgshapiro#endif 89995060Sjmallett nc = strlen(fc); 90095060Sjmallett if (argc >= 5) 9011590Srgrimes#ifdef EXPR 90295060Sjmallett nc = min(nc, expr(argv[4])); 9031590Srgrimes#else 90495060Sjmallett nc = min(nc, atoi(argv[4])); 9051590Srgrimes#endif 9061590Srgrimes if (fc >= ap && fc < ap + strlen(ap)) 90776822Sgshapiro for (k = fc + nc - 1; k >= fc; k--) 908228063Sbapt pushback(*k); 9091590Srgrimes} 9101590Srgrimes 9111590Srgrimes/* 9121590Srgrimes * map: 9131590Srgrimes * map every character of s1 that is specified in from 9141590Srgrimes * into s3 and replace in s. (source s1 remains untouched) 9151590Srgrimes * 916228063Sbapt * This is derived from the a standard implementation of map(s,from,to) 917228063Sbapt * function of ICON language. Within mapvec, we replace every character 918228063Sbapt * of "from" with the corresponding character in "to". 919228063Sbapt * If "to" is shorter than "from", than the corresponding entries are null, 920298879Spfg * which means that those characters disappear altogether. 9211590Srgrimes */ 92295060Sjmallettstatic void 92395887Sjmallettmap(char *dest, const char *src, const char *from, const char *to) 9241590Srgrimes{ 92595060Sjmallett const char *tmp; 92695060Sjmallett unsigned char sch, dch; 92795060Sjmallett static char frombis[257]; 92895060Sjmallett static char tobis[257]; 929228063Sbapt int i; 930228063Sbapt char seen[256]; 93195060Sjmallett static unsigned char mapvec[256] = { 93295060Sjmallett 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 93395060Sjmallett 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 93495060Sjmallett 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 93595060Sjmallett 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 93695060Sjmallett 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 93795060Sjmallett 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 93895060Sjmallett 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 93995060Sjmallett 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 94095060Sjmallett 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 94195060Sjmallett 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 94295060Sjmallett 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 94395060Sjmallett 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 94495060Sjmallett 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 94595060Sjmallett 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 94695060Sjmallett 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 94795060Sjmallett 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 94895060Sjmallett 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 94995060Sjmallett 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 9501590Srgrimes }; 9511590Srgrimes 9521590Srgrimes if (*src) { 95395060Sjmallett if (mimic_gnu) { 95495060Sjmallett /* 95595060Sjmallett * expand character ranges on the fly 95695060Sjmallett */ 95795060Sjmallett from = handledash(frombis, frombis + 256, from); 95895060Sjmallett to = handledash(tobis, tobis + 256, to); 95995060Sjmallett } 9601590Srgrimes tmp = from; 9611590Srgrimes /* 9621590Srgrimes * create a mapping between "from" and 9631590Srgrimes * "to" 9641590Srgrimes */ 965228063Sbapt for (i = 0; i < 256; i++) 966228063Sbapt seen[i] = 0; 967228063Sbapt while (*from) { 968228063Sbapt if (!seen[(unsigned char)(*from)]) { 969228063Sbapt mapvec[(unsigned char)(*from)] = (unsigned char)(*to); 970228063Sbapt seen[(unsigned char)(*from)] = 1; 971228063Sbapt } 972228063Sbapt from++; 973228063Sbapt if (*to) 974228063Sbapt to++; 975228063Sbapt } 9761590Srgrimes 9771590Srgrimes while (*src) { 97895060Sjmallett sch = (unsigned char)(*src++); 9791590Srgrimes dch = mapvec[sch]; 98095060Sjmallett if ((*dest = (char)dch)) 9811590Srgrimes dest++; 9821590Srgrimes } 9831590Srgrimes /* 9841590Srgrimes * restore all the changed characters 9851590Srgrimes */ 9861590Srgrimes while (*tmp) { 98795060Sjmallett mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp); 9881590Srgrimes tmp++; 9891590Srgrimes } 9901590Srgrimes } 99195060Sjmallett *dest = '\0'; 9921590Srgrimes} 99395060Sjmallett 99495060Sjmallett 99595060Sjmallett/* 99695060Sjmallett * handledash: 99795060Sjmallett * use buffer to copy the src string, expanding character ranges 99895060Sjmallett * on the way. 99995060Sjmallett */ 100095060Sjmallettstatic const char * 100195887Sjmalletthandledash(char *buffer, char *end, const char *src) 100295060Sjmallett{ 100395060Sjmallett char *p; 1004100014Sjmallett 100595060Sjmallett p = buffer; 100695060Sjmallett while(*src) { 100795060Sjmallett if (src[1] == '-' && src[2]) { 100895060Sjmallett unsigned char i; 1009228063Sbapt if ((unsigned char)src[0] <= (unsigned char)src[2]) { 1010228063Sbapt for (i = (unsigned char)src[0]; 1011228063Sbapt i <= (unsigned char)src[2]; i++) { 1012228063Sbapt *p++ = i; 1013228063Sbapt if (p == end) { 1014228063Sbapt *p = '\0'; 1015228063Sbapt return buffer; 1016228063Sbapt } 101795060Sjmallett } 1018228063Sbapt } else { 1019228063Sbapt for (i = (unsigned char)src[0]; 1020228063Sbapt i >= (unsigned char)src[2]; i--) { 1021228063Sbapt *p++ = i; 1022228063Sbapt if (p == end) { 1023228063Sbapt *p = '\0'; 1024228063Sbapt return buffer; 1025228063Sbapt } 1026228063Sbapt } 102795060Sjmallett } 102895060Sjmallett src += 3; 102995060Sjmallett } else 103095060Sjmallett *p++ = *src++; 103195060Sjmallett if (p == end) 103295060Sjmallett break; 103395060Sjmallett } 103495060Sjmallett *p = '\0'; 103595060Sjmallett return buffer; 103695060Sjmallett} 1037