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