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
11 extern int unlink(const char *fn
);
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
);
28 x3f(const char * fmt
, ...)
34 vasprintf(& result
, fmt
, va
);
42 x3_array_init(X3_Array
*ma
)
44 memset(ma
, 0, sizeof(*ma
));
48 x3_array_fini(X3_Array
*ma
)
51 memset(ma
, 0, sizeof(*ma
));
55 x3_array_push(X3_Array
*ma
, void *data
)
57 if (ma
->length
>= ma
->alloc
) {
62 ma
->data
= realloc(ma
->data
, sizeof(void*) * ma
->alloc
);
64 ma
->data
[ma
->length
++] = data
;
68 x3_array_pop(X3_Array
*ma
, X3_Size count
)
70 if (count
<= ma
->length
)
77 x3_array_first(X3_Array
*ma
)
86 x3_array_last(X3_Array
*ma
)
89 return ma
->data
[ma
->length
- 1];
97 X3_Result
* r
= x3_new(X3_Result
);
103 x3_result_init(X3_Result
* r
)
105 memset(r
, 0, sizeof(*r
));
109 x3_result_delete(X3_Result
* r
)
119 x3_result_read_from_file(X3_Result
* r
, const char *filename
)
128 f
= fopen(filename
, "rb");
130 fprintf(stderr
, "cannot open object file: %s: %s\n", filename
, strerror(errno
));
133 fseek(f
, 0, SEEK_END
);
135 fseek(f
, 0, SEEK_SET
);
137 r
->data
= (X3u8
*) malloc(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
));
152 x3_result_rewind(X3_Result
* r
)
158 x3_result_skip(X3_Result
* r
, unsigned count
)
165 x3_result_read_sig(X3_Result
* r
)
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);
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))
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
)
196 x3_result_find_sig(X3_Result
* r
, X3sig sig
)
199 if (x3_result_find_next(r
, sig
))
202 x3_error("cannot find expected data in output");
208 x3_result_find_item(X3_Result
* r
, unsigned uid
)
211 while (x3_result_find_next(r
, X3_SIG_ITEM
))
212 if (x3_result_read_uint(r
) == uid
)
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");
227 x3_result_read_int(X3_Result
* r
)
229 return x3_result_read_integer(r
, global
->target_info
.sizeof_int
, 1);
233 x3_result_read_uint(X3_Result
* r
)
235 return x3_result_read_integer(r
, global
->target_info
.sizeof_int
, 0);
239 x3_result_read_size(X3_Result
* r
)
241 return x3_result_read_integer(r
, global
->target_info
.sizeof_size_type
, 0);
245 x3_result_read_integer(X3_Result
* r
, int size
, int is_signed
)
248 X3u8
* p
= r
->data
+ r
->pos
;
254 if (! r
->target_info
->is_big_endian
)
256 if (is_signed
&& (*p
& 0x80))
257 result
= (X3_Int
) -1;
260 if (r
->target_info
->is_big_endian
)
262 result
= (result
<< 8) | *p
++;
265 result
= (result
<< 8) | *p
--;
272 X3_InputItem
* ii
= x3_new0(X3_InputItem
);
277 _x3_input_item_text_write_func(X3_InputItem
* ii
, FILE * f
)
279 fputs(ii
->input_text
, f
);
284 _x3_input_item_subst_text_write_func(X3_InputItem
* ii
, FILE * f
)
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
);
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
;
309 X3_InputGroup
* ig
= x3_new(X3_Array
);
317 global
= x3_new0(X3_Global
);
318 x3_global_init(global
);
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
;
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
;
362 x3_global_get_temp_fn(const char * suffix
)
364 // TODO: use make_temp_file..
365 if (global
->temp_base
) {
367 snprintf(buf
, sizeof(buf
), "%s%s", global
->temp_base
, suffix
);
370 return make_temp_file(suffix
);
374 x3_global_keep_temps()
376 return global
->temp_base
!= NULL
;
381 x3_push_optional(int optional
)
383 x3_array_push(& global
->optional_stack
, (void *) optional
);
389 x3_array_pop(& global
->optional_stack
, 1);
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
;
403 stream
= global
->log_stream
;
405 fputs("x3: ", stream
);
406 vfprintf(stream
, fmt
, va
);
411 void x3_log(const char *fmt
, ...)
420 x3_error(const char *fmt
, ...)
424 fputs("x3: ", stderr
);
428 vfprintf(stderr
, fmt
, va
);
430 global
->error_count
++;
436 x3_unsupported(const char * detail
)
438 x3_error("target unsupported: %s", detail
);
443 x3_interp_error(const char * detail
)
445 x3_error("cannot interpret output: %s", detail
);
450 x3_gcc_execute(X3_Array extra_args
)
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
458 const char * exec_bit
= "\"$@\"";
460 const char * exec_bit
= "exec \"$@\"";
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" : "",
468 char**args
= (char**)malloc(sizeof(char*) *
469 (global
->gcc_command
.length
+ extra_args
.length
+ 4 + 1));
471 char * shell
= getenv("SHELL");
476 args
[argi
++] = shell
;
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
;
490 FILE * stream
= global
->log_stream
;
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");
500 #ifdef PEX_RECORD_TIMES
503 result
= pex_one(PEX_SEARCH
, args
[0], args
, "x3", NULL
, NULL
, & status
, & err
);
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);
523 int pid
= pexecute(args
[0], args
, "x3", NULL
,
524 & rr
, & errmsg_arg
, PEXECUTE_SEARCH
| PEXECUTE_ONE
);
526 if (pid
> 0) { /* !! */
527 if (pwait(pid
, & status
, 0) != -1)
530 fprintf(stderr
, "pwait failed: %s\n", strerror(errno
));
538 x3_error("failed to run compiler: %s", result
);
543 x3_gcc_execute_l(const char * extra
, ...)
549 x3_array_init(& extra_args
);
550 x3_array_push(& extra_args
, (/*!!*/ char *) extra
);
552 char *p
= va_arg(va
, char *);
554 x3_array_push(& extra_args
, p
);
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");
573 x3_result_delete(global
->result
);
574 global
->result
= NULL
;
577 x3_gi_write_to_FILE(f
);
580 gcc_result
= x3_gcc_execute_l("-c", src_fn
, "-o", obj_fn
, NULL
);
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? */
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
*);
596 ii
->post_func(ii
, global
->result
);
604 if (! x3_global_keep_temps()) {
612 _x3_read_line(FILE *f
, char * buf
, unsigned buf_size
)
614 char * p
= fgets(buf
, buf_size
, f
);
618 while (! (q
=strchr(p
, '\n')) && ! feof(f
)) {
619 size_t len
= strlen(p
);
621 p
= (char*) malloc(len
* 2);
622 strncpy(p
, buf
, len
);
625 p
= (char*) realloc(p
, len
* 2);
626 fgets(p
+ len
, len
, f
);
634 _x3_get_macros_regex() {
635 static int initialized
= 0;
636 static regex_t macros_regex
;
639 if (regcomp(& macros_regex
,
640 "^#define ([^[:space:]\(]+)(\\([^[:space:]]+\\))?([[:space:]](.*))?$",
641 REG_EXTENDED
) != 0) {
642 x3_assert("failed to compile regex"==0);
646 return & macros_regex
;
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
);
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");
667 regex_t
* re
= _x3_get_macros_regex();
670 x3_gi_write_to_FILE(f
);
676 gcc_result
= x3_gcc_execute_l("-E", "-dM", "-o", mac_fn
, src_fn
, NULL
);
683 f
= fopen(mac_fn
, "r");
685 x3_error("cannot open %s: %s", mac_fn
, strerror(errno
));
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
;
708 if (! x3_global_keep_temps()) {
715 /* Run GCC. If it fails, it is an error. */
719 int result
= x3_compile_test();
721 x3_error("error: compiler exited with error");
725 static const char * _x3_offsetof_function
= "offsetof";
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>");
737 x3_gi_write_to_FILE(FILE *f
)
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
*);
748 ii
->write_func(ii
, f
);
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
);
762 x3_gi_push_headers_l(const char * hdr
, ...)
764 x3_gi_push_header(hdr
);
769 const char *p
= va_arg(va
, const char *);
771 x3_gi_push_header(p
);
781 x3_gi_pop_headers(1);
785 x3_gi_pop_headers(int count
)
787 x3_array_pop(global
->header_group
, 1);
793 global
->current_group
= x3_input_group_new();
794 x3_array_push(& global
->input_groups
, global
->current_group
);
800 x3_array_pop(& global
->input_groups
, 1);
801 global
->current_group
= x3_array_last(& global
->input_groups
);
805 x3_gi_push_input_item(X3_InputItem
*ii
)
807 x3_array_push(global
->current_group
, ii
);
811 x3_gi_pop_items(int count
)
813 x3_array_pop(global
->current_group
, count
);
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
);
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
);
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
);
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? */
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
);
876 x3_gi_push_default_enum(const char * default_val
, ...)
881 va_start(va
, default_val
);
883 const char * p
= va_arg(va
, const char *);
887 "#ifndef %s\n# define %s %s\n#endif\n",
888 result
, p
, p
, default_val
);
890 x3_gi_push_text(result
);
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 ");
900 x3_gi_write_start_item_data(FILE *f
, unsigned uid
)
902 fprintf(f
, "} __attribute__((packed)) \n_x3_item_%d\n = { \"zOmG\", \"iTeM\", %d, ",
907 x3_gi_write_finish_item(FILE *f
)
913 x3_query_target_info(X3_TargetInfo
*ti
)
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), "
933 if (! x3_result_find_sig(global
->result
, X3_SIG('t','G','t','I')))
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");
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
);
947 ti
->is_big_endian
= 0;
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>");
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");
962 x3_gi_pop_headers(1);
963 ti
->size_type
= "unsigned int";
964 ti
->sizeof_size_type
= ti
->sizeof_int
;
974 x3_query_int_type(const char *name
, X3_Type
* type
)
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;
987 unsigned my_uid
= ++uid_counter
;
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())
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
) {
1003 type
->kind
= X3_TYPE_KIND_VOID
;
1005 if (! x3_query_int_value(x3f("sizeof(%s)", name
), "x3i_size_t", & int_val
, & dummy
))
1007 type
->type_size
= (X3_UInt
) int_val
;
1009 /* test if scalarish (or array...) */
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();
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();
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
))
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
;
1040 type
->u
.array_length
= 0;
1041 type
->next
->out_name
= NULL
;
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
;
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... */
1065 type
->next
->kind
= X3_TYPE_KIND_VOID
;
1066 type
->next
->c_name
= type
->next
->out_name
= "void";
1068 type
->next
->out_name
= NULL
;
1074 /* Must be an int */
1075 x3_query_int_type(name
, type
);
1076 type
->out_name
= NULL
;
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();
1089 f
= x3_struct_new_field(s
);
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... */
1099 type
->kind
= X3_TYPE_KIND_RECORD
;
1100 type
->u
.struct_def
= s
;
1103 s
->struct_type
= *type
;
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()) {
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
;
1132 return out_type
->ok
;
1137 _x3_d_int_type(X3_Type
* type
)
1139 x3_assert(type
->kind
== X3_TYPE_KIND_INT
);
1140 switch (type
->type_size
) {
1142 if (type
->flags
& X3_FLAG_USE_BYTE
)
1143 return type
->type_is_signed
? "byte" : "ubyte";
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";
1150 x3_error("no D equivalent for integer type of %d bytes", (int) type
->type_size
);
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";
1164 x3_error("no D character type of %d bytes", (int) type
->type_size
);
1170 _x3_write_d_int_2(FILE * f
, X3_Int value
, unsigned size
, int is_signed
)
1173 int hi
= (value
>> (int)32) & 0xffffffff;
1174 if (hi
== 0 || hi
== -1)
1175 fprintf(f
, "%d", (int)value
);
1178 fprintf(f
, "cast(long)0x%x%08x", hi
, (unsigned)(value
& 0xffffffff));
1180 unsigned hi
= ((X3_UInt
) value
>> (unsigned)32) & 0xffffffff;
1182 fprintf(f
, "%u", (unsigned)value
);
1184 fprintf(f
, "0x%x%08xUL", hi
, (unsigned)(value
& 0xffffffff));
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
);
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
) {
1205 case X3_TYPE_KIND_VOID
:
1208 case X3_TYPE_KIND_INT
:
1209 result
= _x3_d_int_type(type
);
1211 case X3_TYPE_KIND_ARRAY
:
1212 result
= x3f("%s[%u]", _x3_format_d_type(type
->next
),
1213 (unsigned) type
->u
.array_length
);
1215 case X3_TYPE_KIND_POINTER
:
1216 result
= x3f("%s*", _x3_format_d_type(type
->next
));
1222 if (! type->out_name && use_name)
1223 type->out_name = result !! // ...should be separate cached.
1226 result
= type
->out_name
;
1231 _x3_format_d_type(X3_Type
*type
)
1233 return _x3_format_d_type_ex(type
, 1);
1240 X3_Type
* t
= x3_new0(X3_Type
);
1246 x3_type_init(X3_Type
* type
)
1248 memset(type
, 0, sizeof(*type
));
1249 type
->flags
|= X3_FLAG_USE_CHAR
;
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
;
1263 case X3_TYPE_KIND_NAME
:
1264 // can't do anything !!?
1266 case X3_TYPE_KIND_RECORD
:
1267 x3_struct_out(type
->u
.struct_def
);
1269 case X3_TYPE_KIND_ERROR
:
1273 fprintf(global
->output_stream
, "alias %s %s;\n",
1274 _x3_format_d_type_ex(type
, 0), out_name
);
1280 x3_out_int_type(const char* name
)
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
)
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
);
1304 x3_out_type(const char* name
)
1306 x3_out_type_ex(name
, NULL
, NULL
);
1309 const char * X3_STRUCT_FALLBACK
= "X3_STRUCT_FALLBACK";
1312 x3_out_type_ex(const char* c_name
, const char * out_name
, const char * fallback
)
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
));
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
);
1330 x3_out_int_value(const char* expr
)
1332 x3_out_int_value_ex(expr
, expr
, NULL
, NULL
, 0, NULL
);
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
)
1344 x3_log("checking for int value '%s'", expr
);
1350 if (x3_query_int_value(expr
, in_type
, & value
, & type
)) {
1351 fprintf(global
->output_stream
, "const %s %s = ",
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 = ",
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
);
1369 x3_out_enum(const char *name
, const char *type
, ...)
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
);
1389 while ( (p
= va_arg(va
, const char *)) ) {
1391 if (strcpsn(p, "-+()[]{}.*?/\\$^") == strlen(p)) { //!! should be ident reg or ident chars..
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
);
1406 if (regcomp(pre
, p
, REG_EXTENDED
) != 0) {
1407 x3_error("invalid pattern '%s'", p
);
1410 x3_array_push(is_excl
? & excl_patterns
: & incl_patterns
, pre
);
1413 fputc('\n', global
->log_stream
);
1415 if (x3_compile_get_macros(& macros
)) {
1418 regmatch_t matches
[1];
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
))
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) {
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) {
1445 if (incl
&& ! excl
) {
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
;
1457 fprintf(f
, " %s", name
);
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
);
1468 fprintf(f
, "}\n\n");
1469 } else if (! x3_is_optional())
1470 x3_error("failed to resolve macro values.");
1473 } else if (! x3_is_optional())
1474 x3_error("failed to get macros.");
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();
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
);
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();
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...");
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
;
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;
1548 s
->struct_type
.out_name
= c_name
;
1553 x3_struct_delete(X3_Struct
* s
)
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
);
1571 x3_struct_add_field(X3_Struct
* s
, X3_Field
* field
)
1573 x3_array_push(& s
->fields
, field
);
1579 _x3_struct_add_fields_v(X3_Struct
* s
, va_list va
)
1582 const char * p
= va_arg(va
, const char *);
1584 const char * flag_end
;
1589 field
= x3_struct_new_field(s
);
1590 if ( (flag_end
= strchr(p
, ':')) ) {
1591 name
= flag_end
+ 1;
1593 while (p
< flag_end
) {
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;
1601 const char * e
= strchr(p
, ';');
1603 char * tn
= (char*) malloc(e
-p
);
1604 strncpy(tn
, p
, e
-p
);
1607 field
->field_type
.kind
= X3_TYPE_KIND_NAME
;
1608 field
->field_type
.out_name
= tn
;
1616 field
->c_name
= field
->out_name
= name
;
1621 x3_struct_add_fields(X3_Struct
* s
, ...)
1625 _x3_struct_add_fields_v(s
, va
);
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
;
1644 x3_struct_finish(X3_Struct
* s
)
1648 x3_log("translating struct '%s'", s
->struct_type
.c_name
);
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
);
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
);
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
);
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
));
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
;
1711 s
->record_kind
= X3_RECORD_STRUCT
;
1714 s
->struct_type
.kind
= X3_TYPE_KIND_RECORD
;
1718 if (! x3_query_int_value(x3f("sizeof(%s)", s
->struct_type
.c_name
), "x3i_size_t",
1721 s
->struct_type
.type_size
= sz
;
1724 s
->struct_type
.ok
= 1;
1732 _x3_struct_write_to_FILE(X3_Struct
* s
, FILE * f
)
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;
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
) {
1753 } else if (in_union
) {
1758 if (field
->field_offset
> next_offset
)
1759 fprintf(f
, " ubyte[%u] __pad%u;\n",
1760 (unsigned)(field
->field_offset
- next_offset
), pad_idx
++);
1763 i
+ 1 != n_fields
&&
1764 field
->field_offset
== all_fields
[i
+1]->field_offset
) {
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 */
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
);
1787 fprintf(f
, "}\n\n");
1791 x3_struct_out(X3_Struct
* s
)
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
);
1806 x3_out_struct(const char * c_name
, const char *out_name
, ...)
1808 X3_Struct
* s
= x3_struct_new_c_name(c_name
);
1813 s
->struct_type
.out_name
= out_name
;
1815 va_start(va
, out_name
);
1816 _x3_struct_add_fields_v(s
, va
);
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
);
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
);