pass-lang/src/io.c

137 lines
3.1 KiB
C

#include "io.h"
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef __unix__
#include <sys/stat.h>
#endif
static const char* outfile_name;
static FILE* infile;
static FILE* outfile;
void open_files(const char* infile_name, const char* outfile_name_) {
outfile_name = outfile_name_;
infile = fopen(infile_name, "rb");
if (infile == NULL) {
fprintf(stderr, "failed to open source file: %s\n", strerror(errno));
exit(1);
}
outfile = fopen(outfile_name, "wb");
if (outfile == NULL) {
fprintf(stderr, "failed to open output file: %s\n", strerror(errno));
exit(1);
}
}
void close_files(void) {
fclose(infile);
if (fclose(outfile) != 0) {
fprintf(stderr, "failed to close output file: %s\n", strerror(errno));
// NOTE: ideally we'd do this on any dirty exit
if (remove(outfile_name) != 0) {
fprintf(stderr, "failed to remove output file; if it exists, it is corrupt: %s\n", strerror(errno));
}
exit(1);
}
#ifdef __unix__
chmod(outfile_name, 0777);
#endif
}
void reserve(size_t len) {
if (fseek(outfile, len, SEEK_CUR) != 0) {
fprintf(stderr, "failed to reserve space in in output file: %s\n", strerror(errno));
exit(1);
}
}
void emit(const void* restrict ptr, size_t count) {
fwrite(ptr, 1, count, outfile);
if (ferror(outfile)) {
fprintf(stderr, "failed to write to output file\n");
exit(1);
}
}
void emit_u8(uint8_t x) {
emit(&x, sizeof(uint8_t));
}
void emit_u32(uint32_t x) {
emit(&x, sizeof(uint32_t));
}
void emit_u64(uint64_t x) {
emit(&x, sizeof(uint64_t));
}
void patch(size_t off, const void* ptr, size_t count) {
fpos_t save;
if (fgetpos(outfile, &save) != 0) {
fprintf(stderr, "failed to save file position before patch: %s\n", strerror(errno));
exit(1);
}
if (fseek(outfile, (long) off, SEEK_SET) != 0) {
fprintf(stderr, "failed to set file position for patch: %s\n", strerror(errno));
exit(1);
}
fwrite(ptr, 1, count, outfile);
if (ferror(outfile) != 0) {
fprintf(stderr, "failed to patch output file: %s\n", strerror(errno));
exit(1);
}
if (fsetpos(outfile, &save) != 0) {
fprintf(stderr, "failed to restore file position after patch: %s\n", strerror(errno));
exit(1);
}
}
void patch_u32(size_t off, uint32_t x) {
patch(off, &x, sizeof(uint32_t));
}
void patch_i32(size_t off, int32_t x) {
patch_u32(off, (uint32_t) x);
}
static _Bool init = false;
static char peek_buf;
static char next_(void) {
char c = getc(infile);
if (c == EOF) {
if (ferror(infile)) {
fprintf(stderr, "failed to read source file: %s\n", strerror(errno));
exit(1);
}
c = 0;
}
return c;
}
char nextc(void) {
if (!init) {
init = true;
peek_buf = next_();
}
int tmp = peek_buf;
peek_buf = next_();
return peek_buf;
}
char peekc(void) {
if (!init) {
init = true;
return nextc();
}
return peek_buf;
}