#include "config.h"
#undef FLOAT
#undef FFS
#include "system.h"
#include "coretypes.h"
#include "intl.h"
#include "pretty-print.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
#define pp_formatted_text_data(PP) \
((const char *) obstack_base (&pp_base (PP)->buffer->obstack))
#define pp_integer_with_precision(PP, ARG, PREC, T, F) \
do \
switch (PREC) \
{ \
case 0: \
pp_scalar (PP, "%" F, va_arg (ARG, T)); \
break; \
\
case 1: \
pp_scalar (PP, "%l" F, va_arg (ARG, long T)); \
break; \
\
case 2: \
pp_scalar (PP, "%ll" F, va_arg (ARG, long long T)); \
break; \
\
default: \
break; \
} \
while (0)
static void
pp_set_real_maximum_length (pretty_printer *pp)
{
if (!pp_is_wrapping_line (pp)
|| pp_prefixing_rule (pp) == DIAGNOSTICS_SHOW_PREFIX_ONCE
|| pp_prefixing_rule (pp) == DIAGNOSTICS_SHOW_PREFIX_NEVER)
pp->maximum_length = pp_line_cutoff (pp);
else
{
int prefix_length = pp->prefix ? strlen (pp->prefix) : 0;
if (pp_line_cutoff (pp) - prefix_length < 32)
pp->maximum_length = pp_line_cutoff (pp) + 32;
else
pp->maximum_length = pp_line_cutoff (pp);
}
}
static inline void
pp_clear_state (pretty_printer *pp)
{
pp->emitted_prefix = false;
pp_indentation (pp) = 0;
}
void
pp_write_text_to_stream (pretty_printer *pp)
{
const char *text = pp_formatted_text (pp);
fputs (text, pp->buffer->stream);
pp_clear_output_area (pp);
}
static void
pp_wrap_text (pretty_printer *pp, const char *start, const char *end)
{
bool wrapping_line = pp_is_wrapping_line (pp);
while (start != end)
{
{
const char *p = start;
while (p != end && !ISBLANK (*p) && *p != '\n')
++p;
if (wrapping_line
&& p - start >= pp_remaining_character_count_for_line (pp))
pp_newline (pp);
pp_append_text (pp, start, p);
start = p;
}
if (start != end && ISBLANK (*start))
{
pp_space (pp);
++start;
}
if (start != end && *start == '\n')
{
pp_newline (pp);
++start;
}
}
}
static inline void
pp_maybe_wrap_text (pretty_printer *pp, const char *start, const char *end)
{
if (pp_is_wrapping_line (pp))
pp_wrap_text (pp, start, end);
else
pp_append_text (pp, start, end);
}
static inline void
pp_append_r (pretty_printer *pp, const char *start, int length)
{
obstack_grow (&pp->buffer->obstack, start, length);
pp->buffer->line_length += length;
}
void
pp_base_indent (pretty_printer *pp)
{
int n = pp_indentation (pp);
int i;
for (i = 0; i < n; ++i)
pp_space (pp);
}
void
pp_base_format_text (pretty_printer *pp, text_info *text)
{
for (; *text->format_spec; ++text->format_spec)
{
int precision = 0;
bool wide = false;
bool quoted = false;
{
const char *p = text->format_spec;
while (*p && *p != '%')
++p;
pp_wrap_text (pp, text->format_spec, p);
text->format_spec = p;
}
if (*text->format_spec == '\0')
break;
if (*++text->format_spec == 'q')
{
quoted = true;
++text->format_spec;
}
switch (*text->format_spec)
{
case 'w':
wide = true;
++text->format_spec;
break;
case 'l':
do
++precision;
while (*++text->format_spec == 'l');
break;
default:
break;
}
if (precision > 2)
abort();
if (quoted)
pp_string (pp, open_quote);
switch (*text->format_spec)
{
case 'c':
pp_character (pp, va_arg (*text->args_ptr, int));
break;
case 'd':
case 'i':
if (wide)
pp_wide_integer (pp, va_arg (*text->args_ptr, HOST_WIDE_INT));
else
pp_integer_with_precision
(pp, *text->args_ptr, precision, int, "d");
break;
case 'o':
if (wide)
pp_scalar (pp, "%" HOST_WIDE_INT_PRINT "o",
va_arg (*text->args_ptr, unsigned HOST_WIDE_INT));
else
pp_integer_with_precision
(pp, *text->args_ptr, precision, unsigned, "u");
break;
case 's':
pp_string (pp, va_arg (*text->args_ptr, const char *));
break;
case 'p':
pp_pointer (pp, va_arg (*text->args_ptr, void *));
break;
case 'u':
if (wide)
pp_scalar (pp, HOST_WIDE_INT_PRINT_UNSIGNED,
va_arg (*text->args_ptr, unsigned HOST_WIDE_INT));
else
pp_integer_with_precision
(pp, *text->args_ptr, precision, unsigned, "u");
break;
case 'x':
if (wide)
pp_scalar (pp, HOST_WIDE_INT_PRINT_HEX,
va_arg (*text->args_ptr, unsigned HOST_WIDE_INT));
else
pp_integer_with_precision
(pp, *text->args_ptr, precision, unsigned, "x");
break;
case 'm':
pp_string (pp, xstrerror (text->err_no));
break;
case '%':
pp_character (pp, '%');
break;
case '<':
pp_string (pp, open_quote);
break;
case '>':
case '\'':
pp_string (pp, close_quote);
break;
case 'H':
{
location_t *locus = va_arg (*text->args_ptr, location_t *);
expanded_location s = expand_location (*locus);
pp_string (pp, "file '");
pp_string (pp, s.file);
pp_string (pp, "', line ");
pp_decimal_int (pp, s.line);
}
break;
case '.':
{
int n;
const char *s;
if (*++text->format_spec != '*')
abort ();
else if (*++text->format_spec != 's')
abort ();
n = va_arg (*text->args_ptr, int);
s = va_arg (*text->args_ptr, const char *);
pp_append_text (pp, s, s + n);
}
break;
default:
if (!pp_format_decoder (pp) || !(*pp_format_decoder (pp)) (pp, text))
{
abort ();
}
}
if (quoted)
pp_string (pp, close_quote);
}
}
void
pp_base_format_verbatim (pretty_printer *pp, text_info *text)
{
diagnostic_prefixing_rule_t rule = pp_prefixing_rule (pp);
int line_cutoff = pp_line_cutoff (pp);
pp->prefixing_rule = DIAGNOSTICS_SHOW_PREFIX_NEVER;
pp_line_cutoff (pp) = 0;
pp_format_text (pp, text);
pp_prefixing_rule (pp) = rule;
pp_line_cutoff (pp) = line_cutoff;
}
void
pp_base_flush (pretty_printer *pp)
{
pp_write_text_to_stream (pp);
pp_clear_state (pp);
fputc ('\n', pp->buffer->stream);
fflush (pp->buffer->stream);
pp_needs_newline (pp) = false;
}
void
pp_base_set_line_maximum_length (pretty_printer *pp, int length)
{
pp_line_cutoff (pp) = length;
pp_set_real_maximum_length (pp);
}
void
pp_base_clear_output_area (pretty_printer *pp)
{
obstack_free (&pp->buffer->obstack, obstack_base (&pp->buffer->obstack));
pp->buffer->line_length = 0;
}
void
pp_base_set_prefix (pretty_printer *pp, const char *prefix)
{
pp->prefix = prefix;
pp_set_real_maximum_length (pp);
pp->emitted_prefix = false;
pp_indentation (pp) = 0;
}
void
pp_base_destroy_prefix (pretty_printer *pp)
{
if (pp->prefix != NULL)
{
free ((char *) pp->prefix);
pp->prefix = NULL;
}
}
void
pp_base_emit_prefix (pretty_printer *pp)
{
if (pp->prefix != NULL)
{
switch (pp_prefixing_rule (pp))
{
default:
case DIAGNOSTICS_SHOW_PREFIX_NEVER:
break;
case DIAGNOSTICS_SHOW_PREFIX_ONCE:
if (pp->emitted_prefix)
{
pp_base_indent (pp);
break;
}
pp_indentation (pp) += 3;
case DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE:
{
int prefix_length = strlen (pp->prefix);
pp_append_r (pp, pp->prefix, prefix_length);
pp->emitted_prefix = true;
}
break;
}
}
}
void
pp_construct (pretty_printer *pp, const char *prefix, int maximum_length)
{
memset (pp, 0, sizeof (pretty_printer));
pp->buffer = xcalloc (1, sizeof (output_buffer));
obstack_init (&pp->buffer->obstack);
pp->buffer->stream = stderr;
pp_line_cutoff (pp) = maximum_length;
pp_prefixing_rule (pp) = DIAGNOSTICS_SHOW_PREFIX_ONCE;
pp_set_prefix (pp, prefix);
}
void
pp_base_append_text (pretty_printer *pp, const char *start, const char *end)
{
if (pp->buffer->line_length == 0)
{
pp_emit_prefix (pp);
if (pp_is_wrapping_line (pp))
while (start != end && *start == ' ')
++start;
}
pp_append_r (pp, start, end - start);
}
const char *
pp_base_formatted_text (pretty_printer *pp)
{
obstack_1grow (&pp->buffer->obstack, '\0');
return pp_formatted_text_data (pp);
}
const char *
pp_base_last_position_in_text (const pretty_printer *pp)
{
const char *p = NULL;
struct obstack *text = &pp->buffer->obstack;
if (obstack_base (text) != obstack_next_free (text))
p = ((const char *) obstack_next_free (text)) - 1;
return p;
}
int
pp_base_remaining_character_count_for_line (pretty_printer *pp)
{
return pp->maximum_length - pp->buffer->line_length;
}
void
pp_printf (pretty_printer *pp, const char *msg, ...)
{
text_info text;
va_list ap;
va_start (ap, msg);
text.err_no = errno;
text.args_ptr = ≈
text.format_spec = msg;
pp_format_text (pp, &text);
va_end (ap);
}
void
pp_verbatim (pretty_printer *pp, const char *msg, ...)
{
text_info text;
va_list ap;
va_start (ap, msg);
text.err_no = errno;
text.args_ptr = ≈
text.format_spec = msg;
pp_format_verbatim (pp, &text);
va_end (ap);
}
void
pp_base_newline (pretty_printer *pp)
{
obstack_1grow (&pp->buffer->obstack, '\n');
pp->buffer->line_length = 0;
}
void
pp_base_character (pretty_printer *pp, int c)
{
if (pp_is_wrapping_line (pp)
&& pp_remaining_character_count_for_line (pp) <= 0)
{
pp_newline (pp);
if (ISSPACE (c))
return;
}
obstack_1grow (&pp->buffer->obstack, c);
++pp->buffer->line_length;
}
void
pp_base_string (pretty_printer *pp, const char *str)
{
pp_maybe_wrap_text (pp, str, str + (str ? strlen (str) : 0));
}
void
pp_base_maybe_space (pretty_printer *pp)
{
if (pp_base (pp)->padding != pp_none)
{
pp_space (pp);
pp_base (pp)->padding = pp_none;
}
}