-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbi.h
105 lines (81 loc) · 2.64 KB
/
bi.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#ifndef BI_H_
#define BI_H_
#include <assert.h>
#include <stddef.h>
#include <stdbool.h>
typedef enum {
BI_BLOB = 'b',
BI_INT = 'i',
} Bi_Type;
typedef struct {
const char *start;
size_t count;
size_t offset;
struct {
size_t offset; // offset at which the field starts
char type; // BI_BLOB or BI_INT, might be something else if the file is incorrect, always check for that
const char *name;
size_t name_count;
size_t integer; // acts like size of the blob when type is BI_BLOB
const char *blob_start;
} field;
} Bi;
#define bi_is_empty(bi) ((bi).offset >= (bi).count)
#define bi_is_digit(x) ('0' <= (x) && (x) <= '9') // so we don't depend on ctype.h
#define bi_chop_byte(bi) ((bi)->start[(bi)->offset++])
// Create a new Bi parser out of the blob field fetched with bi_get_field().
// Useful to parse .bi recursively.
Bi bi_of_blob(Bi bi);
// Parse the next field into bi->field. Returns true on success, returns false otherwise
bool bi_get_field(Bi *bi);
// Bi_Type as human readable name for logging
const char *bi_display_type(Bi_Type type);
#endif // BI_H_
#ifdef BI_IMPLEMENTATION
Bi bi_of_blob(Bi bi)
{
assert(bi.field.type == BI_BLOB);
return (Bi) {
.start = bi.field.blob_start,
.count = bi.field.integer,
};
}
bool bi_get_field(Bi *bi)
{
bi->field.offset = bi->offset;
if (bi_is_empty(*bi) || bi_chop_byte(bi) != ':') return false;
if (bi_is_empty(*bi)) return false;
bi->field.type = bi_chop_byte(bi);
if (bi_is_empty(*bi) || bi_chop_byte(bi) != ' ') return false;
bi->field.name = &bi->start[bi->offset];
bi->field.name_count = 0;
while (!bi_is_empty(*bi) && bi->start[bi->offset] != ' ') {
bi->field.name_count++;
bi->offset++;
}
if (bi_is_empty(*bi) || bi_chop_byte(bi) != ' ') return false;
bi->field.integer = 0;
while (!bi_is_empty(*bi) && bi_is_digit(bi->start[bi->offset])) {
bi->field.integer *= 10;
bi->field.integer += bi_chop_byte(bi);
bi->field.integer -= '0';
}
if (bi_is_empty(*bi) || bi_chop_byte(bi) != '\n') return false;
bi->field.blob_start = NULL;
if (bi->field.type == BI_BLOB) {
bi->field.blob_start = &bi->start[bi->offset];
bi->offset += bi->field.integer;
if (bi_is_empty(*bi) || bi_chop_byte(bi) != '\n') return false;
return true;
}
return true;
}
const char *bi_display_type(Bi_Type type)
{
switch (type) {
case BI_INT: return "Integer";
case BI_BLOB: return "Blob";
default: return "Unknown";
}
}
#endif // BI_IMPLEMENTATION