1*423624b7Sespie /* $OpenBSD: eval.c,v 1.23 2000/01/05 16:06:14 espie Exp $ */ 2aa676ce1Smillert /* $NetBSD: eval.c,v 1.7 1996/11/10 21:21:29 pk Exp $ */ 3df930be7Sderaadt 4df930be7Sderaadt /* 5df930be7Sderaadt * Copyright (c) 1989, 1993 6df930be7Sderaadt * The Regents of the University of California. All rights reserved. 7df930be7Sderaadt * 8df930be7Sderaadt * This code is derived from software contributed to Berkeley by 9df930be7Sderaadt * Ozan Yigit at York University. 10df930be7Sderaadt * 11df930be7Sderaadt * Redistribution and use in source and binary forms, with or without 12df930be7Sderaadt * modification, are permitted provided that the following conditions 13df930be7Sderaadt * are met: 14df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright 15df930be7Sderaadt * notice, this list of conditions and the following disclaimer. 16df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 17df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the 18df930be7Sderaadt * documentation and/or other materials provided with the distribution. 19df930be7Sderaadt * 3. All advertising materials mentioning features or use of this software 20df930be7Sderaadt * must display the following acknowledgement: 21df930be7Sderaadt * This product includes software developed by the University of 22df930be7Sderaadt * California, Berkeley and its contributors. 23df930be7Sderaadt * 4. Neither the name of the University nor the names of its contributors 24df930be7Sderaadt * may be used to endorse or promote products derived from this software 25df930be7Sderaadt * without specific prior written permission. 26df930be7Sderaadt * 27df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37df930be7Sderaadt * SUCH DAMAGE. 38df930be7Sderaadt */ 39df930be7Sderaadt 40df930be7Sderaadt #ifndef lint 41df930be7Sderaadt #if 0 42df930be7Sderaadt static char sccsid[] = "@(#)eval.c 8.2 (Berkeley) 4/27/95"; 43df930be7Sderaadt #else 44*423624b7Sespie static char rcsid[] = "$OpenBSD: eval.c,v 1.23 2000/01/05 16:06:14 espie Exp $"; 45df930be7Sderaadt #endif 46df930be7Sderaadt #endif /* not lint */ 47df930be7Sderaadt 48df930be7Sderaadt /* 49df930be7Sderaadt * eval.c 50df930be7Sderaadt * Facility: m4 macro processor 51df930be7Sderaadt * by: oz 52df930be7Sderaadt */ 53df930be7Sderaadt 54df930be7Sderaadt #include <sys/types.h> 55df930be7Sderaadt #include <errno.h> 56df930be7Sderaadt #include <unistd.h> 57df930be7Sderaadt #include <stdio.h> 58df930be7Sderaadt #include <stdlib.h> 593f42598dSespie #include <stddef.h> 60df930be7Sderaadt #include <string.h> 61445b77f7Smillert #include <fcntl.h> 6281c2181eSespie #include <err.h> 63df930be7Sderaadt #include "mdef.h" 64df930be7Sderaadt #include "stdd.h" 65df930be7Sderaadt #include "extern.h" 66df930be7Sderaadt #include "pathnames.h" 67df930be7Sderaadt 68bb34cd6cSespie static void dodefn __P((const char *)); 69bb34cd6cSespie static void dopushdef __P((const char *, const char *)); 70bb34cd6cSespie static void dodump __P((const char *[], int)); 71bb34cd6cSespie static void doifelse __P((const char *[], int)); 72bb34cd6cSespie static int doincl __P((const char *)); 73bb34cd6cSespie static int dopaste __P((const char *)); 74bb34cd6cSespie static void dochq __P((const char *[], int)); 75bb34cd6cSespie static void dochc __P((const char *[], int)); 76bb34cd6cSespie static void dodiv __P((int)); 77bb34cd6cSespie static void doundiv __P((const char *[], int)); 78bb34cd6cSespie static void dosub __P((const char *[], int)); 79bb34cd6cSespie static void map __P((char *, const char *, const char *, const char *)); 80df930be7Sderaadt /* 81df930be7Sderaadt * eval - evaluate built-in macros. 82df930be7Sderaadt * argc - number of elements in argv. 83df930be7Sderaadt * argv - element vector : 84df930be7Sderaadt * argv[0] = definition of a user 85df930be7Sderaadt * macro or nil if built-in. 86df930be7Sderaadt * argv[1] = name of the macro or 87df930be7Sderaadt * built-in. 88df930be7Sderaadt * argv[2] = parameters to user-defined 89df930be7Sderaadt * . macro or built-in. 90df930be7Sderaadt * . 91df930be7Sderaadt * 92df930be7Sderaadt * Note that the minimum value for argc is 3. A call in the form 93df930be7Sderaadt * of macro-or-builtin() will result in: 94df930be7Sderaadt * argv[0] = nullstr 95df930be7Sderaadt * argv[1] = macro-or-builtin 96df930be7Sderaadt * argv[2] = nullstr 97df930be7Sderaadt */ 98df930be7Sderaadt 99df930be7Sderaadt void 100df930be7Sderaadt eval(argv, argc, td) 101bb34cd6cSespie const char *argv[]; 10253f6f6bfSespie int argc; 10353f6f6bfSespie int td; 104df930be7Sderaadt { 10553f6f6bfSespie int c, n; 106df930be7Sderaadt static int sysval = 0; 107df930be7Sderaadt 108df930be7Sderaadt #ifdef DEBUG 109df930be7Sderaadt printf("argc = %d\n", argc); 110df930be7Sderaadt for (n = 0; n < argc; n++) 111df930be7Sderaadt printf("argv[%d] = %s\n", n, argv[n]); 112df930be7Sderaadt #endif 113718b194dSespie 114718b194dSespie if (td & RECDEF) 115718b194dSespie errx(1, "expanding recursive definition for %s", argv[1]); 116df930be7Sderaadt /* 117df930be7Sderaadt * if argc == 3 and argv[2] is null, then we 118df930be7Sderaadt * have macro-or-builtin() type call. We adjust 119df930be7Sderaadt * argc to avoid further checking.. 120df930be7Sderaadt */ 121df930be7Sderaadt if (argc == 3 && !*(argv[2])) 122df930be7Sderaadt argc--; 123df930be7Sderaadt 124718b194dSespie switch (td & TYPEMASK) { 125df930be7Sderaadt 126df930be7Sderaadt case DEFITYPE: 127df930be7Sderaadt if (argc > 2) 128df930be7Sderaadt dodefine(argv[2], (argc > 3) ? argv[3] : null); 129df930be7Sderaadt break; 130df930be7Sderaadt 131df930be7Sderaadt case PUSDTYPE: 132df930be7Sderaadt if (argc > 2) 133df930be7Sderaadt dopushdef(argv[2], (argc > 3) ? argv[3] : null); 134df930be7Sderaadt break; 135df930be7Sderaadt 136df930be7Sderaadt case DUMPTYPE: 137df930be7Sderaadt dodump(argv, argc); 138df930be7Sderaadt break; 139df930be7Sderaadt 140df930be7Sderaadt case EXPRTYPE: 141df930be7Sderaadt /* 142df930be7Sderaadt * doexpr - evaluate arithmetic 143df930be7Sderaadt * expression 144df930be7Sderaadt */ 145df930be7Sderaadt if (argc > 2) 146df930be7Sderaadt pbnum(expr(argv[2])); 147df930be7Sderaadt break; 148df930be7Sderaadt 149df930be7Sderaadt case IFELTYPE: 150df930be7Sderaadt if (argc > 4) 151df930be7Sderaadt doifelse(argv, argc); 152df930be7Sderaadt break; 153df930be7Sderaadt 154df930be7Sderaadt case IFDFTYPE: 155df930be7Sderaadt /* 156df930be7Sderaadt * doifdef - select one of two 157df930be7Sderaadt * alternatives based on the existence of 158df930be7Sderaadt * another definition 159df930be7Sderaadt */ 160df930be7Sderaadt if (argc > 3) { 161df930be7Sderaadt if (lookup(argv[2]) != nil) 162df930be7Sderaadt pbstr(argv[3]); 163df930be7Sderaadt else if (argc > 4) 164df930be7Sderaadt pbstr(argv[4]); 165df930be7Sderaadt } 166df930be7Sderaadt break; 167df930be7Sderaadt 168df930be7Sderaadt case LENGTYPE: 169df930be7Sderaadt /* 170df930be7Sderaadt * dolen - find the length of the 171df930be7Sderaadt * argument 172df930be7Sderaadt */ 173df930be7Sderaadt pbnum((argc > 2) ? strlen(argv[2]) : 0); 174df930be7Sderaadt break; 175df930be7Sderaadt 176df930be7Sderaadt case INCRTYPE: 177df930be7Sderaadt /* 178df930be7Sderaadt * doincr - increment the value of the 179df930be7Sderaadt * argument 180df930be7Sderaadt */ 181df930be7Sderaadt if (argc > 2) 182df930be7Sderaadt pbnum(atoi(argv[2]) + 1); 183df930be7Sderaadt break; 184df930be7Sderaadt 185df930be7Sderaadt case DECRTYPE: 186df930be7Sderaadt /* 187df930be7Sderaadt * dodecr - decrement the value of the 188df930be7Sderaadt * argument 189df930be7Sderaadt */ 190df930be7Sderaadt if (argc > 2) 191df930be7Sderaadt pbnum(atoi(argv[2]) - 1); 192df930be7Sderaadt break; 193df930be7Sderaadt 194df930be7Sderaadt case SYSCTYPE: 195df930be7Sderaadt /* 196df930be7Sderaadt * dosys - execute system command 197df930be7Sderaadt */ 198df930be7Sderaadt if (argc > 2) 199df930be7Sderaadt sysval = system(argv[2]); 200df930be7Sderaadt break; 201df930be7Sderaadt 202df930be7Sderaadt case SYSVTYPE: 203df930be7Sderaadt /* 204df930be7Sderaadt * dosysval - return value of the last 205df930be7Sderaadt * system call. 206df930be7Sderaadt * 207df930be7Sderaadt */ 208df930be7Sderaadt pbnum(sysval); 209df930be7Sderaadt break; 210df930be7Sderaadt 211df930be7Sderaadt case INCLTYPE: 212df930be7Sderaadt if (argc > 2) 213df930be7Sderaadt if (!doincl(argv[2])) 21481c2181eSespie err(1, "%s", argv[2]); 215df930be7Sderaadt break; 216df930be7Sderaadt 217df930be7Sderaadt case SINCTYPE: 218df930be7Sderaadt if (argc > 2) 219df930be7Sderaadt (void) doincl(argv[2]); 220df930be7Sderaadt break; 221df930be7Sderaadt #ifdef EXTENDED 222df930be7Sderaadt case PASTTYPE: 223df930be7Sderaadt if (argc > 2) 224df930be7Sderaadt if (!dopaste(argv[2])) 22581c2181eSespie err(1, "%s", argv[2]); 226df930be7Sderaadt break; 227df930be7Sderaadt 228df930be7Sderaadt case SPASTYPE: 229df930be7Sderaadt if (argc > 2) 230df930be7Sderaadt (void) dopaste(argv[2]); 231df930be7Sderaadt break; 232df930be7Sderaadt #endif 233df930be7Sderaadt case CHNQTYPE: 234df930be7Sderaadt dochq(argv, argc); 235df930be7Sderaadt break; 236df930be7Sderaadt 237df930be7Sderaadt case CHNCTYPE: 238df930be7Sderaadt dochc(argv, argc); 239df930be7Sderaadt break; 240df930be7Sderaadt 241df930be7Sderaadt case SUBSTYPE: 242df930be7Sderaadt /* 243df930be7Sderaadt * dosub - select substring 244df930be7Sderaadt * 245df930be7Sderaadt */ 246df930be7Sderaadt if (argc > 3) 247df930be7Sderaadt dosub(argv, argc); 248df930be7Sderaadt break; 249df930be7Sderaadt 250df930be7Sderaadt case SHIFTYPE: 251df930be7Sderaadt /* 252df930be7Sderaadt * doshift - push back all arguments 253df930be7Sderaadt * except the first one (i.e. skip 254df930be7Sderaadt * argv[2]) 255df930be7Sderaadt */ 256df930be7Sderaadt if (argc > 3) { 257df930be7Sderaadt for (n = argc - 1; n > 3; n--) { 2583a73db8cSderaadt pbstr(rquote); 259df930be7Sderaadt pbstr(argv[n]); 2603a73db8cSderaadt pbstr(lquote); 261aa676ce1Smillert putback(COMMA); 262df930be7Sderaadt } 2633a73db8cSderaadt pbstr(rquote); 264df930be7Sderaadt pbstr(argv[3]); 2653a73db8cSderaadt pbstr(lquote); 266df930be7Sderaadt } 267df930be7Sderaadt break; 268df930be7Sderaadt 269df930be7Sderaadt case DIVRTYPE: 270df930be7Sderaadt if (argc > 2 && (n = atoi(argv[2])) != 0) 271df930be7Sderaadt dodiv(n); 272df930be7Sderaadt else { 273df930be7Sderaadt active = stdout; 274df930be7Sderaadt oindex = 0; 275df930be7Sderaadt } 276df930be7Sderaadt break; 277df930be7Sderaadt 278df930be7Sderaadt case UNDVTYPE: 279df930be7Sderaadt doundiv(argv, argc); 280df930be7Sderaadt break; 281df930be7Sderaadt 282df930be7Sderaadt case DIVNTYPE: 283df930be7Sderaadt /* 284df930be7Sderaadt * dodivnum - return the number of 285df930be7Sderaadt * current output diversion 286df930be7Sderaadt */ 287df930be7Sderaadt pbnum(oindex); 288df930be7Sderaadt break; 289df930be7Sderaadt 290df930be7Sderaadt case UNDFTYPE: 291df930be7Sderaadt /* 292df930be7Sderaadt * doundefine - undefine a previously 293df930be7Sderaadt * defined macro(s) or m4 keyword(s). 294df930be7Sderaadt */ 295df930be7Sderaadt if (argc > 2) 296df930be7Sderaadt for (n = 2; n < argc; n++) 297df930be7Sderaadt remhash(argv[n], ALL); 298df930be7Sderaadt break; 299df930be7Sderaadt 300df930be7Sderaadt case POPDTYPE: 301df930be7Sderaadt /* 302df930be7Sderaadt * dopopdef - remove the topmost 303df930be7Sderaadt * definitions of macro(s) or m4 304df930be7Sderaadt * keyword(s). 305df930be7Sderaadt */ 306df930be7Sderaadt if (argc > 2) 307df930be7Sderaadt for (n = 2; n < argc; n++) 308df930be7Sderaadt remhash(argv[n], TOP); 309df930be7Sderaadt break; 310df930be7Sderaadt 311df930be7Sderaadt case MKTMTYPE: 312df930be7Sderaadt /* 313df930be7Sderaadt * dotemp - create a temporary file 314df930be7Sderaadt */ 31501e71e69Sespie if (argc > 2) { 31601e71e69Sespie int fd; 317bb34cd6cSespie char *temp; 31801e71e69Sespie 319bb34cd6cSespie temp = xstrdup(argv[2]); 320bb34cd6cSespie 321bb34cd6cSespie fd = mkstemp(temp); 32201e71e69Sespie if (fd == -1) 32301e71e69Sespie err(1, "couldn't make temp file %s", argv[2]); 32401e71e69Sespie close(fd); 325bb34cd6cSespie pbstr(temp); 326bb34cd6cSespie free(temp); 32701e71e69Sespie } 328df930be7Sderaadt break; 329df930be7Sderaadt 330df930be7Sderaadt case TRNLTYPE: 331df930be7Sderaadt /* 332df930be7Sderaadt * dotranslit - replace all characters in 333df930be7Sderaadt * the source string that appears in the 334df930be7Sderaadt * "from" string with the corresponding 335df930be7Sderaadt * characters in the "to" string. 336df930be7Sderaadt */ 337df930be7Sderaadt if (argc > 3) { 3387d3e0b6bSderaadt char temp[STRSPMAX+1]; 339df930be7Sderaadt if (argc > 4) 340df930be7Sderaadt map(temp, argv[2], argv[3], argv[4]); 341df930be7Sderaadt else 342df930be7Sderaadt map(temp, argv[2], argv[3], null); 343df930be7Sderaadt pbstr(temp); 3447d3e0b6bSderaadt } else if (argc > 2) 345df930be7Sderaadt pbstr(argv[2]); 346df930be7Sderaadt break; 347df930be7Sderaadt 348df930be7Sderaadt case INDXTYPE: 349df930be7Sderaadt /* 350df930be7Sderaadt * doindex - find the index of the second 351df930be7Sderaadt * argument string in the first argument 352df930be7Sderaadt * string. -1 if not present. 353df930be7Sderaadt */ 354df930be7Sderaadt pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1); 355df930be7Sderaadt break; 356df930be7Sderaadt 357df930be7Sderaadt case ERRPTYPE: 358df930be7Sderaadt /* 359df930be7Sderaadt * doerrp - print the arguments to stderr 360df930be7Sderaadt * file 361df930be7Sderaadt */ 362df930be7Sderaadt if (argc > 2) { 363df930be7Sderaadt for (n = 2; n < argc; n++) 364df930be7Sderaadt fprintf(stderr, "%s ", argv[n]); 365df930be7Sderaadt fprintf(stderr, "\n"); 366df930be7Sderaadt } 367df930be7Sderaadt break; 368df930be7Sderaadt 369df930be7Sderaadt case DNLNTYPE: 370df930be7Sderaadt /* 371df930be7Sderaadt * dodnl - eat-up-to and including 372df930be7Sderaadt * newline 373df930be7Sderaadt */ 374df930be7Sderaadt while ((c = gpbc()) != '\n' && c != EOF) 375df930be7Sderaadt ; 376df930be7Sderaadt break; 377df930be7Sderaadt 378df930be7Sderaadt case M4WRTYPE: 379df930be7Sderaadt /* 380df930be7Sderaadt * dom4wrap - set up for 381df930be7Sderaadt * wrap-up/wind-down activity 382df930be7Sderaadt */ 383df930be7Sderaadt m4wraps = (argc > 2) ? xstrdup(argv[2]) : null; 384df930be7Sderaadt break; 385df930be7Sderaadt 386df930be7Sderaadt case EXITTYPE: 387df930be7Sderaadt /* 388df930be7Sderaadt * doexit - immediate exit from m4. 389df930be7Sderaadt */ 390df930be7Sderaadt killdiv(); 391df930be7Sderaadt exit((argc > 2) ? atoi(argv[2]) : 0); 392df930be7Sderaadt break; 393df930be7Sderaadt 394df930be7Sderaadt case DEFNTYPE: 395df930be7Sderaadt if (argc > 2) 396df930be7Sderaadt for (n = 2; n < argc; n++) 397df930be7Sderaadt dodefn(argv[n]); 398df930be7Sderaadt break; 399df930be7Sderaadt 400*423624b7Sespie case SELFTYPE: 401*423624b7Sespie pbstr(rquote); 402*423624b7Sespie pbstr(argv[1]); 403*423624b7Sespie pbstr(lquote); 404*423624b7Sespie break; 405df930be7Sderaadt default: 40681c2181eSespie errx(1, "eval: major botch."); 407df930be7Sderaadt break; 408df930be7Sderaadt } 409df930be7Sderaadt } 410df930be7Sderaadt 411df930be7Sderaadt char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */ 412df930be7Sderaadt 413df930be7Sderaadt /* 414df930be7Sderaadt * expand - user-defined macro expansion 415df930be7Sderaadt */ 416df930be7Sderaadt void 417df930be7Sderaadt expand(argv, argc) 418bb34cd6cSespie const char *argv[]; 41953f6f6bfSespie int argc; 420df930be7Sderaadt { 421bb34cd6cSespie const char *t; 422bb34cd6cSespie const char *p; 42353f6f6bfSespie int n; 42453f6f6bfSespie int argno; 425df930be7Sderaadt 426df930be7Sderaadt t = argv[0]; /* defn string as a whole */ 427df930be7Sderaadt p = t; 428df930be7Sderaadt while (*p) 429df930be7Sderaadt p++; 430df930be7Sderaadt p--; /* last character of defn */ 431df930be7Sderaadt while (p > t) { 432df930be7Sderaadt if (*(p - 1) != ARGFLAG) 433df930be7Sderaadt putback(*p); 434df930be7Sderaadt else { 435df930be7Sderaadt switch (*p) { 436df930be7Sderaadt 437df930be7Sderaadt case '#': 438df930be7Sderaadt pbnum(argc - 2); 439df930be7Sderaadt break; 440df930be7Sderaadt case '0': 441df930be7Sderaadt case '1': 442df930be7Sderaadt case '2': 443df930be7Sderaadt case '3': 444df930be7Sderaadt case '4': 445df930be7Sderaadt case '5': 446df930be7Sderaadt case '6': 447df930be7Sderaadt case '7': 448df930be7Sderaadt case '8': 449df930be7Sderaadt case '9': 450df930be7Sderaadt if ((argno = *p - '0') < argc - 1) 451df930be7Sderaadt pbstr(argv[argno + 1]); 452df930be7Sderaadt break; 453df930be7Sderaadt case '*': 454df930be7Sderaadt for (n = argc - 1; n > 2; n--) { 455df930be7Sderaadt pbstr(argv[n]); 456aa676ce1Smillert putback(COMMA); 457df930be7Sderaadt } 458df930be7Sderaadt pbstr(argv[2]); 459df930be7Sderaadt break; 460aa676ce1Smillert case '@': 461aa676ce1Smillert for (n = argc - 1; n > 2; n--) { 462aa676ce1Smillert pbstr(rquote); 463aa676ce1Smillert pbstr(argv[n]); 464aa676ce1Smillert pbstr(lquote); 465aa676ce1Smillert putback(COMMA); 466aa676ce1Smillert } 467aa676ce1Smillert pbstr(rquote); 468aa676ce1Smillert pbstr(argv[2]); 469aa676ce1Smillert pbstr(lquote); 470aa676ce1Smillert break; 471df930be7Sderaadt default: 472df930be7Sderaadt putback(*p); 473df930be7Sderaadt putback('$'); 474df930be7Sderaadt break; 475df930be7Sderaadt } 476df930be7Sderaadt p--; 477df930be7Sderaadt } 478df930be7Sderaadt p--; 479df930be7Sderaadt } 480df930be7Sderaadt if (p == t) /* do last character */ 481df930be7Sderaadt putback(*p); 482df930be7Sderaadt } 483df930be7Sderaadt 484df930be7Sderaadt /* 485df930be7Sderaadt * dodefine - install definition in the table 486df930be7Sderaadt */ 487df930be7Sderaadt void 488df930be7Sderaadt dodefine(name, defn) 489bb34cd6cSespie const char *name; 490bb34cd6cSespie const char *defn; 491df930be7Sderaadt { 49253f6f6bfSespie ndptr p; 493df930be7Sderaadt 494df930be7Sderaadt if (!*name) 49581c2181eSespie errx(1, "null definition."); 496df930be7Sderaadt if ((p = lookup(name)) == nil) 497df930be7Sderaadt p = addent(name); 498df930be7Sderaadt else if (p->defn != null) 499df930be7Sderaadt free((char *) p->defn); 500df930be7Sderaadt if (!*defn) 501df930be7Sderaadt p->defn = null; 502df930be7Sderaadt else 503df930be7Sderaadt p->defn = xstrdup(defn); 504df930be7Sderaadt p->type = MACRTYPE; 505718b194dSespie if (STREQ(name, defn)) 506718b194dSespie p->type |= RECDEF; 507df930be7Sderaadt } 508df930be7Sderaadt 509df930be7Sderaadt /* 510df930be7Sderaadt * dodefn - push back a quoted definition of 511df930be7Sderaadt * the given name. 512df930be7Sderaadt */ 513bb34cd6cSespie static void 514df930be7Sderaadt dodefn(name) 515bb34cd6cSespie const char *name; 516df930be7Sderaadt { 51753f6f6bfSespie ndptr p; 518df930be7Sderaadt 519df930be7Sderaadt if ((p = lookup(name)) != nil && p->defn != null) { 5203a73db8cSderaadt pbstr(rquote); 521df930be7Sderaadt pbstr(p->defn); 5223a73db8cSderaadt pbstr(lquote); 523df930be7Sderaadt } 524df930be7Sderaadt } 525df930be7Sderaadt 526df930be7Sderaadt /* 527df930be7Sderaadt * dopushdef - install a definition in the hash table 528df930be7Sderaadt * without removing a previous definition. Since 529df930be7Sderaadt * each new entry is entered in *front* of the 530df930be7Sderaadt * hash bucket, it hides a previous definition from 531df930be7Sderaadt * lookup. 532df930be7Sderaadt */ 533bb34cd6cSespie static void 534df930be7Sderaadt dopushdef(name, defn) 535bb34cd6cSespie const char *name; 536bb34cd6cSespie const char *defn; 537df930be7Sderaadt { 53853f6f6bfSespie ndptr p; 539df930be7Sderaadt 540df930be7Sderaadt if (!*name) 54181c2181eSespie errx(1, "null definition"); 542df930be7Sderaadt p = addent(name); 543df930be7Sderaadt if (!*defn) 544df930be7Sderaadt p->defn = null; 545df930be7Sderaadt else 546df930be7Sderaadt p->defn = xstrdup(defn); 547df930be7Sderaadt p->type = MACRTYPE; 548718b194dSespie if (STREQ(name, defn)) 549718b194dSespie p->type |= RECDEF; 550df930be7Sderaadt } 551df930be7Sderaadt 552df930be7Sderaadt /* 553df930be7Sderaadt * dodumpdef - dump the specified definitions in the hash 554df930be7Sderaadt * table to stderr. If nothing is specified, the entire 555df930be7Sderaadt * hash table is dumped. 556df930be7Sderaadt */ 557bb34cd6cSespie static void 558df930be7Sderaadt dodump(argv, argc) 559bb34cd6cSespie const char *argv[]; 56053f6f6bfSespie int argc; 561df930be7Sderaadt { 56253f6f6bfSespie int n; 563df930be7Sderaadt ndptr p; 564df930be7Sderaadt 565df930be7Sderaadt if (argc > 2) { 566df930be7Sderaadt for (n = 2; n < argc; n++) 567df930be7Sderaadt if ((p = lookup(argv[n])) != nil) 568df930be7Sderaadt fprintf(stderr, dumpfmt, p->name, 569df930be7Sderaadt p->defn); 5707d3e0b6bSderaadt } else { 571df930be7Sderaadt for (n = 0; n < HASHSIZE; n++) 572df930be7Sderaadt for (p = hashtab[n]; p != nil; p = p->nxtptr) 573df930be7Sderaadt fprintf(stderr, dumpfmt, p->name, 574df930be7Sderaadt p->defn); 575df930be7Sderaadt } 576df930be7Sderaadt } 577df930be7Sderaadt 578df930be7Sderaadt /* 579df930be7Sderaadt * doifelse - select one of two alternatives - loop. 580df930be7Sderaadt */ 581bb34cd6cSespie static void 582df930be7Sderaadt doifelse(argv, argc) 583bb34cd6cSespie const char *argv[]; 58453f6f6bfSespie int argc; 585df930be7Sderaadt { 586df930be7Sderaadt cycle { 587df930be7Sderaadt if (STREQ(argv[2], argv[3])) 588df930be7Sderaadt pbstr(argv[4]); 589df930be7Sderaadt else if (argc == 6) 590df930be7Sderaadt pbstr(argv[5]); 591df930be7Sderaadt else if (argc > 6) { 592df930be7Sderaadt argv += 3; 593df930be7Sderaadt argc -= 3; 594df930be7Sderaadt continue; 595df930be7Sderaadt } 596df930be7Sderaadt break; 597df930be7Sderaadt } 598df930be7Sderaadt } 599df930be7Sderaadt 600df930be7Sderaadt /* 601df930be7Sderaadt * doinclude - include a given file. 602df930be7Sderaadt */ 603bb34cd6cSespie static int 604df930be7Sderaadt doincl(ifile) 605bb34cd6cSespie const char *ifile; 606df930be7Sderaadt { 607df930be7Sderaadt if (ilevel + 1 == MAXINP) 60881c2181eSespie errx(1, "too many include files."); 6094a769388Sespie if ((infile[ilevel + 1] = fopen_trypath(ifile)) != NULL) { 610df930be7Sderaadt ilevel++; 611df930be7Sderaadt bbase[ilevel] = bufbase = bp; 612df930be7Sderaadt return (1); 6137d3e0b6bSderaadt } else 614df930be7Sderaadt return (0); 615df930be7Sderaadt } 616df930be7Sderaadt 617df930be7Sderaadt #ifdef EXTENDED 618df930be7Sderaadt /* 619df930be7Sderaadt * dopaste - include a given file without any 620df930be7Sderaadt * macro processing. 621df930be7Sderaadt */ 622bb34cd6cSespie static int 623df930be7Sderaadt dopaste(pfile) 624bb34cd6cSespie const char *pfile; 625df930be7Sderaadt { 626df930be7Sderaadt FILE *pf; 62753f6f6bfSespie int c; 628df930be7Sderaadt 629df930be7Sderaadt if ((pf = fopen(pfile, "r")) != NULL) { 630df930be7Sderaadt while ((c = getc(pf)) != EOF) 631df930be7Sderaadt putc(c, active); 632df930be7Sderaadt (void) fclose(pf); 633df930be7Sderaadt return (1); 6347d3e0b6bSderaadt } else 635df930be7Sderaadt return (0); 636df930be7Sderaadt } 637df930be7Sderaadt #endif 638df930be7Sderaadt 639df930be7Sderaadt /* 640df930be7Sderaadt * dochq - change quote characters 641df930be7Sderaadt */ 642bb34cd6cSespie static void 643df930be7Sderaadt dochq(argv, argc) 644bb34cd6cSespie const char *argv[]; 64553f6f6bfSespie int argc; 646df930be7Sderaadt { 647df930be7Sderaadt if (argc > 2) { 64818a1973bSderaadt if (*argv[2]) 649b81b15b2Sespie strlcpy(lquote, argv[2], sizeof(lquote)); 65018a1973bSderaadt else { 65118a1973bSderaadt lquote[0] = LQUOTE; 652f0484631Sespie lquote[1] = EOS; 65318a1973bSderaadt } 654df930be7Sderaadt if (argc > 3) { 655df930be7Sderaadt if (*argv[3]) 656b81b15b2Sespie strlcpy(rquote, argv[3], sizeof(rquote)); 6577d3e0b6bSderaadt } else 65829a0bfdcSderaadt strcpy(rquote, lquote); 6597d3e0b6bSderaadt } else { 660f0484631Sespie lquote[0] = LQUOTE, lquote[1] = EOS; 661f0484631Sespie rquote[0] = RQUOTE, rquote[1] = EOS; 662df930be7Sderaadt } 663df930be7Sderaadt } 664df930be7Sderaadt 665df930be7Sderaadt /* 666df930be7Sderaadt * dochc - change comment characters 667df930be7Sderaadt */ 668bb34cd6cSespie static void 669df930be7Sderaadt dochc(argv, argc) 670bb34cd6cSespie const char *argv[]; 67153f6f6bfSespie int argc; 672df930be7Sderaadt { 673df930be7Sderaadt if (argc > 2) { 674df930be7Sderaadt if (*argv[2]) 675b81b15b2Sespie strlcpy(scommt, argv[2], sizeof(scommt)); 676df930be7Sderaadt if (argc > 3) { 677df930be7Sderaadt if (*argv[3]) 678b81b15b2Sespie strlcpy(ecommt, argv[3], sizeof(ecommt)); 679df930be7Sderaadt } 680df930be7Sderaadt else 681f0484631Sespie ecommt[0] = ECOMMT, ecommt[1] = EOS; 682df930be7Sderaadt } 683df930be7Sderaadt else { 684f0484631Sespie scommt[0] = SCOMMT, scommt[1] = EOS; 685f0484631Sespie ecommt[0] = ECOMMT, ecommt[1] = EOS; 686df930be7Sderaadt } 687df930be7Sderaadt } 688df930be7Sderaadt 689df930be7Sderaadt /* 690df930be7Sderaadt * dodivert - divert the output to a temporary file 691df930be7Sderaadt */ 692bb34cd6cSespie static void 693df930be7Sderaadt dodiv(n) 69453f6f6bfSespie int n; 695df930be7Sderaadt { 696445b77f7Smillert int fd; 697445b77f7Smillert 6987d3e0b6bSderaadt oindex = n; 699df930be7Sderaadt if (n < 0 || n >= MAXOUT) 700df930be7Sderaadt n = 0; /* bitbucket */ 701df930be7Sderaadt if (outfile[n] == NULL) { 7023f42598dSespie char fname[] = _PATH_DIVNAME; 7033f42598dSespie 7043f42598dSespie if ((fd = mkstemp(fname)) < 0 || 7053f42598dSespie (outfile[n] = fdopen(fd, "w+")) == NULL) 7063f42598dSespie err(1, "%s: cannot divert", fname); 7073f42598dSespie if (unlink(fname) == -1) 7083f42598dSespie err(1, "%s: cannot unlink", fname); 709df930be7Sderaadt } 710df930be7Sderaadt active = outfile[n]; 711df930be7Sderaadt } 712df930be7Sderaadt 713df930be7Sderaadt /* 714df930be7Sderaadt * doundivert - undivert a specified output, or all 715df930be7Sderaadt * other outputs, in numerical order. 716df930be7Sderaadt */ 717bb34cd6cSespie static void 718df930be7Sderaadt doundiv(argv, argc) 719bb34cd6cSespie const char *argv[]; 72053f6f6bfSespie int argc; 721df930be7Sderaadt { 72253f6f6bfSespie int ind; 72353f6f6bfSespie int n; 724df930be7Sderaadt 725df930be7Sderaadt if (argc > 2) { 726df930be7Sderaadt for (ind = 2; ind < argc; ind++) { 727df930be7Sderaadt n = atoi(argv[ind]); 728df930be7Sderaadt if (n > 0 && n < MAXOUT && outfile[n] != NULL) 729df930be7Sderaadt getdiv(n); 730df930be7Sderaadt 731df930be7Sderaadt } 732df930be7Sderaadt } 733df930be7Sderaadt else 734df930be7Sderaadt for (n = 1; n < MAXOUT; n++) 735df930be7Sderaadt if (outfile[n] != NULL) 736df930be7Sderaadt getdiv(n); 737df930be7Sderaadt } 738df930be7Sderaadt 739df930be7Sderaadt /* 740df930be7Sderaadt * dosub - select substring 741df930be7Sderaadt */ 742bb34cd6cSespie static void 743df930be7Sderaadt dosub(argv, argc) 744bb34cd6cSespie const char *argv[]; 74553f6f6bfSespie int argc; 746df930be7Sderaadt { 747bb34cd6cSespie const char *ap, *fc, *k; 74853f6f6bfSespie int nc; 749df930be7Sderaadt 750df930be7Sderaadt if (argc < 5) 751df930be7Sderaadt nc = MAXTOK; 752df930be7Sderaadt else 753df930be7Sderaadt #ifdef EXPR 754df930be7Sderaadt nc = expr(argv[4]); 755df930be7Sderaadt #else 756df930be7Sderaadt nc = atoi(argv[4]); 757df930be7Sderaadt #endif 758df930be7Sderaadt ap = argv[2]; /* target string */ 759df930be7Sderaadt #ifdef EXPR 760df930be7Sderaadt fc = ap + expr(argv[3]); /* first char */ 761df930be7Sderaadt #else 762df930be7Sderaadt fc = ap + atoi(argv[3]); /* first char */ 763df930be7Sderaadt #endif 764df930be7Sderaadt if (fc >= ap && fc < ap + strlen(ap)) 765df930be7Sderaadt for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--) 766df930be7Sderaadt putback(*k); 767df930be7Sderaadt } 768df930be7Sderaadt 769df930be7Sderaadt /* 770df930be7Sderaadt * map: 771df930be7Sderaadt * map every character of s1 that is specified in from 772df930be7Sderaadt * into s3 and replace in s. (source s1 remains untouched) 773df930be7Sderaadt * 774df930be7Sderaadt * This is a standard implementation of map(s,from,to) function of ICON 775df930be7Sderaadt * language. Within mapvec, we replace every character of "from" with 776df930be7Sderaadt * the corresponding character in "to". If "to" is shorter than "from", 777df930be7Sderaadt * than the corresponding entries are null, which means that those 778df930be7Sderaadt * characters dissapear altogether. Furthermore, imagine 779df930be7Sderaadt * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, 780df930be7Sderaadt * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' 781df930be7Sderaadt * ultimately maps to `*'. In order to achieve this effect in an efficient 782df930be7Sderaadt * manner (i.e. without multiple passes over the destination string), we 783df930be7Sderaadt * loop over mapvec, starting with the initial source character. if the 784df930be7Sderaadt * character value (dch) in this location is different than the source 785df930be7Sderaadt * character (sch), sch becomes dch, once again to index into mapvec, until 786df930be7Sderaadt * the character value stabilizes (i.e. sch = dch, in other words 787df930be7Sderaadt * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary 788df930be7Sderaadt * character, it will stabilize, since mapvec[0] == 0 at all times. At the 789df930be7Sderaadt * end, we restore mapvec* back to normal where mapvec[n] == n for 790df930be7Sderaadt * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is 791df930be7Sderaadt * about 5 times faster than any algorithm that makes multiple passes over 792df930be7Sderaadt * destination string. 793df930be7Sderaadt */ 794bb34cd6cSespie static void 795df930be7Sderaadt map(dest, src, from, to) 79653f6f6bfSespie char *dest; 797bb34cd6cSespie const char *src; 798bb34cd6cSespie const char *from; 799bb34cd6cSespie const char *to; 800df930be7Sderaadt { 801bb34cd6cSespie const char *tmp; 802ee3599c7Sespie unsigned char sch, dch; 803ee3599c7Sespie static unsigned char mapvec[256] = { 804ee3599c7Sespie 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 805ee3599c7Sespie 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 806ee3599c7Sespie 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 807ee3599c7Sespie 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 808ee3599c7Sespie 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 809ee3599c7Sespie 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 810ee3599c7Sespie 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 811ee3599c7Sespie 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 812ee3599c7Sespie 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 813ee3599c7Sespie 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 814ee3599c7Sespie 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 815ee3599c7Sespie 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 816ee3599c7Sespie 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 817ee3599c7Sespie 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 818ee3599c7Sespie 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 819ee3599c7Sespie 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 820ee3599c7Sespie 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 821ee3599c7Sespie 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 822df930be7Sderaadt }; 823df930be7Sderaadt 824df930be7Sderaadt if (*src) { 825df930be7Sderaadt tmp = from; 826df930be7Sderaadt /* 827df930be7Sderaadt * create a mapping between "from" and 828df930be7Sderaadt * "to" 829df930be7Sderaadt */ 830df930be7Sderaadt while (*from) 831ee3599c7Sespie mapvec[(unsigned char)(*from++)] = (*to) ? 832ee3599c7Sespie (unsigned char)(*to++) : 0; 833df930be7Sderaadt 834df930be7Sderaadt while (*src) { 835ee3599c7Sespie sch = (unsigned char)(*src++); 836df930be7Sderaadt dch = mapvec[sch]; 837df930be7Sderaadt while (dch != sch) { 838df930be7Sderaadt sch = dch; 839df930be7Sderaadt dch = mapvec[sch]; 840df930be7Sderaadt } 841ee3599c7Sespie if ((*dest = (char)dch)) 842df930be7Sderaadt dest++; 843df930be7Sderaadt } 844df930be7Sderaadt /* 845df930be7Sderaadt * restore all the changed characters 846df930be7Sderaadt */ 847df930be7Sderaadt while (*tmp) { 848ee3599c7Sespie mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp); 849df930be7Sderaadt tmp++; 850df930be7Sderaadt } 851df930be7Sderaadt } 852ee3599c7Sespie *dest = '\0'; 853df930be7Sderaadt } 854