xref: /netbsd/external/historical/nawk/dist/main.c (revision e66db18e)
1 /****************************************************************
2 Copyright (C) Lucent Technologies 1997
3 All Rights Reserved
4 
5 Permission to use, copy, modify, and distribute this software and
6 its documentation for any purpose and without fee is hereby
7 granted, provided that the above copyright notice appear in all
8 copies and that both that the copyright notice and this
9 permission notice and warranty disclaimer appear in supporting
10 documentation, and that the name Lucent Technologies or any of
11 its entities not be used in advertising or publicity pertaining
12 to distribution of the software without specific, written prior
13 permission.
14 
15 LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17 IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20 IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22 THIS SOFTWARE.
23 ****************************************************************/
24 
25 #if HAVE_NBTOOL_CONFIG_H
26 #include "nbtool_config.h"
27 #endif
28 
29 const char	*version = "version 20200218";
30 
31 #define DEBUG
32 #include <stdio.h>
33 #include <ctype.h>
34 #include <locale.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <signal.h>
38 #include "awk.h"
39 #include "awkgram.h"
40 
41 extern	char	**environ;
42 extern	int	nfields;
43 
44 int	dbg	= 0;
45 Awkfloat	srand_seed = 1;
46 char	*cmdname;	/* gets argv[0] for error messages */
47 extern	FILE	*yyin;	/* lex input file */
48 char	*lexprog;	/* points to program argument if it exists */
49 extern	int errorflag;	/* non-zero if any syntax errors; set by yyerror */
50 enum compile_states	compile_time = ERROR_PRINTING;
51 
52 static char	**pfile;	/* program filenames from -f's */
53 static size_t	maxpfile;	/* max program filename */
54 static size_t	npfile;		/* number of filenames */
55 static size_t	curpfile;	/* current filename */
56 
57 bool	safe = false;	/* true => "safe" mode */
58 
fpecatch(int n,siginfo_t * si,void * uc)59 static __attribute__((__noreturn__)) void fpecatch(int n
60 #ifdef SA_SIGINFO
61 	, siginfo_t *si, void *uc
62 #endif
63 )
64 {
65 #ifdef SA_SIGINFO
66 	static const char *emsg[] = {
67 		[0] = "Unknown error",
68 		[FPE_INTDIV] = "Integer divide by zero",
69 		[FPE_INTOVF] = "Integer overflow",
70 		[FPE_FLTDIV] = "Floating point divide by zero",
71 		[FPE_FLTOVF] = "Floating point overflow",
72 		[FPE_FLTUND] = "Floating point underflow",
73 		[FPE_FLTRES] = "Floating point inexact result",
74 		[FPE_FLTINV] = "Invalid Floating point operation",
75 		[FPE_FLTSUB] = "Subscript out of range",
76 	};
77 #endif
78 	FATAL("floating point exception"
79 #ifdef SA_SIGINFO
80 		": %s", (size_t)si->si_code < sizeof(emsg) / sizeof(emsg[0]) &&
81 		emsg[si->si_code] ? emsg[si->si_code] : emsg[0]
82 #endif
83 	    );
84 }
85 
86 /* Can this work with recursive calls?  I don't think so.
87 void segvcatch(int n)
88 {
89 	FATAL("segfault.  Do you have an unbounded recursive call?", n);
90 }
91 */
92 
93 static const char *
setfs(char * p)94 setfs(char *p)
95 {
96 	/* wart: t=>\t */
97 	if (p[0] == 't' && p[1] == '\0')
98 		return "\t";
99 	else if (p[0] != '\0')
100 		return p;
101 	return NULL;
102 }
103 
104 static char *
getarg(int * argc,char *** argv,const char * msg)105 getarg(int *argc, char ***argv, const char *msg)
106 {
107 	if ((*argv)[1][2] != '\0') {	/* arg is -fsomething */
108 		return &(*argv)[1][2];
109 	} else {			/* arg is -f something */
110 		(*argc)--; (*argv)++;
111 		if (*argc <= 1)
112 			FATAL("%s", msg);
113 		return (*argv)[1];
114 	}
115 }
116 
main(int argc,char * argv[])117 int main(int argc, char *argv[])
118 {
119 	const char *fs = NULL;
120 	char *fn, *vn;
121 
122 	setlocale(LC_CTYPE, "");
123 	setlocale(LC_NUMERIC, "C"); /* for parsing cmdline & prog */
124 	cmdname = argv[0];
125 	if (argc == 1) {
126 		fprintf(stderr,
127 		  "usage: %s [-F fs] [-v var=value] [-f progfile | 'prog'] [file ...]\n",
128 		  cmdname);
129 		exit(1);
130 	}
131 #ifdef SA_SIGINFO
132 	{
133 		struct sigaction sa;
134 		sa.sa_sigaction = fpecatch;
135 		sa.sa_flags = SA_SIGINFO;
136 		sigemptyset(&sa.sa_mask);
137 		(void)sigaction(SIGFPE, &sa, NULL);
138 	}
139 #else
140 	(void)signal(SIGFPE, fpecatch);
141 #endif
142 	/*signal(SIGSEGV, segvcatch); experiment */
143 
144 	/* Set and keep track of the random seed */
145 	srand_seed = 1;
146 	srandom((unsigned long) srand_seed);
147 
148 	yyin = NULL;
149 	symtab = makesymtab(NSYMTAB/NSYMTAB);
150 	while (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') {
151 		if (strcmp(argv[1], "-version") == 0 || strcmp(argv[1], "--version") == 0) {
152 			printf("awk %s\n", version);
153 			return 0;
154 		}
155 		if (strcmp(argv[1], "--") == 0) {	/* explicit end of args */
156 			argc--;
157 			argv++;
158 			break;
159 		}
160 		switch (argv[1][1]) {
161 		case 's':
162 			if (strcmp(argv[1], "-safe") == 0)
163 				safe = true;
164 			break;
165 		case 'f':	/* next argument is program filename */
166 			fn = getarg(&argc, &argv, "no program filename");
167 			if (npfile >= maxpfile) {
168 				maxpfile += 20;
169 				pfile = realloc(pfile, maxpfile * sizeof(*pfile));
170 				if (pfile == NULL)
171 					FATAL("error allocating space for -f options");
172  			}
173 			pfile[npfile++] = fn;
174  			break;
175 		case 'F':	/* set field separator */
176 			fs = setfs(getarg(&argc, &argv, "no field separator"));
177 			if (fs == NULL)
178 				WARNING("field separator FS is empty");
179 			break;
180 		case 'v':	/* -v a=1 to be done NOW.  one -v for each */
181 			vn = getarg(&argc, &argv, "no variable name");
182 			if (isclvar(vn))
183 				setclvar(vn);
184 			else
185 				FATAL("invalid -v option argument: %s", vn);
186 			break;
187 		case 'd':
188 			dbg = atoi(&argv[1][2]);
189 			if (dbg == 0)
190 				dbg = 1;
191 			printf("awk %s\n", version);
192 			break;
193 		default:
194 			WARNING("unknown option %s ignored", argv[1]);
195 			break;
196 		}
197 		argc--;
198 		argv++;
199 	}
200 	/* argv[1] is now the first argument */
201 	if (npfile == 0) {	/* no -f; first argument is program */
202 		if (argc <= 1) {
203 			if (dbg)
204 				exit(0);
205 			FATAL("no program given");
206 		}
207 		   dprintf( ("program = |%s|\n", argv[1]) );
208 		lexprog = argv[1];
209 		argc--;
210 		argv++;
211 	}
212 	recinit(recsize);
213 	syminit();
214 	compile_time = COMPILING;
215 	argv[0] = cmdname;	/* put prog name at front of arglist */
216 	   dprintf( ("argc=%d, argv[0]=%s\n", argc, argv[0]) );
217 	arginit(argc, argv);
218 	if (!safe)
219 		envinit(environ);
220 	yyparse();
221 #if 0
222 	setlocale(LC_NUMERIC, ""); /* back to whatever it is locally */
223 #endif
224 	if (fs)
225 		*FS = qstring(fs, '\0');
226 	   dprintf( ("errorflag=%d\n", errorflag) );
227 	if (errorflag == 0) {
228 		compile_time = RUNNING;
229 		run(winner);
230 	} else
231 		bracecheck();
232 	return(errorflag);
233 }
234 
pgetc(void)235 int pgetc(void)		/* get 1 character from awk program */
236 {
237 	int c;
238 
239 	for (;;) {
240 		if (yyin == NULL) {
241 			if (curpfile >= npfile)
242 				return EOF;
243 			if (strcmp(pfile[curpfile], "-") == 0)
244 				yyin = stdin;
245 			else if ((yyin = fopen(pfile[curpfile], "r")) == NULL)
246 				FATAL("can't open file %s", pfile[curpfile]);
247 			lineno = 1;
248 		}
249 		if ((c = getc(yyin)) != EOF)
250 			return c;
251 		if (yyin != stdin)
252 			fclose(yyin);
253 		yyin = NULL;
254 		curpfile++;
255 	}
256 }
257 
cursource(void)258 char *cursource(void)	/* current source file name */
259 {
260 	if (npfile > 0)
261 		return pfile[curpfile];
262 	else
263 		return NULL;
264 }
265