14b588458SPeter Avalos /****************************************************************
24b588458SPeter Avalos Copyright (C) Lucent Technologies 1997
34b588458SPeter Avalos All Rights Reserved
44b588458SPeter Avalos
54b588458SPeter Avalos Permission to use, copy, modify, and distribute this software and
64b588458SPeter Avalos its documentation for any purpose and without fee is hereby
74b588458SPeter Avalos granted, provided that the above copyright notice appear in all
84b588458SPeter Avalos copies and that both that the copyright notice and this
94b588458SPeter Avalos permission notice and warranty disclaimer appear in supporting
104b588458SPeter Avalos documentation, and that the name Lucent Technologies or any of
114b588458SPeter Avalos its entities not be used in advertising or publicity pertaining
124b588458SPeter Avalos to distribution of the software without specific, written prior
134b588458SPeter Avalos permission.
144b588458SPeter Avalos
154b588458SPeter Avalos LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
164b588458SPeter Avalos INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
174b588458SPeter Avalos IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
184b588458SPeter Avalos SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
194b588458SPeter Avalos WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
204b588458SPeter Avalos IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
214b588458SPeter Avalos ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
224b588458SPeter Avalos THIS SOFTWARE.
234b588458SPeter Avalos ****************************************************************/
244b588458SPeter Avalos
25*ed569bc2SAaron LI const char *version = "version 20240122";
264b588458SPeter Avalos
274b588458SPeter Avalos #define DEBUG
284b588458SPeter Avalos #include <stdio.h>
294b588458SPeter Avalos #include <ctype.h>
304b588458SPeter Avalos #include <locale.h>
314b588458SPeter Avalos #include <stdlib.h>
324b588458SPeter Avalos #include <string.h>
334b588458SPeter Avalos #include <signal.h>
344b588458SPeter Avalos #include "awk.h"
354b588458SPeter Avalos
364b588458SPeter Avalos extern char **environ;
374b588458SPeter Avalos extern int nfields;
384b588458SPeter Avalos
394b588458SPeter Avalos int dbg = 0;
400020174dSPeter Avalos Awkfloat srand_seed = 1;
414b588458SPeter Avalos char *cmdname; /* gets argv[0] for error messages */
424b588458SPeter Avalos extern FILE *yyin; /* lex input file */
434b588458SPeter Avalos char *lexprog; /* points to program argument if it exists */
444b588458SPeter Avalos extern int errorflag; /* non-zero if any syntax errors; set by yyerror */
451d48fce0SDaniel Fojt enum compile_states compile_time = ERROR_PRINTING;
464b588458SPeter Avalos
471d48fce0SDaniel Fojt static char **pfile; /* program filenames from -f's */
481d48fce0SDaniel Fojt static size_t maxpfile; /* max program filename */
491d48fce0SDaniel Fojt static size_t npfile; /* number of filenames */
501d48fce0SDaniel Fojt static size_t curpfile; /* current filename */
514b588458SPeter Avalos
52*ed569bc2SAaron LI bool CSV = false; /* true for csv input */
53*ed569bc2SAaron LI
541d48fce0SDaniel Fojt bool safe = false; /* true => "safe" mode */
554b588458SPeter Avalos
56*ed569bc2SAaron LI size_t awk_mb_cur_max = 1;
57*ed569bc2SAaron LI
fpecatch(int n,siginfo_t * si,void * uc)581d48fce0SDaniel Fojt static noreturn void fpecatch(int n
591d48fce0SDaniel Fojt #ifdef SA_SIGINFO
601d48fce0SDaniel Fojt , siginfo_t *si, void *uc
611d48fce0SDaniel Fojt #endif
621d48fce0SDaniel Fojt )
631d48fce0SDaniel Fojt {
641d48fce0SDaniel Fojt #ifdef SA_SIGINFO
651d48fce0SDaniel Fojt static const char *emsg[] = {
661d48fce0SDaniel Fojt [0] = "Unknown error",
671d48fce0SDaniel Fojt [FPE_INTDIV] = "Integer divide by zero",
681d48fce0SDaniel Fojt [FPE_INTOVF] = "Integer overflow",
691d48fce0SDaniel Fojt [FPE_FLTDIV] = "Floating point divide by zero",
701d48fce0SDaniel Fojt [FPE_FLTOVF] = "Floating point overflow",
711d48fce0SDaniel Fojt [FPE_FLTUND] = "Floating point underflow",
721d48fce0SDaniel Fojt [FPE_FLTRES] = "Floating point inexact result",
731d48fce0SDaniel Fojt [FPE_FLTINV] = "Invalid Floating point operation",
741d48fce0SDaniel Fojt [FPE_FLTSUB] = "Subscript out of range",
751d48fce0SDaniel Fojt };
761d48fce0SDaniel Fojt #endif
771d48fce0SDaniel Fojt FATAL("floating point exception"
781d48fce0SDaniel Fojt #ifdef SA_SIGINFO
791d48fce0SDaniel Fojt ": %s", (size_t)si->si_code < sizeof(emsg) / sizeof(emsg[0]) &&
801d48fce0SDaniel Fojt emsg[si->si_code] ? emsg[si->si_code] : emsg[0]
811d48fce0SDaniel Fojt #endif
821d48fce0SDaniel Fojt );
831d48fce0SDaniel Fojt }
841d48fce0SDaniel Fojt
851d48fce0SDaniel Fojt /* Can this work with recursive calls? I don't think so.
861d48fce0SDaniel Fojt void segvcatch(int n)
871d48fce0SDaniel Fojt {
881d48fce0SDaniel Fojt FATAL("segfault. Do you have an unbounded recursive call?", n);
891d48fce0SDaniel Fojt }
901d48fce0SDaniel Fojt */
911d48fce0SDaniel Fojt
921d48fce0SDaniel Fojt static const char *
setfs(char * p)931d48fce0SDaniel Fojt setfs(char *p)
941d48fce0SDaniel Fojt {
951d48fce0SDaniel Fojt /* wart: t=>\t */
961d48fce0SDaniel Fojt if (p[0] == 't' && p[1] == '\0')
971d48fce0SDaniel Fojt return "\t";
981d48fce0SDaniel Fojt return p;
991d48fce0SDaniel Fojt }
1001d48fce0SDaniel Fojt
1011d48fce0SDaniel Fojt static char *
getarg(int * argc,char *** argv,const char * msg)1021d48fce0SDaniel Fojt getarg(int *argc, char ***argv, const char *msg)
1031d48fce0SDaniel Fojt {
1041d48fce0SDaniel Fojt if ((*argv)[1][2] != '\0') { /* arg is -fsomething */
1051d48fce0SDaniel Fojt return &(*argv)[1][2];
1061d48fce0SDaniel Fojt } else { /* arg is -f something */
1071d48fce0SDaniel Fojt (*argc)--; (*argv)++;
1081d48fce0SDaniel Fojt if (*argc <= 1)
1091d48fce0SDaniel Fojt FATAL("%s", msg);
1101d48fce0SDaniel Fojt return (*argv)[1];
1111d48fce0SDaniel Fojt }
1121d48fce0SDaniel Fojt }
1134b588458SPeter Avalos
main(int argc,char * argv[])1144b588458SPeter Avalos int main(int argc, char *argv[])
1154b588458SPeter Avalos {
1164b588458SPeter Avalos const char *fs = NULL;
1171d48fce0SDaniel Fojt char *fn, *vn;
1184b588458SPeter Avalos
1194b588458SPeter Avalos setlocale(LC_CTYPE, "");
1204b588458SPeter Avalos setlocale(LC_NUMERIC, "C"); /* for parsing cmdline & prog */
121*ed569bc2SAaron LI awk_mb_cur_max = MB_CUR_MAX;
1224b588458SPeter Avalos cmdname = argv[0];
1234b588458SPeter Avalos if (argc == 1) {
1244b588458SPeter Avalos fprintf(stderr,
125*ed569bc2SAaron LI "usage: %s [-F fs | --csv] [-v var=value] [-f progfile | 'prog'] [file ...]\n",
1264b588458SPeter Avalos cmdname);
1274b588458SPeter Avalos exit(1);
1284b588458SPeter Avalos }
1291d48fce0SDaniel Fojt #ifdef SA_SIGINFO
1301d48fce0SDaniel Fojt {
1311d48fce0SDaniel Fojt struct sigaction sa;
1321d48fce0SDaniel Fojt sa.sa_sigaction = fpecatch;
1331d48fce0SDaniel Fojt sa.sa_flags = SA_SIGINFO;
1341d48fce0SDaniel Fojt sigemptyset(&sa.sa_mask);
1351d48fce0SDaniel Fojt (void)sigaction(SIGFPE, &sa, NULL);
1361d48fce0SDaniel Fojt }
1371d48fce0SDaniel Fojt #else
1381d48fce0SDaniel Fojt (void)signal(SIGFPE, fpecatch);
1391d48fce0SDaniel Fojt #endif
1401d48fce0SDaniel Fojt /*signal(SIGSEGV, segvcatch); experiment */
1410020174dSPeter Avalos
1421d48fce0SDaniel Fojt /* Set and keep track of the random seed */
1430020174dSPeter Avalos srand_seed = 1;
1441d48fce0SDaniel Fojt srandom((unsigned long) srand_seed);
1450020174dSPeter Avalos
1464b588458SPeter Avalos yyin = NULL;
1474b588458SPeter Avalos symtab = makesymtab(NSYMTAB/NSYMTAB);
1484b588458SPeter Avalos while (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') {
1494b588458SPeter Avalos if (strcmp(argv[1], "-version") == 0 || strcmp(argv[1], "--version") == 0) {
1504b588458SPeter Avalos printf("awk %s\n", version);
1511d48fce0SDaniel Fojt return 0;
1524b588458SPeter Avalos }
1531d48fce0SDaniel Fojt if (strcmp(argv[1], "--") == 0) { /* explicit end of args */
1544b588458SPeter Avalos argc--;
1554b588458SPeter Avalos argv++;
1564b588458SPeter Avalos break;
1574b588458SPeter Avalos }
158*ed569bc2SAaron LI if (strcmp(argv[1], "--csv") == 0) { /* turn on csv input processing */
159*ed569bc2SAaron LI CSV = true;
160*ed569bc2SAaron LI argc--;
161*ed569bc2SAaron LI argv++;
162*ed569bc2SAaron LI continue;
163*ed569bc2SAaron LI }
1644b588458SPeter Avalos switch (argv[1][1]) {
1654b588458SPeter Avalos case 's':
1664b588458SPeter Avalos if (strcmp(argv[1], "-safe") == 0)
1671d48fce0SDaniel Fojt safe = true;
1684b588458SPeter Avalos break;
1694b588458SPeter Avalos case 'f': /* next argument is program filename */
1701d48fce0SDaniel Fojt fn = getarg(&argc, &argv, "no program filename");
1711d48fce0SDaniel Fojt if (npfile >= maxpfile) {
1721d48fce0SDaniel Fojt maxpfile += 20;
17348f09a05SAntonio Huete Jimenez pfile = (char **) realloc(pfile, maxpfile * sizeof(*pfile));
1741d48fce0SDaniel Fojt if (pfile == NULL)
1751d48fce0SDaniel Fojt FATAL("error allocating space for -f options");
1760020174dSPeter Avalos }
1771d48fce0SDaniel Fojt pfile[npfile++] = fn;
1784b588458SPeter Avalos break;
1794b588458SPeter Avalos case 'F': /* set field separator */
1801d48fce0SDaniel Fojt fs = setfs(getarg(&argc, &argv, "no field separator"));
1814b588458SPeter Avalos break;
1824b588458SPeter Avalos case 'v': /* -v a=1 to be done NOW. one -v for each */
1831d48fce0SDaniel Fojt vn = getarg(&argc, &argv, "no variable name");
1841d48fce0SDaniel Fojt if (isclvar(vn))
1851d48fce0SDaniel Fojt setclvar(vn);
186b12bae18SSascha Wildner else
1871d48fce0SDaniel Fojt FATAL("invalid -v option argument: %s", vn);
1884b588458SPeter Avalos break;
1894b588458SPeter Avalos case 'd':
1904b588458SPeter Avalos dbg = atoi(&argv[1][2]);
1914b588458SPeter Avalos if (dbg == 0)
1924b588458SPeter Avalos dbg = 1;
1934b588458SPeter Avalos printf("awk %s\n", version);
1944b588458SPeter Avalos break;
1954b588458SPeter Avalos default:
1964b588458SPeter Avalos WARNING("unknown option %s ignored", argv[1]);
1974b588458SPeter Avalos break;
1984b588458SPeter Avalos }
1994b588458SPeter Avalos argc--;
2004b588458SPeter Avalos argv++;
2014b588458SPeter Avalos }
202*ed569bc2SAaron LI
203*ed569bc2SAaron LI if (CSV && (fs != NULL || lookup("FS", symtab) != NULL))
204*ed569bc2SAaron LI WARNING("danger: don't set FS when --csv is in effect");
205*ed569bc2SAaron LI
2064b588458SPeter Avalos /* argv[1] is now the first argument */
2074b588458SPeter Avalos if (npfile == 0) { /* no -f; first argument is program */
2084b588458SPeter Avalos if (argc <= 1) {
2094b588458SPeter Avalos if (dbg)
2104b588458SPeter Avalos exit(0);
2114b588458SPeter Avalos FATAL("no program given");
2124b588458SPeter Avalos }
213e5e686a0SDaniel Fojt DPRINTF("program = |%s|\n", argv[1]);
2144b588458SPeter Avalos lexprog = argv[1];
2154b588458SPeter Avalos argc--;
2164b588458SPeter Avalos argv++;
2174b588458SPeter Avalos }
2184b588458SPeter Avalos recinit(recsize);
2194b588458SPeter Avalos syminit();
2201d48fce0SDaniel Fojt compile_time = COMPILING;
2214b588458SPeter Avalos argv[0] = cmdname; /* put prog name at front of arglist */
222e5e686a0SDaniel Fojt DPRINTF("argc=%d, argv[0]=%s\n", argc, argv[0]);
2234b588458SPeter Avalos arginit(argc, argv);
2244b588458SPeter Avalos if (!safe)
2254b588458SPeter Avalos envinit(environ);
2264b588458SPeter Avalos yyparse();
2271d48fce0SDaniel Fojt #if 0
2281d48fce0SDaniel Fojt // Doing this would comply with POSIX, but is not compatible with
2291d48fce0SDaniel Fojt // other awks and with what most users expect. So comment it out.
2304b588458SPeter Avalos setlocale(LC_NUMERIC, ""); /* back to whatever it is locally */
2311d48fce0SDaniel Fojt #endif
2324b588458SPeter Avalos if (fs)
2334b588458SPeter Avalos *FS = qstring(fs, '\0');
234e5e686a0SDaniel Fojt DPRINTF("errorflag=%d\n", errorflag);
2354b588458SPeter Avalos if (errorflag == 0) {
2361d48fce0SDaniel Fojt compile_time = RUNNING;
2374b588458SPeter Avalos run(winner);
2384b588458SPeter Avalos } else
2394b588458SPeter Avalos bracecheck();
2404b588458SPeter Avalos return(errorflag);
2414b588458SPeter Avalos }
2424b588458SPeter Avalos
pgetc(void)2434b588458SPeter Avalos int pgetc(void) /* get 1 character from awk program */
2444b588458SPeter Avalos {
2454b588458SPeter Avalos int c;
2464b588458SPeter Avalos
2474b588458SPeter Avalos for (;;) {
2484b588458SPeter Avalos if (yyin == NULL) {
2494b588458SPeter Avalos if (curpfile >= npfile)
2504b588458SPeter Avalos return EOF;
2514b588458SPeter Avalos if (strcmp(pfile[curpfile], "-") == 0)
2524b588458SPeter Avalos yyin = stdin;
2534b588458SPeter Avalos else if ((yyin = fopen(pfile[curpfile], "r")) == NULL)
2544b588458SPeter Avalos FATAL("can't open file %s", pfile[curpfile]);
2554b588458SPeter Avalos lineno = 1;
2564b588458SPeter Avalos }
2574b588458SPeter Avalos if ((c = getc(yyin)) != EOF)
2584b588458SPeter Avalos return c;
2594b588458SPeter Avalos if (yyin != stdin)
2604b588458SPeter Avalos fclose(yyin);
2614b588458SPeter Avalos yyin = NULL;
2624b588458SPeter Avalos curpfile++;
2634b588458SPeter Avalos }
2644b588458SPeter Avalos }
2654b588458SPeter Avalos
cursource(void)2664b588458SPeter Avalos char *cursource(void) /* current source file name */
2674b588458SPeter Avalos {
2684b588458SPeter Avalos if (npfile > 0)
26948f09a05SAntonio Huete Jimenez return pfile[curpfile < npfile ? curpfile : curpfile - 1];
2704b588458SPeter Avalos else
2714b588458SPeter Avalos return NULL;
2724b588458SPeter Avalos }
273