1*d2d86e25Sbcallah /* $OpenBSD: eval.c,v 1.75 2017/06/15 13:48:42 bcallah 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 /* 37df930be7Sderaadt * eval.c 38df930be7Sderaadt * Facility: m4 macro processor 39df930be7Sderaadt * by: oz 40df930be7Sderaadt */ 41df930be7Sderaadt 42df930be7Sderaadt #include <sys/types.h> 43df44a85aSespie #include <err.h> 44df930be7Sderaadt #include <errno.h> 45e79fa687Sespie #include <limits.h> 46df930be7Sderaadt #include <unistd.h> 47df930be7Sderaadt #include <stdio.h> 481357284aSmillert #include <stdint.h> 49df930be7Sderaadt #include <stdlib.h> 503f42598dSespie #include <stddef.h> 51df930be7Sderaadt #include <string.h> 52445b77f7Smillert #include <fcntl.h> 53df930be7Sderaadt #include "mdef.h" 54df930be7Sderaadt #include "stdd.h" 55df930be7Sderaadt #include "extern.h" 56df930be7Sderaadt #include "pathnames.h" 57df930be7Sderaadt 58c72b5b24Smillert static void dodefn(const char *); 59c72b5b24Smillert static void dopushdef(const char *, const char *); 60c72b5b24Smillert static void dodump(const char *[], int); 61c72b5b24Smillert static void dotrace(const char *[], int, int); 62c72b5b24Smillert static void doifelse(const char *[], int); 63c72b5b24Smillert static int doincl(const char *); 64c72b5b24Smillert static int dopaste(const char *); 65c72b5b24Smillert static void dochq(const char *[], int); 66c72b5b24Smillert static void dochc(const char *[], int); 67ad459a23Sespie static void dom4wrap(const char *); 68c72b5b24Smillert static void dodiv(int); 69c72b5b24Smillert static void doundiv(const char *[], int); 70c72b5b24Smillert static void dosub(const char *[], int); 71c72b5b24Smillert static void map(char *, const char *, const char *, const char *); 72c72b5b24Smillert static const char *handledash(char *, char *, const char *); 73c72b5b24Smillert static void expand_builtin(const char *[], int, int); 74c72b5b24Smillert static void expand_macro(const char *[], int); 753509e8ffSespie static void dump_one_def(const char *, struct macro_definition *); 7608f7f207Sespie 7799f77b33Sespie unsigned long expansion_id; 7808f7f207Sespie 79df930be7Sderaadt /* 8008f7f207Sespie * eval - eval all macros and builtins calls 81054026c0Sespie * argc - number of elements in argv. 82054026c0Sespie * argv - element vector : 83054026c0Sespie * argv[0] = definition of a user 843509e8ffSespie * macro or NULL if built-in. 85054026c0Sespie * argv[1] = name of the macro or 86054026c0Sespie * built-in. 87054026c0Sespie * argv[2] = parameters to user-defined 88054026c0Sespie * . macro or built-in. 89054026c0Sespie * . 90054026c0Sespie * 91054026c0Sespie * A call in the form of macro-or-builtin() will result in: 92054026c0Sespie * argv[0] = nullstr 93054026c0Sespie * argv[1] = macro-or-builtin 94054026c0Sespie * argv[2] = nullstr 95054026c0Sespie * 96054026c0Sespie * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin 9708f7f207Sespie */ 9808f7f207Sespie void 99dde05c5fSespie eval(const char *argv[], int argc, int td, int is_traced) 10008f7f207Sespie { 1010b7a013eSespie size_t mark = SIZE_MAX; 1024dac505dSespie 10399f77b33Sespie expansion_id++; 10408f7f207Sespie if (td & RECDEF) 10575ebbed7Sespie m4errx(1, "expanding recursive definition for %s.", argv[1]); 106dde05c5fSespie if (is_traced) 1074dac505dSespie mark = trace(argv, argc, infile+ilevel); 10808f7f207Sespie if (td == MACRTYPE) 10908f7f207Sespie expand_macro(argv, argc); 11008f7f207Sespie else 11108f7f207Sespie expand_builtin(argv, argc, td); 1120b7a013eSespie if (mark != SIZE_MAX) 1134dac505dSespie finish_trace(mark); 11408f7f207Sespie } 11508f7f207Sespie 11608f7f207Sespie /* 11708f7f207Sespie * expand_builtin - evaluate built-in macros. 118df930be7Sderaadt */ 119df930be7Sderaadt void 1208e061d4bSespie expand_builtin(const char *argv[], int argc, int td) 121df930be7Sderaadt { 12253f6f6bfSespie int c, n; 123054026c0Sespie int ac; 124df930be7Sderaadt static int sysval = 0; 125df930be7Sderaadt 126df930be7Sderaadt #ifdef DEBUG 127df930be7Sderaadt printf("argc = %d\n", argc); 128df930be7Sderaadt for (n = 0; n < argc; n++) 129df930be7Sderaadt printf("argv[%d] = %s\n", n, argv[n]); 13028728804Sespie fflush(stdout); 131df930be7Sderaadt #endif 132718b194dSespie 133df930be7Sderaadt /* 134df930be7Sderaadt * if argc == 3 and argv[2] is null, then we 135df930be7Sderaadt * have macro-or-builtin() type call. We adjust 136df930be7Sderaadt * argc to avoid further checking.. 137df930be7Sderaadt */ 138739ce124Sespie /* we keep the initial value for those built-ins that differentiate 139739ce124Sespie * between builtin() and builtin. 140739ce124Sespie */ 141054026c0Sespie ac = argc; 142054026c0Sespie 14387a9001aSespie if (argc == 3 && !*(argv[2]) && !mimic_gnu) 144df930be7Sderaadt argc--; 145df930be7Sderaadt 146718b194dSespie switch (td & TYPEMASK) { 147df930be7Sderaadt 148df930be7Sderaadt case DEFITYPE: 149df930be7Sderaadt if (argc > 2) 150df930be7Sderaadt dodefine(argv[2], (argc > 3) ? argv[3] : null); 151df930be7Sderaadt break; 152df930be7Sderaadt 153df930be7Sderaadt case PUSDTYPE: 154df930be7Sderaadt if (argc > 2) 155df930be7Sderaadt dopushdef(argv[2], (argc > 3) ? argv[3] : null); 156df930be7Sderaadt break; 157df930be7Sderaadt 158df930be7Sderaadt case DUMPTYPE: 159df930be7Sderaadt dodump(argv, argc); 160df930be7Sderaadt break; 161df930be7Sderaadt 16234970243Sespie case TRACEONTYPE: 16334970243Sespie dotrace(argv, argc, 1); 16434970243Sespie break; 16534970243Sespie 16634970243Sespie case TRACEOFFTYPE: 16734970243Sespie dotrace(argv, argc, 0); 16834970243Sespie break; 16934970243Sespie 170df930be7Sderaadt case EXPRTYPE: 171df930be7Sderaadt /* 172df930be7Sderaadt * doexpr - evaluate arithmetic 173df930be7Sderaadt * expression 174df930be7Sderaadt */ 175e79fa687Sespie { 176e79fa687Sespie int base = 10; 177e79fa687Sespie int maxdigits = 0; 178e79fa687Sespie const char *errstr; 179e79fa687Sespie 180e79fa687Sespie if (argc > 3) { 181e79fa687Sespie base = strtonum(argv[3], 2, 36, &errstr); 182e79fa687Sespie if (errstr) { 18375ebbed7Sespie m4errx(1, "expr: base %s invalid.", argv[3]); 184e79fa687Sespie } 185e79fa687Sespie } 186e79fa687Sespie if (argc > 4) { 187e79fa687Sespie maxdigits = strtonum(argv[4], 0, INT_MAX, &errstr); 188e79fa687Sespie if (errstr) { 18975ebbed7Sespie m4errx(1, "expr: maxdigits %s invalid.", argv[4]); 190e79fa687Sespie } 191e79fa687Sespie } 192df930be7Sderaadt if (argc > 2) 193e79fa687Sespie pbnumbase(expr(argv[2]), base, maxdigits); 194df930be7Sderaadt break; 195e79fa687Sespie } 196df930be7Sderaadt 197df930be7Sderaadt case IFELTYPE: 198df930be7Sderaadt if (argc > 4) 199df930be7Sderaadt doifelse(argv, argc); 200df930be7Sderaadt break; 201df930be7Sderaadt 202df930be7Sderaadt case IFDFTYPE: 203df930be7Sderaadt /* 204df930be7Sderaadt * doifdef - select one of two 205df930be7Sderaadt * alternatives based on the existence of 206df930be7Sderaadt * another definition 207df930be7Sderaadt */ 208df930be7Sderaadt if (argc > 3) { 2093509e8ffSespie if (lookup_macro_definition(argv[2]) != NULL) 210df930be7Sderaadt pbstr(argv[3]); 211df930be7Sderaadt else if (argc > 4) 212df930be7Sderaadt pbstr(argv[4]); 213df930be7Sderaadt } 214df930be7Sderaadt break; 215df930be7Sderaadt 216df930be7Sderaadt case LENGTYPE: 217df930be7Sderaadt /* 218df930be7Sderaadt * dolen - find the length of the 219df930be7Sderaadt * argument 220df930be7Sderaadt */ 221df930be7Sderaadt pbnum((argc > 2) ? strlen(argv[2]) : 0); 222df930be7Sderaadt break; 223df930be7Sderaadt 224df930be7Sderaadt case INCRTYPE: 225df930be7Sderaadt /* 226df930be7Sderaadt * doincr - increment the value of the 227df930be7Sderaadt * argument 228df930be7Sderaadt */ 229df930be7Sderaadt if (argc > 2) 230df930be7Sderaadt pbnum(atoi(argv[2]) + 1); 231df930be7Sderaadt break; 232df930be7Sderaadt 233df930be7Sderaadt case DECRTYPE: 234df930be7Sderaadt /* 235df930be7Sderaadt * dodecr - decrement the value of the 236df930be7Sderaadt * argument 237df930be7Sderaadt */ 238df930be7Sderaadt if (argc > 2) 239df930be7Sderaadt pbnum(atoi(argv[2]) - 1); 240df930be7Sderaadt break; 241df930be7Sderaadt 242df930be7Sderaadt case SYSCTYPE: 243df930be7Sderaadt /* 244df930be7Sderaadt * dosys - execute system command 245df930be7Sderaadt */ 246b3d09a36Srobert if (argc > 2) { 247b3d09a36Srobert fflush(stdout); 248df930be7Sderaadt sysval = system(argv[2]); 249b3d09a36Srobert } 250df930be7Sderaadt break; 251df930be7Sderaadt 252df930be7Sderaadt case SYSVTYPE: 253df930be7Sderaadt /* 254df930be7Sderaadt * dosysval - return value of the last 255df930be7Sderaadt * system call. 256df930be7Sderaadt * 257df930be7Sderaadt */ 258df930be7Sderaadt pbnum(sysval); 259df930be7Sderaadt break; 260df930be7Sderaadt 261c91edbbbSespie case ESYSCMDTYPE: 262c91edbbbSespie if (argc > 2) 263c91edbbbSespie doesyscmd(argv[2]); 264c91edbbbSespie break; 265df930be7Sderaadt case INCLTYPE: 2662aa31d4aSderaadt if (argc > 2) { 2672aa31d4aSderaadt if (!doincl(argv[2])) { 268a45fdd0cSespie if (mimic_gnu) { 269a45fdd0cSespie warn("%s at line %lu: include(%s)", 270a45fdd0cSespie CURRENT_NAME, CURRENT_LINE, argv[2]); 271a45fdd0cSespie exit_code = 1; 272*d2d86e25Sbcallah if (fatal_warns) { 273*d2d86e25Sbcallah killdiv(); 274*d2d86e25Sbcallah exit(exit_code); 275*d2d86e25Sbcallah } 276a45fdd0cSespie } else 2770d3ffe1dSespie err(1, "%s at line %lu: include(%s)", 2780d3ffe1dSespie CURRENT_NAME, CURRENT_LINE, argv[2]); 2792aa31d4aSderaadt } 2802aa31d4aSderaadt } 281df930be7Sderaadt break; 282df930be7Sderaadt 283df930be7Sderaadt case SINCTYPE: 284df930be7Sderaadt if (argc > 2) 285df930be7Sderaadt (void) doincl(argv[2]); 286df930be7Sderaadt break; 287df930be7Sderaadt #ifdef EXTENDED 288df930be7Sderaadt case PASTTYPE: 289df930be7Sderaadt if (argc > 2) 290df930be7Sderaadt if (!dopaste(argv[2])) 2910d3ffe1dSespie err(1, "%s at line %lu: paste(%s)", 2920d3ffe1dSespie CURRENT_NAME, CURRENT_LINE, argv[2]); 293df930be7Sderaadt break; 294df930be7Sderaadt 295df930be7Sderaadt case SPASTYPE: 296df930be7Sderaadt if (argc > 2) 297df930be7Sderaadt (void) dopaste(argv[2]); 298df930be7Sderaadt break; 29909d1584fSespie case FORMATTYPE: 30009d1584fSespie doformat(argv, argc); 30109d1584fSespie break; 302df930be7Sderaadt #endif 303df930be7Sderaadt case CHNQTYPE: 304739ce124Sespie dochq(argv, ac); 305df930be7Sderaadt break; 306df930be7Sderaadt 307df930be7Sderaadt case CHNCTYPE: 308df930be7Sderaadt dochc(argv, argc); 309df930be7Sderaadt break; 310df930be7Sderaadt 311df930be7Sderaadt case SUBSTYPE: 312df930be7Sderaadt /* 313df930be7Sderaadt * dosub - select substring 314df930be7Sderaadt * 315df930be7Sderaadt */ 316df930be7Sderaadt if (argc > 3) 317df930be7Sderaadt dosub(argv, argc); 318df930be7Sderaadt break; 319df930be7Sderaadt 320df930be7Sderaadt case SHIFTYPE: 321df930be7Sderaadt /* 322df930be7Sderaadt * doshift - push back all arguments 323df930be7Sderaadt * except the first one (i.e. skip 324df930be7Sderaadt * argv[2]) 325df930be7Sderaadt */ 326df930be7Sderaadt if (argc > 3) { 327df930be7Sderaadt for (n = argc - 1; n > 3; n--) { 3283a73db8cSderaadt pbstr(rquote); 329df930be7Sderaadt pbstr(argv[n]); 3303a73db8cSderaadt pbstr(lquote); 331739ce124Sespie pushback(COMMA); 332df930be7Sderaadt } 3333a73db8cSderaadt pbstr(rquote); 334df930be7Sderaadt pbstr(argv[3]); 3353a73db8cSderaadt pbstr(lquote); 336df930be7Sderaadt } 337df930be7Sderaadt break; 338df930be7Sderaadt 339df930be7Sderaadt case DIVRTYPE: 340df930be7Sderaadt if (argc > 2 && (n = atoi(argv[2])) != 0) 341df930be7Sderaadt dodiv(n); 342df930be7Sderaadt else { 343df930be7Sderaadt active = stdout; 344df930be7Sderaadt oindex = 0; 345df930be7Sderaadt } 346df930be7Sderaadt break; 347df930be7Sderaadt 348df930be7Sderaadt case UNDVTYPE: 349df930be7Sderaadt doundiv(argv, argc); 350df930be7Sderaadt break; 351df930be7Sderaadt 352df930be7Sderaadt case DIVNTYPE: 353df930be7Sderaadt /* 354df930be7Sderaadt * dodivnum - return the number of 355df930be7Sderaadt * current output diversion 356df930be7Sderaadt */ 357df930be7Sderaadt pbnum(oindex); 358df930be7Sderaadt break; 359df930be7Sderaadt 360df930be7Sderaadt case UNDFTYPE: 361df930be7Sderaadt /* 362df930be7Sderaadt * doundefine - undefine a previously 363df930be7Sderaadt * defined macro(s) or m4 keyword(s). 364df930be7Sderaadt */ 365df930be7Sderaadt if (argc > 2) 366df930be7Sderaadt for (n = 2; n < argc; n++) 3673509e8ffSespie macro_undefine(argv[n]); 368df930be7Sderaadt break; 369df930be7Sderaadt 370df930be7Sderaadt case POPDTYPE: 371df930be7Sderaadt /* 372df930be7Sderaadt * dopopdef - remove the topmost 373df930be7Sderaadt * definitions of macro(s) or m4 374df930be7Sderaadt * keyword(s). 375df930be7Sderaadt */ 376df930be7Sderaadt if (argc > 2) 377df930be7Sderaadt for (n = 2; n < argc; n++) 3783509e8ffSespie macro_popdef(argv[n]); 379df930be7Sderaadt break; 380df930be7Sderaadt 381df930be7Sderaadt case MKTMTYPE: 382df930be7Sderaadt /* 383df930be7Sderaadt * dotemp - create a temporary file 384df930be7Sderaadt */ 38501e71e69Sespie if (argc > 2) { 38601e71e69Sespie int fd; 387bb34cd6cSespie char *temp; 38801e71e69Sespie 389bb34cd6cSespie temp = xstrdup(argv[2]); 390bb34cd6cSespie 391bb34cd6cSespie fd = mkstemp(temp); 39201e71e69Sespie if (fd == -1) 3930d3ffe1dSespie err(1, 3940d3ffe1dSespie "%s at line %lu: couldn't make temp file %s", 3950d3ffe1dSespie CURRENT_NAME, CURRENT_LINE, argv[2]); 39601e71e69Sespie close(fd); 397bb34cd6cSespie pbstr(temp); 398bb34cd6cSespie free(temp); 39901e71e69Sespie } 400df930be7Sderaadt break; 401df930be7Sderaadt 402df930be7Sderaadt case TRNLTYPE: 403df930be7Sderaadt /* 404df930be7Sderaadt * dotranslit - replace all characters in 405df930be7Sderaadt * the source string that appears in the 406df930be7Sderaadt * "from" string with the corresponding 407df930be7Sderaadt * characters in the "to" string. 408df930be7Sderaadt */ 409df930be7Sderaadt if (argc > 3) { 41028728804Sespie char *temp; 41128728804Sespie 412f6169a2cSespie temp = xalloc(strlen(argv[2])+1, NULL); 413df930be7Sderaadt if (argc > 4) 414df930be7Sderaadt map(temp, argv[2], argv[3], argv[4]); 415df930be7Sderaadt else 416df930be7Sderaadt map(temp, argv[2], argv[3], null); 417df930be7Sderaadt pbstr(temp); 41828728804Sespie free(temp); 4197d3e0b6bSderaadt } else if (argc > 2) 420df930be7Sderaadt pbstr(argv[2]); 421df930be7Sderaadt break; 422df930be7Sderaadt 423df930be7Sderaadt case INDXTYPE: 424df930be7Sderaadt /* 425df930be7Sderaadt * doindex - find the index of the second 426df930be7Sderaadt * argument string in the first argument 427df930be7Sderaadt * string. -1 if not present. 428df930be7Sderaadt */ 429df930be7Sderaadt pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1); 430df930be7Sderaadt break; 431df930be7Sderaadt 432df930be7Sderaadt case ERRPTYPE: 433df930be7Sderaadt /* 434df930be7Sderaadt * doerrp - print the arguments to stderr 435df930be7Sderaadt * file 436df930be7Sderaadt */ 437df930be7Sderaadt if (argc > 2) { 438df930be7Sderaadt for (n = 2; n < argc; n++) 439df930be7Sderaadt fprintf(stderr, "%s ", argv[n]); 440df930be7Sderaadt fprintf(stderr, "\n"); 441df930be7Sderaadt } 442df930be7Sderaadt break; 443df930be7Sderaadt 444df930be7Sderaadt case DNLNTYPE: 445df930be7Sderaadt /* 446df930be7Sderaadt * dodnl - eat-up-to and including 447df930be7Sderaadt * newline 448df930be7Sderaadt */ 449df930be7Sderaadt while ((c = gpbc()) != '\n' && c != EOF) 450df930be7Sderaadt ; 451df930be7Sderaadt break; 452df930be7Sderaadt 453df930be7Sderaadt case M4WRTYPE: 454df930be7Sderaadt /* 455df930be7Sderaadt * dom4wrap - set up for 456df930be7Sderaadt * wrap-up/wind-down activity 457df930be7Sderaadt */ 458ad459a23Sespie if (argc > 2) 459ad459a23Sespie dom4wrap(argv[2]); 460df930be7Sderaadt break; 461df930be7Sderaadt 462df930be7Sderaadt case EXITTYPE: 463df930be7Sderaadt /* 464df930be7Sderaadt * doexit - immediate exit from m4. 465df930be7Sderaadt */ 466df930be7Sderaadt killdiv(); 467df930be7Sderaadt exit((argc > 2) ? atoi(argv[2]) : 0); 468df930be7Sderaadt break; 469df930be7Sderaadt 470df930be7Sderaadt case DEFNTYPE: 471df930be7Sderaadt if (argc > 2) 472df930be7Sderaadt for (n = 2; n < argc; n++) 473df930be7Sderaadt dodefn(argv[n]); 474df930be7Sderaadt break; 475df930be7Sderaadt 476b8161682Sespie case INDIRTYPE: /* Indirect call */ 477b8161682Sespie if (argc > 2) 478b8161682Sespie doindir(argv, argc); 479b8161682Sespie break; 480b8161682Sespie 481b8161682Sespie case BUILTINTYPE: /* Builtins only */ 482b8161682Sespie if (argc > 2) 483b8161682Sespie dobuiltin(argv, argc); 484b8161682Sespie break; 485b8161682Sespie 486b8161682Sespie case PATSTYPE: 487b8161682Sespie if (argc > 2) 488b8161682Sespie dopatsubst(argv, argc); 489b8161682Sespie break; 490b8161682Sespie case REGEXPTYPE: 491b8161682Sespie if (argc > 2) 492b8161682Sespie doregexp(argv, argc); 493b8161682Sespie break; 494b8161682Sespie case LINETYPE: 495b8161682Sespie doprintlineno(infile+ilevel); 496b8161682Sespie break; 497b8161682Sespie case FILENAMETYPE: 498b8161682Sespie doprintfilename(infile+ilevel); 499b8161682Sespie break; 500423624b7Sespie case SELFTYPE: 501423624b7Sespie pbstr(rquote); 502423624b7Sespie pbstr(argv[1]); 503423624b7Sespie pbstr(lquote); 504423624b7Sespie break; 505df930be7Sderaadt default: 50675ebbed7Sespie m4errx(1, "eval: major botch."); 507df930be7Sderaadt break; 508df930be7Sderaadt } 509df930be7Sderaadt } 510df930be7Sderaadt 511df930be7Sderaadt /* 51208f7f207Sespie * expand_macro - user-defined macro expansion 513df930be7Sderaadt */ 514df930be7Sderaadt void 5158e061d4bSespie expand_macro(const char *argv[], int argc) 516df930be7Sderaadt { 517bb34cd6cSespie const char *t; 518bb34cd6cSespie const char *p; 51953f6f6bfSespie int n; 52053f6f6bfSespie int argno; 521df930be7Sderaadt 522df930be7Sderaadt t = argv[0]; /* defn string as a whole */ 523df930be7Sderaadt p = t; 524df930be7Sderaadt while (*p) 525df930be7Sderaadt p++; 526df930be7Sderaadt p--; /* last character of defn */ 527df930be7Sderaadt while (p > t) { 528df930be7Sderaadt if (*(p - 1) != ARGFLAG) 529739ce124Sespie PUSHBACK(*p); 530df930be7Sderaadt else { 531df930be7Sderaadt switch (*p) { 532df930be7Sderaadt 533df930be7Sderaadt case '#': 534df930be7Sderaadt pbnum(argc - 2); 535df930be7Sderaadt break; 536df930be7Sderaadt case '0': 537df930be7Sderaadt case '1': 538df930be7Sderaadt case '2': 539df930be7Sderaadt case '3': 540df930be7Sderaadt case '4': 541df930be7Sderaadt case '5': 542df930be7Sderaadt case '6': 543df930be7Sderaadt case '7': 544df930be7Sderaadt case '8': 545df930be7Sderaadt case '9': 546df930be7Sderaadt if ((argno = *p - '0') < argc - 1) 547df930be7Sderaadt pbstr(argv[argno + 1]); 548df930be7Sderaadt break; 549df930be7Sderaadt case '*': 550faa30e49Sespie if (argc > 2) { 551df930be7Sderaadt for (n = argc - 1; n > 2; n--) { 552df930be7Sderaadt pbstr(argv[n]); 553739ce124Sespie pushback(COMMA); 554df930be7Sderaadt } 555df930be7Sderaadt pbstr(argv[2]); 556faa30e49Sespie } 557df930be7Sderaadt break; 558aa676ce1Smillert case '@': 559faa30e49Sespie if (argc > 2) { 560aa676ce1Smillert for (n = argc - 1; n > 2; n--) { 561aa676ce1Smillert pbstr(rquote); 562aa676ce1Smillert pbstr(argv[n]); 563aa676ce1Smillert pbstr(lquote); 564739ce124Sespie pushback(COMMA); 565aa676ce1Smillert } 566aa676ce1Smillert pbstr(rquote); 567aa676ce1Smillert pbstr(argv[2]); 568aa676ce1Smillert pbstr(lquote); 569faa30e49Sespie } 570aa676ce1Smillert break; 571df930be7Sderaadt default: 572739ce124Sespie PUSHBACK(*p); 573739ce124Sespie PUSHBACK('$'); 574df930be7Sderaadt break; 575df930be7Sderaadt } 576df930be7Sderaadt p--; 577df930be7Sderaadt } 578df930be7Sderaadt p--; 579df930be7Sderaadt } 580df930be7Sderaadt if (p == t) /* do last character */ 581739ce124Sespie PUSHBACK(*p); 582df930be7Sderaadt } 583df930be7Sderaadt 5845ddad5ccSespie 585df930be7Sderaadt /* 5865ddad5ccSespie * dodefine - install definition in the table 5875ddad5ccSespie */ 5885ddad5ccSespie void 5895ddad5ccSespie dodefine(const char *name, const char *defn) 5905ddad5ccSespie { 59187a9001aSespie if (!*name && !mimic_gnu) 59275ebbed7Sespie m4errx(1, "null definition."); 59387a9001aSespie else 5943509e8ffSespie macro_define(name, defn); 595df930be7Sderaadt } 596df930be7Sderaadt 597df930be7Sderaadt /* 598df930be7Sderaadt * dodefn - push back a quoted definition of 599df930be7Sderaadt * the given name. 600df930be7Sderaadt */ 601bb34cd6cSespie static void 6028e061d4bSespie dodefn(const char *name) 603df930be7Sderaadt { 6043509e8ffSespie struct macro_definition *p; 605df930be7Sderaadt 6063509e8ffSespie if ((p = lookup_macro_definition(name)) != NULL) { 6075ddad5ccSespie if ((p->type & TYPEMASK) == MACRTYPE) { 6083a73db8cSderaadt pbstr(rquote); 609df930be7Sderaadt pbstr(p->defn); 6103a73db8cSderaadt pbstr(lquote); 6115ddad5ccSespie } else { 6125ddad5ccSespie pbstr(p->defn); 613f8b42d48Sespie pbstr(BUILTIN_MARKER); 614f8b42d48Sespie } 615df930be7Sderaadt } 616df930be7Sderaadt } 617df930be7Sderaadt 618df930be7Sderaadt /* 619df930be7Sderaadt * dopushdef - install a definition in the hash table 620df930be7Sderaadt * without removing a previous definition. Since 621df930be7Sderaadt * each new entry is entered in *front* of the 622df930be7Sderaadt * hash bucket, it hides a previous definition from 623df930be7Sderaadt * lookup. 624df930be7Sderaadt */ 625bb34cd6cSespie static void 6268e061d4bSespie dopushdef(const char *name, const char *defn) 627df930be7Sderaadt { 62887a9001aSespie if (!*name && !mimic_gnu) 62975ebbed7Sespie m4errx(1, "null definition."); 63087a9001aSespie else 6313509e8ffSespie macro_pushdef(name, defn); 632df930be7Sderaadt } 633df930be7Sderaadt 634df930be7Sderaadt /* 635dd0682a2Sespie * dump_one_def - dump the specified definition. 636dd0682a2Sespie */ 637dd0682a2Sespie static void 6383509e8ffSespie dump_one_def(const char *name, struct macro_definition *p) 639dd0682a2Sespie { 640ad93774eSespie if (!traceout) 641ad93774eSespie traceout = stderr; 6425191fa0aSespie if (mimic_gnu) { 6435191fa0aSespie if ((p->type & TYPEMASK) == MACRTYPE) 6443509e8ffSespie fprintf(traceout, "%s:\t%s\n", name, p->defn); 6455191fa0aSespie else { 6463509e8ffSespie fprintf(traceout, "%s:\t<%s>\n", name, p->defn); 6475191fa0aSespie } 6485191fa0aSespie } else 6493509e8ffSespie fprintf(traceout, "`%s'\t`%s'\n", name, p->defn); 650dd0682a2Sespie } 651dd0682a2Sespie 652dd0682a2Sespie /* 653df930be7Sderaadt * dodumpdef - dump the specified definitions in the hash 654df930be7Sderaadt * table to stderr. If nothing is specified, the entire 655df930be7Sderaadt * hash table is dumped. 656df930be7Sderaadt */ 657bb34cd6cSespie static void 6588e061d4bSespie dodump(const char *argv[], int argc) 659df930be7Sderaadt { 66053f6f6bfSespie int n; 6613509e8ffSespie struct macro_definition *p; 662df930be7Sderaadt 663df930be7Sderaadt if (argc > 2) { 664df930be7Sderaadt for (n = 2; n < argc; n++) 6653509e8ffSespie if ((p = lookup_macro_definition(argv[n])) != NULL) 6663509e8ffSespie dump_one_def(argv[n], p); 6673509e8ffSespie } else 6683509e8ffSespie macro_for_all(dump_one_def); 669df930be7Sderaadt } 670df930be7Sderaadt 671df930be7Sderaadt /* 67234970243Sespie * dotrace - mark some macros as traced/untraced depending upon on. 67334970243Sespie */ 67434970243Sespie static void 6758e061d4bSespie dotrace(const char *argv[], int argc, int on) 67634970243Sespie { 67734970243Sespie int n; 67834970243Sespie 67934970243Sespie if (argc > 2) { 68034970243Sespie for (n = 2; n < argc; n++) 68134970243Sespie mark_traced(argv[n], on); 68234970243Sespie } else 68334970243Sespie mark_traced(NULL, on); 68434970243Sespie } 68534970243Sespie 68634970243Sespie /* 687df930be7Sderaadt * doifelse - select one of two alternatives - loop. 688df930be7Sderaadt */ 689bb34cd6cSespie static void 6908e061d4bSespie doifelse(const char *argv[], int argc) 691df930be7Sderaadt { 692df930be7Sderaadt cycle { 693df930be7Sderaadt if (STREQ(argv[2], argv[3])) 694df930be7Sderaadt pbstr(argv[4]); 695df930be7Sderaadt else if (argc == 6) 696df930be7Sderaadt pbstr(argv[5]); 697df930be7Sderaadt else if (argc > 6) { 698df930be7Sderaadt argv += 3; 699df930be7Sderaadt argc -= 3; 700df930be7Sderaadt continue; 701df930be7Sderaadt } 702df930be7Sderaadt break; 703df930be7Sderaadt } 704df930be7Sderaadt } 705df930be7Sderaadt 706df930be7Sderaadt /* 707df930be7Sderaadt * doinclude - include a given file. 708df930be7Sderaadt */ 709bb34cd6cSespie static int 7108e061d4bSespie doincl(const char *ifile) 711df930be7Sderaadt { 712df930be7Sderaadt if (ilevel + 1 == MAXINP) 71375ebbed7Sespie m4errx(1, "too many include files."); 7140d3ffe1dSespie if (fopen_trypath(infile+ilevel+1, ifile) != NULL) { 715df930be7Sderaadt ilevel++; 716df930be7Sderaadt bbase[ilevel] = bufbase = bp; 717df930be7Sderaadt return (1); 7187d3e0b6bSderaadt } else 719df930be7Sderaadt return (0); 720df930be7Sderaadt } 721df930be7Sderaadt 722df930be7Sderaadt #ifdef EXTENDED 723df930be7Sderaadt /* 724df930be7Sderaadt * dopaste - include a given file without any 725df930be7Sderaadt * macro processing. 726df930be7Sderaadt */ 727bb34cd6cSespie static int 7288e061d4bSespie dopaste(const char *pfile) 729df930be7Sderaadt { 730df930be7Sderaadt FILE *pf; 73153f6f6bfSespie int c; 732df930be7Sderaadt 733df930be7Sderaadt if ((pf = fopen(pfile, "r")) != NULL) { 734aec72266Sespie if (synch_lines) 735aec72266Sespie fprintf(active, "#line 1 \"%s\"\n", pfile); 736df930be7Sderaadt while ((c = getc(pf)) != EOF) 737df930be7Sderaadt putc(c, active); 738df930be7Sderaadt (void) fclose(pf); 739aec72266Sespie emit_synchline(); 740df930be7Sderaadt return (1); 7417d3e0b6bSderaadt } else 742df930be7Sderaadt return (0); 743df930be7Sderaadt } 744df930be7Sderaadt #endif 745df930be7Sderaadt 746df930be7Sderaadt /* 747df930be7Sderaadt * dochq - change quote characters 748df930be7Sderaadt */ 749bb34cd6cSespie static void 750739ce124Sespie dochq(const char *argv[], int ac) 751df930be7Sderaadt { 752739ce124Sespie if (ac == 2) { 753739ce124Sespie lquote[0] = LQUOTE; lquote[1] = EOS; 754739ce124Sespie rquote[0] = RQUOTE; rquote[1] = EOS; 7557d3e0b6bSderaadt } else { 756739ce124Sespie strlcpy(lquote, argv[2], sizeof(lquote)); 757739ce124Sespie if (ac > 3) { 758739ce124Sespie strlcpy(rquote, argv[3], sizeof(rquote)); 759739ce124Sespie } else { 760739ce124Sespie rquote[0] = ECOMMT; rquote[1] = EOS; 761739ce124Sespie } 762df930be7Sderaadt } 763df930be7Sderaadt } 764df930be7Sderaadt 765df930be7Sderaadt /* 766df930be7Sderaadt * dochc - change comment characters 767df930be7Sderaadt */ 768bb34cd6cSespie static void 7698e061d4bSespie dochc(const char *argv[], int argc) 770df930be7Sderaadt { 771739ce124Sespie /* XXX Note that there is no difference between no argument and a single 772739ce124Sespie * empty argument. 773739ce124Sespie */ 774739ce124Sespie if (argc == 2) { 775739ce124Sespie scommt[0] = EOS; 776739ce124Sespie ecommt[0] = EOS; 777739ce124Sespie } else { 778b81b15b2Sespie strlcpy(scommt, argv[2], sizeof(scommt)); 779739ce124Sespie if (argc == 3) { 780739ce124Sespie ecommt[0] = ECOMMT; ecommt[1] = EOS; 781739ce124Sespie } else { 782b81b15b2Sespie strlcpy(ecommt, argv[3], sizeof(ecommt)); 783df930be7Sderaadt } 784df930be7Sderaadt } 785df930be7Sderaadt } 786df930be7Sderaadt 787df930be7Sderaadt /* 788ad459a23Sespie * dom4wrap - expand text at EOF 789ad459a23Sespie */ 790ad459a23Sespie static void 791ad459a23Sespie dom4wrap(const char *text) 792ad459a23Sespie { 793ad459a23Sespie if (wrapindex >= maxwraps) { 794ad459a23Sespie if (maxwraps == 0) 795ad459a23Sespie maxwraps = 16; 796ad459a23Sespie else 797ad459a23Sespie maxwraps *= 2; 798c608d5f4Sespie m4wraps = xreallocarray(m4wraps, maxwraps, sizeof(*m4wraps), 799ad459a23Sespie "too many m4wraps"); 800ad459a23Sespie } 801ad459a23Sespie m4wraps[wrapindex++] = xstrdup(text); 802ad459a23Sespie } 803ad459a23Sespie 804ad459a23Sespie /* 805df930be7Sderaadt * dodivert - divert the output to a temporary file 806df930be7Sderaadt */ 807bb34cd6cSespie static void 8088e061d4bSespie dodiv(int n) 809df930be7Sderaadt { 810445b77f7Smillert int fd; 811445b77f7Smillert 8127d3e0b6bSderaadt oindex = n; 81325afcddbSespie if (n >= maxout) { 81425afcddbSespie if (mimic_gnu) 81525afcddbSespie resizedivs(n + 10); 81625afcddbSespie else 81725afcddbSespie n = 0; /* bitbucket */ 81825afcddbSespie } 81925afcddbSespie 82025afcddbSespie if (n < 0) 821df930be7Sderaadt n = 0; /* bitbucket */ 822df930be7Sderaadt if (outfile[n] == NULL) { 8233f42598dSespie char fname[] = _PATH_DIVNAME; 8243f42598dSespie 8253f42598dSespie if ((fd = mkstemp(fname)) < 0 || 826f5d2852fSespie unlink(fname) == -1 || 8273f42598dSespie (outfile[n] = fdopen(fd, "w+")) == NULL) 8283f42598dSespie err(1, "%s: cannot divert", fname); 829df930be7Sderaadt } 830df930be7Sderaadt active = outfile[n]; 831df930be7Sderaadt } 832df930be7Sderaadt 833df930be7Sderaadt /* 834df930be7Sderaadt * doundivert - undivert a specified output, or all 835df930be7Sderaadt * other outputs, in numerical order. 836df930be7Sderaadt */ 837bb34cd6cSespie static void 8388e061d4bSespie doundiv(const char *argv[], int argc) 839df930be7Sderaadt { 84053f6f6bfSespie int ind; 84153f6f6bfSespie int n; 842df930be7Sderaadt 843df930be7Sderaadt if (argc > 2) { 844df930be7Sderaadt for (ind = 2; ind < argc; ind++) { 845e79fa687Sespie const char *errstr; 846e79fa687Sespie n = strtonum(argv[ind], 1, INT_MAX, &errstr); 847e79fa687Sespie if (errstr) { 848e79fa687Sespie if (errno == EINVAL && mimic_gnu) 849e79fa687Sespie getdivfile(argv[ind]); 850e79fa687Sespie } else { 851e79fa687Sespie if (n < maxout && outfile[n] != NULL) 852df930be7Sderaadt getdiv(n); 853e79fa687Sespie } 854df930be7Sderaadt } 855df930be7Sderaadt } 856df930be7Sderaadt else 85725afcddbSespie for (n = 1; n < maxout; n++) 858df930be7Sderaadt if (outfile[n] != NULL) 859df930be7Sderaadt getdiv(n); 860df930be7Sderaadt } 861df930be7Sderaadt 862df930be7Sderaadt /* 863df930be7Sderaadt * dosub - select substring 864df930be7Sderaadt */ 865bb34cd6cSespie static void 8668e061d4bSespie dosub(const char *argv[], int argc) 867df930be7Sderaadt { 868bb34cd6cSespie const char *ap, *fc, *k; 86953f6f6bfSespie int nc; 870df930be7Sderaadt 871df930be7Sderaadt ap = argv[2]; /* target string */ 872df930be7Sderaadt #ifdef EXPR 873df930be7Sderaadt fc = ap + expr(argv[3]); /* first char */ 874df930be7Sderaadt #else 875df930be7Sderaadt fc = ap + atoi(argv[3]); /* first char */ 876df930be7Sderaadt #endif 877bee8364eSespie nc = strlen(fc); 878bee8364eSespie if (argc >= 5) 879bee8364eSespie #ifdef EXPR 880bee8364eSespie nc = min(nc, expr(argv[4])); 881bee8364eSespie #else 882bee8364eSespie nc = min(nc, atoi(argv[4])); 883bee8364eSespie #endif 884df930be7Sderaadt if (fc >= ap && fc < ap + strlen(ap)) 885bee8364eSespie for (k = fc + nc - 1; k >= fc; k--) 886739ce124Sespie pushback(*k); 887df930be7Sderaadt } 888df930be7Sderaadt 889df930be7Sderaadt /* 890df930be7Sderaadt * map: 891df930be7Sderaadt * map every character of s1 that is specified in from 892df930be7Sderaadt * into s3 and replace in s. (source s1 remains untouched) 893df930be7Sderaadt * 89487ab3cf4Sespie * This is derived from the a standard implementation of map(s,from,to) 89587ab3cf4Sespie * function of ICON language. Within mapvec, we replace every character 89687ab3cf4Sespie * of "from" with the corresponding character in "to". 89787ab3cf4Sespie * If "to" is shorter than "from", than the corresponding entries are null, 89887ab3cf4Sespie * which means that those characters dissapear altogether. 899df930be7Sderaadt */ 900bb34cd6cSespie static void 9018e061d4bSespie map(char *dest, const char *src, const char *from, const char *to) 902df930be7Sderaadt { 903bb34cd6cSespie const char *tmp; 904ee3599c7Sespie unsigned char sch, dch; 90587c5c065Sespie static char frombis[257]; 90687c5c065Sespie static char tobis[257]; 90727e0c134Sespie int i; 90827e0c134Sespie char seen[256]; 909ee3599c7Sespie static unsigned char mapvec[256] = { 910ee3599c7Sespie 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 911ee3599c7Sespie 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 912ee3599c7Sespie 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 913ee3599c7Sespie 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 914ee3599c7Sespie 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 915ee3599c7Sespie 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 916ee3599c7Sespie 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 917ee3599c7Sespie 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 918ee3599c7Sespie 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 919ee3599c7Sespie 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 920ee3599c7Sespie 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 921ee3599c7Sespie 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 922ee3599c7Sespie 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 923ee3599c7Sespie 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 924ee3599c7Sespie 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 925ee3599c7Sespie 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 926ee3599c7Sespie 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 927ee3599c7Sespie 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 928df930be7Sderaadt }; 929df930be7Sderaadt 930df930be7Sderaadt if (*src) { 93187c5c065Sespie if (mimic_gnu) { 93287c5c065Sespie /* 93387c5c065Sespie * expand character ranges on the fly 93487c5c065Sespie */ 93587c5c065Sespie from = handledash(frombis, frombis + 256, from); 93687c5c065Sespie to = handledash(tobis, tobis + 256, to); 93787c5c065Sespie } 938df930be7Sderaadt tmp = from; 939df930be7Sderaadt /* 940df930be7Sderaadt * create a mapping between "from" and 941df930be7Sderaadt * "to" 942df930be7Sderaadt */ 94327e0c134Sespie for (i = 0; i < 256; i++) 94427e0c134Sespie seen[i] = 0; 94527e0c134Sespie while (*from) { 94627e0c134Sespie if (!seen[(unsigned char)(*from)]) { 94727e0c134Sespie mapvec[(unsigned char)(*from)] = (unsigned char)(*to); 94827e0c134Sespie seen[(unsigned char)(*from)] = 1; 94927e0c134Sespie } 95027e0c134Sespie from++; 95127e0c134Sespie if (*to) 95227e0c134Sespie to++; 95327e0c134Sespie } 954df930be7Sderaadt 955df930be7Sderaadt while (*src) { 956ee3599c7Sespie sch = (unsigned char)(*src++); 957df930be7Sderaadt dch = mapvec[sch]; 958ee3599c7Sespie if ((*dest = (char)dch)) 959df930be7Sderaadt dest++; 960df930be7Sderaadt } 961df930be7Sderaadt /* 962df930be7Sderaadt * restore all the changed characters 963df930be7Sderaadt */ 964df930be7Sderaadt while (*tmp) { 965ee3599c7Sespie mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp); 966df930be7Sderaadt tmp++; 967df930be7Sderaadt } 968df930be7Sderaadt } 969ee3599c7Sespie *dest = '\0'; 970df930be7Sderaadt } 97187c5c065Sespie 97287c5c065Sespie 97387c5c065Sespie /* 97487c5c065Sespie * handledash: 97587c5c065Sespie * use buffer to copy the src string, expanding character ranges 97687c5c065Sespie * on the way. 97787c5c065Sespie */ 97887c5c065Sespie static const char * 9798e061d4bSespie handledash(char *buffer, char *end, const char *src) 98087c5c065Sespie { 98187c5c065Sespie char *p; 98287c5c065Sespie 98387c5c065Sespie p = buffer; 98487c5c065Sespie while(*src) { 98587c5c065Sespie if (src[1] == '-' && src[2]) { 98687c5c065Sespie unsigned char i; 987e79fa687Sespie if ((unsigned char)src[0] <= (unsigned char)src[2]) { 98887c5c065Sespie for (i = (unsigned char)src[0]; 98987c5c065Sespie i <= (unsigned char)src[2]; i++) { 99087c5c065Sespie *p++ = i; 99187c5c065Sespie if (p == end) { 99287c5c065Sespie *p = '\0'; 99387c5c065Sespie return buffer; 99487c5c065Sespie } 99587c5c065Sespie } 996e79fa687Sespie } else { 997e79fa687Sespie for (i = (unsigned char)src[0]; 998e79fa687Sespie i >= (unsigned char)src[2]; i--) { 999e79fa687Sespie *p++ = i; 1000e79fa687Sespie if (p == end) { 1001e79fa687Sespie *p = '\0'; 1002e79fa687Sespie return buffer; 1003e79fa687Sespie } 1004e79fa687Sespie } 1005e79fa687Sespie } 100687c5c065Sespie src += 3; 100787c5c065Sespie } else 100887c5c065Sespie *p++ = *src++; 100987c5c065Sespie if (p == end) 101087c5c065Sespie break; 101187c5c065Sespie } 101287c5c065Sespie *p = '\0'; 101387c5c065Sespie return buffer; 101487c5c065Sespie } 1015