"cond ? yes : no" to "yes if cond else no"
[delight/core.git] / phobos / config / x3.c
bloba86e4eb1cbadabca440ec8fd8a63554232f4266e
1 #include <string.h>
2 #include <stdlib.h>
3 #include <libiberty.h>
4 #include <errno.h>
6 /* TODO: need to use autoconf to figure out which header to
7 include for unlink -- but need to do it for the *build*
8 system. Also, before linking disabled due to cross
9 compilation... */
11 extern int unlink(const char *fn);
13 #include "x3.h"
14 #include "xregex.h"
16 #define x3_assert(cond) {if(cond){}else{x3_error("assert failed: %s:%d: %s", \
17 __FILE__,__LINE__,#cond);exit(1);}}
19 #define x3_new(T) ((T*)malloc(sizeof(T)))
20 #define x3_new0(T) ((T*)calloc(1, sizeof(T)))
22 #define diag(x) fprintf(stderr, x);
24 static void _x3_write_d_int(FILE * f, X3_Int value, X3_Type *type);
25 static void _x3_write_d_int_2(FILE * f, X3_Int value, unsigned size, int is_signed);
27 char *
28 x3f(const char * fmt, ...)
30 char * result = NULL;
31 va_list va;
33 va_start(va, fmt);
34 vasprintf(& result, fmt, va);
36 return result;
39 X3_Global * global;
41 void
42 x3_array_init(X3_Array *ma)
44 memset(ma, 0, sizeof(*ma));
47 void
48 x3_array_fini(X3_Array *ma)
50 free(ma->data);
51 memset(ma, 0, sizeof(*ma));
54 void
55 x3_array_push(X3_Array *ma, void *data)
57 if (ma->length >= ma->alloc) {
58 if (ma->alloc)
59 ma->alloc *= 2;
60 else
61 ma->alloc = 4;
62 ma->data = realloc(ma->data, sizeof(void*) * ma->alloc);
64 ma->data[ma->length++] = data;
67 void
68 x3_array_pop(X3_Array *ma, X3_Size count)
70 if (count <= ma->length)
71 ma->length -= count;
72 else
73 ma->length = 0;
76 void*
77 x3_array_first(X3_Array *ma)
79 if (ma->length)
80 return ma->data[0];
81 else
82 return NULL;
85 void*
86 x3_array_last(X3_Array *ma)
88 if (ma->length)
89 return ma->data[ma->length - 1];
90 else
91 return NULL;
94 X3_Result *
95 x3_result_new()
97 X3_Result * r = x3_new(X3_Result);
98 x3_result_init(r);
99 return r;
102 void
103 x3_result_init(X3_Result * r)
105 memset(r, 0, sizeof(*r));
108 void
109 x3_result_delete(X3_Result * r)
111 if (! r)
112 return;
113 free(r->data);
114 r->data = NULL;
115 free(r);
119 x3_result_read_from_file(X3_Result * r, const char *filename)
121 FILE * f;
122 X3_Size f_size;
123 int result = 0;
125 free(r->data);
126 r->data = NULL;
128 f = fopen(filename, "rb");
129 if (! f) {
130 fprintf(stderr, "cannot open object file: %s: %s\n", filename, strerror(errno));
131 return 0;
133 fseek(f, 0, SEEK_END);
134 f_size = ftell(f);
135 fseek(f, 0, SEEK_SET);
137 r->data = (X3u8*) malloc(f_size);
138 r->length = f_size;
139 if (fread(r->data, 1, f_size, f) != f_size) {
140 fprintf(stderr, "failed to read object file: %s: %s\n", filename, strerror(errno));
141 goto cleanup;
144 result = 1;
146 cleanup:
147 fclose(f);
148 return result;
151 void
152 x3_result_rewind(X3_Result * r)
154 r->pos = 0;
157 void
158 x3_result_skip(X3_Result * r, unsigned count)
160 /* !! */
161 r->pos += count;
164 static inline X3sig
165 x3_result_read_sig(X3_Result * r)
167 X3sig sig;
168 sig = (r->data[r->pos])|(r->data[r->pos+1]<<8)|
169 (r->data[r->pos+2]<<16)|(r->data[r->pos+3]<<24);
170 r->pos += 4;
171 return sig;
173 static inline unsigned/*!!*/
174 x3_result_read_u32(X3_Result * r)
176 return x3_result_read_integer(r, 4, 0);
180 x3_result_find_next(X3_Result * r, X3sig sig)
182 /* assumes data in object file is aligned.. */
183 while (r->pos < r->length && (r->pos & 3))
184 ++r->pos;
186 while (r->pos < r->length) {
187 if (x3_result_read_sig(r) == X3_SIG_HEADER)
188 if (r->pos < r->length &&
189 x3_result_read_sig(r) == sig)
190 return 1;
192 return 0;
196 x3_result_find_sig(X3_Result * r, X3sig sig)
198 x3_result_rewind(r);
199 if (x3_result_find_next(r, sig))
200 return 1;
201 else {
202 x3_error("cannot find expected data in output");
203 return 0;
208 x3_result_find_item(X3_Result * r, unsigned uid)
210 x3_result_rewind(r);
211 while (x3_result_find_next(r, X3_SIG_ITEM))
212 if (x3_result_read_uint(r) == uid)
213 return 1;
214 return 0;
218 x3_result_read_u8(X3_Result * r)
220 if (r->pos < r->length)
221 return r->data[r->pos++];
222 x3_error("read beyond end of input");
223 return -1;
227 x3_result_read_int(X3_Result * r)
229 return x3_result_read_integer(r, global->target_info.sizeof_int, 1);
232 unsigned
233 x3_result_read_uint(X3_Result * r)
235 return x3_result_read_integer(r, global->target_info.sizeof_int, 0);
238 X3_TgtSize
239 x3_result_read_size(X3_Result * r)
241 return x3_result_read_integer(r, global->target_info.sizeof_size_type, 0);
244 X3_Int
245 x3_result_read_integer(X3_Result * r, int size, int is_signed)
247 X3_UInt result;
248 X3u8 * p = r->data + r->pos ;
250 if (! size)
251 return 0;
253 r->pos += size;
254 if (! r->target_info->is_big_endian)
255 p += size - 1;
256 if (is_signed && (*p & 0x80))
257 result = (X3_Int) -1;
258 else
259 result = 0;
260 if (r->target_info->is_big_endian)
261 while (size--)
262 result = (result << 8) | *p++;
263 else
264 while (size--)
265 result = (result << 8) | *p--;
266 return result;
269 X3_InputItem*
270 x3_input_item_new()
272 X3_InputItem * ii = x3_new0(X3_InputItem);
273 return ii;
276 static void
277 _x3_input_item_text_write_func(X3_InputItem * ii , FILE * f)
279 fputs(ii->input_text, f);
280 fputc('\n', f);
283 static void
284 _x3_input_item_subst_text_write_func(X3_InputItem * ii , FILE * f)
286 const char *p;
287 const char *text = ii->input_text;
288 while ( (p = strchr(text, '@')) ) {
289 fwrite(text, 1, p - text, f);
290 fprintf(f, "%d", ii->uid);
291 text = p + 1;
293 fputs(text, f);
294 fputc('\n', f);
297 X3_InputItem*
298 x3_input_item_new_text(const char * text)
300 X3_InputItem * ii = x3_new0(X3_InputItem);
301 ii->input_text = text;
302 ii->write_func = & _x3_input_item_text_write_func;
303 return ii;
306 X3_InputGroup *
307 x3_input_group_new()
309 X3_InputGroup * ig = x3_new(X3_Array);
310 x3_array_init(ig);
311 return ig;
314 X3_Global*
315 x3_global_create()
317 global = x3_new0(X3_Global);
318 x3_global_init(global);
319 return global;
322 void
323 x3_global_init(X3_Global * global)
325 /* needed for integer writing to work */
326 x3_assert(sizeof(X3_Int) >= 8); /* maybe not for 32-bit targets */
327 x3_assert(sizeof(int) >= 4);
328 x3_assert(sizeof(int) * 2 >= sizeof(X3_Int));
330 memset(global, 0, sizeof(*global));
331 x3_array_init(& global->gcc_command);
333 x3_array_init(& global->input_groups);
335 global->header_group = x3_input_group_new();
336 x3_array_push(& global->input_groups, global->header_group);
338 global->current_group = x3_input_group_new();
339 x3_array_push(& global->input_groups, global->current_group);
341 x3_array_init(& global->optional_stack);
343 global->log_stream = stderr;
345 x3_push_optional(0);
349 void
350 x3_global_set_temp_fn_base(const char * temp_base)
352 global->temp_base = temp_base;
354 char * log_fn = concat(global->temp_base, ".log", NULL);
355 if ( (global->log_stream = fopen(log_fn, "a")) != NULL )
356 global->log_path = log_fn;
357 else
358 free(log_fn);
361 char *
362 x3_global_get_temp_fn(const char * suffix)
364 // TODO: use make_temp_file..
365 if (global->temp_base) {
366 char buf[96];
367 snprintf(buf, sizeof(buf), "%s%s", global->temp_base, suffix);
368 return strdup(buf);
369 } else
370 return make_temp_file(suffix);
374 x3_global_keep_temps()
376 return global->temp_base != NULL;
380 void
381 x3_push_optional(int optional)
383 x3_array_push(& global->optional_stack, (void *) optional);
386 void
387 x3_pop_optional()
389 x3_array_pop(& global->optional_stack, 1);
393 x3_is_optional()
395 return x3_array_last(& global->optional_stack) != (void*) 0 ;
398 static void x3_logv(const char *fmt, va_list va)
400 FILE * stream = stderr;
402 if (global)
403 stream = global->log_stream;
405 fputs("x3: ", stream);
406 vfprintf(stream, fmt, va);
407 fputc('\n', stream);
411 void x3_log(const char *fmt, ...)
413 va_list va;
414 va_start(va, fmt);
415 x3_logv(fmt, va);
416 va_end(va);
419 void
420 x3_error(const char *fmt, ...)
422 va_list va, va2;
424 fputs("x3: ", stderr);
425 va_start(va, fmt);
426 va_copy(va2, va);
427 x3_logv(fmt, va2);
428 vfprintf(stderr, fmt, va);
429 if (global)
430 global->error_count++;
431 fputc('\n', stderr);
432 exit(1);
436 x3_unsupported(const char * detail)
438 x3_error("target unsupported: %s", detail);
439 return 0;
443 x3_interp_error(const char * detail)
445 x3_error("cannot interpret output: %s", detail);
446 return 0;
450 x3_gcc_execute(X3_Array extra_args)
452 int status;
453 const char * result;
454 #if _WIN32
455 /* x3 programs get the c:\foo\bar form of path names. Passing that
456 as a program name to the MSYS shell's 'exec' causes the path
457 to be mangled. */
458 const char * exec_bit = "\"$@\"";
459 #else
460 const char * exec_bit = "exec \"$@\"";
461 #endif
462 char * cmd = concat(exec_bit,
463 global->log_path ? " >>" : "",
464 global->log_path ? global->log_path : "", // TODO: assumptions about charaters in the path
465 global->log_path ? " 2>&1" : "",
466 NULL);
468 char**args = (char**)malloc(sizeof(char*) *
469 (global->gcc_command.length + extra_args.length + 4 + 1));
470 int argi = 0;
471 char * shell = getenv("SHELL");
473 if (! shell)
474 shell = "sh";
476 args[argi++] = shell;
477 args[argi++] = "-c";
478 args[argi++] = cmd;
479 args[argi++] = shell;
481 memcpy(args + argi, global->gcc_command.data,
482 global->gcc_command.length * sizeof(char*));
483 argi += global->gcc_command.length;
485 memcpy(args + argi, extra_args.data,
486 extra_args.length * sizeof(char*));
487 argi += extra_args.length;
488 args[argi++] = NULL;
490 FILE * stream = global->log_stream;
491 int i;
492 if (global->print_gcc_command) {
493 fprintf(stream, "x3: running gcc: ");
494 for (i = 0; args[i]; ++i)
495 fprintf(stream, "%s ", args[i]);
496 fprintf(stream, "\n");
498 fflush(stream);
500 #ifdef PEX_RECORD_TIMES
502 int err;
503 result = pex_one(PEX_SEARCH, args[0], args, "x3", NULL, NULL, & status, & err);
504 if (! result) {
506 if (status == 0)
507 return 1;
508 else { // TODO: signals fatal?
509 fprintf(stderr, "error: %s exited with %s %d\n",
510 args[0], status > 0 ? "code" : "signal",
511 status > 0 ? status : -status);
512 return 0;
515 return status == 0;
518 #else
520 char * errmsg_arg;
521 char * rr;
523 int pid = pexecute(args[0], args, "x3", NULL,
524 & rr, & errmsg_arg, PEXECUTE_SEARCH | PEXECUTE_ONE);
525 result = rr;
526 if (pid > 0) { /* !! */
527 if (pwait(pid, & status, 0) != -1)
528 return status == 0;
529 else {
530 fprintf(stderr, "pwait failed: %s\n", strerror(errno));
531 return 0;
535 #endif
536 free(cmd);
538 x3_error("failed to run compiler: %s", result);
539 return 0;
543 x3_gcc_execute_l(const char * extra, ...)
545 va_list va;
546 X3_Array extra_args;
548 va_start(va, extra);
549 x3_array_init(& extra_args);
550 x3_array_push(& extra_args, (/*!!*/ char *) extra);
551 while (1) {
552 char *p = va_arg(va, char *);
553 if (p)
554 x3_array_push(& extra_args, p);
555 else
556 break;
558 va_end(va);
560 return x3_gcc_execute(extra_args);
563 /* Run compiler using the current input data. Not an error if it fails. */
565 x3_compile_test(void)
567 const char * src_fn = x3_global_get_temp_fn(".c");
568 const char * obj_fn = x3_global_get_temp_fn(".o");
569 FILE * f = fopen(src_fn, "w");
570 int result = 0;
571 int gcc_result;
573 x3_result_delete(global->result);
574 global->result = NULL;
576 /* TODO: errors */
577 x3_gi_write_to_FILE(f);
578 fclose(f);
580 gcc_result = x3_gcc_execute_l("-c", src_fn, "-o", obj_fn, NULL);
581 if (gcc_result) {
582 int i1, i2;
584 /* open blob... */
585 global->result = x3_result_new();
586 global->result->target_info = & global->target_info;
587 if (! x3_result_read_from_file(global->result, obj_fn))
588 /* TODO print error? */
589 goto cleanup;
591 for (i1 = 0; i1 < x3al(& global->input_groups); ++i1) {
592 X3_InputGroup * ig = x3ae(& global->input_groups, i1, X3_InputGroup *);
593 for (i2 = 0; i2 < x3al(ig); ++i2) {
594 X3_InputItem * ii = x3ae(ig, i2, X3_InputItem *);
595 if (ii->post_func)
596 ii->post_func(ii, global->result);
600 result = 1;
603 cleanup:
604 if (! x3_global_keep_temps()) {
605 unlink(src_fn);
606 unlink(obj_fn);
608 return result;
611 char *
612 _x3_read_line(FILE *f, char * buf, unsigned buf_size)
614 char * p = fgets(buf, buf_size, f);
615 char * q;
616 if (! p)
617 return NULL;
618 while (! (q=strchr(p, '\n')) && ! feof(f)) {
619 size_t len = strlen(p);
620 if (p == buf) {
621 p = (char*) malloc(len * 2);
622 strncpy(p, buf, len);
623 p[len] = 0;
624 } else
625 p = (char*) realloc(p, len * 2);
626 fgets(p + len, len, f);
628 if (q)
629 *q = 0;
630 return p;
633 static regex_t *
634 _x3_get_macros_regex() {
635 static int initialized = 0;
636 static regex_t macros_regex;
637 if (! initialized) {
638 initialized = 1;
639 if (regcomp(& macros_regex,
640 "^#define ([^[:space:]\(]+)(\\([^[:space:]]+\\))?([[:space:]](.*))?$",
641 REG_EXTENDED) != 0) {
642 x3_assert("failed to compile regex"==0);
643 return NULL;
646 return & macros_regex;
649 char *
650 _x3_strdup_slice(const char * s, int start, int end)
652 int len = end - start;
653 char * result = (char*) malloc(len + 1);
654 strncpy(result, s + start, len);
655 result[len] = '\0';
656 return result;
660 x3_compile_get_macros(X3_Array * out_macros)
662 const char * src_fn = x3_global_get_temp_fn(".c");
663 const char * mac_fn = x3_global_get_temp_fn(".macros");
664 FILE * f = fopen(src_fn, "w");
665 int result = 0;
666 int gcc_result;
667 regex_t * re = _x3_get_macros_regex();
669 /* TODO: errors */
670 x3_gi_write_to_FILE(f);
671 fclose(f);
673 if (! re)
674 return 0;
676 gcc_result = x3_gcc_execute_l("-E", "-dM", "-o", mac_fn, src_fn, NULL);
677 if (gcc_result) {
678 X3_Array macros;
679 char buf[1024];
680 char *line;
682 result = 0;
683 f = fopen(mac_fn, "r");
684 if (!f) {
685 x3_error("cannot open %s: %s", mac_fn, strerror(errno));
686 goto cleanup;
689 x3_array_init(& macros);
691 while ( (line = _x3_read_line(f, buf, sizeof(buf))) ) {
692 regmatch_t matches[4];
693 if (regexec(re, line, 4, matches, 0) == 0) {
694 X3_Macro * macro = x3_new0(X3_Macro);
695 macro->name = _x3_strdup_slice(line, matches[1].rm_so, matches[1].rm_eo);
696 macro->args = _x3_strdup_slice(line, matches[2].rm_so, matches[2].rm_eo);
697 macro->def = _x3_strdup_slice(line, matches[3].rm_so, matches[3].rm_eo);
698 /*fprintf(stderr, "{%s}{%s}{%s}\n", macro->name, macro->args, macro->def);*/
699 x3_array_push(& macros, macro);
703 *out_macros = macros;
704 result = 1;
707 cleanup:
708 if (! x3_global_keep_temps()) {
709 unlink(src_fn);
710 unlink(mac_fn);
712 return result;
715 /* Run GCC. If it fails, it is an error. */
717 x3_compile(void)
719 int result = x3_compile_test();
720 if (! result)
721 x3_error("error: compiler exited with error");
722 return result;
725 static const char * _x3_offsetof_function = "offsetof";
727 void
728 x3_gi_push_standard()
730 x3_gi_push_text(x3f("typedef %s x3i_size_t;", global->target_info.size_type));
732 /* GCC 3.x does not have __builtin_offsetof... */
733 x3_gi_push_header("<stddef.h>");
736 void
737 x3_gi_write_to_FILE(FILE *f)
739 int i1, i2;
740 unsigned uid = 1;
742 for (i1 = 0; i1 < x3al(& global->input_groups); ++i1) {
743 X3_InputGroup * ig = x3ae(& global->input_groups, i1, X3_InputGroup *);
744 for (i2 = 0; i2 < x3al(ig); ++i2) {
745 X3_InputItem * ii = x3ae(ig, i2, X3_InputItem *);
746 ii->uid = uid++;
747 if (ii->write_func)
748 ii->write_func(ii, f);
754 void
755 x3_gi_push_header(const char *hdr)
757 X3_InputItem * ii = x3_input_item_new_text(x3f("#include %s\n", hdr));
758 x3_array_push(global->header_group, ii);
761 void
762 x3_gi_push_headers_l(const char * hdr, ...)
764 x3_gi_push_header(hdr);
766 va_list va;
767 va_start(va, hdr);
768 while (1) {
769 const char *p = va_arg(va, const char *);
770 if (p)
771 x3_gi_push_header(p);
772 else
773 break;
775 va_end(va);
778 void
779 x3_gi_pop_header()
781 x3_gi_pop_headers(1);
784 void
785 x3_gi_pop_headers(int count)
787 x3_array_pop(global->header_group, 1);
790 void
791 x3_gi_push_group()
793 global->current_group = x3_input_group_new();
794 x3_array_push(& global->input_groups, global->current_group);
797 void
798 x3_gi_pop_group()
800 x3_array_pop(& global->input_groups, 1);
801 global->current_group = x3_array_last(& global->input_groups);
804 void
805 x3_gi_push_input_item(X3_InputItem *ii)
807 x3_array_push(global->current_group, ii);
810 void
811 x3_gi_pop_items(int count)
813 x3_array_pop(global->current_group, count);
816 X3_InputItem*
817 x3_gi_push_text(const char *text)
819 X3_InputItem* ii = x3_input_item_new_text(text);
820 x3_gi_push_input_item(ii);
821 return ii;
824 X3_InputItem*
825 x3_gi_push_subst_text(const char *text)
827 X3_InputItem* ii = x3_input_item_new_text(text);
828 ii->write_func = & _x3_input_item_subst_text_write_func;
829 x3_gi_push_input_item(ii);
830 return ii;
834 static void
835 _x3_input_int_value_write_func(X3_InputItem * xi , FILE * f)
837 X3_InputIntValue * ii = (X3_InputIntValue *) xi;
838 unsigned uid = ii->iit.ii.uid;
839 const char *type_name = ii->iit.type_name;
840 x3_gi_write_start_item(f, uid);
841 fprintf(f, "x3i_size_t int_sz; int int_sgn; %s int_val;\n", type_name);
842 x3_gi_write_start_item_data(f, uid);
843 fprintf(f, "sizeof(%s), ((%s)-1)<0, %s", type_name, type_name,
844 ii->iit.ii.input_text);
845 x3_gi_write_finish_item(f);
848 static void
849 _x3_input_int_value_post_func(X3_InputItem * xi , X3_Result * result)
851 X3_InputIntValue * ii = (X3_InputIntValue *) xi;
852 if (x3_result_find_item(result, ii->iit.ii.uid)) {
853 int sz = x3_result_read_size(result);
854 int sgn = x3_result_read_int(result);
855 ii->iit.int_type_size = sz;
856 ii->iit.int_type_is_signed = sgn;
857 ii->int_value = x3_result_read_integer(result, sz, sgn);
859 /* !! find_item doesn't record error ... do it here? */
862 X3_InputIntValue*
863 x3_gi_push_int_value(const char *expr)
865 X3_InputIntValue * ii = x3_new0(X3_InputIntValue);
866 ii->iit.ii.write_func = & _x3_input_int_value_write_func;
867 ii->iit.ii.post_func = & _x3_input_int_value_post_func;
868 ii->iit.type_name = "int";
869 ii->iit.ii.input_text = expr;
870 x3_gi_push_input_item(& ii->iit.ii);
871 return ii;
875 void
876 x3_gi_push_default_enum(const char * default_val, ...)
878 va_list va;
879 char * result = "";
881 va_start(va, default_val);
882 while (1) {
883 const char * p = va_arg(va, const char *);
884 if (! p)
885 break;
886 result = x3f("%s"
887 "#ifndef %s\n# define %s %s\n#endif\n",
888 result, p, p, default_val);
890 x3_gi_push_text(result);
893 void
894 x3_gi_write_start_item(FILE *f, unsigned uid)
896 fprintf(f, "struct { char _x3_sig[4]; char _x3_type[4]; unsigned _x3_uid;\n ");
899 void
900 x3_gi_write_start_item_data(FILE *f, unsigned uid)
902 fprintf(f, "} __attribute__((packed)) \n_x3_item_%d\n = { \"zOmG\", \"iTeM\", %d, ",
903 uid, uid);
906 void
907 x3_gi_write_finish_item(FILE *f)
909 fprintf(f, "};\n");
913 x3_query_target_info(X3_TargetInfo *ti)
915 int v;
916 int sz[5];
917 int result = 0;
918 int ok;
920 x3_gi_push_group();
922 x3_gi_push_text("struct { char sig[4]; char what[4];"
923 "unsigned char sz_char; unsigned char sz_short; "
924 "unsigned char sz_int; unsigned char sz_long_long; "
925 "unsigned char sz_long; unsigned short endian_test; }\n "
926 "__attribute__((packed)) _x3i_tgt_info = {\n"
927 "\"zOmG\", \"tGtI\", sizeof(char), sizeof(short), "
928 "sizeof(int), sizeof(long long), sizeof(long), "
929 "0x2211 };\n");
930 if (! x3_compile())
931 goto cleanup;
933 if (! x3_result_find_sig(global->result, X3_SIG('t','G','t','I')))
934 goto cleanup;
936 sz[0] = ti->sizeof_char = x3_result_read_u8(global->result);
937 if (ti->sizeof_char != 1) {
938 x3_unsupported("sizeof(char) is not 1");
939 goto cleanup;
941 sz[1] = ti->sizeof_short = x3_result_read_u8(global->result);
942 sz[2] = ti->sizeof_int = x3_result_read_u8(global->result);
943 sz[3] = ti->sizeof_long_long = x3_result_read_u8(global->result);
944 sz[4] = ti->sizeof_long = x3_result_read_u8(global->result);
945 v = x3_result_read_u8(global->result);
946 if (v == 0x11)
947 ti->is_big_endian = 0;
948 else {
949 x3_result_skip(global->result, ti->sizeof_short - 2);
950 if (x3_result_read_u8(global->result) != 0x11)
951 x3_interp_error("cannot determine byte order");
952 ti->is_big_endian = 1;
955 x3_gi_push_header("<sys/types.h>");
956 x3_gi_pop_items(1);
957 x3_gi_push_text("struct { char sig[4]; char what[4];"
958 "unsigned char sz_szt; }\n "
959 "__attribute__((packed)) _x3i_szt_info = {\n"
960 "\"zOmG\", \"tGtI\", sizeof(size_t) };\n");
961 ok = x3_compile();
962 x3_gi_pop_headers(1);
963 ti->size_type = "unsigned int";
964 ti->sizeof_size_type = ti->sizeof_int;
966 result = 1;
968 cleanup:
969 x3_gi_pop_group();
970 return result;
974 x3_query_int_type(const char *name, X3_Type * type)
976 X3_Int dummy;
977 return x3_query_int_value("0", name, & dummy, type);
981 x3_query_type(const char *name, X3_Type * type)
983 static unsigned uid_counter = 1;
984 X3_Int int_val;
985 X3_Type dummy;
986 char * p;
987 unsigned my_uid = ++uid_counter;
989 type->ok = 0;
991 x3_gi_push_group();
993 /* test if type is even valid */
994 const char * td_name = x3f("_x3i_qttd_%d", my_uid);
995 x3_gi_push_text(p = x3f("typedef %s %s;\n", name, td_name));
996 if (! x3_compile_test())
997 goto cleanup;
999 /* is it just void? */
1000 if (x3_query_int_value(x3f("__builtin_types_compatible_p(void,%s)", name),
1001 "int", & int_val, & dummy) && int_val) {
1002 type->ok = 1;
1003 type->kind = X3_TYPE_KIND_VOID;
1004 } else {
1005 if (! x3_query_int_value(x3f("sizeof(%s)", name), "x3i_size_t", & int_val, & dummy))
1006 goto cleanup;
1007 type->type_size = (X3_UInt) int_val;
1009 /* test if scalarish (or array...) */
1010 int result1;
1011 x3_gi_push_subst_text(x3f("\n"
1012 "const %s _x3i_qt_@_1;\n"
1013 "typedef typeof(_x3i_qt_@_1 < 0) _x3i_qt_@_2;", name));
1014 result1 = x3_compile_test();
1015 x3_gi_pop_items(1);
1016 if (result1) {
1017 int result2;
1018 /* is it a pointer or array? */
1019 const char * sub_td_name = x3f("_x3i_qttd_%d_sub", my_uid);
1020 x3_gi_push_subst_text(p = x3f("\n"
1021 "const %s _x3i_qt_inst_@;\n"
1022 "typedef typeof(* _x3i_qt_inst_@) %s;", name, sub_td_name));
1023 result2 = x3_compile_test();
1024 if (result2) {
1026 if (x3_query_int_value(x3f(""
1027 "__builtin_types_compatible_p(%s[],%s)",
1028 sub_td_name, td_name),
1029 "int", & int_val, & dummy) && int_val) {
1030 /* It is an array type. */
1031 type->kind = X3_TYPE_KIND_ARRAY;
1032 type->next = x3_type_new();
1033 type->next->flags |= type->flags & (X3_FLAG_USE_CHAR|X3_FLAG_USE_BYTE);
1034 if (! x3_query_type(sub_td_name, type->next))
1035 goto cleanup;
1036 if (type->type_size && type->next->type_size) {
1037 x3_assert( (type->type_size % type->next->type_size) == 0);
1038 type->u.array_length = type->type_size / type->next->type_size;
1039 } else
1040 type->u.array_length = 0;
1041 type->next->out_name = NULL;
1042 type->ok = 1;
1044 } else { /* It is pointer. */
1045 int is_ptr_to_func = 0;
1047 type->kind = X3_TYPE_KIND_POINTER;
1048 type->next = x3_type_new();
1050 /* Test for pointer to function which can do *type forever... */
1051 x3_gi_push_subst_text(x3f("\n"
1052 "const %s _x3i_qtptf_@;\n"
1053 "typedef typeof(*_x3i_qtptf_@) _x3i_qtptf_f2_%d;\n",
1054 sub_td_name, my_uid));
1055 is_ptr_to_func = x3_query_int_value(x3f("\n"
1056 "__builtin_types_compatible_p(%s,_x3i_qtptf_f2_%d)",
1057 sub_td_name, my_uid),
1058 "int", & int_val, & dummy) && int_val;
1059 x3_gi_pop_items(1);
1060 if (! is_ptr_to_func)
1061 x3_query_type(sub_td_name, type->next);
1062 if (! type->next->ok || type->next->kind == X3_TYPE_KIND_RECORD) {
1063 /* void* is good enough... */
1064 type->next->ok = 1;
1065 type->next->kind = X3_TYPE_KIND_VOID;
1066 type->next->c_name = type->next->out_name = "void";
1068 type->next->out_name = NULL;
1069 type->ok = 1;
1071 x3_gi_pop_items(1);
1072 } else {
1073 x3_gi_pop_items(1);
1074 /* Must be an int */
1075 x3_query_int_type(name, type);
1076 type->out_name = NULL;
1078 } else {
1079 /* if we get a pointer to this, there's gonna be a problem...
1080 array and pointer above need to check this and either push
1081 a private type or change it to an array of bytes... !!
1083 also a problem if an instance...
1086 X3_Struct * s = x3_struct_new();
1087 X3_Field * f;
1089 f = x3_struct_new_field(s);
1090 f->ok = 1;
1091 f->out_name = "__opaque";
1092 f->field_type.ok = 1;
1093 f->field_type.kind = X3_TYPE_KIND_NAME;
1094 f->field_type.type_size = type->type_size;
1095 f->field_type.out_name = x3f("byte[%u]", (unsigned) type->type_size);
1096 /* might be function (not ptr-to-functiono) or struct... keep it as a name.. */
1097 /* !! figure out alignment... */
1098 type->ok = 1;
1099 type->kind = X3_TYPE_KIND_RECORD;
1100 type->u.struct_def = s;
1102 s->finished = 1;
1103 s->struct_type = *type;
1107 cleanup:
1108 --uid_counter;
1109 x3_gi_pop_group();
1110 return type->ok;
1114 x3_query_int_value(const char *expr, const char *type_name,
1115 X3_Int * out_value, X3_Type * out_type)
1117 x3_assert(type_name != NULL);
1118 X3_InputIntValue *c = x3_gi_push_int_value(expr);
1119 c->iit.type_name = type_name;
1120 if (x3_compile_test()) {
1121 out_type->ok = 1;
1122 out_type->kind = X3_TYPE_KIND_INT;
1123 out_type->c_name = type_name;
1124 if (! out_type->out_name)
1125 out_type->out_name = type_name;
1126 out_type->type_size = c->iit.int_type_size;
1127 out_type->type_is_signed = c->iit.int_type_is_signed;
1128 *out_value = c->int_value;
1129 } else
1130 out_type->ok = 0;
1131 x3_gi_pop_items(1);
1132 return out_type->ok;
1136 static const char *
1137 _x3_d_int_type(X3_Type * type)
1139 x3_assert(type->kind == X3_TYPE_KIND_INT);
1140 switch (type->type_size) {
1141 case 1:
1142 if (type->flags & X3_FLAG_USE_BYTE)
1143 return type->type_is_signed ? "byte" : "ubyte";
1144 else
1145 return "char";
1146 case 2: return type->type_is_signed ? "short" : "ushort";
1147 case 4: return type->type_is_signed ? "int" : "uint";
1148 case 8: return type->type_is_signed ? "long" : "ulong";
1149 default:
1150 x3_error("no D equivalent for integer type of %d bytes", (int) type->type_size);
1151 return "error";
1155 static const char *
1156 _x3_d_char_type(X3_Type * type)
1158 x3_assert(type->kind == X3_TYPE_KIND_INT);
1159 switch (type->type_size) {
1160 case 1: return "char";
1161 case 2: return "wchar";
1162 case 4: return "dchar";
1163 default:
1164 x3_error("no D character type of %d bytes", (int) type->type_size);
1165 return "error";
1169 static void
1170 _x3_write_d_int_2(FILE * f, X3_Int value, unsigned size, int is_signed)
1172 if (is_signed) {
1173 int hi = (value >> (int)32) & 0xffffffff;
1174 if (hi == 0 || hi == -1)
1175 fprintf(f, "%d", (int)value);
1176 else
1177 /* !! grr.... */
1178 fprintf(f, "cast(long)0x%x%08x", hi, (unsigned)(value & 0xffffffff));
1179 } else {
1180 unsigned hi = ((X3_UInt) value >> (unsigned)32) & 0xffffffff;
1181 if (hi == 0)
1182 fprintf(f, "%u", (unsigned)value);
1183 else
1184 fprintf(f, "0x%x%08xUL", hi, (unsigned)(value & 0xffffffff));
1188 static void
1189 _x3_write_d_int(FILE * f, X3_Int value, X3_Type *type)
1191 x3_assert(type->kind == X3_TYPE_KIND_INT);
1192 _x3_write_d_int_2(f, value, type->type_size, type->type_is_signed);
1195 static const char * _x3_format_d_type(X3_Type *type);
1197 static const char *
1198 _x3_format_d_type_ex(X3_Type *type, int use_name)
1200 const char * result;
1201 x3_assert(type->ok);
1202 if (! type->out_name || ! use_name) {
1203 switch (type->kind)
1205 case X3_TYPE_KIND_VOID:
1206 result = "void";
1207 break;
1208 case X3_TYPE_KIND_INT:
1209 result = _x3_d_int_type(type);
1210 break;
1211 case X3_TYPE_KIND_ARRAY:
1212 result = x3f("%s[%u]", _x3_format_d_type(type->next),
1213 (unsigned) type->u.array_length);
1214 break;
1215 case X3_TYPE_KIND_POINTER:
1216 result = x3f("%s*", _x3_format_d_type(type->next));
1217 break;
1218 default:
1219 x3_assert(0);
1222 if (! type->out_name && use_name)
1223 type->out_name = result !! // ...should be separate cached.
1225 } else
1226 result = type->out_name;
1227 return result;;
1230 static const char *
1231 _x3_format_d_type(X3_Type *type)
1233 return _x3_format_d_type_ex(type, 1);
1237 X3_Type *
1238 x3_type_new(void)
1240 X3_Type * t = x3_new0(X3_Type);
1241 x3_type_init(t);
1242 return t;
1245 void
1246 x3_type_init(X3_Type * type)
1248 memset(type, 0, sizeof(*type));
1249 type->flags |= X3_FLAG_USE_CHAR;
1252 void
1253 x3_type_out(X3_Type * type)
1255 x3_assert(type->ok);
1257 const char * out_name = type->out_name ? type->out_name : type->c_name;
1258 if (! out_name)
1259 return; // !!?
1261 switch (type->kind)
1263 case X3_TYPE_KIND_NAME:
1264 // can't do anything !!?
1265 break;
1266 case X3_TYPE_KIND_RECORD:
1267 x3_struct_out(type->u.struct_def);
1268 break;
1269 case X3_TYPE_KIND_ERROR:
1270 // !!
1271 break;
1272 default:
1273 fprintf(global->output_stream, "alias %s %s;\n",
1274 _x3_format_d_type_ex(type, 0), out_name);
1275 break;
1279 void
1280 x3_out_int_type(const char* name)
1282 X3_Type it;
1283 x3_log("checking for int type '%s'", name);
1284 if (x3_query_int_type(name, & it)) {
1285 fprintf(global->output_stream, x3f("alias %s %s;\n",
1286 _x3_d_int_type(& it), name));
1287 } else if (! x3_is_optional())
1288 x3_error("cannot resolve integer type %s", name);
1291 void x3_out_char_type(const char* name)
1293 X3_Type it;
1294 x3_log("checking for char type '%s'", name);
1295 if (x3_query_int_type(name, & it)) {
1296 fprintf(global->output_stream, x3f("alias %s %s;\n",
1297 _x3_d_char_type(& it), name));
1298 } else if (! x3_is_optional())
1299 x3_error("cannot resolve integer type %s", name);
1303 void
1304 x3_out_type(const char* name)
1306 x3_out_type_ex(name, NULL, NULL);
1309 const char * X3_STRUCT_FALLBACK = "X3_STRUCT_FALLBACK";
1311 void
1312 x3_out_type_ex(const char* c_name, const char * out_name, const char * fallback)
1314 X3_Type type;
1316 x3_log("checking for type '%s'", c_name);
1317 out_name = type.out_name = out_name ? out_name : c_name;
1318 if (x3_query_type(c_name, & type))
1319 x3_type_out(& type);
1320 else if (fallback) {
1321 if (fallback != X3_STRUCT_FALLBACK)
1322 x3_out_text(x3f("alias %s %s;\n", fallback, out_name));
1323 else
1324 x3_out_text(x3f("struct %s;\n", out_name));
1325 } else if (! x3_is_optional())
1326 x3_error("cannot resolve type %s", c_name);
1329 void
1330 x3_out_int_value(const char* expr)
1332 x3_out_int_value_ex(expr, expr, NULL, NULL, 0, NULL);
1335 void
1336 x3_out_int_value_ex(const char *name, const char* expr, const char *in_type,
1337 const char *out_type, int explicit_cast, const char * fallback)
1339 X3_Int value;
1340 X3_Type type;
1342 if (! expr)
1343 expr = name;
1344 x3_log("checking for int value '%s'", expr);
1345 if (! in_type)
1346 in_type = "int";
1347 if (! out_type)
1348 out_type = in_type;
1350 if (x3_query_int_value(expr, in_type, & value, & type)) {
1351 fprintf(global->output_stream, "const %s %s = ",
1352 out_type, name);
1353 if (explicit_cast)
1354 fprintf(global->output_stream, "cast(%s) ", out_type);
1355 _x3_write_d_int(global->output_stream, value, & type);
1356 fprintf(global->output_stream, ";\n");
1357 } else if (fallback) {
1358 fprintf(global->output_stream, "const %s %s = ",
1359 out_type, name);
1360 if (explicit_cast)
1361 fprintf(global->output_stream, "cast(%s) ", out_type);
1362 fputs(fallback, global->output_stream);
1363 fprintf(global->output_stream, ";\n");
1364 } else if (! x3_is_optional())
1365 x3_error("cannot resolve integer expression '%s'", expr);
1368 void
1369 x3_out_enum(const char *name, const char *type, ...)
1371 X3_Array macros;
1372 //X3_MArray incl_symbols;
1373 X3_Array incl_patterns;
1374 X3_Array excl_patterns;
1376 X3_Array enum_names;
1377 X3_Array enum_exprs;
1379 x3_array_init(& incl_patterns);
1380 x3_array_init(& excl_patterns);
1381 x3_array_init(& enum_names);
1382 x3_array_init(& enum_exprs);
1384 fputs("x3: enums ", global->log_stream);
1386 va_list va;
1387 const char * p;
1388 va_start(va, type);
1389 while ( (p = va_arg(va, const char *)) ) {
1391 if (strcpsn(p, "-+()[]{}.*?/\\$^") == strlen(p)) { //!! should be ident reg or ident chars..
1392 x3_marray_push(&
1393 } else {
1396 if (excl_patterns.length || incl_patterns.length)
1397 fputs(", ", global->log_stream);
1398 fputs(p, global->log_stream);
1400 int is_excl = *p == '-';
1401 regex_t * pre = x3_new0(regex_t);
1403 if (is_excl)
1404 ++p;
1406 if (regcomp(pre, p, REG_EXTENDED) != 0) {
1407 x3_error("invalid pattern '%s'", p);
1408 exit(1);
1410 x3_array_push(is_excl ? & excl_patterns : & incl_patterns, pre);
1413 fputc('\n', global->log_stream);
1415 if (x3_compile_get_macros(& macros)) {
1416 int i;
1417 int mi;
1418 regmatch_t matches[1];
1420 x3_gi_push_group();
1422 for (i = 0; i < macros.length; i++) {
1423 X3_Macro * macro = (X3_Macro *) macros.data[i];
1424 int incl = 0, excl = 0;
1426 if (strlen(macro->args))
1427 continue;
1429 for (mi = 0; mi < incl_patterns.length; mi++) {
1430 if ( regexec((regex_t*) incl_patterns.data[mi],
1431 macro->name, 1, matches, 0) == 0) {
1432 incl = 1;
1433 break;
1436 if (incl) {
1437 for (mi = 0; mi < excl_patterns.length; mi++) {
1438 if ( regexec((regex_t*) excl_patterns.data[mi],
1439 macro->name, 1, matches, 0) == 0) {
1440 excl = 1;
1441 break;
1445 if (incl && ! excl) {
1446 // !! TYPE
1447 x3_array_push(& enum_exprs,
1448 x3_gi_push_int_value(macro->def));
1449 x3_array_push(& enum_names, (char *) macro->name);
1453 if (enum_names.length && x3_compile_test()) {
1454 FILE * f = global->output_stream;
1455 fprintf(f, "enum");
1456 if (name)
1457 fprintf(f, " %s", name);
1458 if (type)
1459 fprintf(f, " : %s", type);
1460 fprintf(f, "\n{\n");
1461 for (i = 0; i < enum_names.length; i++) {
1462 X3_InputIntValue * ii = (X3_InputIntValue *) enum_exprs.data[i];
1463 fprintf(f, " %s = ", (char*) enum_names.data[i]);
1464 _x3_write_d_int_2(f, ii->int_value, ii->iit.int_type_size,
1465 ii->iit.int_type_is_signed);
1466 fprintf(f, ",\n");
1468 fprintf(f, "}\n\n");
1469 } else if (! x3_is_optional())
1470 x3_error("failed to resolve macro values.");
1472 x3_gi_pop_group();
1473 } else if (! x3_is_optional())
1474 x3_error("failed to get macros.");
1477 void
1478 x3_out_text(const char *text)
1480 fputs(text, global->output_stream);
1484 x3_query_struct_field(const char * struct_name, const char * field_name)
1486 x3_gi_push_subst_text(x3f(""
1487 "const int _x3i_struct_field_test_@ = "
1488 "%s(%s, %s);", _x3_offsetof_function, struct_name, field_name));
1489 int result = x3_compile_test();
1490 x3_gi_pop_items(1);
1491 return result;
1494 static void
1495 _x3_query_cpp_if_write_func(X3_InputItem * ii , FILE * f)
1497 fprintf(f, "#if %s\n", ii->input_text);
1498 x3_gi_write_start_item(f, ii->uid);
1499 fputs("int unused;", f);
1500 x3_gi_write_start_item_data(f, ii->uid);
1501 fprintf(f, "0");
1502 x3_gi_write_finish_item(f);
1503 fputs("#endif\n", f);
1507 x3_query_cpp_if(const char * expr)
1509 X3_InputItem * ii = x3_input_item_new();
1510 int result = 0;
1512 ii->input_text = expr;
1513 ii->write_func = & _x3_query_cpp_if_write_func;
1514 x3_gi_push_input_item(ii);
1515 if (x3_compile_test())
1516 result = x3_result_find_item(global->result, ii->uid);
1517 else if (! x3_is_optional())
1518 x3_error("failed to test conditional...");
1520 x3_gi_pop_items(1);
1522 return result;
1525 X3_Struct *
1526 x3_struct_new()
1528 X3_Struct * s = x3_new0(X3_Struct);
1529 x3_array_init(& s->fields);
1530 x3_array_init(& s->extra);
1531 s->struct_type.kind = X3_TYPE_KIND_RECORD;
1532 s->struct_type.u.struct_def = s;
1533 return s;
1536 X3_Struct *
1537 x3_struct_new_c_name(const char * c_name)
1539 X3_Struct * s = x3_struct_new();
1540 s->struct_type.c_name = c_name;
1541 if (strncmp(c_name, "struct ", 7) == 0) {
1542 s->record_kind = X3_RECORD_STRUCT;
1543 s->struct_type.out_name = c_name + 7;
1544 } else if (strncmp(c_name, "union ", 6) == 0) {
1545 s->record_kind = X3_RECORD_UNION;
1546 s->struct_type.out_name = c_name + 6;
1547 } else
1548 s->struct_type.out_name = c_name;
1549 return s;
1552 void
1553 x3_struct_delete(X3_Struct * s)
1555 if (! s)
1556 return;
1557 /* blah... */
1558 free(s);
1561 X3_Field *
1562 x3_struct_new_field(X3_Struct * s)
1564 X3_Field * field = x3_new0(X3_Field);
1565 x3_type_init(& field->field_type);
1566 x3_array_push(& s->fields, field);
1567 return field;
1570 X3_Field *
1571 x3_struct_add_field(X3_Struct * s, X3_Field * field)
1573 x3_array_push(& s->fields, field);
1574 return field;
1578 void
1579 _x3_struct_add_fields_v(X3_Struct * s, va_list va)
1581 while (1) {
1582 const char * p = va_arg(va, const char *);
1583 const char * name;
1584 const char * flag_end;
1585 X3_Field * field;
1587 if (! p)
1588 break;
1589 field = x3_struct_new_field(s);
1590 if ( (flag_end = strchr(p, ':')) ) {
1591 name = flag_end + 1;
1593 while (p < flag_end) {
1594 switch (*p++) {
1595 case 'i': field->flags |= X3_FLAG_INT_TYPE; break;
1596 case 'o': field->flags |= X3_FLAG_OPTIONAL; break;
1597 case 'c': field->flags |= X3_FLAG_USE_CHAR; break;
1598 case 'b': field->flags |= X3_FLAG_USE_BYTE; break;
1599 case 't':
1601 const char * e = strchr(p, ';');
1603 char * tn = (char*) malloc(e-p);
1604 strncpy(tn, p, e-p);
1605 tn[e-p] = 0;
1607 field->field_type.kind = X3_TYPE_KIND_NAME;
1608 field->field_type.out_name = tn;
1609 p = e + 1;
1611 break;
1614 } else
1615 name = p;
1616 field->c_name = field->out_name = name;
1620 void
1621 x3_struct_add_fields(X3_Struct * s, ...)
1623 va_list va;
1624 va_start(va, s);
1625 _x3_struct_add_fields_v(s, va);
1629 void
1630 x3_struct_add_extra(X3_Struct * s, const char * text)
1632 x3_array_push(& s->extra, (char*) text);
1636 _x3_field_compare(const void * pa, const void * pb)
1638 X3_Field * fa = (X3_Field*) * (void**) pa;
1639 X3_Field * fb = (X3_Field*) * (void**) pb;
1640 return (int) fa->field_offset - (int) fb->field_offset;
1643 void
1644 x3_struct_finish(X3_Struct * s)
1646 int i;
1648 x3_log("translating struct '%s'", s->struct_type.c_name);
1649 x3_gi_push_group();
1651 X3_Array cur_fields = s->fields;
1652 X3_Array next_fields;
1654 x3_array_init(& next_fields);
1655 for (i = 0; i < cur_fields.length; ++i) {
1656 X3_Field * field = (X3_Field *) cur_fields.data[i];
1657 if (/*! field->ok && */(field->flags & X3_FLAG_OPTIONAL)) {
1658 x3_log("checking for %s.%s", s->struct_type.c_name, field->c_name);
1659 if (x3_query_struct_field(s->struct_type.c_name, field->c_name))
1660 x3_array_push(& next_fields, field);
1661 } else
1662 x3_array_push(& next_fields, field);
1665 /* No uid for 'inst' -- assumes no recursive x3_struct_finish. */
1666 x3_gi_push_text(x3f("static %s inst;", s->struct_type.c_name));
1668 cur_fields = next_fields;
1669 for (i = 0; i < cur_fields.length; ++i) {
1670 X3_Field * field = (X3_Field *) cur_fields.data[i];
1671 if (! field->field_type.ok) {
1672 /* note: does not clear existing flags... */
1673 field->field_type.flags |= field->flags & (X3_FLAG_USE_CHAR | X3_FLAG_USE_BYTE);
1674 if (field->flags & X3_FLAG_INT_TYPE) {
1675 x3_query_int_type(x3f("typeof(inst.%s)", field->c_name),
1676 & field->field_type);
1677 field->field_type.out_name = _x3_d_int_type(& field->field_type);
1678 } else {
1679 x3_query_type(x3f("typeof(inst.%s)", field->c_name),
1680 & field->field_type);
1682 if (! field->field_type.ok) {
1683 x3_error("cannot resolve type of %s.%s", s->struct_type.c_name, field->c_name);
1684 goto cleanup;
1689 X3_InputIntValue **offsets = (X3_InputIntValue**) calloc(cur_fields.length, sizeof(void**));
1690 for (i = 0; i < cur_fields.length; ++i) {
1691 X3_Field * field = (X3_Field *) cur_fields.data[i];
1692 offsets[i] = x3_gi_push_int_value(x3f("%s(%s,%s)",
1693 _x3_offsetof_function, s->struct_type.c_name, field->c_name));
1695 if (! x3_compile())
1696 goto cleanup;
1697 for (i = 0; i < cur_fields.length; ++i) {
1698 X3_Field * field = (X3_Field *) cur_fields.data[i];
1699 field->field_offset = offsets[i]->int_value;
1702 qsort(cur_fields.data, cur_fields.length, sizeof(void*), & _x3_field_compare);
1704 s->fields = cur_fields;
1706 if (s->record_kind == X3_RECORD_UNKNOWN) {
1707 if (cur_fields.length > 1 &&
1708 ((X3_Field *) cur_fields.data[cur_fields.length - 1])->field_offset == 0)
1709 s->record_kind = X3_RECORD_UNION;
1710 else
1711 s->record_kind = X3_RECORD_STRUCT;
1714 s->struct_type.kind = X3_TYPE_KIND_RECORD;
1716 X3_Int sz;
1717 X3_Type dummy;
1718 if (! x3_query_int_value(x3f("sizeof(%s)", s->struct_type.c_name), "x3i_size_t",
1719 & sz, & dummy))
1720 goto cleanup;
1721 s->struct_type.type_size = sz;
1724 s->struct_type.ok = 1;
1725 cleanup:
1726 x3_gi_pop_group();
1728 s->finished = 1;
1731 static void
1732 _x3_struct_write_to_FILE(X3_Struct * s, FILE * f)
1734 int i;
1735 unsigned pad_idx = 1;
1736 X3_TgtSize last_offset = (X3_TgtSize) -1;
1737 X3_TgtSize next_offset = 0;
1738 //FieldInfo *p_fi = fields;
1739 //FieldInfo *p_fi_end = p_fi + field_count;
1740 int in_union = 0;
1742 int n_fields = s->fields.length;
1743 X3_Field **all_fields = (X3_Field **) s->fields.data;
1745 fprintf(f, "%s %s\n{\n",
1746 s->record_kind == X3_RECORD_UNION ? "union" : "struct",
1747 s->struct_type.out_name);
1749 for (i = 0; i < n_fields; ++i) {
1750 X3_Field * field = (X3_Field *) all_fields[i];
1751 if (field->field_offset == last_offset) {
1752 // in a union
1753 } else if (in_union) {
1754 fprintf(f, " }\n");
1755 in_union = 0;
1758 if (field->field_offset > next_offset)
1759 fprintf(f, " ubyte[%u] __pad%u;\n",
1760 (unsigned)(field->field_offset - next_offset), pad_idx++);
1762 if (! in_union &&
1763 i + 1 != n_fields &&
1764 field->field_offset == all_fields[i +1]->field_offset) {
1765 in_union = 1;
1766 fprintf(f, " union {\n");
1769 fprintf(f, "%s %s %s%s%s;\n", in_union?" ":"",
1770 _x3_format_d_type(& field->field_type), field->out_name,
1771 field->init_expr ? " = " : "",
1772 field->init_expr ? field->init_expr : "");
1773 last_offset = field->field_offset;
1774 next_offset = last_offset + field->field_type.type_size; /* doesn't handle alignment */
1776 if (in_union)
1777 fprintf(f, " }\n");
1778 X3_TgtSize size = s->struct_type.type_size;
1779 if (next_offset < size)
1780 fprintf(f, " ubyte[%u] __pad%u;\n", (unsigned)(size - next_offset), pad_idx++);
1782 for (i = 0; i < s->extra.length; ++i) {
1783 fputs((const char *) s->extra.data[i], f);
1784 fputc('\n', f);
1787 fprintf(f, "}\n\n");
1790 void
1791 x3_struct_out(X3_Struct * s)
1793 if (! s->finished)
1794 x3_struct_finish(s);
1795 if (s->struct_type.ok)
1796 _x3_struct_write_to_FILE(s, global->output_stream);
1797 else if (s->fallback)
1798 fprintf(global->output_stream, "struct %s;\n",
1799 s->struct_type.out_name ?
1800 s->struct_type.out_name : s->struct_type.c_name);
1801 else if (! x3_is_optional())
1802 x3_error("cannot resolve struct type %s", s->struct_type.c_name);
1805 void
1806 x3_out_struct(const char * c_name, const char *out_name, ...)
1808 X3_Struct * s = x3_struct_new_c_name(c_name);
1810 va_list va;
1812 if (out_name)
1813 s->struct_type.out_name = out_name;
1815 va_start(va, out_name);
1816 _x3_struct_add_fields_v(s, va);
1818 x3_struct_out(s);
1821 void x3_out_struct_ex(const char * c_name, const char *out_name, int fallback, ...)
1823 X3_Struct * s = x3_struct_new_c_name(c_name);
1825 va_list va;
1827 if (out_name)
1828 s->struct_type.out_name = out_name;
1830 s->fallback = fallback;
1832 va_start(va, fallback);
1833 _x3_struct_add_fields_v(s, va);
1835 x3_struct_out(s);