-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.c
188 lines (155 loc) · 5.51 KB
/
main.c
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "stb_c_lexer.h"
#include "str_hashmap.h"
#include "config.h"
#define BLACKLIST_FILENAME ".minify_blacklist"
#define PRINTABLES "abcdefghijklmnopqrstuvwxyz"
struct str_hashmap g_ids_map; // will record all ids
size_t read_file_to_str(char **dst, char const *filename) {
FILE *file = fopen(filename, "rb");
if (!file) {
fprintf(stderr, "Cannot open file %s\n", filename);
return 0;
}
fseek(file, 0, SEEK_END);
size_t len = ftell(file);
if (!len) {
return 0; // Don't read and malloc an empty file
}
*dst = (char*)malloc(len+1);
fseek(file, 0, SEEK_SET);
size_t read = fread(*dst, sizeof(char), len, file);
fclose(file);
(*dst)[len] = '\0';
if (read != len) {
free(*dst);
fprintf(stderr, "Failed to read file %s\n", filename);
return 0;
}
return len;
}
void gen_alias(char* id, size_t len) {
static struct str_hashmap ids = {0};
static unsigned long current = 0; // current "number" (to become a base 26)
if (!ids.capacity) { // init known ids hashmap if not done yet
ids = str_hashmap_init(2048);
}
char *gen_id = str_hashmap_get(&ids, id); // check if id is known
size_t gen_len; // len of string to be written to param "id"
if (gen_id) {
gen_len = strlen(gen_id);
strcpy(id, gen_id); // if id known, we can just write it out
} else {
char gen_id[32]; // TODO make this safer
do {
gen_len = 0; // start from most significant
long n = current; // our number
// Thank mr stackoverflow for helping a brainlet out
do {
// insert the character this digit represents
gen_id[gen_len++] = PRINTABLES[n % (sizeof(PRINTABLES)-1)];
// move "magnitude" of n down to the next less significant digit
} while ((long)(n = n / (sizeof(PRINTABLES)-1) - 1) >= 0);
if (len <= gen_len) {
return; // don't give alias if no benefit
}
// next number for next call
current++;
gen_id[gen_len] = '\0';
// try again if id is potentially reserved
} while (str_hashmap_get(&g_ids_map, gen_id));
str_hashmap_put(&ids, id, gen_id); // save result of this id
strncpy(id, gen_id, gen_len); // write out
}
// fill rest of transformed id with whitespace
for (size_t i = gen_len; i<len; i++) {
id[i] = ' ';
}
}
void replace_id_with_alias(stb_lexer *lex, struct str_hashmap *blacklist_map) {
size_t len = strlen(lex->string);
gen_alias(lex->string, len);
strncpy(lex->parse_point-len, lex->string, len);
}
void record_id_to_blacklist(stb_lexer *lex, struct str_hashmap *blacklist_map) {
str_hashmap_put(blacklist_map, lex->string, "");
}
void process(char *src, size_t len, struct str_hashmap *blacklist_map, void(*callback)(stb_lexer*, struct str_hashmap*)) {
stb_lexer lex;
char *tmp = (char*)malloc(len*2); // stb_lexer scratch space
stb_c_lexer_init(&lex, src, src+len, tmp, len*2);
while (stb_c_lexer_get_token(&lex)) {
if (lex.token == CLEX_id) {
if (!str_hashmap_get(blacklist_map, lex.string)) {
callback(&lex, blacklist_map);
}
}
}
free(tmp);
}
struct str_hashmap load_blacklist(char **header_files) {
char *str;
size_t len = read_file_to_str(&str, BLACKLIST_FILENAME);
struct str_hashmap map = str_hashmap_init(128);
if (len) {
for (char *token = strtok(str, "\n"); token; token = strtok(NULL, "\n")) {
if (*token != '#' && *token != '\n') { // ignore comment or empty
str_hashmap_put(&map, token, "");
}
}
free(str);
} // if read_file_to_str returns 0, should be nothing to free up manually
for (int i=0; i < sizeof(INTERNAL_BLACKLIST)/sizeof(char*); i++) {
str_hashmap_put(&map, INTERNAL_BLACKLIST[i], "");
}
for (char **f = header_files; *f != NULL; f++) {
len = read_file_to_str(&str, *f);
if (!len) {
exit(EXIT_FAILURE);
}
process(str, len, &map, record_id_to_blacklist);
free(str);
}
return map;
}
int main(int argc, char *argv[]) {
char *filename = NULL;
size_t header_files_size = sizeof(char*) * argc + 1;
char **header_files = (char**)malloc(header_files_size);
size_t header_files_n = 0;
memset(header_files, 0, header_files_size);
for (int i=1; i<argc; i++) {
if (strcmp(argv[i], "-h") == 0) {
if (i == argc - 1) {
fprintf(stderr, "-h expects a filename\n");
return EXIT_SUCCESS;
}
header_files[header_files_n++] = argv[++i];
} else {
filename = argv[i];
}
}
if (filename == NULL) {
fprintf(stderr, "please give an input file\n");
return EXIT_SUCCESS;
}
// Load blacklist
struct str_hashmap blacklist_map = load_blacklist(header_files);
free(header_files);
// Read source file
char *src;
size_t len = read_file_to_str(&src, filename);
if (!len) {
return EXIT_FAILURE;
}
// Pre-pass store all ids (globally, TODO refactor)
g_ids_map = str_hashmap_init(2048);
process(src, len, &g_ids_map, record_id_to_blacklist);
// Actually replace all ids
process(src, len, &blacklist_map, replace_id_with_alias);
puts(src);
free(src);
return EXIT_SUCCESS;
}