GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/m4/eval.c Lines: 201 356 56.5 %
Date: 2017-11-07 Branches: 141 336 42.0 %

Line Branch Exec Source
1
/*	$OpenBSD: eval.c,v 1.75 2017/06/15 13:48:42 bcallah Exp $	*/
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.
19
 * 3. Neither the name of the University nor the names of its contributors
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.
34
 */
35
36
/*
37
 * eval.c
38
 * Facility: m4 macro processor
39
 * by: oz
40
 */
41
42
#include <sys/types.h>
43
#include <err.h>
44
#include <errno.h>
45
#include <limits.h>
46
#include <unistd.h>
47
#include <stdio.h>
48
#include <stdint.h>
49
#include <stdlib.h>
50
#include <stddef.h>
51
#include <string.h>
52
#include <fcntl.h>
53
#include "mdef.h"
54
#include "stdd.h"
55
#include "extern.h"
56
#include "pathnames.h"
57
58
static void	dodefn(const char *);
59
static void	dopushdef(const char *, const char *);
60
static void	dodump(const char *[], int);
61
static void	dotrace(const char *[], int, int);
62
static void	doifelse(const char *[], int);
63
static int	doincl(const char *);
64
static int	dopaste(const char *);
65
static void	dochq(const char *[], int);
66
static void	dochc(const char *[], int);
67
static void	dom4wrap(const char *);
68
static void	dodiv(int);
69
static void	doundiv(const char *[], int);
70
static void	dosub(const char *[], int);
71
static void	map(char *, const char *, const char *, const char *);
72
static const char *handledash(char *, char *, const char *);
73
static void	expand_builtin(const char *[], int, int);
74
static void	expand_macro(const char *[], int);
75
static void	dump_one_def(const char *, struct macro_definition *);
76
77
unsigned long	expansion_id;
78
79
/*
80
 * eval - eval all macros and builtins calls
81
 *	  argc - number of elements in argv.
82
 *	  argv - element vector :
83
 *			argv[0] = definition of a user
84
 *				  macro or NULL if built-in.
85
 *			argv[1] = name of the macro or
86
 *				  built-in.
87
 *			argv[2] = parameters to user-defined
88
 *			   .	  macro or built-in.
89
 *			   .
90
 *
91
 * A call in the form of macro-or-builtin() will result in:
92
 *			argv[0] = nullstr
93
 *			argv[1] = macro-or-builtin
94
 *			argv[2] = nullstr
95
 *
96
 * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin
97
 */
98
void
99
eval(const char *argv[], int argc, int td, int is_traced)
100
{
101
	size_t mark = SIZE_MAX;
102
103
28441410
	expansion_id++;
104
14220705
	if (td & RECDEF)
105
		m4errx(1, "expanding recursive definition for %s.", argv[1]);
106
14220705
	if (is_traced)
107
		mark = trace(argv, argc, infile+ilevel);
108
14220705
	if (td == MACRTYPE)
109
4380977
		expand_macro(argv, argc);
110
	else
111
9839728
		expand_builtin(argv, argc, td);
112
14220696
	if (mark != SIZE_MAX)
113
		finish_trace(mark);
114
14220696
}
115
116
/*
117
 * expand_builtin - evaluate built-in macros.
118
 */
