GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/m4/eval.c Lines: 85 345 24.6 %
Date: 2016-12-06 Branches: 59 339 17.4 %

Line Branch Exec Source
1
/*	$OpenBSD: eval.c,v 1.74 2015/02/05 12:59:57 millert 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
6934
{
101
6934
	size_t mark = SIZE_MAX;
102
103
6934
	expansion_id++;
104
6934
	if (td & RECDEF)
105
		m4errx(1, "expanding recursive definition for %s.", argv[1]);
106
6934
	if (is_traced)
107
		mark = trace(argv, argc, infile+ilevel);
108
6934
	if (td == MACRTYPE)
109
4510
		expand_macro(argv, argc);
110
	else
111
2424
		expand_builtin(argv, argc, td);
112
6934
	if (mark != SIZE_MAX)
113
		finish_trace(mark);
114
6934
}
115
116
/*
117
 * expand_builtin - evaluate built-in macros.
118
 */
119
void
120
expand_builtin(const char *argv[], int argc, int td)
121
2424
{
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
2424
	ac = argc;
142
143

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











2424
	switch (td & TYPEMASK) {
147
148
	case DEFITYPE:
149
343
		if (argc > 2)
150
343
			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
		dodump(argv, argc);
160
		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
		const char *errstr;
179
180
		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
		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
		if (argc > 2)
193
			pbnumbase(expr(argv[2]), base, maxdigits);
194
		break;
195
	}
196
197
	case IFELTYPE:
198
1170
		if (argc > 4)
199
1170
			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
660
		if (argc > 3) {
209
660
			if (lookup_macro_definition(argv[2]) != NULL)
210
216
				pbstr(argv[3]);
211
444
			else if (argc > 4)
212
294
				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
		if (argc > 2)
239
			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
		if (argc > 2)
263
			doesyscmd(argv[2]);
264
		break;
265
	case INCLTYPE:
266
		if (argc > 2) {
267
			if (!doincl(argv[2])) {
268
				if (mimic_gnu) {
269
					warn("%s at line %lu: include(%s)",
270
					    CURRENT_NAME, CURRENT_LINE, argv[2]);
271
					exit_code = 1;
272
				} else
273
					err(1, "%s at line %lu: include(%s)",
274
					    CURRENT_NAME, CURRENT_LINE, argv[2]);
275
			}
276
		}
277
		break;
278
279
	case SINCTYPE:
280
		if (argc > 2)
281
			(void) doincl(argv[2]);
282
		break;
283
#ifdef EXTENDED
284
	case PASTTYPE:
285
		if (argc > 2)
286
			if (!dopaste(argv[2]))
287
				err(1, "%s at line %lu: paste(%s)",
288
				    CURRENT_NAME, CURRENT_LINE, argv[2]);
289
		break;
290
291
	case SPASTYPE:
292
		if (argc > 2)
293
			(void) dopaste(argv[2]);
294
		break;
295
	case FORMATTYPE:
296
		doformat(argv, argc);
297
		break;
298
#endif
299
	case CHNQTYPE:
300
30
		dochq(argv, ac);
301
30
		break;
302
303
	case CHNCTYPE:
304
10
		dochc(argv, argc);
305
10
		break;
306
307
	case SUBSTYPE:
308
	/*
309
	 * dosub - select substring
310
	 *
311
	 */
312
		if (argc > 3)
313
			dosub(argv, argc);
314
		break;
315
316
	case SHIFTYPE:
317
	/*
318
	 * doshift - push back all arguments
319
	 * except the first one (i.e. skip
320
	 * argv[2])
321
	 */
322
		if (argc > 3) {
323
			for (n = argc - 1; n > 3; n--) {
324
				pbstr(rquote);
325
				pbstr(argv[n]);
326
				pbstr(lquote);
327
				pushback(COMMA);
328
			}
329
			pbstr(rquote);
330
			pbstr(argv[3]);
331
			pbstr(lquote);
332
		}
333
		break;
334
335
	case DIVRTYPE:
336
		if (argc > 2 && (n = atoi(argv[2])) != 0)
337
			dodiv(n);
338
		else {
339
			active = stdout;
340
			oindex = 0;
341
		}
342
		break;
343
344
	case UNDVTYPE:
345
		doundiv(argv, argc);
346
		break;
347
348
	case DIVNTYPE:
349
	/*
350
	 * dodivnum - return the number of
351
	 * current output diversion
352
	 */
353
		pbnum(oindex);
354
		break;
355
356
	case UNDFTYPE:
357
	/*
358
	 * doundefine - undefine a previously
359
	 * defined macro(s) or m4 keyword(s).
360
	 */
361
		if (argc > 2)
362
			for (n = 2; n < argc; n++)
363
				macro_undefine(argv[n]);
364
		break;
365
366
	case POPDTYPE:
367
	/*
368
	 * dopopdef - remove the topmost
369
	 * definitions of macro(s) or m4
370
	 * keyword(s).
371
	 */
372
		if (argc > 2)
373
			for (n = 2; n < argc; n++)
374
				macro_popdef(argv[n]);
375
		break;
376
377
	case MKTMTYPE:
378
	/*
379
	 * dotemp - create a temporary file
380
	 */
381
		if (argc > 2) {
382
			int fd;
383
			char *temp;
384
385
			temp = xstrdup(argv[2]);
386
387
			fd = mkstemp(temp);
388
			if (fd == -1)
389
				err(1,
390
	    "%s at line %lu: couldn't make temp file %s",
391
	    CURRENT_NAME, CURRENT_LINE, argv[2]);
392
			close(fd);
393
			pbstr(temp);
394
			free(temp);
395
		}
396
		break;
397
398
	case TRNLTYPE:
399
	/*
400
	 * dotranslit - replace all characters in
401
	 * the source string that appears in the
402
	 * "from" string with the corresponding
403
	 * characters in the "to" string.
404
	 */
405
		if (argc > 3) {
406
			char *temp;
407
408
			temp = xalloc(strlen(argv[2])+1, NULL);
409
			if (argc > 4)
410
				map(temp, argv[2], argv[3], argv[4]);
411
			else
412
				map(temp, argv[2], argv[3], null);
413
			pbstr(temp);
414
			free(temp);
415
		} else if (argc > 2)
416
			pbstr(argv[2]);
417
		break;
418
419
	case INDXTYPE:
420
	/*
421
	 * doindex - find the index of the second
422
	 * argument string in the first argument
423
	 * string. -1 if not present.
424
	 */
425
		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
426
		break;
427
428
	case ERRPTYPE:
429
	/*
430
	 * doerrp - print the arguments to stderr
431
	 * file
432
	 */
433
		if (argc > 2) {
434
			for (n = 2; n < argc; n++)
435
				fprintf(stderr, "%s ", argv[n]);
436
			fprintf(stderr, "\n");
437
		}
438
		break;
439
440
	case DNLNTYPE:
441
	/*
442
	 * dodnl - eat-up-to and including
443
	 * newline
444
	 */
445

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

3599
			switch (*p) {
528
529
			case '#':
530
1165
				pbnum(argc - 2);
531
1165
				break;
532
			case '0':
533
			case '1':
534
			case '2':
535
			case '3':
536
			case '4':
537
			case '5':
538
			case '6':
539
			case '7':
540
			case '8':
541
			case '9':
542
1061
				if ((argno = *p - '0') < argc - 1)
543
1061
					pbstr(argv[argno + 1]);
544
				break;
545
			case '*':
546
208
				if (argc > 2) {
547
246
					for (n = argc - 1; n > 2; n--) {
548
38
						pbstr(argv[n]);
549
38
						pushback(COMMA);
550
					}
551
208
					pbstr(argv[2]);
552
				}
553
				break;
554
                        case '@':
555
1165
				if (argc > 2) {
556
372
					for (n = argc - 1; n > 2; n--) {
557
54
						pbstr(rquote);
558
54
						pbstr(argv[n]);
559
54
						pbstr(lquote);
560
54
						pushback(COMMA);
561
					}
562
318
					pbstr(rquote);
563
318
					pbstr(argv[2]);
564
318
					pbstr(lquote);
565
				}
566
                                break;
567
			default:
568
				PUSHBACK(*p);
569
				PUSHBACK('$');
570
				break;
571
			}
572
3599
			p--;
573
		}
574
62688
		p--;
575
	}
