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