GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/m4/eval.c Lines: 203 373 54.4 %
Date: 2017-11-13 Branches: 142 340 41.8 %

Line Branch Exec Source
1
/*	$OpenBSD: eval.c,v 1.77 2017/11/11 12:55:59 espie 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
15796356
	expansion_id++;
104
7898178
	if (td & RECDEF)
105
		m4errx(1, "expanding recursive definition for %s.", argv[1]);
106
7898178
	if (is_traced)
107
		mark = trace(argv, argc, infile+ilevel);
108
7898178
	if (td == MACRTYPE)
109
2432422
		expand_macro(argv, argc);
110
	else
111
5465756
		expand_builtin(argv, argc, td);
112
7898173
	if (mark != SIZE_MAX)
113
		finish_trace(mark);
114
7898173
}
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
10931512
	const char *errstr;
124
	int ac;
125
	static int sysval = 0;
126
127
#ifdef DEBUG
128
	printf("argc = %d\n", argc);
129
	for (n = 0; n < argc; n++)
130
		printf("argv[%d] = %s\n", n, argv[n]);
131
	fflush(stdout);
132
#endif
133
134
 /*
135
  * if argc == 3 and argv[2] is null, then we
136
  * have macro-or-builtin() type call. We adjust
137
  * argc to avoid further checking..
138
  */
139
 /* we keep the initial value for those built-ins that differentiate
140
  * between builtin() and builtin.
141
  */
142
	ac = argc;
143
144

7286897
	if (argc == 3 && !*(argv[2]) && !mimic_gnu)
145
20
		argc--;
146
147











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

9788244
		while ((c = gpbc()) != '\n' && c != EOF)
467
			;
468
		break;
469
470
	case M4WRTYPE:
471
	/*
472
	 * dom4wrap - set up for
473
	 * wrap-up/wind-down activity
474
	 */
475
50
		if (argc > 2)
476
50
			dom4wrap(argv[2]);
477
		break;
478
479
	case EXITTYPE:
480
	/*
481
	 * doexit - immediate exit from m4.
482
	 */
483
		killdiv();
484
		exit((argc > 2) ? atoi(argv[2]) : 0);
485
		break;
486
487
	case DEFNTYPE:
488
30
		if (argc > 2)
489
120
			for (n = 2; n < argc; n++)
490
30
				dodefn(argv[n]);
491
		break;
492
493
	case INDIRTYPE:	/* Indirect call */
494
10
		if (argc > 2)
495
10
			doindir(argv, argc);
496
		break;
497
498
	case BUILTINTYPE: /* Builtins only */
499
		if (argc > 2)
500
			dobuiltin(argv, argc);
501
		break;
502
503
	case PATSTYPE:
504
60
		if (argc > 2)
505
60
			dopatsubst(argv, argc);
506
		break;
507
	case REGEXPTYPE:
508
		if (argc > 2)
509
			doregexp(argv, argc);
510
		break;
511
	case LINETYPE:
512
		doprintlineno(infile+ilevel);
513
		break;
514
	case FILENAMETYPE:
515
5
		doprintfilename(infile+ilevel);
516
5
		break;
517
	case SELFTYPE:
518
		pbstr(rquote);
519
		pbstr(argv[1]);
520
		pbstr(lquote);
521
		break;
522
	default:
523
		m4errx(1, "eval: major botch.");
524
		break;
525
	}
526
5465751
}
527
528
/*
529
 * expand_macro - user-defined macro expansion
530
 */
531
void
532
expand_macro(const char *argv[], int argc)
533
{
534
	const char *t;
535
	const char *p;
536
	int n;
537
	int argno;
538
539
4864844
	t = argv[0];		       /* defn string as a whole */
540
	p = t;
541
214336262
	while (*p)
542
104735709
		p++;
543
2432422
	p--;			       /* last character of defn */
544
199733780
	while (p > t) {
545
97434468
		if (*(p - 1) != ARGFLAG)
546
182702484
			PUSHBACK(*p);
547
		else {
548



6083226
			switch (*p) {
549
550
			case '#':
551
866
				pbnum(argc - 2);
552
866
				break;
553
			case '0':
554
			case '1':
555
			case '2':
556
			case '3':
557
			case '4':
558
			case '5':
559
			case '6':
560
			case '7':
561
			case '8':
562
			case '9':
563
6074896
				if ((argno = *p - '0') < argc - 1)
564
6074891
					pbstr(argv[argno + 1]);
565
				break;
566
			case '*':
567
183
				if (argc > 2) {
568
460
					for (n = argc - 1; n > 2; n--) {
569
52
						pbstr(argv[n]);
570
52
						pushback(COMMA);
571
					}
572
178
					pbstr(argv[2]);
573
178
				}
574
				break;
575
                        case '@':
576
881
				if (argc > 2) {
577
936
					for (n = argc - 1; n > 2; n--) {
578
312
						pbstr(rquote);
579
58
						pbstr(argv[n]);
580
58
						pbstr(lquote);
581
58
						pushback(COMMA);
582
					}
583
					pbstr(rquote);
584
254
					pbstr(argv[2]);
585
254
					pbstr(lquote);
586
254
				}
587
                                break;
588
			default:
589
12800
				PUSHBACK(*p);
590
12800
				PUSHBACK('$');
591
6400
				break;
592
			}
593
6083226
			p--;
594
		}
595
97434468
		p--;
596
	}
597
2432422
	if (p == t)		       /* do last character */
598
2436030
		PUSHBACK(*p);
599
2432422
}
600
601
602
/*
603
 * dodefine - install definition in the table
604
 */
