eval.c revision 228701
1228063Sbapt/* $OpenBSD: eval.c,v 1.69 2011/03/24 11:23:08 espie 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: head/usr.bin/m4/eval.c 228701 2011-12-19 08:50:17Z bz $"); 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> 51228063Sbapt#include <stdint.h> 521590Srgrimes#include <stdio.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: 2701590Srgrimes if (argc > 2) 271228701Sbz if (!doincl(argv[2])) { 272228697Sbapt if (mimic_gnu) 273228697Sbapt warn("%s at line %lu: include(%s)", 274228697Sbapt CURRENT_NAME, CURRENT_LINE, argv[2]); 275228697Sbapt else 276228697Sbapt err(1, "%s at line %lu: include(%s)", 277228697Sbapt CURRENT_NAME, CURRENT_LINE, argv[2]); 278228701Sbz } 2791590Srgrimes break; 2801590Srgrimes 2811590Srgrimes case SINCTYPE: 2821590Srgrimes if (argc > 2) 2831590Srgrimes (void) doincl(argv[2]); 2841590Srgrimes break; 2851590Srgrimes#ifdef EXTENDED 2861590Srgrimes case PASTTYPE: 2871590Srgrimes if (argc > 2) 2881590Srgrimes if (!dopaste(argv[2])) 289228063Sbapt err(1, "%s at line %lu: paste(%s)", 29095060Sjmallett CURRENT_NAME, CURRENT_LINE, argv[2]); 2911590Srgrimes break; 2921590Srgrimes 2931590Srgrimes case SPASTYPE: 2941590Srgrimes if (argc > 2) 2951590Srgrimes (void) dopaste(argv[2]); 2961590Srgrimes break; 297228063Sbapt case FORMATTYPE: 298228063Sbapt doformat(argv, argc); 299228063Sbapt break; 3001590Srgrimes#endif 3011590Srgrimes case CHNQTYPE: 302228063Sbapt dochq(argv, ac); 3031590Srgrimes break; 3041590Srgrimes 3051590Srgrimes case CHNCTYPE: 306228063Sbapt dochc(argv, argc); 3071590Srgrimes break; 3081590Srgrimes 3091590Srgrimes case SUBSTYPE: 3101590Srgrimes /* 3111590Srgrimes * dosub - select substring 312100014Sjmallett * 3131590Srgrimes */ 3141590Srgrimes if (argc > 3) 3151590Srgrimes dosub(argv, argc); 3161590Srgrimes break; 3171590Srgrimes 3181590Srgrimes case SHIFTYPE: 3191590Srgrimes /* 3201590Srgrimes * doshift - push back all arguments 3211590Srgrimes * except the first one (i.e. skip 3221590Srgrimes * argv[2]) 3231590Srgrimes */ 3241590Srgrimes if (argc > 3) { 3251590Srgrimes for (n = argc - 1; n > 3; n--) { 32695060Sjmallett pbstr(rquote); 3271590Srgrimes pbstr(argv[n]); 32895060Sjmallett pbstr(lquote); 329228063Sbapt pushback(COMMA); 3301590Srgrimes } 33195060Sjmallett pbstr(rquote); 3321590Srgrimes pbstr(argv[3]); 33395060Sjmallett pbstr(lquote); 3341590Srgrimes } 3351590Srgrimes break; 3361590Srgrimes 3371590Srgrimes case DIVRTYPE: 3381590Srgrimes if (argc > 2 && (n = atoi(argv[2])) != 0) 3391590Srgrimes dodiv(n); 3401590Srgrimes else { 3411590Srgrimes active = stdout; 3421590Srgrimes oindex = 0; 3431590Srgrimes } 3441590Srgrimes break; 3451590Srgrimes 3461590Srgrimes case UNDVTYPE: 3471590Srgrimes doundiv(argv, argc); 3481590Srgrimes break; 3491590Srgrimes 3501590Srgrimes case DIVNTYPE: 3511590Srgrimes /* 3521590Srgrimes * dodivnum - return the number of 3531590Srgrimes * current output diversion 3541590Srgrimes */ 3551590Srgrimes pbnum(oindex); 3561590Srgrimes break; 3571590Srgrimes 3581590Srgrimes case UNDFTYPE: 3591590Srgrimes /* 3601590Srgrimes * doundefine - undefine a previously 3611590Srgrimes * defined macro(s) or m4 keyword(s). 3621590Srgrimes */ 3631590Srgrimes if (argc > 2) 3641590Srgrimes for (n = 2; n < argc; n++) 365228063Sbapt macro_undefine(argv[n]); 3661590Srgrimes break; 3671590Srgrimes 3681590Srgrimes case POPDTYPE: 3691590Srgrimes /* 3701590Srgrimes * dopopdef - remove the topmost 3711590Srgrimes * definitions of macro(s) or m4 3721590Srgrimes * keyword(s). 3731590Srgrimes */ 3741590Srgrimes if (argc > 2) 3751590Srgrimes for (n = 2; n < argc; n++) 376228063Sbapt macro_popdef(argv[n]); 3771590Srgrimes break; 3781590Srgrimes 3791590Srgrimes case MKTMTYPE: 3801590Srgrimes /* 3811590Srgrimes * dotemp - create a temporary file 3821590Srgrimes */ 38395060Sjmallett if (argc > 2) { 38495060Sjmallett int fd; 38595060Sjmallett char *temp; 38695060Sjmallett 38795060Sjmallett temp = xstrdup(argv[2]); 388100014Sjmallett 38995060Sjmallett fd = mkstemp(temp); 39095060Sjmallett if (fd == -1) 391100014Sjmallett err(1, 392100014Sjmallett "%s at line %lu: couldn't make temp file %s", 39395060Sjmallett CURRENT_NAME, CURRENT_LINE, argv[2]); 39495060Sjmallett close(fd); 39595060Sjmallett pbstr(temp); 39695060Sjmallett free(temp); 39795060Sjmallett } 3981590Srgrimes break; 3991590Srgrimes 4001590Srgrimes case TRNLTYPE: 4011590Srgrimes /* 4021590Srgrimes * dotranslit - replace all characters in 4031590Srgrimes * the source string that appears in the 4041590Srgrimes * "from" string with the corresponding 4051590Srgrimes * characters in the "to" string. 4061590Srgrimes */ 4071590Srgrimes if (argc > 3) { 40895060Sjmallett char *temp; 40995060Sjmallett 410228063Sbapt temp = xalloc(strlen(argv[2])+1, NULL); 4111590Srgrimes if (argc > 4) 4121590Srgrimes map(temp, argv[2], argv[3], argv[4]); 4131590Srgrimes else 4141590Srgrimes map(temp, argv[2], argv[3], null); 4151590Srgrimes pbstr(temp); 41695060Sjmallett free(temp); 41795060Sjmallett } else if (argc > 2) 4181590Srgrimes pbstr(argv[2]); 4191590Srgrimes break; 4201590Srgrimes 4211590Srgrimes case INDXTYPE: 4221590Srgrimes /* 4231590Srgrimes * doindex - find the index of the second 4241590Srgrimes * argument string in the first argument 4251590Srgrimes * string. -1 if not present. 4261590Srgrimes */ 4271590Srgrimes pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1); 4281590Srgrimes break; 4291590Srgrimes 4301590Srgrimes case ERRPTYPE: 4311590Srgrimes /* 4321590Srgrimes * doerrp - print the arguments to stderr 4331590Srgrimes * file 4341590Srgrimes */ 4351590Srgrimes if (argc > 2) { 4361590Srgrimes for (n = 2; n < argc; n++) 4371590Srgrimes fprintf(stderr, "%s ", argv[n]); 4381590Srgrimes fprintf(stderr, "\n"); 4391590Srgrimes } 4401590Srgrimes break; 4411590Srgrimes 4421590Srgrimes case DNLNTYPE: 4431590Srgrimes /* 4441590Srgrimes * dodnl - eat-up-to and including 4451590Srgrimes * newline 4461590Srgrimes */ 4471590Srgrimes while ((c = gpbc()) != '\n' && c != EOF) 4481590Srgrimes ; 4491590Srgrimes break; 4501590Srgrimes 4511590Srgrimes case M4WRTYPE: 4521590Srgrimes /* 4531590Srgrimes * dom4wrap - set up for 4541590Srgrimes * wrap-up/wind-down activity 4551590Srgrimes */ 456228063Sbapt if (argc > 2) 457228063Sbapt dom4wrap(argv[2]); 4581590Srgrimes break; 4591590Srgrimes 4601590Srgrimes case EXITTYPE: 4611590Srgrimes /* 4621590Srgrimes * doexit - immediate exit from m4. 4631590Srgrimes */ 4647896Sache killdiv(); 4651590Srgrimes exit((argc > 2) ? atoi(argv[2]) : 0); 4661590Srgrimes break; 4671590Srgrimes 4681590Srgrimes case DEFNTYPE: 4691590Srgrimes if (argc > 2) 4701590Srgrimes for (n = 2; n < argc; n++) 4711590Srgrimes dodefn(argv[n]); 4721590Srgrimes break; 4731590Srgrimes 47495060Sjmallett case INDIRTYPE: /* Indirect call */ 47595060Sjmallett if (argc > 2) 47695060Sjmallett doindir(argv, argc); 47738926Ssteve break; 478100014Sjmallett 47995060Sjmallett case BUILTINTYPE: /* Builtins only */ 48095060Sjmallett if (argc > 2) 48195060Sjmallett dobuiltin(argv, argc); 48295060Sjmallett break; 48338926Ssteve 48495060Sjmallett case PATSTYPE: 48595060Sjmallett if (argc > 2) 48695060Sjmallett dopatsubst(argv, argc); 48795060Sjmallett break; 48895060Sjmallett case REGEXPTYPE: 48995060Sjmallett if (argc > 2) 49095060Sjmallett doregexp(argv, argc); 49195060Sjmallett break; 49295060Sjmallett case LINETYPE: 49395060Sjmallett doprintlineno(infile+ilevel); 49495060Sjmallett break; 49595060Sjmallett case FILENAMETYPE: 49695060Sjmallett doprintfilename(infile+ilevel); 49795060Sjmallett break; 49895060Sjmallett case SELFTYPE: 49995060Sjmallett pbstr(rquote); 50095060Sjmallett pbstr(argv[1]); 50195060Sjmallett pbstr(lquote); 50295060Sjmallett break; 5031590Srgrimes default: 504228063Sbapt m4errx(1, "eval: major botch."); 5051590Srgrimes break; 5061590Srgrimes } 5071590Srgrimes} 5081590Srgrimes 5091590Srgrimes/* 51095060Sjmallett * expand_macro - user-defined macro expansion 5111590Srgrimes */ 5121590Srgrimesvoid 51395887Sjmallettexpand_macro(const char *argv[], int argc) 5141590Srgrimes{ 51595060Sjmallett const char *t; 51695060Sjmallett const char *p; 51795060Sjmallett int n; 51895060Sjmallett int argno; 5191590Srgrimes 5201590Srgrimes t = argv[0]; /* defn string as a whole */ 5211590Srgrimes p = t; 5221590Srgrimes while (*p) 5231590Srgrimes p++; 5241590Srgrimes p--; /* last character of defn */ 5251590Srgrimes while (p > t) { 5261590Srgrimes if (*(p - 1) != ARGFLAG) 527228063Sbapt PUSHBACK(*p); 5281590Srgrimes else { 5291590Srgrimes switch (*p) { 5301590Srgrimes 5311590Srgrimes case '#': 5321590Srgrimes pbnum(argc - 2); 5331590Srgrimes break; 5341590Srgrimes case '0': 5351590Srgrimes case '1': 5361590Srgrimes case '2': 5371590Srgrimes case '3': 5381590Srgrimes case '4': 5391590Srgrimes case '5': 5401590Srgrimes case '6': 5411590Srgrimes case '7': 5421590Srgrimes case '8': 5431590Srgrimes case '9': 5441590Srgrimes if ((argno = *p - '0') < argc - 1) 5451590Srgrimes pbstr(argv[argno + 1]); 5461590Srgrimes break; 5471590Srgrimes case '*': 54895060Sjmallett if (argc > 2) { 54995060Sjmallett for (n = argc - 1; n > 2; n--) { 55095060Sjmallett pbstr(argv[n]); 551228063Sbapt pushback(COMMA); 55295060Sjmallett } 55395060Sjmallett pbstr(argv[2]); 554228063Sbapt } 5551590Srgrimes break; 55695060Sjmallett case '@': 55795060Sjmallett if (argc > 2) { 55895060Sjmallett for (n = argc - 1; n > 2; n--) { 55995060Sjmallett pbstr(rquote); 56095060Sjmallett pbstr(argv[n]); 56195060Sjmallett pbstr(lquote); 562228063Sbapt pushback(COMMA); 56395060Sjmallett } 56495060Sjmallett pbstr(rquote); 56595060Sjmallett pbstr(argv[2]); 56695060Sjmallett pbstr(lquote); 56724901Sjoerg } 56895060Sjmallett break; 5691590Srgrimes default: 570228063Sbapt PUSHBACK(*p); 571228063Sbapt PUSHBACK('$'); 5721590Srgrimes break; 5731590Srgrimes } 5741590Srgrimes p--; 5751590Srgrimes } 5761590Srgrimes p--; 5771590Srgrimes } 5781590Srgrimes if (p == t) /* do last character */ 579228063Sbapt PUSHBACK(*p); 5801590Srgrimes} 5811590Srgrimes 582228063Sbapt 5831590Srgrimes/* 5841590Srgrimes * dodefine - install definition in the table 5851590Srgrimes */ 5861590Srgrimesvoid 58795887Sjmallettdodefine(const char *name, const char *defn) 5881590Srgrimes{ 589228063Sbapt if (!*name && !mimic_gnu) 590228063Sbapt m4errx(1, "null definition."); 5911590Srgrimes else 592228063Sbapt macro_define(name, defn); 5931590Srgrimes} 5941590Srgrimes 5951590Srgrimes/* 5961590Srgrimes * dodefn - push back a quoted definition of 5971590Srgrimes * the given name. 5981590Srgrimes */ 59995060Sjmallettstatic void 60095887Sjmallettdodefn(const char *name) 6011590Srgrimes{ 602228063Sbapt struct macro_definition *p; 6031590Srgrimes 604228063Sbapt if ((p = lookup_macro_definition(name)) != NULL) { 605228063Sbapt if ((p->type & TYPEMASK) == MACRTYPE) { 60695060Sjmallett pbstr(rquote); 60795060Sjmallett pbstr(p->defn); 60895060Sjmallett pbstr(lquote); 609228063Sbapt } else { 610228063Sbapt pbstr(p->defn); 61195060Sjmallett pbstr(BUILTIN_MARKER); 61295060Sjmallett } 6131590Srgrimes } 6141590Srgrimes} 6151590Srgrimes 6161590Srgrimes/* 6171590Srgrimes * dopushdef - install a definition in the hash table 6181590Srgrimes * without removing a previous definition. Since 6191590Srgrimes * each new entry is entered in *front* of the 6201590Srgrimes * hash bucket, it hides a previous definition from 6211590Srgrimes * lookup. 6221590Srgrimes */ 62395060Sjmallettstatic void 62495887Sjmallettdopushdef(const char *name, const char *defn) 6251590Srgrimes{ 626228063Sbapt if (!*name && !mimic_gnu) 627228063Sbapt m4errx(1, "null definition."); 6281590Srgrimes else 629228063Sbapt macro_pushdef(name, defn); 6301590Srgrimes} 6311590Srgrimes 6321590Srgrimes/* 63395060Sjmallett * dump_one_def - dump the specified definition. 63495060Sjmallett */ 63595060Sjmallettstatic void 636228063Sbaptdump_one_def(const char *name, struct macro_definition *p) 63795060Sjmallett{ 638228063Sbapt if (!traceout) 639228063Sbapt traceout = stderr; 64095060Sjmallett if (mimic_gnu) { 64195060Sjmallett if ((p->type & TYPEMASK) == MACRTYPE) 642228063Sbapt fprintf(traceout, "%s:\t%s\n", name, p->defn); 64395060Sjmallett else { 644228063Sbapt fprintf(traceout, "%s:\t<%s>\n", name, p->defn); 645228063Sbapt } 64695060Sjmallett } else 647228063Sbapt fprintf(traceout, "`%s'\t`%s'\n", name, p->defn); 64895060Sjmallett} 64995060Sjmallett 65095060Sjmallett/* 6511590Srgrimes * dodumpdef - dump the specified definitions in the hash 6521590Srgrimes * table to stderr. If nothing is specified, the entire 6531590Srgrimes * hash table is dumped. 6541590Srgrimes */ 65595060Sjmallettstatic void 65695887Sjmallettdodump(const char *argv[], int argc) 6571590Srgrimes{ 65895060Sjmallett int n; 659228063Sbapt struct macro_definition *p; 6601590Srgrimes 6611590Srgrimes if (argc > 2) { 6621590Srgrimes for (n = 2; n < argc; n++) 663228063Sbapt if ((p = lookup_macro_definition(argv[n])) != NULL) 664228063Sbapt dump_one_def(argv[n], p); 665228063Sbapt } else 666228063Sbapt macro_for_all(dump_one_def); 6671590Srgrimes} 6681590Srgrimes 6691590Srgrimes/* 67095060Sjmallett * dotrace - mark some macros as traced/untraced depending upon on. 67195060Sjmallett */ 67295060Sjmallettstatic void 67395887Sjmallettdotrace(const char *argv[], int argc, int on) 67495060Sjmallett{ 67595060Sjmallett int n; 67695060Sjmallett 67795060Sjmallett if (argc > 2) { 67895060Sjmallett for (n = 2; n < argc; n++) 67995060Sjmallett mark_traced(argv[n], on); 68095060Sjmallett } else 68195060Sjmallett mark_traced(NULL, on); 68295060Sjmallett} 68395060Sjmallett 68495060Sjmallett/* 6851590Srgrimes * doifelse - select one of two alternatives - loop. 6861590Srgrimes */ 68795060Sjmallettstatic void 68895887Sjmallettdoifelse(const char *argv[], int argc) 6891590Srgrimes{ 6901590Srgrimes cycle { 6911590Srgrimes if (STREQ(argv[2], argv[3])) 6921590Srgrimes pbstr(argv[4]); 6931590Srgrimes else if (argc == 6) 6941590Srgrimes pbstr(argv[5]); 6951590Srgrimes else if (argc > 6) { 6961590Srgrimes argv += 3; 6971590Srgrimes argc -= 3; 6981590Srgrimes continue; 6991590Srgrimes } 7001590Srgrimes break; 7011590Srgrimes } 7021590Srgrimes} 7031590Srgrimes 7041590Srgrimes/* 7051590Srgrimes * doinclude - include a given file. 7061590Srgrimes */ 70795060Sjmallettstatic int 70895887Sjmallettdoincl(const char *ifile) 7091590Srgrimes{ 7101590Srgrimes if (ilevel + 1 == MAXINP) 711228063Sbapt m4errx(1, "too many include files."); 71295060Sjmallett if (fopen_trypath(infile+ilevel+1, ifile) != NULL) { 7131590Srgrimes ilevel++; 7141590Srgrimes bbase[ilevel] = bufbase = bp; 7151590Srgrimes return (1); 71695060Sjmallett } else 7171590Srgrimes return (0); 7181590Srgrimes} 7191590Srgrimes 7201590Srgrimes#ifdef EXTENDED 7211590Srgrimes/* 7221590Srgrimes * dopaste - include a given file without any 7231590Srgrimes * macro processing. 7241590Srgrimes */ 72595060Sjmallettstatic int 72695887Sjmallettdopaste(const char *pfile) 7271590Srgrimes{ 7281590Srgrimes FILE *pf; 72995060Sjmallett int c; 7301590Srgrimes 7311590Srgrimes if ((pf = fopen(pfile, "r")) != NULL) { 732228063Sbapt if (synch_lines) 733228063Sbapt fprintf(active, "#line 1 \"%s\"\n", pfile); 7341590Srgrimes while ((c = getc(pf)) != EOF) 7351590Srgrimes putc(c, active); 7361590Srgrimes (void) fclose(pf); 737228063Sbapt emit_synchline(); 7381590Srgrimes return (1); 73995060Sjmallett } else 7401590Srgrimes return (0); 7411590Srgrimes} 7421590Srgrimes#endif 7431590Srgrimes 744228063Sbapt/* 745228063Sbapt * dochq - change quote characters 746228063Sbapt */ 74795060Sjmallettstatic void 748228063Sbaptdochq(const char *argv[], int ac) 74995060Sjmallett{ 75095060Sjmallett if (ac == 2) { 751228063Sbapt lquote[0] = LQUOTE; lquote[1] = EOS; 752228063Sbapt rquote[0] = RQUOTE; rquote[1] = EOS; 75395060Sjmallett } else { 75495060Sjmallett strlcpy(lquote, argv[2], sizeof(lquote)); 755228063Sbapt if (ac > 3) { 75695060Sjmallett strlcpy(rquote, argv[3], sizeof(rquote)); 757228063Sbapt } else { 758228063Sbapt rquote[0] = ECOMMT; rquote[1] = EOS; 759228063Sbapt } 76095060Sjmallett } 76195060Sjmallett} 76295060Sjmallett 7631590Srgrimes/* 764228063Sbapt * dochc - change comment characters 7651590Srgrimes */ 76695060Sjmallettstatic void 767228063Sbaptdochc(const char *argv[], int argc) 7681590Srgrimes{ 769228063Sbapt/* XXX Note that there is no difference between no argument and a single 770228063Sbapt * empty argument. 771228063Sbapt */ 772228063Sbapt if (argc == 2) { 77395060Sjmallett scommt[0] = EOS; 77495060Sjmallett ecommt[0] = EOS; 77595060Sjmallett } else { 776228063Sbapt strlcpy(scommt, argv[2], sizeof(scommt)); 777228063Sbapt if (argc == 3) { 778228063Sbapt ecommt[0] = ECOMMT; ecommt[1] = EOS; 779228063Sbapt } else { 78095060Sjmallett strlcpy(ecommt, argv[3], sizeof(ecommt)); 781228063Sbapt } 7821590Srgrimes } 7831590Srgrimes} 784228063Sbapt 7851590Srgrimes/* 786228063Sbapt * dom4wrap - expand text at EOF 7871590Srgrimes */ 78895060Sjmallettstatic void 789228063Sbaptdom4wrap(const char *text) 7901590Srgrimes{ 791228063Sbapt if (wrapindex >= maxwraps) { 792228063Sbapt if (maxwraps == 0) 793228063Sbapt maxwraps = 16; 7941590Srgrimes else 795228063Sbapt maxwraps *= 2; 796228063Sbapt m4wraps = xrealloc(m4wraps, maxwraps * sizeof(*m4wraps), 797228063Sbapt "too many m4wraps"); 7981590Srgrimes } 799228063Sbapt m4wraps[wrapindex++] = xstrdup(text); 8001590Srgrimes} 8011590Srgrimes 8021590Srgrimes/* 8031590Srgrimes * dodivert - divert the output to a temporary file 8041590Srgrimes */ 80595060Sjmallettstatic void 80695887Sjmallettdodiv(int n) 8071590Srgrimes{ 80895060Sjmallett int fd; 80995060Sjmallett 81028386Sjlemon oindex = n; 81195060Sjmallett if (n >= maxout) { 81295060Sjmallett if (mimic_gnu) 81395060Sjmallett resizedivs(n + 10); 81495060Sjmallett else 81595060Sjmallett n = 0; /* bitbucket */ 816228063Sbapt } 81795060Sjmallett 81895060Sjmallett if (n < 0) 8191590Srgrimes n = 0; /* bitbucket */ 8201590Srgrimes if (outfile[n] == NULL) { 82195060Sjmallett char fname[] = _PATH_DIVNAME; 82295060Sjmallett 823228063Sbapt if ((fd = mkstemp(fname)) < 0 || 82495060Sjmallett (outfile[n] = fdopen(fd, "w+")) == NULL) 82595060Sjmallett err(1, "%s: cannot divert", fname); 82695060Sjmallett if (unlink(fname) == -1) 82795060Sjmallett err(1, "%s: cannot unlink", fname); 8281590Srgrimes } 8291590Srgrimes active = outfile[n]; 8301590Srgrimes} 8311590Srgrimes 8321590Srgrimes/* 8331590Srgrimes * doundivert - undivert a specified output, or all 8341590Srgrimes * other outputs, in numerical order. 8351590Srgrimes */ 83695060Sjmallettstatic void 83795887Sjmallettdoundiv(const char *argv[], int argc) 8381590Srgrimes{ 83995060Sjmallett int ind; 84095060Sjmallett int n; 8411590Srgrimes 8421590Srgrimes if (argc > 2) { 8431590Srgrimes for (ind = 2; ind < argc; ind++) { 844228063Sbapt const char *errstr; 845228063Sbapt n = strtonum(argv[ind], 1, INT_MAX, &errstr); 846228063Sbapt if (errstr) { 847228063Sbapt if (errno == EINVAL && mimic_gnu) 848228063Sbapt getdivfile(argv[ind]); 849228063Sbapt } else { 850228063Sbapt if (n < maxout && outfile[n] != NULL) 851228063Sbapt getdiv(n); 852228063Sbapt } 8531590Srgrimes } 8541590Srgrimes } 8551590Srgrimes else 85695060Sjmallett for (n = 1; n < maxout; n++) 8571590Srgrimes if (outfile[n] != NULL) 8581590Srgrimes getdiv(n); 8591590Srgrimes} 8601590Srgrimes 8611590Srgrimes/* 8621590Srgrimes * dosub - select substring 8631590Srgrimes */ 86495060Sjmallettstatic void 86595887Sjmallettdosub(const char *argv[], int argc) 8661590Srgrimes{ 86795060Sjmallett const char *ap, *fc, *k; 86895060Sjmallett int nc; 8691590Srgrimes 87076822Sgshapiro ap = argv[2]; /* target string */ 87176822Sgshapiro#ifdef EXPR 87276822Sgshapiro fc = ap + expr(argv[3]); /* first char */ 87376822Sgshapiro#else 87476822Sgshapiro fc = ap + atoi(argv[3]); /* first char */ 87576822Sgshapiro#endif 87695060Sjmallett nc = strlen(fc); 87795060Sjmallett if (argc >= 5) 8781590Srgrimes#ifdef EXPR 87995060Sjmallett nc = min(nc, expr(argv[4])); 8801590Srgrimes#else 88195060Sjmallett nc = min(nc, atoi(argv[4])); 8821590Srgrimes#endif 8831590Srgrimes if (fc >= ap && fc < ap + strlen(ap)) 88476822Sgshapiro for (k = fc + nc - 1; k >= fc; k--) 885228063Sbapt pushback(*k); 8861590Srgrimes} 8871590Srgrimes 8881590Srgrimes/* 8891590Srgrimes * map: 8901590Srgrimes * map every character of s1 that is specified in from 8911590Srgrimes * into s3 and replace in s. (source s1 remains untouched) 8921590Srgrimes * 893228063Sbapt * This is derived from the a standard implementation of map(s,from,to) 894228063Sbapt * function of ICON language. Within mapvec, we replace every character 895228063Sbapt * of "from" with the corresponding character in "to". 896228063Sbapt * If "to" is shorter than "from", than the corresponding entries are null, 897228063Sbapt * which means that those characters dissapear altogether. 8981590Srgrimes */ 89995060Sjmallettstatic void 90095887Sjmallettmap(char *dest, const char *src, const char *from, const char *to) 9011590Srgrimes{ 90295060Sjmallett const char *tmp; 90395060Sjmallett unsigned char sch, dch; 90495060Sjmallett static char frombis[257]; 90595060Sjmallett static char tobis[257]; 906228063Sbapt int i; 907228063Sbapt char seen[256]; 90895060Sjmallett static unsigned char mapvec[256] = { 90995060Sjmallett 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 91095060Sjmallett 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 91195060Sjmallett 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 91295060Sjmallett 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 91395060Sjmallett 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 91495060Sjmallett 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 91595060Sjmallett 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 91695060Sjmallett 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 91795060Sjmallett 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 91895060Sjmallett 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 91995060Sjmallett 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 92095060Sjmallett 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 92195060Sjmallett 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 92295060Sjmallett 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 92395060Sjmallett 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 92495060Sjmallett 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 92595060Sjmallett 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 92695060Sjmallett 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 9271590Srgrimes }; 9281590Srgrimes 9291590Srgrimes if (*src) { 93095060Sjmallett if (mimic_gnu) { 93195060Sjmallett /* 93295060Sjmallett * expand character ranges on the fly 93395060Sjmallett */ 93495060Sjmallett from = handledash(frombis, frombis + 256, from); 93595060Sjmallett to = handledash(tobis, tobis + 256, to); 93695060Sjmallett } 9371590Srgrimes tmp = from; 9381590Srgrimes /* 9391590Srgrimes * create a mapping between "from" and 9401590Srgrimes * "to" 9411590Srgrimes */ 942228063Sbapt for (i = 0; i < 256; i++) 943228063Sbapt seen[i] = 0; 944228063Sbapt while (*from) { 945228063Sbapt if (!seen[(unsigned char)(*from)]) { 946228063Sbapt mapvec[(unsigned char)(*from)] = (unsigned char)(*to); 947228063Sbapt seen[(unsigned char)(*from)] = 1; 948228063Sbapt } 949228063Sbapt from++; 950228063Sbapt if (*to) 951228063Sbapt to++; 952228063Sbapt } 9531590Srgrimes 9541590Srgrimes while (*src) { 95595060Sjmallett sch = (unsigned char)(*src++); 9561590Srgrimes dch = mapvec[sch]; 95795060Sjmallett if ((*dest = (char)dch)) 9581590Srgrimes dest++; 9591590Srgrimes } 9601590Srgrimes /* 9611590Srgrimes * restore all the changed characters 9621590Srgrimes */ 9631590Srgrimes while (*tmp) { 96495060Sjmallett mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp); 9651590Srgrimes tmp++; 9661590Srgrimes } 9671590Srgrimes } 96895060Sjmallett *dest = '\0'; 9691590Srgrimes} 97095060Sjmallett 97195060Sjmallett 97295060Sjmallett/* 97395060Sjmallett * handledash: 97495060Sjmallett * use buffer to copy the src string, expanding character ranges 97595060Sjmallett * on the way. 97695060Sjmallett */ 97795060Sjmallettstatic const char * 97895887Sjmalletthandledash(char *buffer, char *end, const char *src) 97995060Sjmallett{ 98095060Sjmallett char *p; 981100014Sjmallett 98295060Sjmallett p = buffer; 98395060Sjmallett while(*src) { 98495060Sjmallett if (src[1] == '-' && src[2]) { 98595060Sjmallett unsigned char i; 986228063Sbapt if ((unsigned char)src[0] <= (unsigned char)src[2]) { 987228063Sbapt for (i = (unsigned char)src[0]; 988228063Sbapt i <= (unsigned char)src[2]; i++) { 989228063Sbapt *p++ = i; 990228063Sbapt if (p == end) { 991228063Sbapt *p = '\0'; 992228063Sbapt return buffer; 993228063Sbapt } 99495060Sjmallett } 995228063Sbapt } else { 996228063Sbapt for (i = (unsigned char)src[0]; 997228063Sbapt i >= (unsigned char)src[2]; i--) { 998228063Sbapt *p++ = i; 999228063Sbapt if (p == end) { 1000228063Sbapt *p = '\0'; 1001228063Sbapt return buffer; 1002228063Sbapt } 1003228063Sbapt } 100495060Sjmallett } 100595060Sjmallett src += 3; 100695060Sjmallett } else 100795060Sjmallett *p++ = *src++; 100895060Sjmallett if (p == end) 100995060Sjmallett break; 101095060Sjmallett } 101195060Sjmallett *p = '\0'; 101295060Sjmallett return buffer; 101395060Sjmallett} 1014