xref: /openbsd-src/usr.bin/awk/main.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: main.c,v 1.22 2020/02/27 21:43:46 millert Exp $	*/
2 /****************************************************************
3 Copyright (C) Lucent Technologies 1997
4 All Rights Reserved
5 
6 Permission to use, copy, modify, and distribute this software and
7 its documentation for any purpose and without fee is hereby
8 granted, provided that the above copyright notice appear in all
9 copies and that both that the copyright notice and this
10 permission notice and warranty disclaimer appear in supporting
11 documentation, and that the name Lucent Technologies or any of
12 its entities not be used in advertising or publicity pertaining
13 to distribution of the software without specific, written prior
14 permission.
15 
16 LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
18 IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
19 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
21 IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
22 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
23 THIS SOFTWARE.
24 ****************************************************************/
25 
26 const char	*version = "version 20121220";
27 
28 #define DEBUG
29 #include <stdio.h>
30 #include <ctype.h>
31 #include <locale.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <signal.h>
35 #include <unistd.h>
36 #include "awk.h"
37 #include "ytab.h"
38 
39 extern	char	**environ;
40 extern	int	nfields;
41 extern	char	*__progname;
42 
43 int	dbg	= 0;
44 Awkfloat	srand_seed = 1;
45 char	*cmdname;	/* gets argv[0] for error messages */
46 extern	FILE	*yyin;	/* lex input file */
47 char	*lexprog;	/* points to program argument if it exists */
48 extern	int errorflag;	/* non-zero if any syntax errors; set by yyerror */
49 int	compile_time = 2;	/* for error printing: */
50 				/* 2 = cmdline, 1 = compile, 0 = running */
51 
52 #define	MAX_PFILE	20	/* max number of -f's */
53 
54 char	*pfile[MAX_PFILE];	/* program filenames from -f's */
55 int	npfile = 0;	/* number of filenames */
56 int	curpfile = 0;	/* current filename */
57 
58 int	safe	= 0;	/* 1 => "safe" mode */
59 
60 int main(int argc, char *argv[])
61 {
62 	const char *fs = NULL;
63 
64 	setlocale(LC_ALL, "");
65 	setlocale(LC_NUMERIC, "C"); /* for parsing cmdline & prog */
66 
67 	cmdname = __progname;
68 	if (pledge("stdio rpath wpath cpath proc exec", NULL) == -1) {
69 		fprintf(stderr, "%s: pledge: incorrect arguments\n",
70 		    cmdname);
71 		exit(1);
72 	}
73 
74 	if (argc == 1) {
75 		fprintf(stderr, "usage: %s [-safe] [-V] [-d[n]] [-F fs] "
76 		    "[-v var=value] [prog | -f progfile]\n\tfile ...\n",
77 		    cmdname);
78 		exit(1);
79 	}
80 	signal(SIGFPE, fpecatch);
81 
82 	yyin = NULL;
83 	symtab = makesymtab(NSYMTAB);
84 	while (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') {
85 		if (strcmp(argv[1], "--") == 0) {	/* explicit end of args */
86 			argc--;
87 			argv++;
88 			break;
89 		}
90 		switch (argv[1][1]) {
91 		case 's':
92 			if (strcmp(argv[1], "-safe") == 0)
93 				safe = 1;
94 			break;
95 		case 'f':	/* next argument is program filename */
96 			if (argv[1][2] != 0) {  /* arg is -fsomething */
97 				if (npfile >= MAX_PFILE - 1)
98 					FATAL("too many -f options");
99 				pfile[npfile++] = &argv[1][2];
100 			} else {		/* arg is -f something */
101 				argc--; argv++;
102 				if (argc <= 1)
103 					FATAL("no program filename");
104 				if (npfile >= MAX_PFILE - 1)
105 					FATAL("too many -f options");
106 				pfile[npfile++] = argv[1];
107 			}
108 			break;
109 		case 'F':	/* set field separator */
110 			if (argv[1][2] != 0) {	/* arg is -Fsomething */
111 				if (argv[1][2] == 't' && argv[1][3] == 0)	/* wart: t=>\t */
112 					fs = "\t";
113 				else if (argv[1][2] != 0)
114 					fs = &argv[1][2];
115 			} else {		/* arg is -F something */
116 				argc--; argv++;
117 				if (argc > 1 && argv[1][0] == 't' && argv[1][1] == 0)	/* wart: t=>\t */
118 					fs = "\t";
119 				else if (argc > 1 && argv[1][0] != 0)
120 					fs = &argv[1][0];
121 			}
122 			if (fs == NULL || *fs == '\0')
123 				WARNING("field separator FS is empty");
124 			break;
125 		case 'v':	/* -v a=1 to be done NOW.  one -v for each */
126 			if (argv[1][2] != 0) {  /* arg is -vsomething */
127 				if (isclvar(&argv[1][2]))
128 					setclvar(&argv[1][2]);
129 				else
130 					FATAL("invalid -v option argument: %s", &argv[1][2]);
131 			} else {		/* arg is -v something */
132 				argc--; argv++;
133 				if (argc <= 1)
134 					FATAL("no variable name");
135 				if (isclvar(argv[1]))
136 					setclvar(argv[1]);
137 				else
138 					FATAL("invalid -v option argument: %s", argv[1]);
139 			}
140 			break;
141 		case 'd':
142 			dbg = atoi(&argv[1][2]);
143 			if (dbg == 0)
144 				dbg = 1;
145 			printf("awk %s\n", version);
146 			break;
147 		case 'V':	/* added for exptools "standard" */
148 			printf("awk %s\n", version);
149 			exit(0);
150 			break;
151 		default:
152 			WARNING("unknown option %s ignored", argv[1]);
153 			break;
154 		}
155 		argc--;
156 		argv++;
157 	}
158 
159 	if (safe) {
160 		if (pledge("stdio rpath", NULL) == -1) {
161 			fprintf(stderr, "%s: pledge: incorrect arguments\n",
162 			    cmdname);
163 			exit(1);
164 		}
165 	}
166 
167 	/* argv[1] is now the first argument */
168 	if (npfile == 0) {	/* no -f; first argument is program */
169 		if (argc <= 1) {
170 			if (dbg)
171 				exit(0);
172 			FATAL("no program given");
173 		}
174 		   DPRINTF( ("program = |%s|\n", argv[1]) );
175 		lexprog = argv[1];
176 		argc--;
177 		argv++;
178 	}
179 	recinit(recsize);
180 	syminit();
181 	compile_time = 1;
182 	argv[0] = cmdname;	/* put prog name at front of arglist */
183 	   DPRINTF( ("argc=%d, argv[0]=%s\n", argc, argv[0]) );
184 	arginit(argc, argv);
185 	if (!safe)
186 		envinit(environ);
187 	yyparse();
188 	setlocale(LC_NUMERIC, ""); /* back to whatever it is locally */
189 	if (fs)
190 		*FS = qstring(fs, '\0');
191 	   DPRINTF( ("errorflag=%d\n", errorflag) );
192 	if (errorflag == 0) {
193 		compile_time = 0;
194 		run(winner);
195 	} else
196 		bracecheck();
197 	return(errorflag);
198 }
199 
200 int pgetc(void)		/* get 1 character from awk program */
201 {
202 	int c;
203 
204 	for (;;) {
205 		if (yyin == NULL) {
206 			if (curpfile >= npfile)
207 				return EOF;
208 			if (strcmp(pfile[curpfile], "-") == 0)
209 				yyin = stdin;
210 			else if ((yyin = fopen(pfile[curpfile], "r")) == NULL)
211 				FATAL("can't open file %s", pfile[curpfile]);
212 			lineno = 1;
213 		}
214 		if ((c = getc(yyin)) != EOF)
215 			return c;
216 		if (yyin != stdin)
217 			fclose(yyin);
218 		yyin = NULL;
219 		curpfile++;
220 	}
221 }
222 
223 char *cursource(void)	/* current source file name */
224 {
225 	if (npfile > 0)
226 		return pfile[curpfile];
227 	else
228 		return NULL;
229 }
230