119
void
120
expand_builtin(const char *argv[], int argc, int td)
121
{
122
	int c, n;
123
	int ac;
124
	static int sysval = 0;
125
126
#ifdef DEBUG
127
	printf("argc = %d\n", argc);
128
	for (n = 0; n < argc; n++)
129
		printf("argv[%d] = %s\n", n, argv[n]);
130
	fflush(stdout);
131
#endif
132
133
 /*
134
  * if argc == 3 and argv[2] is null, then we
135
  * have macro-or-builtin() type call. We adjust
136
  * argc to avoid further checking..
137
  */
138
 /* we keep the initial value for those built-ins that differentiate
139
  * between builtin() and builtin.
140
  */
141
	ac = argc;
142
143

22957535
	if (argc == 3 && !*(argv[2]) && !mimic_gnu)
144
36
		argc--;
145
146











9873216
	switch (td & TYPEMASK) {
147
148
	case DEFITYPE:
149
981
		if (argc > 2)
150
981
			dodefine(argv[2], (argc > 3) ? argv[3] : null);
151
		break;
152
153
	case PUSDTYPE:
154
		if (argc > 2)
155
			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
156
		break;
157
158
	case DUMPTYPE:
159
18
		dodump(argv, argc);
160
18
		break;
161
162
	case TRACEONTYPE:
163
		dotrace(argv, argc, 1);
164
		break;
165
166
	case TRACEOFFTYPE:
167
		dotrace(argv, argc, 0);
168
		break;
169
170
	case EXPRTYPE:
171
	/*
172
	 * doexpr - evaluate arithmetic
173
	 * expression
174
	 */
175
	{
176
		int base = 10;
177
		int maxdigits = 0;
178
54
		const char *errstr;
179
180
54
		if (argc > 3) {
181
			base = strtonum(argv[3], 2, 36, &errstr);
182
			if (errstr) {
183
				m4errx(1, "expr: base %s invalid.", argv[3]);
184
			}
185
		}
186
54
		if (argc > 4) {
187
			maxdigits = strtonum(argv[4], 0, INT_MAX, &errstr);
188
			if (errstr) {
189
				m4errx(1, "expr: maxdigits %s invalid.", argv[4]);
190
			}
191
		}
192
54
		if (argc > 2)
193
54
			pbnumbase(expr(argv[2]), base, maxdigits);
194
		break;
195
54
	}
196
197
	case IFELTYPE:
198
2187340
		if (argc > 4)
199
2187340
			doifelse(argv, argc);
200
		break;
201
202
	case IFDFTYPE:
203
	/*
204
	 * doifdef - select one of two
205
	 * alternatives based on the existence of
206
	 * another definition
207
	 */
208
1328
		if (argc > 3) {
209
1328
			if (lookup_macro_definition(argv[2]) != NULL)
210
451
				pbstr(argv[3]);
211
877
			else if (argc > 4)
212
584
				pbstr(argv[4]);
213
		}
214
		break;
215
216
	case LENGTYPE:
217
	/*
218
	 * dolen - find the length of the
219
	 * argument
220
	 */
221
		pbnum((argc > 2) ? strlen(argv[2]) : 0);
222
		break;
223
224
	case INCRTYPE:
225
	/*
226
	 * doincr - increment the value of the
227
	 * argument
228
	 */
229
		if (argc > 2)
230
			pbnum(atoi(argv[2]) + 1);
231
		break;
232
233
	case DECRTYPE:
234
	/*
235
	 * dodecr - decrement the value of the
236
	 * argument
237
	 */
238
3277584
		if (argc > 2)
239
3277584
			pbnum(atoi(argv[2]) - 1);
240
		break;
241
242
	case SYSCTYPE:
243
	/*
244
	 * dosys - execute system command
245
	 */
246
		if (argc > 2) {
247
			fflush(stdout);
248
			sysval = system(argv[2]);
249
		}
250
		break;
251
252
	case SYSVTYPE:
253
	/*
254
	 * dosysval - return value of the last
255
	 * system call.
256
	 *
257
	 */
258
		pbnum(sysval);
259
		break;
260
261
	case ESYSCMDTYPE:
262
9
		if (argc > 2)
263
9
			doesyscmd(argv[2]);
264
		break;
265
	case INCLTYPE:
266
27
		if (argc > 2) {
267
27
			if (!doincl(argv[2])) {
268
18
				if (mimic_gnu) {
269
18
					warn("%s at line %lu: include(%s)",
270
					    CURRENT_NAME, CURRENT_LINE, argv[2]);
271
18
					exit_code = 1;
272
18
					if (fatal_warns) {
273
						killdiv();
274
						exit(exit_code);
275
					}
276
				} else
277
					err(1, "%s at line %lu: include(%s)",
278
					    CURRENT_NAME, CURRENT_LINE, argv[2]);
279
			}
280
		}
281
		break;
282
283
	case SINCTYPE:
284
		if (argc > 2)
285
			(void) doincl(argv[2]);
286
		break;
287
#ifdef EXTENDED
288
	case PASTTYPE:
289
		if (argc > 2)
290
			if (!dopaste(argv[2]))
291
				err(1, "%s at line %lu: paste(%s)",
292
				    CURRENT_NAME, CURRENT_LINE, argv[2]);
293
		break;
294
295
	case SPASTYPE:
296
		if (argc > 2)
297
			(void) dopaste(argv[2]);
298
		break;
299
	case FORMATTYPE:
300
9
		doformat(argv, argc);
301
9
		break;
302
#endif
303
	case CHNQTYPE:
304
141
		dochq(argv, ac);
305
141
		break;
306
307
	case CHNCTYPE:
308
83
		dochc(argv, argc);
309
83
		break;
310
311
	case SUBSTYPE:
312
	/*
313
	 * dosub - select substring
314
	 *
315
	 */
316
		if (argc > 3)
317
			dosub(argv, argc);
318
		break;
319
320
	case SHIFTYPE:
321
	/*
322
	 * doshift - push back all arguments
323
	 * except the first one (i.e. skip
324
	 * argv[2])
325
	 */
326
		if (argc > 3) {
327
			for (n = argc - 1; n > 3; n--) {
328
				pbstr(rquote);
329
				pbstr(argv[n]);
330
				pbstr(lquote);
331
				pushback(COMMA);
332
			}
333
			pbstr(rquote);
334
			pbstr(argv[3]);
335
			pbstr(lquote);
336
		}
337
		break;
338
339
	case DIVRTYPE:
340
		if (argc > 2 && (n = atoi(argv[2])) != 0)
341
			dodiv(n);
342
		else {
343
			active = stdout;
344
			oindex = 0;
345
		}
346
		break;
347
348
	case UNDVTYPE:
349
		doundiv(argv, argc);
350
		break;
351
352
	case DIVNTYPE:
353
	/*
354
	 * dodivnum - return the number of
355
	 * current output diversion
356
	 */
357
		pbnum(oindex);
358
		break;
359
360
	case UNDFTYPE:
361
	/*
362
	 * doundefine - undefine a previously
363
	 * defined macro(s) or m4 keyword(s).
364
	 */
365
54
		if (argc > 2)
366
216
			for (n = 2; n < argc; n++)
367
54
				macro_undefine(argv[n]);
368
		break;
369
370
	case POPDTYPE:
371
	/*
372
	 * dopopdef - remove the topmost
373
	 * definitions of macro(s) or m4
374
	 * keyword(s).
375
	 */
376
		if (argc > 2)
377
			for (n = 2; n < argc; n++)
378
				macro_popdef(argv[n]);
379
		break;
380
381
	case MKTMTYPE:
382
	/*
383
	 * dotemp - create a temporary file
384
	 */
385
		if (argc > 2) {
386
			int fd;
387
			char *temp;
388
389
			temp = xstrdup(argv[2]);
390
391
			fd = mkstemp(temp);
392
			if (fd == -1)
393
				err(1,
394
	    "%s at line %lu: couldn't make temp file %s",
395
	    CURRENT_NAME, CURRENT_LINE, argv[2]);
396
			close(fd);
397
			pbstr(temp);
398
			free(temp);
399
		}
400
		break;
401
402
	case TRNLTYPE:
403
	/*
404
	 * dotranslit - replace all characters in
405
	 * the source string that appears in the
406
	 * "from" string with the corresponding
407
	 * characters in the "to" string.
408
	 */
409
117
		if (argc > 3) {
410
			char *temp;
411
412
117
			temp = xalloc(strlen(argv[2])+1, NULL);
413
117
			if (argc > 4)
414
117
				map(temp, argv[2], argv[3], argv[4]);
415
			else
416
				map(temp, argv[2], argv[3], null);
417
117
			pbstr(temp);
418
117
			free(temp);
419
117
		} else if (argc > 2)
420
			pbstr(argv[2]);
421
		break;
422
423
	case INDXTYPE:
424
	/*
425
	 * doindex - find the index of the second
426
	 * argument string in the first argument
427
	 * string. -1 if not present.
428
	 */
429
		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
430
		break;
431
432
	case ERRPTYPE:
433
	/*
434
	 * doerrp - print the arguments to stderr
435
	 * file
436
	 */
437
		if (argc > 2) {
438
			for (n = 2; n < argc; n++)
439
				fprintf(stderr, "%s ", argv[n]);
440
			fprintf(stderr, "\n");
441
		}
442
		break;
443
444
	case DNLNTYPE:
445
	/*
446
	 * dodnl - eat-up-to and including
447
	 * newline
448
	 */
449

13215576
		while ((c = gpbc()) != '\n' && c != EOF)
450
			;
451
		break;
452
453
	case M4WRTYPE:
454
	/*
455
	 * dom4wrap - set up for
456
	 * wrap-up/wind-down activity
457
	 */
458
90
		if (argc > 2)
459
90
			dom4wrap(argv[2]);
460
		break;
461
462
	case EXITTYPE:
463
	/*
464
	 * doexit - immediate exit from m4.
465
	 */
466
		killdiv();
467
		exit((argc > 2) ? atoi(argv[2]) : 0);
468
		break;
469
470
	case DEFNTYPE:
471
54
		if (argc > 2)
472
216
			for (n = 2; n < argc; n++)
473
54
				dodefn(argv[n]);
474
		break;
475
476
	case INDIRTYPE:	/* Indirect call */
477
18
		if (argc > 2)
478
18
			doindir(argv, argc);
479
		break;
480
481
	case BUILTINTYPE: /* Builtins only */
482
		if (argc > 2)
483
			dobuiltin(argv, argc);
484
		break;
485
486
	case PATSTYPE:
487
108
		if (argc > 2)
488
108
			dopatsubst(argv, argc);
489
		break;
490
	case REGEXPTYPE:
491
		if (argc > 2)
492
			doregexp(argv, argc);
493
		break;
494
	case LINETYPE:
495
		doprintlineno(infile+ilevel);
496
		break;
497
	case FILENAMETYPE:
498
9
		doprintfilename(infile+ilevel);
499
9
		break;
500
	case SELFTYPE:
501
		pbstr(rquote);
502
		pbstr(argv[1]);
503
		pbstr(lquote);
504
		break;
505
	default:
506
		m4errx(1, "eval: major botch.");
507
		break;
508
	}
509
9839719
}
510
511
/*
512
 * expand_macro - user-defined macro expansion
513
 */