605
void
606
dodefine(const char *name, const char *defn)
607
{
608
900
	if (!*name && !mimic_gnu)
609
		m4errx(1, "null definition.");
610
	else
611
450
		macro_define(name, defn);
612
450
}
613
614
/*
615
 * dodefn - push back a quoted definition of
616
 *      the given name.
617
 */
618
static void
619
dodefn(const char *name)
620
{
621
	struct macro_definition *p;
622
623
60
	if ((p = lookup_macro_definition(name)) != NULL) {
624
25
		if ((p->type & TYPEMASK) == MACRTYPE) {
625
			pbstr(rquote);
626
			pbstr(p->defn);
627
			pbstr(lquote);
628
		} else {
629
25
			pbstr(p->defn);
630
25
			pbstr(BUILTIN_MARKER);
631
		}
632
	}
633
30
}
634
635
/*
636
 * dopushdef - install a definition in the hash table
637
 *      without removing a previous definition. Since
638
 *      each new entry is entered in *front* of the
639
 *      hash bucket, it hides a previous definition from
640
 *      lookup.
641
 */
642
static void
643
dopushdef(const char *name, const char *defn)
644
{
645
	if (!*name && !mimic_gnu)
646
		m4errx(1, "null definition.");
647
	else
648
		macro_pushdef(name, defn);
649
}
650
651
/*
652
 * dump_one_def - dump the specified definition.
653
 */
654
static void
655
dump_one_def(const char *name, struct macro_definition *p)
656
{
657
870
	if (!traceout)
658
10
		traceout = stderr;
659
435
	if (mimic_gnu) {
660
		if ((p->type & TYPEMASK) == MACRTYPE)
661
			fprintf(traceout, "%s:\t%s\n", name, p->defn);
662
		else {
663
			fprintf(traceout, "%s:\t<%s>\n", name, p->defn);
664
		}
665
	} else
666
435
		fprintf(traceout, "`%s'\t`%s'\n", name, p->defn);
667
435
}
668
669
/*
670
 * dodumpdef - dump the specified definitions in the hash
671
 *      table to stderr. If nothing is specified, the entire
672
 *      hash table is dumped.
673
 */
674
static void
675
dodump(const char *argv[], int argc)
676
{
677
	int n;
678
	struct macro_definition *p;
679
680
20
	if (argc > 2) {
681
		for (n = 2; n < argc; n++)
682
			if ((p = lookup_macro_definition(argv[n])) != NULL)
683
				dump_one_def(argv[n], p);
684
	} else
685
10
		macro_for_all(dump_one_def);
686
10
}
687
688
/*
689
 * dotrace - mark some macros as traced/untraced depending upon on.
690
 */
691
static void
692
dotrace(const char *argv[], int argc, int on)
693
{
694
	int n;
695
696
	if (argc > 2) {
697
		for (n = 2; n < argc; n++)
698
			mark_traced(argv[n], on);
699
	} else
700
		mark_traced(NULL, on);
701
}
702
703
/*
704
 * doifelse - select one of two alternatives - loop.
705
 */
706
static void
707
doifelse(const char *argv[], int argc)
708
{
709
5608580
	while (argc > 4) {
710

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

500
		if (src[1] == '-' && src[2]) {
1003
			unsigned char i;
1004
20
			if ((unsigned char)src[0] <= (unsigned char)src[2]) {
1005
760
				for (i = (unsigned char)src[0];
1006
740
				    i <= (unsigned char)src[2]; i++) {
1007
360
					*p++ = i;
1008
360
					if (p == end) {
1009
						*p = '\0';
1010
						return buffer;
1011
					}
1012
				}
1013
			} else {
1014
				for (i = (unsigned char)src[0];
1015
				    i >= (unsigned char)src[2]; i--) {
1016
					*p++ = i;
1017
					if (p == end) {
1018
						*p = '\0';
1019
						return buffer;
1020
					}
1021
				}
1022
			}
1023
20
			src += 3;
1024
20
		} else
1025
460
			*p++ = *src++;
1026
480
		if (p == end)
1027
			break;
1028
	}
1029
60
	*p = '\0';
1030
60
	return buffer;
1031
60
}