1291128Sbapt/* $OpenBSD: eval.c,v 1.74 2015/02/05 12:59:57 millert Exp $ */ 295060Sjmallett/* $NetBSD: eval.c,v 1.7 1996/11/10 21:21:29 pk Exp $ */ 395060Sjmallett 41590Srgrimes/* 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: releng/11.0/usr.bin/m4/eval.c 298879 2016-05-01 16:13:05Z pfg $"); 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; 12795060Sjmallett int ac; 1281590Srgrimes static int sysval = 0; 1291590Srgrimes 1301590Srgrimes#ifdef DEBUG 1311590Srgrimes printf("argc = %d\n", argc); 1321590Srgrimes for (n = 0; n < argc; n++) 1331590Srgrimes printf("argv[%d] = %s\n", n, argv[n]); 13495060Sjmallett fflush(stdout); 1351590Srgrimes#endif 13695060Sjmallett 1371590Srgrimes /* 1381590Srgrimes * if argc == 3 and argv[2] is null, then we 1391590Srgrimes * have macro-or-builtin() type call. We adjust 1401590Srgrimes * argc to avoid further checking.. 1411590Srgrimes */ 142228063Sbapt /* we keep the initial value for those built-ins that differentiate 143228063Sbapt * between builtin() and builtin. 144228063Sbapt */ 145228063Sbapt ac = argc; 14695060Sjmallett 147228063Sbapt if (argc == 3 && !*(argv[2]) && !mimic_gnu) 1481590Srgrimes argc--; 1491590Srgrimes 15095060Sjmallett switch (td & TYPEMASK) { 1511590Srgrimes 1521590Srgrimes case DEFITYPE: 1531590Srgrimes if (argc > 2) 1541590Srgrimes dodefine(argv[2], (argc > 3) ? argv[3] : null); 1551590Srgrimes break; 1561590Srgrimes 1571590Srgrimes case PUSDTYPE: 1581590Srgrimes if (argc > 2) 1591590Srgrimes dopushdef(argv[2], (argc > 3) ? argv[3] : null); 1601590Srgrimes break; 1611590Srgrimes 1621590Srgrimes case DUMPTYPE: 1631590Srgrimes dodump(argv, argc); 1641590Srgrimes break; 1651590Srgrimes 16695060Sjmallett case TRACEONTYPE: 16795060Sjmallett dotrace(argv, argc, 1); 16895060Sjmallett break; 16995060Sjmallett 17095060Sjmallett case TRACEOFFTYPE: 17195060Sjmallett dotrace(argv, argc, 0); 17295060Sjmallett break; 17395060Sjmallett 1741590Srgrimes case EXPRTYPE: 1751590Srgrimes /* 1761590Srgrimes * doexpr - evaluate arithmetic 1771590Srgrimes * expression 1781590Srgrimes */ 179228063Sbapt { 180228063Sbapt int base = 10; 181228063Sbapt int maxdigits = 0; 182228063Sbapt const char *errstr; 183228063Sbapt 184228063Sbapt if (argc > 3) { 185228063Sbapt base = strtonum(argv[3], 2, 36, &errstr); 186228063Sbapt if (errstr) { 187228063Sbapt m4errx(1, "expr: base %s invalid.", argv[3]); 188228063Sbapt } 189228063Sbapt } 190228063Sbapt if (argc > 4) { 191228063Sbapt maxdigits = strtonum(argv[4], 0, INT_MAX, &errstr); 192228063Sbapt if (errstr) { 193228063Sbapt m4errx(1, "expr: maxdigits %s invalid.", argv[4]); 194228063Sbapt } 195228063Sbapt } 1961590Srgrimes if (argc > 2) 197228063Sbapt pbnumbase(expr(argv[2]), base, maxdigits); 1981590Srgrimes break; 199228063Sbapt } 2001590Srgrimes 2011590Srgrimes case IFELTYPE: 2021590Srgrimes if (argc > 4) 2031590Srgrimes doifelse(argv, argc); 2041590Srgrimes break; 2051590Srgrimes 2061590Srgrimes case IFDFTYPE: 2071590Srgrimes /* 2081590Srgrimes * doifdef - select one of two 2091590Srgrimes * alternatives based on the existence of 2101590Srgrimes * another definition 2111590Srgrimes */ 2121590Srgrimes if (argc > 3) { 213228063Sbapt if (lookup_macro_definition(argv[2]) != NULL) 2141590Srgrimes pbstr(argv[3]); 2151590Srgrimes else if (argc > 4) 2161590Srgrimes pbstr(argv[4]); 2171590Srgrimes } 2181590Srgrimes break; 2191590Srgrimes 2201590Srgrimes case LENGTYPE: 2211590Srgrimes /* 2221590Srgrimes * dolen - find the length of the 2231590Srgrimes * argument 2241590Srgrimes */ 22577378Sgshapiro pbnum((argc > 2) ? strlen(argv[2]) : 0); 2261590Srgrimes break; 2271590Srgrimes 2281590Srgrimes case INCRTYPE: 2291590Srgrimes /* 2301590Srgrimes * doincr - increment the value of the 2311590Srgrimes * argument 2321590Srgrimes */ 2331590Srgrimes if (argc > 2) 2341590Srgrimes pbnum(atoi(argv[2]) + 1); 2351590Srgrimes break; 2361590Srgrimes 2371590Srgrimes case DECRTYPE: 2381590Srgrimes /* 2391590Srgrimes * dodecr - decrement the value of the 2401590Srgrimes * argument 2411590Srgrimes */ 2421590Srgrimes if (argc > 2) 2431590Srgrimes pbnum(atoi(argv[2]) - 1); 2441590Srgrimes break; 2451590Srgrimes 2461590Srgrimes case SYSCTYPE: 2471590Srgrimes /* 2481590Srgrimes * dosys - execute system command 2498874Srgrimes */ 250114368Stjr if (argc > 2) { 251228063Sbapt fflush(stdout); 2521590Srgrimes sysval = system(argv[2]); 253114368Stjr } 2541590Srgrimes break; 2551590Srgrimes 2561590Srgrimes case SYSVTYPE: 2571590Srgrimes /* 2581590Srgrimes * dosysval - return value of the last 2591590Srgrimes * system call. 260100014Sjmallett * 2611590Srgrimes */ 2621590Srgrimes pbnum(sysval); 2631590Srgrimes break; 2641590Srgrimes 26595060Sjmallett case ESYSCMDTYPE: 26695060Sjmallett if (argc > 2) 26795060Sjmallett doesyscmd(argv[2]); 268228063Sbapt break; 2691590Srgrimes case INCLTYPE: 270269162Sbapt if (argc > 2) { 271228701Sbz if (!doincl(argv[2])) { 272234310Sbapt if (mimic_gnu) { 273228697Sbapt warn("%s at line %lu: include(%s)", 274228697Sbapt CURRENT_NAME, CURRENT_LINE, argv[2]); 275234310Sbapt exit_code = 1; 276234310Sbapt } else 277228697Sbapt err(1, "%s at line %lu: include(%s)", 278228697Sbapt CURRENT_NAME, CURRENT_LINE, argv[2]); 279228701Sbz } 280269162Sbapt } 2811590Srgrimes break; 2821590Srgrimes 2831590Srgrimes case SINCTYPE: 2841590Srgrimes if (argc > 2) 2851590Srgrimes (void) doincl(argv[2]); 2861590Srgrimes break; 2871590Srgrimes#ifdef EXTENDED 2881590Srgrimes case PASTTYPE: 2891590Srgrimes if (argc > 2) 2901590Srgrimes if (!dopaste(argv[2])) 291228063Sbapt err(1, "%s at line %lu: paste(%s)", 29295060Sjmallett CURRENT_NAME, CURRENT_LINE, argv[2]); 2931590Srgrimes break; 2941590Srgrimes 2951590Srgrimes case SPASTYPE: 2961590Srgrimes if (argc > 2) 2971590Srgrimes (void) dopaste(argv[2]); 2981590Srgrimes break; 299228063Sbapt case FORMATTYPE: 300228063Sbapt doformat(argv, argc); 301228063Sbapt break; 3021590Srgrimes#endif 3031590Srgrimes case CHNQTYPE: 304228063Sbapt dochq(argv, ac); 3051590Srgrimes break; 3061590Srgrimes 3071590Srgrimes case CHNCTYPE: 308228063Sbapt dochc(argv, argc); 3091590Srgrimes break; 3101590Srgrimes 3111590Srgrimes case SUBSTYPE: 3121590Srgrimes /* 3131590Srgrimes * dosub - select substring 314100014Sjmallett * 3151590Srgrimes */ 3161590Srgrimes if (argc > 3) 3171590Srgrimes dosub(argv, argc); 3181590Srgrimes break; 3191590Srgrimes 3201590Srgrimes case SHIFTYPE: 3211590Srgrimes /* 3221590Srgrimes * doshift - push back all arguments 3231590Srgrimes * except the first one (i.e. skip 3241590Srgrimes * argv[2]) 3251590Srgrimes */ 3261590Srgrimes if (argc > 3) { 3271590Srgrimes for (n = argc - 1; n > 3; n--) { 32895060Sjmallett pbstr(rquote); 3291590Srgrimes pbstr(argv[n]); 33095060Sjmallett pbstr(lquote); 331228063Sbapt pushback(COMMA); 3321590Srgrimes } 33395060Sjmallett pbstr(rquote); 3341590Srgrimes pbstr(argv[3]); 33595060Sjmallett pbstr(lquote); 3361590Srgrimes } 3371590Srgrimes break; 3381590Srgrimes 3391590Srgrimes case DIVRTYPE: 3401590Srgrimes if (argc > 2 && (n = atoi(argv[2])) != 0) 3411590Srgrimes dodiv(n); 3421590Srgrimes else { 3431590Srgrimes active = stdout; 3441590Srgrimes oindex = 0; 3451590Srgrimes } 3461590Srgrimes break; 3471590Srgrimes 3481590Srgrimes case UNDVTYPE: 3491590Srgrimes doundiv(argv, argc); 3501590Srgrimes break; 3511590Srgrimes 3521590Srgrimes case DIVNTYPE: 3531590Srgrimes /* 3541590Srgrimes * dodivnum - return the number of 3551590Srgrimes * current output diversion 3561590Srgrimes */ 3571590Srgrimes pbnum(oindex); 3581590Srgrimes break; 3591590Srgrimes 3601590Srgrimes case UNDFTYPE: 3611590Srgrimes /* 3621590Srgrimes * doundefine - undefine a previously 3631590Srgrimes * defined macro(s) or m4 keyword(s). 3641590Srgrimes */ 3651590Srgrimes if (argc > 2) 3661590Srgrimes for (n = 2; n < argc; n++) 367228063Sbapt macro_undefine(argv[n]); 3681590Srgrimes break; 3691590Srgrimes 3701590Srgrimes case POPDTYPE: 3711590Srgrimes /* 3721590Srgrimes * dopopdef - remove the topmost 3731590Srgrimes * definitions of macro(s) or m4 3741590Srgrimes * keyword(s). 3751590Srgrimes */ 3761590Srgrimes if (argc > 2) 3771590Srgrimes for (n = 2; n < argc; n++) 378228063Sbapt macro_popdef(argv[n]); 3791590Srgrimes break; 3801590Srgrimes 3811590Srgrimes case MKTMTYPE: 3821590Srgrimes /* 3831590Srgrimes * dotemp - create a temporary file 3841590Srgrimes */ 38595060Sjmallett if (argc > 2) { 38695060Sjmallett int fd; 38795060Sjmallett char *temp; 38895060Sjmallett 38995060Sjmallett temp = xstrdup(argv[2]); 390100014Sjmallett 39195060Sjmallett fd = mkstemp(temp); 39295060Sjmallett if (fd == -1) 393100014Sjmallett err(1, 394100014Sjmallett "%s at line %lu: couldn't make temp file %s", 39595060Sjmallett CURRENT_NAME, CURRENT_LINE, argv[2]); 39695060Sjmallett close(fd); 39795060Sjmallett pbstr(temp); 39895060Sjmallett free(temp); 39995060Sjmallett } 4001590Srgrimes break; 4011590Srgrimes 4021590Srgrimes case TRNLTYPE: 4031590Srgrimes /* 4041590Srgrimes * dotranslit - replace all characters in 4051590Srgrimes * the source string that appears in the 4061590Srgrimes * "from" string with the corresponding 4071590Srgrimes * characters in the "to" string. 4081590Srgrimes */ 4091590Srgrimes if (argc > 3) { 41095060Sjmallett char *temp; 41195060Sjmallett 412228063Sbapt temp = xalloc(strlen(argv[2])+1, NULL); 4131590Srgrimes if (argc > 4) 4141590Srgrimes map(temp, argv[2], argv[3], argv[4]); 4151590Srgrimes else 4161590Srgrimes map(temp, argv[2], argv[3], null); 4171590Srgrimes pbstr(temp); 41895060Sjmallett free(temp); 41995060Sjmallett } else if (argc > 2) 4201590Srgrimes pbstr(argv[2]); 4211590Srgrimes break; 4221590Srgrimes 4231590Srgrimes case INDXTYPE: 4241590Srgrimes /* 4251590Srgrimes * doindex - find the index of the second 4261590Srgrimes * argument string in the first argument 4271590Srgrimes * string. -1 if not present. 4281590Srgrimes */ 4291590Srgrimes pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1); 4301590Srgrimes break; 4311590Srgrimes 4321590Srgrimes case ERRPTYPE: 4331590Srgrimes /* 4341590Srgrimes * doerrp - print the arguments to stderr 4351590Srgrimes * file 4361590Srgrimes */ 4371590Srgrimes if (argc > 2) { 4381590Srgrimes for (n = 2; n < argc; n++) 4391590Srgrimes fprintf(stderr, "%s ", argv[n]); 4401590Srgrimes fprintf(stderr, "\n"); 4411590Srgrimes } 4421590Srgrimes break; 4431590Srgrimes 4441590Srgrimes case DNLNTYPE: 4451590Srgrimes /* 4461590Srgrimes * dodnl - eat-up-to and including 4471590Srgrimes * newline 4481590Srgrimes */ 4491590Srgrimes while ((c = gpbc()) != '\n' && c != EOF) 4501590Srgrimes ; 4511590Srgrimes break; 4521590Srgrimes 4531590Srgrimes case M4WRTYPE: 4541590Srgrimes /* 4551590Srgrimes * dom4wrap - set up for 4561590Srgrimes * wrap-up/wind-down activity 4571590Srgrimes */ 458228063Sbapt if (argc > 2) 459228063Sbapt dom4wrap(argv[2]); 4601590Srgrimes break; 4611590Srgrimes 4621590Srgrimes case EXITTYPE: 4631590Srgrimes /* 4641590Srgrimes * doexit - immediate exit from m4. 4651590Srgrimes */ 4667896Sache killdiv(); 4671590Srgrimes exit((argc > 2) ? atoi(argv[2]) : 0); 4681590Srgrimes break; 4691590Srgrimes 4701590Srgrimes case DEFNTYPE: 4711590Srgrimes if (argc > 2) 4721590Srgrimes for (n = 2; n < argc; n++) 4731590Srgrimes dodefn(argv[n]); 4741590Srgrimes break; 4751590Srgrimes 47695060Sjmallett case INDIRTYPE: /* Indirect call */ 47795060Sjmallett if (argc > 2) 47895060Sjmallett doindir(argv, argc); 47938926Ssteve break; 480100014Sjmallett 48195060Sjmallett case BUILTINTYPE: /* Builtins only */ 48295060Sjmallett if (argc > 2) 48395060Sjmallett dobuiltin(argv, argc); 48495060Sjmallett break; 48538926Ssteve 48695060Sjmallett case PATSTYPE: 48795060Sjmallett if (argc > 2) 48895060Sjmallett dopatsubst(argv, argc); 48995060Sjmallett break; 49095060Sjmallett case REGEXPTYPE: 49195060Sjmallett if (argc > 2) 49295060Sjmallett doregexp(argv, argc); 49395060Sjmallett break; 49495060Sjmallett case LINETYPE: 49595060Sjmallett doprintlineno(infile+ilevel); 49695060Sjmallett break; 49795060Sjmallett case FILENAMETYPE: 49895060Sjmallett doprintfilename(infile+ilevel); 49995060Sjmallett break; 50095060Sjmallett case SELFTYPE: 50195060Sjmallett pbstr(rquote); 50295060Sjmallett pbstr(argv[1]); 50395060Sjmallett pbstr(lquote); 50495060Sjmallett break; 5051590Srgrimes default: 506228063Sbapt m4errx(1, "eval: major botch."); 5071590Srgrimes break; 5081590Srgrimes } 5091590Srgrimes} 5101590Srgrimes 5111590Srgrimes/* 51295060Sjmallett * expand_macro - user-defined macro expansion 5131590Srgrimes */ 5141590Srgrimesvoid 51595887Sjmallettexpand_macro(const char *argv[], int argc) 5161590Srgrimes{ 51795060Sjmallett const char *t; 51895060Sjmallett const char *p; 51995060Sjmallett int n; 52095060Sjmallett int argno; 5211590Srgrimes 5221590Srgrimes t = argv[0]; /* defn string as a whole */ 5231590Srgrimes p = t; 5241590Srgrimes while (*p) 5251590Srgrimes p++; 5261590Srgrimes p--; /* last character of defn */ 5271590Srgrimes while (p > t) { 5281590Srgrimes if (*(p - 1) != ARGFLAG) 529228063Sbapt PUSHBACK(*p); 5301590Srgrimes else { 5311590Srgrimes switch (*p) { 5321590Srgrimes 5331590Srgrimes case '#': 5341590Srgrimes pbnum(argc - 2); 5351590Srgrimes break; 5361590Srgrimes case '0': 5371590Srgrimes case '1': 5381590Srgrimes case '2': 5391590Srgrimes case '3': 5401590Srgrimes case '4': 5411590Srgrimes case '5': 5421590Srgrimes case '6': 5431590Srgrimes case '7': 5441590Srgrimes case '8': 5451590Srgrimes case '9': 5461590Srgrimes if ((argno = *p - '0') < argc - 1) 5471590Srgrimes pbstr(argv[argno + 1]); 5481590Srgrimes break; 5491590Srgrimes case '*': 55095060Sjmallett if (argc > 2) { 55195060Sjmallett for (n = argc - 1; n > 2; n--) { 55295060Sjmallett pbstr(argv[n]); 553228063Sbapt pushback(COMMA); 55495060Sjmallett } 55595060Sjmallett pbstr(argv[2]); 556228063Sbapt } 5571590Srgrimes break; 55895060Sjmallett case '@': 55995060Sjmallett if (argc > 2) { 56095060Sjmallett for (n = argc - 1; n > 2; n--) { 56195060Sjmallett pbstr(rquote); 56295060Sjmallett pbstr(argv[n]); 56395060Sjmallett pbstr(lquote); 564228063Sbapt pushback(COMMA); 56595060Sjmallett } 56695060Sjmallett pbstr(rquote); 56795060Sjmallett pbstr(argv[2]); 56895060Sjmallett pbstr(lquote); 56924901Sjoerg } 57095060Sjmallett break; 5711590Srgrimes default: 572228063Sbapt PUSHBACK(*p); 573228063Sbapt PUSHBACK('$'); 5741590Srgrimes break; 5751590Srgrimes } 5761590Srgrimes p--; 5771590Srgrimes } 5781590Srgrimes p--; 5791590Srgrimes } 5801590Srgrimes if (p == t) /* do last character */ 581228063Sbapt PUSHBACK(*p); 5821590Srgrimes} 5831590Srgrimes 584228063Sbapt 5851590Srgrimes/* 5861590Srgrimes * dodefine - install definition in the table 5871590Srgrimes */ 5881590Srgrimesvoid 58995887Sjmallettdodefine(const char *name, const char *defn) 5901590Srgrimes{ 591228063Sbapt if (!*name && !mimic_gnu) 592228063Sbapt m4errx(1, "null definition."); 5931590Srgrimes else 594228063Sbapt macro_define(name, defn); 5951590Srgrimes} 5961590Srgrimes 5971590Srgrimes/* 5981590Srgrimes * dodefn - push back a quoted definition of 5991590Srgrimes * the given name. 6001590Srgrimes */ 60195060Sjmallettstatic void 60295887Sjmallettdodefn(const char *name) 6031590Srgrimes{ 604228063Sbapt struct macro_definition *p; 6051590Srgrimes 606228063Sbapt if ((p = lookup_macro_definition(name)) != NULL) { 607228063Sbapt if ((p->type & TYPEMASK) == MACRTYPE) { 60895060Sjmallett pbstr(rquote); 60995060Sjmallett pbstr(p->defn); 61095060Sjmallett pbstr(lquote); 611228063Sbapt } else { 612228063Sbapt pbstr(p->defn); 61395060Sjmallett pbstr(BUILTIN_MARKER); 61495060Sjmallett } 6151590Srgrimes } 6161590Srgrimes} 6171590Srgrimes 6181590Srgrimes/* 6191590Srgrimes * dopushdef - install a definition in the hash table 6201590Srgrimes * without removing a previous definition. Since 6211590Srgrimes * each new entry is entered in *front* of the 6221590Srgrimes * hash bucket, it hides a previous definition from 6231590Srgrimes * lookup. 6241590Srgrimes */ 62595060Sjmallettstatic void 62695887Sjmallettdopushdef(const char *name, const char *defn) 6271590Srgrimes{ 628228063Sbapt if (!*name && !mimic_gnu) 629228063Sbapt m4errx(1, "null definition."); 6301590Srgrimes else 631228063Sbapt macro_pushdef(name, defn); 6321590Srgrimes} 6331590Srgrimes 6341590Srgrimes/* 63595060Sjmallett * dump_one_def - dump the specified definition. 63695060Sjmallett */ 63795060Sjmallettstatic void 638228063Sbaptdump_one_def(const char *name, struct macro_definition *p) 63995060Sjmallett{ 640228063Sbapt if (!traceout) 641228063Sbapt traceout = stderr; 64295060Sjmallett if (mimic_gnu) { 64395060Sjmallett if ((p->type & TYPEMASK) == MACRTYPE) 644228063Sbapt fprintf(traceout, "%s:\t%s\n", name, p->defn); 64595060Sjmallett else { 646228063Sbapt fprintf(traceout, "%s:\t<%s>\n", name, p->defn); 647228063Sbapt } 64895060Sjmallett } else 649228063Sbapt fprintf(traceout, "`%s'\t`%s'\n", name, p->defn); 65095060Sjmallett} 65195060Sjmallett 65295060Sjmallett/* 6531590Srgrimes * dodumpdef - dump the specified definitions in the hash 6541590Srgrimes * table to stderr. If nothing is specified, the entire 6551590Srgrimes * hash table is dumped. 6561590Srgrimes */ 65795060Sjmallettstatic void 65895887Sjmallettdodump(const char *argv[], int argc) 6591590Srgrimes{ 66095060Sjmallett int n; 661228063Sbapt struct macro_definition *p; 6621590Srgrimes 6631590Srgrimes if (argc > 2) { 6641590Srgrimes for (n = 2; n < argc; n++) 665228063Sbapt if ((p = lookup_macro_definition(argv[n])) != NULL) 666228063Sbapt dump_one_def(argv[n], p); 667228063Sbapt } else 668228063Sbapt macro_for_all(dump_one_def); 6691590Srgrimes} 6701590Srgrimes 6711590Srgrimes/* 67295060Sjmallett * dotrace - mark some macros as traced/untraced depending upon on. 67395060Sjmallett */ 67495060Sjmallettstatic void 67595887Sjmallettdotrace(const char *argv[], int argc, int on) 67695060Sjmallett{ 67795060Sjmallett int n; 67895060Sjmallett 67995060Sjmallett if (argc > 2) { 68095060Sjmallett for (n = 2; n < argc; n++) 68195060Sjmallett mark_traced(argv[n], on); 68295060Sjmallett } else 68395060Sjmallett mark_traced(NULL, on); 68495060Sjmallett} 68595060Sjmallett 68695060Sjmallett/* 6871590Srgrimes * doifelse - select one of two alternatives - loop. 6881590Srgrimes */ 68995060Sjmallettstatic void 69095887Sjmallettdoifelse(const char *argv[], int argc) 6911590Srgrimes{ 6921590Srgrimes cycle { 6931590Srgrimes if (STREQ(argv[2], argv[3])) 6941590Srgrimes pbstr(argv[4]); 6951590Srgrimes else if (argc == 6) 6961590Srgrimes pbstr(argv[5]); 6971590Srgrimes else if (argc > 6) { 6981590Srgrimes argv += 3; 6991590Srgrimes argc -= 3; 7001590Srgrimes continue; 7011590Srgrimes } 7021590Srgrimes break; 7031590Srgrimes } 7041590Srgrimes} 7051590Srgrimes 7061590Srgrimes/* 7071590Srgrimes * doinclude - include a given file. 7081590Srgrimes */ 70995060Sjmallettstatic int 71095887Sjmallettdoincl(const char *ifile) 7111590Srgrimes{ 7121590Srgrimes if (ilevel + 1 == MAXINP) 713228063Sbapt m4errx(1, "too many include files."); 71495060Sjmallett if (fopen_trypath(infile+ilevel+1, ifile) != NULL) { 7151590Srgrimes ilevel++; 7161590Srgrimes bbase[ilevel] = bufbase = bp; 7171590Srgrimes return (1); 71895060Sjmallett } else 7191590Srgrimes return (0); 7201590Srgrimes} 7211590Srgrimes 7221590Srgrimes#ifdef EXTENDED 7231590Srgrimes/* 7241590Srgrimes * dopaste - include a given file without any 7251590Srgrimes * macro processing. 7261590Srgrimes */ 72795060Sjmallettstatic int 72895887Sjmallettdopaste(const char *pfile) 7291590Srgrimes{ 7301590Srgrimes FILE *pf; 73195060Sjmallett int c; 7321590Srgrimes 7331590Srgrimes if ((pf = fopen(pfile, "r")) != NULL) { 734228063Sbapt if (synch_lines) 735228063Sbapt fprintf(active, "#line 1 \"%s\"\n", pfile); 7361590Srgrimes while ((c = getc(pf)) != EOF) 7371590Srgrimes putc(c, active); 7381590Srgrimes (void) fclose(pf); 739228063Sbapt emit_synchline(); 7401590Srgrimes return (1); 74195060Sjmallett } else 7421590Srgrimes return (0); 7431590Srgrimes} 7441590Srgrimes#endif 7451590Srgrimes 746228063Sbapt/* 747228063Sbapt * dochq - change quote characters 748228063Sbapt */ 74995060Sjmallettstatic void 750228063Sbaptdochq(const char *argv[], int ac) 75195060Sjmallett{ 75295060Sjmallett if (ac == 2) { 753228063Sbapt lquote[0] = LQUOTE; lquote[1] = EOS; 754228063Sbapt rquote[0] = RQUOTE; rquote[1] = EOS; 75595060Sjmallett } else { 75695060Sjmallett strlcpy(lquote, argv[2], sizeof(lquote)); 757228063Sbapt if (ac > 3) { 75895060Sjmallett strlcpy(rquote, argv[3], sizeof(rquote)); 759228063Sbapt } else { 760228063Sbapt rquote[0] = ECOMMT; rquote[1] = EOS; 761228063Sbapt } 76295060Sjmallett } 76395060Sjmallett} 76495060Sjmallett 7651590Srgrimes/* 766228063Sbapt * dochc - change comment characters 7671590Srgrimes */ 76895060Sjmallettstatic void 769228063Sbaptdochc(const char *argv[], int argc) 7701590Srgrimes{ 771228063Sbapt/* XXX Note that there is no difference between no argument and a single 772228063Sbapt * empty argument. 773228063Sbapt */ 774228063Sbapt if (argc == 2) { 77595060Sjmallett scommt[0] = EOS; 77695060Sjmallett ecommt[0] = EOS; 77795060Sjmallett } else { 778228063Sbapt strlcpy(scommt, argv[2], sizeof(scommt)); 779228063Sbapt if (argc == 3) { 780228063Sbapt ecommt[0] = ECOMMT; ecommt[1] = EOS; 781228063Sbapt } else { 78295060Sjmallett strlcpy(ecommt, argv[3], sizeof(ecommt)); 783228063Sbapt } 7841590Srgrimes } 7851590Srgrimes} 786228063Sbapt 7871590Srgrimes/* 788228063Sbapt * dom4wrap - expand text at EOF 7891590Srgrimes */ 79095060Sjmallettstatic void 791228063Sbaptdom4wrap(const char *text) 7921590Srgrimes{ 793228063Sbapt if (wrapindex >= maxwraps) { 794228063Sbapt if (maxwraps == 0) 795228063Sbapt maxwraps = 16; 7961590Srgrimes else 797228063Sbapt maxwraps *= 2; 798269162Sbapt m4wraps = xreallocarray(m4wraps, maxwraps, sizeof(*m4wraps), 799228063Sbapt "too many m4wraps"); 8001590Srgrimes } 801228063Sbapt m4wraps[wrapindex++] = xstrdup(text); 8021590Srgrimes} 8031590Srgrimes 8041590Srgrimes/* 8051590Srgrimes * dodivert - divert the output to a temporary file 8061590Srgrimes */ 80795060Sjmallettstatic void 80895887Sjmallettdodiv(int n) 8091590Srgrimes{ 81095060Sjmallett int fd; 81195060Sjmallett 81228386Sjlemon oindex = n; 81395060Sjmallett if (n >= maxout) { 81495060Sjmallett if (mimic_gnu) 81595060Sjmallett resizedivs(n + 10); 81695060Sjmallett else 81795060Sjmallett n = 0; /* bitbucket */ 818228063Sbapt } 81995060Sjmallett 82095060Sjmallett if (n < 0) 8211590Srgrimes n = 0; /* bitbucket */ 8221590Srgrimes if (outfile[n] == NULL) { 82395060Sjmallett char fname[] = _PATH_DIVNAME; 82495060Sjmallett 825269162Sbapt if ((fd = mkstemp(fname)) < 0 || 826269162Sbapt unlink(fname) == -1 || 827269162Sbapt (outfile[n] = fdopen(fd, "w+")) == NULL) 828269162Sbapt err(1, "%s: cannot divert", fname); 8291590Srgrimes } 8301590Srgrimes active = outfile[n]; 8311590Srgrimes} 8321590Srgrimes 8331590Srgrimes/* 8341590Srgrimes * doundivert - undivert a specified output, or all 8351590Srgrimes * other outputs, in numerical order. 8361590Srgrimes */ 83795060Sjmallettstatic void 83895887Sjmallettdoundiv(const char *argv[], int argc) 8391590Srgrimes{ 84095060Sjmallett int ind; 84195060Sjmallett int n; 8421590Srgrimes 8431590Srgrimes if (argc > 2) { 8441590Srgrimes for (ind = 2; ind < argc; ind++) { 845228063Sbapt const char *errstr; 846228063Sbapt n = strtonum(argv[ind], 1, INT_MAX, &errstr); 847228063Sbapt if (errstr) { 848228063Sbapt if (errno == EINVAL && mimic_gnu) 849228063Sbapt getdivfile(argv[ind]); 850228063Sbapt } else { 851228063Sbapt if (n < maxout && outfile[n] != NULL) 852228063Sbapt getdiv(n); 853228063Sbapt } 8541590Srgrimes } 8551590Srgrimes } 8561590Srgrimes else 85795060Sjmallett for (n = 1; n < maxout; n++) 8581590Srgrimes if (outfile[n] != NULL) 8591590Srgrimes getdiv(n); 8601590Srgrimes} 8611590Srgrimes 8621590Srgrimes/* 8631590Srgrimes * dosub - select substring 8641590Srgrimes */ 86595060Sjmallettstatic void 86695887Sjmallettdosub(const char *argv[], int argc) 8671590Srgrimes{ 86895060Sjmallett const char *ap, *fc, *k; 86995060Sjmallett int nc; 8701590Srgrimes 87176822Sgshapiro ap = argv[2]; /* target string */ 87276822Sgshapiro#ifdef EXPR 87376822Sgshapiro fc = ap + expr(argv[3]); /* first char */ 87476822Sgshapiro#else 87576822Sgshapiro fc = ap + atoi(argv[3]); /* first char */ 87676822Sgshapiro#endif 87795060Sjmallett nc = strlen(fc); 87895060Sjmallett if (argc >= 5) 8791590Srgrimes#ifdef EXPR 88095060Sjmallett nc = min(nc, expr(argv[4])); 8811590Srgrimes#else 88295060Sjmallett nc = min(nc, atoi(argv[4])); 8831590Srgrimes#endif 8841590Srgrimes if (fc >= ap && fc < ap + strlen(ap)) 88576822Sgshapiro for (k = fc + nc - 1; k >= fc; k--) 886228063Sbapt pushback(*k); 8871590Srgrimes} 8881590Srgrimes 8891590Srgrimes/* 8901590Srgrimes * map: 8911590Srgrimes * map every character of s1 that is specified in from 8921590Srgrimes * into s3 and replace in s. (source s1 remains untouched) 8931590Srgrimes * 894228063Sbapt * This is derived from the a standard implementation of map(s,from,to) 895228063Sbapt * function of ICON language. Within mapvec, we replace every character 896228063Sbapt * of "from" with the corresponding character in "to". 897228063Sbapt * If "to" is shorter than "from", than the corresponding entries are null, 898298879Spfg * which means that those characters disappear altogether. 8991590Srgrimes */ 90095060Sjmallettstatic void 90195887Sjmallettmap(char *dest, const char *src, const char *from, const char *to) 9021590Srgrimes{ 90395060Sjmallett const char *tmp; 90495060Sjmallett unsigned char sch, dch; 90595060Sjmallett static char frombis[257]; 90695060Sjmallett static char tobis[257]; 907228063Sbapt int i; 908228063Sbapt char seen[256]; 90995060Sjmallett static unsigned char mapvec[256] = { 91095060Sjmallett 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 91195060Sjmallett 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 91295060Sjmallett 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 91395060Sjmallett 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 91495060Sjmallett 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 91595060Sjmallett 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 91695060Sjmallett 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 91795060Sjmallett 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 91895060Sjmallett 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 91995060Sjmallett 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 92095060Sjmallett 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 92195060Sjmallett 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 92295060Sjmallett 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 92395060Sjmallett 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 92495060Sjmallett 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 92595060Sjmallett 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 92695060Sjmallett 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 92795060Sjmallett 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 9281590Srgrimes }; 9291590Srgrimes 9301590Srgrimes if (*src) { 93195060Sjmallett if (mimic_gnu) { 93295060Sjmallett /* 93395060Sjmallett * expand character ranges on the fly 93495060Sjmallett */ 93595060Sjmallett from = handledash(frombis, frombis + 256, from); 93695060Sjmallett to = handledash(tobis, tobis + 256, to); 93795060Sjmallett } 9381590Srgrimes tmp = from; 9391590Srgrimes /* 9401590Srgrimes * create a mapping between "from" and 9411590Srgrimes * "to" 9421590Srgrimes */ 943228063Sbapt for (i = 0; i < 256; i++) 944228063Sbapt seen[i] = 0; 945228063Sbapt while (*from) { 946228063Sbapt if (!seen[(unsigned char)(*from)]) { 947228063Sbapt mapvec[(unsigned char)(*from)] = (unsigned char)(*to); 948228063Sbapt seen[(unsigned char)(*from)] = 1; 949228063Sbapt } 950228063Sbapt from++; 951228063Sbapt if (*to) 952228063Sbapt to++; 953228063Sbapt } 9541590Srgrimes 9551590Srgrimes while (*src) { 95695060Sjmallett sch = (unsigned char)(*src++); 9571590Srgrimes dch = mapvec[sch]; 95895060Sjmallett if ((*dest = (char)dch)) 9591590Srgrimes dest++; 9601590Srgrimes } 9611590Srgrimes /* 9621590Srgrimes * restore all the changed characters 9631590Srgrimes */ 9641590Srgrimes while (*tmp) { 96595060Sjmallett mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp); 9661590Srgrimes tmp++; 9671590Srgrimes } 9681590Srgrimes } 96995060Sjmallett *dest = '\0'; 9701590Srgrimes} 97195060Sjmallett 97295060Sjmallett 97395060Sjmallett/* 97495060Sjmallett * handledash: 97595060Sjmallett * use buffer to copy the src string, expanding character ranges 97695060Sjmallett * on the way. 97795060Sjmallett */ 97895060Sjmallettstatic const char * 97995887Sjmalletthandledash(char *buffer, char *end, const char *src) 98095060Sjmallett{ 98195060Sjmallett char *p; 982100014Sjmallett 98395060Sjmallett p = buffer; 98495060Sjmallett while(*src) { 98595060Sjmallett if (src[1] == '-' && src[2]) { 98695060Sjmallett unsigned char i; 987228063Sbapt if ((unsigned char)src[0] <= (unsigned char)src[2]) { 988228063Sbapt for (i = (unsigned char)src[0]; 989228063Sbapt i <= (unsigned char)src[2]; i++) { 990228063Sbapt *p++ = i; 991228063Sbapt if (p == end) { 992228063Sbapt *p = '\0'; 993228063Sbapt return buffer; 994228063Sbapt } 99595060Sjmallett } 996228063Sbapt } else { 997228063Sbapt for (i = (unsigned char)src[0]; 998228063Sbapt i >= (unsigned char)src[2]; i--) { 999228063Sbapt *p++ = i; 1000228063Sbapt if (p == end) { 1001228063Sbapt *p = '\0'; 1002228063Sbapt return buffer; 1003228063Sbapt } 1004228063Sbapt } 100595060Sjmallett } 100695060Sjmallett src += 3; 100795060Sjmallett } else 100895060Sjmallett *p++ = *src++; 100995060Sjmallett if (p == end) 101095060Sjmallett break; 101195060Sjmallett } 101295060Sjmallett *p = '\0'; 101395060Sjmallett return buffer; 101495060Sjmallett} 1015