514
void
515
expand_macro(const char *argv[], int argc)
516
{
517
	const char *t;
518
	const char *p;
519
	int n;
520
	int argno;
521
522
8761954
	t = argv[0];		       /* defn string as a whole */
523
	p = t;
524
385890052
	while (*p)
525
188564049
		p++;
526
4380977
	p--;			       /* last character of defn */
527
359596762
	while (p > t) {
528
175417404
		if (*(p - 1) != ARGFLAG)
529
328930972
			PUSHBACK(*p);
530
		else {
531



10951918
			switch (*p) {
532
533
			case '#':
534
2265
				pbnum(argc - 2);
535
2265
				break;
536
			case '0':
537
			case '1':
538
			case '2':
539
			case '3':
540
			case '4':
541
			case '5':
542
			case '6':
543
			case '7':
544
			case '8':
545
			case '9':
546
10935396
				if ((argno = *p - '0') < argc - 1)
547
10935387
					pbstr(argv[argno + 1]);
548
				break;
549
			case '*':
550
445
				if (argc > 2) {
551
1100
					for (n = argc - 1; n > 2; n--) {
552
114
						pbstr(argv[n]);
553
114
						pushback(COMMA);
554
					}
555
436
					pbstr(argv[2]);
556
436
				}
557
				break;
558
                        case '@':
559
2292
				if (argc > 2) {
560
2328
					for (n = argc - 1; n > 2; n--) {
561
776
						pbstr(rquote);
562
137
						pbstr(argv[n]);
563
137
						pbstr(lquote);
564
137
						pushback(COMMA);
565
					}
566
					pbstr(rquote);
567
639
					pbstr(argv[2]);
568
639
					pbstr(lquote);
569
639
				}
570
                                break;
571
			default:
572
23040
				PUSHBACK(*p);
573
23040
				PUSHBACK('$');
574
11520
				break;
575
			}
576
10951918
			p--;
577
		}
578
175417404
		p--;
579
	}
580
4380977
	if (p == t)		       /* do last character */
581
4389454
		PUSHBACK(*p);
582
4380977
}
583
584
585
/*
586
 * dodefine - install definition in the table
587
 */
