Annotation of src/usr.bin/awk/main.c, Revision 1.64
1.64 ! millert 1: /* $OpenBSD: main.c,v 1.63 2023/10/06 22:29:24 millert Exp $ */
1.1 tholo 2: /****************************************************************
1.4 kstailey 3: Copyright (C) Lucent Technologies 1997
1.1 tholo 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
1.4 kstailey 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.
1.1 tholo 24: ****************************************************************/
25:
1.64 ! millert 26: const char *version = "version 20231030";
1.1 tholo 27:
28: #define DEBUG
29: #include <stdio.h>
30: #include <ctype.h>
1.3 millert 31: #include <locale.h>
1.1 tholo 32: #include <stdlib.h>
33: #include <string.h>
34: #include <signal.h>
1.18 doug 35: #include <unistd.h>
1.1 tholo 36: #include "awk.h"
37:
1.64 ! millert 38: extern char *__progname;
1.1 tholo 39: extern char **environ;
40: extern int nfields;
41:
42: int dbg = 0;
1.17 millert 43: Awkfloat srand_seed = 1;
1.1 tholo 44: char *cmdname; /* gets argv[0] for error messages */
45: extern FILE *yyin; /* lex input file */
46: char *lexprog; /* points to program argument if it exists */
47: extern int errorflag; /* non-zero if any syntax errors; set by yyerror */
1.34 millert 48: enum compile_states compile_time = ERROR_PRINTING;
1.1 tholo 49:
1.37 millert 50: static char **pfile; /* program filenames from -f's */
51: static size_t maxpfile; /* max program filename */
52: static size_t npfile; /* number of filenames */
53: static size_t curpfile; /* current filename */
1.15 millert 54:
1.59 millert 55: bool CSV = false; /* true for csv input */
1.40 millert 56: bool safe = false; /* true => "safe" mode */
57: bool do_posix = false; /* true => POSIX mode */
1.37 millert 58:
1.61 millert 59: size_t awk_mb_cur_max = 1;
60:
1.38 millert 61: static noreturn void fpecatch(int n
1.37 millert 62: #ifdef SA_SIGINFO
63: , siginfo_t *si, void *uc
64: #endif
65: )
66: {
67: extern Node *curnode;
68: #ifdef SA_SIGINFO
69: static const char *emsg[] = {
70: [0] = "Unknown error",
71: [FPE_INTDIV] = "Integer divide by zero",
72: [FPE_INTOVF] = "Integer overflow",
73: [FPE_FLTDIV] = "Floating point divide by zero",
74: [FPE_FLTOVF] = "Floating point overflow",
75: [FPE_FLTUND] = "Floating point underflow",
76: [FPE_FLTRES] = "Floating point inexact result",
77: [FPE_FLTINV] = "Invalid Floating point operation",
78: [FPE_FLTSUB] = "Subscript out of range",
79: };
80: #endif
81: dprintf(STDERR_FILENO, "floating point exception%s%s\n",
82: #ifdef SA_SIGINFO
83: ": ", (size_t)si->si_code < sizeof(emsg) / sizeof(emsg[0]) &&
84: emsg[si->si_code] ? emsg[si->si_code] : emsg[0]
85: #else
86: "", ""
87: #endif
88: );
89:
90: if (compile_time != 2 && NR && *NR > 0) {
91: dprintf(STDERR_FILENO, " input record number %d", (int) (*FNR));
92: if (strcmp(*FILENAME, "-") != 0) {
93: dprintf(STDERR_FILENO, ", file %s", *FILENAME);
94: }
95: dprintf(STDERR_FILENO, "\n");
96: }
97: if (compile_time != 2 && curnode) {
98: dprintf(STDERR_FILENO, " source line number %d", curnode->lineno);
99: } else if (compile_time != 2 && lineno) {
100: dprintf(STDERR_FILENO, " source line number %d", lineno);
101: }
102: if (compile_time == 1 && cursource() != NULL) {
103: dprintf(STDERR_FILENO, " source file %s", cursource());
104: }
105: dprintf(STDERR_FILENO, "\n");
106: if (dbg > 1) /* core dump if serious debugging on */
107: abort();
108: _exit(2);
109: }
1.1 tholo 110:
1.37 millert 111: static const char *
112: setfs(char *p)
113: {
114: /* wart: t=>\t */
115: if (p[0] == 't' && p[1] == '\0')
116: return "\t";
1.48 millert 117: return p;
1.37 millert 118: }
119:
120: static char *
121: getarg(int *argc, char ***argv, const char *msg)
122: {
123: if ((*argv)[1][2] != '\0') { /* arg is -fsomething */
124: return &(*argv)[1][2];
125: } else { /* arg is -f something */
126: (*argc)--; (*argv)++;
127: if (*argc <= 1)
128: FATAL("%s", msg);
129: return (*argv)[1];
130: }
131: }
1.4 kstailey 132:
1.1 tholo 133: int main(int argc, char *argv[])
134: {
1.12 millert 135: const char *fs = NULL;
1.37 millert 136: char *fn, *vn;
1.2 tholo 137:
1.39 millert 138: setlocale(LC_CTYPE, "");
1.19 deraadt 139: setlocale(LC_NUMERIC, "C"); /* for parsing cmdline & prog */
1.61 millert 140: awk_mb_cur_max = MB_CUR_MAX;
1.64 ! millert 141: cmdname = __progname;
1.19 deraadt 142:
1.18 doug 143: if (pledge("stdio rpath wpath cpath proc exec", NULL) == -1) {
144: fprintf(stderr, "%s: pledge: incorrect arguments\n",
145: cmdname);
146: exit(1);
147: }
148:
1.1 tholo 149: if (argc == 1) {
1.60 jmc 150: fprintf(stderr, "usage: %s [-safe] [-V] [-d[n]] "
151: "[-f fs | --csv] [-v var=value]\n"
1.64 ! millert 152: "\t [prog | -f progfile] file ...\n", cmdname);
! 153: return 1;
1.1 tholo 154: }
1.37 millert 155: #ifdef SA_SIGINFO
156: {
157: struct sigaction sa;
158: sa.sa_sigaction = fpecatch;
159: sa.sa_flags = SA_SIGINFO;
160: sigemptyset(&sa.sa_mask);
161: (void)sigaction(SIGFPE, &sa, NULL);
162: }
163: #else
164: (void)signal(SIGFPE, fpecatch);
165: #endif
1.40 millert 166:
167: do_posix = (getenv("POSIXLY_CORRECT") != NULL);
1.17 millert 168:
1.1 tholo 169: yyin = NULL;
170: symtab = makesymtab(NSYMTAB);
171: while (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') {
1.62 millert 172: if (strcmp(argv[1], "--version") == 0) {
173: printf("awk %s\n", version);
174: return 0;
175: }
1.4 kstailey 176: if (strcmp(argv[1], "--") == 0) { /* explicit end of args */
1.1 tholo 177: argc--;
178: argv++;
179: break;
180: }
1.59 millert 181: if (strcmp(argv[1], "--csv") == 0) { /* turn on csv input processing */
182: CSV = true;
183: argc--;
184: argv++;
185: continue;
186: }
1.1 tholo 187: switch (argv[1][1]) {
1.4 kstailey 188: case 's':
189: if (strcmp(argv[1], "-safe") == 0)
1.34 millert 190: safe = true;
1.4 kstailey 191: break;
1.1 tholo 192: case 'f': /* next argument is program filename */
1.37 millert 193: fn = getarg(&argc, &argv, "no program filename");
194: if (npfile >= maxpfile) {
195: maxpfile += 20;
1.59 millert 196: pfile = (char **) reallocarray(pfile, maxpfile, sizeof(*pfile));
1.37 millert 197: if (pfile == NULL)
198: FATAL("error allocating space for -f options");
199: }
200: pfile[npfile++] = fn;
201: break;
1.1 tholo 202: case 'F': /* set field separator */
1.37 millert 203: fs = setfs(getarg(&argc, &argv, "no field separator"));
1.1 tholo 204: break;
205: case 'v': /* -v a=1 to be done NOW. one -v for each */
1.37 millert 206: vn = getarg(&argc, &argv, "no variable name");
207: if (isclvar(vn))
208: setclvar(vn);
209: else
210: FATAL("invalid -v option argument: %s", vn);
1.1 tholo 211: break;
212: case 'd':
213: dbg = atoi(&argv[1][2]);
214: if (dbg == 0)
215: dbg = 1;
216: printf("awk %s\n", version);
1.6 millert 217: break;
1.64 ! millert 218: case 'V':
1.6 millert 219: printf("awk %s\n", version);
1.62 millert 220: return 0;
1.1 tholo 221: default:
1.9 millert 222: WARNING("unknown option %s ignored", argv[1]);
1.1 tholo 223: break;
224: }
225: argc--;
226: argv++;
227: }
1.18 doug 228:
229: if (safe) {
230: if (pledge("stdio rpath", NULL) == -1) {
231: fprintf(stderr, "%s: pledge: incorrect arguments\n",
232: cmdname);
233: exit(1);
234: }
235: }
236:
1.1 tholo 237: /* argv[1] is now the first argument */
238: if (npfile == 0) { /* no -f; first argument is program */
239: if (argc <= 1) {
240: if (dbg)
241: exit(0);
1.9 millert 242: FATAL("no program given");
1.1 tholo 243: }
1.42 millert 244: DPRINTF("program = |%s|\n", argv[1]);
1.1 tholo 245: lexprog = argv[1];
246: argc--;
247: argv++;
248: }
249: recinit(recsize);
250: syminit();
1.34 millert 251: compile_time = COMPILING;
1.1 tholo 252: argv[0] = cmdname; /* put prog name at front of arglist */
1.42 millert 253: DPRINTF("argc=%d, argv[0]=%s\n", argc, argv[0]);
1.1 tholo 254: arginit(argc, argv);
1.4 kstailey 255: if (!safe)
256: envinit(environ);
1.1 tholo 257: yyparse();
1.37 millert 258: #if 0
259: // Doing this would comply with POSIX, but is not compatible with
260: // other awks and with what most users expect. So comment it out.
1.13 millert 261: setlocale(LC_NUMERIC, ""); /* back to whatever it is locally */
1.37 millert 262: #endif
1.1 tholo 263: if (fs)
1.4 kstailey 264: *FS = qstring(fs, '\0');
1.42 millert 265: DPRINTF("errorflag=%d\n", errorflag);
1.1 tholo 266: if (errorflag == 0) {
1.34 millert 267: compile_time = RUNNING;
1.1 tholo 268: run(winner);
269: } else
270: bracecheck();
271: return(errorflag);
272: }
273:
274: int pgetc(void) /* get 1 character from awk program */
275: {
276: int c;
277:
278: for (;;) {
279: if (yyin == NULL) {
280: if (curpfile >= npfile)
281: return EOF;
1.4 kstailey 282: if (strcmp(pfile[curpfile], "-") == 0)
1.1 tholo 283: yyin = stdin;
1.4 kstailey 284: else if ((yyin = fopen(pfile[curpfile], "r")) == NULL)
1.9 millert 285: FATAL("can't open file %s", pfile[curpfile]);
1.7 millert 286: lineno = 1;
1.1 tholo 287: }
288: if ((c = getc(yyin)) != EOF)
289: return c;
290: if (yyin != stdin)
291: fclose(yyin);
292: yyin = NULL;
293: curpfile++;
294: }
1.7 millert 295: }
296:
297: char *cursource(void) /* current source file name */
298: {
299: if (npfile > 0)
1.44 millert 300: return pfile[curpfile < npfile ? curpfile : curpfile - 1];
1.7 millert 301: else
302: return NULL;
1.1 tholo 303: }