1 /* Copyright 2010-2021 Free Software Foundation, Inc.
2
3 This program is free software: you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation, either version 3 of the License, or
6 (at your option) any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>. */
15
16 #include <config.h>
17
18
19 #ifdef ENABLE_NLS
20 #include <libintl.h>
21 #endif
22
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26
27 #include "errors.h"
28 #include "input.h"
29 #include "text.h"
30
bug(char * message)31 void bug (char *message)
32 {
33 fprintf (stderr, "texi2any (XS parser): bug: %s\n", message);
34 }
35
fatal(char * message)36 void fatal (char *message)
37 {
38 bug (message);
39 abort ();
40 }
41
42
43 typedef struct {
44 char *message;
45 enum error_type type;
46 LINE_NR line_nr;
47 } ERROR_MESSAGE;
48
49 static ERROR_MESSAGE *error_list = 0;
50 static size_t error_number = 0;
51 static size_t error_space = 0;
52
53 static void
line_error_internal(enum error_type type,LINE_NR * cmd_line_nr,char * format,va_list v)54 line_error_internal (enum error_type type, LINE_NR *cmd_line_nr,
55 char *format, va_list v)
56 {
57 char *message;
58 #ifdef ENABLE_NLS
59 vasprintf (&message, gettext(format), v);
60 #else
61 vasprintf (&message, format, v);
62 #endif
63 if (!message) fatal ("vasprintf failed");
64
65 if (error_number == error_space)
66 {
67 error_list = realloc (error_list,
68 (error_space += 10) * sizeof (ERROR_MESSAGE));
69 }
70 error_list[error_number].message = message;
71 error_list[error_number].type = type;
72
73 if (cmd_line_nr)
74 {
75 if (cmd_line_nr->line_nr)
76 error_list[error_number++].line_nr = *cmd_line_nr;
77 else
78 error_list[error_number++].line_nr = line_nr;
79 }
80 else
81 error_list[error_number++].line_nr = line_nr;
82 }
83
84 void
line_error_ext(enum error_type type,LINE_NR * cmd_line_nr,char * format,...)85 line_error_ext (enum error_type type, LINE_NR *cmd_line_nr,
86 char *format, ...)
87 {
88 va_list v;
89
90 va_start (v, format);
91 line_error_internal (type, cmd_line_nr, format, v);
92 }
93
94 void
line_error(char * format,...)95 line_error (char *format, ...)
96 {
97 va_list v;
98
99 va_start (v, format);
100 line_error_internal (error, 0, format, v);
101 }
102
103 void
line_warn(char * format,...)104 line_warn (char *format, ...)
105 {
106 va_list v;
107
108 va_start (v, format);
109 line_error_internal (warning, 0, format, v);
110 }
111
112 void
command_warn(ELEMENT * e,char * format,...)113 command_warn (ELEMENT *e, char *format, ...)
114 {
115 va_list v;
116
117 va_start (v, format);
118 line_error_internal (warning, &e->line_nr, format, v);
119 }
120
121 void
command_error(ELEMENT * e,char * format,...)122 command_error (ELEMENT *e, char *format, ...)
123 {
124 va_list v;
125
126 va_start (v, format);
127 line_error_internal (error, &e->line_nr, format, v);
128 }
129
130 void
wipe_errors(void)131 wipe_errors (void)
132 {
133 int i;
134 for (i = 0; i < error_number; i++)
135 free (error_list[i].message);
136 error_number = 0;
137 }
138
139 static void
bug_message_internal(char * format,va_list v)140 bug_message_internal (char *format, va_list v)
141 {
142 fprintf (stderr, "You found a bug: ");
143 vfprintf (stderr, format, v);
144 fprintf (stderr, "\n");
145 if (line_nr.file_name)
146 {
147 fprintf (stderr,
148 "last location %s:%d", line_nr.file_name, line_nr.line_nr);
149 if (line_nr.macro)
150 fprintf (stderr, " (possibly involving @%s)", line_nr.macro);
151 fprintf (stderr, "\n");
152 }
153 exit (1);
154 }
155
156 void
bug_message(char * format,...)157 bug_message (char *format, ...)
158 {
159 va_list v;
160
161 va_start (v, format);
162 bug_message_internal (format, v);
163 }
164
165 static int indent = 0;
166
167 /* Output INDENT spaces. */
168 static void
dump_indent(TEXT * text)169 dump_indent (TEXT *text)
170 {
171 int i;
172
173 for (i = 0; i < indent; i++)
174 text_append_n (text, " ", 1);
175 }
176
177 /* Ouput S escaping single quotes and backslashes, so that
178 Perl can read it in when it is surrounded by single quotes. */
179 void
dump_string(char * s,TEXT * text)180 dump_string (char *s, TEXT *text)
181 {
182 while (*s)
183 {
184 if (*s == '\''
185 || *s == '\\')
186 text_append_n (text, "\\", 1);
187 text_append_n (text, s++, 1);
188 }
189 }
190
191 static void
dump_line_nr(LINE_NR * line_nr,TEXT * text)192 dump_line_nr (LINE_NR *line_nr, TEXT *text)
193 {
194 text_append_n (text, "{\n", 2);
195 indent += 2;
196
197 dump_indent (text);
198 text_printf (text, "'file_name' => '%s',\n",
199 line_nr->file_name ?
200 line_nr->file_name : "");
201
202 if (line_nr->line_nr)
203 {
204 dump_indent (text);
205 text_append (text, "'line_nr' => ");
206 text_printf (text, "%d", line_nr->line_nr);
207 text_append (text, ",\n");
208 }
209
210 /* TODO: macro. */
211 if (line_nr->macro)
212 {
213 dump_indent (text);
214 text_append (text, "'macro' => ");
215 text_printf (text, "'%s'", line_nr->macro);
216 text_append (text, ",\n");
217 }
218 else
219 {
220 dump_indent (text);
221 text_append (text, "'macro' => ''\n");
222 }
223
224
225 indent -= 2;
226 dump_indent (text);
227 text_append_n (text, "},\n", 3);
228 }
229
230 char *
dump_errors(void)231 dump_errors (void)
232 {
233 int i;
234 static TEXT t;
235
236 text_reset (&t);
237 text_append (&t, "$ERRORS = [\n");
238 for (i = 0; i < error_number; i++)
239 {
240 text_append (&t, "{ 'message' =>\n'");
241 dump_string (error_list[i].message, &t);
242 text_append (&t, "',\n");
243 text_printf (&t, "'type' => '%s',", error_list[i].type == error ? "error"
244 : "warning");
245 text_append (&t, "'line_nr' => ");
246 dump_line_nr (&error_list[i].line_nr, &t);
247 text_append (&t, "},\n");
248 }
249 text_append (&t, "];\n");
250
251 return t.text;
252 }
253
254
255