588
void
589
dodefine(const char *name, const char *defn)
590
{
591
1998
	if (!*name && !mimic_gnu)
592
		m4errx(1, "null definition.");
593
	else
594
999
		macro_define(name, defn);
595
999
}
596
597
/*
598
 * dodefn - push back a quoted definition of
599
 *      the given name.
600
 */
601
static void
602
dodefn(const char *name)
603
{
604
	struct macro_definition *p;
605
606
108
	if ((p = lookup_macro_definition(name)) != NULL) {
607
45
		if ((p->type & TYPEMASK) == MACRTYPE) {
608
			pbstr(rquote);
609
			pbstr(p->defn);
610
			pbstr(lquote);
611
		} else {
612
45
			pbstr(p->defn);
613
45
			pbstr(BUILTIN_MARKER);
614
		}
615
	}
616
54
}
617
618
/*
619
 * dopushdef - install a definition in the hash table
620
 *      without removing a previous definition. Since
621
 *      each new entry is entered in *front* of the
622
 *      hash bucket, it hides a previous definition from
623
 *      lookup.
624
 */
625
static void
626
dopushdef(const char *name, const char *defn)
627
{
628
	if (!*name && !mimic_gnu)
629
		m4errx(1, "null definition.");
630
	else
631
		macro_pushdef(name, defn);
632
}
633
634
/*
635
 * dump_one_def - dump the specified definition.
636
 */