576
4510
	if (p == t)		       /* do last character */
577
3938
		PUSHBACK(*p);
578
4510
}
579
580
581
/*
582
 * dodefine - install definition in the table
583
 */
584
void
585
dodefine(const char *name, const char *defn)
586
343
{
587

343
	if (!*name && !mimic_gnu)
588
		m4errx(1, "null definition.");
589
	else
590
343
		macro_define(name, defn);
591
343
}
592
593
/*
594
 * dodefn - push back a quoted definition of
595
 *      the given name.
596
 */
597
static void
598
dodefn(const char *name)
599
{
600
	struct macro_definition *p;
601
602
	if ((p = lookup_macro_definition(name)) != NULL) {
603
		if ((p->type & TYPEMASK) == MACRTYPE) {
604
			pbstr(rquote);
605
			pbstr(p->defn);
606
			pbstr(lquote);
607
		} else {
608
			pbstr(p->defn);
609
			pbstr(BUILTIN_MARKER);
610
		}
611
	}
612
}
613
614
/*
615
 * dopushdef - install a definition in the hash table
616
 *      without removing a previous definition. Since
617
 *      each new entry is entered in *front* of the
618
 *      hash bucket, it hides a previous definition from
619
 *      lookup.
620
 */
621
static void
622
dopushdef(const char *name, const char *defn)
623
{
624
	if (!*name && !mimic_gnu)
625
		m4errx(1, "null definition.");
626
	else
627
		macro_pushdef(name, defn);
628
}
629
630
/*
631
 * dump_one_def - dump the specified definition.
632
 */
