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