637
static void
638
dump_one_def(const char *name, struct macro_definition *p)
639
{
640
1566
	if (!traceout)
641
18
		traceout = stderr;
642
783
	if (mimic_gnu) {
643
		if ((p->type & TYPEMASK) == MACRTYPE)
644
			fprintf(traceout, "%s:\t%s\n", name, p->defn);
645
		else {
646
			fprintf(traceout, "%s:\t<%s>\n", name, p->defn);
647
		}
648
	} else
649
783
		fprintf(traceout, "`%s'\t`%s'\n", name, p->defn);
650
783
}
651
652
/*
653
 * dodumpdef - dump the specified definitions in the hash
654
 *      table to stderr. If nothing is specified, the entire
655
 *      hash table is dumped.
656
 */
657
static void
658
dodump(const char *argv[], int argc)
659
{
660
	int n;
661
	struct macro_definition *p;
662
663
36
	if (argc > 2) {
664
		for (n = 2; n < argc; n++)
665
			if ((p = lookup_macro_definition(argv[n])) != NULL)
666
				dump_one_def(argv[n], p);
667
	} else
668
18
		macro_for_all(dump_one_def);
669
18
}
670
671
/*
672
 * dotrace - mark some macros as traced/untraced depending upon on.
673
 */
674
static void
675
dotrace(const char *argv[], int argc, int on)
676
{
677
	int n;
678
679
	if (argc > 2) {
680
		for (n = 2; n < argc; n++)
681
			mark_traced(argv[n], on);
682
	} else
683
		mark_traced(NULL, on);
684
}
685
686
/*
687
 * doifelse - select one of two alternatives - loop.
688
 */
689
static void
690
doifelse(const char *argv[], int argc)
691
{
692
4374680
	cycle {
693

5072347
		if (STREQ(argv[2], argv[3]))
694
1094187
			pbstr(argv[4]);
695
2860906
		else if (argc == 6)
696
1093153
			pbstr(argv[5]);
697
1767753
		else if (argc > 6) {
698
			argv += 3;
699
1767753
			argc -= 3;
700
1767753
			continue;
701
		}
702
		break;
703
	}
704
2187340
}
705
706
/*
707
 * doinclude - include a given file.
708
 */
709
static int
710
doincl(const char *ifile)
711
{
712
54
	if (ilevel + 1 == MAXINP)
713
		m4errx(1, "too many include files.");
714
27
	if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
715
9
		ilevel++;
716
9
		bbase[ilevel] = bufbase = bp;
717
9
		return (1);
718
	} else
719
18
		return (0);
720
27
}
721
722
#ifdef EXTENDED
723
/*
724
 * dopaste - include a given file without any
725
 *           macro processing.
726
 */
