1 /* $OpenBSD: main.c,v 1.45 2020/08/11 16:57:05 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 20200807"; 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 else if (p[0] != '\0') 115 return p; 116 return NULL; 117 } 118 119 static char * 120 getarg(int *argc, char ***argv, const char *msg) 121 { 122 if ((*argv)[1][2] != '\0') { /* arg is -fsomething */ 123 return &(*argv)[1][2]; 124 } else { /* arg is -f something */ 125 (*argc)--; (*argv)++; 126 if (*argc <= 1) 127 FATAL("%s", msg); 128 return (*argv)[1]; 129 } 130 } 131 132 int main(int argc, char *argv[]) 133 { 134 const char *fs = NULL; 135 char *fn, *vn; 136 137 setlocale(LC_CTYPE, ""); 138 setlocale(LC_NUMERIC, "C"); /* for parsing cmdline & prog */ 139 140 cmdname = __progname; 141 if (pledge("stdio rpath wpath cpath proc exec", NULL) == -1) { 142 fprintf(stderr, "%s: pledge: incorrect arguments\n", 143 cmdname); 144 exit(1); 145 } 146 147 if (argc == 1) { 148 fprintf(stderr, "usage: %s [-safe] [-V] [-d[n]] [-F fs] " 149 "[-v var=value] [prog | -f progfile]\n\tfile ...\n", 150 cmdname); 151 exit(1); 152 } 153 #ifdef SA_SIGINFO 154 { 155 struct sigaction sa; 156 sa.sa_sigaction = fpecatch; 157 sa.sa_flags = SA_SIGINFO; 158 sigemptyset(&sa.sa_mask); 159 (void)sigaction(SIGFPE, &sa, NULL); 160 } 161 #else 162 (void)signal(SIGFPE, fpecatch); 163 #endif 164 165 do_posix = (getenv("POSIXLY_CORRECT") != NULL); 166 167 yyin = NULL; 168 symtab = makesymtab(NSYMTAB); 169 while (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') { 170 if (strcmp(argv[1], "--") == 0) { /* explicit end of args */ 171 argc--; 172 argv++; 173 break; 174 } 175 switch (argv[1][1]) { 176 case 's': 177 if (strcmp(argv[1], "-safe") == 0) 178 safe = true; 179 break; 180 case 'f': /* next argument is program filename */ 181 fn = getarg(&argc, &argv, "no program filename"); 182 if (npfile >= maxpfile) { 183 maxpfile += 20; 184 pfile = realloc(pfile, maxpfile * sizeof(*pfile)); 185 if (pfile == NULL) 186 FATAL("error allocating space for -f options"); 187 } 188 pfile[npfile++] = fn; 189 break; 190 case 'F': /* set field separator */ 191 fs = setfs(getarg(&argc, &argv, "no field separator")); 192 if (fs == NULL) 193 WARNING("field separator FS is empty"); 194 break; 195 case 'v': /* -v a=1 to be done NOW. one -v for each */ 196 vn = getarg(&argc, &argv, "no variable name"); 197 if (isclvar(vn)) 198 setclvar(vn); 199 else 200 FATAL("invalid -v option argument: %s", vn); 201 break; 202 case 'd': 203 dbg = atoi(&argv[1][2]); 204 if (dbg == 0) 205 dbg = 1; 206 printf("awk %s\n", version); 207 break; 208 case 'V': /* added for exptools "standard" */ 209 printf("awk %s\n", version); 210 exit(0); 211 break; 212 default: 213 WARNING("unknown option %s ignored", argv[1]); 214 break; 215 } 216 argc--; 217 argv++; 218 } 219 220 if (safe) { 221 if (pledge("stdio rpath", NULL) == -1) { 222 fprintf(stderr, "%s: pledge: incorrect arguments\n", 223 cmdname); 224 exit(1); 225 } 226 } 227 228 /* argv[1] is now the first argument */ 229 if (npfile == 0) { /* no -f; first argument is program */ 230 if (argc <= 1) { 231 if (dbg) 232 exit(0); 233 FATAL("no program given"); 234 } 235 DPRINTF("program = |%s|\n", argv[1]); 236 lexprog = argv[1]; 237 argc--; 238 argv++; 239 } 240 recinit(recsize); 241 syminit(); 242 compile_time = COMPILING; 243 argv[0] = cmdname; /* put prog name at front of arglist */ 244 DPRINTF("argc=%d, argv[0]=%s\n", argc, argv[0]); 245 arginit(argc, argv); 246 if (!safe) 247 envinit(environ); 248 yyparse(); 249 #if 0 250 // Doing this would comply with POSIX, but is not compatible with 251 // other awks and with what most users expect. So comment it out. 252 setlocale(LC_NUMERIC, ""); /* back to whatever it is locally */ 253 #endif 254 if (fs) 255 *FS = qstring(fs, '\0'); 256 DPRINTF("errorflag=%d\n", errorflag); 257 if (errorflag == 0) { 258 compile_time = RUNNING; 259 run(winner); 260 } else 261 bracecheck(); 262 return(errorflag); 263 } 264 265 int pgetc(void) /* get 1 character from awk program */ 266 { 267 int c; 268 269 for (;;) { 270 if (yyin == NULL) { 271 if (curpfile >= npfile) 272 return EOF; 273 if (strcmp(pfile[curpfile], "-") == 0) 274 yyin = stdin; 275 else if ((yyin = fopen(pfile[curpfile], "r")) == NULL) 276 FATAL("can't open file %s", pfile[curpfile]); 277 lineno = 1; 278 } 279 if ((c = getc(yyin)) != EOF) 280 return c; 281 if (yyin != stdin) 282 fclose(yyin); 283 yyin = NULL; 284 curpfile++; 285 } 286 } 287 288 char *cursource(void) /* current source file name */ 289 { 290 if (npfile > 0) 291 return pfile[curpfile < npfile ? curpfile : curpfile - 1]; 292 else 293 return NULL; 294 } 295