1*2e8d1edaSArun Thomas /* $OpenBSD: eval.c,v 1.66 2008/08/21 21:01:47 espie Exp $ */ 2*2e8d1edaSArun Thomas /* $NetBSD: eval.c,v 1.20 2009/10/26 21:11:28 christos Exp $ */ 3*2e8d1edaSArun Thomas 4*2e8d1edaSArun Thomas /* 5*2e8d1edaSArun Thomas * Copyright (c) 1989, 1993 6*2e8d1edaSArun Thomas * The Regents of the University of California. All rights reserved. 7*2e8d1edaSArun Thomas * 8*2e8d1edaSArun Thomas * This code is derived from software contributed to Berkeley by 9*2e8d1edaSArun Thomas * Ozan Yigit at York University. 10*2e8d1edaSArun Thomas * 11*2e8d1edaSArun Thomas * Redistribution and use in source and binary forms, with or without 12*2e8d1edaSArun Thomas * modification, are permitted provided that the following conditions 13*2e8d1edaSArun Thomas * are met: 14*2e8d1edaSArun Thomas * 1. Redistributions of source code must retain the above copyright 15*2e8d1edaSArun Thomas * notice, this list of conditions and the following disclaimer. 16*2e8d1edaSArun Thomas * 2. Redistributions in binary form must reproduce the above copyright 17*2e8d1edaSArun Thomas * notice, this list of conditions and the following disclaimer in the 18*2e8d1edaSArun Thomas * documentation and/or other materials provided with the distribution. 19*2e8d1edaSArun Thomas * 3. Neither the name of the University nor the names of its contributors 20*2e8d1edaSArun Thomas * may be used to endorse or promote products derived from this software 21*2e8d1edaSArun Thomas * without specific prior written permission. 22*2e8d1edaSArun Thomas * 23*2e8d1edaSArun Thomas * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24*2e8d1edaSArun Thomas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25*2e8d1edaSArun Thomas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26*2e8d1edaSArun Thomas * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27*2e8d1edaSArun Thomas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28*2e8d1edaSArun Thomas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29*2e8d1edaSArun Thomas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30*2e8d1edaSArun Thomas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31*2e8d1edaSArun Thomas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32*2e8d1edaSArun Thomas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33*2e8d1edaSArun Thomas * SUCH DAMAGE. 34*2e8d1edaSArun Thomas */ 35*2e8d1edaSArun Thomas 36*2e8d1edaSArun Thomas /* 37*2e8d1edaSArun Thomas * eval.c 38*2e8d1edaSArun Thomas * Facility: m4 macro processor 39*2e8d1edaSArun Thomas * by: oz 40*2e8d1edaSArun Thomas */ 41*2e8d1edaSArun Thomas #if HAVE_NBTOOL_CONFIG_H 42*2e8d1edaSArun Thomas #include "nbtool_config.h" 43*2e8d1edaSArun Thomas #endif 44*2e8d1edaSArun Thomas #include <sys/cdefs.h> 45*2e8d1edaSArun Thomas __RCSID("$NetBSD: eval.c,v 1.20 2009/10/26 21:11:28 christos Exp $"); 46*2e8d1edaSArun Thomas 47*2e8d1edaSArun Thomas #include <sys/types.h> 48*2e8d1edaSArun Thomas #include <err.h> 49*2e8d1edaSArun Thomas #include <errno.h> 50*2e8d1edaSArun Thomas #include <limits.h> 51*2e8d1edaSArun Thomas #include <unistd.h> 52*2e8d1edaSArun Thomas #include <stdio.h> 53*2e8d1edaSArun Thomas #include <stdlib.h> 54*2e8d1edaSArun Thomas #include <stddef.h> 55*2e8d1edaSArun Thomas #include <string.h> 56*2e8d1edaSArun Thomas #include <fcntl.h> 57*2e8d1edaSArun Thomas #include "mdef.h" 58*2e8d1edaSArun Thomas #include "stdd.h" 59*2e8d1edaSArun Thomas #include "extern.h" 60*2e8d1edaSArun Thomas #include "pathnames.h" 61*2e8d1edaSArun Thomas 62*2e8d1edaSArun Thomas static void dodefn(const char *); 63*2e8d1edaSArun Thomas static void dopushdef(const char *, const char *); 64*2e8d1edaSArun Thomas static void dodump(const char *[], int); 65*2e8d1edaSArun Thomas static void dotrace(const char *[], int, int); 66*2e8d1edaSArun Thomas static void doifelse(const char *[], int); 67*2e8d1edaSArun Thomas static int doincl(const char *); 68*2e8d1edaSArun Thomas static int dopaste(const char *); 69*2e8d1edaSArun Thomas static void dochq(const char *[], int); 70*2e8d1edaSArun Thomas static void dochc(const char *[], int); 71*2e8d1edaSArun Thomas static void dom4wrap(const char *); 72*2e8d1edaSArun Thomas static void dodiv(int); 73*2e8d1edaSArun Thomas static void doundiv(const char *[], int); 74*2e8d1edaSArun Thomas static void dosub(const char *[], int); 75*2e8d1edaSArun Thomas static void map(char *, const char *, const char *, const char *); 76*2e8d1edaSArun Thomas static const char *handledash(char *, char *, const char *); 77*2e8d1edaSArun Thomas static void expand_builtin(const char *[], int, int); 78*2e8d1edaSArun Thomas static void expand_macro(const char *[], int); 79*2e8d1edaSArun Thomas static void dump_one_def(const char *, struct macro_definition *); 80*2e8d1edaSArun Thomas 81*2e8d1edaSArun Thomas unsigned long expansion_id; 82*2e8d1edaSArun Thomas 83*2e8d1edaSArun Thomas /* 84*2e8d1edaSArun Thomas * eval - eval all macros and builtins calls 85*2e8d1edaSArun Thomas * argc - number of elements in argv. 86*2e8d1edaSArun Thomas * argv - element vector : 87*2e8d1edaSArun Thomas * argv[0] = definition of a user 88*2e8d1edaSArun Thomas * macro or NULL if built-in. 89*2e8d1edaSArun Thomas * argv[1] = name of the macro or 90*2e8d1edaSArun Thomas * built-in. 91*2e8d1edaSArun Thomas * argv[2] = parameters to user-defined 92*2e8d1edaSArun Thomas * . macro or built-in. 93*2e8d1edaSArun Thomas * . 94*2e8d1edaSArun Thomas * 95*2e8d1edaSArun Thomas * A call in the form of macro-or-builtin() will result in: 96*2e8d1edaSArun Thomas * argv[0] = nullstr 97*2e8d1edaSArun Thomas * argv[1] = macro-or-builtin 98*2e8d1edaSArun Thomas * argv[2] = nullstr 99*2e8d1edaSArun Thomas * 100*2e8d1edaSArun Thomas * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin 101*2e8d1edaSArun Thomas */ 102*2e8d1edaSArun Thomas void 103*2e8d1edaSArun Thomas eval(const char *argv[], int argc, int td, int is_traced) 104*2e8d1edaSArun Thomas { 105*2e8d1edaSArun Thomas size_t mark = SIZE_MAX; 106*2e8d1edaSArun Thomas 107*2e8d1edaSArun Thomas expansion_id++; 108*2e8d1edaSArun Thomas if (td & RECDEF) 109*2e8d1edaSArun Thomas m4errx(1, "expanding recursive definition for %s.", argv[1]); 110*2e8d1edaSArun Thomas if (is_traced) 111*2e8d1edaSArun Thomas mark = trace(argv, argc, infile+ilevel); 112*2e8d1edaSArun Thomas if (td == MACRTYPE) 113*2e8d1edaSArun Thomas expand_macro(argv, argc); 114*2e8d1edaSArun Thomas else 115*2e8d1edaSArun Thomas expand_builtin(argv, argc, td); 116*2e8d1edaSArun Thomas if (mark != SIZE_MAX) 117*2e8d1edaSArun Thomas finish_trace(mark); 118*2e8d1edaSArun Thomas } 119*2e8d1edaSArun Thomas 120*2e8d1edaSArun Thomas /* 121*2e8d1edaSArun Thomas * expand_builtin - evaluate built-in macros. 122*2e8d1edaSArun Thomas */ 123*2e8d1edaSArun Thomas void 124*2e8d1edaSArun Thomas expand_builtin(const char *argv[], int argc, int td) 125*2e8d1edaSArun Thomas { 126*2e8d1edaSArun Thomas int c, n; 127*2e8d1edaSArun Thomas int ac; 128*2e8d1edaSArun Thomas static int sysval = 0; 129*2e8d1edaSArun Thomas 130*2e8d1edaSArun Thomas #ifdef DEBUG 131*2e8d1edaSArun Thomas printf("argc = %d\n", argc); 132*2e8d1edaSArun Thomas for (n = 0; n < argc; n++) 133*2e8d1edaSArun Thomas printf("argv[%d] = %s\n", n, argv[n]); 134*2e8d1edaSArun Thomas fflush(stdout); 135*2e8d1edaSArun Thomas #endif 136*2e8d1edaSArun Thomas 137*2e8d1edaSArun Thomas /* 138*2e8d1edaSArun Thomas * if argc == 3 and argv[2] is null, then we 139*2e8d1edaSArun Thomas * have macro-or-builtin() type call. We adjust 140*2e8d1edaSArun Thomas * argc to avoid further checking.. 141*2e8d1edaSArun Thomas */ 142*2e8d1edaSArun Thomas /* we keep the initial value for those built-ins that differentiate 143*2e8d1edaSArun Thomas * between builtin() and builtin. 144*2e8d1edaSArun Thomas */ 145*2e8d1edaSArun Thomas ac = argc; 146*2e8d1edaSArun Thomas 147*2e8d1edaSArun Thomas if (argc == 3 && !*(argv[2]) && !mimic_gnu) 148*2e8d1edaSArun Thomas argc--; 149*2e8d1edaSArun Thomas 150*2e8d1edaSArun Thomas switch (td & TYPEMASK) { 151*2e8d1edaSArun Thomas 152*2e8d1edaSArun Thomas case DEFITYPE: 153*2e8d1edaSArun Thomas if (argc > 2) 154*2e8d1edaSArun Thomas dodefine(argv[2], (argc > 3) ? argv[3] : null); 155*2e8d1edaSArun Thomas break; 156*2e8d1edaSArun Thomas 157*2e8d1edaSArun Thomas case PUSDTYPE: 158*2e8d1edaSArun Thomas if (argc > 2) 159*2e8d1edaSArun Thomas dopushdef(argv[2], (argc > 3) ? argv[3] : null); 160*2e8d1edaSArun Thomas break; 161*2e8d1edaSArun Thomas 162*2e8d1edaSArun Thomas case DUMPTYPE: 163*2e8d1edaSArun Thomas dodump(argv, argc); 164*2e8d1edaSArun Thomas break; 165*2e8d1edaSArun Thomas 166*2e8d1edaSArun Thomas case TRACEONTYPE: 167*2e8d1edaSArun Thomas dotrace(argv, argc, 1); 168*2e8d1edaSArun Thomas break; 169*2e8d1edaSArun Thomas 170*2e8d1edaSArun Thomas case TRACEOFFTYPE: 171*2e8d1edaSArun Thomas dotrace(argv, argc, 0); 172*2e8d1edaSArun Thomas break; 173*2e8d1edaSArun Thomas 174*2e8d1edaSArun Thomas case EXPRTYPE: 175*2e8d1edaSArun Thomas /* 176*2e8d1edaSArun Thomas * doexpr - evaluate arithmetic 177*2e8d1edaSArun Thomas * expression 178*2e8d1edaSArun Thomas */ 179*2e8d1edaSArun Thomas { 180*2e8d1edaSArun Thomas int base = 10; 181*2e8d1edaSArun Thomas int maxdigits = 0; 182*2e8d1edaSArun Thomas const char *errstr; 183*2e8d1edaSArun Thomas 184*2e8d1edaSArun Thomas if (argc > 3) { 185*2e8d1edaSArun Thomas base = strtonum(argv[3], 2, 36, &errstr); 186*2e8d1edaSArun Thomas if (errstr) { 187*2e8d1edaSArun Thomas m4errx(1, "expr: base %s invalid.", argv[3]); 188*2e8d1edaSArun Thomas } 189*2e8d1edaSArun Thomas } 190*2e8d1edaSArun Thomas if (argc > 4) { 191*2e8d1edaSArun Thomas maxdigits = strtonum(argv[4], 0, INT_MAX, &errstr); 192*2e8d1edaSArun Thomas if (errstr) { 193*2e8d1edaSArun Thomas m4errx(1, "expr: maxdigits %s invalid.", argv[4]); 194*2e8d1edaSArun Thomas } 195*2e8d1edaSArun Thomas } 196*2e8d1edaSArun Thomas if (argc > 2) 197*2e8d1edaSArun Thomas pbnumbase(expr(argv[2]), base, maxdigits); 198*2e8d1edaSArun Thomas break; 199*2e8d1edaSArun Thomas } 200*2e8d1edaSArun Thomas 201*2e8d1edaSArun Thomas case IFELTYPE: 202*2e8d1edaSArun Thomas if (argc > 4) 203*2e8d1edaSArun Thomas doifelse(argv, argc); 204*2e8d1edaSArun Thomas break; 205*2e8d1edaSArun Thomas 206*2e8d1edaSArun Thomas case IFDFTYPE: 207*2e8d1edaSArun Thomas /* 208*2e8d1edaSArun Thomas * doifdef - select one of two 209*2e8d1edaSArun Thomas * alternatives based on the existence of 210*2e8d1edaSArun Thomas * another definition 211*2e8d1edaSArun Thomas */ 212*2e8d1edaSArun Thomas if (argc > 3) { 213*2e8d1edaSArun Thomas if (lookup_macro_definition(argv[2]) != NULL) 214*2e8d1edaSArun Thomas pbstr(argv[3]); 215*2e8d1edaSArun Thomas else if (argc > 4) 216*2e8d1edaSArun Thomas pbstr(argv[4]); 217*2e8d1edaSArun Thomas } 218*2e8d1edaSArun Thomas break; 219*2e8d1edaSArun Thomas 220*2e8d1edaSArun Thomas case LENGTYPE: 221*2e8d1edaSArun Thomas /* 222*2e8d1edaSArun Thomas * dolen - find the length of the 223*2e8d1edaSArun Thomas * argument 224*2e8d1edaSArun Thomas */ 225*2e8d1edaSArun Thomas pbnum((argc > 2) ? strlen(argv[2]) : 0); 226*2e8d1edaSArun Thomas break; 227*2e8d1edaSArun Thomas 228*2e8d1edaSArun Thomas case INCRTYPE: 229*2e8d1edaSArun Thomas /* 230*2e8d1edaSArun Thomas * doincr - increment the value of the 231*2e8d1edaSArun Thomas * argument 232*2e8d1edaSArun Thomas */ 233*2e8d1edaSArun Thomas if (argc > 2) 234*2e8d1edaSArun Thomas pbnum(atoi(argv[2]) + 1); 235*2e8d1edaSArun Thomas break; 236*2e8d1edaSArun Thomas 237*2e8d1edaSArun Thomas case DECRTYPE: 238*2e8d1edaSArun Thomas /* 239*2e8d1edaSArun Thomas * dodecr - decrement the value of the 240*2e8d1edaSArun Thomas * argument 241*2e8d1edaSArun Thomas */ 242*2e8d1edaSArun Thomas if (argc > 2) 243*2e8d1edaSArun Thomas pbnum(atoi(argv[2]) - 1); 244*2e8d1edaSArun Thomas break; 245*2e8d1edaSArun Thomas 246*2e8d1edaSArun Thomas case SYSCTYPE: 247*2e8d1edaSArun Thomas /* 248*2e8d1edaSArun Thomas * dosys - execute system command 249*2e8d1edaSArun Thomas */ 250*2e8d1edaSArun Thomas if (argc > 2) { 251*2e8d1edaSArun Thomas fflush(stdout); 252*2e8d1edaSArun Thomas sysval = system(argv[2]); 253*2e8d1edaSArun Thomas } 254*2e8d1edaSArun Thomas break; 255*2e8d1edaSArun Thomas 256*2e8d1edaSArun Thomas case SYSVTYPE: 257*2e8d1edaSArun Thomas /* 258*2e8d1edaSArun Thomas * dosysval - return value of the last 259*2e8d1edaSArun Thomas * system call. 260*2e8d1edaSArun Thomas * 261*2e8d1edaSArun Thomas */ 262*2e8d1edaSArun Thomas pbnum(sysval); 263*2e8d1edaSArun Thomas break; 264*2e8d1edaSArun Thomas 265*2e8d1edaSArun Thomas case ESYSCMDTYPE: 266*2e8d1edaSArun Thomas if (argc > 2) 267*2e8d1edaSArun Thomas doesyscmd(argv[2]); 268*2e8d1edaSArun Thomas break; 269*2e8d1edaSArun Thomas case INCLTYPE: 270*2e8d1edaSArun Thomas if (argc > 2) 271*2e8d1edaSArun Thomas if (!doincl(argv[2])) 272*2e8d1edaSArun Thomas err(1, "%s at line %lu: include(%s)", 273*2e8d1edaSArun Thomas CURRENT_NAME, CURRENT_LINE, argv[2]); 274*2e8d1edaSArun Thomas break; 275*2e8d1edaSArun Thomas 276*2e8d1edaSArun Thomas case SINCTYPE: 277*2e8d1edaSArun Thomas if (argc > 2) 278*2e8d1edaSArun Thomas (void) doincl(argv[2]); 279*2e8d1edaSArun Thomas break; 280*2e8d1edaSArun Thomas #ifdef EXTENDED 281*2e8d1edaSArun Thomas case PASTTYPE: 282*2e8d1edaSArun Thomas if (argc > 2) 283*2e8d1edaSArun Thomas if (!dopaste(argv[2])) 284*2e8d1edaSArun Thomas err(1, "%s at line %lu: paste(%s)", 285*2e8d1edaSArun Thomas CURRENT_NAME, CURRENT_LINE, argv[2]); 286*2e8d1edaSArun Thomas break; 287*2e8d1edaSArun Thomas 288*2e8d1edaSArun Thomas case SPASTYPE: 289*2e8d1edaSArun Thomas if (argc > 2) 290*2e8d1edaSArun Thomas (void) dopaste(argv[2]); 291*2e8d1edaSArun Thomas break; 292*2e8d1edaSArun Thomas case FORMATTYPE: 293*2e8d1edaSArun Thomas doformat(argv, argc); 294*2e8d1edaSArun Thomas break; 295*2e8d1edaSArun Thomas #endif 296*2e8d1edaSArun Thomas case CHNQTYPE: 297*2e8d1edaSArun Thomas dochq(argv, ac); 298*2e8d1edaSArun Thomas break; 299*2e8d1edaSArun Thomas 300*2e8d1edaSArun Thomas case CHNCTYPE: 301*2e8d1edaSArun Thomas dochc(argv, argc); 302*2e8d1edaSArun Thomas break; 303*2e8d1edaSArun Thomas 304*2e8d1edaSArun Thomas case SUBSTYPE: 305*2e8d1edaSArun Thomas /* 306*2e8d1edaSArun Thomas * dosub - select substring 307*2e8d1edaSArun Thomas * 308*2e8d1edaSArun Thomas */ 309*2e8d1edaSArun Thomas if (argc > 3) 310*2e8d1edaSArun Thomas dosub(argv, argc); 311*2e8d1edaSArun Thomas break; 312*2e8d1edaSArun Thomas 313*2e8d1edaSArun Thomas case SHIFTYPE: 314*2e8d1edaSArun Thomas /* 315*2e8d1edaSArun Thomas * doshift - push back all arguments 316*2e8d1edaSArun Thomas * except the first one (i.e. skip 317*2e8d1edaSArun Thomas * argv[2]) 318*2e8d1edaSArun Thomas */ 319*2e8d1edaSArun Thomas if (argc > 3) { 320*2e8d1edaSArun Thomas for (n = argc - 1; n > 3; n--) { 321*2e8d1edaSArun Thomas pbstr(rquote); 322*2e8d1edaSArun Thomas pbstr(argv[n]); 323*2e8d1edaSArun Thomas pbstr(lquote); 324*2e8d1edaSArun Thomas pushback(COMMA); 325*2e8d1edaSArun Thomas } 326*2e8d1edaSArun Thomas pbstr(rquote); 327*2e8d1edaSArun Thomas pbstr(argv[3]); 328*2e8d1edaSArun Thomas pbstr(lquote); 329*2e8d1edaSArun Thomas } 330*2e8d1edaSArun Thomas break; 331*2e8d1edaSArun Thomas 332*2e8d1edaSArun Thomas case DIVRTYPE: 333*2e8d1edaSArun Thomas if (argc > 2 && (n = atoi(argv[2])) != 0) 334*2e8d1edaSArun Thomas dodiv(n); 335*2e8d1edaSArun Thomas else { 336*2e8d1edaSArun Thomas active = stdout; 337*2e8d1edaSArun Thomas oindex = 0; 338*2e8d1edaSArun Thomas } 339*2e8d1edaSArun Thomas break; 340*2e8d1edaSArun Thomas 341*2e8d1edaSArun Thomas case UNDVTYPE: 342*2e8d1edaSArun Thomas doundiv(argv, argc); 343*2e8d1edaSArun Thomas break; 344*2e8d1edaSArun Thomas 345*2e8d1edaSArun Thomas case DIVNTYPE: 346*2e8d1edaSArun Thomas /* 347*2e8d1edaSArun Thomas * dodivnum - return the number of 348*2e8d1edaSArun Thomas * current output diversion 349*2e8d1edaSArun Thomas */ 350*2e8d1edaSArun Thomas pbnum(oindex); 351*2e8d1edaSArun Thomas break; 352*2e8d1edaSArun Thomas 353*2e8d1edaSArun Thomas case UNDFTYPE: 354*2e8d1edaSArun Thomas /* 355*2e8d1edaSArun Thomas * doundefine - undefine a previously 356*2e8d1edaSArun Thomas * defined macro(s) or m4 keyword(s). 357*2e8d1edaSArun Thomas */ 358*2e8d1edaSArun Thomas if (argc > 2) 359*2e8d1edaSArun Thomas for (n = 2; n < argc; n++) 360*2e8d1edaSArun Thomas macro_undefine(argv[n]); 361*2e8d1edaSArun Thomas break; 362*2e8d1edaSArun Thomas 363*2e8d1edaSArun Thomas case POPDTYPE: 364*2e8d1edaSArun Thomas /* 365*2e8d1edaSArun Thomas * dopopdef - remove the topmost 366*2e8d1edaSArun Thomas * definitions of macro(s) or m4 367*2e8d1edaSArun Thomas * keyword(s). 368*2e8d1edaSArun Thomas */ 369*2e8d1edaSArun Thomas if (argc > 2) 370*2e8d1edaSArun Thomas for (n = 2; n < argc; n++) 371*2e8d1edaSArun Thomas macro_popdef(argv[n]); 372*2e8d1edaSArun Thomas break; 373*2e8d1edaSArun Thomas 374*2e8d1edaSArun Thomas case MKTMTYPE: 375*2e8d1edaSArun Thomas /* 376*2e8d1edaSArun Thomas * dotemp - create a temporary file 377*2e8d1edaSArun Thomas */ 378*2e8d1edaSArun Thomas if (argc > 2) { 379*2e8d1edaSArun Thomas int fd; 380*2e8d1edaSArun Thomas char *temp; 381*2e8d1edaSArun Thomas 382*2e8d1edaSArun Thomas temp = xstrdup(argv[2]); 383*2e8d1edaSArun Thomas 384*2e8d1edaSArun Thomas fd = mkstemp(temp); 385*2e8d1edaSArun Thomas if (fd == -1) 386*2e8d1edaSArun Thomas err(1, 387*2e8d1edaSArun Thomas "%s at line %lu: couldn't make temp file %s", 388*2e8d1edaSArun Thomas CURRENT_NAME, CURRENT_LINE, argv[2]); 389*2e8d1edaSArun Thomas close(fd); 390*2e8d1edaSArun Thomas pbstr(temp); 391*2e8d1edaSArun Thomas free(temp); 392*2e8d1edaSArun Thomas } 393*2e8d1edaSArun Thomas break; 394*2e8d1edaSArun Thomas 395*2e8d1edaSArun Thomas case TRNLTYPE: 396*2e8d1edaSArun Thomas /* 397*2e8d1edaSArun Thomas * dotranslit - replace all characters in 398*2e8d1edaSArun Thomas * the source string that appears in the 399*2e8d1edaSArun Thomas * "from" string with the corresponding 400*2e8d1edaSArun Thomas * characters in the "to" string. 401*2e8d1edaSArun Thomas */ 402*2e8d1edaSArun Thomas if (argc > 3) { 403*2e8d1edaSArun Thomas char *temp; 404*2e8d1edaSArun Thomas 405*2e8d1edaSArun Thomas temp = xalloc(strlen(argv[2])+1, NULL); 406*2e8d1edaSArun Thomas if (argc > 4) 407*2e8d1edaSArun Thomas map(temp, argv[2], argv[3], argv[4]); 408*2e8d1edaSArun Thomas else 409*2e8d1edaSArun Thomas map(temp, argv[2], argv[3], null); 410*2e8d1edaSArun Thomas pbstr(temp); 411*2e8d1edaSArun Thomas free(temp); 412*2e8d1edaSArun Thomas } else if (argc > 2) 413*2e8d1edaSArun Thomas pbstr(argv[2]); 414*2e8d1edaSArun Thomas break; 415*2e8d1edaSArun Thomas 416*2e8d1edaSArun Thomas case INDXTYPE: 417*2e8d1edaSArun Thomas /* 418*2e8d1edaSArun Thomas * doindex - find the index of the second 419*2e8d1edaSArun Thomas * argument string in the first argument 420*2e8d1edaSArun Thomas * string. -1 if not present. 421*2e8d1edaSArun Thomas */ 422*2e8d1edaSArun Thomas pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1); 423*2e8d1edaSArun Thomas break; 424*2e8d1edaSArun Thomas 425*2e8d1edaSArun Thomas case ERRPTYPE: 426*2e8d1edaSArun Thomas /* 427*2e8d1edaSArun Thomas * doerrp - print the arguments to stderr 428*2e8d1edaSArun Thomas * file 429*2e8d1edaSArun Thomas */ 430*2e8d1edaSArun Thomas if (argc > 2) { 431*2e8d1edaSArun Thomas for (n = 2; n < argc; n++) 432*2e8d1edaSArun Thomas fprintf(stderr, "%s ", argv[n]); 433*2e8d1edaSArun Thomas fprintf(stderr, "\n"); 434*2e8d1edaSArun Thomas } 435*2e8d1edaSArun Thomas break; 436*2e8d1edaSArun Thomas 437*2e8d1edaSArun Thomas case DNLNTYPE: 438*2e8d1edaSArun Thomas /* 439*2e8d1edaSArun Thomas * dodnl - eat-up-to and including 440*2e8d1edaSArun Thomas * newline 441*2e8d1edaSArun Thomas */ 442*2e8d1edaSArun Thomas while ((c = gpbc()) != '\n' && c != EOF) 443*2e8d1edaSArun Thomas ; 444*2e8d1edaSArun Thomas break; 445*2e8d1edaSArun Thomas 446*2e8d1edaSArun Thomas case M4WRTYPE: 447*2e8d1edaSArun Thomas /* 448*2e8d1edaSArun Thomas * dom4wrap - set up for 449*2e8d1edaSArun Thomas * wrap-up/wind-down activity 450*2e8d1edaSArun Thomas */ 451*2e8d1edaSArun Thomas if (argc > 2) 452*2e8d1edaSArun Thomas dom4wrap(argv[2]); 453*2e8d1edaSArun Thomas break; 454*2e8d1edaSArun Thomas 455*2e8d1edaSArun Thomas case EXITTYPE: 456*2e8d1edaSArun Thomas /* 457*2e8d1edaSArun Thomas * doexit - immediate exit from m4. 458*2e8d1edaSArun Thomas */ 459*2e8d1edaSArun Thomas killdiv(); 460*2e8d1edaSArun Thomas exit((argc > 2) ? atoi(argv[2]) : 0); 461*2e8d1edaSArun Thomas break; 462*2e8d1edaSArun Thomas 463*2e8d1edaSArun Thomas case DEFNTYPE: 464*2e8d1edaSArun Thomas if (argc > 2) 465*2e8d1edaSArun Thomas for (n = 2; n < argc; n++) 466*2e8d1edaSArun Thomas dodefn(argv[n]); 467*2e8d1edaSArun Thomas break; 468*2e8d1edaSArun Thomas 469*2e8d1edaSArun Thomas case INDIRTYPE: /* Indirect call */ 470*2e8d1edaSArun Thomas if (argc > 2) 471*2e8d1edaSArun Thomas doindir(argv, argc); 472*2e8d1edaSArun Thomas break; 473*2e8d1edaSArun Thomas 474*2e8d1edaSArun Thomas case BUILTINTYPE: /* Builtins only */ 475*2e8d1edaSArun Thomas if (argc > 2) 476*2e8d1edaSArun Thomas dobuiltin(argv, argc); 477*2e8d1edaSArun Thomas break; 478*2e8d1edaSArun Thomas 479*2e8d1edaSArun Thomas case PATSTYPE: 480*2e8d1edaSArun Thomas if (argc > 2) 481*2e8d1edaSArun Thomas dopatsubst(argv, argc); 482*2e8d1edaSArun Thomas break; 483*2e8d1edaSArun Thomas case REGEXPTYPE: 484*2e8d1edaSArun Thomas if (argc > 2) 485*2e8d1edaSArun Thomas doregexp(argv, argc); 486*2e8d1edaSArun Thomas break; 487*2e8d1edaSArun Thomas case LINETYPE: 488*2e8d1edaSArun Thomas doprintlineno(infile+ilevel); 489*2e8d1edaSArun Thomas break; 490*2e8d1edaSArun Thomas case FILENAMETYPE: 491*2e8d1edaSArun Thomas doprintfilename(infile+ilevel); 492*2e8d1edaSArun Thomas break; 493*2e8d1edaSArun Thomas case SELFTYPE: 494*2e8d1edaSArun Thomas pbstr(rquote); 495*2e8d1edaSArun Thomas pbstr(argv[1]); 496*2e8d1edaSArun Thomas pbstr(lquote); 497*2e8d1edaSArun Thomas break; 498*2e8d1edaSArun Thomas default: 499*2e8d1edaSArun Thomas m4errx(1, "eval: major botch."); 500*2e8d1edaSArun Thomas break; 501*2e8d1edaSArun Thomas } 502*2e8d1edaSArun Thomas } 503*2e8d1edaSArun Thomas 504*2e8d1edaSArun Thomas /* 505*2e8d1edaSArun Thomas * expand_macro - user-defined macro expansion 506*2e8d1edaSArun Thomas */ 507*2e8d1edaSArun Thomas void 508*2e8d1edaSArun Thomas expand_macro(const char *argv[], int argc) 509*2e8d1edaSArun Thomas { 510*2e8d1edaSArun Thomas const char *t; 511*2e8d1edaSArun Thomas const char *p; 512*2e8d1edaSArun Thomas int n; 513*2e8d1edaSArun Thomas int argno; 514*2e8d1edaSArun Thomas 515*2e8d1edaSArun Thomas t = argv[0]; /* defn string as a whole */ 516*2e8d1edaSArun Thomas p = t; 517*2e8d1edaSArun Thomas while (*p) 518*2e8d1edaSArun Thomas p++; 519*2e8d1edaSArun Thomas p--; /* last character of defn */ 520*2e8d1edaSArun Thomas while (p > t) { 521*2e8d1edaSArun Thomas if (*(p - 1) != ARGFLAG) 522*2e8d1edaSArun Thomas PUSHBACK(*p); 523*2e8d1edaSArun Thomas else { 524*2e8d1edaSArun Thomas switch (*p) { 525*2e8d1edaSArun Thomas 526*2e8d1edaSArun Thomas case '#': 527*2e8d1edaSArun Thomas pbnum(argc - 2); 528*2e8d1edaSArun Thomas break; 529*2e8d1edaSArun Thomas case '0': 530*2e8d1edaSArun Thomas case '1': 531*2e8d1edaSArun Thomas case '2': 532*2e8d1edaSArun Thomas case '3': 533*2e8d1edaSArun Thomas case '4': 534*2e8d1edaSArun Thomas case '5': 535*2e8d1edaSArun Thomas case '6': 536*2e8d1edaSArun Thomas case '7': 537*2e8d1edaSArun Thomas case '8': 538*2e8d1edaSArun Thomas case '9': 539*2e8d1edaSArun Thomas if ((argno = *p - '0') < argc - 1) 540*2e8d1edaSArun Thomas pbstr(argv[argno + 1]); 541*2e8d1edaSArun Thomas break; 542*2e8d1edaSArun Thomas case '*': 543*2e8d1edaSArun Thomas if (argc > 2) { 544*2e8d1edaSArun Thomas for (n = argc - 1; n > 2; n--) { 545*2e8d1edaSArun Thomas pbstr(argv[n]); 546*2e8d1edaSArun Thomas pushback(COMMA); 547*2e8d1edaSArun Thomas } 548*2e8d1edaSArun Thomas pbstr(argv[2]); 549*2e8d1edaSArun Thomas } 550*2e8d1edaSArun Thomas break; 551*2e8d1edaSArun Thomas case '@': 552*2e8d1edaSArun Thomas if (argc > 2) { 553*2e8d1edaSArun Thomas for (n = argc - 1; n > 2; n--) { 554*2e8d1edaSArun Thomas pbstr(rquote); 555*2e8d1edaSArun Thomas pbstr(argv[n]); 556*2e8d1edaSArun Thomas pbstr(lquote); 557*2e8d1edaSArun Thomas pushback(COMMA); 558*2e8d1edaSArun Thomas } 559*2e8d1edaSArun Thomas pbstr(rquote); 560*2e8d1edaSArun Thomas pbstr(argv[2]); 561*2e8d1edaSArun Thomas pbstr(lquote); 562*2e8d1edaSArun Thomas } 563*2e8d1edaSArun Thomas break; 564*2e8d1edaSArun Thomas default: 565*2e8d1edaSArun Thomas PUSHBACK(*p); 566*2e8d1edaSArun Thomas PUSHBACK('$'); 567*2e8d1edaSArun Thomas break; 568*2e8d1edaSArun Thomas } 569*2e8d1edaSArun Thomas p--; 570*2e8d1edaSArun Thomas } 571*2e8d1edaSArun Thomas p--; 572*2e8d1edaSArun Thomas } 573*2e8d1edaSArun Thomas if (p == t) /* do last character */ 574*2e8d1edaSArun Thomas PUSHBACK(*p); 575*2e8d1edaSArun Thomas } 576*2e8d1edaSArun Thomas 577*2e8d1edaSArun Thomas 578*2e8d1edaSArun Thomas /* 579*2e8d1edaSArun Thomas * dodefine - install definition in the table 580*2e8d1edaSArun Thomas */ 581*2e8d1edaSArun Thomas void 582*2e8d1edaSArun Thomas dodefine(const char *name, const char *defn) 583*2e8d1edaSArun Thomas { 584*2e8d1edaSArun Thomas if (!*name && !mimic_gnu) 585*2e8d1edaSArun Thomas m4errx(1, "null definition."); 586*2e8d1edaSArun Thomas else 587*2e8d1edaSArun Thomas macro_define(name, defn); 588*2e8d1edaSArun Thomas } 589*2e8d1edaSArun Thomas 590*2e8d1edaSArun Thomas /* 591*2e8d1edaSArun Thomas * dodefn - push back a quoted definition of 592*2e8d1edaSArun Thomas * the given name. 593*2e8d1edaSArun Thomas */ 594*2e8d1edaSArun Thomas static void 595*2e8d1edaSArun Thomas dodefn(const char *name) 596*2e8d1edaSArun Thomas { 597*2e8d1edaSArun Thomas struct macro_definition *p; 598*2e8d1edaSArun Thomas 599*2e8d1edaSArun Thomas if ((p = lookup_macro_definition(name)) != NULL) { 600*2e8d1edaSArun Thomas if ((p->type & TYPEMASK) == MACRTYPE) { 601*2e8d1edaSArun Thomas pbstr(rquote); 602*2e8d1edaSArun Thomas pbstr(p->defn); 603*2e8d1edaSArun Thomas pbstr(lquote); 604*2e8d1edaSArun Thomas } else { 605*2e8d1edaSArun Thomas pbstr(p->defn); 606*2e8d1edaSArun Thomas pbstr(BUILTIN_MARKER); 607*2e8d1edaSArun Thomas } 608*2e8d1edaSArun Thomas } 609*2e8d1edaSArun Thomas } 610*2e8d1edaSArun Thomas 611*2e8d1edaSArun Thomas /* 612*2e8d1edaSArun Thomas * dopushdef - install a definition in the hash table 613*2e8d1edaSArun Thomas * without removing a previous definition. Since 614*2e8d1edaSArun Thomas * each new entry is entered in *front* of the 615*2e8d1edaSArun Thomas * hash bucket, it hides a previous definition from 616*2e8d1edaSArun Thomas * lookup. 617*2e8d1edaSArun Thomas */ 618*2e8d1edaSArun Thomas static void 619*2e8d1edaSArun Thomas dopushdef(const char *name, const char *defn) 620*2e8d1edaSArun Thomas { 621*2e8d1edaSArun Thomas if (!*name && !mimic_gnu) 622*2e8d1edaSArun Thomas m4errx(1, "null definition."); 623*2e8d1edaSArun Thomas else 624*2e8d1edaSArun Thomas macro_pushdef(name, defn); 625*2e8d1edaSArun Thomas } 626*2e8d1edaSArun Thomas 627*2e8d1edaSArun Thomas /* 628*2e8d1edaSArun Thomas * dump_one_def - dump the specified definition. 629*2e8d1edaSArun Thomas */ 630*2e8d1edaSArun Thomas static void 631*2e8d1edaSArun Thomas dump_one_def(const char *name, struct macro_definition *p) 632*2e8d1edaSArun Thomas { 633*2e8d1edaSArun Thomas if (!traceout) 634*2e8d1edaSArun Thomas traceout = stderr; 635*2e8d1edaSArun Thomas if (mimic_gnu) { 636*2e8d1edaSArun Thomas if ((p->type & TYPEMASK) == MACRTYPE) 637*2e8d1edaSArun Thomas fprintf(traceout, "%s:\t%s\n", name, p->defn); 638*2e8d1edaSArun Thomas else { 639*2e8d1edaSArun Thomas fprintf(traceout, "%s:\t<%s>\n", name, p->defn); 640*2e8d1edaSArun Thomas } 641*2e8d1edaSArun Thomas } else 642*2e8d1edaSArun Thomas fprintf(traceout, "`%s'\t`%s'\n", name, p->defn); 643*2e8d1edaSArun Thomas } 644*2e8d1edaSArun Thomas 645*2e8d1edaSArun Thomas /* 646*2e8d1edaSArun Thomas * dodumpdef - dump the specified definitions in the hash 647*2e8d1edaSArun Thomas * table to stderr. If nothing is specified, the entire 648*2e8d1edaSArun Thomas * hash table is dumped. 649*2e8d1edaSArun Thomas */ 650*2e8d1edaSArun Thomas static void 651*2e8d1edaSArun Thomas dodump(const char *argv[], int argc) 652*2e8d1edaSArun Thomas { 653*2e8d1edaSArun Thomas int n; 654*2e8d1edaSArun Thomas struct macro_definition *p; 655*2e8d1edaSArun Thomas 656*2e8d1edaSArun Thomas if (argc > 2) { 657*2e8d1edaSArun Thomas for (n = 2; n < argc; n++) 658*2e8d1edaSArun Thomas if ((p = lookup_macro_definition(argv[n])) != NULL) 659*2e8d1edaSArun Thomas dump_one_def(argv[n], p); 660*2e8d1edaSArun Thomas } else 661*2e8d1edaSArun Thomas macro_for_all(dump_one_def); 662*2e8d1edaSArun Thomas } 663*2e8d1edaSArun Thomas 664*2e8d1edaSArun Thomas /* 665*2e8d1edaSArun Thomas * dotrace - mark some macros as traced/untraced depending upon on. 666*2e8d1edaSArun Thomas */ 667*2e8d1edaSArun Thomas static void 668*2e8d1edaSArun Thomas dotrace(const char *argv[], int argc, int on) 669*2e8d1edaSArun Thomas { 670*2e8d1edaSArun Thomas int n; 671*2e8d1edaSArun Thomas 672*2e8d1edaSArun Thomas if (argc > 2) { 673*2e8d1edaSArun Thomas for (n = 2; n < argc; n++) 674*2e8d1edaSArun Thomas mark_traced(argv[n], on); 675*2e8d1edaSArun Thomas } else 676*2e8d1edaSArun Thomas mark_traced(NULL, on); 677*2e8d1edaSArun Thomas } 678*2e8d1edaSArun Thomas 679*2e8d1edaSArun Thomas /* 680*2e8d1edaSArun Thomas * doifelse - select one of two alternatives - loop. 681*2e8d1edaSArun Thomas */ 682*2e8d1edaSArun Thomas static void 683*2e8d1edaSArun Thomas doifelse(const char *argv[], int argc) 684*2e8d1edaSArun Thomas { 685*2e8d1edaSArun Thomas cycle { 686*2e8d1edaSArun Thomas if (STREQ(argv[2], argv[3])) 687*2e8d1edaSArun Thomas pbstr(argv[4]); 688*2e8d1edaSArun Thomas else if (argc == 6) 689*2e8d1edaSArun Thomas pbstr(argv[5]); 690*2e8d1edaSArun Thomas else if (argc > 6) { 691*2e8d1edaSArun Thomas argv += 3; 692*2e8d1edaSArun Thomas argc -= 3; 693*2e8d1edaSArun Thomas continue; 694*2e8d1edaSArun Thomas } 695*2e8d1edaSArun Thomas break; 696*2e8d1edaSArun Thomas } 697*2e8d1edaSArun Thomas } 698*2e8d1edaSArun Thomas 699*2e8d1edaSArun Thomas /* 700*2e8d1edaSArun Thomas * doinclude - include a given file. 701*2e8d1edaSArun Thomas */ 702*2e8d1edaSArun Thomas static int 703*2e8d1edaSArun Thomas doincl(const char *ifile) 704*2e8d1edaSArun Thomas { 705*2e8d1edaSArun Thomas if (ilevel + 1 == MAXINP) 706*2e8d1edaSArun Thomas m4errx(1, "too many include files."); 707*2e8d1edaSArun Thomas if (fopen_trypath(infile+ilevel+1, ifile) != NULL) { 708*2e8d1edaSArun Thomas ilevel++; 709*2e8d1edaSArun Thomas bbase[ilevel] = bufbase = bp; 710*2e8d1edaSArun Thomas return (1); 711*2e8d1edaSArun Thomas } else 712*2e8d1edaSArun Thomas return (0); 713*2e8d1edaSArun Thomas } 714*2e8d1edaSArun Thomas 715*2e8d1edaSArun Thomas #ifdef EXTENDED 716*2e8d1edaSArun Thomas /* 717*2e8d1edaSArun Thomas * dopaste - include a given file without any 718*2e8d1edaSArun Thomas * macro processing. 719*2e8d1edaSArun Thomas */ 720*2e8d1edaSArun Thomas static int 721*2e8d1edaSArun Thomas dopaste(const char *pfile) 722*2e8d1edaSArun Thomas { 723*2e8d1edaSArun Thomas FILE *pf; 724*2e8d1edaSArun Thomas int c; 725*2e8d1edaSArun Thomas 726*2e8d1edaSArun Thomas if ((pf = fopen(pfile, "r")) != NULL) { 727*2e8d1edaSArun Thomas if (synch_lines) 728*2e8d1edaSArun Thomas fprintf(active, "#line 1 \"%s\"\n", pfile); 729*2e8d1edaSArun Thomas while ((c = getc(pf)) != EOF) 730*2e8d1edaSArun Thomas putc(c, active); 731*2e8d1edaSArun Thomas (void) fclose(pf); 732*2e8d1edaSArun Thomas emit_synchline(); 733*2e8d1edaSArun Thomas return (1); 734*2e8d1edaSArun Thomas } else 735*2e8d1edaSArun Thomas return (0); 736*2e8d1edaSArun Thomas } 737*2e8d1edaSArun Thomas #endif 738*2e8d1edaSArun Thomas 739*2e8d1edaSArun Thomas /* 740*2e8d1edaSArun Thomas * dochq - change quote characters 741*2e8d1edaSArun Thomas */ 742*2e8d1edaSArun Thomas static void 743*2e8d1edaSArun Thomas dochq(const char *argv[], int ac) 744*2e8d1edaSArun Thomas { 745*2e8d1edaSArun Thomas if (ac == 2) { 746*2e8d1edaSArun Thomas lquote[0] = LQUOTE; lquote[1] = EOS; 747*2e8d1edaSArun Thomas rquote[0] = RQUOTE; rquote[1] = EOS; 748*2e8d1edaSArun Thomas } else { 749*2e8d1edaSArun Thomas strlcpy(lquote, argv[2], sizeof(lquote)); 750*2e8d1edaSArun Thomas if (ac > 3) { 751*2e8d1edaSArun Thomas strlcpy(rquote, argv[3], sizeof(rquote)); 752*2e8d1edaSArun Thomas } else { 753*2e8d1edaSArun Thomas rquote[0] = ECOMMT; rquote[1] = EOS; 754*2e8d1edaSArun Thomas } 755*2e8d1edaSArun Thomas } 756*2e8d1edaSArun Thomas } 757*2e8d1edaSArun Thomas 758*2e8d1edaSArun Thomas /* 759*2e8d1edaSArun Thomas * dochc - change comment characters 760*2e8d1edaSArun Thomas */ 761*2e8d1edaSArun Thomas static void 762*2e8d1edaSArun Thomas dochc(const char *argv[], int argc) 763*2e8d1edaSArun Thomas { 764*2e8d1edaSArun Thomas /* XXX Note that there is no difference between no argument and a single 765*2e8d1edaSArun Thomas * empty argument. 766*2e8d1edaSArun Thomas */ 767*2e8d1edaSArun Thomas if (argc == 2) { 768*2e8d1edaSArun Thomas scommt[0] = EOS; 769*2e8d1edaSArun Thomas ecommt[0] = EOS; 770*2e8d1edaSArun Thomas } else { 771*2e8d1edaSArun Thomas strlcpy(scommt, argv[2], sizeof(scommt)); 772*2e8d1edaSArun Thomas if (argc == 3) { 773*2e8d1edaSArun Thomas ecommt[0] = ECOMMT; ecommt[1] = EOS; 774*2e8d1edaSArun Thomas } else { 775*2e8d1edaSArun Thomas strlcpy(ecommt, argv[3], sizeof(ecommt)); 776*2e8d1edaSArun Thomas } 777*2e8d1edaSArun Thomas } 778*2e8d1edaSArun Thomas } 779*2e8d1edaSArun Thomas 780*2e8d1edaSArun Thomas /* 781*2e8d1edaSArun Thomas * dom4wrap - expand text at EOF 782*2e8d1edaSArun Thomas */ 783*2e8d1edaSArun Thomas static void 784*2e8d1edaSArun Thomas dom4wrap(const char *text) 785*2e8d1edaSArun Thomas { 786*2e8d1edaSArun Thomas if (wrapindex >= maxwraps) { 787*2e8d1edaSArun Thomas if (maxwraps == 0) 788*2e8d1edaSArun Thomas maxwraps = 16; 789*2e8d1edaSArun Thomas else 790*2e8d1edaSArun Thomas maxwraps *= 2; 791*2e8d1edaSArun Thomas m4wraps = xrealloc(m4wraps, maxwraps * sizeof(*m4wraps), 792*2e8d1edaSArun Thomas "too many m4wraps"); 793*2e8d1edaSArun Thomas } 794*2e8d1edaSArun Thomas m4wraps[wrapindex++] = xstrdup(text); 795*2e8d1edaSArun Thomas } 796*2e8d1edaSArun Thomas 797*2e8d1edaSArun Thomas /* 798*2e8d1edaSArun Thomas * dodivert - divert the output to a temporary file 799*2e8d1edaSArun Thomas */ 800*2e8d1edaSArun Thomas static void 801*2e8d1edaSArun Thomas dodiv(int n) 802*2e8d1edaSArun Thomas { 803*2e8d1edaSArun Thomas int fd; 804*2e8d1edaSArun Thomas 805*2e8d1edaSArun Thomas oindex = n; 806*2e8d1edaSArun Thomas if (n >= maxout) { 807*2e8d1edaSArun Thomas if (mimic_gnu) 808*2e8d1edaSArun Thomas resizedivs(n + 10); 809*2e8d1edaSArun Thomas else 810*2e8d1edaSArun Thomas n = 0; /* bitbucket */ 811*2e8d1edaSArun Thomas } 812*2e8d1edaSArun Thomas 813*2e8d1edaSArun Thomas if (n < 0) 814*2e8d1edaSArun Thomas n = 0; /* bitbucket */ 815*2e8d1edaSArun Thomas if (outfile[n] == NULL) { 816*2e8d1edaSArun Thomas char fname[] = _PATH_DIVNAME; 817*2e8d1edaSArun Thomas 818*2e8d1edaSArun Thomas if ((fd = mkstemp(fname)) < 0 || 819*2e8d1edaSArun Thomas (outfile[n] = fdopen(fd, "w+")) == NULL) 820*2e8d1edaSArun Thomas err(1, "%s: cannot divert", fname); 821*2e8d1edaSArun Thomas if (unlink(fname) == -1) 822*2e8d1edaSArun Thomas err(1, "%s: cannot unlink", fname); 823*2e8d1edaSArun Thomas } 824*2e8d1edaSArun Thomas active = outfile[n]; 825*2e8d1edaSArun Thomas } 826*2e8d1edaSArun Thomas 827*2e8d1edaSArun Thomas /* 828*2e8d1edaSArun Thomas * doundivert - undivert a specified output, or all 829*2e8d1edaSArun Thomas * other outputs, in numerical order. 830*2e8d1edaSArun Thomas */ 831*2e8d1edaSArun Thomas static void 832*2e8d1edaSArun Thomas doundiv(const char *argv[], int argc) 833*2e8d1edaSArun Thomas { 834*2e8d1edaSArun Thomas int ind; 835*2e8d1edaSArun Thomas int n; 836*2e8d1edaSArun Thomas 837*2e8d1edaSArun Thomas if (argc > 2) { 838*2e8d1edaSArun Thomas for (ind = 2; ind < argc; ind++) { 839*2e8d1edaSArun Thomas const char *errstr; 840*2e8d1edaSArun Thomas n = strtonum(argv[ind], 1, INT_MAX, &errstr); 841*2e8d1edaSArun Thomas if (errstr) { 842*2e8d1edaSArun Thomas if (errno == EINVAL && mimic_gnu) 843*2e8d1edaSArun Thomas getdivfile(argv[ind]); 844*2e8d1edaSArun Thomas } else { 845*2e8d1edaSArun Thomas if (n < maxout && outfile[n] != NULL) 846*2e8d1edaSArun Thomas getdiv(n); 847*2e8d1edaSArun Thomas } 848*2e8d1edaSArun Thomas } 849*2e8d1edaSArun Thomas } 850*2e8d1edaSArun Thomas else 851*2e8d1edaSArun Thomas for (n = 1; n < maxout; n++) 852*2e8d1edaSArun Thomas if (outfile[n] != NULL) 853*2e8d1edaSArun Thomas getdiv(n); 854*2e8d1edaSArun Thomas } 855*2e8d1edaSArun Thomas 856*2e8d1edaSArun Thomas /* 857*2e8d1edaSArun Thomas * dosub - select substring 858*2e8d1edaSArun Thomas */ 859*2e8d1edaSArun Thomas static void 860*2e8d1edaSArun Thomas dosub(const char *argv[], int argc) 861*2e8d1edaSArun Thomas { 862*2e8d1edaSArun Thomas const char *ap, *fc, *k; 863*2e8d1edaSArun Thomas int nc; 864*2e8d1edaSArun Thomas 865*2e8d1edaSArun Thomas ap = argv[2]; /* target string */ 866*2e8d1edaSArun Thomas #ifdef EXPR 867*2e8d1edaSArun Thomas fc = ap + expr(argv[3]); /* first char */ 868*2e8d1edaSArun Thomas #else 869*2e8d1edaSArun Thomas fc = ap + atoi(argv[3]); /* first char */ 870*2e8d1edaSArun Thomas #endif 871*2e8d1edaSArun Thomas nc = strlen(fc); 872*2e8d1edaSArun Thomas if (argc >= 5) 873*2e8d1edaSArun Thomas #ifdef EXPR 874*2e8d1edaSArun Thomas nc = min(nc, expr(argv[4])); 875*2e8d1edaSArun Thomas #else 876*2e8d1edaSArun Thomas nc = min(nc, atoi(argv[4])); 877*2e8d1edaSArun Thomas #endif 878*2e8d1edaSArun Thomas if (fc >= ap && fc < ap + strlen(ap)) 879*2e8d1edaSArun Thomas for (k = fc + nc - 1; k >= fc; k--) 880*2e8d1edaSArun Thomas pushback(*k); 881*2e8d1edaSArun Thomas } 882*2e8d1edaSArun Thomas 883*2e8d1edaSArun Thomas /* 884*2e8d1edaSArun Thomas * map: 885*2e8d1edaSArun Thomas * map every character of s1 that is specified in from 886*2e8d1edaSArun Thomas * into s3 and replace in s. (source s1 remains untouched) 887*2e8d1edaSArun Thomas * 888*2e8d1edaSArun Thomas * This is a standard implementation of map(s,from,to) function of ICON 889*2e8d1edaSArun Thomas * language. Within mapvec, we replace every character of "from" with 890*2e8d1edaSArun Thomas * the corresponding character in "to". If "to" is shorter than "from", 891*2e8d1edaSArun Thomas * than the corresponding entries are null, which means that those 892*2e8d1edaSArun Thomas * characters dissapear altogether. Furthermore, imagine 893*2e8d1edaSArun Thomas * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, 894*2e8d1edaSArun Thomas * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' 895*2e8d1edaSArun Thomas * ultimately maps to `*'. In order to achieve this effect in an efficient 896*2e8d1edaSArun Thomas * manner (i.e. without multiple passes over the destination string), we 897*2e8d1edaSArun Thomas * loop over mapvec, starting with the initial source character. if the 898*2e8d1edaSArun Thomas * character value (dch) in this location is different than the source 899*2e8d1edaSArun Thomas * character (sch), sch becomes dch, once again to index into mapvec, until 900*2e8d1edaSArun Thomas * the character value stabilizes (i.e. sch = dch, in other words 901*2e8d1edaSArun Thomas * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary 902*2e8d1edaSArun Thomas * character, it will stabilize, since mapvec[0] == 0 at all times. At the 903*2e8d1edaSArun Thomas * end, we restore mapvec* back to normal where mapvec[n] == n for 904*2e8d1edaSArun Thomas * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is 905*2e8d1edaSArun Thomas * about 5 times faster than any algorithm that makes multiple passes over 906*2e8d1edaSArun Thomas * destination string. 907*2e8d1edaSArun Thomas */ 908*2e8d1edaSArun Thomas static void 909*2e8d1edaSArun Thomas map(char *dest, const char *src, const char *from, const char *to) 910*2e8d1edaSArun Thomas { 911*2e8d1edaSArun Thomas const char *tmp; 912*2e8d1edaSArun Thomas unsigned char sch, dch; 913*2e8d1edaSArun Thomas static char frombis[257]; 914*2e8d1edaSArun Thomas static char tobis[257]; 915*2e8d1edaSArun Thomas static unsigned char mapvec[256] = { 916*2e8d1edaSArun Thomas 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 917*2e8d1edaSArun Thomas 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 918*2e8d1edaSArun Thomas 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 919*2e8d1edaSArun Thomas 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 920*2e8d1edaSArun Thomas 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 921*2e8d1edaSArun Thomas 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 922*2e8d1edaSArun Thomas 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 923*2e8d1edaSArun Thomas 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 924*2e8d1edaSArun Thomas 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 925*2e8d1edaSArun Thomas 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 926*2e8d1edaSArun Thomas 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 927*2e8d1edaSArun Thomas 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 928*2e8d1edaSArun Thomas 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 929*2e8d1edaSArun Thomas 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 930*2e8d1edaSArun Thomas 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 931*2e8d1edaSArun Thomas 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 932*2e8d1edaSArun Thomas 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 933*2e8d1edaSArun Thomas 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 934*2e8d1edaSArun Thomas }; 935*2e8d1edaSArun Thomas 936*2e8d1edaSArun Thomas if (*src) { 937*2e8d1edaSArun Thomas if (mimic_gnu) { 938*2e8d1edaSArun Thomas /* 939*2e8d1edaSArun Thomas * expand character ranges on the fly 940*2e8d1edaSArun Thomas */ 941*2e8d1edaSArun Thomas from = handledash(frombis, frombis + 256, from); 942*2e8d1edaSArun Thomas to = handledash(tobis, tobis + 256, to); 943*2e8d1edaSArun Thomas } 944*2e8d1edaSArun Thomas tmp = from; 945*2e8d1edaSArun Thomas /* 946*2e8d1edaSArun Thomas * create a mapping between "from" and 947*2e8d1edaSArun Thomas * "to" 948*2e8d1edaSArun Thomas */ 949*2e8d1edaSArun Thomas while (*from) 950*2e8d1edaSArun Thomas mapvec[(unsigned char)(*from++)] = (*to) ? 951*2e8d1edaSArun Thomas (unsigned char)(*to++) : 0; 952*2e8d1edaSArun Thomas 953*2e8d1edaSArun Thomas while (*src) { 954*2e8d1edaSArun Thomas sch = (unsigned char)(*src++); 955*2e8d1edaSArun Thomas dch = mapvec[sch]; 956*2e8d1edaSArun Thomas while (dch != sch) { 957*2e8d1edaSArun Thomas sch = dch; 958*2e8d1edaSArun Thomas dch = mapvec[sch]; 959*2e8d1edaSArun Thomas } 960*2e8d1edaSArun Thomas if ((*dest = (char)dch)) 961*2e8d1edaSArun Thomas dest++; 962*2e8d1edaSArun Thomas } 963*2e8d1edaSArun Thomas /* 964*2e8d1edaSArun Thomas * restore all the changed characters 965*2e8d1edaSArun Thomas */ 966*2e8d1edaSArun Thomas while (*tmp) { 967*2e8d1edaSArun Thomas mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp); 968*2e8d1edaSArun Thomas tmp++; 969*2e8d1edaSArun Thomas } 970*2e8d1edaSArun Thomas } 971*2e8d1edaSArun Thomas *dest = '\0'; 972*2e8d1edaSArun Thomas } 973*2e8d1edaSArun Thomas 974*2e8d1edaSArun Thomas 975*2e8d1edaSArun Thomas /* 976*2e8d1edaSArun Thomas * handledash: 977*2e8d1edaSArun Thomas * use buffer to copy the src string, expanding character ranges 978*2e8d1edaSArun Thomas * on the way. 979*2e8d1edaSArun Thomas */ 980*2e8d1edaSArun Thomas static const char * 981*2e8d1edaSArun Thomas handledash(char *buffer, char *end, const char *src) 982*2e8d1edaSArun Thomas { 983*2e8d1edaSArun Thomas char *p; 984*2e8d1edaSArun Thomas 985*2e8d1edaSArun Thomas p = buffer; 986*2e8d1edaSArun Thomas while(*src) { 987*2e8d1edaSArun Thomas if (src[1] == '-' && src[2]) { 988*2e8d1edaSArun Thomas unsigned char i; 989*2e8d1edaSArun Thomas if ((unsigned char)src[0] <= (unsigned char)src[2]) { 990*2e8d1edaSArun Thomas for (i = (unsigned char)src[0]; 991*2e8d1edaSArun Thomas i <= (unsigned char)src[2]; i++) { 992*2e8d1edaSArun Thomas *p++ = i; 993*2e8d1edaSArun Thomas if (p == end) { 994*2e8d1edaSArun Thomas *p = '\0'; 995*2e8d1edaSArun Thomas return buffer; 996*2e8d1edaSArun Thomas } 997*2e8d1edaSArun Thomas } 998*2e8d1edaSArun Thomas } else { 999*2e8d1edaSArun Thomas for (i = (unsigned char)src[0]; 1000*2e8d1edaSArun Thomas i >= (unsigned char)src[2]; i--) { 1001*2e8d1edaSArun Thomas *p++ = i; 1002*2e8d1edaSArun Thomas if (p == end) { 1003*2e8d1edaSArun Thomas *p = '\0'; 1004*2e8d1edaSArun Thomas return buffer; 1005*2e8d1edaSArun Thomas } 1006*2e8d1edaSArun Thomas } 1007*2e8d1edaSArun Thomas } 1008*2e8d1edaSArun Thomas src += 3; 1009*2e8d1edaSArun Thomas } else 1010*2e8d1edaSArun Thomas *p++ = *src++; 1011*2e8d1edaSArun Thomas if (p == end) 1012*2e8d1edaSArun Thomas break; 1013*2e8d1edaSArun Thomas } 1014*2e8d1edaSArun Thomas *p = '\0'; 1015*2e8d1edaSArun Thomas return buffer; 1016*2e8d1edaSArun Thomas } 1017