727
static int
728
dopaste(const char *pfile)
729
{
730
	FILE *pf;
731
	int c;
732
733
	if ((pf = fopen(pfile, "r")) != NULL) {
734
		if (synch_lines)
735
		    fprintf(active, "#line 1 \"%s\"\n", pfile);
736
		while ((c = getc(pf)) != EOF)
737
			putc(c, active);
738
		(void) fclose(pf);
739
		emit_synchline();
740
		return (1);
741
	} else
742
		return (0);
743
}
744
#endif
745
746
/*
747
 * dochq - change quote characters
748
 */
749
static void
750
dochq(const char *argv[], int ac)
751
{
752
282
	if (ac == 2) {
753
39
		lquote[0] = LQUOTE; lquote[1] = EOS;
754
39
		rquote[0] = RQUOTE; rquote[1] = EOS;
755
39
	} else {
756
102
		strlcpy(lquote, argv[2], sizeof(lquote));
757
102
		if (ac > 3) {
758
84
			strlcpy(rquote, argv[3], sizeof(rquote));
759
84
		} else {
760
18
			rquote[0] = ECOMMT; rquote[1] = EOS;
761
		}
762
	}
763
141
}
764
765
/*
766
 * dochc - change comment characters
767
 */
768
static void
769
dochc(const char *argv[], int argc)
770
{
771
/* XXX Note that there is no difference between no argument and a single
772
 * empty argument.
773
 */
774
166
	if (argc == 2) {
775
38
		scommt[0] = EOS;
776
38
		ecommt[0] = EOS;
777
38
	} else {
778
45
		strlcpy(scommt, argv[2], sizeof(scommt));
779
45
		if (argc == 3) {
780
27
			ecommt[0] = ECOMMT; ecommt[1] = EOS;
781
27
		} else {
782
18
			strlcpy(ecommt, argv[3], sizeof(ecommt));
783
		}
784
	}
785
83
}
786
787
/*
788
 * dom4wrap - expand text at EOF
789
 */
790
static void
791
dom4wrap(const char *text)
792
{
793
180
	if (wrapindex >= maxwraps) {
794
72
		if (maxwraps == 0)
795
			maxwraps = 16;
796
		else
797
36
			maxwraps *= 2;
798
36
		m4wraps = xreallocarray(m4wraps, maxwraps, sizeof(*m4wraps),
799
		   "too many m4wraps");
800
36
	}
801
90
	m4wraps[wrapindex++] = xstrdup(text);
802
90
}
803
804
/*
805
 * dodivert - divert the output to a temporary file
806
 */
807
static void
808
dodiv(int n)
809
{
810
	int fd;
811
812
	oindex = n;
813
	if (n >= maxout) {
814
		if (mimic_gnu)
815
			resizedivs(n + 10);
816
		else
817
			n = 0;		/* bitbucket */
818
	}
819
820
	if (n < 0)
821
		n = 0;		       /* bitbucket */
822
	if (outfile[n] == NULL) {
823
		char fname[] = _PATH_DIVNAME;
824
825
		if ((fd = mkstemp(fname)) < 0 ||
826
		    unlink(fname) == -1 ||
827
		    (outfile[n] = fdopen(fd, "w+")) == NULL)
828
			err(1, "%s: cannot divert", fname);
829
	}
830
	active = outfile[n];
831
}
832
833
/*
834
 * doundivert - undivert a specified output, or all
835
 *              other outputs, in numerical order.
836
 */
837
static void
838
doundiv(const char *argv[], int argc)
839
{
840
	int ind;
841
	int n;
842
843
	if (argc > 2) {
844
		for (ind = 2; ind < argc; ind++) {
845
			const char *errstr;
846
			n = strtonum(argv[ind], 1, INT_MAX, &errstr);
847
			if (errstr) {
848
				if (errno == EINVAL && mimic_gnu)
849
					getdivfile(argv[ind]);
850
			} else {
851
				if (n < maxout && outfile[n] != NULL)
852
					getdiv(n);
853
			}
854
		}
855
	}
856
	else
857
		for (n = 1; n < maxout; n++)
858
			if (outfile[n] != NULL)
859
				getdiv(n);
860
}
861
862
/*
863
 * dosub - select substring
864
 */
