/* CUR points to any character in the input buffer. Skips over all contiguous horizontal white space and NULs, including comments if SKIP_COMMENTS, until reaching the first non-horizontal-whitespace character or the end of the current context. Escaped newlines are removed. The whitespace is copied verbatim to the output buffer, except that comments are handled as described in copy_comment(). pfile->out.cur is updated. Returns a pointer to the first character after the whitespace in the input buffer. */ static const uchar * skip_whitespace (cpp_reader *pfile, const uchar *cur, int skip_comments) { uchar *out = pfile->out.cur; for (;;) { unsigned int c = *cur++; *out++ = c; if (is_nvspace (c)) continue; if (c == '/' && *cur == '*' && skip_comments) { pfile->out.cur = out; cur = copy_comment (pfile, cur, false /* in_define */); out = pfile->out.cur; continue; } out--; break; } pfile->out.cur = out; return cur - 1; }
/* Skips whitespace, saving the next non-whitespace character. */ static void skip_whitespace (cpp_reader *pfile, cppchar_t c) { cpp_buffer *buffer = pfile->buffer; bool saw_NUL = false; do { /* Horizontal space always OK. */ if (c == ' ' || c == '\t') ; /* Just \f \v or \0 left. */ else if (c == '\0') saw_NUL = true; else if (pfile->state.in_directive && CPP_PEDANTIC (pfile)) cpp_error_with_line (pfile, CPP_DL_PEDWARN, pfile->line_table->highest_line, CPP_BUF_COL (buffer), "%s in preprocessing directive", c == '\f' ? "form feed" : "vertical tab"); c = *buffer->cur++; } /* We only want non-vertical space, i.e. ' ' \t \f \v \0. */ while (is_nvspace (c)); if (saw_NUL) cpp_error (pfile, CPP_DL_WARNING, "null character(s) ignored"); buffer->cur--; }
/* Return true if the trigraph indicated by NOTE should be warned about in a comment. */ static bool warn_in_comment (cpp_reader *pfile, _cpp_line_note *note) { const uchar *p; /* Within comments we don't warn about trigraphs, unless the trigraph forms an escaped newline, as that may change behavior. */ if (note->type != '/') return false; /* If -trigraphs, then this was an escaped newline iff the next note is coincident. */ if (CPP_OPTION (pfile, trigraphs)) return note[1].pos == note->pos; /* Otherwise, see if this forms an escaped newline. */ p = note->pos + 3; while (is_nvspace (*p)) p++; /* There might have been escaped newlines between the trigraph and the newline we found. Hence the position test. */ return (*p == '\n' && p < note[1].pos); }
/* 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; }
/* Returns with a logical line that contains no escaped newlines or trigraphs. This is a time-critical inner loop. */ void _cpp_clean_line (cpp_reader *pfile) { cpp_buffer *buffer; const uchar *s; uchar c, *d, *p; buffer = pfile->buffer; buffer->cur_note = buffer->notes_used = 0; buffer->cur = buffer->line_base = buffer->next_line; buffer->need_line = false; s = buffer->next_line - 1; if (!buffer->from_stage3) { const uchar *pbackslash = NULL; /* Short circuit for the common case of an un-escaped line with no trigraphs. The primary win here is by not writing any data back to memory until we have to. */ for (;;) { c = *++s; if (__builtin_expect (c == '\n', false) || __builtin_expect (c == '\r', false)) { d = (uchar *) s; if (__builtin_expect (s == buffer->rlimit, false)) goto done; /* DOS line ending? */ if (__builtin_expect (c == '\r', false) && s[1] == '\n') { s++; if (s == buffer->rlimit) goto done; } if (__builtin_expect (pbackslash == NULL, true)) goto done; /* Check for escaped newline. */ p = d; while (is_nvspace (p[-1])) p--; if (p - 1 != pbackslash) goto done; /* Have an escaped newline; process it and proceed to the slow path. */ add_line_note (buffer, p - 1, p != d ? ' ' : '\\'); d = p - 2; buffer->next_line = p - 1; break; } if (__builtin_expect (c == '\\', false)) pbackslash = s; else if (__builtin_expect (c == '?', false) && __builtin_expect (s[1] == '?', false) && _cpp_trigraph_map[s[2]]) { /* Have a trigraph. We may or may not have to convert it. Add a line note regardless, for -Wtrigraphs. */ add_line_note (buffer, s, s[2]); if (CPP_OPTION (pfile, trigraphs)) { /* We do, and that means we have to switch to the slow path. */ d = (uchar *) s; *d = _cpp_trigraph_map[s[2]]; s += 2; break; } } } for (;;) { c = *++s; *++d = c; if (c == '\n' || c == '\r') { /* Handle DOS line endings. */ if (c == '\r' && s != buffer->rlimit && s[1] == '\n') s++; if (s == buffer->rlimit) break; /* Escaped? */ p = d; while (p != buffer->next_line && is_nvspace (p[-1])) p--; if (p == buffer->next_line || p[-1] != '\\') break; add_line_note (buffer, p - 1, p != d ? ' ': '\\'); d = p - 2; buffer->next_line = p - 1; } else if (c == '?' && s[1] == '?' && _cpp_trigraph_map[s[2]]) { /* Add a note regardless, for the benefit of -Wtrigraphs. */ add_line_note (buffer, d, s[2]); if (CPP_OPTION (pfile, trigraphs)) { *d = _cpp_trigraph_map[s[2]]; s += 2; } } } } else { do s++; while (*s != '\n' && *s != '\r'); d = (uchar *) s; /* Handle DOS line endings. */ if (*s == '\r' && s != buffer->rlimit && s[1] == '\n') s++; } done: *d = '\n'; /* A sentinel note that should never be processed. */ add_line_note (buffer, d + 1, '\n'); buffer->next_line = s + 1; }