1*b81b15b2Sespie /* $OpenBSD: eval.c,v 1.21 1999/11/30 22:19:50 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*b81b15b2Sespie static char rcsid[] = "$OpenBSD: eval.c,v 1.21 1999/11/30 22:19:50 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 113df930be7Sderaadt /* 114df930be7Sderaadt * if argc == 3 and argv[2] is null, then we 115df930be7Sderaadt * have macro-or-builtin() type call. We adjust 116df930be7Sderaadt * argc to avoid further checking.. 117df930be7Sderaadt */ 118df930be7Sderaadt if (argc == 3 && !*(argv[2])) 119df930be7Sderaadt argc--; 120df930be7Sderaadt 121df930be7Sderaadt switch (td & ~STATIC) { 122df930be7Sderaadt 123df930be7Sderaadt case DEFITYPE: 124df930be7Sderaadt if (argc > 2) 125df930be7Sderaadt dodefine(argv[2], (argc > 3) ? argv[3] : null); 126df930be7Sderaadt break; 127df930be7Sderaadt 128df930be7Sderaadt case PUSDTYPE: 129df930be7Sderaadt if (argc > 2) 130df930be7Sderaadt dopushdef(argv[2], (argc > 3) ? argv[3] : null); 131df930be7Sderaadt break; 132df930be7Sderaadt 133df930be7Sderaadt case DUMPTYPE: 134df930be7Sderaadt dodump(argv, argc); 135df930be7Sderaadt break; 136df930be7Sderaadt 137df930be7Sderaadt case EXPRTYPE: 138df930be7Sderaadt /* 139df930be7Sderaadt * doexpr - evaluate arithmetic 140df930be7Sderaadt * expression 141df930be7Sderaadt */ 142df930be7Sderaadt if (argc > 2) 143df930be7Sderaadt pbnum(expr(argv[2])); 144df930be7Sderaadt break; 145df930be7Sderaadt 146df930be7Sderaadt case IFELTYPE: 147df930be7Sderaadt if (argc > 4) 148df930be7Sderaadt doifelse(argv, argc); 149df930be7Sderaadt break; 150df930be7Sderaadt 151df930be7Sderaadt case IFDFTYPE: 152df930be7Sderaadt /* 153df930be7Sderaadt * doifdef - select one of two 154df930be7Sderaadt * alternatives based on the existence of 155df930be7Sderaadt * another definition 156df930be7Sderaadt */ 157df930be7Sderaadt if (argc > 3) { 158df930be7Sderaadt if (lookup(argv[2]) != nil) 159df930be7Sderaadt pbstr(argv[3]); 160df930be7Sderaadt else if (argc > 4) 161df930be7Sderaadt pbstr(argv[4]); 162df930be7Sderaadt } 163df930be7Sderaadt break; 164df930be7Sderaadt 165df930be7Sderaadt case LENGTYPE: 166df930be7Sderaadt /* 167df930be7Sderaadt * dolen - find the length of the 168df930be7Sderaadt * argument 169df930be7Sderaadt */ 170df930be7Sderaadt pbnum((argc > 2) ? strlen(argv[2]) : 0); 171df930be7Sderaadt break; 172df930be7Sderaadt 173df930be7Sderaadt case INCRTYPE: 174df930be7Sderaadt /* 175df930be7Sderaadt * doincr - increment the value of the 176df930be7Sderaadt * argument 177df930be7Sderaadt */ 178df930be7Sderaadt if (argc > 2) 179df930be7Sderaadt pbnum(atoi(argv[2]) + 1); 180df930be7Sderaadt break; 181df930be7Sderaadt 182df930be7Sderaadt case DECRTYPE: 183df930be7Sderaadt /* 184df930be7Sderaadt * dodecr - decrement the value of the 185df930be7Sderaadt * argument 186df930be7Sderaadt */ 187df930be7Sderaadt if (argc > 2) 188df930be7Sderaadt pbnum(atoi(argv[2]) - 1); 189df930be7Sderaadt break; 190df930be7Sderaadt 191df930be7Sderaadt case SYSCTYPE: 192df930be7Sderaadt /* 193df930be7Sderaadt * dosys - execute system command 194df930be7Sderaadt */ 195df930be7Sderaadt if (argc > 2) 196df930be7Sderaadt sysval = system(argv[2]); 197df930be7Sderaadt break; 198df930be7Sderaadt 199df930be7Sderaadt case SYSVTYPE: 200df930be7Sderaadt /* 201df930be7Sderaadt * dosysval - return value of the last 202df930be7Sderaadt * system call. 203df930be7Sderaadt * 204df930be7Sderaadt */ 205df930be7Sderaadt pbnum(sysval); 206df930be7Sderaadt break; 207df930be7Sderaadt 208df930be7Sderaadt case INCLTYPE: 209df930be7Sderaadt if (argc > 2) 210df930be7Sderaadt if (!doincl(argv[2])) 21181c2181eSespie err(1, "%s", argv[2]); 212df930be7Sderaadt break; 213df930be7Sderaadt 214df930be7Sderaadt case SINCTYPE: 215df930be7Sderaadt if (argc > 2) 216df930be7Sderaadt (void) doincl(argv[2]); 217df930be7Sderaadt break; 218df930be7Sderaadt #ifdef EXTENDED 219df930be7Sderaadt case PASTTYPE: 220df930be7Sderaadt if (argc > 2) 221df930be7Sderaadt if (!dopaste(argv[2])) 22281c2181eSespie err(1, "%s", argv[2]); 223df930be7Sderaadt break; 224df930be7Sderaadt 225df930be7Sderaadt case SPASTYPE: 226df930be7Sderaadt if (argc > 2) 227df930be7Sderaadt (void) dopaste(argv[2]); 228df930be7Sderaadt break; 229df930be7Sderaadt #endif 230df930be7Sderaadt case CHNQTYPE: 231df930be7Sderaadt dochq(argv, argc); 232df930be7Sderaadt break; 233df930be7Sderaadt 234df930be7Sderaadt case CHNCTYPE: 235df930be7Sderaadt dochc(argv, argc); 236df930be7Sderaadt break; 237df930be7Sderaadt 238df930be7Sderaadt case SUBSTYPE: 239df930be7Sderaadt /* 240df930be7Sderaadt * dosub - select substring 241df930be7Sderaadt * 242df930be7Sderaadt */ 243df930be7Sderaadt if (argc > 3) 244df930be7Sderaadt dosub(argv, argc); 245df930be7Sderaadt break; 246df930be7Sderaadt 247df930be7Sderaadt case SHIFTYPE: 248df930be7Sderaadt /* 249df930be7Sderaadt * doshift - push back all arguments 250df930be7Sderaadt * except the first one (i.e. skip 251df930be7Sderaadt * argv[2]) 252df930be7Sderaadt */ 253df930be7Sderaadt if (argc > 3) { 254df930be7Sderaadt for (n = argc - 1; n > 3; n--) { 2553a73db8cSderaadt pbstr(rquote); 256df930be7Sderaadt pbstr(argv[n]); 2573a73db8cSderaadt pbstr(lquote); 258aa676ce1Smillert putback(COMMA); 259df930be7Sderaadt } 2603a73db8cSderaadt pbstr(rquote); 261df930be7Sderaadt pbstr(argv[3]); 2623a73db8cSderaadt pbstr(lquote); 263df930be7Sderaadt } 264df930be7Sderaadt break; 265df930be7Sderaadt 266df930be7Sderaadt case DIVRTYPE: 267df930be7Sderaadt if (argc > 2 && (n = atoi(argv[2])) != 0) 268df930be7Sderaadt dodiv(n); 269df930be7Sderaadt else { 270df930be7Sderaadt active = stdout; 271df930be7Sderaadt oindex = 0; 272df930be7Sderaadt } 273df930be7Sderaadt break; 274df930be7Sderaadt 275df930be7Sderaadt case UNDVTYPE: 276df930be7Sderaadt doundiv(argv, argc); 277df930be7Sderaadt break; 278df930be7Sderaadt 279df930be7Sderaadt case DIVNTYPE: 280df930be7Sderaadt /* 281df930be7Sderaadt * dodivnum - return the number of 282df930be7Sderaadt * current output diversion 283df930be7Sderaadt */ 284df930be7Sderaadt pbnum(oindex); 285df930be7Sderaadt break; 286df930be7Sderaadt 287df930be7Sderaadt case UNDFTYPE: 288df930be7Sderaadt /* 289df930be7Sderaadt * doundefine - undefine a previously 290df930be7Sderaadt * defined macro(s) or m4 keyword(s). 291df930be7Sderaadt */ 292df930be7Sderaadt if (argc > 2) 293df930be7Sderaadt for (n = 2; n < argc; n++) 294df930be7Sderaadt remhash(argv[n], ALL); 295df930be7Sderaadt break; 296df930be7Sderaadt 297df930be7Sderaadt case POPDTYPE: 298df930be7Sderaadt /* 299df930be7Sderaadt * dopopdef - remove the topmost 300df930be7Sderaadt * definitions of macro(s) or m4 301df930be7Sderaadt * keyword(s). 302df930be7Sderaadt */ 303df930be7Sderaadt if (argc > 2) 304df930be7Sderaadt for (n = 2; n < argc; n++) 305df930be7Sderaadt remhash(argv[n], TOP); 306df930be7Sderaadt break; 307df930be7Sderaadt 308df930be7Sderaadt case MKTMTYPE: 309df930be7Sderaadt /* 310df930be7Sderaadt * dotemp - create a temporary file 311df930be7Sderaadt */ 31201e71e69Sespie if (argc > 2) { 31301e71e69Sespie int fd; 314bb34cd6cSespie char *temp; 31501e71e69Sespie 316bb34cd6cSespie temp = xstrdup(argv[2]); 317bb34cd6cSespie 318bb34cd6cSespie fd = mkstemp(temp); 31901e71e69Sespie if (fd == -1) 32001e71e69Sespie err(1, "couldn't make temp file %s", argv[2]); 32101e71e69Sespie close(fd); 322bb34cd6cSespie pbstr(temp); 323bb34cd6cSespie free(temp); 32401e71e69Sespie } 325df930be7Sderaadt break; 326df930be7Sderaadt 327df930be7Sderaadt case TRNLTYPE: 328df930be7Sderaadt /* 329df930be7Sderaadt * dotranslit - replace all characters in 330df930be7Sderaadt * the source string that appears in the 331df930be7Sderaadt * "from" string with the corresponding 332df930be7Sderaadt * characters in the "to" string. 333df930be7Sderaadt */ 334df930be7Sderaadt if (argc > 3) { 3357d3e0b6bSderaadt char temp[STRSPMAX+1]; 336df930be7Sderaadt if (argc > 4) 337df930be7Sderaadt map(temp, argv[2], argv[3], argv[4]); 338df930be7Sderaadt else 339df930be7Sderaadt map(temp, argv[2], argv[3], null); 340df930be7Sderaadt pbstr(temp); 3417d3e0b6bSderaadt } else if (argc > 2) 342df930be7Sderaadt pbstr(argv[2]); 343df930be7Sderaadt break; 344df930be7Sderaadt 345df930be7Sderaadt case INDXTYPE: 346df930be7Sderaadt /* 347df930be7Sderaadt * doindex - find the index of the second 348df930be7Sderaadt * argument string in the first argument 349df930be7Sderaadt * string. -1 if not present. 350df930be7Sderaadt */ 351df930be7Sderaadt pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1); 352df930be7Sderaadt break; 353df930be7Sderaadt 354df930be7Sderaadt case ERRPTYPE: 355df930be7Sderaadt /* 356df930be7Sderaadt * doerrp - print the arguments to stderr 357df930be7Sderaadt * file 358df930be7Sderaadt */ 359df930be7Sderaadt if (argc > 2) { 360df930be7Sderaadt for (n = 2; n < argc; n++) 361df930be7Sderaadt fprintf(stderr, "%s ", argv[n]); 362df930be7Sderaadt fprintf(stderr, "\n"); 363df930be7Sderaadt } 364df930be7Sderaadt break; 365df930be7Sderaadt 366df930be7Sderaadt case DNLNTYPE: 367df930be7Sderaadt /* 368df930be7Sderaadt * dodnl - eat-up-to and including 369df930be7Sderaadt * newline 370df930be7Sderaadt */ 371df930be7Sderaadt while ((c = gpbc()) != '\n' && c != EOF) 372df930be7Sderaadt ; 373df930be7Sderaadt break; 374df930be7Sderaadt 375df930be7Sderaadt case M4WRTYPE: 376df930be7Sderaadt /* 377df930be7Sderaadt * dom4wrap - set up for 378df930be7Sderaadt * wrap-up/wind-down activity 379df930be7Sderaadt */ 380df930be7Sderaadt m4wraps = (argc > 2) ? xstrdup(argv[2]) : null; 381df930be7Sderaadt break; 382df930be7Sderaadt 383df930be7Sderaadt case EXITTYPE: 384df930be7Sderaadt /* 385df930be7Sderaadt * doexit - immediate exit from m4. 386df930be7Sderaadt */ 387df930be7Sderaadt killdiv(); 388df930be7Sderaadt exit((argc > 2) ? atoi(argv[2]) : 0); 389df930be7Sderaadt break; 390df930be7Sderaadt 391df930be7Sderaadt case DEFNTYPE: 392df930be7Sderaadt if (argc > 2) 393df930be7Sderaadt for (n = 2; n < argc; n++) 394df930be7Sderaadt dodefn(argv[n]); 395df930be7Sderaadt break; 396df930be7Sderaadt 397df930be7Sderaadt default: 39881c2181eSespie errx(1, "eval: major botch."); 399df930be7Sderaadt break; 400df930be7Sderaadt } 401df930be7Sderaadt } 402df930be7Sderaadt 403df930be7Sderaadt char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */ 404df930be7Sderaadt 405df930be7Sderaadt /* 406df930be7Sderaadt * expand - user-defined macro expansion 407df930be7Sderaadt */ 408df930be7Sderaadt void 409df930be7Sderaadt expand(argv, argc) 410bb34cd6cSespie const char *argv[]; 41153f6f6bfSespie int argc; 412df930be7Sderaadt { 413bb34cd6cSespie const char *t; 414bb34cd6cSespie const char *p; 41553f6f6bfSespie int n; 41653f6f6bfSespie int argno; 417df930be7Sderaadt 418df930be7Sderaadt t = argv[0]; /* defn string as a whole */ 419df930be7Sderaadt p = t; 420df930be7Sderaadt while (*p) 421df930be7Sderaadt p++; 422df930be7Sderaadt p--; /* last character of defn */ 423df930be7Sderaadt while (p > t) { 424df930be7Sderaadt if (*(p - 1) != ARGFLAG) 425df930be7Sderaadt putback(*p); 426df930be7Sderaadt else { 427df930be7Sderaadt switch (*p) { 428df930be7Sderaadt 429df930be7Sderaadt case '#': 430df930be7Sderaadt pbnum(argc - 2); 431df930be7Sderaadt break; 432df930be7Sderaadt case '0': 433df930be7Sderaadt case '1': 434df930be7Sderaadt case '2': 435df930be7Sderaadt case '3': 436df930be7Sderaadt case '4': 437df930be7Sderaadt case '5': 438df930be7Sderaadt case '6': 439df930be7Sderaadt case '7': 440df930be7Sderaadt case '8': 441df930be7Sderaadt case '9': 442df930be7Sderaadt if ((argno = *p - '0') < argc - 1) 443df930be7Sderaadt pbstr(argv[argno + 1]); 444df930be7Sderaadt break; 445df930be7Sderaadt case '*': 446df930be7Sderaadt for (n = argc - 1; n > 2; n--) { 447df930be7Sderaadt pbstr(argv[n]); 448aa676ce1Smillert putback(COMMA); 449df930be7Sderaadt } 450df930be7Sderaadt pbstr(argv[2]); 451df930be7Sderaadt break; 452aa676ce1Smillert case '@': 453aa676ce1Smillert for (n = argc - 1; n > 2; n--) { 454aa676ce1Smillert pbstr(rquote); 455aa676ce1Smillert pbstr(argv[n]); 456aa676ce1Smillert pbstr(lquote); 457aa676ce1Smillert putback(COMMA); 458aa676ce1Smillert } 459aa676ce1Smillert pbstr(rquote); 460aa676ce1Smillert pbstr(argv[2]); 461aa676ce1Smillert pbstr(lquote); 462aa676ce1Smillert break; 463df930be7Sderaadt default: 464df930be7Sderaadt putback(*p); 465df930be7Sderaadt putback('$'); 466df930be7Sderaadt break; 467df930be7Sderaadt } 468df930be7Sderaadt p--; 469df930be7Sderaadt } 470df930be7Sderaadt p--; 471df930be7Sderaadt } 472df930be7Sderaadt if (p == t) /* do last character */ 473df930be7Sderaadt putback(*p); 474df930be7Sderaadt } 475df930be7Sderaadt 476df930be7Sderaadt /* 477df930be7Sderaadt * dodefine - install definition in the table 478df930be7Sderaadt */ 479df930be7Sderaadt void 480df930be7Sderaadt dodefine(name, defn) 481bb34cd6cSespie const char *name; 482bb34cd6cSespie const char *defn; 483df930be7Sderaadt { 48453f6f6bfSespie ndptr p; 485df930be7Sderaadt 486df930be7Sderaadt if (!*name) 48781c2181eSespie errx(1, "null definition."); 488df930be7Sderaadt if (STREQ(name, defn)) 48981c2181eSespie errx(1, "%s: recursive definition.", name); 490df930be7Sderaadt if ((p = lookup(name)) == nil) 491df930be7Sderaadt p = addent(name); 492df930be7Sderaadt else if (p->defn != null) 493df930be7Sderaadt free((char *) p->defn); 494df930be7Sderaadt if (!*defn) 495df930be7Sderaadt p->defn = null; 496df930be7Sderaadt else 497df930be7Sderaadt p->defn = xstrdup(defn); 498df930be7Sderaadt p->type = MACRTYPE; 499df930be7Sderaadt } 500df930be7Sderaadt 501df930be7Sderaadt /* 502df930be7Sderaadt * dodefn - push back a quoted definition of 503df930be7Sderaadt * the given name. 504df930be7Sderaadt */ 505bb34cd6cSespie static void 506df930be7Sderaadt dodefn(name) 507bb34cd6cSespie const char *name; 508df930be7Sderaadt { 50953f6f6bfSespie ndptr p; 510df930be7Sderaadt 511df930be7Sderaadt if ((p = lookup(name)) != nil && p->defn != null) { 5123a73db8cSderaadt pbstr(rquote); 513df930be7Sderaadt pbstr(p->defn); 5143a73db8cSderaadt pbstr(lquote); 515df930be7Sderaadt } 516df930be7Sderaadt } 517df930be7Sderaadt 518df930be7Sderaadt /* 519df930be7Sderaadt * dopushdef - install a definition in the hash table 520df930be7Sderaadt * without removing a previous definition. Since 521df930be7Sderaadt * each new entry is entered in *front* of the 522df930be7Sderaadt * hash bucket, it hides a previous definition from 523df930be7Sderaadt * lookup. 524df930be7Sderaadt */ 525bb34cd6cSespie static void 526df930be7Sderaadt dopushdef(name, defn) 527bb34cd6cSespie const char *name; 528bb34cd6cSespie const char *defn; 529df930be7Sderaadt { 53053f6f6bfSespie ndptr p; 531df930be7Sderaadt 532df930be7Sderaadt if (!*name) 53381c2181eSespie errx(1, "null definition"); 534df930be7Sderaadt if (STREQ(name, defn)) 53581c2181eSespie errx(1, "%s: recursive definition.", name); 536df930be7Sderaadt p = addent(name); 537df930be7Sderaadt if (!*defn) 538df930be7Sderaadt p->defn = null; 539df930be7Sderaadt else 540df930be7Sderaadt p->defn = xstrdup(defn); 541df930be7Sderaadt p->type = MACRTYPE; 542df930be7Sderaadt } 543df930be7Sderaadt 544df930be7Sderaadt /* 545df930be7Sderaadt * dodumpdef - dump the specified definitions in the hash 546df930be7Sderaadt * table to stderr. If nothing is specified, the entire 547df930be7Sderaadt * hash table is dumped. 548df930be7Sderaadt */ 549bb34cd6cSespie static void 550df930be7Sderaadt dodump(argv, argc) 551bb34cd6cSespie const char *argv[]; 55253f6f6bfSespie int argc; 553df930be7Sderaadt { 55453f6f6bfSespie int n; 555df930be7Sderaadt ndptr p; 556df930be7Sderaadt 557df930be7Sderaadt if (argc > 2) { 558df930be7Sderaadt for (n = 2; n < argc; n++) 559df930be7Sderaadt if ((p = lookup(argv[n])) != nil) 560df930be7Sderaadt fprintf(stderr, dumpfmt, p->name, 561df930be7Sderaadt p->defn); 5627d3e0b6bSderaadt } else { 563df930be7Sderaadt for (n = 0; n < HASHSIZE; n++) 564df930be7Sderaadt for (p = hashtab[n]; p != nil; p = p->nxtptr) 565df930be7Sderaadt fprintf(stderr, dumpfmt, p->name, 566df930be7Sderaadt p->defn); 567df930be7Sderaadt } 568df930be7Sderaadt } 569df930be7Sderaadt 570df930be7Sderaadt /* 571df930be7Sderaadt * doifelse - select one of two alternatives - loop. 572df930be7Sderaadt */ 573bb34cd6cSespie static void 574df930be7Sderaadt doifelse(argv, argc) 575bb34cd6cSespie const char *argv[]; 57653f6f6bfSespie int argc; 577df930be7Sderaadt { 578df930be7Sderaadt cycle { 579df930be7Sderaadt if (STREQ(argv[2], argv[3])) 580df930be7Sderaadt pbstr(argv[4]); 581df930be7Sderaadt else if (argc == 6) 582df930be7Sderaadt pbstr(argv[5]); 583df930be7Sderaadt else if (argc > 6) { 584df930be7Sderaadt argv += 3; 585df930be7Sderaadt argc -= 3; 586df930be7Sderaadt continue; 587df930be7Sderaadt } 588df930be7Sderaadt break; 589df930be7Sderaadt } 590df930be7Sderaadt } 591df930be7Sderaadt 592df930be7Sderaadt /* 593df930be7Sderaadt * doinclude - include a given file. 594df930be7Sderaadt */ 595bb34cd6cSespie static int 596df930be7Sderaadt doincl(ifile) 597bb34cd6cSespie const char *ifile; 598df930be7Sderaadt { 599df930be7Sderaadt if (ilevel + 1 == MAXINP) 60081c2181eSespie errx(1, "too many include files."); 6014a769388Sespie if ((infile[ilevel + 1] = fopen_trypath(ifile)) != NULL) { 602df930be7Sderaadt ilevel++; 603df930be7Sderaadt bbase[ilevel] = bufbase = bp; 604df930be7Sderaadt return (1); 6057d3e0b6bSderaadt } else 606df930be7Sderaadt return (0); 607df930be7Sderaadt } 608df930be7Sderaadt 609df930be7Sderaadt #ifdef EXTENDED 610df930be7Sderaadt /* 611df930be7Sderaadt * dopaste - include a given file without any 612df930be7Sderaadt * macro processing. 613df930be7Sderaadt */ 614bb34cd6cSespie static int 615df930be7Sderaadt dopaste(pfile) 616bb34cd6cSespie const char *pfile; 617df930be7Sderaadt { 618df930be7Sderaadt FILE *pf; 61953f6f6bfSespie int c; 620df930be7Sderaadt 621df930be7Sderaadt if ((pf = fopen(pfile, "r")) != NULL) { 622df930be7Sderaadt while ((c = getc(pf)) != EOF) 623df930be7Sderaadt putc(c, active); 624df930be7Sderaadt (void) fclose(pf); 625df930be7Sderaadt return (1); 6267d3e0b6bSderaadt } else 627df930be7Sderaadt return (0); 628df930be7Sderaadt } 629df930be7Sderaadt #endif 630df930be7Sderaadt 631df930be7Sderaadt /* 632df930be7Sderaadt * dochq - change quote characters 633df930be7Sderaadt */ 634bb34cd6cSespie static void 635df930be7Sderaadt dochq(argv, argc) 636bb34cd6cSespie const char *argv[]; 63753f6f6bfSespie int argc; 638df930be7Sderaadt { 639df930be7Sderaadt if (argc > 2) { 64018a1973bSderaadt if (*argv[2]) 641*b81b15b2Sespie strlcpy(lquote, argv[2], sizeof(lquote)); 64218a1973bSderaadt else { 64318a1973bSderaadt lquote[0] = LQUOTE; 644f0484631Sespie lquote[1] = EOS; 64518a1973bSderaadt } 646df930be7Sderaadt if (argc > 3) { 647df930be7Sderaadt if (*argv[3]) 648*b81b15b2Sespie strlcpy(rquote, argv[3], sizeof(rquote)); 6497d3e0b6bSderaadt } else 65029a0bfdcSderaadt strcpy(rquote, lquote); 6517d3e0b6bSderaadt } else { 652f0484631Sespie lquote[0] = LQUOTE, lquote[1] = EOS; 653f0484631Sespie rquote[0] = RQUOTE, rquote[1] = EOS; 654df930be7Sderaadt } 655df930be7Sderaadt } 656df930be7Sderaadt 657df930be7Sderaadt /* 658df930be7Sderaadt * dochc - change comment characters 659df930be7Sderaadt */ 660bb34cd6cSespie static void 661df930be7Sderaadt dochc(argv, argc) 662bb34cd6cSespie const char *argv[]; 66353f6f6bfSespie int argc; 664df930be7Sderaadt { 665df930be7Sderaadt if (argc > 2) { 666df930be7Sderaadt if (*argv[2]) 667*b81b15b2Sespie strlcpy(scommt, argv[2], sizeof(scommt)); 668df930be7Sderaadt if (argc > 3) { 669df930be7Sderaadt if (*argv[3]) 670*b81b15b2Sespie strlcpy(ecommt, argv[3], sizeof(ecommt)); 671df930be7Sderaadt } 672df930be7Sderaadt else 673f0484631Sespie ecommt[0] = ECOMMT, ecommt[1] = EOS; 674df930be7Sderaadt } 675df930be7Sderaadt else { 676f0484631Sespie scommt[0] = SCOMMT, scommt[1] = EOS; 677f0484631Sespie ecommt[0] = ECOMMT, ecommt[1] = EOS; 678df930be7Sderaadt } 679df930be7Sderaadt } 680df930be7Sderaadt 681df930be7Sderaadt /* 682df930be7Sderaadt * dodivert - divert the output to a temporary file 683df930be7Sderaadt */ 684bb34cd6cSespie static void 685df930be7Sderaadt dodiv(n) 68653f6f6bfSespie int n; 687df930be7Sderaadt { 688445b77f7Smillert int fd; 689445b77f7Smillert 6907d3e0b6bSderaadt oindex = n; 691df930be7Sderaadt if (n < 0 || n >= MAXOUT) 692df930be7Sderaadt n = 0; /* bitbucket */ 693df930be7Sderaadt if (outfile[n] == NULL) { 6943f42598dSespie char fname[] = _PATH_DIVNAME; 6953f42598dSespie 6963f42598dSespie if ((fd = mkstemp(fname)) < 0 || 6973f42598dSespie (outfile[n] = fdopen(fd, "w+")) == NULL) 6983f42598dSespie err(1, "%s: cannot divert", fname); 6993f42598dSespie if (unlink(fname) == -1) 7003f42598dSespie err(1, "%s: cannot unlink", fname); 701df930be7Sderaadt } 702df930be7Sderaadt active = outfile[n]; 703df930be7Sderaadt } 704df930be7Sderaadt 705df930be7Sderaadt /* 706df930be7Sderaadt * doundivert - undivert a specified output, or all 707df930be7Sderaadt * other outputs, in numerical order. 708df930be7Sderaadt */ 709bb34cd6cSespie static void 710df930be7Sderaadt doundiv(argv, argc) 711bb34cd6cSespie const char *argv[]; 71253f6f6bfSespie int argc; 713df930be7Sderaadt { 71453f6f6bfSespie int ind; 71553f6f6bfSespie int n; 716df930be7Sderaadt 717df930be7Sderaadt if (argc > 2) { 718df930be7Sderaadt for (ind = 2; ind < argc; ind++) { 719df930be7Sderaadt n = atoi(argv[ind]); 720df930be7Sderaadt if (n > 0 && n < MAXOUT && outfile[n] != NULL) 721df930be7Sderaadt getdiv(n); 722df930be7Sderaadt 723df930be7Sderaadt } 724df930be7Sderaadt } 725df930be7Sderaadt else 726df930be7Sderaadt for (n = 1; n < MAXOUT; n++) 727df930be7Sderaadt if (outfile[n] != NULL) 728df930be7Sderaadt getdiv(n); 729df930be7Sderaadt } 730df930be7Sderaadt 731df930be7Sderaadt /* 732df930be7Sderaadt * dosub - select substring 733df930be7Sderaadt */ 734bb34cd6cSespie static void 735df930be7Sderaadt dosub(argv, argc) 736bb34cd6cSespie const char *argv[]; 73753f6f6bfSespie int argc; 738df930be7Sderaadt { 739bb34cd6cSespie const char *ap, *fc, *k; 74053f6f6bfSespie int nc; 741df930be7Sderaadt 742df930be7Sderaadt if (argc < 5) 743df930be7Sderaadt nc = MAXTOK; 744df930be7Sderaadt else 745df930be7Sderaadt #ifdef EXPR 746df930be7Sderaadt nc = expr(argv[4]); 747df930be7Sderaadt #else 748df930be7Sderaadt nc = atoi(argv[4]); 749df930be7Sderaadt #endif 750df930be7Sderaadt ap = argv[2]; /* target string */ 751df930be7Sderaadt #ifdef EXPR 752df930be7Sderaadt fc = ap + expr(argv[3]); /* first char */ 753df930be7Sderaadt #else 754df930be7Sderaadt fc = ap + atoi(argv[3]); /* first char */ 755df930be7Sderaadt #endif 756df930be7Sderaadt if (fc >= ap && fc < ap + strlen(ap)) 757df930be7Sderaadt for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--) 758df930be7Sderaadt putback(*k); 759df930be7Sderaadt } 760df930be7Sderaadt 761df930be7Sderaadt /* 762df930be7Sderaadt * map: 763df930be7Sderaadt * map every character of s1 that is specified in from 764df930be7Sderaadt * into s3 and replace in s. (source s1 remains untouched) 765df930be7Sderaadt * 766df930be7Sderaadt * This is a standard implementation of map(s,from,to) function of ICON 767df930be7Sderaadt * language. Within mapvec, we replace every character of "from" with 768df930be7Sderaadt * the corresponding character in "to". If "to" is shorter than "from", 769df930be7Sderaadt * than the corresponding entries are null, which means that those 770df930be7Sderaadt * characters dissapear altogether. Furthermore, imagine 771df930be7Sderaadt * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, 772df930be7Sderaadt * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' 773df930be7Sderaadt * ultimately maps to `*'. In order to achieve this effect in an efficient 774df930be7Sderaadt * manner (i.e. without multiple passes over the destination string), we 775df930be7Sderaadt * loop over mapvec, starting with the initial source character. if the 776df930be7Sderaadt * character value (dch) in this location is different than the source 777df930be7Sderaadt * character (sch), sch becomes dch, once again to index into mapvec, until 778df930be7Sderaadt * the character value stabilizes (i.e. sch = dch, in other words 779df930be7Sderaadt * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary 780df930be7Sderaadt * character, it will stabilize, since mapvec[0] == 0 at all times. At the 781df930be7Sderaadt * end, we restore mapvec* back to normal where mapvec[n] == n for 782df930be7Sderaadt * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is 783df930be7Sderaadt * about 5 times faster than any algorithm that makes multiple passes over 784df930be7Sderaadt * destination string. 785df930be7Sderaadt */ 786bb34cd6cSespie static void 787df930be7Sderaadt map(dest, src, from, to) 78853f6f6bfSespie char *dest; 789bb34cd6cSespie const char *src; 790bb34cd6cSespie const char *from; 791bb34cd6cSespie const char *to; 792df930be7Sderaadt { 793bb34cd6cSespie const char *tmp; 794ee3599c7Sespie unsigned char sch, dch; 795ee3599c7Sespie static unsigned char mapvec[256] = { 796ee3599c7Sespie 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 797ee3599c7Sespie 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 798ee3599c7Sespie 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 799ee3599c7Sespie 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 800ee3599c7Sespie 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 801ee3599c7Sespie 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 802ee3599c7Sespie 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 803ee3599c7Sespie 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 804ee3599c7Sespie 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 805ee3599c7Sespie 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 806ee3599c7Sespie 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 807ee3599c7Sespie 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 808ee3599c7Sespie 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 809ee3599c7Sespie 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 810ee3599c7Sespie 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 811ee3599c7Sespie 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 812ee3599c7Sespie 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 813ee3599c7Sespie 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 814df930be7Sderaadt }; 815df930be7Sderaadt 816df930be7Sderaadt if (*src) { 817df930be7Sderaadt tmp = from; 818df930be7Sderaadt /* 819df930be7Sderaadt * create a mapping between "from" and 820df930be7Sderaadt * "to" 821df930be7Sderaadt */ 822df930be7Sderaadt while (*from) 823ee3599c7Sespie mapvec[(unsigned char)(*from++)] = (*to) ? 824ee3599c7Sespie (unsigned char)(*to++) : 0; 825df930be7Sderaadt 826df930be7Sderaadt while (*src) { 827ee3599c7Sespie sch = (unsigned char)(*src++); 828df930be7Sderaadt dch = mapvec[sch]; 829df930be7Sderaadt while (dch != sch) { 830df930be7Sderaadt sch = dch; 831df930be7Sderaadt dch = mapvec[sch]; 832df930be7Sderaadt } 833ee3599c7Sespie if ((*dest = (char)dch)) 834df930be7Sderaadt dest++; 835df930be7Sderaadt } 836df930be7Sderaadt /* 837df930be7Sderaadt * restore all the changed characters 838df930be7Sderaadt */ 839df930be7Sderaadt while (*tmp) { 840ee3599c7Sespie mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp); 841df930be7Sderaadt tmp++; 842df930be7Sderaadt } 843df930be7Sderaadt } 844ee3599c7Sespie *dest = '\0'; 845df930be7Sderaadt } 846