aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/cc1/io.c
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-05-03 17:29:12 +0900
committernsfisis <nsfisis@gmail.com>2026-05-03 18:42:58 +0900
commit3654ce578e6fff53950874adf7e0e4ae0a6eb956 (patch)
tree5b6c04273de38dba70b7c25e55da144f5f7c37da /src/cc1/io.c
parent1b406b13b03055d2b2d08e8279a4a80c41ca7c20 (diff)
downloadducc-3654ce578e6fff53950874adf7e0e4ae0a6eb956.tar.gz
ducc-3654ce578e6fff53950874adf7e0e4ae0a6eb956.tar.zst
ducc-3654ce578e6fff53950874adf7e0e4ae0a6eb956.zip
refactor: organize directory structureHEADmain
Diffstat (limited to 'src/cc1/io.c')
-rw-r--r--src/cc1/io.c127
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;
+ }
+}