blob: 5a1ecbf824c4130cb200312f2acfad0047c5ee05 [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. Robbins5068d202020-02-06 22:27:31 +020025const char *version = "version 20200206";
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
zoulasc94e4c042020-02-18 14:20:27 -050055static __attribute__((__noreturn__)) void fpecatch(int n
56#ifdef SA_SIGINFO
57 , siginfo_t *si, void *uc
58#endif
59)
60 {
61#ifdef SA_SIGINFO
62 static const char *emsg[] = {
63 [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",
72 };
73#endif
74 FATAL("floating point exception"
75#ifdef SA_SIGINFO
76 ": %s\n", (size_t)si->si_code < sizeof(emsg) / sizeof(emsg[0]) &&
77 emsg[si->si_code] ? emsg[si->si_code] : emsg[0]
78#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') {
zoulasc94e4c042020-02-18 14:20:27 -0500147 if (strcmp(argv[1], "-version") == 0 ||
148 strcmp(argv[1], "--version") == 0) {
Brian Kernighan87b94932012-12-22 10:35:39 -0500149 printf("awk %s\n", version);
zoulasc94e4c042020-02-18 14:20:27 -0500150 return 0;
Brian Kernighan87b94932012-12-22 10:35:39 -0500151 }
Cody Peter Mello9b093ea2018-10-09 11:46:57 -0700152 if (strcmp(argv[1], "--") == 0) { /* explicit end of args */
Brian Kernighan87b94932012-12-22 10:35:39 -0500153 argc--;
154 argv++;
155 break;
156 }
157 switch (argv[1][1]) {
158 case 's':
159 if (strcmp(argv[1], "-safe") == 0)
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200160 safe = true;
Brian Kernighan87b94932012-12-22 10:35:39 -0500161 break;
162 case 'f': /* next argument is program filename */
zoulasc94e4c042020-02-18 14:20:27 -0500163 fn = getarg(&argc, &argv, "no program filename");
164 if (npfile >= maxpfile) {
165 maxpfile += 20;
166 pfile = realloc(pfile, maxpfile * sizeof(*pfile));
167 if (pfile == NULL)
168 FATAL("error allocating space for "
169 "-f options");
170 }
171 pfile[npfile++] = fn;
172 break;
Brian Kernighan87b94932012-12-22 10:35:39 -0500173 case 'F': /* set field separator */
zoulasc94e4c042020-02-18 14:20:27 -0500174 fs = setfs(getarg(&argc, &argv, "no field separator"));
175 if (fs == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -0500176 WARNING("field separator FS is empty");
177 break;
178 case 'v': /* -v a=1 to be done NOW. one -v for each */
zoulasc94e4c042020-02-18 14:20:27 -0500179 vn = getarg(&argc, &argv, "no variable name");
180 if (isclvar(vn))
181 setclvar(vn);
182 else
183 FATAL("invalid -v option argument: %s", vn);
Brian Kernighan87b94932012-12-22 10:35:39 -0500184 break;
185 case 'd':
186 dbg = atoi(&argv[1][2]);
187 if (dbg == 0)
188 dbg = 1;
189 printf("awk %s\n", version);
190 break;
191 default:
192 WARNING("unknown option %s ignored", argv[1]);
193 break;
194 }
195 argc--;
196 argv++;
197 }
198 /* argv[1] is now the first argument */
199 if (npfile == 0) { /* no -f; first argument is program */
200 if (argc <= 1) {
201 if (dbg)
202 exit(0);
203 FATAL("no program given");
204 }
205 dprintf( ("program = |%s|\n", argv[1]) );
206 lexprog = argv[1];
207 argc--;
208 argv++;
209 }
210 recinit(recsize);
211 syminit();
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200212 compile_time = COMPILING;
Brian Kernighan87b94932012-12-22 10:35:39 -0500213 argv[0] = cmdname; /* put prog name at front of arglist */
214 dprintf( ("argc=%d, argv[0]=%s\n", argc, argv[0]) );
215 arginit(argc, argv);
216 if (!safe)
217 envinit(environ);
218 yyparse();
219 setlocale(LC_NUMERIC, ""); /* back to whatever it is locally */
220 if (fs)
221 *FS = qstring(fs, '\0');
222 dprintf( ("errorflag=%d\n", errorflag) );
223 if (errorflag == 0) {
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200224 compile_time = RUNNING;
Brian Kernighan87b94932012-12-22 10:35:39 -0500225 run(winner);
226 } else
227 bracecheck();
228 return(errorflag);
229}
230
231int pgetc(void) /* get 1 character from awk program */
232{
233 int c;
234
235 for (;;) {
236 if (yyin == NULL) {
237 if (curpfile >= npfile)
238 return EOF;
239 if (strcmp(pfile[curpfile], "-") == 0)
240 yyin = stdin;
241 else if ((yyin = fopen(pfile[curpfile], "r")) == NULL)
242 FATAL("can't open file %s", pfile[curpfile]);
243 lineno = 1;
244 }
245 if ((c = getc(yyin)) != EOF)
246 return c;
247 if (yyin != stdin)
248 fclose(yyin);
249 yyin = NULL;
250 curpfile++;
251 }
252}
253
254char *cursource(void) /* current source file name */
255{
256 if (npfile > 0)
257 return pfile[curpfile];
258 else
259 return NULL;
260}