const char *version = "version 20250116";
#define DEBUG
#include <stdio.h>
#include <ctype.h>
#include <locale.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include "awk.h"
extern char *__progname;
extern char **environ;
extern int nfields;
int dbg = 0;
Awkfloat srand_seed = 1;
char *cmdname;
extern FILE *yyin;
char *lexprog;
extern int errorflag;
enum compile_states compile_time = ERROR_PRINTING;
static char **pfile;
static size_t maxpfile;
static size_t npfile;
static size_t curpfile;
bool CSV = false;
bool safe = false;
bool do_posix = false;
size_t awk_mb_cur_max = 1;
static noreturn void fpecatch(int n
#ifdef SA_SIGINFO
, siginfo_t *si, void *uc
#endif
)
{
extern Node *curnode;
#ifdef SA_SIGINFO
const char *mesg = NULL;
switch (si->si_code) {
case FPE_INTDIV:
mesg = "Integer divide by zero";
break;
case FPE_INTOVF:
mesg = "Integer overflow";
break;
case FPE_FLTDIV:
mesg = "Floating point divide by zero";
break;
case FPE_FLTOVF:
mesg = "Floating point overflow";
break;
case FPE_FLTUND:
mesg = "Floating point underflow";
break;
case FPE_FLTRES:
mesg = "Floating point inexact result";
break;
case FPE_FLTINV:
mesg = "Invalid Floating point operation";
break;
case FPE_FLTSUB:
mesg = "Subscript out of range";
break;
case 0:
default:
mesg = "Unknown error";
break;
}
#endif
dprintf(STDERR_FILENO, "floating point exception%s%s\n",
#ifdef SA_SIGINFO
": ", mesg
#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)
abort();
_exit(2);
}
static const char *
setfs(char *p)
{
if (p[0] == 't' && p[1] == '\0')
return "\t";
return p;
}
static char *
getarg(int *argc, char ***argv, const char *msg)
{
if ((*argv)[1][2] != '\0') {
return &(*argv)[1][2];
} else {
(*argc)--; (*argv)++;
if (*argc <= 1)
FATAL("%s", msg);
return (*argv)[1];
}
}
int main(int argc, char *argv[])
{
const char *fs = NULL;
char *fn, *vn;
setlocale(LC_CTYPE, "");
setlocale(LC_NUMERIC, "C");
awk_mb_cur_max = MB_CUR_MAX;
cmdname = __progname;
if (argc == 1) {
fprintf(stderr, "usage: %s [-safe] [-V] [-d[n]] "
"[-f fs | --csv] [-v var=value]\n"
"\t [prog | -f progfile] file ...\n", cmdname);
return 1;
}
#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
do_posix = (getenv("POSIXLY_CORRECT") != NULL);
yyin = NULL;
symtab = makesymtab(NSYMTAB);
while (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') {
if (strcmp(argv[1], "--version") == 0) {
printf("awk %s\n", version);
return 0;
}
if (strcmp(argv[1], "--") == 0) {
argc--;
argv++;
break;
}
if (strcmp(argv[1], "--csv") == 0) {
CSV = true;
argc--;
argv++;
continue;
}
switch (argv[1][1]) {
case 's':
if (strcmp(argv[1], "-safe") == 0)
safe = true;
break;
case 'f':
fn = getarg(&argc, &argv, "no program filename");
if (npfile >= maxpfile) {
maxpfile += 20;
pfile = (char **) reallocarray(pfile, maxpfile, sizeof(*pfile));
if (pfile == NULL)
FATAL("error allocating space for -f options");
}
pfile[npfile++] = fn;
break;
case 'F':
fs = setfs(getarg(&argc, &argv, "no field separator"));
break;
case 'v':
vn = getarg(&argc, &argv, "no variable name");
if (isclvar(vn))
setclvar(vn);
else
FATAL("invalid -v option argument: %s", vn);
break;
case 'd':
dbg = atoi(&argv[1][2]);
if (dbg == 0)
dbg = 1;
printf("awk %s\n", version);
break;
case 'V':
printf("awk %s\n", version);
return 0;
default:
WARNING("unknown option %s ignored", argv[1]);
break;
}
argc--;
argv++;
}
if (safe) {
if (unveil("/", "r") == -1) {
fprintf(stderr, "%s: unveil: / r\n",
cmdname);
exit(1);
}
if (unveil("/dev/null", "rw") == -1) {
fprintf(stderr, "%s: unveil: /dev/null rw\n",
cmdname);
exit(1);
}
if (pledge("stdio rpath wpath", NULL) == -1) {
fprintf(stderr, "%s: pledge: incorrect arguments\n",
cmdname);
exit(1);
}
} else {
if (pledge("stdio rpath wpath cpath proc exec", NULL) == -1) {
fprintf(stderr, "%s: pledge: incorrect arguments\n",
cmdname);
exit(1);
}
}
if (CSV && (fs != NULL || lookup("FS", symtab) != NULL))
WARNING("danger: don't set FS when --csv is in effect");
if (npfile == 0) {
if (argc <= 1) {
if (dbg)
exit(0);
FATAL("no program given");
}
DPRINTF("program = |%s|\n", argv[1]);
lexprog = argv[1];
argc--;
argv++;
}
recinit(recsize);
syminit();
compile_time = COMPILING;
argv[0] = cmdname;
DPRINTF("argc=%d, argv[0]=%s\n", argc, argv[0]);
arginit(argc, argv);
if (!safe)
envinit(environ);
yyparse();
#if 0
setlocale(LC_NUMERIC, "");
#endif
if (fs)
*FS = qstring(fs, '\0');
DPRINTF("errorflag=%d\n", errorflag);
if (errorflag == 0) {
compile_time = RUNNING;
run(winner);
} else
bracecheck();
return(errorflag);
}
int pgetc(void)
{
int c;
for (;;) {
if (yyin == NULL) {
if (curpfile >= npfile)
return EOF;
if (strcmp(pfile[curpfile], "-") == 0)
yyin = stdin;
else if ((yyin = fopen(pfile[curpfile], "r")) == NULL)
FATAL("can't open file %s", pfile[curpfile]);
lineno = 1;
}
if ((c = getc(yyin)) != EOF)
return c;
if (yyin != stdin)
fclose(yyin);
yyin = NULL;
curpfile++;
}
}
char *cursource(void)
{
if (npfile > 0)
return pfile[curpfile < npfile ? curpfile : curpfile - 1];
else
return NULL;
}