865
static void
866
dosub(const char *argv[], int argc)
867
{
868
	const char *ap, *fc, *k;
869
	int nc;
870
871
	ap = argv[2];		       /* target string */
872
#ifdef EXPR
873
	fc = ap + expr(argv[3]);       /* first char */
874
#else
875
	fc = ap + atoi(argv[3]);       /* first char */
876
#endif
877
	nc = strlen(fc);
878
	if (argc >= 5)
879
#ifdef EXPR
880
		nc = min(nc, expr(argv[4]));
881
#else
882
		nc = min(nc, atoi(argv[4]));
883
#endif
884
	if (fc >= ap && fc < ap + strlen(ap))
885
		for (k = fc + nc - 1; k >= fc; k--)
886
			pushback(*k);
887
}
888
889
/*
890
 * map:
891
 * map every character of s1 that is specified in from
892
 * into s3 and replace in s. (source s1 remains untouched)
893
 *
894
 * This is derived from the a standard implementation of map(s,from,to)
895
 * function of ICON language. Within mapvec, we replace every character
896
 * of "from" with the corresponding character in "to".
897
 * If "to" is shorter than "from", than the corresponding entries are null,
898
 * which means that those characters dissapear altogether.
899
 */
900
static void
901
map(char *dest, const char *src, const char *from, const char *to)
902
{
903
	const char *tmp;
904
	unsigned char sch, dch;
905
	static char frombis[257];
906
	static char tobis[257];
907
	int i;
908
234
	char seen[256];
909
	static unsigned char mapvec[256] = {
910
	    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
911
	    19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
912
	    36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
913
	    53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
914
	    70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
915
	    87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
916
	    103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
917
	    116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
918
	    129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
919
	    142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
920
	    155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
921
	    168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
922
	    181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
923
	    194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
924
	    207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
925
	    220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
926
	    233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
927
	    246, 247, 248, 249, 250, 251, 252, 253, 254, 255
928
	};
929
930
117
	if (*src) {
931
117
		if (mimic_gnu) {
932
			/*
933
			 * expand character ranges on the fly
934
			 */
935
54
			from = handledash(frombis, frombis + 256, from);
936
54
			to = handledash(tobis, tobis + 256, to);
937
54
		}
938
		tmp = from;
939
	/*
940
	 * create a mapping between "from" and
941
	 * "to"
942
	 */
943
60138
		for (i = 0; i < 256; i++)
944
29952
			seen[i] = 0;
945
1341
		while (*from) {
946
1224
			if (!seen[(unsigned char)(*from)]) {
947
1215
				mapvec[(unsigned char)(*from)] = (unsigned char)(*to);
948
1215
				seen[(unsigned char)(*from)] = 1;
949
1215
			}
950
1224
			from++;
951
1224
			if (*to)
952
1224
				to++;
953
		}
954
955
1557
		while (*src) {
956
1440
			sch = (unsigned char)(*src++);
957
1440
			dch = mapvec[sch];
958
1440
			if ((*dest = (char)dch))
959
1440
				dest++;
960
		}
961
	/*
962
	 * restore all the changed characters
963
	 */
964
2565
		while (*tmp) {
965
1224
			mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
966
1224
			tmp++;
967
		}
968
	}
969
117
	*dest = '\0';
970
117
}
971
972
973
/*
974
 * handledash:
975
 *  use buffer to copy the src string, expanding character ranges
976
 * on the way.
977
 */
978
static const char *
979
handledash(char *buffer, char *end, const char *src)
980
{
981
	char *p;
982
983
	p = buffer;
984
1188
	while(*src) {
985

900
		if (src[1] == '-' && src[2]) {
986
			unsigned char i;
987
36
			if ((unsigned char)src[0] <= (unsigned char)src[2]) {
988
1332
				for (i = (unsigned char)src[0];
989
1332
				    i <= (unsigned char)src[2]; i++) {
990
648
					*p++ = i;
991
648
					if (p == end) {
992
						*p = '\0';
993
						return buffer;
994
					}
995
				}
996
			} else {
997
				for (i = (unsigned char)src[0];
998
				    i >= (unsigned char)src[2]; i--) {
999
					*p++ = i;
1000
					if (p == end) {
1001
						*p = '\0';
1002
						return buffer;
1003
					}
1004
				}
1005
			}
1006
36
			src += 3;
1007
36
		} else
1008
828
			*p++ = *src++;
1009
864
		if (p == end)
1010
			break;
1011
	}
1012
108
	*p = '\0';
1013
108
	return buffer;
1014
108
}