libedit: Adjustments after the import
[dragonfly.git] / contrib / awk / main.c
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 const char      *version = "version 20220912";
26
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
36 extern  char    **environ;
37 extern  int     nfields;
38
39 int     dbg     = 0;
40 Awkfloat        srand_seed = 1;
41 char    *cmdname;       /* gets argv[0] for error messages */
42 extern  FILE    *yyin;  /* lex input file */
43 char    *lexprog;       /* points to program argument if it exists */
44 extern  int errorflag;  /* non-zero if any syntax errors; set by yyerror */
45 enum compile_states     compile_time = ERROR_PRINTING;
46
47 static char     **pfile;        /* program filenames from -f's */
48 static size_t   maxpfile;       /* max program filename */
49 static size_t   npfile;         /* number of filenames */
50 static size_t   curpfile;       /* current filename */
51
52 bool    safe = false;   /* true => "safe" mode */
53
54 static noreturn void fpecatch(int n
55 #ifdef SA_SIGINFO
56         , siginfo_t *si, void *uc
57 #endif
58 )
59 {
60 #ifdef SA_SIGINFO
61         static const char *emsg[] = {
62                 [0] = "Unknown error",
63                 [FPE_INTDIV] = "Integer divide by zero",
64                 [FPE_INTOVF] = "Integer overflow",
65                 [FPE_FLTDIV] = "Floating point divide by zero",
66                 [FPE_FLTOVF] = "Floating point overflow",
67                 [FPE_FLTUND] = "Floating point underflow",
68                 [FPE_FLTRES] = "Floating point inexact result",
69                 [FPE_FLTINV] = "Invalid Floating point operation",
70                 [FPE_FLTSUB] = "Subscript out of range",
71         };
72 #endif
73         FATAL("floating point exception"
74 #ifdef SA_SIGINFO
75                 ": %s", (size_t)si->si_code < sizeof(emsg) / sizeof(emsg[0]) &&
76                 emsg[si->si_code] ? emsg[si->si_code] : emsg[0]
77 #endif
78             );
79 }
80
81 /* Can this work with recursive calls?  I don't think so.
82 void segvcatch(int n)
83 {
84         FATAL("segfault.  Do you have an unbounded recursive call?", n);
85 }
86 */
87
88 static const char *
89 setfs(char *p)
90 {
91         /* wart: t=>\t */
92         if (p[0] == 't' && p[1] == '\0')
93                 return "\t";
94         return p;
95 }
96
97 static char *
98 getarg(int *argc, char ***argv, const char *msg)
99 {
100         if ((*argv)[1][2] != '\0') {    /* arg is -fsomething */
101                 return &(*argv)[1][2];
102         } else {                        /* arg is -f something */
103                 (*argc)--; (*argv)++;
104                 if (*argc <= 1)
105                         FATAL("%s", msg);
106                 return (*argv)[1];
107         }
108 }
109
110 int main(int argc, char *argv[])
111 {
112         const char *fs = NULL;
113         char *fn, *vn;
114
115         setlocale(LC_CTYPE, "");
116         setlocale(LC_NUMERIC, "C"); /* for parsing cmdline & prog */
117         cmdname = argv[0];
118         if (argc == 1) {
119                 fprintf(stderr,
120                   "usage: %s [-F fs] [-v var=value] [-f progfile | 'prog'] [file ...]\n",
121                   cmdname);
122                 exit(1);
123         }
124 #ifdef SA_SIGINFO
125         {
126                 struct sigaction sa;
127                 sa.sa_sigaction = fpecatch;
128                 sa.sa_flags = SA_SIGINFO;
129                 sigemptyset(&sa.sa_mask);
130                 (void)sigaction(SIGFPE, &sa, NULL);
131         }
132 #else
133         (void)signal(SIGFPE, fpecatch);
134 #endif
135         /*signal(SIGSEGV, segvcatch); experiment */
136
137         /* Set and keep track of the random seed */
138         srand_seed = 1;
139         srandom((unsigned long) srand_seed);
140
141         yyin = NULL;
142         symtab = makesymtab(NSYMTAB/NSYMTAB);
143         while (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') {
144                 if (strcmp(argv[1], "-version") == 0 || strcmp(argv[1], "--version") == 0) {
145                         printf("awk %s\n", version);
146                         return 0;
147                 }
148                 if (strcmp(argv[1], "--") == 0) {       /* explicit end of args */
149                         argc--;
150                         argv++;
151                         break;
152                 }
153                 switch (argv[1][1]) {
154                 case 's':
155                         if (strcmp(argv[1], "-safe") == 0)
156                                 safe = true;
157                         break;
158                 case 'f':       /* next argument is program filename */
159                         fn = getarg(&argc, &argv, "no program filename");
160                         if (npfile >= maxpfile) {
161                                 maxpfile += 20;
162                                 pfile = (char **) realloc(pfile, maxpfile * sizeof(*pfile));
163                                 if (pfile == NULL)
164                                         FATAL("error allocating space for -f options");
165                         }
166                         pfile[npfile++] = fn;
167                         break;
168                 case 'F':       /* set field separator */
169                         fs = setfs(getarg(&argc, &argv, "no field separator"));
170                         break;
171                 case 'v':       /* -v a=1 to be done NOW.  one -v for each */
172                         vn = getarg(&argc, &argv, "no variable name");
173                         if (isclvar(vn))
174                                 setclvar(vn);
175                         else
176                                 FATAL("invalid -v option argument: %s", vn);
177                         break;
178                 case 'd':
179                         dbg = atoi(&argv[1][2]);
180                         if (dbg == 0)
181                                 dbg = 1;
182                         printf("awk %s\n", version);
183                         break;
184                 default:
185                         WARNING("unknown option %s ignored", argv[1]);
186                         break;
187                 }
188                 argc--;
189                 argv++;
190         }
191         /* argv[1] is now the first argument */
192         if (npfile == 0) {      /* no -f; first argument is program */
193                 if (argc <= 1) {
194                         if (dbg)
195                                 exit(0);
196                         FATAL("no program given");
197                 }
198                 DPRINTF("program = |%s|\n", argv[1]);
199                 lexprog = argv[1];
200                 argc--;
201                 argv++;
202         }
203         recinit(recsize);
204         syminit();
205         compile_time = COMPILING;
206         argv[0] = cmdname;      /* put prog name at front of arglist */
207         DPRINTF("argc=%d, argv[0]=%s\n", argc, argv[0]);
208         arginit(argc, argv);
209         if (!safe)
210                 envinit(environ);
211         yyparse();
212 #if 0
213         // Doing this would comply with POSIX, but is not compatible with
214         // other awks and with what most users expect. So comment it out.
215         setlocale(LC_NUMERIC, ""); /* back to whatever it is locally */
216 #endif
217         if (fs)
218                 *FS = qstring(fs, '\0');
219         DPRINTF("errorflag=%d\n", errorflag);
220         if (errorflag == 0) {
221                 compile_time = RUNNING;
222                 run(winner);
223         } else
224                 bracecheck();
225         return(errorflag);
226 }
227
228 int pgetc(void)         /* get 1 character from awk program */
229 {
230         int c;
231
232         for (;;) {
233                 if (yyin == NULL) {
234                         if (curpfile >= npfile)
235                                 return EOF;
236                         if (strcmp(pfile[curpfile], "-") == 0)
237                                 yyin = stdin;
238                         else if ((yyin = fopen(pfile[curpfile], "r")) == NULL)
239                                 FATAL("can't open file %s", pfile[curpfile]);
240                         lineno = 1;
241                 }
242                 if ((c = getc(yyin)) != EOF)
243                         return c;
244                 if (yyin != stdin)
245                         fclose(yyin);
246                 yyin = NULL;
247                 curpfile++;
248         }
249 }
250
251 char *cursource(void)   /* current source file name */
252 {
253         if (npfile > 0)
254                 return pfile[curpfile < npfile ? curpfile : curpfile - 1];
255         else
256                 return NULL;
257 }