diff options
Diffstat (limited to 'src/cc1/io.c')
| -rw-r--r-- | src/cc1/io.c | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/src/cc1/io.c b/src/cc1/io.c new file mode 100644 index 0000000..65cd448 --- /dev/null +++ b/src/cc1/io.c @@ -0,0 +1,127 @@ +#include "io.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "../lib/common.h" +#include "../lib/json.h" + +void sourcelocation_build_json(JsonBuilder* builder, SourceLocation* loc) { + jsonbuilder_object_start(builder); + jsonbuilder_object_member_start(builder, "filename"); + jsonbuilder_string(builder, loc->filename); + jsonbuilder_object_member_end(builder); + jsonbuilder_object_member_start(builder, "line"); + jsonbuilder_integer(builder, loc->line); + jsonbuilder_object_member_end(builder); + jsonbuilder_object_end(builder); +} + +InFile* infile_open(const char* filename) { + FILE* in = fopen(filename, "rb"); + if (!in) { + return NULL; + } + + size_t buf_size = 1024 * 10; + char* buf = calloc(buf_size, sizeof(char)); + char* cur = buf; + char* tmp = calloc(1024, sizeof(char)); + + while (fgets(tmp, 1024, in)) { + size_t len = strlen(tmp); + size_t used_size = cur - buf; + + if (buf_size <= used_size + len) { + size_t old_size = buf_size; + buf_size *= 2; + buf = realloc(buf, buf_size); + memset(buf + old_size, 0, buf_size - old_size); + cur = buf + used_size; + } + + memcpy(cur, tmp, len); + cur += len; + } + fclose(in); + + InFile* in_file = calloc(1, sizeof(InFile)); + in_file->buf = buf; + in_file->loc.filename = filename; + in_file->loc.line = 1; + return in_file; +} + +bool infile_eof(InFile* f) { + return f->buf[f->pos] == '\0'; +} + +char infile_peek_char(InFile* f) { + char c = f->buf[f->pos]; + + // Skip a pair of backslash and new-line. + if (c == '\\') { + char c2 = f->buf[f->pos + 1]; + // C23: 5.1.1.2 + // A source file that is not empty shall end in a new-line character, which shall not be immediately preceded by + // a backslash character before any such splicing takes place. + if (c2 == '\0') { + fatal_error("%s:%d: <new-line> expected, but got <eof>", f->loc.filename, f->loc.line); + } + // Handle line continuation. + if (c2 == '\r') { + if (f->buf[f->pos + 2] == '\n') { + f->pos += 3; // Backslash + CRLF + } else { + f->pos += 2; // Backslash + CR + } + ++f->loc.line; + return infile_peek_char(f); + } else if (c2 == '\n') { + f->pos += 2; // Backslash + LF + ++f->loc.line; + return infile_peek_char(f); + } + } + + // Normalize new-line. + if (c == '\r') + c = '\n'; + return c; +} + +char infile_next_char(InFile* f) { + char c = infile_peek_char(f); + + if (f->buf[f->pos] == '\r') { + ++f->pos; + if (f->buf[f->pos] == '\n') { + ++f->pos; // CRLF + } + c = '\n'; + } else { + ++f->pos; + } + + if (c == '\n') + ++f->loc.line; + return c; +} + +char infile_peek_char2(InFile* f) { + int saved_pos = f->pos; + int saved_line = f->loc.line; + infile_next_char(f); + char c = infile_peek_char(f); + f->pos = saved_pos; + f->loc.line = saved_line; + return c; +} + +bool infile_consume_if(InFile* f, char expected) { + if (infile_peek_char(f) == expected) { + infile_next_char(f); + return true; + } else { + return false; + } +} |
