195967Speter/*	$OpenBSD: eval.c,v 1.70 2012/04/12 17:00:11 espie Exp $	*/
2299389Sjkim/*	$NetBSD: eval.c,v 1.7 1996/11/10 21:21:29 pk Exp $	*/
395967Speter
4299389Sjkim/*
5299389Sjkim * Copyright (c) 1989, 1993
695967Speter *	The Regents of the University of California.  All rights reserved.
795967Speter *
895967Speter * This code is derived from software contributed to Berkeley by
9305150Sjkim * Ozan Yigit at York University.
10106538Sobrien *
11238405Sjkim * Redistribution and use in source and binary forms, with or without
12238405Sjkim * modification, are permitted provided that the following conditions
13238405Sjkim * are met:
14238405Sjkim * 1. Redistributions of source code must retain the above copyright
15290207Sjkim *    notice, this list of conditions and the following disclaimer.
16238405Sjkim * 2. Redistributions in binary form must reproduce the above copyright
17238405Sjkim *    notice, this list of conditions and the following disclaimer in the
18238405Sjkim *    documentation and/or other materials provided with the distribution.
19238405Sjkim * 3. Neither the name of the University nor the names of its contributors
20238405Sjkim *    may be used to endorse or promote products derived from this software
21238405Sjkim *    without specific prior written permission.
22238405Sjkim *
23290207Sjkim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24290207Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25238405Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26238405Sjkim * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27238405Sjkim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28290207Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29290207Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30238405Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31238405Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32238405Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33238405Sjkim * SUCH DAMAGE.
34290207Sjkim */
35290207Sjkim
36290207Sjkim#include <sys/cdefs.h>
37238405Sjkim__FBSDID("$FreeBSD$");
38238405Sjkim
39238405Sjkim
40238405Sjkim/*
41290207Sjkim * eval.c
42238405Sjkim * Facility: m4 macro processor
43238405Sjkim * by: oz
44238405Sjkim */
45238405Sjkim
46238405Sjkim#include <sys/types.h>
47299479Sjkim#include <err.h>
48238405Sjkim#include <errno.h>
49238405Sjkim#include <limits.h>
50238405Sjkim#include <unistd.h>
51238405Sjkim#include <stdint.h>
52299479Sjkim#include <stdio.h>
53299479Sjkim#include <stdlib.h>
54238405Sjkim#include <stddef.h>
55299479Sjkim#include <string.h>
56299479Sjkim#include <fcntl.h>
57299479Sjkim#include "mdef.h"
58299479Sjkim#include "stdd.h"
59299479Sjkim#include "extern.h"
60299479Sjkim#include "pathnames.h"
61238405Sjkim
62238405Sjkimstatic void	dodefn(const char *);
63299479Sjkimstatic void	dopushdef(const char *, const char *);
64299479Sjkimstatic void	dodump(const char *[], int);
65238405Sjkimstatic void	dotrace(const char *[], int, int);
66299479Sjkimstatic void	doifelse(const char *[], int);
67305153Sjkimstatic int	doincl(const char *);
68305153Sjkimstatic int	dopaste(const char *);
69299480Sjkimstatic void	dochq(const char *[], int);
70238405Sjkimstatic void	dochc(const char *[], int);
71299479Sjkimstatic void	dom4wrap(const char *);
72299480Sjkimstatic void	dodiv(int);
73299479Sjkimstatic void	doundiv(const char *[], int);
74299479Sjkimstatic void	dosub(const char *[], int);
75299479Sjkimstatic void	map(char *, const char *, const char *, const char *);
76305153Sjkimstatic const char *handledash(char *, char *, const char *);
77305153Sjkimstatic void	expand_builtin(const char *[], int, int);
78299479Sjkimstatic void	expand_macro(const char *[], int);
79299479Sjkimstatic void	dump_one_def(const char *, struct macro_definition *);
80238405Sjkim
81305152Sjkimunsigned long	expansion_id;
82305152Sjkim
83305152Sjkim/*
84305152Sjkim * eval - eval all macros and builtins calls
85305152Sjkim *	  argc - number of elements in argv.
86305152Sjkim *	  argv - element vector :
87305152Sjkim *			argv[0] = definition of a user
88305152Sjkim *				  macro or NULL if built-in.
89305152Sjkim *			argv[1] = name of the macro or
90305152Sjkim *				  built-in.
91305152Sjkim *			argv[2] = parameters to user-defined
92305152Sjkim *			   .	  macro or built-in.
93305152Sjkim *			   .
94305152Sjkim *
95305152Sjkim * A call in the form of macro-or-builtin() will result in:
96305152Sjkim *			argv[0] = nullstr
97305152Sjkim *			argv[1] = macro-or-builtin
98305152Sjkim *			argv[2] = nullstr
99305152Sjkim *
100305152Sjkim * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin
101305152Sjkim */
102305152Sjkimvoid
103305152Sjkimeval(const char *argv[], int argc, int td, int is_traced)
104305152Sjkim{
105305152Sjkim	size_t mark = SIZE_MAX;
106305152Sjkim
107305152Sjkim	expansion_id++;
108305152Sjkim	if (td & RECDEF)
109305152Sjkim		m4errx(1, "expanding recursive definition for %s.", argv[1]);
110305152Sjkim	if (is_traced)
111305153Sjkim		mark = trace(argv, argc, infile+ilevel);
112305153Sjkim	if (td == MACRTYPE)
113305152Sjkim		expand_macro(argv, argc);
114305152Sjkim	else
115305152Sjkim		expand_builtin(argv, argc, td);
116305152Sjkim	if (mark != SIZE_MAX)
117305153Sjkim		finish_trace(mark);
118305153Sjkim}
119305152Sjkim
120305152Sjkim/*
121305150Sjkim * expand_builtin - evaluate built-in macros.
122238405Sjkim */
123238405Sjkimvoid
124238405Sjkimexpand_builtin(const char *argv[], int argc, int td)
125238405Sjkim{
126238405Sjkim	int c, n;
127238405Sjkim	int ac;
128238405Sjkim	static int sysval = 0;
129238405Sjkim
130238405Sjkim#ifdef DEBUG
131238405Sjkim	printf("argc = %d\n", argc);
132238405Sjkim	for (n = 0; n < argc; n++)
133238405Sjkim		printf("argv[%d] = %s\n", n, argv[n]);
134238405Sjkim	fflush(stdout);
135238405Sjkim#endif
136238405Sjkim
137142429Snectar /*
13895967Speter  * if argc == 3 and argv[2] is null, then we
139238405Sjkim  * have macro-or-builtin() type call. We adjust
140238405Sjkim  * argc to avoid further checking..
141238405Sjkim  */
14295967Speter /* we keep the initial value for those built-ins that differentiate
143238405Sjkim  * between builtin() and builtin.
14495967Speter  */
14595967Speter	ac = argc;
146238405Sjkim
14795967Speter	if (argc == 3 && !*(argv[2]) && !mimic_gnu)
148238405Sjkim		argc--;
149238405Sjkim
150238405Sjkim	switch (td & TYPEMASK) {
15195967Speter
152238405Sjkim	case DEFITYPE:
15395967Speter		if (argc > 2)
15495967Speter			dodefine(argv[2], (argc > 3) ? argv[3] : null);
15595967Speter		break;
15695967Speter
157238405Sjkim	case PUSDTYPE:
158238405Sjkim		if (argc > 2)
159238405Sjkim			dopushdef(argv[2], (argc > 3) ? argv[3] : null);
16095967Speter		break;
16195967Speter
16295967Speter	case DUMPTYPE:
16395967Speter		dodump(argv, argc);
16495967Speter		break;
16595967Speter
16695967Speter	case TRACEONTYPE:
16795967Speter		dotrace(argv, argc, 1);
16895967Speter		break;
16995967Speter
170238405Sjkim	case TRACEOFFTYPE:
17195967Speter		dotrace(argv, argc, 0);
172238405Sjkim		break;
173238405Sjkim
174238405Sjkim	case EXPRTYPE:
175238405Sjkim	/*
176238405Sjkim	 * doexpr - evaluate arithmetic
177238405Sjkim	 * expression
178299479Sjkim	 */
17995967Speter	{
18095967Speter		int base = 10;
18195967Speter		int maxdigits = 0;
182299479Sjkim		const char *errstr;
183238405Sjkim
18495967Speter		if (argc > 3) {
185299389Sjkim			base = strtonum(argv[3], 2, 36, &errstr);
186305153Sjkim			if (errstr) {
187305153Sjkim				m4errx(1, "expr: base %s invalid.", argv[3]);
188299389Sjkim			}
189299480Sjkim		}
190299389Sjkim		if (argc > 4) {
191299480Sjkim			maxdigits = strtonum(argv[4], 0, INT_MAX, &errstr);
192299389Sjkim			if (errstr) {
193299389Sjkim				m4errx(1, "expr: maxdigits %s invalid.", argv[4]);
194238405Sjkim			}
19595967Speter		}
19695967Speter		if (argc > 2)
197			pbnumbase(expr(argv[2]), base, maxdigits);
198		break;
199	}
200
201	case IFELTYPE:
202		if (argc > 4)
203			doifelse(argv, argc);
204		break;
205
206	case IFDFTYPE:
207	/*
208	 * doifdef - select one of two
209	 * alternatives based on the existence of
210	 * another definition
211	 */
212		if (argc > 3) {
213			if (lookup_macro_definition(argv[2]) != NULL)
214				pbstr(argv[3]);
215			else if (argc > 4)
216				pbstr(argv[4]);
217		}
218		break;
219
220	case LENGTYPE:
221	/*
222	 * dolen - find the length of the
223	 * argument
224	 */
225		pbnum((argc > 2) ? strlen(argv[2]) : 0);
226		break;
227
228	case INCRTYPE:
229	/*
230	 * doincr - increment the value of the
231	 * argument
232	 */
233		if (argc > 2)
234			pbnum(atoi(argv[2]) + 1);
235		break;
236
237	case DECRTYPE:
238	/*
239	 * dodecr - decrement the value of the
240	 * argument
241	 */
242		if (argc > 2)
243			pbnum(atoi(argv[2]) - 1);
244		break;
245
246	case SYSCTYPE:
247	/*
248	 * dosys - execute system command
249	 */
250		if (argc > 2) {
251			fflush(stdout);
252			sysval = system(argv[2]);
253		}
254		break;
255
256	case SYSVTYPE:
257	/*
258	 * dosysval - return value of the last
259	 * system call.
260	 *
261	 */
262		pbnum(sysval);
263		break;
264
265	case ESYSCMDTYPE:
266		if (argc > 2)
267			doesyscmd(argv[2]);
268		break;
269	case INCLTYPE:
270		if (argc > 2)
271			if (!doincl(argv[2])) {
272				if (mimic_gnu) {
273					warn("%s at line %lu: include(%s)",
274					    CURRENT_NAME, CURRENT_LINE, argv[2]);
275					exit_code = 1;
276				} else
277					err(1, "%s at line %lu: include(%s)",
278					    CURRENT_NAME, CURRENT_LINE, argv[2]);
279			}
280		break;
281
282	case SINCTYPE:
283		if (argc > 2)
284			(void) doincl(argv[2]);
285		break;
286#ifdef EXTENDED
287	case PASTTYPE:
288		if (argc > 2)
289			if (!dopaste(argv[2]))
290				err(1, "%s at line %lu: paste(%s)",
291				    CURRENT_NAME, CURRENT_LINE, argv[2]);
292		break;
293
294	case SPASTYPE:
295		if (argc > 2)
296			(void) dopaste(argv[2]);
297		break;
298	case FORMATTYPE:
299		doformat(argv, argc);
300		break;
301#endif
302	case CHNQTYPE:
303		dochq(argv, ac);
304		break;
305
306	case CHNCTYPE:
307		dochc(argv, argc);
308		break;
309
310	case SUBSTYPE:
311	/*
312	 * dosub - select substring
313	 *
314	 */
315		if (argc > 3)
316			dosub(argv, argc);
317		break;
318
319	case SHIFTYPE:
320	/*
321	 * doshift - push back all arguments
322	 * except the first one (i.e. skip
323	 * argv[2])
324	 */
325		if (argc > 3) {
326			for (n = argc - 1; n > 3; n--) {
327				pbstr(rquote);
328				pbstr(argv[n]);
329				pbstr(lquote);
330				pushback(COMMA);
331			}
332			pbstr(rquote);
333			pbstr(argv[3]);
334			pbstr(lquote);
335		}
336		break;
337
338	case DIVRTYPE:
339		if (argc > 2 && (n = atoi(argv[2])) != 0)
340			dodiv(n);
341		else {
342			active = stdout;
343			oindex = 0;
344		}
345		break;
346
347	case UNDVTYPE:
348		doundiv(argv, argc);
349		break;
350
351	case DIVNTYPE:
352	/*
353	 * dodivnum - return the number of
354	 * current output diversion
355	 */
356		pbnum(oindex);
357		break;
358
359	case UNDFTYPE:
360	/*
361	 * doundefine - undefine a previously
362	 * defined macro(s) or m4 keyword(s).
363	 */
364		if (argc > 2)
365			for (n = 2; n < argc; n++)
366				macro_undefine(argv[n]);
367		break;
368
369	case POPDTYPE:
370	/*
371	 * dopopdef - remove the topmost
372	 * definitions of macro(s) or m4
373	 * keyword(s).
374	 */
375		if (argc > 2)
376			for (n = 2; n < argc; n++)
377				macro_popdef(argv[n]);
378		break;
379
380	case MKTMTYPE:
381	/*
382	 * dotemp - create a temporary file
383	 */
384		if (argc > 2) {
385			int fd;
386			char *temp;
387
388			temp = xstrdup(argv[2]);
389
390			fd = mkstemp(temp);
391			if (fd == -1)
392				err(1,
393	    "%s at line %lu: couldn't make temp file %s",
394	    CURRENT_NAME, CURRENT_LINE, argv[2]);
395			close(fd);
396			pbstr(temp);
397			free(temp);
398		}
399		break;
400
401	case TRNLTYPE:
402	/*
403	 * dotranslit - replace all characters in
404	 * the source string that appears in the
405	 * "from" string with the corresponding
406	 * characters in the "to" string.
407	 */
408		if (argc > 3) {
409			char *temp;
410
411			temp = xalloc(strlen(argv[2])+1, NULL);
412			if (argc > 4)
413				map(temp, argv[2], argv[3], argv[4]);
414			else
415				map(temp, argv[2], argv[3], null);
416			pbstr(temp);
417			free(temp);
418		} else if (argc > 2)
419			pbstr(argv[2]);
420		break;
421
422	case INDXTYPE:
423	/*
424	 * doindex - find the index of the second
425	 * argument string in the first argument
426	 * string. -1 if not present.
427	 */
428		pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
429		break;
430
431	case ERRPTYPE:
432	/*
433	 * doerrp - print the arguments to stderr
434	 * file
435	 */
436		if (argc > 2) {
437			for (n = 2; n < argc; n++)
438				fprintf(stderr, "%s ", argv[n]);
439			fprintf(stderr, "\n");
440		}
441		break;
442
443	case DNLNTYPE:
444	/*
445	 * dodnl - eat-up-to and including
446	 * newline
447	 */
448		while ((c = gpbc()) != '\n' && c != EOF)
449			;
450		break;
451
452	case M4WRTYPE:
453	/*
454	 * dom4wrap - set up for
455	 * wrap-up/wind-down activity
456	 */
457		if (argc > 2)
458			dom4wrap(argv[2]);
459		break;
460
461	case EXITTYPE:
462	/*
463	 * doexit - immediate exit from m4.
464	 */
465		killdiv();
466		exit((argc > 2) ? atoi(argv[2]) : 0);
467		break;
468
469	case DEFNTYPE:
470		if (argc > 2)
471			for (n = 2; n < argc; n++)
472				dodefn(argv[n]);
473		break;
474
475	case INDIRTYPE:	/* Indirect call */
476		if (argc > 2)
477			doindir(argv, argc);
478		break;
479
480	case BUILTINTYPE: /* Builtins only */
481		if (argc > 2)
482			dobuiltin(argv, argc);
483		break;
484
485	case PATSTYPE:
486		if (argc > 2)
487			dopatsubst(argv, argc);
488		break;
489	case REGEXPTYPE:
490		if (argc > 2)
491			doregexp(argv, argc);
492		break;
493	case LINETYPE:
494		doprintlineno(infile+ilevel);
495		break;
496	case FILENAMETYPE:
497		doprintfilename(infile+ilevel);
498		break;
499	case SELFTYPE:
500		pbstr(rquote);
501		pbstr(argv[1]);
502		pbstr(lquote);
503		break;
504	default:
505		m4errx(1, "eval: major botch.");
506		break;
507	}
508}
509
510/*
511 * expand_macro - user-defined macro expansion
512 */
513void
514expand_macro(const char *argv[], int argc)
515{
516	const char *t;
517	const char *p;
518	int n;
519	int argno;
520
521	t = argv[0];		       /* defn string as a whole */
522	p = t;
523	while (*p)
524		p++;
525	p--;			       /* last character of defn */
526	while (p > t) {
527		if (*(p - 1) != ARGFLAG)
528			PUSHBACK(*p);
529		else {
530			switch (*p) {
531
532			case '#':
533				pbnum(argc - 2);
534				break;
535			case '0':
536			case '1':
537			case '2':
538			case '3':
539			case '4':
540			case '5':
541			case '6':
542			case '7':
543			case '8':
544			case '9':
545				if ((argno = *p - '0') < argc - 1)
546					pbstr(argv[argno + 1]);
547				break;
548			case '*':
549				if (argc > 2) {
550					for (n = argc - 1; n > 2; n--) {
551						pbstr(argv[n]);
552						pushback(COMMA);
553					}
554					pbstr(argv[2]);
555				}
556				break;
557                        case '@':
558				if (argc > 2) {
559					for (n = argc - 1; n > 2; n--) {
560						pbstr(rquote);
561						pbstr(argv[n]);
562						pbstr(lquote);
563						pushback(COMMA);
564					}
565					pbstr(rquote);
566					pbstr(argv[2]);
567					pbstr(lquote);
568				}
569                                break;
570			default:
571				PUSHBACK(*p);
572				PUSHBACK('$');
573				break;
574			}
575			p--;
576		}
577		p--;
578	}
579	if (p == t)		       /* do last character */
580		PUSHBACK(*p);
581}
582
583
584/*
585 * dodefine - install definition in the table
586 */
587void
588dodefine(const char *name, const char *defn)
589{
590	if (!*name && !mimic_gnu)
591		m4errx(1, "null definition.");
592	else
593		macro_define(name, defn);
594}
595
596/*
597 * dodefn - push back a quoted definition of
598 *      the given name.
599 */
600static void
601dodefn(const char *name)
602{
603	struct macro_definition *p;
604
605	if ((p = lookup_macro_definition(name)) != NULL) {
606		if ((p->type & TYPEMASK) == MACRTYPE) {
607			pbstr(rquote);
608			pbstr(p->defn);
609			pbstr(lquote);
610		} else {
611			pbstr(p->defn);
612			pbstr(BUILTIN_MARKER);
613		}
614	}
615}
616
617/*
618 * dopushdef - install a definition in the hash table
619 *      without removing a previous definition. Since
620 *      each new entry is entered in *front* of the
621 *      hash bucket, it hides a previous definition from
622 *      lookup.
623 */
624static void
625dopushdef(const char *name, const char *defn)
626{
627	if (!*name && !mimic_gnu)
628		m4errx(1, "null definition.");
629	else
630		macro_pushdef(name, defn);
631}
632
633/*
634 * dump_one_def - dump the specified definition.
635 */
636static void
637dump_one_def(const char *name, struct macro_definition *p)
638{
639	if (!traceout)
640		traceout = stderr;
641	if (mimic_gnu) {
642		if ((p->type & TYPEMASK) == MACRTYPE)
643			fprintf(traceout, "%s:\t%s\n", name, p->defn);
644		else {
645			fprintf(traceout, "%s:\t<%s>\n", name, p->defn);
646		}
647	} else
648		fprintf(traceout, "`%s'\t`%s'\n", name, p->defn);
649}
650
651/*
652 * dodumpdef - dump the specified definitions in the hash
653 *      table to stderr. If nothing is specified, the entire
654 *      hash table is dumped.
655 */
656static void
657dodump(const char *argv[], int argc)
658{
659	int n;
660	struct macro_definition *p;
661
662	if (argc > 2) {
663		for (n = 2; n < argc; n++)
664			if ((p = lookup_macro_definition(argv[n])) != NULL)
665				dump_one_def(argv[n], p);
666	} else
667		macro_for_all(dump_one_def);
668}
669
670/*
671 * dotrace - mark some macros as traced/untraced depending upon on.
672 */
673static void
674dotrace(const char *argv[], int argc, int on)
675{
676	int n;
677
678	if (argc > 2) {
679		for (n = 2; n < argc; n++)
680			mark_traced(argv[n], on);
681	} else
682		mark_traced(NULL, on);
683}
684
685/*
686 * doifelse - select one of two alternatives - loop.
687 */
688static void
689doifelse(const char *argv[], int argc)
690{
691	cycle {
692		if (STREQ(argv[2], argv[3]))
693			pbstr(argv[4]);
694		else if (argc == 6)
695			pbstr(argv[5]);
696		else if (argc > 6) {
697			argv += 3;
698			argc -= 3;
699			continue;
700		}
701		break;
702	}
703}
704
705/*
706 * doinclude - include a given file.
707 */
708static int
709doincl(const char *ifile)
710{
711	if (ilevel + 1 == MAXINP)
712		m4errx(1, "too many include files.");
713	if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
714		ilevel++;
715		bbase[ilevel] = bufbase = bp;
716		return (1);
717	} else
718		return (0);
719}
720
721#ifdef EXTENDED
722/*
723 * dopaste - include a given file without any
724 *           macro processing.
725 */
726static int
727dopaste(const char *pfile)
728{
729	FILE *pf;
730	int c;
731
732	if ((pf = fopen(pfile, "r")) != NULL) {
733		if (synch_lines)
734		    fprintf(active, "#line 1 \"%s\"\n", pfile);
735		while ((c = getc(pf)) != EOF)
736			putc(c, active);
737		(void) fclose(pf);
738		emit_synchline();
739		return (1);
740	} else
741		return (0);
742}
743#endif
744
745/*
746 * dochq - change quote characters
747 */
748static void
749dochq(const char *argv[], int ac)
750{
751	if (ac == 2) {
752		lquote[0] = LQUOTE; lquote[1] = EOS;
753		rquote[0] = RQUOTE; rquote[1] = EOS;
754	} else {
755		strlcpy(lquote, argv[2], sizeof(lquote));
756		if (ac > 3) {
757			strlcpy(rquote, argv[3], sizeof(rquote));
758		} else {
759			rquote[0] = ECOMMT; rquote[1] = EOS;
760		}
761	}
762}
763
764/*
765 * dochc - change comment characters
766 */
767static void
768dochc(const char *argv[], int argc)
769{
770/* XXX Note that there is no difference between no argument and a single
771 * empty argument.
772 */
773	if (argc == 2) {
774		scommt[0] = EOS;
775		ecommt[0] = EOS;
776	} else {
777		strlcpy(scommt, argv[2], sizeof(scommt));
778		if (argc == 3) {
779			ecommt[0] = ECOMMT; ecommt[1] = EOS;
780		} else {
781			strlcpy(ecommt, argv[3], sizeof(ecommt));
782		}
783	}
784}
785
786/*
787 * dom4wrap - expand text at EOF
788 */
789static void
790dom4wrap(const char *text)
791{
792	if (wrapindex >= maxwraps) {
793		if (maxwraps == 0)
794			maxwraps = 16;
795		else
796			maxwraps *= 2;
797		m4wraps = xrealloc(m4wraps, maxwraps * sizeof(*m4wraps),
798		   "too many m4wraps");
799	}
800	m4wraps[wrapindex++] = xstrdup(text);
801}
802
803/*
804 * dodivert - divert the output to a temporary file
805 */
806static void
807dodiv(int n)
808{
809	int fd;
810
811	oindex = n;
812	if (n >= maxout) {
813		if (mimic_gnu)
814			resizedivs(n + 10);
815		else
816			n = 0;		/* bitbucket */
817	}
818
819	if (n < 0)
820		n = 0;		       /* bitbucket */
821	if (outfile[n] == NULL) {
822		char fname[] = _PATH_DIVNAME;
823
824		if ((fd = mkstemp(fname)) < 0 ||
825			(outfile[n] = fdopen(fd, "w+")) == NULL)
826				err(1, "%s: cannot divert", fname);
827		if (unlink(fname) == -1)
828			err(1, "%s: cannot unlink", fname);
829	}
830	active = outfile[n];
831}
832
833/*
834 * doundivert - undivert a specified output, or all
835 *              other outputs, in numerical order.
836 */
837static void
838doundiv(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 */
865static void
866dosub(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 */
900static void
901map(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	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	if (*src) {
931		if (mimic_gnu) {
932			/*
933			 * expand character ranges on the fly
934			 */
935			from = handledash(frombis, frombis + 256, from);
936			to = handledash(tobis, tobis + 256, to);
937		}
938		tmp = from;
939	/*
940	 * create a mapping between "from" and
941	 * "to"
942	 */
943		for (i = 0; i < 256; i++)
944			seen[i] = 0;
945		while (*from) {
946			if (!seen[(unsigned char)(*from)]) {
947				mapvec[(unsigned char)(*from)] = (unsigned char)(*to);
948				seen[(unsigned char)(*from)] = 1;
949			}
950			from++;
951			if (*to)
952				to++;
953		}
954
955		while (*src) {
956			sch = (unsigned char)(*src++);
957			dch = mapvec[sch];
958			if ((*dest = (char)dch))
959				dest++;
960		}
961	/*
962	 * restore all the changed characters
963	 */
964		while (*tmp) {
965			mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
966			tmp++;
967		}
968	}
969	*dest = '\0';
970}
971
972
973/*
974 * handledash:
975 *  use buffer to copy the src string, expanding character ranges
976 * on the way.
977 */
978static const char *
979handledash(char *buffer, char *end, const char *src)
980{
981	char *p;
982
983	p = buffer;
984	while(*src) {
985		if (src[1] == '-' && src[2]) {
986			unsigned char i;
987			if ((unsigned char)src[0] <= (unsigned char)src[2]) {
988				for (i = (unsigned char)src[0];
989				    i <= (unsigned char)src[2]; i++) {
990					*p++ = i;
991					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			src += 3;
1007		} else
1008			*p++ = *src++;
1009		if (p == end)
1010			break;
1011	}
1012	*p = '\0';
1013	return buffer;
1014}
1015