/* This is called at the end of preprocessing. It pops the last buffer and writes dependency output. Maybe it should also reset state, such that you could call cpp_start_read with a new filename to restart processing. */ void cpp_finish (cpp_reader *pfile, FILE *deps_stream) { /* Warn about unused macros before popping the final buffer. */ if (CPP_OPTION (pfile, warn_unused_macros)) cpp_forall_identifiers (pfile, _cpp_warn_if_unused_macro, NULL); /* lex.c leaves the final buffer on the stack. This it so that it returns an unending stream of CPP_EOFs to the client. If we popped the buffer, we'd dereference a NULL buffer pointer and segfault. It's nice to allow the client to do worry-free excess cpp_get_token calls. */ while (pfile->buffer) _cpp_pop_buffer (pfile); if (CPP_OPTION (pfile, deps.style) != DEPS_NONE && deps_stream) { deps_write (pfile->deps, deps_stream, 72); if (CPP_OPTION (pfile, deps.phony_targets)) deps_phony_targets (pfile->deps, deps_stream); } /* Report on headers that could use multiple include guards. */ if (CPP_OPTION (pfile, print_include_names)) _cpp_report_missing_guards (pfile); }
/* Free resources used by PFILE. Accessing PFILE after this function returns leads to undefined behavior. Returns the error count. */ void cpp_destroy (cpp_reader *pfile) { cpp_context *context, *contextn; tokenrun *run, *runn; int i; free (pfile->op_stack); while (CPP_BUFFER (pfile) != NULL) _cpp_pop_buffer (pfile); if (pfile->out.base) free (pfile->out.base); if (pfile->macro_buffer) { free (pfile->macro_buffer); pfile->macro_buffer = NULL; pfile->macro_buffer_len = 0; } if (pfile->deps) deps_free (pfile->deps); obstack_free (&pfile->buffer_ob, 0); _cpp_destroy_hashtable (pfile); _cpp_cleanup_files (pfile); _cpp_destroy_iconv (pfile); _cpp_free_buff (pfile->a_buff); _cpp_free_buff (pfile->u_buff); _cpp_free_buff (pfile->free_buffs); for (run = &pfile->base_run; run; run = runn) { runn = run->next; free (run->base); if (run != &pfile->base_run) free (run); } for (context = pfile->base_context.next; context; context = contextn) { contextn = context->next; free (context); } if (pfile->comments.entries) { for (i = 0; i < pfile->comments.count; i++) free (pfile->comments.entries[i].comment); free (pfile->comments.entries); } free (pfile); }
/* Returns true if a fresh line has been loaded. */ bool _cpp_get_fresh_line (cpp_reader *pfile) { int return_at_eof; /* We can't get a new line until we leave the current directive. */ if (pfile->state.in_directive) return false; for (;;) { cpp_buffer *buffer = pfile->buffer; if (!buffer->need_line) return true; if (buffer->next_line < buffer->rlimit) { _cpp_clean_line (pfile); return true; } /* First, get out of parsing arguments state. */ if (pfile->state.parsing_args) return false; /* End of buffer. Non-empty files should end in a newline. */ if (buffer->buf != buffer->rlimit && buffer->next_line > buffer->rlimit && !buffer->from_stage3) { /* Only warn once. */ buffer->next_line = buffer->rlimit; cpp_error_with_line (pfile, CPP_DL_PEDWARN, pfile->line - 1, CPP_BUF_COLUMN (buffer, buffer->cur), "no newline at end of file"); } return_at_eof = buffer->return_at_eof; _cpp_pop_buffer (pfile); if (pfile->buffer == NULL || return_at_eof) return false; } }
/* Writes out the preprocessed file, handling spacing and paste avoidance issues. */ void _cpp_preprocess_dir_only (cpp_reader *pfile, const struct _cpp_dir_only_callbacks *cb) { struct cpp_buffer *buffer; const unsigned char *cur, *base, *next_line, *rlimit; cppchar_t c, last_c; unsigned flags; linenum_type lines; int col; source_location loc; restart: /* Buffer initialization ala _cpp_clean_line(). */ buffer = pfile->buffer; buffer->cur_note = buffer->notes_used = 0; buffer->cur = buffer->line_base = buffer->next_line; buffer->need_line = false; /* This isn't really needed. It prevents a compiler warning, though. */ loc = pfile->line_table->highest_line; /* Scan initialization. */ next_line = cur = base = buffer->cur; rlimit = buffer->rlimit; flags = DO_BOL; lines = 0; col = 1; for (last_c = '\n', c = *cur; cur < rlimit; last_c = c, c = *++cur, ++col) { /* Skip over escaped newlines. */ if (__builtin_expect (c == '\\', false)) { const unsigned char *tmp = cur + 1; while (is_nvspace (*tmp) && tmp < rlimit) tmp++; if (*tmp == '\r') tmp++; if (*tmp == '\n' && tmp < rlimit) { CPP_INCREMENT_LINE (pfile, 0); lines++; col = 0; cur = tmp; c = last_c; continue; } } if (__builtin_expect (last_c == '#', false) && !(flags & DO_SPECIAL)) { if (c != '#' && (flags & DO_BOL)) { struct line_maps *line_table; if (!pfile->state.skipping && next_line != base) cb->print_lines (lines, base, next_line - base); /* Prep things for directive handling. */ buffer->next_line = cur; buffer->need_line = true; _cpp_get_fresh_line (pfile); /* Ensure proper column numbering for generated error messages. */ buffer->line_base -= col - 1; _cpp_handle_directive (pfile, 0 /* ignore indented */); /* Sanitize the line settings. Duplicate #include's can mess things up. */ line_table = pfile->line_table; line_table->highest_location = line_table->highest_line; /* The if block prevents us from outputing line information when the file ends with a directive and no newline. Note that we must use pfile->buffer, not buffer. */ if (pfile->buffer->next_line < pfile->buffer->rlimit) cb->maybe_print_line (pfile->line_table->highest_line); goto restart; } flags &= ~DO_BOL; pfile->mi_valid = false; } else if (__builtin_expect (last_c == '/', false) \ && !(flags & DO_SPECIAL) && c != '*' && c != '/') { /* If a previous slash is not starting a block comment, clear the DO_BOL flag. */ flags &= ~DO_BOL; pfile->mi_valid = false; } switch (c) { case '/': if ((flags & DO_BLOCK_COMMENT) && last_c == '*') { flags &= ~DO_BLOCK_COMMENT; c = 0; } else if (!(flags & DO_SPECIAL) && last_c == '/') flags |= DO_LINE_COMMENT; else if (!(flags & DO_SPECIAL)) /* Mark the position for possible error reporting. */ loc = linemap_position_for_column (pfile->line_table, col); break; case '*': if (!(flags & DO_SPECIAL)) { if (last_c == '/') flags |= DO_BLOCK_COMMENT; else { flags &= ~DO_BOL; pfile->mi_valid = false; } } break; case '\'': case '"': { unsigned state = (c == '"') ? DO_STRING : DO_CHAR; if (!(flags & DO_SPECIAL)) { flags |= state; flags &= ~DO_BOL; pfile->mi_valid = false; } else if ((flags & state) && last_c != '\\') flags &= ~state; break; } case '\\': { if ((flags & (DO_STRING | DO_CHAR)) && last_c == '\\') c = 0; if (!(flags & DO_SPECIAL)) { flags &= ~DO_BOL; pfile->mi_valid = false; } break; } case '\n': CPP_INCREMENT_LINE (pfile, 0); lines++; col = 0; flags &= ~DO_LINE_SPECIAL; if (!(flags & DO_SPECIAL)) flags |= DO_BOL; break; case '#': next_line = cur; /* Don't update DO_BOL yet. */ break; case ' ': case '\t': case '\f': case '\v': case '\0': break; default: if (!(flags & DO_SPECIAL)) { flags &= ~DO_BOL; pfile->mi_valid = false; } break; } } if (flags & DO_BLOCK_COMMENT) cpp_error_with_line (pfile, CPP_DL_ERROR, loc, 0, "unterminated comment"); if (!pfile->state.skipping && cur != base) { /* If the file was not newline terminated, add rlimit, which is guaranteed to point to a newline, to the end of our range. */ if (cur[-1] != '\n') { cur++; CPP_INCREMENT_LINE (pfile, 0); lines++; } cb->print_lines (lines, base, cur - base); } _cpp_pop_buffer (pfile); if (pfile->buffer) goto restart; }