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