#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "cpplib.h"
#include "../libcpp/internal.h"
#include "tree.h"
#include "c-common.h"
#include "c-pragma.h"
static struct
{
FILE *outf;
const cpp_token *prev;
const cpp_token *source;
int src_line;
unsigned char printed;
bool first_time;
} print;
static void scan_translation_unit (cpp_reader *);
static void scan_translation_unit_trad (cpp_reader *);
static void account_for_newlines (const unsigned char *, size_t);
static int dump_macro (cpp_reader *, cpp_hashnode *, void *);
static void print_line (source_location, const char *);
static void maybe_print_line (source_location);
static void cb_line_change (cpp_reader *, const cpp_token *, int);
static void cb_define (cpp_reader *, source_location, cpp_hashnode *);
static void cb_undef (cpp_reader *, source_location, cpp_hashnode *);
static void cb_include (cpp_reader *, source_location, const unsigned char *,
const char *, int, const cpp_token **);
static void cb_ident (cpp_reader *, source_location, const cpp_string *);
static void cb_def_pragma (cpp_reader *, source_location);
static void cb_read_pch (cpp_reader *pfile, const char *name,
int fd, const char *orig_name);
void
preprocess_file (cpp_reader *pfile)
{
if (flag_no_output)
{
while (pfile->buffer->prev)
cpp_scan_nooutput (pfile);
cpp_scan_nooutput (pfile);
}
else if (cpp_get_options (pfile)->traditional)
scan_translation_unit_trad (pfile);
else
scan_translation_unit (pfile);
if (flag_dump_macros == 'M')
cpp_forall_identifiers (pfile, dump_macro, NULL);
if (print.printed)
putc ('\n', print.outf);
}
void
init_pp_output (FILE *out_stream)
{
cpp_callbacks *cb = cpp_get_callbacks (parse_in);
if (!flag_no_output)
{
cb->line_change = cb_line_change;
if (cpp_get_options (parse_in)->lang != CLK_ASM)
{
cb->ident = cb_ident;
cb->def_pragma = cb_def_pragma;
}
}
if (flag_dump_includes)
cb->include = cb_include;
if (flag_pch_preprocess)
{
cb->valid_pch = c_common_valid_pch;
cb->read_pch = cb_read_pch;
}
if (flag_dump_macros == 'N' || flag_dump_macros == 'D')
{
cb->define = cb_define;
cb->undef = cb_undef;
}
print.src_line = -1;
print.printed = 0;
print.prev = 0;
print.outf = out_stream;
print.first_time = 1;
}
static void
scan_translation_unit (cpp_reader *pfile)
{
bool avoid_paste = false;
print.source = NULL;
for (;;)
{
const cpp_token *token = cpp_get_token (pfile);
if (token->type == CPP_PADDING)
{
avoid_paste = true;
if (print.source == NULL
|| (!(print.source->flags & PREV_WHITE)
&& token->val.source == NULL))
print.source = token->val.source;
continue;
}
if (token->type == CPP_EOF)
break;
if (avoid_paste)
{
if (print.source == NULL)
print.source = token;
if (print.source->flags & PREV_WHITE
|| (print.prev
&& cpp_avoid_paste (pfile, print.prev, token))
|| (print.prev == NULL && token->type == CPP_HASH))
putc (' ', print.outf);
}
else if (token->flags & PREV_WHITE)
putc (' ', print.outf);
avoid_paste = false;
print.source = NULL;
print.prev = token;
cpp_output_token (token, print.outf);
if (token->type == CPP_COMMENT)
account_for_newlines (token->val.str.text, token->val.str.len);
}
}
static void
account_for_newlines (const unsigned char *str, size_t len)
{
while (len--)
if (*str++ == '\n')
print.src_line++;
}
static void
scan_translation_unit_trad (cpp_reader *pfile)
{
while (_cpp_read_logical_line_trad (pfile))
{
size_t len = pfile->out.cur - pfile->out.base;
maybe_print_line (pfile->out.first_line);
fwrite (pfile->out.base, 1, len, print.outf);
print.printed = 1;
if (!CPP_OPTION (pfile, discard_comments))
account_for_newlines (pfile->out.base, len);
}
}
static void
maybe_print_line (source_location src_loc)
{
const struct line_map *map = linemap_lookup (&line_table, src_loc);
int src_line = SOURCE_LINE (map, src_loc);
if (print.printed)
{
putc ('\n', print.outf);
print.src_line++;
print.printed = 0;
}
if (src_line >= print.src_line && src_line < print.src_line + 8)
{
while (src_line > print.src_line)
{
putc ('\n', print.outf);
print.src_line++;
}
}
else
print_line (src_loc, "");
}
static void
print_line (source_location src_loc, const char *special_flags)
{
if (print.printed)
putc ('\n', print.outf);
print.printed = 0;
if (!flag_no_line_commands)
{
const struct line_map *map = linemap_lookup (&line_table, src_loc);
size_t to_file_len = strlen (map->to_file);
unsigned char *to_file_quoted =
(unsigned char *) alloca (to_file_len * 4 + 1);
unsigned char *p;
print.src_line = SOURCE_LINE (map, src_loc);
p = cpp_quote_string (to_file_quoted,
(unsigned char *) map->to_file, to_file_len);
*p = '\0';
fprintf (print.outf, "# %u \"%s\"%s",
print.src_line == 0 ? 1 : print.src_line,
to_file_quoted, special_flags);
if (map->sysp == 2)
fputs (" 3 4", print.outf);
else if (map->sysp == 1)
fputs (" 3", print.outf);
putc ('\n', print.outf);
}
}
static void
cb_line_change (cpp_reader *pfile, const cpp_token *token,
int parsing_args)
{
source_location src_loc = token->src_loc;
if (token->type == CPP_EOF || parsing_args)
return;
maybe_print_line (src_loc);
print.prev = 0;
print.source = 0;
if (!CPP_OPTION (pfile, traditional))
{
const struct line_map *map = linemap_lookup (&line_table, src_loc);
int spaces = SOURCE_COLUMN (map, src_loc) - 2;
print.printed = 1;
while (-- spaces >= 0)
putc (' ', print.outf);
}
}
static void
cb_ident (cpp_reader *pfile ATTRIBUTE_UNUSED, source_location line,
const cpp_string *str)
{
maybe_print_line (line);
fprintf (print.outf, "#ident %s\n", str->text);
print.src_line++;
}
static void
cb_define (cpp_reader *pfile, source_location line, cpp_hashnode *node)
{
maybe_print_line (line);
fputs ("#define ", print.outf);
if (flag_dump_macros == 'D')
fputs ((const char *) cpp_macro_definition (pfile, node),
print.outf);
else
fputs ((const char *) NODE_NAME (node), print.outf);
putc ('\n', print.outf);
if (linemap_lookup (&line_table, line)->to_line != 0)
print.src_line++;
}
static void
cb_undef (cpp_reader *pfile ATTRIBUTE_UNUSED, source_location line,
cpp_hashnode *node)
{
maybe_print_line (line);
fprintf (print.outf, "#undef %s\n", NODE_NAME (node));
print.src_line++;
}
static void
cb_include (cpp_reader *pfile ATTRIBUTE_UNUSED, source_location line,
const unsigned char *dir, const char *header, int angle_brackets,
const cpp_token **comments)
{
maybe_print_line (line);
if (angle_brackets)
fprintf (print.outf, "#%s <%s>", dir, header);
else
fprintf (print.outf, "#%s \"%s\"", dir, header);
if (comments != NULL)
{
while (*comments != NULL)
{
if ((*comments)->flags & PREV_WHITE)
putc (' ', print.outf);
cpp_output_token (*comments, print.outf);
++comments;
}
}
putc ('\n', print.outf);
print.src_line++;
}
void
pp_dir_change (cpp_reader *pfile ATTRIBUTE_UNUSED, const char *dir)
{
size_t to_file_len = strlen (dir);
unsigned char *to_file_quoted =
(unsigned char *) alloca (to_file_len * 4 + 1);
unsigned char *p;
p = cpp_quote_string (to_file_quoted, (unsigned char *) dir, to_file_len);
*p = '\0';
fprintf (print.outf, "# 1 \"%s//\"\n", to_file_quoted);
}
void
pp_file_change (const struct line_map *map)
{
const char *flags = "";
if (flag_no_line_commands)
return;
if (map != NULL)
{
if (print.first_time)
{
if (!cpp_get_options (parse_in)->preprocessed)
print_line (map->start_location, flags);
print.first_time = 0;
}
else
{
if (map->reason == LC_ENTER)
{
const struct line_map *from = INCLUDED_FROM (&line_table, map);
maybe_print_line (LAST_SOURCE_LINE_LOCATION (from));
}
if (map->reason == LC_ENTER)
flags = " 1";
else if (map->reason == LC_LEAVE)
flags = " 2";
print_line (map->start_location, flags);
}
}
}
static void
cb_def_pragma (cpp_reader *pfile, source_location line)
{
maybe_print_line (line);
fputs ("#pragma ", print.outf);
cpp_output_line (pfile, print.outf);
print.src_line++;
}
static int
dump_macro (cpp_reader *pfile, cpp_hashnode *node, void *v ATTRIBUTE_UNUSED)
{
if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN))
{
fputs ("#define ", print.outf);
fputs ((const char *) cpp_macro_definition (pfile, node),
print.outf);
putc ('\n', print.outf);
print.src_line++;
}
return 1;
}
static void
cb_read_pch (cpp_reader *pfile, const char *name,
int fd, const char *orig_name ATTRIBUTE_UNUSED)
{
c_common_read_pch (pfile, name, fd, orig_name);
fprintf (print.outf, "#pragma GCC pch_preprocess \"%s\"\n", name);
print.src_line++;
}