blob: a3e0022254bddb1b95aaeaf485790126c0ac3c8a [file] [log] [blame]
Brian Kernighan87b94932012-12-22 10:35:39 -05001/****************************************************************
2Copyright (C) Lucent Technologies 1997
3All Rights Reserved
4
5Permission to use, copy, modify, and distribute this software and
6its documentation for any purpose and without fee is hereby
7granted, provided that the above copyright notice appear in all
8copies and that both that the copyright notice and this
9permission notice and warranty disclaimer appear in supporting
10documentation, and that the name Lucent Technologies or any of
11its entities not be used in advertising or publicity pertaining
12to distribution of the software without specific, written prior
13permission.
14
15LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22THIS SOFTWARE.
23****************************************************************/
24
Arnold D. Robbinsb2554a92020-07-02 21:35:06 +030025const char *version = "version 20200702";
Brian Kernighan87b94932012-12-22 10:35:39 -050026
27#define DEBUG
28#include <stdio.h>
29#include <ctype.h>
30#include <locale.h>
31#include <stdlib.h>
32#include <string.h>
33#include <signal.h>
34#include "awk.h"
35#include "ytab.h"
36
37extern char **environ;
38extern int nfields;
39
40int dbg = 0;
41Awkfloat srand_seed = 1;
42char *cmdname; /* gets argv[0] for error messages */
43extern FILE *yyin; /* lex input file */
44char *lexprog; /* points to program argument if it exists */
45extern int errorflag; /* non-zero if any syntax errors; set by yyerror */
Arnold D. Robbins108224b2019-11-10 21:19:18 +020046enum compile_states compile_time = ERROR_PRINTING;
Brian Kernighan87b94932012-12-22 10:35:39 -050047
zoulasc94e4c042020-02-18 14:20:27 -050048static char **pfile; /* program filenames from -f's */
49static size_t maxpfile; /* max program filename */
50static size_t npfile; /* number of filenames */
51static size_t curpfile; /* current filename */
Brian Kernighan87b94932012-12-22 10:35:39 -050052
Arnold D. Robbins108224b2019-11-10 21:19:18 +020053bool safe = false; /* true => "safe" mode */
Brian Kernighan87b94932012-12-22 10:35:39 -050054
awkfan77bb538fe2020-04-05 19:10:52 +010055static noreturn void fpecatch(int n
zoulasc94e4c042020-02-18 14:20:27 -050056#ifdef SA_SIGINFO
57 , siginfo_t *si, void *uc
58#endif
59)
Arnold D. Robbinsed6ff8c2020-02-18 21:26:24 +020060{
zoulasc94e4c042020-02-18 14:20:27 -050061#ifdef SA_SIGINFO
62 static const char *emsg[] = {
Arnold D. Robbinsed6ff8c2020-02-18 21:26:24 +020063 [0] = "Unknown error",
64 [FPE_INTDIV] = "Integer divide by zero",
65 [FPE_INTOVF] = "Integer overflow",
66 [FPE_FLTDIV] = "Floating point divide by zero",
67 [FPE_FLTOVF] = "Floating point overflow",
68 [FPE_FLTUND] = "Floating point underflow",
69 [FPE_FLTRES] = "Floating point inexact result",
70 [FPE_FLTINV] = "Invalid Floating point operation",
71 [FPE_FLTSUB] = "Subscript out of range",
zoulasc94e4c042020-02-18 14:20:27 -050072 };
73#endif
74 FATAL("floating point exception"
75#ifdef SA_SIGINFO
Arnold D. Robbinsed6ff8c2020-02-18 21:26:24 +020076 ": %s", (size_t)si->si_code < sizeof(emsg) / sizeof(emsg[0]) &&
77 emsg[si->si_code] ? emsg[si->si_code] : emsg[0]
zoulasc94e4c042020-02-18 14:20:27 -050078#endif
79 );
80}
81
Brian Kernighan3ed9e242018-08-15 10:45:03 -040082/* Can this work with recursive calls? I don't think so.
83void segvcatch(int n)
84{
85 FATAL("segfault. Do you have an unbounded recursive call?", n);
86}
87*/
88
zoulasc94e4c042020-02-18 14:20:27 -050089static const char *
90setfs(char *p)
91{
92 /* wart: t=>\t */
93 if (p[0] == 't' && p[1] == '\0')
94 return "\t";
95 else if (p[0] != '\0')
96 return p;
97 return NULL;
98}
99
100static char *
101getarg(int *argc, char ***argv, const char *msg)
102{
103 if ((*argv)[1][2] != '\0') { /* arg is -fsomething */
104 return &(*argv)[1][2];
105 } else { /* arg is -f something */
106 (*argc)--; (*argv)++;
107 if (*argc <= 1)
108 FATAL("%s", msg);
109 return (*argv)[1];
110 }
111}
112
Brian Kernighan87b94932012-12-22 10:35:39 -0500113int main(int argc, char *argv[])
114{
115 const char *fs = NULL;
zoulasc94e4c042020-02-18 14:20:27 -0500116 char *fn, *vn;
Brian Kernighan87b94932012-12-22 10:35:39 -0500117
118 setlocale(LC_CTYPE, "");
119 setlocale(LC_NUMERIC, "C"); /* for parsing cmdline & prog */
120 cmdname = argv[0];
121 if (argc == 1) {
Arnold D. Robbins795a06b2019-07-28 05:51:52 -0600122 fprintf(stderr,
123 "usage: %s [-F fs] [-v var=value] [-f progfile | 'prog'] [file ...]\n",
Brian Kernighan87b94932012-12-22 10:35:39 -0500124 cmdname);
125 exit(1);
126 }
zoulasc94e4c042020-02-18 14:20:27 -0500127#ifdef SA_SIGINFO
128 {
129 struct sigaction sa;
130 sa.sa_sigaction = fpecatch;
131 sa.sa_flags = SA_SIGINFO;
132 sigemptyset(&sa.sa_mask);
133 (void)sigaction(SIGFPE, &sa, NULL);
134 }
135#else
136 (void)signal(SIGFPE, fpecatch);
137#endif
Brian Kernighan3ed9e242018-08-15 10:45:03 -0400138 /*signal(SIGSEGV, segvcatch); experiment */
Brian Kernighan87b94932012-12-22 10:35:39 -0500139
zoulasc94e4c042020-02-18 14:20:27 -0500140 /* Set and keep track of the random seed */
Brian Kernighan87b94932012-12-22 10:35:39 -0500141 srand_seed = 1;
pfgc70b9fe2014-09-19 18:24:02 +0000142 srandom((unsigned long) srand_seed);
Brian Kernighan87b94932012-12-22 10:35:39 -0500143
144 yyin = NULL;
145 symtab = makesymtab(NSYMTAB/NSYMTAB);
146 while (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') {
Arnold D. Robbinsed6ff8c2020-02-18 21:26:24 +0200147 if (strcmp(argv[1], "-version") == 0 || strcmp(argv[1], "--version") == 0) {
Brian Kernighan87b94932012-12-22 10:35:39 -0500148 printf("awk %s\n", version);
zoulasc94e4c042020-02-18 14:20:27 -0500149 return 0;
Brian Kernighan87b94932012-12-22 10:35:39 -0500150 }
Cody Peter Mello9b093ea2018-10-09 11:46:57 -0700151 if (strcmp(argv[1], "--") == 0) { /* explicit end of args */
Brian Kernighan87b94932012-12-22 10:35:39 -0500152 argc--;
153 argv++;
154 break;
155 }
156 switch (argv[1][1]) {
157 case 's':
158 if (strcmp(argv[1], "-safe") == 0)
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200159 safe = true;
Brian Kernighan87b94932012-12-22 10:35:39 -0500160 break;
161 case 'f': /* next argument is program filename */
zoulasc94e4c042020-02-18 14:20:27 -0500162 fn = getarg(&argc, &argv, "no program filename");
163 if (npfile >= maxpfile) {
164 maxpfile += 20;
165 pfile = realloc(pfile, maxpfile * sizeof(*pfile));
166 if (pfile == NULL)
Arnold D. Robbinsed6ff8c2020-02-18 21:26:24 +0200167 FATAL("error allocating space for -f options");
zoulasc94e4c042020-02-18 14:20:27 -0500168 }
169 pfile[npfile++] = fn;
170 break;
Brian Kernighan87b94932012-12-22 10:35:39 -0500171 case 'F': /* set field separator */
zoulasc94e4c042020-02-18 14:20:27 -0500172 fs = setfs(getarg(&argc, &argv, "no field separator"));
173 if (fs == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -0500174 WARNING("field separator FS is empty");
175 break;
176 case 'v': /* -v a=1 to be done NOW. one -v for each */
zoulasc94e4c042020-02-18 14:20:27 -0500177 vn = getarg(&argc, &argv, "no variable name");
178 if (isclvar(vn))
179 setclvar(vn);
180 else
181 FATAL("invalid -v option argument: %s", vn);
Brian Kernighan87b94932012-12-22 10:35:39 -0500182 break;
183 case 'd':
184 dbg = atoi(&argv[1][2]);
185 if (dbg == 0)
186 dbg = 1;
187 printf("awk %s\n", version);
188 break;
189 default:
190 WARNING("unknown option %s ignored", argv[1]);
191 break;
192 }
193 argc--;
194 argv++;
195 }
196 /* argv[1] is now the first argument */
197 if (npfile == 0) { /* no -f; first argument is program */
198 if (argc <= 1) {
199 if (dbg)
200 exit(0);
201 FATAL("no program given");
202 }
Todd C. Miller292d39f2020-06-25 12:32:34 -0600203 DPRINTF("program = |%s|\n", argv[1]);
Brian Kernighan87b94932012-12-22 10:35:39 -0500204 lexprog = argv[1];
205 argc--;
206 argv++;
207 }
208 recinit(recsize);
209 syminit();
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200210 compile_time = COMPILING;
Brian Kernighan87b94932012-12-22 10:35:39 -0500211 argv[0] = cmdname; /* put prog name at front of arglist */
Todd C. Miller292d39f2020-06-25 12:32:34 -0600212 DPRINTF("argc=%d, argv[0]=%s\n", argc, argv[0]);
Brian Kernighan87b94932012-12-22 10:35:39 -0500213 arginit(argc, argv);
214 if (!safe)
215 envinit(environ);
216 yyparse();
Arnold D. Robbins2017c2e2020-02-28 13:47:42 +0200217#if 0
218 // Doing this would comply with POSIX, but is not compatible with
219 // other awks and with what most users expect. So comment it out.
220 setlocale(LC_NUMERIC, ""); /* back to whatever it is locally */
221#endif
Brian Kernighan87b94932012-12-22 10:35:39 -0500222 if (fs)
223 *FS = qstring(fs, '\0');
Todd C. Miller292d39f2020-06-25 12:32:34 -0600224 DPRINTF("errorflag=%d\n", errorflag);
Brian Kernighan87b94932012-12-22 10:35:39 -0500225 if (errorflag == 0) {
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200226 compile_time = RUNNING;
Brian Kernighan87b94932012-12-22 10:35:39 -0500227 run(winner);
228 } else
229 bracecheck();
230 return(errorflag);
231}
232
233int pgetc(void) /* get 1 character from awk program */
234{
235 int c;
236
237 for (;;) {
238 if (yyin == NULL) {
239 if (curpfile >= npfile)
240 return EOF;
241 if (strcmp(pfile[curpfile], "-") == 0)
242 yyin = stdin;
243 else if ((yyin = fopen(pfile[curpfile], "r")) == NULL)
244 FATAL("can't open file %s", pfile[curpfile]);
245 lineno = 1;
246 }
247 if ((c = getc(yyin)) != EOF)
248 return c;
249 if (yyin != stdin)
250 fclose(yyin);
251 yyin = NULL;
252 curpfile++;
253 }
254}
255
256char *cursource(void) /* current source file name */
257{
258 if (npfile > 0)
Todd C. Miller453ce862020-07-29 12:31:29 -0600259 return pfile[curpfile < npfile ? curpfile : curpfile - 1];
Brian Kernighan87b94932012-12-22 10:35:39 -0500260 else
261 return NULL;
262}