version 1.36, 2020/06/10 21:05:02 |
version 1.37, 2020/06/10 21:05:50 |
|
|
THIS SOFTWARE. |
THIS SOFTWARE. |
****************************************************************/ |
****************************************************************/ |
|
|
const char *version = "version 20200131"; |
const char *version = "version 20200228"; |
|
|
#define DEBUG |
#define DEBUG |
#include <stdio.h> |
#include <stdio.h> |
|
|
extern int errorflag; /* non-zero if any syntax errors; set by yyerror */ |
extern int errorflag; /* non-zero if any syntax errors; set by yyerror */ |
enum compile_states compile_time = ERROR_PRINTING; |
enum compile_states compile_time = ERROR_PRINTING; |
|
|
#define MAX_PFILE 20 /* max number of -f's */ |
static char **pfile; /* program filenames from -f's */ |
|
static size_t maxpfile; /* max program filename */ |
|
static size_t npfile; /* number of filenames */ |
|
static size_t curpfile; /* current filename */ |
|
|
char *pfile[MAX_PFILE]; /* program filenames from -f's */ |
|
int npfile = 0; /* number of filenames */ |
|
int curpfile = 0; /* current filename */ |
|
|
|
bool safe = false; /* true => "safe" mode */ |
bool safe = false; /* true => "safe" mode */ |
|
|
|
static __attribute__((__noreturn__)) void fpecatch(int n |
|
#ifdef SA_SIGINFO |
|
, siginfo_t *si, void *uc |
|
#endif |
|
) |
|
{ |
|
extern Node *curnode; |
|
#ifdef SA_SIGINFO |
|
static const char *emsg[] = { |
|
[0] = "Unknown error", |
|
[FPE_INTDIV] = "Integer divide by zero", |
|
[FPE_INTOVF] = "Integer overflow", |
|
[FPE_FLTDIV] = "Floating point divide by zero", |
|
[FPE_FLTOVF] = "Floating point overflow", |
|
[FPE_FLTUND] = "Floating point underflow", |
|
[FPE_FLTRES] = "Floating point inexact result", |
|
[FPE_FLTINV] = "Invalid Floating point operation", |
|
[FPE_FLTSUB] = "Subscript out of range", |
|
}; |
|
#endif |
|
dprintf(STDERR_FILENO, "floating point exception%s%s\n", |
|
#ifdef SA_SIGINFO |
|
": ", (size_t)si->si_code < sizeof(emsg) / sizeof(emsg[0]) && |
|
emsg[si->si_code] ? emsg[si->si_code] : emsg[0] |
|
#else |
|
"", "" |
|
#endif |
|
); |
|
|
|
if (compile_time != 2 && NR && *NR > 0) { |
|
dprintf(STDERR_FILENO, " input record number %d", (int) (*FNR)); |
|
if (strcmp(*FILENAME, "-") != 0) { |
|
dprintf(STDERR_FILENO, ", file %s", *FILENAME); |
|
} |
|
dprintf(STDERR_FILENO, "\n"); |
|
} |
|
if (compile_time != 2 && curnode) { |
|
dprintf(STDERR_FILENO, " source line number %d", curnode->lineno); |
|
} else if (compile_time != 2 && lineno) { |
|
dprintf(STDERR_FILENO, " source line number %d", lineno); |
|
} |
|
if (compile_time == 1 && cursource() != NULL) { |
|
dprintf(STDERR_FILENO, " source file %s", cursource()); |
|
} |
|
dprintf(STDERR_FILENO, "\n"); |
|
if (dbg > 1) /* core dump if serious debugging on */ |
|
abort(); |
|
_exit(2); |
|
} |
|
|
|
static const char * |
|
setfs(char *p) |
|
{ |
|
/* wart: t=>\t */ |
|
if (p[0] == 't' && p[1] == '\0') |
|
return "\t"; |
|
else if (p[0] != '\0') |
|
return p; |
|
return NULL; |
|
} |
|
|
|
static char * |
|
getarg(int *argc, char ***argv, const char *msg) |
|
{ |
|
if ((*argv)[1][2] != '\0') { /* arg is -fsomething */ |
|
return &(*argv)[1][2]; |
|
} else { /* arg is -f something */ |
|
(*argc)--; (*argv)++; |
|
if (*argc <= 1) |
|
FATAL("%s", msg); |
|
return (*argv)[1]; |
|
} |
|
} |
|
|
int main(int argc, char *argv[]) |
int main(int argc, char *argv[]) |
{ |
{ |
const char *fs = NULL; |
const char *fs = NULL; |
|
char *fn, *vn; |
|
|
setlocale(LC_ALL, ""); |
setlocale(LC_ALL, ""); |
setlocale(LC_NUMERIC, "C"); /* for parsing cmdline & prog */ |
setlocale(LC_NUMERIC, "C"); /* for parsing cmdline & prog */ |
|
|
cmdname); |
cmdname); |
exit(1); |
exit(1); |
} |
} |
signal(SIGFPE, fpecatch); |
#ifdef SA_SIGINFO |
|
{ |
|
struct sigaction sa; |
|
sa.sa_sigaction = fpecatch; |
|
sa.sa_flags = SA_SIGINFO; |
|
sigemptyset(&sa.sa_mask); |
|
(void)sigaction(SIGFPE, &sa, NULL); |
|
} |
|
#else |
|
(void)signal(SIGFPE, fpecatch); |
|
#endif |
|
|
yyin = NULL; |
yyin = NULL; |
symtab = makesymtab(NSYMTAB); |
symtab = makesymtab(NSYMTAB); |
|
|
safe = true; |
safe = true; |
break; |
break; |
case 'f': /* next argument is program filename */ |
case 'f': /* next argument is program filename */ |
if (argv[1][2] != 0) { /* arg is -fsomething */ |
fn = getarg(&argc, &argv, "no program filename"); |
if (npfile >= MAX_PFILE - 1) |
if (npfile >= maxpfile) { |
FATAL("too many -f options"); |
maxpfile += 20; |
pfile[npfile++] = &argv[1][2]; |
pfile = realloc(pfile, maxpfile * sizeof(*pfile)); |
} else { /* arg is -f something */ |
if (pfile == NULL) |
argc--; argv++; |
FATAL("error allocating space for -f options"); |
if (argc <= 1) |
} |
FATAL("no program filename"); |
pfile[npfile++] = fn; |
if (npfile >= MAX_PFILE - 1) |
break; |
FATAL("too many -f options"); |
|
pfile[npfile++] = argv[1]; |
|
} |
|
break; |
|
case 'F': /* set field separator */ |
case 'F': /* set field separator */ |
if (argv[1][2] != 0) { /* arg is -Fsomething */ |
fs = setfs(getarg(&argc, &argv, "no field separator")); |
if (argv[1][2] == 't' && argv[1][3] == 0) /* wart: t=>\t */ |
if (fs == NULL) |
fs = "\t"; |
|
else if (argv[1][2] != 0) |
|
fs = &argv[1][2]; |
|
} else { /* arg is -F something */ |
|
argc--; argv++; |
|
if (argc > 1 && argv[1][0] == 't' && argv[1][1] == 0) /* wart: t=>\t */ |
|
fs = "\t"; |
|
else if (argc > 1 && argv[1][0] != 0) |
|
fs = &argv[1][0]; |
|
} |
|
if (fs == NULL || *fs == '\0') |
|
WARNING("field separator FS is empty"); |
WARNING("field separator FS is empty"); |
break; |
break; |
case 'v': /* -v a=1 to be done NOW. one -v for each */ |
case 'v': /* -v a=1 to be done NOW. one -v for each */ |
if (argv[1][2] != 0) { /* arg is -vsomething */ |
vn = getarg(&argc, &argv, "no variable name"); |
if (isclvar(&argv[1][2])) |
if (isclvar(vn)) |
setclvar(&argv[1][2]); |
setclvar(vn); |
else |
else |
FATAL("invalid -v option argument: %s", &argv[1][2]); |
FATAL("invalid -v option argument: %s", vn); |
} else { /* arg is -v something */ |
|
argc--; argv++; |
|
if (argc <= 1) |
|
FATAL("no variable name"); |
|
if (isclvar(argv[1])) |
|
setclvar(argv[1]); |
|
else |
|
FATAL("invalid -v option argument: %s", argv[1]); |
|
} |
|
break; |
break; |
case 'd': |
case 'd': |
dbg = atoi(&argv[1][2]); |
dbg = atoi(&argv[1][2]); |
|
|
if (!safe) |
if (!safe) |
envinit(environ); |
envinit(environ); |
yyparse(); |
yyparse(); |
|
#if 0 |
|
// Doing this would comply with POSIX, but is not compatible with |
|
// other awks and with what most users expect. So comment it out. |
setlocale(LC_NUMERIC, ""); /* back to whatever it is locally */ |
setlocale(LC_NUMERIC, ""); /* back to whatever it is locally */ |
|
#endif |
if (fs) |
if (fs) |
*FS = qstring(fs, '\0'); |
*FS = qstring(fs, '\0'); |
DPRINTF( ("errorflag=%d\n", errorflag) ); |
DPRINTF( ("errorflag=%d\n", errorflag) ); |