xref: /dflybsd-src/contrib/awk/main.c (revision e2ee60a4f1757f9ded9e1041053222b631f387b6)
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