1*5ddad5ccSespie /* $OpenBSD: eval.c,v 1.48 2003/06/18 21:08:07 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*5ddad5ccSespie static char rcsid[] = "$OpenBSD: eval.c,v 1.48 2003/06/18 21:08:07 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 64f8b42d48Sespie #define BUILTIN_MARKER "__builtin_" 65f8b42d48Sespie 66*5ddad5ccSespie static void setup_definition(ndptr, const char *); 67c72b5b24Smillert static void dodefn(const char *); 68c72b5b24Smillert static void dopushdef(const char *, const char *); 69c72b5b24Smillert static void dodump(const char *[], int); 70c72b5b24Smillert static void dotrace(const char *[], int, int); 71c72b5b24Smillert static void doifelse(const char *[], int); 72c72b5b24Smillert static int doincl(const char *); 73c72b5b24Smillert static int dopaste(const char *); 74c72b5b24Smillert static void gnu_dochq(const char *[], int); 75c72b5b24Smillert static void dochq(const char *[], int); 76c72b5b24Smillert static void gnu_dochc(const char *[], int); 77c72b5b24Smillert static void dochc(const char *[], int); 78c72b5b24Smillert static void dodiv(int); 79c72b5b24Smillert static void doundiv(const char *[], int); 80c72b5b24Smillert static void dosub(const char *[], int); 81c72b5b24Smillert static void map(char *, const char *, const char *, const char *); 82c72b5b24Smillert static const char *handledash(char *, char *, const char *); 83c72b5b24Smillert static void expand_builtin(const char *[], int, int); 84c72b5b24Smillert static void expand_macro(const char *[], int); 85c72b5b24Smillert static void dump_one_def(ndptr); 8608f7f207Sespie 8799f77b33Sespie unsigned long expansion_id; 8808f7f207Sespie 89df930be7Sderaadt /* 9008f7f207Sespie * eval - eval all macros and builtins calls 91054026c0Sespie * argc - number of elements in argv. 92054026c0Sespie * argv - element vector : 93054026c0Sespie * argv[0] = definition of a user 94054026c0Sespie * macro or nil if built-in. 95054026c0Sespie * argv[1] = name of the macro or 96054026c0Sespie * built-in. 97054026c0Sespie * argv[2] = parameters to user-defined 98054026c0Sespie * . macro or built-in. 99054026c0Sespie * . 100054026c0Sespie * 101054026c0Sespie * A call in the form of macro-or-builtin() will result in: 102054026c0Sespie * argv[0] = nullstr 103054026c0Sespie * argv[1] = macro-or-builtin 104054026c0Sespie * argv[2] = nullstr 105054026c0Sespie * 106054026c0Sespie * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin 10708f7f207Sespie */ 10808f7f207Sespie void 1098e061d4bSespie eval(const char *argv[], int argc, int td) 11008f7f207Sespie { 1114dac505dSespie ssize_t mark = -1; 1124dac505dSespie 11399f77b33Sespie expansion_id++; 11408f7f207Sespie if (td & RECDEF) 11508f7f207Sespie errx(1, "%s at line %lu: expanding recursive definition for %s", 11608f7f207Sespie CURRENT_NAME, CURRENT_LINE, argv[1]); 1174dac505dSespie if (traced_macros && is_traced(argv[1])) 1184dac505dSespie mark = trace(argv, argc, infile+ilevel); 11908f7f207Sespie if (td == MACRTYPE) 12008f7f207Sespie expand_macro(argv, argc); 12108f7f207Sespie else 12208f7f207Sespie expand_builtin(argv, argc, td); 1234dac505dSespie if (mark != -1) 1244dac505dSespie finish_trace(mark); 12508f7f207Sespie } 12608f7f207Sespie 12708f7f207Sespie /* 12808f7f207Sespie * expand_builtin - evaluate built-in macros. 129df930be7Sderaadt */ 130df930be7Sderaadt void 1318e061d4bSespie expand_builtin(const char *argv[], int argc, int td) 132df930be7Sderaadt { 13353f6f6bfSespie int c, n; 134054026c0Sespie int ac; 135df930be7Sderaadt static int sysval = 0; 136df930be7Sderaadt 137df930be7Sderaadt #ifdef DEBUG 138df930be7Sderaadt printf("argc = %d\n", argc); 139df930be7Sderaadt for (n = 0; n < argc; n++) 140df930be7Sderaadt printf("argv[%d] = %s\n", n, argv[n]); 14128728804Sespie fflush(stdout); 142df930be7Sderaadt #endif 143718b194dSespie 144df930be7Sderaadt /* 145df930be7Sderaadt * if argc == 3 and argv[2] is null, then we 146df930be7Sderaadt * have macro-or-builtin() type call. We adjust 147df930be7Sderaadt * argc to avoid further checking.. 148df930be7Sderaadt */ 149054026c0Sespie ac = argc; 150054026c0Sespie 151df930be7Sderaadt if (argc == 3 && !*(argv[2])) 152df930be7Sderaadt argc--; 153df930be7Sderaadt 154718b194dSespie switch (td & TYPEMASK) { 155df930be7Sderaadt 156df930be7Sderaadt case DEFITYPE: 157df930be7Sderaadt if (argc > 2) 158df930be7Sderaadt dodefine(argv[2], (argc > 3) ? argv[3] : null); 159df930be7Sderaadt break; 160df930be7Sderaadt 161df930be7Sderaadt case PUSDTYPE: 162df930be7Sderaadt if (argc > 2) 163df930be7Sderaadt dopushdef(argv[2], (argc > 3) ? argv[3] : null); 164df930be7Sderaadt break; 165df930be7Sderaadt 166df930be7Sderaadt case DUMPTYPE: 167df930be7Sderaadt dodump(argv, argc); 168df930be7Sderaadt break; 169df930be7Sderaadt 17034970243Sespie case TRACEONTYPE: 17134970243Sespie dotrace(argv, argc, 1); 17234970243Sespie break; 17334970243Sespie 17434970243Sespie case TRACEOFFTYPE: 17534970243Sespie dotrace(argv, argc, 0); 17634970243Sespie break; 17734970243Sespie 178df930be7Sderaadt case EXPRTYPE: 179df930be7Sderaadt /* 180df930be7Sderaadt * doexpr - evaluate arithmetic 181df930be7Sderaadt * expression 182df930be7Sderaadt */ 183df930be7Sderaadt if (argc > 2) 184df930be7Sderaadt pbnum(expr(argv[2])); 185df930be7Sderaadt break; 186df930be7Sderaadt 187df930be7Sderaadt case IFELTYPE: 188df930be7Sderaadt if (argc > 4) 189df930be7Sderaadt doifelse(argv, argc); 190df930be7Sderaadt break; 191df930be7Sderaadt 192df930be7Sderaadt case IFDFTYPE: 193df930be7Sderaadt /* 194df930be7Sderaadt * doifdef - select one of two 195df930be7Sderaadt * alternatives based on the existence of 196df930be7Sderaadt * another definition 197df930be7Sderaadt */ 198df930be7Sderaadt if (argc > 3) { 199df930be7Sderaadt if (lookup(argv[2]) != nil) 200df930be7Sderaadt pbstr(argv[3]); 201df930be7Sderaadt else if (argc > 4) 202df930be7Sderaadt pbstr(argv[4]); 203df930be7Sderaadt } 204df930be7Sderaadt break; 205df930be7Sderaadt 206df930be7Sderaadt case LENGTYPE: 207df930be7Sderaadt /* 208df930be7Sderaadt * dolen - find the length of the 209df930be7Sderaadt * argument 210df930be7Sderaadt */ 211df930be7Sderaadt pbnum((argc > 2) ? strlen(argv[2]) : 0); 212df930be7Sderaadt break; 213df930be7Sderaadt 214df930be7Sderaadt case INCRTYPE: 215df930be7Sderaadt /* 216df930be7Sderaadt * doincr - increment the value of the 217df930be7Sderaadt * argument 218df930be7Sderaadt */ 219df930be7Sderaadt if (argc > 2) 220df930be7Sderaadt pbnum(atoi(argv[2]) + 1); 221df930be7Sderaadt break; 222df930be7Sderaadt 223df930be7Sderaadt case DECRTYPE: 224df930be7Sderaadt /* 225df930be7Sderaadt * dodecr - decrement the value of the 226df930be7Sderaadt * argument 227df930be7Sderaadt */ 228df930be7Sderaadt if (argc > 2) 229df930be7Sderaadt pbnum(atoi(argv[2]) - 1); 230df930be7Sderaadt break; 231df930be7Sderaadt 232df930be7Sderaadt case SYSCTYPE: 233df930be7Sderaadt /* 234df930be7Sderaadt * dosys - execute system command 235df930be7Sderaadt */ 236df930be7Sderaadt if (argc > 2) 237df930be7Sderaadt sysval = system(argv[2]); 238df930be7Sderaadt break; 239df930be7Sderaadt 240df930be7Sderaadt case SYSVTYPE: 241df930be7Sderaadt /* 242df930be7Sderaadt * dosysval - return value of the last 243df930be7Sderaadt * system call. 244df930be7Sderaadt * 245df930be7Sderaadt */ 246df930be7Sderaadt pbnum(sysval); 247df930be7Sderaadt break; 248df930be7Sderaadt 249c91edbbbSespie case ESYSCMDTYPE: 250c91edbbbSespie if (argc > 2) 251c91edbbbSespie doesyscmd(argv[2]); 252c91edbbbSespie break; 253df930be7Sderaadt case INCLTYPE: 254df930be7Sderaadt if (argc > 2) 255df930be7Sderaadt if (!doincl(argv[2])) 2560d3ffe1dSespie err(1, "%s at line %lu: include(%s)", 2570d3ffe1dSespie CURRENT_NAME, CURRENT_LINE, argv[2]); 258df930be7Sderaadt break; 259df930be7Sderaadt 260df930be7Sderaadt case SINCTYPE: 261df930be7Sderaadt if (argc > 2) 262df930be7Sderaadt (void) doincl(argv[2]); 263df930be7Sderaadt break; 264df930be7Sderaadt #ifdef EXTENDED 265df930be7Sderaadt case PASTTYPE: 266df930be7Sderaadt if (argc > 2) 267df930be7Sderaadt if (!dopaste(argv[2])) 2680d3ffe1dSespie err(1, "%s at line %lu: paste(%s)", 2690d3ffe1dSespie CURRENT_NAME, CURRENT_LINE, argv[2]); 270df930be7Sderaadt break; 271df930be7Sderaadt 272df930be7Sderaadt case SPASTYPE: 273df930be7Sderaadt if (argc > 2) 274df930be7Sderaadt (void) dopaste(argv[2]); 275df930be7Sderaadt break; 276df930be7Sderaadt #endif 277df930be7Sderaadt case CHNQTYPE: 278054026c0Sespie if (mimic_gnu) 279054026c0Sespie gnu_dochq(argv, ac); 280054026c0Sespie else 281df930be7Sderaadt dochq(argv, argc); 282df930be7Sderaadt break; 283df930be7Sderaadt 284df930be7Sderaadt case CHNCTYPE: 285054026c0Sespie if (mimic_gnu) 286054026c0Sespie gnu_dochc(argv, ac); 287054026c0Sespie else 288df930be7Sderaadt dochc(argv, argc); 289df930be7Sderaadt break; 290df930be7Sderaadt 291df930be7Sderaadt case SUBSTYPE: 292df930be7Sderaadt /* 293df930be7Sderaadt * dosub - select substring 294df930be7Sderaadt * 295df930be7Sderaadt */ 296df930be7Sderaadt if (argc > 3) 297df930be7Sderaadt dosub(argv, argc); 298df930be7Sderaadt break; 299df930be7Sderaadt 300df930be7Sderaadt case SHIFTYPE: 301df930be7Sderaadt /* 302df930be7Sderaadt * doshift - push back all arguments 303df930be7Sderaadt * except the first one (i.e. skip 304df930be7Sderaadt * argv[2]) 305df930be7Sderaadt */ 306df930be7Sderaadt if (argc > 3) { 307df930be7Sderaadt for (n = argc - 1; n > 3; n--) { 3083a73db8cSderaadt pbstr(rquote); 309df930be7Sderaadt pbstr(argv[n]); 3103a73db8cSderaadt pbstr(lquote); 311aa676ce1Smillert putback(COMMA); 312df930be7Sderaadt } 3133a73db8cSderaadt pbstr(rquote); 314df930be7Sderaadt pbstr(argv[3]); 3153a73db8cSderaadt pbstr(lquote); 316df930be7Sderaadt } 317df930be7Sderaadt break; 318df930be7Sderaadt 319df930be7Sderaadt case DIVRTYPE: 320df930be7Sderaadt if (argc > 2 && (n = atoi(argv[2])) != 0) 321df930be7Sderaadt dodiv(n); 322df930be7Sderaadt else { 323df930be7Sderaadt active = stdout; 324df930be7Sderaadt oindex = 0; 325df930be7Sderaadt } 326df930be7Sderaadt break; 327df930be7Sderaadt 328df930be7Sderaadt case UNDVTYPE: 329df930be7Sderaadt doundiv(argv, argc); 330df930be7Sderaadt break; 331df930be7Sderaadt 332df930be7Sderaadt case DIVNTYPE: 333df930be7Sderaadt /* 334df930be7Sderaadt * dodivnum - return the number of 335df930be7Sderaadt * current output diversion 336df930be7Sderaadt */ 337df930be7Sderaadt pbnum(oindex); 338df930be7Sderaadt break; 339df930be7Sderaadt 340df930be7Sderaadt case UNDFTYPE: 341df930be7Sderaadt /* 342df930be7Sderaadt * doundefine - undefine a previously 343df930be7Sderaadt * defined macro(s) or m4 keyword(s). 344df930be7Sderaadt */ 345df930be7Sderaadt if (argc > 2) 346df930be7Sderaadt for (n = 2; n < argc; n++) 347df930be7Sderaadt remhash(argv[n], ALL); 348df930be7Sderaadt break; 349df930be7Sderaadt 350df930be7Sderaadt case POPDTYPE: 351df930be7Sderaadt /* 352df930be7Sderaadt * dopopdef - remove the topmost 353df930be7Sderaadt * definitions of macro(s) or m4 354df930be7Sderaadt * keyword(s). 355df930be7Sderaadt */ 356df930be7Sderaadt if (argc > 2) 357df930be7Sderaadt for (n = 2; n < argc; n++) 358df930be7Sderaadt remhash(argv[n], TOP); 359df930be7Sderaadt break; 360df930be7Sderaadt 361df930be7Sderaadt case MKTMTYPE: 362df930be7Sderaadt /* 363df930be7Sderaadt * dotemp - create a temporary file 364df930be7Sderaadt */ 36501e71e69Sespie if (argc > 2) { 36601e71e69Sespie int fd; 367bb34cd6cSespie char *temp; 36801e71e69Sespie 369bb34cd6cSespie temp = xstrdup(argv[2]); 370bb34cd6cSespie 371bb34cd6cSespie fd = mkstemp(temp); 37201e71e69Sespie if (fd == -1) 3730d3ffe1dSespie err(1, 3740d3ffe1dSespie "%s at line %lu: couldn't make temp file %s", 3750d3ffe1dSespie CURRENT_NAME, CURRENT_LINE, argv[2]); 37601e71e69Sespie close(fd); 377bb34cd6cSespie pbstr(temp); 378bb34cd6cSespie free(temp); 37901e71e69Sespie } 380df930be7Sderaadt break; 381df930be7Sderaadt 382df930be7Sderaadt case TRNLTYPE: 383df930be7Sderaadt /* 384df930be7Sderaadt * dotranslit - replace all characters in 385df930be7Sderaadt * the source string that appears in the 386df930be7Sderaadt * "from" string with the corresponding 387df930be7Sderaadt * characters in the "to" string. 388df930be7Sderaadt */ 389df930be7Sderaadt if (argc > 3) { 39028728804Sespie char *temp; 39128728804Sespie 39228728804Sespie temp = xalloc(strlen(argv[2])+1); 393df930be7Sderaadt if (argc > 4) 394df930be7Sderaadt map(temp, argv[2], argv[3], argv[4]); 395df930be7Sderaadt else 396df930be7Sderaadt map(temp, argv[2], argv[3], null); 397df930be7Sderaadt pbstr(temp); 39828728804Sespie free(temp); 3997d3e0b6bSderaadt } else if (argc > 2) 400df930be7Sderaadt pbstr(argv[2]); 401df930be7Sderaadt break; 402df930be7Sderaadt 403df930be7Sderaadt case INDXTYPE: 404df930be7Sderaadt /* 405df930be7Sderaadt * doindex - find the index of the second 406df930be7Sderaadt * argument string in the first argument 407df930be7Sderaadt * string. -1 if not present. 408df930be7Sderaadt */ 409df930be7Sderaadt pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1); 410df930be7Sderaadt break; 411df930be7Sderaadt 412df930be7Sderaadt case ERRPTYPE: 413df930be7Sderaadt /* 414df930be7Sderaadt * doerrp - print the arguments to stderr 415df930be7Sderaadt * file 416df930be7Sderaadt */ 417df930be7Sderaadt if (argc > 2) { 418df930be7Sderaadt for (n = 2; n < argc; n++) 419df930be7Sderaadt fprintf(stderr, "%s ", argv[n]); 420df930be7Sderaadt fprintf(stderr, "\n"); 421df930be7Sderaadt } 422df930be7Sderaadt break; 423df930be7Sderaadt 424df930be7Sderaadt case DNLNTYPE: 425df930be7Sderaadt /* 426df930be7Sderaadt * dodnl - eat-up-to and including 427df930be7Sderaadt * newline 428df930be7Sderaadt */ 429df930be7Sderaadt while ((c = gpbc()) != '\n' && c != EOF) 430df930be7Sderaadt ; 431df930be7Sderaadt break; 432df930be7Sderaadt 433df930be7Sderaadt case M4WRTYPE: 434df930be7Sderaadt /* 435df930be7Sderaadt * dom4wrap - set up for 436df930be7Sderaadt * wrap-up/wind-down activity 437df930be7Sderaadt */ 438df930be7Sderaadt m4wraps = (argc > 2) ? xstrdup(argv[2]) : null; 439df930be7Sderaadt break; 440df930be7Sderaadt 441df930be7Sderaadt case EXITTYPE: 442df930be7Sderaadt /* 443df930be7Sderaadt * doexit - immediate exit from m4. 444df930be7Sderaadt */ 445df930be7Sderaadt killdiv(); 446df930be7Sderaadt exit((argc > 2) ? atoi(argv[2]) : 0); 447df930be7Sderaadt break; 448df930be7Sderaadt 449df930be7Sderaadt case DEFNTYPE: 450df930be7Sderaadt if (argc > 2) 451df930be7Sderaadt for (n = 2; n < argc; n++) 452df930be7Sderaadt dodefn(argv[n]); 453df930be7Sderaadt break; 454df930be7Sderaadt 455b8161682Sespie case INDIRTYPE: /* Indirect call */ 456b8161682Sespie if (argc > 2) 457b8161682Sespie doindir(argv, argc); 458b8161682Sespie break; 459b8161682Sespie 460b8161682Sespie case BUILTINTYPE: /* Builtins only */ 461b8161682Sespie if (argc > 2) 462b8161682Sespie dobuiltin(argv, argc); 463b8161682Sespie break; 464b8161682Sespie 465b8161682Sespie case PATSTYPE: 466b8161682Sespie if (argc > 2) 467b8161682Sespie dopatsubst(argv, argc); 468b8161682Sespie break; 469b8161682Sespie case REGEXPTYPE: 470b8161682Sespie if (argc > 2) 471b8161682Sespie doregexp(argv, argc); 472b8161682Sespie break; 473b8161682Sespie case LINETYPE: 474b8161682Sespie doprintlineno(infile+ilevel); 475b8161682Sespie break; 476b8161682Sespie case FILENAMETYPE: 477b8161682Sespie doprintfilename(infile+ilevel); 478b8161682Sespie break; 479423624b7Sespie case SELFTYPE: 480423624b7Sespie pbstr(rquote); 481423624b7Sespie pbstr(argv[1]); 482423624b7Sespie pbstr(lquote); 483423624b7Sespie break; 484df930be7Sderaadt default: 4850d3ffe1dSespie errx(1, "%s at line %lu: eval: major botch.", 4860d3ffe1dSespie CURRENT_NAME, CURRENT_LINE); 487df930be7Sderaadt break; 488df930be7Sderaadt } 489df930be7Sderaadt } 490df930be7Sderaadt 491df930be7Sderaadt /* 49208f7f207Sespie * expand_macro - user-defined macro expansion 493df930be7Sderaadt */ 494df930be7Sderaadt void 4958e061d4bSespie expand_macro(const char *argv[], int argc) 496df930be7Sderaadt { 497bb34cd6cSespie const char *t; 498bb34cd6cSespie const char *p; 49953f6f6bfSespie int n; 50053f6f6bfSespie int argno; 501df930be7Sderaadt 502df930be7Sderaadt t = argv[0]; /* defn string as a whole */ 503df930be7Sderaadt p = t; 504df930be7Sderaadt while (*p) 505df930be7Sderaadt p++; 506df930be7Sderaadt p--; /* last character of defn */ 507df930be7Sderaadt while (p > t) { 508df930be7Sderaadt if (*(p - 1) != ARGFLAG) 509dd84b4a6Sespie PUTBACK(*p); 510df930be7Sderaadt else { 511df930be7Sderaadt switch (*p) { 512df930be7Sderaadt 513df930be7Sderaadt case '#': 514df930be7Sderaadt pbnum(argc - 2); 515df930be7Sderaadt break; 516df930be7Sderaadt case '0': 517df930be7Sderaadt case '1': 518df930be7Sderaadt case '2': 519df930be7Sderaadt case '3': 520df930be7Sderaadt case '4': 521df930be7Sderaadt case '5': 522df930be7Sderaadt case '6': 523df930be7Sderaadt case '7': 524df930be7Sderaadt case '8': 525df930be7Sderaadt case '9': 526df930be7Sderaadt if ((argno = *p - '0') < argc - 1) 527df930be7Sderaadt pbstr(argv[argno + 1]); 528df930be7Sderaadt break; 529df930be7Sderaadt case '*': 530faa30e49Sespie if (argc > 2) { 531df930be7Sderaadt for (n = argc - 1; n > 2; n--) { 532df930be7Sderaadt pbstr(argv[n]); 533aa676ce1Smillert putback(COMMA); 534df930be7Sderaadt } 535df930be7Sderaadt pbstr(argv[2]); 536faa30e49Sespie } 537df930be7Sderaadt break; 538aa676ce1Smillert case '@': 539faa30e49Sespie if (argc > 2) { 540aa676ce1Smillert for (n = argc - 1; n > 2; n--) { 541aa676ce1Smillert pbstr(rquote); 542aa676ce1Smillert pbstr(argv[n]); 543aa676ce1Smillert pbstr(lquote); 544aa676ce1Smillert putback(COMMA); 545aa676ce1Smillert } 546aa676ce1Smillert pbstr(rquote); 547aa676ce1Smillert pbstr(argv[2]); 548aa676ce1Smillert pbstr(lquote); 549faa30e49Sespie } 550aa676ce1Smillert break; 551df930be7Sderaadt default: 552dd84b4a6Sespie PUTBACK(*p); 553dd84b4a6Sespie PUTBACK('$'); 554df930be7Sderaadt break; 555df930be7Sderaadt } 556df930be7Sderaadt p--; 557df930be7Sderaadt } 558df930be7Sderaadt p--; 559df930be7Sderaadt } 560df930be7Sderaadt if (p == t) /* do last character */ 561dd84b4a6Sespie PUTBACK(*p); 562df930be7Sderaadt } 563df930be7Sderaadt 564*5ddad5ccSespie 565df930be7Sderaadt /* 566*5ddad5ccSespie * common part to dodefine and dopushdef 567df930be7Sderaadt */ 568*5ddad5ccSespie static void 569*5ddad5ccSespie setup_definition(ndptr p, const char *defn) 570df930be7Sderaadt { 571f8b42d48Sespie int n; 572df930be7Sderaadt 573f8b42d48Sespie if (strncmp(defn, BUILTIN_MARKER, sizeof(BUILTIN_MARKER)-1) == 0) { 574f8b42d48Sespie n = builtin_type(defn+sizeof(BUILTIN_MARKER)-1); 575f8b42d48Sespie if (n != -1) { 57655d92b07Sespie p->type = n & TYPEMASK; 57755d92b07Sespie if ((n & NOARGS) == 0) 57855d92b07Sespie p->type |= NEEDARGS; 579*5ddad5ccSespie p->defn = xstrdup(defn+sizeof(BUILTIN_MARKER)-1); 580f8b42d48Sespie return; 581f8b42d48Sespie } 582f8b42d48Sespie } 583df930be7Sderaadt if (!*defn) 584df930be7Sderaadt p->defn = null; 585df930be7Sderaadt else 586df930be7Sderaadt p->defn = xstrdup(defn); 587df930be7Sderaadt p->type = MACRTYPE; 588*5ddad5ccSespie } 589*5ddad5ccSespie 590*5ddad5ccSespie /* 591*5ddad5ccSespie * dodefine - install definition in the table 592*5ddad5ccSespie */ 593*5ddad5ccSespie void 594*5ddad5ccSespie dodefine(const char *name, const char *defn) 595*5ddad5ccSespie { 596*5ddad5ccSespie ndptr p; 597*5ddad5ccSespie 598*5ddad5ccSespie if (!*name) 599*5ddad5ccSespie errx(1, "%s at line %lu: null definition.", CURRENT_NAME, 600*5ddad5ccSespie CURRENT_LINE); 601*5ddad5ccSespie if ((p = lookup(name)) == nil) 602*5ddad5ccSespie p = addent(name); 603*5ddad5ccSespie else if (p->defn != null) 604*5ddad5ccSespie free((char *) p->defn); 605*5ddad5ccSespie setup_definition(p, defn); 606718b194dSespie if (STREQ(name, defn)) 607718b194dSespie p->type |= RECDEF; 608df930be7Sderaadt } 609df930be7Sderaadt 610df930be7Sderaadt /* 611df930be7Sderaadt * dodefn - push back a quoted definition of 612df930be7Sderaadt * the given name. 613df930be7Sderaadt */ 614bb34cd6cSespie static void 6158e061d4bSespie dodefn(const char *name) 616df930be7Sderaadt { 61753f6f6bfSespie ndptr p; 618f8b42d48Sespie char *real; 619df930be7Sderaadt 620f8b42d48Sespie if ((p = lookup(name)) != nil) { 621*5ddad5ccSespie if ((p->type & TYPEMASK) == MACRTYPE) { 6223a73db8cSderaadt pbstr(rquote); 623df930be7Sderaadt pbstr(p->defn); 6243a73db8cSderaadt pbstr(lquote); 625*5ddad5ccSespie } else { 626*5ddad5ccSespie pbstr(p->defn); 627f8b42d48Sespie pbstr(BUILTIN_MARKER); 628f8b42d48Sespie } 629df930be7Sderaadt } 630df930be7Sderaadt } 631df930be7Sderaadt 632df930be7Sderaadt /* 633df930be7Sderaadt * dopushdef - install a definition in the hash table 634df930be7Sderaadt * without removing a previous definition. Since 635df930be7Sderaadt * each new entry is entered in *front* of the 636df930be7Sderaadt * hash bucket, it hides a previous definition from 637df930be7Sderaadt * lookup. 638df930be7Sderaadt */ 639bb34cd6cSespie static void 6408e061d4bSespie dopushdef(const char *name, const char *defn) 641df930be7Sderaadt { 64253f6f6bfSespie ndptr p; 643df930be7Sderaadt 644df930be7Sderaadt if (!*name) 6450d3ffe1dSespie errx(1, "%s at line %lu: null definition", CURRENT_NAME, 6460d3ffe1dSespie CURRENT_LINE); 647df930be7Sderaadt p = addent(name); 648*5ddad5ccSespie setup_definition(p, defn); 649718b194dSespie if (STREQ(name, defn)) 650718b194dSespie p->type |= RECDEF; 651df930be7Sderaadt } 652df930be7Sderaadt 653df930be7Sderaadt /* 654dd0682a2Sespie * dump_one_def - dump the specified definition. 655dd0682a2Sespie */ 656dd0682a2Sespie static void 6578e061d4bSespie dump_one_def(ndptr p) 658dd0682a2Sespie { 6595191fa0aSespie if (mimic_gnu) { 6605191fa0aSespie if ((p->type & TYPEMASK) == MACRTYPE) 6614dac505dSespie fprintf(traceout, "%s:\t%s\n", p->name, p->defn); 6625191fa0aSespie else { 663*5ddad5ccSespie fprintf(traceout, "%s:\t<%s>\n", p->name, p->defn); 6645191fa0aSespie } 6655191fa0aSespie } else 6664dac505dSespie fprintf(traceout, "`%s'\t`%s'\n", p->name, p->defn); 667dd0682a2Sespie } 668dd0682a2Sespie 669dd0682a2Sespie /* 670df930be7Sderaadt * dodumpdef - dump the specified definitions in the hash 671df930be7Sderaadt * table to stderr. If nothing is specified, the entire 672df930be7Sderaadt * hash table is dumped. 673df930be7Sderaadt */ 674bb34cd6cSespie static void 6758e061d4bSespie dodump(const char *argv[], int argc) 676df930be7Sderaadt { 67753f6f6bfSespie int n; 678df930be7Sderaadt ndptr p; 679df930be7Sderaadt 680df930be7Sderaadt if (argc > 2) { 681df930be7Sderaadt for (n = 2; n < argc; n++) 682df930be7Sderaadt if ((p = lookup(argv[n])) != nil) 683dd0682a2Sespie dump_one_def(p); 6847d3e0b6bSderaadt } else { 685df930be7Sderaadt for (n = 0; n < HASHSIZE; n++) 686df930be7Sderaadt for (p = hashtab[n]; p != nil; p = p->nxtptr) 687dd0682a2Sespie dump_one_def(p); 688df930be7Sderaadt } 689df930be7Sderaadt } 690df930be7Sderaadt 691df930be7Sderaadt /* 69234970243Sespie * dotrace - mark some macros as traced/untraced depending upon on. 69334970243Sespie */ 69434970243Sespie static void 6958e061d4bSespie dotrace(const char *argv[], int argc, int on) 69634970243Sespie { 69734970243Sespie int n; 69834970243Sespie 69934970243Sespie if (argc > 2) { 70034970243Sespie for (n = 2; n < argc; n++) 70134970243Sespie mark_traced(argv[n], on); 70234970243Sespie } else 70334970243Sespie mark_traced(NULL, on); 70434970243Sespie } 70534970243Sespie 70634970243Sespie /* 707df930be7Sderaadt * doifelse - select one of two alternatives - loop. 708df930be7Sderaadt */ 709bb34cd6cSespie static void 7108e061d4bSespie doifelse(const char *argv[], int argc) 711df930be7Sderaadt { 712df930be7Sderaadt cycle { 713df930be7Sderaadt if (STREQ(argv[2], argv[3])) 714df930be7Sderaadt pbstr(argv[4]); 715df930be7Sderaadt else if (argc == 6) 716df930be7Sderaadt pbstr(argv[5]); 717df930be7Sderaadt else if (argc > 6) { 718df930be7Sderaadt argv += 3; 719df930be7Sderaadt argc -= 3; 720df930be7Sderaadt continue; 721df930be7Sderaadt } 722df930be7Sderaadt break; 723df930be7Sderaadt } 724df930be7Sderaadt } 725df930be7Sderaadt 726df930be7Sderaadt /* 727df930be7Sderaadt * doinclude - include a given file. 728df930be7Sderaadt */ 729bb34cd6cSespie static int 7308e061d4bSespie doincl(const char *ifile) 731df930be7Sderaadt { 732df930be7Sderaadt if (ilevel + 1 == MAXINP) 7330d3ffe1dSespie errx(1, "%s at line %lu: too many include files.", 7340d3ffe1dSespie CURRENT_NAME, CURRENT_LINE); 7350d3ffe1dSespie if (fopen_trypath(infile+ilevel+1, ifile) != NULL) { 736df930be7Sderaadt ilevel++; 737df930be7Sderaadt bbase[ilevel] = bufbase = bp; 738df930be7Sderaadt return (1); 7397d3e0b6bSderaadt } else 740df930be7Sderaadt return (0); 741df930be7Sderaadt } 742df930be7Sderaadt 743df930be7Sderaadt #ifdef EXTENDED 744df930be7Sderaadt /* 745df930be7Sderaadt * dopaste - include a given file without any 746df930be7Sderaadt * macro processing. 747df930be7Sderaadt */ 748bb34cd6cSespie static int 7498e061d4bSespie dopaste(const char *pfile) 750df930be7Sderaadt { 751df930be7Sderaadt FILE *pf; 75253f6f6bfSespie int c; 753df930be7Sderaadt 754df930be7Sderaadt if ((pf = fopen(pfile, "r")) != NULL) { 755aec72266Sespie if (synch_lines) 756aec72266Sespie fprintf(active, "#line 1 \"%s\"\n", pfile); 757df930be7Sderaadt while ((c = getc(pf)) != EOF) 758df930be7Sderaadt putc(c, active); 759df930be7Sderaadt (void) fclose(pf); 760aec72266Sespie emit_synchline(); 761df930be7Sderaadt return (1); 7627d3e0b6bSderaadt } else 763df930be7Sderaadt return (0); 764df930be7Sderaadt } 765df930be7Sderaadt #endif 766df930be7Sderaadt 767054026c0Sespie static void 7688e061d4bSespie gnu_dochq(const char *argv[], int ac) 769054026c0Sespie { 770054026c0Sespie /* In gnu-m4 mode, the only way to restore quotes is to have no 771054026c0Sespie * arguments at all. */ 772054026c0Sespie if (ac == 2) { 773054026c0Sespie lquote[0] = LQUOTE, lquote[1] = EOS; 774054026c0Sespie rquote[0] = RQUOTE, rquote[1] = EOS; 775054026c0Sespie } else { 776054026c0Sespie strlcpy(lquote, argv[2], sizeof(lquote)); 777054026c0Sespie if(ac > 3) 778054026c0Sespie strlcpy(rquote, argv[3], sizeof(rquote)); 779054026c0Sespie else 780054026c0Sespie rquote[0] = EOS; 781054026c0Sespie } 782054026c0Sespie } 783054026c0Sespie 784df930be7Sderaadt /* 785df930be7Sderaadt * dochq - change quote characters 786df930be7Sderaadt */ 787bb34cd6cSespie static void 7888e061d4bSespie dochq(const char *argv[], int argc) 789df930be7Sderaadt { 790df930be7Sderaadt if (argc > 2) { 79118a1973bSderaadt if (*argv[2]) 792b81b15b2Sespie strlcpy(lquote, argv[2], sizeof(lquote)); 79318a1973bSderaadt else { 79418a1973bSderaadt lquote[0] = LQUOTE; 795f0484631Sespie lquote[1] = EOS; 79618a1973bSderaadt } 797df930be7Sderaadt if (argc > 3) { 798df930be7Sderaadt if (*argv[3]) 799b81b15b2Sespie strlcpy(rquote, argv[3], sizeof(rquote)); 8007d3e0b6bSderaadt } else 8013ffdcb07Sespie strlcpy(rquote, lquote, sizeof(rquote)); 8027d3e0b6bSderaadt } else { 803f0484631Sespie lquote[0] = LQUOTE, lquote[1] = EOS; 804f0484631Sespie rquote[0] = RQUOTE, rquote[1] = EOS; 805df930be7Sderaadt } 806df930be7Sderaadt } 807df930be7Sderaadt 808054026c0Sespie static void 8098e061d4bSespie gnu_dochc(const char *argv[], int ac) 810054026c0Sespie { 811054026c0Sespie /* In gnu-m4 mode, no arguments mean no comment 812054026c0Sespie * arguments at all. */ 813054026c0Sespie if (ac == 2) { 814054026c0Sespie scommt[0] = EOS; 815054026c0Sespie ecommt[0] = EOS; 816054026c0Sespie } else { 817054026c0Sespie if (*argv[2]) 818054026c0Sespie strlcpy(scommt, argv[2], sizeof(scommt)); 819054026c0Sespie else 820054026c0Sespie scommt[0] = SCOMMT, scommt[1] = EOS; 821054026c0Sespie if(ac > 3 && *argv[3]) 822054026c0Sespie strlcpy(ecommt, argv[3], sizeof(ecommt)); 823054026c0Sespie else 824054026c0Sespie ecommt[0] = ECOMMT, ecommt[1] = EOS; 825054026c0Sespie } 826054026c0Sespie } 827df930be7Sderaadt /* 828df930be7Sderaadt * dochc - change comment characters 829df930be7Sderaadt */ 830bb34cd6cSespie static void 8318e061d4bSespie dochc(const char *argv[], int argc) 832df930be7Sderaadt { 833df930be7Sderaadt if (argc > 2) { 834df930be7Sderaadt if (*argv[2]) 835b81b15b2Sespie strlcpy(scommt, argv[2], sizeof(scommt)); 836df930be7Sderaadt if (argc > 3) { 837df930be7Sderaadt if (*argv[3]) 838b81b15b2Sespie strlcpy(ecommt, argv[3], sizeof(ecommt)); 839df930be7Sderaadt } 840df930be7Sderaadt else 841f0484631Sespie ecommt[0] = ECOMMT, ecommt[1] = EOS; 842df930be7Sderaadt } 843df930be7Sderaadt else { 844f0484631Sespie scommt[0] = SCOMMT, scommt[1] = EOS; 845f0484631Sespie ecommt[0] = ECOMMT, ecommt[1] = EOS; 846df930be7Sderaadt } 847df930be7Sderaadt } 848df930be7Sderaadt 849df930be7Sderaadt /* 850df930be7Sderaadt * dodivert - divert the output to a temporary file 851df930be7Sderaadt */ 852bb34cd6cSespie static void 8538e061d4bSespie dodiv(int n) 854df930be7Sderaadt { 855445b77f7Smillert int fd; 856445b77f7Smillert 8577d3e0b6bSderaadt oindex = n; 85825afcddbSespie if (n >= maxout) { 85925afcddbSespie if (mimic_gnu) 86025afcddbSespie resizedivs(n + 10); 86125afcddbSespie else 86225afcddbSespie n = 0; /* bitbucket */ 86325afcddbSespie } 86425afcddbSespie 86525afcddbSespie if (n < 0) 866df930be7Sderaadt n = 0; /* bitbucket */ 867df930be7Sderaadt if (outfile[n] == NULL) { 8683f42598dSespie char fname[] = _PATH_DIVNAME; 8693f42598dSespie 8703f42598dSespie if ((fd = mkstemp(fname)) < 0 || 8713f42598dSespie (outfile[n] = fdopen(fd, "w+")) == NULL) 8723f42598dSespie err(1, "%s: cannot divert", fname); 8733f42598dSespie if (unlink(fname) == -1) 8743f42598dSespie err(1, "%s: cannot unlink", fname); 875df930be7Sderaadt } 876df930be7Sderaadt active = outfile[n]; 877df930be7Sderaadt } 878df930be7Sderaadt 879df930be7Sderaadt /* 880df930be7Sderaadt * doundivert - undivert a specified output, or all 881df930be7Sderaadt * other outputs, in numerical order. 882df930be7Sderaadt */ 883bb34cd6cSespie static void 8848e061d4bSespie doundiv(const char *argv[], int argc) 885df930be7Sderaadt { 88653f6f6bfSespie int ind; 88753f6f6bfSespie int n; 888df930be7Sderaadt 889df930be7Sderaadt if (argc > 2) { 890df930be7Sderaadt for (ind = 2; ind < argc; ind++) { 891df930be7Sderaadt n = atoi(argv[ind]); 89225afcddbSespie if (n > 0 && n < maxout && outfile[n] != NULL) 893df930be7Sderaadt getdiv(n); 894df930be7Sderaadt 895df930be7Sderaadt } 896df930be7Sderaadt } 897df930be7Sderaadt else 89825afcddbSespie for (n = 1; n < maxout; n++) 899df930be7Sderaadt if (outfile[n] != NULL) 900df930be7Sderaadt getdiv(n); 901df930be7Sderaadt } 902df930be7Sderaadt 903df930be7Sderaadt /* 904df930be7Sderaadt * dosub - select substring 905df930be7Sderaadt */ 906bb34cd6cSespie static void 9078e061d4bSespie dosub(const char *argv[], int argc) 908df930be7Sderaadt { 909bb34cd6cSespie const char *ap, *fc, *k; 91053f6f6bfSespie int nc; 911df930be7Sderaadt 912df930be7Sderaadt ap = argv[2]; /* target string */ 913df930be7Sderaadt #ifdef EXPR 914df930be7Sderaadt fc = ap + expr(argv[3]); /* first char */ 915df930be7Sderaadt #else 916df930be7Sderaadt fc = ap + atoi(argv[3]); /* first char */ 917df930be7Sderaadt #endif 918bee8364eSespie nc = strlen(fc); 919bee8364eSespie if (argc >= 5) 920bee8364eSespie #ifdef EXPR 921bee8364eSespie nc = min(nc, expr(argv[4])); 922bee8364eSespie #else 923bee8364eSespie nc = min(nc, atoi(argv[4])); 924bee8364eSespie #endif 925df930be7Sderaadt if (fc >= ap && fc < ap + strlen(ap)) 926bee8364eSespie for (k = fc + nc - 1; k >= fc; k--) 927df930be7Sderaadt putback(*k); 928df930be7Sderaadt } 929df930be7Sderaadt 930df930be7Sderaadt /* 931df930be7Sderaadt * map: 932df930be7Sderaadt * map every character of s1 that is specified in from 933df930be7Sderaadt * into s3 and replace in s. (source s1 remains untouched) 934df930be7Sderaadt * 935df930be7Sderaadt * This is a standard implementation of map(s,from,to) function of ICON 936df930be7Sderaadt * language. Within mapvec, we replace every character of "from" with 937df930be7Sderaadt * the corresponding character in "to". If "to" is shorter than "from", 938df930be7Sderaadt * than the corresponding entries are null, which means that those 939df930be7Sderaadt * characters dissapear altogether. Furthermore, imagine 940df930be7Sderaadt * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, 941df930be7Sderaadt * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' 942df930be7Sderaadt * ultimately maps to `*'. In order to achieve this effect in an efficient 943df930be7Sderaadt * manner (i.e. without multiple passes over the destination string), we 944df930be7Sderaadt * loop over mapvec, starting with the initial source character. if the 945df930be7Sderaadt * character value (dch) in this location is different than the source 946df930be7Sderaadt * character (sch), sch becomes dch, once again to index into mapvec, until 947df930be7Sderaadt * the character value stabilizes (i.e. sch = dch, in other words 948df930be7Sderaadt * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary 949df930be7Sderaadt * character, it will stabilize, since mapvec[0] == 0 at all times. At the 950df930be7Sderaadt * end, we restore mapvec* back to normal where mapvec[n] == n for 951df930be7Sderaadt * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is 952df930be7Sderaadt * about 5 times faster than any algorithm that makes multiple passes over 953df930be7Sderaadt * destination string. 954df930be7Sderaadt */ 955bb34cd6cSespie static void 9568e061d4bSespie map(char *dest, const char *src, const char *from, const char *to) 957df930be7Sderaadt { 958bb34cd6cSespie const char *tmp; 959ee3599c7Sespie unsigned char sch, dch; 96087c5c065Sespie static char frombis[257]; 96187c5c065Sespie static char tobis[257]; 962ee3599c7Sespie static unsigned char mapvec[256] = { 963ee3599c7Sespie 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 964ee3599c7Sespie 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 965ee3599c7Sespie 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 966ee3599c7Sespie 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 967ee3599c7Sespie 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 968ee3599c7Sespie 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 969ee3599c7Sespie 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 970ee3599c7Sespie 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 971ee3599c7Sespie 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 972ee3599c7Sespie 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 973ee3599c7Sespie 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 974ee3599c7Sespie 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 975ee3599c7Sespie 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 976ee3599c7Sespie 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 977ee3599c7Sespie 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 978ee3599c7Sespie 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 979ee3599c7Sespie 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 980ee3599c7Sespie 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 981df930be7Sderaadt }; 982df930be7Sderaadt 983df930be7Sderaadt if (*src) { 98487c5c065Sespie if (mimic_gnu) { 98587c5c065Sespie /* 98687c5c065Sespie * expand character ranges on the fly 98787c5c065Sespie */ 98887c5c065Sespie from = handledash(frombis, frombis + 256, from); 98987c5c065Sespie to = handledash(tobis, tobis + 256, to); 99087c5c065Sespie } 991df930be7Sderaadt tmp = from; 992df930be7Sderaadt /* 993df930be7Sderaadt * create a mapping between "from" and 994df930be7Sderaadt * "to" 995df930be7Sderaadt */ 996df930be7Sderaadt while (*from) 997ee3599c7Sespie mapvec[(unsigned char)(*from++)] = (*to) ? 998ee3599c7Sespie (unsigned char)(*to++) : 0; 999df930be7Sderaadt 1000df930be7Sderaadt while (*src) { 1001ee3599c7Sespie sch = (unsigned char)(*src++); 1002df930be7Sderaadt dch = mapvec[sch]; 1003df930be7Sderaadt while (dch != sch) { 1004df930be7Sderaadt sch = dch; 1005df930be7Sderaadt dch = mapvec[sch]; 1006df930be7Sderaadt } 1007ee3599c7Sespie if ((*dest = (char)dch)) 1008df930be7Sderaadt dest++; 1009df930be7Sderaadt } 1010df930be7Sderaadt /* 1011df930be7Sderaadt * restore all the changed characters 1012df930be7Sderaadt */ 1013df930be7Sderaadt while (*tmp) { 1014ee3599c7Sespie mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp); 1015df930be7Sderaadt tmp++; 1016df930be7Sderaadt } 1017df930be7Sderaadt } 1018ee3599c7Sespie *dest = '\0'; 1019df930be7Sderaadt } 102087c5c065Sespie 102187c5c065Sespie 102287c5c065Sespie /* 102387c5c065Sespie * handledash: 102487c5c065Sespie * use buffer to copy the src string, expanding character ranges 102587c5c065Sespie * on the way. 102687c5c065Sespie */ 102787c5c065Sespie static const char * 10288e061d4bSespie handledash(char *buffer, char *end, const char *src) 102987c5c065Sespie { 103087c5c065Sespie char *p; 103187c5c065Sespie 103287c5c065Sespie p = buffer; 103387c5c065Sespie while(*src) { 103487c5c065Sespie if (src[1] == '-' && src[2]) { 103587c5c065Sespie unsigned char i; 103687c5c065Sespie for (i = (unsigned char)src[0]; 103787c5c065Sespie i <= (unsigned char)src[2]; i++) { 103887c5c065Sespie *p++ = i; 103987c5c065Sespie if (p == end) { 104087c5c065Sespie *p = '\0'; 104187c5c065Sespie return buffer; 104287c5c065Sespie } 104387c5c065Sespie } 104487c5c065Sespie src += 3; 104587c5c065Sespie } else 104687c5c065Sespie *p++ = *src++; 104787c5c065Sespie if (p == end) 104887c5c065Sespie break; 104987c5c065Sespie } 105087c5c065Sespie *p = '\0'; 105187c5c065Sespie return buffer; 105287c5c065Sespie } 1053