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