2 Copyright (C) 2011 rofl0r
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "../lib/include/strlib.h"
20 #include "../lib/include/stringptrlist.h"
21 #include "../lib/include/stringptr.h"
22 #include "../lib/include/hashlist.h"
23 #include "../lib/include/fileparser.h"
24 #include "../lib/include/logger.h"
25 #include "../lib/include/strswitch.h"
31 typedef sblist size_t_ptrlist
;
44 static uint32_t daliashash_sp(stringptr
* str
) {
47 size_t size
= str
->size
;
56 stringptr
normalize(stringptr
* id
, char* workbuf
, ssize_t buflen
) {
60 stringptr res
= {workbuf
, 0};
62 for(i
= 0; i
< id
->size
; i
++) {
66 if(buflen
<= 0) goto err
;
67 *workbuf
++ = id
->ptr
[i
];
71 if(buflen
<= 0) goto err
;
72 ulz_snprintf(hexbuf
, 5, "0x%.2X", id
->ptr
[i
]);
73 memcpy(workbuf
, hexbuf
, 4);
82 res
.size
= os
- buflen
;
91 typedef sblist variant_info_list
;
95 size_t_ptrlist
* members
;
96 variant_info_list
* variants
;
100 variant_info
* find_variant(sblist
* variants
, int c
) {
103 for(i
= 0; i
< sblist_getsize(variants
); i
++) {
104 res
= sblist_get(variants
, i
);
105 if(res
->c
== c
) return res
;
110 int in_member_list(variant_info
* variant
, size_t index
) {
112 for(i
= 0; i
< sblist_getsize(variant
->members
); i
++) {
113 r
= sblist_get(variant
->members
, i
);
114 if (*r
== index
) return 1;
119 void write_enum(int outfd
, sectionrec
* sref
) {
121 hashlist_iterator iter2
;
123 stringptrlist
* newlist
;
125 stringptr
*entry
, normalized
;
129 log_put(outfd
, VARISL("typedef enum {\n\tstringswitch_enumerator_default_member_name("), VARIS(sref
->id
), VARISL("),"), NULL
);
132 hashlist_iterator_init(&iter2
);
133 while((href
= hashlist_next(h
, &iter2
))) {
134 newlist
= href
->list
;
135 for(i
= 0; i
< stringptrlist_getsize(newlist
); i
++) {
136 entry
= stringptrlist_get(newlist
, i
);
137 log_put(1, VARISL("id "), VARIS(sref
->id
), VARISL(", entry: "), VARII((int) entry
->size
), VARISL(", "), VARIS(entry
), NULL
);
138 normalized
= normalize(entry
, norm_buf
, sizeof(norm_buf
));
139 ulz_snprintf(buf
, sizeof(buf
), "\tstringswitch_enumerator_member_name(%s, %s),\n", sref
->id
->ptr
, normalized
.ptr
);
140 log_putc(outfd
, buf
);
144 log_put(outfd
, VARISL("} stringswitch_enumerator_name("), VARIS(sref
->id
), VARISL(");\n"), NULL
);
148 // initialise with members list, containing all ids
149 variant_info_list
* get_variants(size_t_ptrlist
* members
, stringptr
* last_prefix
, stringptrlist
* block_strings
, size_t block_len
) {
151 variant_info vr
, *vp
;
152 stringptr
* next_prefix
, *act
;
154 if(last_prefix
->size
== block_len
) return NULL
;
155 variant_info_list
* res
= NULL
;
159 for(i
= 0; i
< sblist_getsize(members
); i
++) {
160 id
= sblist_get(members
, i
);
161 act
= stringptrlist_get(block_strings
, *id
);
162 if(last_prefix
->size
== 0 || stringptr_here(act
, 0, last_prefix
)) {
163 if(!res
) res
= sblist_new(sizeof(variant_info
), 16);
164 if(!(vp
= find_variant(res
, act
->ptr
[last_prefix
->size
]))) {
165 vr
.c
= act
->ptr
[last_prefix
->size
];
166 vr
.members
= sblist_new(sizeof(size_t), stringptrlist_getsize(members
));
168 sblist_add(res
, &vr
);
169 vp
= find_variant(res
, vr
.c
);
171 sblist_add(vp
->members
, id
);
175 for (i
= 0; i
< sblist_getsize(res
); i
++) {
176 vp
= sblist_get(res
, i
);
180 next_prefix
= stringptr_concat(last_prefix
, &temp
, NULL
);
181 vp
->variants
= get_variants(vp
->members
, next_prefix
, block_strings
, block_len
);
187 void print_level_tabs(int fd
, size_t level
) {
189 for (i
= 0; i
< level
+ 3; i
++)
190 ulz_fprintf(fd
, "\t");
193 void dump_variants(int outfd
, stringptr
* section_name
, variant_info_list
* variants
,
194 stringptrlist
* block_strings
, size_t level
, size_t previous_membercount
, ssize_t backindent
) {
195 if(variants
== NULL
) return;
197 stringptr
* act
, normalized
;
202 sblist_iter(variants
, vp
) {
203 membercount
= sblist_getsize(vp
->members
);
204 if(membercount
== previous_membercount
) {
205 print_level_tabs(outfd
, level
- backindent
);
206 ulz_fprintf(outfd
, "if(str[%zu]!='%c') goto main_default;\n", level
, vp
->c
);
210 print_level_tabs(outfd
, level
- backindent
);
211 ulz_fprintf(outfd
, "switch(str[%zu]) {\n", level
);
215 print_level_tabs(outfd
, level
- backindent
);
216 ulz_fprintf(outfd
, "case '%c':\n", vp
->c
);
219 print_level_tabs(outfd
, level
- backindent
);
220 id
= sblist_get(vp
->members
, 0);
221 act
= sblist_get(block_strings
, *id
);
222 normalized
= normalize(act
, norm_buf
, sizeof(norm_buf
));
223 log_put(outfd
, VARISL("\treturn stringswitch_enumerator_member_name("),
224 VARIS(section_name
), VARISL(", "), VARIS(&normalized
), VARISL(");"), NULL
);
226 dump_variants(outfd
, section_name
, vp
->variants
, block_strings
, level
+1, membercount
, backindent
);
229 print_level_tabs(outfd
, level
- backindent
);
230 ulz_fprintf(outfd
, "default: goto main_default;\n");
232 print_level_tabs(outfd
, level
- backindent
);
233 ulz_fprintf(outfd
, "}\n");
237 void free_variants(variant_info_list
* v
) {
242 void write_length_block(int outfd
, hashrec
* block_href
, stringptr
* section_name
) {
243 stringptrlist
* newlist
;
248 newlist
= block_href
->list
;
249 log_put(outfd
, VARISL("\t\tcase "),VARII((int) block_href
->len
), VARISL(":"), NULL
);
251 size_t_ptrlist
* initial_members
= sblist_new(sizeof(size_t), stringptrlist_getsize(block_href
->list
));
255 for(i
= 0; i
< stringptrlist_getsize(block_href
->list
); i
++)
256 sblist_add(initial_members
, &i
);
258 variant_info_list
* variants
= get_variants(initial_members
, &temp
, block_href
->list
, block_href
->len
);
259 dump_variants(outfd
, section_name
, variants
, block_href
->list
, 0, stringptrlist_getsize(block_href
->list
), 0);
261 sblist_free(initial_members
);
262 free_variants(variants
);
266 void codegen(hashlist
* hashlists
) {
270 hashlist_iterator iter
, iter2
;
271 hashlist_iterator_init(&iter
);
275 if(hashlists
) while((sref
= hashlist_next(hashlists
, &iter
))) {
277 // iterating through the "sections", that is each different strswitch usage
278 ulz_snprintf(buf
, sizeof(buf
), "stringswitch_impl_%s.c", sref
->id
->ptr
);
280 outfd
= open(buf
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0660);
283 log_perror(" : couldnt open");
286 log_put(1, VARISL("writing to "), VARIC(buf
), NULL
);
287 write_enum(outfd
, sref
);
289 log_put(outfd
, VARISL("static int stringswitch_enumerator_eval_func("), VARIS(sref
->id
),
290 VARISL(") (char* str, size_t l) {"), NULL
);
291 log_put(outfd
, VARISL("\tswitch(l) {"), NULL
);
294 hashlist_iterator_init(&iter2
);
295 while((href
= hashlist_next(sref
->h
, &iter2
))) {
296 // iterating through the different length blocks in our switch statement
298 write_length_block(outfd
, href
, sref
->id
);
302 log_put(outfd
, VARISL("\t\tdefault:\n\t\t\tmain_default:\n\t\t\treturn stringswitch_enumerator_default_member_name("),
303 VARIS(sref
->id
), VARISL(");\n\t}\n}"), NULL
);
310 void free_sections_hashlist(hashlist
* l
) {
311 // TODO ... free recursive
315 // we have a hashlist, "hashlists", in which we will insert one record of type
316 // sectionrec per different "section". a section is the identifier of a stringswitch statement.
317 // this rec contains a reference to another hashlist, which will contain one stringptrlist per
318 // length of the "add"ed entries.
320 static stringptr
* command_prefix
= SPL("//stringswitch_gen ");
321 hashlist
* parse(char* file
) {
322 hashlist
*hashlists
= NULL
;
324 fileparser fb
, *f
= &fb
;
327 stringptr param1
, param2
;
330 sectionrec sr
, *sref
;
332 stringptrlist
* newlist
;
336 fileparser_open(f
, file
);
337 while(!fileparser_readline(f
) && !fileparser_getline(f
, &line
)) {
338 if(stringptr_here(&line
, 0, command_prefix
)) {
340 command
.ptr
= line
.ptr
+ command_prefix
->size
;
342 while(command_prefix
->size
+ x
< line
.size
&&
343 !(command
.ptr
[x
] == ' ' || command
.ptr
[x
] == 0)) x
++;
346 //log_puts(1, &command); log_putln(1);
348 param1
.ptr
= command
.ptr
+ x
+ 1;
349 if(param1
.ptr
>= line
.ptr
+ line
.size
) {
350 ulz_printf("no param1\n");
354 while(command_prefix
->size
+ command
.size
+ x
+ 1 < line
.size
&&
355 !(param1
.ptr
[x
] == ' ' || param1
.ptr
[x
] == 0))
359 //log_puts(1, ¶m1); log_putln(1);
362 hashlists
= hashlist_new(64, sizeof(sectionrec
));
364 p1hash
= daliashash_sp(¶m1
);
367 sbt
= hashlist_get(hashlists
, p1hash
);
370 h
= hashlist_new(64, sizeof(hashrec
));
373 sr
.id
= stringptr_copy(¶m1
);
374 hashlist_add(hashlists
, p1hash
, &sr
);
375 sbt
= hashlist_get(hashlists
, p1hash
);
378 for(i
= 0; i
< sblist_getsize(sbt
); i
++) {
379 sref
= sblist_get(sbt
, i
);
380 if(sref
->hash
== p1hash
&& EQ(¶m1
, sref
->id
)) {
386 if(!h
) goto insert_hashlist
;
389 if(EQ(&command
, SPL("add"))) {
391 param2
.ptr
= param1
.ptr
+ x
+ 1;
393 if(param2
.ptr
>= line
.ptr
+ line
.size
) {
394 ulz_printf("no param2\n");
398 if(param2
.ptr
[0] != '"') {
399 ulz_printf("add parameter must be double-quoted\n");
404 if(param2
.ptr
>= line
.ptr
+ line
.size
) {
405 ulz_printf("no param2\n");
410 while(command_prefix
->size
+ command
.size
+ param1
.size
+ x
+ 2 + 1 < line
.size
&&
411 !(param2
.ptr
[x
] == '"' || param2
.ptr
[x
] == 0)) x
++;
414 //log_puts(1, ¶m2); log_putln(1);
417 sbt
= hashlist_get(h
, param2
.size
);
419 insert_stringptrlist
:
420 newlist
= stringptrlist_new(4);
421 hr
.len
= param2
.size
;
423 hashlist_add(h
, param2
.size
, &hr
);
424 sbt
= hashlist_get(h
, param2
.size
);
427 for(i
= 0; i
< sblist_getsize(sbt
); i
++) {
428 href
= sblist_get(sbt
, i
);
429 if(href
->len
== param2
.size
) {
430 newlist
= href
->list
;
434 if(!newlist
) goto insert_stringptrlist
;
435 stringptrlist_add(newlist
, stringptr_strdup(¶m2
), param2
.size
);
441 log_put(1, VARISL("the \"add\" command needs an additional parameter embedded in double quotes!"), NULL
);
450 if(hashlists
) free_sections_hashlist(hashlists
);
458 int main(int argc
, char** argv
) {
461 ulz_printf("stringswitch generator 1.0 by rofl0r\n");
462 ulz_printf("^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~\n");
464 ulz_printf("pass one or more filenames containing stringswitch directives embedded as C99 comments!\n");
467 for(i
= 1; i
< argc
; i
++) {
468 if(access(argv
[i
], R_OK
) != -1) {
469 sections
= parse(argv
[i
]);
470 if(!sections
) return 1;