diff options
| author | nsfisis <nsfisis@gmail.com> | 2025-08-22 23:28:25 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2025-08-22 23:28:25 +0900 |
| commit | 9c202a496e75903fe37e5c19cb97c98eba6e35f2 (patch) | |
| tree | 52de494a4717a3c30c4bacb9dd9b91980be2a575 /src/io.c | |
| parent | 0ac6ac95283735dd70ebf55b26ef78a4c32c31de (diff) | |
| download | ducc-9c202a496e75903fe37e5c19cb97c98eba6e35f2.tar.gz ducc-9c202a496e75903fe37e5c19cb97c98eba6e35f2.tar.zst ducc-9c202a496e75903fe37e5c19cb97c98eba6e35f2.zip | |
chore: move *.c and *.h files to src/
Diffstat (limited to 'src/io.c')
| -rw-r--r-- | src/io.c | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/src/io.c b/src/io.c new file mode 100644 index 0000000..5cd5e86 --- /dev/null +++ b/src/io.c @@ -0,0 +1,99 @@ +struct SourceLocation { + const char* filename; + int line; +}; +typedef struct SourceLocation SourceLocation; + +struct InFile { + const char* buf; + int pos; + SourceLocation loc; +}; +typedef struct InFile InFile; + +InFile* infile_open(const char* filename) { + FILE* in; + if (strcmp(filename, "-") == 0) { + in = stdin; + } else { + 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); + } + // TODO: crlf + if (c2 == '\r' || c2 == '\n') { + f->pos += 2; + return infile_peek_char(f); + } + } + + // Normalize new-line. + // TODO: crlf + if (c == '\r') + c = '\n'; + return c; +} + +char infile_next_char(InFile* f) { + char c = infile_peek_char(f); + ++f->pos; + if (c == '\n') + ++f->loc.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; + } +} |
