summaryrefslogtreecommitdiff
path: root/tools/common.h
diff options
context:
space:
mode:
authorRangi <remy.oukaour+rangi42@gmail.com>2022-03-08 21:52:57 -0500
committerRangi <remy.oukaour+rangi42@gmail.com>2022-03-08 21:52:57 -0500
commita75dd222709c92ae136d835ff2451391d5a88e45 (patch)
tree9bb631acafee493c6fc75335964b4774d023f2e1 /tools/common.h
parent7e78c1171d1206ca2f31cc67c55cc715eeb44ee5 (diff)
Slightly refactor some C tools
Diffstat (limited to 'tools/common.h')
-rw-r--r--tools/common.h130
1 files changed, 111 insertions, 19 deletions
diff --git a/tools/common.h b/tools/common.h
index 4da0b2ef..a8b69445 100644
--- a/tools/common.h
+++ b/tools/common.h
@@ -1,40 +1,132 @@
#ifndef GUARD_COMMON_H
#define GUARD_COMMON_H
-int __getopt_long_i__;
-#define getopt_long(c, v, s, l) getopt_long(c, v, s, l, &__getopt_long_i__)
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
-FILE *fopen_verbose(char *filename, char *mode) {
+#ifndef PROGRAM_NAME
+#error Define PROGRAM_NAME before including common.h!
+#endif
+#ifndef USAGE_OPTS
+#error Define USAGE_OPTS before including common.h!
+#endif
+
+#define error_exit(...) exit((fprintf(stderr, PROGRAM_NAME ": " __VA_ARGS__), 1))
+
+void usage_exit(int status) {
+ fprintf(stderr, "Usage: " PROGRAM_NAME " " USAGE_OPTS "\n");
+ exit(status);
+}
+
+int getopt_long_index;
+#define getopt_long(argc, argv, optstring, longopts) getopt_long(argc, argv, optstring, longopts, &getopt_long_index)
+
+void *xmalloc(size_t size) {
+ errno = 0;
+ void *m = malloc(size);
+ if (!m) {
+ error_exit("Could not allocate %zu bytes: %s\n", size, strerror(errno));
+ }
+ return m;
+}
+
+void *xcalloc(size_t size) {
+ errno = 0;
+ void *m = calloc(size, 1);
+ if (!m) {
+ error_exit("Could not allocate %zu bytes: %s\n", size, strerror(errno));
+ }
+ return m;
+}
+
+void *xrealloc(void *m, size_t size) {
+ errno = 0;
+ m = realloc(m, size);
+ if (!m) {
+ error_exit("Could not allocate %zu bytes: %s\n", size, strerror(errno));
+ }
+ return m;
+}
+
+FILE *xfopen(const char *filename, char rw) {
+ char mode[3] = {rw, 'b', '\0'};
+ errno = 0;
FILE *f = fopen(filename, mode);
if (!f) {
- fprintf(stderr, "Could not open file: \"%s\"\n", filename);
+ error_exit("Could not open file \"%s\": %s\n", filename, strerror(errno));
}
return f;
}
-uint8_t *read_u8(char *filename, int *size) {
- FILE *f = fopen_verbose(filename, "rb");
- if (!f) {
- exit(1);
+void xfread(uint8_t *data, size_t size, const char *filename, FILE *f) {
+ errno = 0;
+ if (fread(data, 1, size, f) != size) {
+ fclose(f);
+ error_exit("Could not read from file \"%s\": %s\n", filename, strerror(errno));
+ }
+}
+
+void xfwrite(const uint8_t *data, size_t size, const char *filename, FILE *f) {
+ errno = 0;
+ if (fwrite(data, 1, size, f) != size) {
+ fclose(f);
+ error_exit("Could not write to file \"%s\": %s\n", filename, strerror(errno));
+ }
+}
+
+long xfsize(const char *filename, FILE *f) {
+ long size = -1;
+ errno = 0;
+ if (!fseek(f, 0, SEEK_END)) {
+ size = ftell(f);
+ if (size != -1) {
+ rewind(f);
+ }
}
- fseek(f, 0, SEEK_END);
- *size = ftell(f);
- rewind(f);
- uint8_t *data = malloc(*size);
- if (*size != (int)fread(data, 1, *size, f)) {
- fprintf(stderr, "Could not read file: \"%s\"\n", filename);
- exit(1);
+ if (size == -1) {
+ error_exit("Could not measure file \"%s\": %s\n", filename, strerror(errno));
}
+ return size;
+}
+
+uint8_t *read_u8(const char *filename, long *size) {
+ FILE *f = xfopen(filename, 'r');
+ *size = xfsize(filename, f);
+ uint8_t *data = xmalloc(*size);
+ xfread(data, *size, filename, f);
fclose(f);
return data;
}
-void write_u8(char *filename, uint8_t *data, int size) {
- FILE *f = fopen_verbose(filename, "wb");
- if (f) {
- fwrite(data, 1, size, f);
+void write_u8(const char *filename, uint8_t *data, size_t size) {
+ FILE *f = xfopen(filename, 'w');
+ xfwrite(data, size, filename, f);
+ fclose(f);
+}
+
+uint32_t read_png_width(const char *filename) {
+ FILE *f = xfopen(filename, 'r');
+ uint8_t header[16] = {0};
+ xfread(header, sizeof(header), filename, f);
+ static uint8_t expected_header[16] = {
+ 0x89, 'P', 'N', 'G', '\r', '\n', 0x1A, '\n', // signature
+ 0, 0, 0, 13, // IHDR chunk length
+ 'I', 'H', 'D', 'R', // IHDR chunk type
+ };
+ if (memcmp(header, expected_header, sizeof(header))) {
fclose(f);
+ error_exit("Not a valid PNG file: \"%s\"\n", filename);
}
+ uint8_t bytes[4] = {0};
+ xfread(bytes, sizeof(bytes), filename, f);
+ fclose(f);
+ return (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3];
}
#endif // GUARD_COMMON_H