1 /*
2  * msg.c - routines for error messages.
3  */
4 
5 /*
6  * Copyright (C) 1986, 1988, 1989, 1991-2001, 2003, 2010-2013, 2017-2019,
7  * 2021,
8  * the Free Software Foundation, Inc.
9  *
10  * This file is part of GAWK, the GNU implementation of the
11  * AWK Programming Language.
12  *
13  * GAWK is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2, or (at your option)
16  * any later version.
17  *
18  * GAWK is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
26  */
27 
28 #include "awk.h"
29 
30 extern FILE *output_fp;
31 int sourceline = 0;
32 char *source = NULL;
33 static const char *srcfile = NULL;
34 static int srcline;
35 
36 jmp_buf fatal_tag;
37 int fatal_tag_valid = 0;
38 
39 /* err --- print an error message with source line and file and record */
40 
41 /* VARARGS2 */
42 void
err(bool isfatal,const char * s,const char * emsg,va_list argp)43 err(bool isfatal, const char *s, const char *emsg, va_list argp)
44 {
45 	char *file;
46 	const char *me;
47 
48 	static bool first = true;
49 	static bool add_src_info = false;
50 	static long lineno_val = 0;	// Easter Egg
51 
52 	if (first) {
53 		first = false;
54 		add_src_info = (getenv("GAWK_MSG_SRC") != NULL);
55 		if (! do_traditional) {
56 			NODE *n = lookup("LINENO");
57 
58 			if (n != NULL && n->type == Node_var)
59 				lineno_val = get_number_d(n->var_value);
60 		}
61 	}
62 
63 	(void) fflush(output_fp);
64 	me = myname;
65 	(void) fprintf(stderr, "%s: ", me);
66 
67 	if (srcfile != NULL && add_src_info) {
68 		fprintf(stderr, "%s:%d:", srcfile, srcline);
69 		srcfile = NULL;
70 	}
71 
72 	if (sourceline > 0) {
73 		if (source != NULL)
74 			(void) fprintf(stderr, "%s:", source);
75 		else
76 			(void) fprintf(stderr, _("cmd. line:"));
77 
78 		(void) fprintf(stderr, "%ld: ", sourceline + lineno_val);
79 	}
80 
81 #ifdef HAVE_MPFR
82 	if (FNR_node && FNR_node->var_value && is_mpg_number(FNR_node->var_value)) {
83 		NODE *val;
84 		val = mpg_update_var(FNR_node);
85 		assert((val->flags & MPZN) != 0);
86 		if (mpz_sgn(val->mpg_i) > 0) {
87 			int len = FILENAME_node->var_value->stlen;
88 			file = FILENAME_node->var_value->stptr;
89 			(void) putc('(', stderr);
90 			if (file)
91 				(void) fprintf(stderr, "FILENAME=%.*s ", len, file);
92 			(void) mpfr_fprintf(stderr, "FNR=%Zd) ", val->mpg_i);
93 		}
94 	} else
95 #endif
96 	if (FNR > 0) {
97 		int len = FILENAME_node->var_value->stlen;
98 		file = FILENAME_node->var_value->stptr;
99 		(void) putc('(', stderr);
100 		if (file)
101 			(void) fprintf(stderr, "FILENAME=%.*s ", len, file);
102 		(void) fprintf(stderr, "FNR=%ld) ", FNR);
103 	}
104 
105 	(void) fprintf(stderr, "%s", s);
106 	vfprintf(stderr, emsg, argp);
107 	(void) fprintf(stderr, "\n");
108 	(void) fflush(stderr);
109 
110 	if (isfatal)
111 		gawk_exit(EXIT_FATAL);
112 
113 }
114 
115 /* msg --- take a varargs error message and print it */
116 
117 void
msg(const char * mesg,...)118 msg(const char *mesg, ...)
119 {
120 	va_list args;
121 	va_start(args, mesg);
122 	err(false, "", mesg, args);
123 	va_end(args);
124 }
125 
126 /* r_warning --- print a warning message */
127 
128 void
r_warning(const char * mesg,...)129 r_warning(const char *mesg, ...)
130 {
131 	va_list args;
132 	va_start(args, mesg);
133 	err(false, _("warning: "), mesg, args);
134 	va_end(args);
135 }
136 
137 void
error(const char * mesg,...)138 error(const char *mesg, ...)
139 {
140 	va_list args;
141 	va_start(args, mesg);
142 	err(false, _("error: "), mesg, args);
143 	va_end(args);
144 }
145 
146 /* set_loc --- set location where a fatal error happened */
147 
148 void
set_loc(const char * file,int line)149 set_loc(const char *file, int line)
150 {
151 	srcfile = file;
152 	srcline = line;
153 
154 	/* This stupid line keeps some compilers happy: */
155 	file = srcfile; line = srcline;
156 }
157 
158 /* r_fatal --- print a fatal error message */
159 
160 void
r_fatal(const char * mesg,...)161 r_fatal(const char *mesg, ...)
162 {
163 	va_list args;
164 	va_start(args, mesg);
165 	err(true, _("fatal: "), mesg, args);
166 	va_end(args);
167 }
168 
169 /* gawk_exit --- longjmp out if necessary */
170 
171 void
gawk_exit(int status)172 gawk_exit(int status)
173 {
174 	if (fatal_tag_valid) {
175 		exit_val = status;
176 		longjmp(fatal_tag, 1);
177 	}
178 
179 	final_exit(status);
180 }
181 
182 /* final_exit --- run extension exit handlers and exit */
183 
184 void
final_exit(int status)185 final_exit(int status)
186 {
187 	/* run any extension exit handlers */
188 	run_ext_exit_handlers(status);
189 
190 	/* we could close_io() here */
191 	close_extensions();
192 
193 	exit(status);
194 }
195