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