1*8e061d4bSespie /* $OpenBSD: eval.c,v 1.44 2002/04/26 16:15:16 espie Exp $ */ 2aa676ce1Smillert /* $NetBSD: eval.c,v 1.7 1996/11/10 21:21:29 pk Exp $ */ 3df930be7Sderaadt 4df930be7Sderaadt /* 5df930be7Sderaadt * Copyright (c) 1989, 1993 6df930be7Sderaadt * The Regents of the University of California. All rights reserved. 7df930be7Sderaadt * 8df930be7Sderaadt * This code is derived from software contributed to Berkeley by 9df930be7Sderaadt * Ozan Yigit at York University. 10df930be7Sderaadt * 11df930be7Sderaadt * Redistribution and use in source and binary forms, with or without 12df930be7Sderaadt * modification, are permitted provided that the following conditions 13df930be7Sderaadt * are met: 14df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright 15df930be7Sderaadt * notice, this list of conditions and the following disclaimer. 16df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 17df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the 18df930be7Sderaadt * documentation and/or other materials provided with the distribution. 19df930be7Sderaadt * 3. All advertising materials mentioning features or use of this software 20df930be7Sderaadt * must display the following acknowledgement: 21df930be7Sderaadt * This product includes software developed by the University of 22df930be7Sderaadt * California, Berkeley and its contributors. 23df930be7Sderaadt * 4. Neither the name of the University nor the names of its contributors 24df930be7Sderaadt * may be used to endorse or promote products derived from this software 25df930be7Sderaadt * without specific prior written permission. 26df930be7Sderaadt * 27df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37df930be7Sderaadt * SUCH DAMAGE. 38df930be7Sderaadt */ 39df930be7Sderaadt 40df930be7Sderaadt #ifndef lint 41df930be7Sderaadt #if 0 42df930be7Sderaadt static char sccsid[] = "@(#)eval.c 8.2 (Berkeley) 4/27/95"; 43df930be7Sderaadt #else 44*8e061d4bSespie static char rcsid[] = "$OpenBSD: eval.c,v 1.44 2002/04/26 16:15:16 espie Exp $"; 45df930be7Sderaadt #endif 46df930be7Sderaadt #endif /* not lint */ 47df930be7Sderaadt 48df930be7Sderaadt /* 49df930be7Sderaadt * eval.c 50df930be7Sderaadt * Facility: m4 macro processor 51df930be7Sderaadt * by: oz 52df930be7Sderaadt */ 53df930be7Sderaadt 54df930be7Sderaadt #include <sys/types.h> 55df930be7Sderaadt #include <errno.h> 56df930be7Sderaadt #include <unistd.h> 57df930be7Sderaadt #include <stdio.h> 58df930be7Sderaadt #include <stdlib.h> 593f42598dSespie #include <stddef.h> 60df930be7Sderaadt #include <string.h> 61445b77f7Smillert #include <fcntl.h> 6281c2181eSespie #include <err.h> 63df930be7Sderaadt #include "mdef.h" 64df930be7Sderaadt #include "stdd.h" 65df930be7Sderaadt #include "extern.h" 66df930be7Sderaadt #include "pathnames.h" 67df930be7Sderaadt 68f8b42d48Sespie #define BUILTIN_MARKER "__builtin_" 69f8b42d48Sespie 70c72b5b24Smillert static void dodefn(const char *); 71c72b5b24Smillert static void dopushdef(const char *, const char *); 72c72b5b24Smillert static void dodump(const char *[], int); 73c72b5b24Smillert static void dotrace(const char *[], int, int); 74c72b5b24Smillert static void doifelse(const char *[], int); 75c72b5b24Smillert static int doincl(const char *); 76c72b5b24Smillert static int dopaste(const char *); 77c72b5b24Smillert static void gnu_dochq(const char *[], int); 78c72b5b24Smillert static void dochq(const char *[], int); 79c72b5b24Smillert static void gnu_dochc(const char *[], int); 80c72b5b24Smillert static void dochc(const char *[], int); 81c72b5b24Smillert static void dodiv(int); 82c72b5b24Smillert static void doundiv(const char *[], int); 83c72b5b24Smillert static void dosub(const char *[], int); 84c72b5b24Smillert static void map(char *, const char *, const char *, const char *); 85c72b5b24Smillert static const char *handledash(char *, char *, const char *); 86c72b5b24Smillert static void expand_builtin(const char *[], int, int); 87c72b5b24Smillert static void expand_macro(const char *[], int); 88c72b5b24Smillert static void dump_one_def(ndptr); 8908f7f207Sespie 9099f77b33Sespie unsigned long expansion_id; 9108f7f207Sespie 92df930be7Sderaadt /* 9308f7f207Sespie * eval - eval all macros and builtins calls 94054026c0Sespie * argc - number of elements in argv. 95054026c0Sespie * argv - element vector : 96054026c0Sespie * argv[0] = definition of a user 97054026c0Sespie * macro or nil if built-in. 98054026c0Sespie * argv[1] = name of the macro or 99054026c0Sespie * built-in. 100054026c0Sespie * argv[2] = parameters to user-defined 101054026c0Sespie * . macro or built-in. 102054026c0Sespie * . 103054026c0Sespie * 104054026c0Sespie * A call in the form of macro-or-builtin() will result in: 105054026c0Sespie * argv[0] = nullstr 106054026c0Sespie * argv[1] = macro-or-builtin 107054026c0Sespie * argv[2] = nullstr 108054026c0Sespie * 109054026c0Sespie * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin 11008f7f207Sespie */ 11108f7f207Sespie void 112*8e061d4bSespie eval(const char *argv[], int argc, int td) 11308f7f207Sespie { 1144dac505dSespie ssize_t mark = -1; 1154dac505dSespie 11699f77b33Sespie expansion_id++; 11708f7f207Sespie if (td & RECDEF) 11808f7f207Sespie errx(1, "%s at line %lu: expanding recursive definition for %s", 11908f7f207Sespie CURRENT_NAME, CURRENT_LINE, argv[1]); 1204dac505dSespie if (traced_macros && is_traced(argv[1])) 1214dac505dSespie mark = trace(argv, argc, infile+ilevel); 12208f7f207Sespie if (td == MACRTYPE) 12308f7f207Sespie expand_macro(argv, argc); 12408f7f207Sespie else 12508f7f207Sespie expand_builtin(argv, argc, td); 1264dac505dSespie if (mark != -1) 1274dac505dSespie finish_trace(mark); 12808f7f207Sespie } 12908f7f207Sespie 13008f7f207Sespie /* 13108f7f207Sespie * expand_builtin - evaluate built-in macros. 132df930be7Sderaadt */ 133df930be7Sderaadt void 134*8e061d4bSespie expand_builtin(const char *argv[], int argc, int td) 135df930be7Sderaadt { 13653f6f6bfSespie int c, n; 137054026c0Sespie int ac; 138df930be7Sderaadt static int sysval = 0; 139df930be7Sderaadt 140df930be7Sderaadt #ifdef DEBUG 141df930be7Sderaadt printf("argc = %d\n", argc); 142df930be7Sderaadt for (n = 0; n < argc; n++) 143df930be7Sderaadt printf("argv[%d] = %s\n", n, argv[n]); 14428728804Sespie fflush(stdout); 145df930be7Sderaadt #endif 146718b194dSespie 147df930be7Sderaadt /* 148df930be7Sderaadt * if argc == 3 and argv[2] is null, then we 149df930be7Sderaadt * have macro-or-builtin() type call. We adjust 150df930be7Sderaadt * argc to avoid further checking.. 151df930be7Sderaadt */ 152054026c0Sespie ac = argc; 153054026c0Sespie 154df930be7Sderaadt if (argc == 3 && !*(argv[2])) 155df930be7Sderaadt argc--; 156df930be7Sderaadt 157718b194dSespie switch (td & TYPEMASK) { 158df930be7Sderaadt 159df930be7Sderaadt case DEFITYPE: 160df930be7Sderaadt if (argc > 2) 161df930be7Sderaadt dodefine(argv[2], (argc > 3) ? argv[3] : null); 162df930be7Sderaadt break; 163df930be7Sderaadt 164df930be7Sderaadt case PUSDTYPE: 165df930be7Sderaadt if (argc > 2) 166df930be7Sderaadt dopushdef(argv[2], (argc > 3) ? argv[3] : null); 167df930be7Sderaadt break; 168df930be7Sderaadt 169df930be7Sderaadt case DUMPTYPE: 170df930be7Sderaadt dodump(argv, argc); 171df930be7Sderaadt break; 172df930be7Sderaadt 17334970243Sespie case TRACEONTYPE: 17434970243Sespie dotrace(argv, argc, 1); 17534970243Sespie break; 17634970243Sespie 17734970243Sespie case TRACEOFFTYPE: 17834970243Sespie dotrace(argv, argc, 0); 17934970243Sespie break; 18034970243Sespie 181df930be7Sderaadt case EXPRTYPE: 182df930be7Sderaadt /* 183df930be7Sderaadt * doexpr - evaluate arithmetic 184df930be7Sderaadt * expression 185df930be7Sderaadt */ 186df930be7Sderaadt if (argc > 2) 187df930be7Sderaadt pbnum(expr(argv[2])); 188df930be7Sderaadt break; 189df930be7Sderaadt 190df930be7Sderaadt case IFELTYPE: 191df930be7Sderaadt if (argc > 4) 192df930be7Sderaadt doifelse(argv, argc); 193df930be7Sderaadt break; 194df930be7Sderaadt 195df930be7Sderaadt case IFDFTYPE: 196df930be7Sderaadt /* 197df930be7Sderaadt * doifdef - select one of two 198df930be7Sderaadt * alternatives based on the existence of 199df930be7Sderaadt * another definition 200df930be7Sderaadt */ 201df930be7Sderaadt if (argc > 3) { 202df930be7Sderaadt if (lookup(argv[2]) != nil) 203df930be7Sderaadt pbstr(argv[3]); 204df930be7Sderaadt else if (argc > 4) 205df930be7Sderaadt pbstr(argv[4]); 206df930be7Sderaadt } 207df930be7Sderaadt break; 208df930be7Sderaadt 209df930be7Sderaadt case LENGTYPE: 210df930be7Sderaadt /* 211df930be7Sderaadt * dolen - find the length of the 212df930be7Sderaadt * argument 213df930be7Sderaadt */ 214df930be7Sderaadt pbnum((argc > 2) ? strlen(argv[2]) : 0); 215df930be7Sderaadt break; 216df930be7Sderaadt 217df930be7Sderaadt case INCRTYPE: 218df930be7Sderaadt /* 219df930be7Sderaadt * doincr - increment the value of the 220df930be7Sderaadt * argument 221df930be7Sderaadt */ 222df930be7Sderaadt if (argc > 2) 223df930be7Sderaadt pbnum(atoi(argv[2]) + 1); 224df930be7Sderaadt break; 225df930be7Sderaadt 226df930be7Sderaadt case DECRTYPE: 227df930be7Sderaadt /* 228df930be7Sderaadt * dodecr - decrement the value of the 229df930be7Sderaadt * argument 230df930be7Sderaadt */ 231df930be7Sderaadt if (argc > 2) 232df930be7Sderaadt pbnum(atoi(argv[2]) - 1); 233df930be7Sderaadt break; 234df930be7Sderaadt 235df930be7Sderaadt case SYSCTYPE: 236df930be7Sderaadt /* 237df930be7Sderaadt * dosys - execute system command 238df930be7Sderaadt */ 239df930be7Sderaadt if (argc > 2) 240df930be7Sderaadt sysval = system(argv[2]); 241df930be7Sderaadt break; 242df930be7Sderaadt 243df930be7Sderaadt case SYSVTYPE: 244df930be7Sderaadt /* 245df930be7Sderaadt * dosysval - return value of the last 246df930be7Sderaadt * system call. 247df930be7Sderaadt * 248df930be7Sderaadt */ 249df930be7Sderaadt pbnum(sysval); 250df930be7Sderaadt break; 251df930be7Sderaadt 252c91edbbbSespie case ESYSCMDTYPE: 253c91edbbbSespie if (argc > 2) 254c91edbbbSespie doesyscmd(argv[2]); 255c91edbbbSespie break; 256df930be7Sderaadt case INCLTYPE: 257df930be7Sderaadt if (argc > 2) 258df930be7Sderaadt if (!doincl(argv[2])) 2590d3ffe1dSespie err(1, "%s at line %lu: include(%s)", 2600d3ffe1dSespie CURRENT_NAME, CURRENT_LINE, argv[2]); 261df930be7Sderaadt break; 262df930be7Sderaadt 263df930be7Sderaadt case SINCTYPE: 264df930be7Sderaadt if (argc > 2) 265df930be7Sderaadt (void) doincl(argv[2]); 266df930be7Sderaadt break; 267df930be7Sderaadt #ifdef EXTENDED 268df930be7Sderaadt case PASTTYPE: 269df930be7Sderaadt if (argc > 2) 270df930be7Sderaadt if (!dopaste(argv[2])) 2710d3ffe1dSespie err(1, "%s at line %lu: paste(%s)", 2720d3ffe1dSespie CURRENT_NAME, CURRENT_LINE, argv[2]); 273df930be7Sderaadt break; 274df930be7Sderaadt 275df930be7Sderaadt case SPASTYPE: 276df930be7Sderaadt if (argc > 2) 277df930be7Sderaadt (void) dopaste(argv[2]); 278df930be7Sderaadt break; 279df930be7Sderaadt #endif 280df930be7Sderaadt case CHNQTYPE: 281054026c0Sespie if (mimic_gnu) 282054026c0Sespie gnu_dochq(argv, ac); 283054026c0Sespie else 284df930be7Sderaadt dochq(argv, argc); 285df930be7Sderaadt break; 286df930be7Sderaadt 287df930be7Sderaadt case CHNCTYPE: 288054026c0Sespie if (mimic_gnu) 289054026c0Sespie gnu_dochc(argv, ac); 290054026c0Sespie else 291df930be7Sderaadt dochc(argv, argc); 292df930be7Sderaadt break; 293df930be7Sderaadt 294df930be7Sderaadt case SUBSTYPE: 295df930be7Sderaadt /* 296df930be7Sderaadt * dosub - select substring 297df930be7Sderaadt * 298df930be7Sderaadt */ 299df930be7Sderaadt if (argc > 3) 300df930be7Sderaadt dosub(argv, argc); 301df930be7Sderaadt break; 302df930be7Sderaadt 303df930be7Sderaadt case SHIFTYPE: 304df930be7Sderaadt /* 305df930be7Sderaadt * doshift - push back all arguments 306df930be7Sderaadt * except the first one (i.e. skip 307df930be7Sderaadt * argv[2]) 308df930be7Sderaadt */ 309df930be7Sderaadt if (argc > 3) { 310df930be7Sderaadt for (n = argc - 1; n > 3; n--) { 3113a73db8cSderaadt pbstr(rquote); 312df930be7Sderaadt pbstr(argv[n]); 3133a73db8cSderaadt pbstr(lquote); 314aa676ce1Smillert putback(COMMA); 315df930be7Sderaadt } 3163a73db8cSderaadt pbstr(rquote); 317df930be7Sderaadt pbstr(argv[3]); 3183a73db8cSderaadt pbstr(lquote); 319df930be7Sderaadt } 320df930be7Sderaadt break; 321df930be7Sderaadt 322df930be7Sderaadt case DIVRTYPE: 323df930be7Sderaadt if (argc > 2 && (n = atoi(argv[2])) != 0) 324df930be7Sderaadt dodiv(n); 325df930be7Sderaadt else { 326df930be7Sderaadt active = stdout; 327df930be7Sderaadt oindex = 0; 328df930be7Sderaadt } 329df930be7Sderaadt break; 330df930be7Sderaadt 331df930be7Sderaadt case UNDVTYPE: 332df930be7Sderaadt doundiv(argv, argc); 333df930be7Sderaadt break; 334df930be7Sderaadt 335df930be7Sderaadt case DIVNTYPE: 336df930be7Sderaadt /* 337df930be7Sderaadt * dodivnum - return the number of 338df930be7Sderaadt * current output diversion 339df930be7Sderaadt */ 340df930be7Sderaadt pbnum(oindex); 341df930be7Sderaadt break; 342df930be7Sderaadt 343df930be7Sderaadt case UNDFTYPE: 344df930be7Sderaadt /* 345df930be7Sderaadt * doundefine - undefine a previously 346df930be7Sderaadt * defined macro(s) or m4 keyword(s). 347df930be7Sderaadt */ 348df930be7Sderaadt if (argc > 2) 349df930be7Sderaadt for (n = 2; n < argc; n++) 350df930be7Sderaadt remhash(argv[n], ALL); 351df930be7Sderaadt break; 352df930be7Sderaadt 353df930be7Sderaadt case POPDTYPE: 354df930be7Sderaadt /* 355df930be7Sderaadt * dopopdef - remove the topmost 356df930be7Sderaadt * definitions of macro(s) or m4 357df930be7Sderaadt * keyword(s). 358df930be7Sderaadt */ 359df930be7Sderaadt if (argc > 2) 360df930be7Sderaadt for (n = 2; n < argc; n++) 361df930be7Sderaadt remhash(argv[n], TOP); 362df930be7Sderaadt break; 363df930be7Sderaadt 364df930be7Sderaadt case MKTMTYPE: 365df930be7Sderaadt /* 366df930be7Sderaadt * dotemp - create a temporary file 367df930be7Sderaadt */ 36801e71e69Sespie if (argc > 2) { 36901e71e69Sespie int fd; 370bb34cd6cSespie char *temp; 37101e71e69Sespie 372bb34cd6cSespie temp = xstrdup(argv[2]); 373bb34cd6cSespie 374bb34cd6cSespie fd = mkstemp(temp); 37501e71e69Sespie if (fd == -1) 3760d3ffe1dSespie err(1, 3770d3ffe1dSespie "%s at line %lu: couldn't make temp file %s", 3780d3ffe1dSespie CURRENT_NAME, CURRENT_LINE, argv[2]); 37901e71e69Sespie close(fd); 380bb34cd6cSespie pbstr(temp); 381bb34cd6cSespie free(temp); 38201e71e69Sespie } 383df930be7Sderaadt break; 384df930be7Sderaadt 385df930be7Sderaadt case TRNLTYPE: 386df930be7Sderaadt /* 387df930be7Sderaadt * dotranslit - replace all characters in 388df930be7Sderaadt * the source string that appears in the 389df930be7Sderaadt * "from" string with the corresponding 390df930be7Sderaadt * characters in the "to" string. 391df930be7Sderaadt */ 392df930be7Sderaadt if (argc > 3) { 39328728804Sespie char *temp; 39428728804Sespie 39528728804Sespie temp = xalloc(strlen(argv[2])+1); 396df930be7Sderaadt if (argc > 4) 397df930be7Sderaadt map(temp, argv[2], argv[3], argv[4]); 398df930be7Sderaadt else 399df930be7Sderaadt map(temp, argv[2], argv[3], null); 400df930be7Sderaadt pbstr(temp); 40128728804Sespie free(temp); 4027d3e0b6bSderaadt } else if (argc > 2) 403df930be7Sderaadt pbstr(argv[2]); 404df930be7Sderaadt break; 405df930be7Sderaadt 406df930be7Sderaadt case INDXTYPE: 407df930be7Sderaadt /* 408df930be7Sderaadt * doindex - find the index of the second 409df930be7Sderaadt * argument string in the first argument 410df930be7Sderaadt * string. -1 if not present. 411df930be7Sderaadt */ 412df930be7Sderaadt pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1); 413df930be7Sderaadt break; 414df930be7Sderaadt 415df930be7Sderaadt case ERRPTYPE: 416df930be7Sderaadt /* 417df930be7Sderaadt * doerrp - print the arguments to stderr 418df930be7Sderaadt * file 419df930be7Sderaadt */ 420df930be7Sderaadt if (argc > 2) { 421df930be7Sderaadt for (n = 2; n < argc; n++) 422df930be7Sderaadt fprintf(stderr, "%s ", argv[n]); 423df930be7Sderaadt fprintf(stderr, "\n"); 424df930be7Sderaadt } 425df930be7Sderaadt break; 426df930be7Sderaadt 427df930be7Sderaadt case DNLNTYPE: 428df930be7Sderaadt /* 429df930be7Sderaadt * dodnl - eat-up-to and including 430df930be7Sderaadt * newline 431df930be7Sderaadt */ 432df930be7Sderaadt while ((c = gpbc()) != '\n' && c != EOF) 433df930be7Sderaadt ; 434df930be7Sderaadt break; 435df930be7Sderaadt 436df930be7Sderaadt case M4WRTYPE: 437df930be7Sderaadt /* 438df930be7Sderaadt * dom4wrap - set up for 439df930be7Sderaadt * wrap-up/wind-down activity 440df930be7Sderaadt */ 441df930be7Sderaadt m4wraps = (argc > 2) ? xstrdup(argv[2]) : null; 442df930be7Sderaadt break; 443df930be7Sderaadt 444df930be7Sderaadt case EXITTYPE: 445df930be7Sderaadt /* 446df930be7Sderaadt * doexit - immediate exit from m4. 447df930be7Sderaadt */ 448df930be7Sderaadt killdiv(); 449df930be7Sderaadt exit((argc > 2) ? atoi(argv[2]) : 0); 450df930be7Sderaadt break; 451df930be7Sderaadt 452df930be7Sderaadt case DEFNTYPE: 453df930be7Sderaadt if (argc > 2) 454df930be7Sderaadt for (n = 2; n < argc; n++) 455df930be7Sderaadt dodefn(argv[n]); 456df930be7Sderaadt break; 457df930be7Sderaadt 458b8161682Sespie case INDIRTYPE: /* Indirect call */ 459b8161682Sespie if (argc > 2) 460b8161682Sespie doindir(argv, argc); 461b8161682Sespie break; 462b8161682Sespie 463b8161682Sespie case BUILTINTYPE: /* Builtins only */ 464b8161682Sespie if (argc > 2) 465b8161682Sespie dobuiltin(argv, argc); 466b8161682Sespie break; 467b8161682Sespie 468b8161682Sespie case PATSTYPE: 469b8161682Sespie if (argc > 2) 470b8161682Sespie dopatsubst(argv, argc); 471b8161682Sespie break; 472b8161682Sespie case REGEXPTYPE: 473b8161682Sespie if (argc > 2) 474b8161682Sespie doregexp(argv, argc); 475b8161682Sespie break; 476b8161682Sespie case LINETYPE: 477b8161682Sespie doprintlineno(infile+ilevel); 478b8161682Sespie break; 479b8161682Sespie case FILENAMETYPE: 480b8161682Sespie doprintfilename(infile+ilevel); 481b8161682Sespie break; 482423624b7Sespie case SELFTYPE: 483423624b7Sespie pbstr(rquote); 484423624b7Sespie pbstr(argv[1]); 485423624b7Sespie pbstr(lquote); 486423624b7Sespie break; 487df930be7Sderaadt default: 4880d3ffe1dSespie errx(1, "%s at line %lu: eval: major botch.", 4890d3ffe1dSespie CURRENT_NAME, CURRENT_LINE); 490df930be7Sderaadt break; 491df930be7Sderaadt } 492df930be7Sderaadt } 493df930be7Sderaadt 494df930be7Sderaadt /* 49508f7f207Sespie * expand_macro - user-defined macro expansion 496df930be7Sderaadt */ 497df930be7Sderaadt void 498*8e061d4bSespie expand_macro(const char *argv[], int argc) 499df930be7Sderaadt { 500bb34cd6cSespie const char *t; 501bb34cd6cSespie const char *p; 50253f6f6bfSespie int n; 50353f6f6bfSespie int argno; 504df930be7Sderaadt 505df930be7Sderaadt t = argv[0]; /* defn string as a whole */ 506df930be7Sderaadt p = t; 507df930be7Sderaadt while (*p) 508df930be7Sderaadt p++; 509df930be7Sderaadt p--; /* last character of defn */ 510df930be7Sderaadt while (p > t) { 511df930be7Sderaadt if (*(p - 1) != ARGFLAG) 512dd84b4a6Sespie PUTBACK(*p); 513df930be7Sderaadt else { 514df930be7Sderaadt switch (*p) { 515df930be7Sderaadt 516df930be7Sderaadt case '#': 517df930be7Sderaadt pbnum(argc - 2); 518df930be7Sderaadt break; 519df930be7Sderaadt case '0': 520df930be7Sderaadt case '1': 521df930be7Sderaadt case '2': 522df930be7Sderaadt case '3': 523df930be7Sderaadt case '4': 524df930be7Sderaadt case '5': 525df930be7Sderaadt case '6': 526df930be7Sderaadt case '7': 527df930be7Sderaadt case '8': 528df930be7Sderaadt case '9': 529df930be7Sderaadt if ((argno = *p - '0') < argc - 1) 530df930be7Sderaadt pbstr(argv[argno + 1]); 531df930be7Sderaadt break; 532df930be7Sderaadt case '*': 533faa30e49Sespie if (argc > 2) { 534df930be7Sderaadt for (n = argc - 1; n > 2; n--) { 535df930be7Sderaadt pbstr(argv[n]); 536aa676ce1Smillert putback(COMMA); 537df930be7Sderaadt } 538df930be7Sderaadt pbstr(argv[2]); 539faa30e49Sespie } 540df930be7Sderaadt break; 541aa676ce1Smillert case '@': 542faa30e49Sespie if (argc > 2) { 543aa676ce1Smillert for (n = argc - 1; n > 2; n--) { 544aa676ce1Smillert pbstr(rquote); 545aa676ce1Smillert pbstr(argv[n]); 546aa676ce1Smillert pbstr(lquote); 547aa676ce1Smillert putback(COMMA); 548aa676ce1Smillert } 549aa676ce1Smillert pbstr(rquote); 550aa676ce1Smillert pbstr(argv[2]); 551aa676ce1Smillert pbstr(lquote); 552faa30e49Sespie } 553aa676ce1Smillert break; 554df930be7Sderaadt default: 555dd84b4a6Sespie PUTBACK(*p); 556dd84b4a6Sespie PUTBACK('$'); 557df930be7Sderaadt break; 558df930be7Sderaadt } 559df930be7Sderaadt p--; 560df930be7Sderaadt } 561df930be7Sderaadt p--; 562df930be7Sderaadt } 563df930be7Sderaadt if (p == t) /* do last character */ 564dd84b4a6Sespie PUTBACK(*p); 565df930be7Sderaadt } 566df930be7Sderaadt 567df930be7Sderaadt /* 568df930be7Sderaadt * dodefine - install definition in the table 569df930be7Sderaadt */ 570df930be7Sderaadt void 571*8e061d4bSespie dodefine(const char *name, const char *defn) 572df930be7Sderaadt { 57353f6f6bfSespie ndptr p; 574f8b42d48Sespie int n; 575df930be7Sderaadt 576df930be7Sderaadt if (!*name) 5770d3ffe1dSespie errx(1, "%s at line %lu: null definition.", CURRENT_NAME, 5780d3ffe1dSespie CURRENT_LINE); 579df930be7Sderaadt if ((p = lookup(name)) == nil) 580df930be7Sderaadt p = addent(name); 581df930be7Sderaadt else if (p->defn != null) 582df930be7Sderaadt free((char *) p->defn); 583f8b42d48Sespie if (strncmp(defn, BUILTIN_MARKER, sizeof(BUILTIN_MARKER)-1) == 0) { 584f8b42d48Sespie n = builtin_type(defn+sizeof(BUILTIN_MARKER)-1); 585f8b42d48Sespie if (n != -1) { 58655d92b07Sespie p->type = n & TYPEMASK; 58755d92b07Sespie if ((n & NOARGS) == 0) 58855d92b07Sespie p->type |= NEEDARGS; 589f8b42d48Sespie p->defn = null; 590f8b42d48Sespie return; 591f8b42d48Sespie } 592f8b42d48Sespie } 593df930be7Sderaadt if (!*defn) 594df930be7Sderaadt p->defn = null; 595df930be7Sderaadt else 596df930be7Sderaadt p->defn = xstrdup(defn); 597df930be7Sderaadt p->type = MACRTYPE; 598718b194dSespie if (STREQ(name, defn)) 599718b194dSespie p->type |= RECDEF; 600df930be7Sderaadt } 601df930be7Sderaadt 602df930be7Sderaadt /* 603df930be7Sderaadt * dodefn - push back a quoted definition of 604df930be7Sderaadt * the given name. 605df930be7Sderaadt */ 606bb34cd6cSespie static void 607*8e061d4bSespie dodefn(const char *name) 608df930be7Sderaadt { 60953f6f6bfSespie ndptr p; 610f8b42d48Sespie char *real; 611df930be7Sderaadt 612f8b42d48Sespie if ((p = lookup(name)) != nil) { 613f8b42d48Sespie if (p->defn != null) { 6143a73db8cSderaadt pbstr(rquote); 615df930be7Sderaadt pbstr(p->defn); 6163a73db8cSderaadt pbstr(lquote); 617f8b42d48Sespie } else if ((real = builtin_realname(p->type)) != NULL) { 618f8b42d48Sespie pbstr(real); 619f8b42d48Sespie pbstr(BUILTIN_MARKER); 620f8b42d48Sespie } 621df930be7Sderaadt } 622df930be7Sderaadt } 623df930be7Sderaadt 624df930be7Sderaadt /* 625df930be7Sderaadt * dopushdef - install a definition in the hash table 626df930be7Sderaadt * without removing a previous definition. Since 627df930be7Sderaadt * each new entry is entered in *front* of the 628df930be7Sderaadt * hash bucket, it hides a previous definition from 629df930be7Sderaadt * lookup. 630df930be7Sderaadt */ 631bb34cd6cSespie static void 632*8e061d4bSespie dopushdef(const char *name, const char *defn) 633df930be7Sderaadt { 63453f6f6bfSespie ndptr p; 635df930be7Sderaadt 636df930be7Sderaadt if (!*name) 6370d3ffe1dSespie errx(1, "%s at line %lu: null definition", CURRENT_NAME, 6380d3ffe1dSespie CURRENT_LINE); 639df930be7Sderaadt p = addent(name); 640df930be7Sderaadt if (!*defn) 641df930be7Sderaadt p->defn = null; 642df930be7Sderaadt else 643df930be7Sderaadt p->defn = xstrdup(defn); 644df930be7Sderaadt p->type = MACRTYPE; 645718b194dSespie if (STREQ(name, defn)) 646718b194dSespie p->type |= RECDEF; 647df930be7Sderaadt } 648df930be7Sderaadt 649df930be7Sderaadt /* 650dd0682a2Sespie * dump_one_def - dump the specified definition. 651dd0682a2Sespie */ 652dd0682a2Sespie static void 653*8e061d4bSespie dump_one_def(ndptr p) 654dd0682a2Sespie { 6555191fa0aSespie char *real; 6565191fa0aSespie 6575191fa0aSespie if (mimic_gnu) { 6585191fa0aSespie if ((p->type & TYPEMASK) == MACRTYPE) 6594dac505dSespie fprintf(traceout, "%s:\t%s\n", p->name, p->defn); 6605191fa0aSespie else { 6615191fa0aSespie real = builtin_realname(p->type); 6625191fa0aSespie if (real == NULL) 6635191fa0aSespie real = null; 6644dac505dSespie fprintf(traceout, "%s:\t<%s>\n", p->name, real); 6655191fa0aSespie } 6665191fa0aSespie } else 6674dac505dSespie fprintf(traceout, "`%s'\t`%s'\n", p->name, p->defn); 668dd0682a2Sespie } 669dd0682a2Sespie 670dd0682a2Sespie /* 671df930be7Sderaadt * dodumpdef - dump the specified definitions in the hash 672df930be7Sderaadt * table to stderr. If nothing is specified, the entire 673df930be7Sderaadt * hash table is dumped. 674df930be7Sderaadt */ 675bb34cd6cSespie static void 676*8e061d4bSespie dodump(const char *argv[], int argc) 677df930be7Sderaadt { 67853f6f6bfSespie int n; 679df930be7Sderaadt ndptr p; 680df930be7Sderaadt 681df930be7Sderaadt if (argc > 2) { 682df930be7Sderaadt for (n = 2; n < argc; n++) 683df930be7Sderaadt if ((p = lookup(argv[n])) != nil) 684dd0682a2Sespie dump_one_def(p); 6857d3e0b6bSderaadt } else { 686df930be7Sderaadt for (n = 0; n < HASHSIZE; n++) 687df930be7Sderaadt for (p = hashtab[n]; p != nil; p = p->nxtptr) 688dd0682a2Sespie dump_one_def(p); 689df930be7Sderaadt } 690df930be7Sderaadt } 691df930be7Sderaadt 692df930be7Sderaadt /* 69334970243Sespie * dotrace - mark some macros as traced/untraced depending upon on. 69434970243Sespie */ 69534970243Sespie static void 696*8e061d4bSespie dotrace(const char *argv[], int argc, int on) 69734970243Sespie { 69834970243Sespie int n; 69934970243Sespie 70034970243Sespie if (argc > 2) { 70134970243Sespie for (n = 2; n < argc; n++) 70234970243Sespie mark_traced(argv[n], on); 70334970243Sespie } else 70434970243Sespie mark_traced(NULL, on); 70534970243Sespie } 70634970243Sespie 70734970243Sespie /* 708df930be7Sderaadt * doifelse - select one of two alternatives - loop. 709df930be7Sderaadt */ 710bb34cd6cSespie static void 711*8e061d4bSespie doifelse(const char *argv[], int argc) 712df930be7Sderaadt { 713df930be7Sderaadt cycle { 714df930be7Sderaadt if (STREQ(argv[2], argv[3])) 715df930be7Sderaadt pbstr(argv[4]); 716df930be7Sderaadt else if (argc == 6) 717df930be7Sderaadt pbstr(argv[5]); 718df930be7Sderaadt else if (argc > 6) { 719df930be7Sderaadt argv += 3; 720df930be7Sderaadt argc -= 3; 721df930be7Sderaadt continue; 722df930be7Sderaadt } 723df930be7Sderaadt break; 724df930be7Sderaadt } 725df930be7Sderaadt } 726df930be7Sderaadt 727df930be7Sderaadt /* 728df930be7Sderaadt * doinclude - include a given file. 729df930be7Sderaadt */ 730bb34cd6cSespie static int 731*8e061d4bSespie doincl(const char *ifile) 732df930be7Sderaadt { 733df930be7Sderaadt if (ilevel + 1 == MAXINP) 7340d3ffe1dSespie errx(1, "%s at line %lu: too many include files.", 7350d3ffe1dSespie CURRENT_NAME, CURRENT_LINE); 7360d3ffe1dSespie if (fopen_trypath(infile+ilevel+1, ifile) != NULL) { 737df930be7Sderaadt ilevel++; 738df930be7Sderaadt bbase[ilevel] = bufbase = bp; 739df930be7Sderaadt return (1); 7407d3e0b6bSderaadt } else 741df930be7Sderaadt return (0); 742df930be7Sderaadt } 743df930be7Sderaadt 744df930be7Sderaadt #ifdef EXTENDED 745df930be7Sderaadt /* 746df930be7Sderaadt * dopaste - include a given file without any 747df930be7Sderaadt * macro processing. 748df930be7Sderaadt */ 749bb34cd6cSespie static int 750*8e061d4bSespie dopaste(const char *pfile) 751df930be7Sderaadt { 752df930be7Sderaadt FILE *pf; 75353f6f6bfSespie int c; 754df930be7Sderaadt 755df930be7Sderaadt if ((pf = fopen(pfile, "r")) != NULL) { 756df930be7Sderaadt while ((c = getc(pf)) != EOF) 757df930be7Sderaadt putc(c, active); 758df930be7Sderaadt (void) fclose(pf); 759df930be7Sderaadt return (1); 7607d3e0b6bSderaadt } else 761df930be7Sderaadt return (0); 762df930be7Sderaadt } 763df930be7Sderaadt #endif 764df930be7Sderaadt 765054026c0Sespie static void 766*8e061d4bSespie gnu_dochq(const char *argv[], int ac) 767054026c0Sespie { 768054026c0Sespie /* In gnu-m4 mode, the only way to restore quotes is to have no 769054026c0Sespie * arguments at all. */ 770054026c0Sespie if (ac == 2) { 771054026c0Sespie lquote[0] = LQUOTE, lquote[1] = EOS; 772054026c0Sespie rquote[0] = RQUOTE, rquote[1] = EOS; 773054026c0Sespie } else { 774054026c0Sespie strlcpy(lquote, argv[2], sizeof(lquote)); 775054026c0Sespie if(ac > 3) 776054026c0Sespie strlcpy(rquote, argv[3], sizeof(rquote)); 777054026c0Sespie else 778054026c0Sespie rquote[0] = EOS; 779054026c0Sespie } 780054026c0Sespie } 781054026c0Sespie 782df930be7Sderaadt /* 783df930be7Sderaadt * dochq - change quote characters 784df930be7Sderaadt */ 785bb34cd6cSespie static void 786*8e061d4bSespie dochq(const char *argv[], int argc) 787df930be7Sderaadt { 788df930be7Sderaadt if (argc > 2) { 78918a1973bSderaadt if (*argv[2]) 790b81b15b2Sespie strlcpy(lquote, argv[2], sizeof(lquote)); 79118a1973bSderaadt else { 79218a1973bSderaadt lquote[0] = LQUOTE; 793f0484631Sespie lquote[1] = EOS; 79418a1973bSderaadt } 795df930be7Sderaadt if (argc > 3) { 796df930be7Sderaadt if (*argv[3]) 797b81b15b2Sespie strlcpy(rquote, argv[3], sizeof(rquote)); 7987d3e0b6bSderaadt } else 79929a0bfdcSderaadt strcpy(rquote, lquote); 8007d3e0b6bSderaadt } else { 801f0484631Sespie lquote[0] = LQUOTE, lquote[1] = EOS; 802f0484631Sespie rquote[0] = RQUOTE, rquote[1] = EOS; 803df930be7Sderaadt } 804df930be7Sderaadt } 805df930be7Sderaadt 806054026c0Sespie static void 807*8e061d4bSespie gnu_dochc(const char *argv[], int ac) 808054026c0Sespie { 809054026c0Sespie /* In gnu-m4 mode, no arguments mean no comment 810054026c0Sespie * arguments at all. */ 811054026c0Sespie if (ac == 2) { 812054026c0Sespie scommt[0] = EOS; 813054026c0Sespie ecommt[0] = EOS; 814054026c0Sespie } else { 815054026c0Sespie if (*argv[2]) 816054026c0Sespie strlcpy(scommt, argv[2], sizeof(scommt)); 817054026c0Sespie else 818054026c0Sespie scommt[0] = SCOMMT, scommt[1] = EOS; 819054026c0Sespie if(ac > 3 && *argv[3]) 820054026c0Sespie strlcpy(ecommt, argv[3], sizeof(ecommt)); 821054026c0Sespie else 822054026c0Sespie ecommt[0] = ECOMMT, ecommt[1] = EOS; 823054026c0Sespie } 824054026c0Sespie } 825df930be7Sderaadt /* 826df930be7Sderaadt * dochc - change comment characters 827df930be7Sderaadt */ 828bb34cd6cSespie static void 829*8e061d4bSespie dochc(const char *argv[], int argc) 830df930be7Sderaadt { 831df930be7Sderaadt if (argc > 2) { 832df930be7Sderaadt if (*argv[2]) 833b81b15b2Sespie strlcpy(scommt, argv[2], sizeof(scommt)); 834df930be7Sderaadt if (argc > 3) { 835df930be7Sderaadt if (*argv[3]) 836b81b15b2Sespie strlcpy(ecommt, argv[3], sizeof(ecommt)); 837df930be7Sderaadt } 838df930be7Sderaadt else 839f0484631Sespie ecommt[0] = ECOMMT, ecommt[1] = EOS; 840df930be7Sderaadt } 841df930be7Sderaadt else { 842f0484631Sespie scommt[0] = SCOMMT, scommt[1] = EOS; 843f0484631Sespie ecommt[0] = ECOMMT, ecommt[1] = EOS; 844df930be7Sderaadt } 845df930be7Sderaadt } 846df930be7Sderaadt 847df930be7Sderaadt /* 848df930be7Sderaadt * dodivert - divert the output to a temporary file 849df930be7Sderaadt */ 850bb34cd6cSespie static void 851*8e061d4bSespie dodiv(int n) 852df930be7Sderaadt { 853445b77f7Smillert int fd; 854445b77f7Smillert 8557d3e0b6bSderaadt oindex = n; 85625afcddbSespie if (n >= maxout) { 85725afcddbSespie if (mimic_gnu) 85825afcddbSespie resizedivs(n + 10); 85925afcddbSespie else 86025afcddbSespie n = 0; /* bitbucket */ 86125afcddbSespie } 86225afcddbSespie 86325afcddbSespie if (n < 0) 864df930be7Sderaadt n = 0; /* bitbucket */ 865df930be7Sderaadt if (outfile[n] == NULL) { 8663f42598dSespie char fname[] = _PATH_DIVNAME; 8673f42598dSespie 8683f42598dSespie if ((fd = mkstemp(fname)) < 0 || 8693f42598dSespie (outfile[n] = fdopen(fd, "w+")) == NULL) 8703f42598dSespie err(1, "%s: cannot divert", fname); 8713f42598dSespie if (unlink(fname) == -1) 8723f42598dSespie err(1, "%s: cannot unlink", fname); 873df930be7Sderaadt } 874df930be7Sderaadt active = outfile[n]; 875df930be7Sderaadt } 876df930be7Sderaadt 877df930be7Sderaadt /* 878df930be7Sderaadt * doundivert - undivert a specified output, or all 879df930be7Sderaadt * other outputs, in numerical order. 880df930be7Sderaadt */ 881bb34cd6cSespie static void 882*8e061d4bSespie doundiv(const char *argv[], int argc) 883df930be7Sderaadt { 88453f6f6bfSespie int ind; 88553f6f6bfSespie int n; 886df930be7Sderaadt 887df930be7Sderaadt if (argc > 2) { 888df930be7Sderaadt for (ind = 2; ind < argc; ind++) { 889df930be7Sderaadt n = atoi(argv[ind]); 89025afcddbSespie if (n > 0 && n < maxout && outfile[n] != NULL) 891df930be7Sderaadt getdiv(n); 892df930be7Sderaadt 893df930be7Sderaadt } 894df930be7Sderaadt } 895df930be7Sderaadt else 89625afcddbSespie for (n = 1; n < maxout; n++) 897df930be7Sderaadt if (outfile[n] != NULL) 898df930be7Sderaadt getdiv(n); 899df930be7Sderaadt } 900df930be7Sderaadt 901df930be7Sderaadt /* 902df930be7Sderaadt * dosub - select substring 903df930be7Sderaadt */ 904bb34cd6cSespie static void 905*8e061d4bSespie dosub(const char *argv[], int argc) 906df930be7Sderaadt { 907bb34cd6cSespie const char *ap, *fc, *k; 90853f6f6bfSespie int nc; 909df930be7Sderaadt 910df930be7Sderaadt ap = argv[2]; /* target string */ 911df930be7Sderaadt #ifdef EXPR 912df930be7Sderaadt fc = ap + expr(argv[3]); /* first char */ 913df930be7Sderaadt #else 914df930be7Sderaadt fc = ap + atoi(argv[3]); /* first char */ 915df930be7Sderaadt #endif 916bee8364eSespie nc = strlen(fc); 917bee8364eSespie if (argc >= 5) 918bee8364eSespie #ifdef EXPR 919bee8364eSespie nc = min(nc, expr(argv[4])); 920bee8364eSespie #else 921bee8364eSespie nc = min(nc, atoi(argv[4])); 922bee8364eSespie #endif 923df930be7Sderaadt if (fc >= ap && fc < ap + strlen(ap)) 924bee8364eSespie for (k = fc + nc - 1; k >= fc; k--) 925df930be7Sderaadt putback(*k); 926df930be7Sderaadt } 927df930be7Sderaadt 928df930be7Sderaadt /* 929df930be7Sderaadt * map: 930df930be7Sderaadt * map every character of s1 that is specified in from 931df930be7Sderaadt * into s3 and replace in s. (source s1 remains untouched) 932df930be7Sderaadt * 933df930be7Sderaadt * This is a standard implementation of map(s,from,to) function of ICON 934df930be7Sderaadt * language. Within mapvec, we replace every character of "from" with 935df930be7Sderaadt * the corresponding character in "to". If "to" is shorter than "from", 936df930be7Sderaadt * than the corresponding entries are null, which means that those 937df930be7Sderaadt * characters dissapear altogether. Furthermore, imagine 938df930be7Sderaadt * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, 939df930be7Sderaadt * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' 940df930be7Sderaadt * ultimately maps to `*'. In order to achieve this effect in an efficient 941df930be7Sderaadt * manner (i.e. without multiple passes over the destination string), we 942df930be7Sderaadt * loop over mapvec, starting with the initial source character. if the 943df930be7Sderaadt * character value (dch) in this location is different than the source 944df930be7Sderaadt * character (sch), sch becomes dch, once again to index into mapvec, until 945df930be7Sderaadt * the character value stabilizes (i.e. sch = dch, in other words 946df930be7Sderaadt * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary 947df930be7Sderaadt * character, it will stabilize, since mapvec[0] == 0 at all times. At the 948df930be7Sderaadt * end, we restore mapvec* back to normal where mapvec[n] == n for 949df930be7Sderaadt * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is 950df930be7Sderaadt * about 5 times faster than any algorithm that makes multiple passes over 951df930be7Sderaadt * destination string. 952df930be7Sderaadt */ 953bb34cd6cSespie static void 954*8e061d4bSespie map(char *dest, const char *src, const char *from, const char *to) 955df930be7Sderaadt { 956bb34cd6cSespie const char *tmp; 957ee3599c7Sespie unsigned char sch, dch; 95887c5c065Sespie static char frombis[257]; 95987c5c065Sespie static char tobis[257]; 960ee3599c7Sespie static unsigned char mapvec[256] = { 961ee3599c7Sespie 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 962ee3599c7Sespie 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 963ee3599c7Sespie 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 964ee3599c7Sespie 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 965ee3599c7Sespie 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 966ee3599c7Sespie 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 967ee3599c7Sespie 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 968ee3599c7Sespie 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 969ee3599c7Sespie 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 970ee3599c7Sespie 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 971ee3599c7Sespie 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 972ee3599c7Sespie 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 973ee3599c7Sespie 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 974ee3599c7Sespie 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 975ee3599c7Sespie 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 976ee3599c7Sespie 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 977ee3599c7Sespie 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 978ee3599c7Sespie 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 979df930be7Sderaadt }; 980df930be7Sderaadt 981df930be7Sderaadt if (*src) { 98287c5c065Sespie if (mimic_gnu) { 98387c5c065Sespie /* 98487c5c065Sespie * expand character ranges on the fly 98587c5c065Sespie */ 98687c5c065Sespie from = handledash(frombis, frombis + 256, from); 98787c5c065Sespie to = handledash(tobis, tobis + 256, to); 98887c5c065Sespie } 989df930be7Sderaadt tmp = from; 990df930be7Sderaadt /* 991df930be7Sderaadt * create a mapping between "from" and 992df930be7Sderaadt * "to" 993df930be7Sderaadt */ 994df930be7Sderaadt while (*from) 995ee3599c7Sespie mapvec[(unsigned char)(*from++)] = (*to) ? 996ee3599c7Sespie (unsigned char)(*to++) : 0; 997df930be7Sderaadt 998df930be7Sderaadt while (*src) { 999ee3599c7Sespie sch = (unsigned char)(*src++); 1000df930be7Sderaadt dch = mapvec[sch]; 1001df930be7Sderaadt while (dch != sch) { 1002df930be7Sderaadt sch = dch; 1003df930be7Sderaadt dch = mapvec[sch]; 1004df930be7Sderaadt } 1005ee3599c7Sespie if ((*dest = (char)dch)) 1006df930be7Sderaadt dest++; 1007df930be7Sderaadt } 1008df930be7Sderaadt /* 1009df930be7Sderaadt * restore all the changed characters 1010df930be7Sderaadt */ 1011df930be7Sderaadt while (*tmp) { 1012ee3599c7Sespie mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp); 1013df930be7Sderaadt tmp++; 1014df930be7Sderaadt } 1015df930be7Sderaadt } 1016ee3599c7Sespie *dest = '\0'; 1017df930be7Sderaadt } 101887c5c065Sespie 101987c5c065Sespie 102087c5c065Sespie /* 102187c5c065Sespie * handledash: 102287c5c065Sespie * use buffer to copy the src string, expanding character ranges 102387c5c065Sespie * on the way. 102487c5c065Sespie */ 102587c5c065Sespie static const char * 1026*8e061d4bSespie handledash(char *buffer, char *end, const char *src) 102787c5c065Sespie { 102887c5c065Sespie char *p; 102987c5c065Sespie 103087c5c065Sespie p = buffer; 103187c5c065Sespie while(*src) { 103287c5c065Sespie if (src[1] == '-' && src[2]) { 103387c5c065Sespie unsigned char i; 103487c5c065Sespie for (i = (unsigned char)src[0]; 103587c5c065Sespie i <= (unsigned char)src[2]; i++) { 103687c5c065Sespie *p++ = i; 103787c5c065Sespie if (p == end) { 103887c5c065Sespie *p = '\0'; 103987c5c065Sespie return buffer; 104087c5c065Sespie } 104187c5c065Sespie } 104287c5c065Sespie src += 3; 104387c5c065Sespie } else 104487c5c065Sespie *p++ = *src++; 104587c5c065Sespie if (p == end) 104687c5c065Sespie break; 104787c5c065Sespie } 104887c5c065Sespie *p = '\0'; 104987c5c065Sespie return buffer; 105087c5c065Sespie } 1051