/* Copyright 2010-2021 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see . */
#include
#ifdef ENABLE_NLS
#include
#endif
#include
#include
#include
#include "errors.h"
#include "input.h"
#include "text.h"
void bug (char *message)
{
fprintf (stderr, "texi2any (XS parser): bug: %s\n", message);
}
void fatal (char *message)
{
bug (message);
abort ();
}
typedef struct {
char *message;
enum error_type type;
LINE_NR line_nr;
} ERROR_MESSAGE;
static ERROR_MESSAGE *error_list = 0;
static size_t error_number = 0;
static size_t error_space = 0;
static void
line_error_internal (enum error_type type, LINE_NR *cmd_line_nr,
char *format, va_list v)
{
char *message;
#ifdef ENABLE_NLS
vasprintf (&message, gettext(format), v);
#else
vasprintf (&message, format, v);
#endif
if (!message) fatal ("vasprintf failed");
if (error_number == error_space)
{
error_list = realloc (error_list,
(error_space += 10) * sizeof (ERROR_MESSAGE));
}
error_list[error_number].message = message;
error_list[error_number].type = type;
if (cmd_line_nr)
{
if (cmd_line_nr->line_nr)
error_list[error_number++].line_nr = *cmd_line_nr;
else
error_list[error_number++].line_nr = line_nr;
}
else
error_list[error_number++].line_nr = line_nr;
}
void
line_error_ext (enum error_type type, LINE_NR *cmd_line_nr,
char *format, ...)
{
va_list v;
va_start (v, format);
line_error_internal (type, cmd_line_nr, format, v);
}
void
line_error (char *format, ...)
{
va_list v;
va_start (v, format);
line_error_internal (error, 0, format, v);
}
void
line_warn (char *format, ...)
{
va_list v;
va_start (v, format);
line_error_internal (warning, 0, format, v);
}
void
command_warn (ELEMENT *e, char *format, ...)
{
va_list v;
va_start (v, format);
line_error_internal (warning, &e->line_nr, format, v);
}
void
command_error (ELEMENT *e, char *format, ...)
{
va_list v;
va_start (v, format);
line_error_internal (error, &e->line_nr, format, v);
}
void
wipe_errors (void)
{
int i;
for (i = 0; i < error_number; i++)
free (error_list[i].message);
error_number = 0;
}
static void
bug_message_internal (char *format, va_list v)
{
fprintf (stderr, "You found a bug: ");
vfprintf (stderr, format, v);
fprintf (stderr, "\n");
if (line_nr.file_name)
{
fprintf (stderr,
"last location %s:%d", line_nr.file_name, line_nr.line_nr);
if (line_nr.macro)
fprintf (stderr, " (possibly involving @%s)", line_nr.macro);
fprintf (stderr, "\n");
}
exit (1);
}
void
bug_message (char *format, ...)
{
va_list v;
va_start (v, format);
bug_message_internal (format, v);
}
static int indent = 0;
/* Output INDENT spaces. */
static void
dump_indent (TEXT *text)
{
int i;
for (i = 0; i < indent; i++)
text_append_n (text, " ", 1);
}
/* Ouput S escaping single quotes and backslashes, so that
Perl can read it in when it is surrounded by single quotes. */
void
dump_string (char *s, TEXT *text)
{
while (*s)
{
if (*s == '\''
|| *s == '\\')
text_append_n (text, "\\", 1);
text_append_n (text, s++, 1);
}
}
static void
dump_line_nr (LINE_NR *line_nr, TEXT *text)
{
text_append_n (text, "{\n", 2);
indent += 2;
dump_indent (text);
text_printf (text, "'file_name' => '%s',\n",
line_nr->file_name ?
line_nr->file_name : "");
if (line_nr->line_nr)
{
dump_indent (text);
text_append (text, "'line_nr' => ");
text_printf (text, "%d", line_nr->line_nr);
text_append (text, ",\n");
}
/* TODO: macro. */
if (line_nr->macro)
{
dump_indent (text);
text_append (text, "'macro' => ");
text_printf (text, "'%s'", line_nr->macro);
text_append (text, ",\n");
}
else
{
dump_indent (text);
text_append (text, "'macro' => ''\n");
}
indent -= 2;
dump_indent (text);
text_append_n (text, "},\n", 3);
}
char *
dump_errors (void)
{
int i;
static TEXT t;
text_reset (&t);
text_append (&t, "$ERRORS = [\n");
for (i = 0; i < error_number; i++)
{
text_append (&t, "{ 'message' =>\n'");
dump_string (error_list[i].message, &t);
text_append (&t, "',\n");
text_printf (&t, "'type' => '%s',", error_list[i].type == error ? "error"
: "warning");
text_append (&t, "'line_nr' => ");
dump_line_nr (&error_list[i].line_nr, &t);
text_append (&t, "},\n");
}
text_append (&t, "];\n");
return t.text;
}