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