1*ad93774eSespie /* $OpenBSD: eval.c,v 1.53 2005/01/21 19:11:02 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. 19f75387cbSmillert * 3. Neither the name of the University nor the names of its contributors 20df930be7Sderaadt * may be used to endorse or promote products derived from this software 21df930be7Sderaadt * without specific prior written permission. 22df930be7Sderaadt * 23df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33df930be7Sderaadt * SUCH DAMAGE. 34df930be7Sderaadt */ 35df930be7Sderaadt 36df930be7Sderaadt #ifndef lint 37df930be7Sderaadt #if 0 38df930be7Sderaadt static char sccsid[] = "@(#)eval.c 8.2 (Berkeley) 4/27/95"; 39df930be7Sderaadt #else 40*ad93774eSespie static char rcsid[] = "$OpenBSD: eval.c,v 1.53 2005/01/21 19:11:02 espie Exp $"; 41df930be7Sderaadt #endif 42df930be7Sderaadt #endif /* not lint */ 43df930be7Sderaadt 44df930be7Sderaadt /* 45df930be7Sderaadt * eval.c 46df930be7Sderaadt * Facility: m4 macro processor 47df930be7Sderaadt * by: oz 48df930be7Sderaadt */ 49df930be7Sderaadt 50df930be7Sderaadt #include <sys/types.h> 51df930be7Sderaadt #include <errno.h> 52df930be7Sderaadt #include <unistd.h> 53df930be7Sderaadt #include <stdio.h> 54df930be7Sderaadt #include <stdlib.h> 553f42598dSespie #include <stddef.h> 56df930be7Sderaadt #include <string.h> 57445b77f7Smillert #include <fcntl.h> 5881c2181eSespie #include <err.h> 59df930be7Sderaadt #include "mdef.h" 60df930be7Sderaadt #include "stdd.h" 61df930be7Sderaadt #include "extern.h" 62df930be7Sderaadt #include "pathnames.h" 63df930be7Sderaadt 64c72b5b24Smillert static void dodefn(const char *); 65c72b5b24Smillert static void dopushdef(const char *, const char *); 66c72b5b24Smillert static void dodump(const char *[], int); 67c72b5b24Smillert static void dotrace(const char *[], int, int); 68c72b5b24Smillert static void doifelse(const char *[], int); 69c72b5b24Smillert static int doincl(const char *); 70c72b5b24Smillert static int dopaste(const char *); 71c72b5b24Smillert static void gnu_dochq(const char *[], int); 72c72b5b24Smillert static void dochq(const char *[], int); 73c72b5b24Smillert static void gnu_dochc(const char *[], int); 74c72b5b24Smillert static void dochc(const char *[], int); 75c72b5b24Smillert static void dodiv(int); 76c72b5b24Smillert static void doundiv(const char *[], int); 77c72b5b24Smillert static void dosub(const char *[], int); 78c72b5b24Smillert static void map(char *, const char *, const char *, const char *); 79c72b5b24Smillert static const char *handledash(char *, char *, const char *); 80c72b5b24Smillert static void expand_builtin(const char *[], int, int); 81c72b5b24Smillert static void expand_macro(const char *[], int); 823509e8ffSespie static void dump_one_def(const char *, struct macro_definition *); 8308f7f207Sespie 8499f77b33Sespie unsigned long expansion_id; 8508f7f207Sespie 86df930be7Sderaadt /* 8708f7f207Sespie * eval - eval all macros and builtins calls 88054026c0Sespie * argc - number of elements in argv. 89054026c0Sespie * argv - element vector : 90054026c0Sespie * argv[0] = definition of a user 913509e8ffSespie * macro or NULL if built-in. 92054026c0Sespie * argv[1] = name of the macro or 93054026c0Sespie * built-in. 94054026c0Sespie * argv[2] = parameters to user-defined 95054026c0Sespie * . macro or built-in. 96054026c0Sespie * . 97054026c0Sespie * 98054026c0Sespie * A call in the form of macro-or-builtin() will result in: 99054026c0Sespie * argv[0] = nullstr 100054026c0Sespie * argv[1] = macro-or-builtin 101054026c0Sespie * argv[2] = nullstr 102054026c0Sespie * 103054026c0Sespie * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin 10408f7f207Sespie */ 10508f7f207Sespie void 106dde05c5fSespie eval(const char *argv[], int argc, int td, int is_traced) 10708f7f207Sespie { 1084dac505dSespie ssize_t mark = -1; 1094dac505dSespie 11099f77b33Sespie expansion_id++; 11108f7f207Sespie if (td & RECDEF) 11208f7f207Sespie errx(1, "%s at line %lu: expanding recursive definition for %s", 11308f7f207Sespie CURRENT_NAME, CURRENT_LINE, argv[1]); 114dde05c5fSespie if (is_traced) 1154dac505dSespie mark = trace(argv, argc, infile+ilevel); 11608f7f207Sespie if (td == MACRTYPE) 11708f7f207Sespie expand_macro(argv, argc); 11808f7f207Sespie else 11908f7f207Sespie expand_builtin(argv, argc, td); 1204dac505dSespie if (mark != -1) 1214dac505dSespie finish_trace(mark); 12208f7f207Sespie } 12308f7f207Sespie 12408f7f207Sespie /* 12508f7f207Sespie * expand_builtin - evaluate built-in macros. 126df930be7Sderaadt */ 127df930be7Sderaadt void 1288e061d4bSespie expand_builtin(const char *argv[], int argc, int td) 129df930be7Sderaadt { 13053f6f6bfSespie int c, n; 131054026c0Sespie int ac; 132df930be7Sderaadt static int sysval = 0; 133df930be7Sderaadt 134df930be7Sderaadt #ifdef DEBUG 135df930be7Sderaadt printf("argc = %d\n", argc); 136df930be7Sderaadt for (n = 0; n < argc; n++) 137df930be7Sderaadt printf("argv[%d] = %s\n", n, argv[n]); 13828728804Sespie fflush(stdout); 139df930be7Sderaadt #endif 140718b194dSespie 141df930be7Sderaadt /* 142df930be7Sderaadt * if argc == 3 and argv[2] is null, then we 143df930be7Sderaadt * have macro-or-builtin() type call. We adjust 144df930be7Sderaadt * argc to avoid further checking.. 145df930be7Sderaadt */ 146054026c0Sespie ac = argc; 147054026c0Sespie 148df930be7Sderaadt if (argc == 3 && !*(argv[2])) 149df930be7Sderaadt argc--; 150df930be7Sderaadt 151718b194dSespie switch (td & TYPEMASK) { 152df930be7Sderaadt 153df930be7Sderaadt case DEFITYPE: 154df930be7Sderaadt if (argc > 2) 155df930be7Sderaadt dodefine(argv[2], (argc > 3) ? argv[3] : null); 156df930be7Sderaadt break; 157df930be7Sderaadt 158df930be7Sderaadt case PUSDTYPE: 159df930be7Sderaadt if (argc > 2) 160df930be7Sderaadt dopushdef(argv[2], (argc > 3) ? argv[3] : null); 161df930be7Sderaadt break; 162df930be7Sderaadt 163df930be7Sderaadt case DUMPTYPE: 164df930be7Sderaadt dodump(argv, argc); 165df930be7Sderaadt break; 166df930be7Sderaadt 16734970243Sespie case TRACEONTYPE: 16834970243Sespie dotrace(argv, argc, 1); 16934970243Sespie break; 17034970243Sespie 17134970243Sespie case TRACEOFFTYPE: 17234970243Sespie dotrace(argv, argc, 0); 17334970243Sespie break; 17434970243Sespie 175df930be7Sderaadt case EXPRTYPE: 176df930be7Sderaadt /* 177df930be7Sderaadt * doexpr - evaluate arithmetic 178df930be7Sderaadt * expression 179df930be7Sderaadt */ 180df930be7Sderaadt if (argc > 2) 181df930be7Sderaadt pbnum(expr(argv[2])); 182df930be7Sderaadt break; 183df930be7Sderaadt 184df930be7Sderaadt case IFELTYPE: 185df930be7Sderaadt if (argc > 4) 186df930be7Sderaadt doifelse(argv, argc); 187df930be7Sderaadt break; 188df930be7Sderaadt 189df930be7Sderaadt case IFDFTYPE: 190df930be7Sderaadt /* 191df930be7Sderaadt * doifdef - select one of two 192df930be7Sderaadt * alternatives based on the existence of 193df930be7Sderaadt * another definition 194df930be7Sderaadt */ 195df930be7Sderaadt if (argc > 3) { 1963509e8ffSespie if (lookup_macro_definition(argv[2]) != NULL) 197df930be7Sderaadt pbstr(argv[3]); 198df930be7Sderaadt else if (argc > 4) 199df930be7Sderaadt pbstr(argv[4]); 200df930be7Sderaadt } 201df930be7Sderaadt break; 202df930be7Sderaadt 203df930be7Sderaadt case LENGTYPE: 204df930be7Sderaadt /* 205df930be7Sderaadt * dolen - find the length of the 206df930be7Sderaadt * argument 207df930be7Sderaadt */ 208df930be7Sderaadt pbnum((argc > 2) ? strlen(argv[2]) : 0); 209df930be7Sderaadt break; 210df930be7Sderaadt 211df930be7Sderaadt case INCRTYPE: 212df930be7Sderaadt /* 213df930be7Sderaadt * doincr - increment the value of the 214df930be7Sderaadt * argument 215df930be7Sderaadt */ 216df930be7Sderaadt if (argc > 2) 217df930be7Sderaadt pbnum(atoi(argv[2]) + 1); 218df930be7Sderaadt break; 219df930be7Sderaadt 220df930be7Sderaadt case DECRTYPE: 221df930be7Sderaadt /* 222df930be7Sderaadt * dodecr - decrement the value of the 223df930be7Sderaadt * argument 224df930be7Sderaadt */ 225df930be7Sderaadt if (argc > 2) 226df930be7Sderaadt pbnum(atoi(argv[2]) - 1); 227df930be7Sderaadt break; 228df930be7Sderaadt 229df930be7Sderaadt case SYSCTYPE: 230df930be7Sderaadt /* 231df930be7Sderaadt * dosys - execute system command 232df930be7Sderaadt */ 233df930be7Sderaadt if (argc > 2) 234df930be7Sderaadt sysval = system(argv[2]); 235df930be7Sderaadt break; 236df930be7Sderaadt 237df930be7Sderaadt case SYSVTYPE: 238df930be7Sderaadt /* 239df930be7Sderaadt * dosysval - return value of the last 240df930be7Sderaadt * system call. 241df930be7Sderaadt * 242df930be7Sderaadt */ 243df930be7Sderaadt pbnum(sysval); 244df930be7Sderaadt break; 245df930be7Sderaadt 246c91edbbbSespie case ESYSCMDTYPE: 247c91edbbbSespie if (argc > 2) 248c91edbbbSespie doesyscmd(argv[2]); 249c91edbbbSespie break; 250df930be7Sderaadt case INCLTYPE: 251df930be7Sderaadt if (argc > 2) 252df930be7Sderaadt if (!doincl(argv[2])) 2530d3ffe1dSespie err(1, "%s at line %lu: include(%s)", 2540d3ffe1dSespie CURRENT_NAME, CURRENT_LINE, argv[2]); 255df930be7Sderaadt break; 256df930be7Sderaadt 257df930be7Sderaadt case SINCTYPE: 258df930be7Sderaadt if (argc > 2) 259df930be7Sderaadt (void) doincl(argv[2]); 260df930be7Sderaadt break; 261df930be7Sderaadt #ifdef EXTENDED 262df930be7Sderaadt case PASTTYPE: 263df930be7Sderaadt if (argc > 2) 264df930be7Sderaadt if (!dopaste(argv[2])) 2650d3ffe1dSespie err(1, "%s at line %lu: paste(%s)", 2660d3ffe1dSespie CURRENT_NAME, CURRENT_LINE, argv[2]); 267df930be7Sderaadt break; 268df930be7Sderaadt 269df930be7Sderaadt case SPASTYPE: 270df930be7Sderaadt if (argc > 2) 271df930be7Sderaadt (void) dopaste(argv[2]); 272df930be7Sderaadt break; 273df930be7Sderaadt #endif 274df930be7Sderaadt case CHNQTYPE: 275054026c0Sespie if (mimic_gnu) 276054026c0Sespie gnu_dochq(argv, ac); 277054026c0Sespie else 278df930be7Sderaadt dochq(argv, argc); 279df930be7Sderaadt break; 280df930be7Sderaadt 281df930be7Sderaadt case CHNCTYPE: 282054026c0Sespie if (mimic_gnu) 283054026c0Sespie gnu_dochc(argv, ac); 284054026c0Sespie else 285df930be7Sderaadt dochc(argv, argc); 286df930be7Sderaadt break; 287df930be7Sderaadt 288df930be7Sderaadt case SUBSTYPE: 289df930be7Sderaadt /* 290df930be7Sderaadt * dosub - select substring 291df930be7Sderaadt * 292df930be7Sderaadt */ 293df930be7Sderaadt if (argc > 3) 294df930be7Sderaadt dosub(argv, argc); 295df930be7Sderaadt break; 296df930be7Sderaadt 297df930be7Sderaadt case SHIFTYPE: 298df930be7Sderaadt /* 299df930be7Sderaadt * doshift - push back all arguments 300df930be7Sderaadt * except the first one (i.e. skip 301df930be7Sderaadt * argv[2]) 302df930be7Sderaadt */ 303df930be7Sderaadt if (argc > 3) { 304df930be7Sderaadt for (n = argc - 1; n > 3; n--) { 3053a73db8cSderaadt pbstr(rquote); 306df930be7Sderaadt pbstr(argv[n]); 3073a73db8cSderaadt pbstr(lquote); 308aa676ce1Smillert putback(COMMA); 309df930be7Sderaadt } 3103a73db8cSderaadt pbstr(rquote); 311df930be7Sderaadt pbstr(argv[3]); 3123a73db8cSderaadt pbstr(lquote); 313df930be7Sderaadt } 314df930be7Sderaadt break; 315df930be7Sderaadt 316df930be7Sderaadt case DIVRTYPE: 317df930be7Sderaadt if (argc > 2 && (n = atoi(argv[2])) != 0) 318df930be7Sderaadt dodiv(n); 319df930be7Sderaadt else { 320df930be7Sderaadt active = stdout; 321df930be7Sderaadt oindex = 0; 322df930be7Sderaadt } 323df930be7Sderaadt break; 324df930be7Sderaadt 325df930be7Sderaadt case UNDVTYPE: 326df930be7Sderaadt doundiv(argv, argc); 327df930be7Sderaadt break; 328df930be7Sderaadt 329df930be7Sderaadt case DIVNTYPE: 330df930be7Sderaadt /* 331df930be7Sderaadt * dodivnum - return the number of 332df930be7Sderaadt * current output diversion 333df930be7Sderaadt */ 334df930be7Sderaadt pbnum(oindex); 335df930be7Sderaadt break; 336df930be7Sderaadt 337df930be7Sderaadt case UNDFTYPE: 338df930be7Sderaadt /* 339df930be7Sderaadt * doundefine - undefine a previously 340df930be7Sderaadt * defined macro(s) or m4 keyword(s). 341df930be7Sderaadt */ 342df930be7Sderaadt if (argc > 2) 343df930be7Sderaadt for (n = 2; n < argc; n++) 3443509e8ffSespie macro_undefine(argv[n]); 345df930be7Sderaadt break; 346df930be7Sderaadt 347df930be7Sderaadt case POPDTYPE: 348df930be7Sderaadt /* 349df930be7Sderaadt * dopopdef - remove the topmost 350df930be7Sderaadt * definitions of macro(s) or m4 351df930be7Sderaadt * keyword(s). 352df930be7Sderaadt */ 353df930be7Sderaadt if (argc > 2) 354df930be7Sderaadt for (n = 2; n < argc; n++) 3553509e8ffSespie macro_popdef(argv[n]); 356df930be7Sderaadt break; 357df930be7Sderaadt 358df930be7Sderaadt case MKTMTYPE: 359df930be7Sderaadt /* 360df930be7Sderaadt * dotemp - create a temporary file 361df930be7Sderaadt */ 36201e71e69Sespie if (argc > 2) { 36301e71e69Sespie int fd; 364bb34cd6cSespie char *temp; 36501e71e69Sespie 366bb34cd6cSespie temp = xstrdup(argv[2]); 367bb34cd6cSespie 368bb34cd6cSespie fd = mkstemp(temp); 36901e71e69Sespie if (fd == -1) 3700d3ffe1dSespie err(1, 3710d3ffe1dSespie "%s at line %lu: couldn't make temp file %s", 3720d3ffe1dSespie CURRENT_NAME, CURRENT_LINE, argv[2]); 37301e71e69Sespie close(fd); 374bb34cd6cSespie pbstr(temp); 375bb34cd6cSespie free(temp); 37601e71e69Sespie } 377df930be7Sderaadt break; 378df930be7Sderaadt 379df930be7Sderaadt case TRNLTYPE: 380df930be7Sderaadt /* 381df930be7Sderaadt * dotranslit - replace all characters in 382df930be7Sderaadt * the source string that appears in the 383df930be7Sderaadt * "from" string with the corresponding 384df930be7Sderaadt * characters in the "to" string. 385df930be7Sderaadt */ 386df930be7Sderaadt if (argc > 3) { 38728728804Sespie char *temp; 38828728804Sespie 389f6169a2cSespie temp = xalloc(strlen(argv[2])+1, NULL); 390df930be7Sderaadt if (argc > 4) 391df930be7Sderaadt map(temp, argv[2], argv[3], argv[4]); 392df930be7Sderaadt else 393df930be7Sderaadt map(temp, argv[2], argv[3], null); 394df930be7Sderaadt pbstr(temp); 39528728804Sespie free(temp); 3967d3e0b6bSderaadt } else if (argc > 2) 397df930be7Sderaadt pbstr(argv[2]); 398df930be7Sderaadt break; 399df930be7Sderaadt 400df930be7Sderaadt case INDXTYPE: 401df930be7Sderaadt /* 402df930be7Sderaadt * doindex - find the index of the second 403df930be7Sderaadt * argument string in the first argument 404df930be7Sderaadt * string. -1 if not present. 405df930be7Sderaadt */ 406df930be7Sderaadt pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1); 407df930be7Sderaadt break; 408df930be7Sderaadt 409df930be7Sderaadt case ERRPTYPE: 410df930be7Sderaadt /* 411df930be7Sderaadt * doerrp - print the arguments to stderr 412df930be7Sderaadt * file 413df930be7Sderaadt */ 414df930be7Sderaadt if (argc > 2) { 415df930be7Sderaadt for (n = 2; n < argc; n++) 416df930be7Sderaadt fprintf(stderr, "%s ", argv[n]); 417df930be7Sderaadt fprintf(stderr, "\n"); 418df930be7Sderaadt } 419df930be7Sderaadt break; 420df930be7Sderaadt 421df930be7Sderaadt case DNLNTYPE: 422df930be7Sderaadt /* 423df930be7Sderaadt * dodnl - eat-up-to and including 424df930be7Sderaadt * newline 425df930be7Sderaadt */ 426df930be7Sderaadt while ((c = gpbc()) != '\n' && c != EOF) 427df930be7Sderaadt ; 428df930be7Sderaadt break; 429df930be7Sderaadt 430df930be7Sderaadt case M4WRTYPE: 431df930be7Sderaadt /* 432df930be7Sderaadt * dom4wrap - set up for 433df930be7Sderaadt * wrap-up/wind-down activity 434df930be7Sderaadt */ 435df930be7Sderaadt m4wraps = (argc > 2) ? xstrdup(argv[2]) : null; 436df930be7Sderaadt break; 437df930be7Sderaadt 438df930be7Sderaadt case EXITTYPE: 439df930be7Sderaadt /* 440df930be7Sderaadt * doexit - immediate exit from m4. 441df930be7Sderaadt */ 442df930be7Sderaadt killdiv(); 443df930be7Sderaadt exit((argc > 2) ? atoi(argv[2]) : 0); 444df930be7Sderaadt break; 445df930be7Sderaadt 446df930be7Sderaadt case DEFNTYPE: 447df930be7Sderaadt if (argc > 2) 448df930be7Sderaadt for (n = 2; n < argc; n++) 449df930be7Sderaadt dodefn(argv[n]); 450df930be7Sderaadt break; 451df930be7Sderaadt 452b8161682Sespie case INDIRTYPE: /* Indirect call */ 453b8161682Sespie if (argc > 2) 454b8161682Sespie doindir(argv, argc); 455b8161682Sespie break; 456b8161682Sespie 457b8161682Sespie case BUILTINTYPE: /* Builtins only */ 458b8161682Sespie if (argc > 2) 459b8161682Sespie dobuiltin(argv, argc); 460b8161682Sespie break; 461b8161682Sespie 462b8161682Sespie case PATSTYPE: 463b8161682Sespie if (argc > 2) 464b8161682Sespie dopatsubst(argv, argc); 465b8161682Sespie break; 466b8161682Sespie case REGEXPTYPE: 467b8161682Sespie if (argc > 2) 468b8161682Sespie doregexp(argv, argc); 469b8161682Sespie break; 470b8161682Sespie case LINETYPE: 471b8161682Sespie doprintlineno(infile+ilevel); 472b8161682Sespie break; 473b8161682Sespie case FILENAMETYPE: 474b8161682Sespie doprintfilename(infile+ilevel); 475b8161682Sespie break; 476423624b7Sespie case SELFTYPE: 477423624b7Sespie pbstr(rquote); 478423624b7Sespie pbstr(argv[1]); 479423624b7Sespie pbstr(lquote); 480423624b7Sespie break; 481df930be7Sderaadt default: 4820d3ffe1dSespie errx(1, "%s at line %lu: eval: major botch.", 4830d3ffe1dSespie CURRENT_NAME, CURRENT_LINE); 484df930be7Sderaadt break; 485df930be7Sderaadt } 486df930be7Sderaadt } 487df930be7Sderaadt 488df930be7Sderaadt /* 48908f7f207Sespie * expand_macro - user-defined macro expansion 490df930be7Sderaadt */ 491df930be7Sderaadt void 4928e061d4bSespie expand_macro(const char *argv[], int argc) 493df930be7Sderaadt { 494bb34cd6cSespie const char *t; 495bb34cd6cSespie const char *p; 49653f6f6bfSespie int n; 49753f6f6bfSespie int argno; 498df930be7Sderaadt 499df930be7Sderaadt t = argv[0]; /* defn string as a whole */ 500df930be7Sderaadt p = t; 501df930be7Sderaadt while (*p) 502df930be7Sderaadt p++; 503df930be7Sderaadt p--; /* last character of defn */ 504df930be7Sderaadt while (p > t) { 505df930be7Sderaadt if (*(p - 1) != ARGFLAG) 506dd84b4a6Sespie PUTBACK(*p); 507df930be7Sderaadt else { 508df930be7Sderaadt switch (*p) { 509df930be7Sderaadt 510df930be7Sderaadt case '#': 511df930be7Sderaadt pbnum(argc - 2); 512df930be7Sderaadt break; 513df930be7Sderaadt case '0': 514df930be7Sderaadt case '1': 515df930be7Sderaadt case '2': 516df930be7Sderaadt case '3': 517df930be7Sderaadt case '4': 518df930be7Sderaadt case '5': 519df930be7Sderaadt case '6': 520df930be7Sderaadt case '7': 521df930be7Sderaadt case '8': 522df930be7Sderaadt case '9': 523df930be7Sderaadt if ((argno = *p - '0') < argc - 1) 524df930be7Sderaadt pbstr(argv[argno + 1]); 525df930be7Sderaadt break; 526df930be7Sderaadt case '*': 527faa30e49Sespie if (argc > 2) { 528df930be7Sderaadt for (n = argc - 1; n > 2; n--) { 529df930be7Sderaadt pbstr(argv[n]); 530aa676ce1Smillert putback(COMMA); 531df930be7Sderaadt } 532df930be7Sderaadt pbstr(argv[2]); 533faa30e49Sespie } 534df930be7Sderaadt break; 535aa676ce1Smillert case '@': 536faa30e49Sespie if (argc > 2) { 537aa676ce1Smillert for (n = argc - 1; n > 2; n--) { 538aa676ce1Smillert pbstr(rquote); 539aa676ce1Smillert pbstr(argv[n]); 540aa676ce1Smillert pbstr(lquote); 541aa676ce1Smillert putback(COMMA); 542aa676ce1Smillert } 543aa676ce1Smillert pbstr(rquote); 544aa676ce1Smillert pbstr(argv[2]); 545aa676ce1Smillert pbstr(lquote); 546faa30e49Sespie } 547aa676ce1Smillert break; 548df930be7Sderaadt default: 549dd84b4a6Sespie PUTBACK(*p); 550dd84b4a6Sespie PUTBACK('$'); 551df930be7Sderaadt break; 552df930be7Sderaadt } 553df930be7Sderaadt p--; 554df930be7Sderaadt } 555df930be7Sderaadt p--; 556df930be7Sderaadt } 557df930be7Sderaadt if (p == t) /* do last character */ 558dd84b4a6Sespie PUTBACK(*p); 559df930be7Sderaadt } 560df930be7Sderaadt 5615ddad5ccSespie 562df930be7Sderaadt /* 5635ddad5ccSespie * dodefine - install definition in the table 5645ddad5ccSespie */ 5655ddad5ccSespie void 5665ddad5ccSespie dodefine(const char *name, const char *defn) 5675ddad5ccSespie { 5685ddad5ccSespie if (!*name) 5695ddad5ccSespie errx(1, "%s at line %lu: null definition.", CURRENT_NAME, 5705ddad5ccSespie CURRENT_LINE); 5713509e8ffSespie macro_define(name, defn); 572df930be7Sderaadt } 573df930be7Sderaadt 574df930be7Sderaadt /* 575df930be7Sderaadt * dodefn - push back a quoted definition of 576df930be7Sderaadt * the given name. 577df930be7Sderaadt */ 578bb34cd6cSespie static void 5798e061d4bSespie dodefn(const char *name) 580df930be7Sderaadt { 5813509e8ffSespie struct macro_definition *p; 582df930be7Sderaadt 5833509e8ffSespie if ((p = lookup_macro_definition(name)) != NULL) { 5845ddad5ccSespie if ((p->type & TYPEMASK) == MACRTYPE) { 5853a73db8cSderaadt pbstr(rquote); 586df930be7Sderaadt pbstr(p->defn); 5873a73db8cSderaadt pbstr(lquote); 5885ddad5ccSespie } else { 5895ddad5ccSespie pbstr(p->defn); 590f8b42d48Sespie pbstr(BUILTIN_MARKER); 591f8b42d48Sespie } 592df930be7Sderaadt } 593df930be7Sderaadt } 594df930be7Sderaadt 595df930be7Sderaadt /* 596df930be7Sderaadt * dopushdef - install a definition in the hash table 597df930be7Sderaadt * without removing a previous definition. Since 598df930be7Sderaadt * each new entry is entered in *front* of the 599df930be7Sderaadt * hash bucket, it hides a previous definition from 600df930be7Sderaadt * lookup. 601df930be7Sderaadt */ 602bb34cd6cSespie static void 6038e061d4bSespie dopushdef(const char *name, const char *defn) 604df930be7Sderaadt { 605df930be7Sderaadt if (!*name) 6060d3ffe1dSespie errx(1, "%s at line %lu: null definition", CURRENT_NAME, 6070d3ffe1dSespie CURRENT_LINE); 6083509e8ffSespie macro_pushdef(name, defn); 609df930be7Sderaadt } 610df930be7Sderaadt 611df930be7Sderaadt /* 612dd0682a2Sespie * dump_one_def - dump the specified definition. 613dd0682a2Sespie */ 614dd0682a2Sespie static void 6153509e8ffSespie dump_one_def(const char *name, struct macro_definition *p) 616dd0682a2Sespie { 617*ad93774eSespie if (!traceout) 618*ad93774eSespie traceout = stderr; 6195191fa0aSespie if (mimic_gnu) { 6205191fa0aSespie if ((p->type & TYPEMASK) == MACRTYPE) 6213509e8ffSespie fprintf(traceout, "%s:\t%s\n", name, p->defn); 6225191fa0aSespie else { 6233509e8ffSespie fprintf(traceout, "%s:\t<%s>\n", name, p->defn); 6245191fa0aSespie } 6255191fa0aSespie } else 6263509e8ffSespie fprintf(traceout, "`%s'\t`%s'\n", name, p->defn); 627dd0682a2Sespie } 628dd0682a2Sespie 629dd0682a2Sespie /* 630df930be7Sderaadt * dodumpdef - dump the specified definitions in the hash 631df930be7Sderaadt * table to stderr. If nothing is specified, the entire 632df930be7Sderaadt * hash table is dumped. 633df930be7Sderaadt */ 634bb34cd6cSespie static void 6358e061d4bSespie dodump(const char *argv[], int argc) 636df930be7Sderaadt { 63753f6f6bfSespie int n; 6383509e8ffSespie struct macro_definition *p; 639df930be7Sderaadt 640df930be7Sderaadt if (argc > 2) { 641df930be7Sderaadt for (n = 2; n < argc; n++) 6423509e8ffSespie if ((p = lookup_macro_definition(argv[n])) != NULL) 6433509e8ffSespie dump_one_def(argv[n], p); 6443509e8ffSespie } else 6453509e8ffSespie macro_for_all(dump_one_def); 646df930be7Sderaadt } 647df930be7Sderaadt 648df930be7Sderaadt /* 64934970243Sespie * dotrace - mark some macros as traced/untraced depending upon on. 65034970243Sespie */ 65134970243Sespie static void 6528e061d4bSespie dotrace(const char *argv[], int argc, int on) 65334970243Sespie { 65434970243Sespie int n; 65534970243Sespie 65634970243Sespie if (argc > 2) { 65734970243Sespie for (n = 2; n < argc; n++) 65834970243Sespie mark_traced(argv[n], on); 65934970243Sespie } else 66034970243Sespie mark_traced(NULL, on); 66134970243Sespie } 66234970243Sespie 66334970243Sespie /* 664df930be7Sderaadt * doifelse - select one of two alternatives - loop. 665df930be7Sderaadt */ 666bb34cd6cSespie static void 6678e061d4bSespie doifelse(const char *argv[], int argc) 668df930be7Sderaadt { 669df930be7Sderaadt cycle { 670df930be7Sderaadt if (STREQ(argv[2], argv[3])) 671df930be7Sderaadt pbstr(argv[4]); 672df930be7Sderaadt else if (argc == 6) 673df930be7Sderaadt pbstr(argv[5]); 674df930be7Sderaadt else if (argc > 6) { 675df930be7Sderaadt argv += 3; 676df930be7Sderaadt argc -= 3; 677df930be7Sderaadt continue; 678df930be7Sderaadt } 679df930be7Sderaadt break; 680df930be7Sderaadt } 681df930be7Sderaadt } 682df930be7Sderaadt 683df930be7Sderaadt /* 684df930be7Sderaadt * doinclude - include a given file. 685df930be7Sderaadt */ 686bb34cd6cSespie static int 6878e061d4bSespie doincl(const char *ifile) 688df930be7Sderaadt { 689df930be7Sderaadt if (ilevel + 1 == MAXINP) 6900d3ffe1dSespie errx(1, "%s at line %lu: too many include files.", 6910d3ffe1dSespie CURRENT_NAME, CURRENT_LINE); 6920d3ffe1dSespie if (fopen_trypath(infile+ilevel+1, ifile) != NULL) { 693df930be7Sderaadt ilevel++; 694df930be7Sderaadt bbase[ilevel] = bufbase = bp; 695df930be7Sderaadt return (1); 6967d3e0b6bSderaadt } else 697df930be7Sderaadt return (0); 698df930be7Sderaadt } 699df930be7Sderaadt 700df930be7Sderaadt #ifdef EXTENDED 701df930be7Sderaadt /* 702df930be7Sderaadt * dopaste - include a given file without any 703df930be7Sderaadt * macro processing. 704df930be7Sderaadt */ 705bb34cd6cSespie static int 7068e061d4bSespie dopaste(const char *pfile) 707df930be7Sderaadt { 708df930be7Sderaadt FILE *pf; 70953f6f6bfSespie int c; 710df930be7Sderaadt 711df930be7Sderaadt if ((pf = fopen(pfile, "r")) != NULL) { 712aec72266Sespie if (synch_lines) 713aec72266Sespie fprintf(active, "#line 1 \"%s\"\n", pfile); 714df930be7Sderaadt while ((c = getc(pf)) != EOF) 715df930be7Sderaadt putc(c, active); 716df930be7Sderaadt (void) fclose(pf); 717aec72266Sespie emit_synchline(); 718df930be7Sderaadt return (1); 7197d3e0b6bSderaadt } else 720df930be7Sderaadt return (0); 721df930be7Sderaadt } 722df930be7Sderaadt #endif 723df930be7Sderaadt 724054026c0Sespie static void 7258e061d4bSespie gnu_dochq(const char *argv[], int ac) 726054026c0Sespie { 727054026c0Sespie /* In gnu-m4 mode, the only way to restore quotes is to have no 728054026c0Sespie * arguments at all. */ 729054026c0Sespie if (ac == 2) { 730054026c0Sespie lquote[0] = LQUOTE, lquote[1] = EOS; 731054026c0Sespie rquote[0] = RQUOTE, rquote[1] = EOS; 732054026c0Sespie } else { 733054026c0Sespie strlcpy(lquote, argv[2], sizeof(lquote)); 734054026c0Sespie if(ac > 3) 735054026c0Sespie strlcpy(rquote, argv[3], sizeof(rquote)); 736054026c0Sespie else 737054026c0Sespie rquote[0] = EOS; 738054026c0Sespie } 739054026c0Sespie } 740054026c0Sespie 741df930be7Sderaadt /* 742df930be7Sderaadt * dochq - change quote characters 743df930be7Sderaadt */ 744bb34cd6cSespie static void 7458e061d4bSespie dochq(const char *argv[], int argc) 746df930be7Sderaadt { 747df930be7Sderaadt if (argc > 2) { 74818a1973bSderaadt if (*argv[2]) 749b81b15b2Sespie strlcpy(lquote, argv[2], sizeof(lquote)); 75018a1973bSderaadt else { 75118a1973bSderaadt lquote[0] = LQUOTE; 752f0484631Sespie lquote[1] = EOS; 75318a1973bSderaadt } 754df930be7Sderaadt if (argc > 3) { 755df930be7Sderaadt if (*argv[3]) 756b81b15b2Sespie strlcpy(rquote, argv[3], sizeof(rquote)); 7577d3e0b6bSderaadt } else 7583ffdcb07Sespie strlcpy(rquote, lquote, sizeof(rquote)); 7597d3e0b6bSderaadt } else { 760f0484631Sespie lquote[0] = LQUOTE, lquote[1] = EOS; 761f0484631Sespie rquote[0] = RQUOTE, rquote[1] = EOS; 762df930be7Sderaadt } 763df930be7Sderaadt } 764df930be7Sderaadt 765054026c0Sespie static void 7668e061d4bSespie gnu_dochc(const char *argv[], int ac) 767054026c0Sespie { 768054026c0Sespie /* In gnu-m4 mode, no arguments mean no comment 769054026c0Sespie * arguments at all. */ 770054026c0Sespie if (ac == 2) { 771054026c0Sespie scommt[0] = EOS; 772054026c0Sespie ecommt[0] = EOS; 773054026c0Sespie } else { 774054026c0Sespie if (*argv[2]) 775054026c0Sespie strlcpy(scommt, argv[2], sizeof(scommt)); 776054026c0Sespie else 777054026c0Sespie scommt[0] = SCOMMT, scommt[1] = EOS; 778054026c0Sespie if(ac > 3 && *argv[3]) 779054026c0Sespie strlcpy(ecommt, argv[3], sizeof(ecommt)); 780054026c0Sespie else 781054026c0Sespie ecommt[0] = ECOMMT, ecommt[1] = EOS; 782054026c0Sespie } 783054026c0Sespie } 784df930be7Sderaadt /* 785df930be7Sderaadt * dochc - change comment characters 786df930be7Sderaadt */ 787bb34cd6cSespie static void 7888e061d4bSespie dochc(const char *argv[], int argc) 789df930be7Sderaadt { 790df930be7Sderaadt if (argc > 2) { 791df930be7Sderaadt if (*argv[2]) 792b81b15b2Sespie strlcpy(scommt, argv[2], sizeof(scommt)); 793df930be7Sderaadt if (argc > 3) { 794df930be7Sderaadt if (*argv[3]) 795b81b15b2Sespie strlcpy(ecommt, argv[3], sizeof(ecommt)); 796df930be7Sderaadt } 797df930be7Sderaadt else 798f0484631Sespie ecommt[0] = ECOMMT, ecommt[1] = EOS; 799df930be7Sderaadt } 800df930be7Sderaadt else { 801f0484631Sespie scommt[0] = SCOMMT, scommt[1] = EOS; 802f0484631Sespie ecommt[0] = ECOMMT, ecommt[1] = EOS; 803df930be7Sderaadt } 804df930be7Sderaadt } 805df930be7Sderaadt 806df930be7Sderaadt /* 807df930be7Sderaadt * dodivert - divert the output to a temporary file 808df930be7Sderaadt */ 809bb34cd6cSespie static void 8108e061d4bSespie dodiv(int n) 811df930be7Sderaadt { 812445b77f7Smillert int fd; 813445b77f7Smillert 8147d3e0b6bSderaadt oindex = n; 81525afcddbSespie if (n >= maxout) { 81625afcddbSespie if (mimic_gnu) 81725afcddbSespie resizedivs(n + 10); 81825afcddbSespie else 81925afcddbSespie n = 0; /* bitbucket */ 82025afcddbSespie } 82125afcddbSespie 82225afcddbSespie if (n < 0) 823df930be7Sderaadt n = 0; /* bitbucket */ 824df930be7Sderaadt if (outfile[n] == NULL) { 8253f42598dSespie char fname[] = _PATH_DIVNAME; 8263f42598dSespie 8273f42598dSespie if ((fd = mkstemp(fname)) < 0 || 8283f42598dSespie (outfile[n] = fdopen(fd, "w+")) == NULL) 8293f42598dSespie err(1, "%s: cannot divert", fname); 8303f42598dSespie if (unlink(fname) == -1) 8313f42598dSespie err(1, "%s: cannot unlink", fname); 832df930be7Sderaadt } 833df930be7Sderaadt active = outfile[n]; 834df930be7Sderaadt } 835df930be7Sderaadt 836df930be7Sderaadt /* 837df930be7Sderaadt * doundivert - undivert a specified output, or all 838df930be7Sderaadt * other outputs, in numerical order. 839df930be7Sderaadt */ 840bb34cd6cSespie static void 8418e061d4bSespie doundiv(const char *argv[], int argc) 842df930be7Sderaadt { 84353f6f6bfSespie int ind; 84453f6f6bfSespie int n; 845df930be7Sderaadt 846df930be7Sderaadt if (argc > 2) { 847df930be7Sderaadt for (ind = 2; ind < argc; ind++) { 848df930be7Sderaadt n = atoi(argv[ind]); 84925afcddbSespie if (n > 0 && n < maxout && outfile[n] != NULL) 850df930be7Sderaadt getdiv(n); 851df930be7Sderaadt 852df930be7Sderaadt } 853df930be7Sderaadt } 854df930be7Sderaadt else 85525afcddbSespie for (n = 1; n < maxout; n++) 856df930be7Sderaadt if (outfile[n] != NULL) 857df930be7Sderaadt getdiv(n); 858df930be7Sderaadt } 859df930be7Sderaadt 860df930be7Sderaadt /* 861df930be7Sderaadt * dosub - select substring 862df930be7Sderaadt */ 863bb34cd6cSespie static void 8648e061d4bSespie dosub(const char *argv[], int argc) 865df930be7Sderaadt { 866bb34cd6cSespie const char *ap, *fc, *k; 86753f6f6bfSespie int nc; 868df930be7Sderaadt 869df930be7Sderaadt ap = argv[2]; /* target string */ 870df930be7Sderaadt #ifdef EXPR 871df930be7Sderaadt fc = ap + expr(argv[3]); /* first char */ 872df930be7Sderaadt #else 873df930be7Sderaadt fc = ap + atoi(argv[3]); /* first char */ 874df930be7Sderaadt #endif 875bee8364eSespie nc = strlen(fc); 876bee8364eSespie if (argc >= 5) 877bee8364eSespie #ifdef EXPR 878bee8364eSespie nc = min(nc, expr(argv[4])); 879bee8364eSespie #else 880bee8364eSespie nc = min(nc, atoi(argv[4])); 881bee8364eSespie #endif 882df930be7Sderaadt if (fc >= ap && fc < ap + strlen(ap)) 883bee8364eSespie for (k = fc + nc - 1; k >= fc; k--) 884df930be7Sderaadt putback(*k); 885df930be7Sderaadt } 886df930be7Sderaadt 887df930be7Sderaadt /* 888df930be7Sderaadt * map: 889df930be7Sderaadt * map every character of s1 that is specified in from 890df930be7Sderaadt * into s3 and replace in s. (source s1 remains untouched) 891df930be7Sderaadt * 892df930be7Sderaadt * This is a standard implementation of map(s,from,to) function of ICON 893df930be7Sderaadt * language. Within mapvec, we replace every character of "from" with 894df930be7Sderaadt * the corresponding character in "to". If "to" is shorter than "from", 895df930be7Sderaadt * than the corresponding entries are null, which means that those 896df930be7Sderaadt * characters dissapear altogether. Furthermore, imagine 897df930be7Sderaadt * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, 898df930be7Sderaadt * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' 899df930be7Sderaadt * ultimately maps to `*'. In order to achieve this effect in an efficient 900df930be7Sderaadt * manner (i.e. without multiple passes over the destination string), we 901df930be7Sderaadt * loop over mapvec, starting with the initial source character. if the 902df930be7Sderaadt * character value (dch) in this location is different than the source 903df930be7Sderaadt * character (sch), sch becomes dch, once again to index into mapvec, until 904df930be7Sderaadt * the character value stabilizes (i.e. sch = dch, in other words 905df930be7Sderaadt * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary 906df930be7Sderaadt * character, it will stabilize, since mapvec[0] == 0 at all times. At the 907df930be7Sderaadt * end, we restore mapvec* back to normal where mapvec[n] == n for 908df930be7Sderaadt * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is 909df930be7Sderaadt * about 5 times faster than any algorithm that makes multiple passes over 910df930be7Sderaadt * destination string. 911df930be7Sderaadt */ 912bb34cd6cSespie static void 9138e061d4bSespie map(char *dest, const char *src, const char *from, const char *to) 914df930be7Sderaadt { 915bb34cd6cSespie const char *tmp; 916ee3599c7Sespie unsigned char sch, dch; 91787c5c065Sespie static char frombis[257]; 91887c5c065Sespie static char tobis[257]; 919ee3599c7Sespie static unsigned char mapvec[256] = { 920ee3599c7Sespie 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 921ee3599c7Sespie 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 922ee3599c7Sespie 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 923ee3599c7Sespie 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 924ee3599c7Sespie 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 925ee3599c7Sespie 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 926ee3599c7Sespie 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 927ee3599c7Sespie 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 928ee3599c7Sespie 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 929ee3599c7Sespie 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 930ee3599c7Sespie 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 931ee3599c7Sespie 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 932ee3599c7Sespie 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 933ee3599c7Sespie 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 934ee3599c7Sespie 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 935ee3599c7Sespie 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 936ee3599c7Sespie 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 937ee3599c7Sespie 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 938df930be7Sderaadt }; 939df930be7Sderaadt 940df930be7Sderaadt if (*src) { 94187c5c065Sespie if (mimic_gnu) { 94287c5c065Sespie /* 94387c5c065Sespie * expand character ranges on the fly 94487c5c065Sespie */ 94587c5c065Sespie from = handledash(frombis, frombis + 256, from); 94687c5c065Sespie to = handledash(tobis, tobis + 256, to); 94787c5c065Sespie } 948df930be7Sderaadt tmp = from; 949df930be7Sderaadt /* 950df930be7Sderaadt * create a mapping between "from" and 951df930be7Sderaadt * "to" 952df930be7Sderaadt */ 953df930be7Sderaadt while (*from) 954ee3599c7Sespie mapvec[(unsigned char)(*from++)] = (*to) ? 955ee3599c7Sespie (unsigned char)(*to++) : 0; 956df930be7Sderaadt 957df930be7Sderaadt while (*src) { 958ee3599c7Sespie sch = (unsigned char)(*src++); 959df930be7Sderaadt dch = mapvec[sch]; 960df930be7Sderaadt while (dch != sch) { 961df930be7Sderaadt sch = dch; 962df930be7Sderaadt dch = mapvec[sch]; 963df930be7Sderaadt } 964ee3599c7Sespie if ((*dest = (char)dch)) 965df930be7Sderaadt dest++; 966df930be7Sderaadt } 967df930be7Sderaadt /* 968df930be7Sderaadt * restore all the changed characters 969df930be7Sderaadt */ 970df930be7Sderaadt while (*tmp) { 971ee3599c7Sespie mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp); 972df930be7Sderaadt tmp++; 973df930be7Sderaadt } 974df930be7Sderaadt } 975ee3599c7Sespie *dest = '\0'; 976df930be7Sderaadt } 97787c5c065Sespie 97887c5c065Sespie 97987c5c065Sespie /* 98087c5c065Sespie * handledash: 98187c5c065Sespie * use buffer to copy the src string, expanding character ranges 98287c5c065Sespie * on the way. 98387c5c065Sespie */ 98487c5c065Sespie static const char * 9858e061d4bSespie handledash(char *buffer, char *end, const char *src) 98687c5c065Sespie { 98787c5c065Sespie char *p; 98887c5c065Sespie 98987c5c065Sespie p = buffer; 99087c5c065Sespie while(*src) { 99187c5c065Sespie if (src[1] == '-' && src[2]) { 99287c5c065Sespie unsigned char i; 99387c5c065Sespie for (i = (unsigned char)src[0]; 99487c5c065Sespie i <= (unsigned char)src[2]; i++) { 99587c5c065Sespie *p++ = i; 99687c5c065Sespie if (p == end) { 99787c5c065Sespie *p = '\0'; 99887c5c065Sespie return buffer; 99987c5c065Sespie } 100087c5c065Sespie } 100187c5c065Sespie src += 3; 100287c5c065Sespie } else 100387c5c065Sespie *p++ = *src++; 100487c5c065Sespie if (p == end) 100587c5c065Sespie break; 100687c5c065Sespie } 100787c5c065Sespie *p = '\0'; 100887c5c065Sespie return buffer; 100987c5c065Sespie } 1010