Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pret
GitHub Repository: pret/pokered
Path: blob/master/tools/common.h
1270 views
1
#ifndef GUARD_COMMON_H
2
#define GUARD_COMMON_H
3
4
#include <stdio.h>
5
#include <stdlib.h>
6
#include <stdint.h>
7
#include <stdbool.h>
8
#include <stddef.h>
9
#include <stdnoreturn.h>
10
#include <inttypes.h>
11
#include <string.h>
12
#include <errno.h>
13
#include <getopt.h>
14
15
#ifndef PROGRAM_NAME
16
#error Define PROGRAM_NAME before including common.h!
17
#endif
18
#ifndef USAGE_OPTS
19
#error Define USAGE_OPTS before including common.h!
20
#endif
21
22
#define COUNTOF(...) (sizeof(__VA_ARGS__) / sizeof(*(__VA_ARGS__)))
23
24
#define error_exit(...) exit((fprintf(stderr, PROGRAM_NAME ": " __VA_ARGS__), 1))
25
26
noreturn void usage_exit(int status) {
27
fprintf(stderr, "Usage: " PROGRAM_NAME " " USAGE_OPTS "\n");
28
exit(status);
29
}
30
31
int getopt_long_index;
32
#define getopt_long(argc, argv, optstring, longopts) getopt_long(argc, argv, optstring, longopts, &getopt_long_index)
33
34
void *xmalloc(size_t size) {
35
errno = 0;
36
void *m = malloc(size);
37
if (!m) {
38
error_exit("Could not allocate %zu bytes: %s\n", size, strerror(errno));
39
}
40
return m;
41
}
42
43
void *xcalloc(size_t size) {
44
errno = 0;
45
void *m = calloc(size, 1);
46
if (!m) {
47
error_exit("Could not allocate %zu bytes: %s\n", size, strerror(errno));
48
}
49
return m;
50
}
51
52
void *xrealloc(void *m, size_t size) {
53
errno = 0;
54
m = realloc(m, size);
55
if (!m) {
56
error_exit("Could not allocate %zu bytes: %s\n", size, strerror(errno));
57
}
58
return m;
59
}
60
61
FILE *xfopen(const char *filename, char rw) {
62
char mode[3] = {rw, 'b', '\0'};
63
errno = 0;
64
FILE *f = fopen(filename, mode);
65
if (!f) {
66
error_exit("Could not open file \"%s\": %s\n", filename, strerror(errno));
67
}
68
return f;
69
}
70
71
void xfread(uint8_t *data, size_t size, const char *filename, FILE *f) {
72
errno = 0;
73
if (fread(data, 1, size, f) != size) {
74
fclose(f);
75
error_exit("Could not read from file \"%s\": %s\n", filename, strerror(errno));
76
}
77
}
78
79
void xfwrite(const uint8_t *data, size_t size, const char *filename, FILE *f) {
80
errno = 0;
81
if (fwrite(data, 1, size, f) != size) {
82
fclose(f);
83
error_exit("Could not write to file \"%s\": %s\n", filename, strerror(errno));
84
}
85
}
86
87
long xfsize(const char *filename, FILE *f) {
88
long size = -1;
89
errno = 0;
90
if (!fseek(f, 0, SEEK_END)) {
91
size = ftell(f);
92
if (size != -1) {
93
rewind(f);
94
}
95
}
96
if (size == -1) {
97
error_exit("Could not measure file \"%s\": %s\n", filename, strerror(errno));
98
}
99
return size;
100
}
101
102
uint8_t *read_u8(const char *filename, long *size) {
103
FILE *f = xfopen(filename, 'r');
104
*size = xfsize(filename, f);
105
uint8_t *data = xmalloc(*size);
106
xfread(data, *size, filename, f);
107
fclose(f);
108
return data;
109
}
110
111
void write_u8(const char *filename, uint8_t *data, size_t size) {
112
FILE *f = xfopen(filename, 'w');
113
xfwrite(data, size, filename, f);
114
fclose(f);
115
}
116
117
uint32_t read_png_width(const char *filename) {
118
FILE *f = xfopen(filename, 'r');
119
uint8_t header[16] = {0};
120
xfread(header, sizeof(header), filename, f);
121
static uint8_t expected_header[16] = {
122
0x89, 'P', 'N', 'G', '\r', '\n', 0x1A, '\n', // signature
123
0, 0, 0, 13, // IHDR chunk length
124
'I', 'H', 'D', 'R', // IHDR chunk type
125
};
126
if (memcmp(header, expected_header, sizeof(header))) {
127
fclose(f);
128
error_exit("Not a valid PNG file: \"%s\"\n", filename);
129
}
130
uint8_t bytes[4] = {0};
131
xfread(bytes, sizeof(bytes), filename, f);
132
fclose(f);
133
return (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3];
134
}
135
136
#endif // GUARD_COMMON_H
137
138