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 } 258