633
static void
634
dump_one_def(const char *name, struct macro_definition *p)
635
{
636
	if (!traceout)
637
		traceout = stderr;
638
	if (mimic_gnu) {
639
		if ((p->type & TYPEMASK) == MACRTYPE)
640
			fprintf(traceout, "%s:\t%s\n", name, p->defn);
641
		else {
642
			fprintf(traceout, "%s:\t<%s>\n", name, p->defn);
643
		}
644
	} else
645
		fprintf(traceout, "`%s'\t`%s'\n", name, p->defn);
646
}
647
648
/*
649
 * dodumpdef - dump the specified definitions in the hash
650
 *      table to stderr. If nothing is specified, the entire
651
 *      hash table is dumped.
652
 */
653
static void
654
dodump(const char *argv[], int argc)
655
{
656
	int n;
657
	struct macro_definition *p;
658
659
	if (argc > 2) {
660
		for (n = 2; n < argc; n++)
661
			if ((p = lookup_macro_definition(argv[n])) != NULL)
662
				dump_one_def(argv[n], p);
663
	} else
664
		macro_for_all(dump_one_def);
665
}
666
667
/*
668
 * dotrace - mark some macros as traced/untraced depending upon on.
669
 */
670
static void
671
dotrace(const char *argv[], int argc, int on)
672
{
673
	int n;
674
675
	if (argc > 2) {
676
		for (n = 2; n < argc; n++)
677
			mark_traced(argv[n], on);
678
	} else
679
		mark_traced(NULL, on);
680
}
681
682
/*
683
 * doifelse - select one of two alternatives - loop.
684
 */
685
static void
686
doifelse(const char *argv[], int argc)
687
1170
{
688
	cycle {
689

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