X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=gmqcc.h;h=e609257d7cf72281b3684fe1943eb1925a2a97b3;hp=d8ad37465ef0525ea2298a9eb484f7a6e9220f04;hb=893f204b30affbb4407fcddb16576156a648eac6;hpb=c2cf41baf95c7a45789e4c73202928baf9e9b650 diff --git a/gmqcc.h b/gmqcc.h index d8ad374..e609257 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 + * Copyright (C) 2012, 2013, 2014, 2015 * Dale Weiler * Wolfgang Bumiller * @@ -24,27 +24,16 @@ #ifndef GMQCC_HDR #define GMQCC_HDR #include -#include /* TODO: remove this */ - -/* - * Disable some over protective warnings in visual studio because fixing them is a waste - * of my time. - */ -#ifdef _MSC_VER -# pragma warning(disable : 4244 ) /* conversion from 'int' to 'float', possible loss of data */ -#endif /*! _MSC_VER */ +#include +#include +#include #define GMQCC_VERSION_MAJOR 0 -#define GMQCC_VERSION_MINOR 4 -#define GMQCC_VERSION_PATCH 0 -#define GMQCC_VERSION_BUILD(J,N,P) (((J)<<16)|((N)<<8)|(P)) -#define GMQCC_VERSION \ - GMQCC_VERSION_BUILD(GMQCC_VERSION_MAJOR, GMQCC_VERSION_MINOR, GMQCC_VERSION_PATCH) -/* Undefine the following on a release-tag: */ -#define GMQCC_VERSION_TYPE_DEVEL - -/* Full version string in case we need it */ -#ifdef GMQCC_VERSION_TYPE_DEVEL +#define GMQCC_VERSION_MINOR 3 +#define GMQCC_VERSION_PATCH 6 +#define GMQCC_VERSION ((GMQCC_VERSION_MAJOR<<16)|(GMQCC_VERSION_MINOR<<8)|GMQCC_VERSION_PATCH) + +#ifdef GMQCC_VERSION_TYPE_RELEASE # ifdef GMQCC_GITINFO # define GMQCC_DEV_VERSION_STRING "git build: " GMQCC_GITINFO "\n" # elif defined(GMQCC_VERSION_TYPE_DEVEL) @@ -66,117 +55,52 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \ " Built " __DATE__ " " __TIME__ \ "\n" GMQCC_DEV_VERSION_STRING -/* - * We cannot rely on C99 at all, since compilers like MSVC - * simply don't support it. We define our own boolean type - * as a result (since we cannot include ). For - * compilers that are in 1999 mode (C99 compliant) we can use - * the language keyword _Bool which can allow for better code - * on GCC and GCC-like compilers, opposed to `int`. - */ #ifndef __cplusplus -# ifdef false -# undef false -# endif /*! false */ -# ifdef true -# undef true -# endif /*! true */ -# define false (unsigned)(0) -# define true (unsigned)(1) -# ifdef __STDC_VERSION__ -# if __STDC_VERSION__ < 199901L && __GNUC__ < 3 - typedef int bool; -# else - typedef _Bool bool; -# endif /*! __STDC_VERSION__ < 199901L && __GNUC__ < 3 */ -# else - typedef int bool; -# endif /*! __STDC_VERSION__ */ -#endif /*! __cplusplus */ +# define false (unsigned char)(0) +# define true (unsigned char)(1) + typedef unsigned char bool; +#endif -/* - * Of some functions which are generated we want to make sure - * that the result isn't ignored. To find such function calls, - * we use this macro. - */ #if defined(__GNUC__) || defined(__CLANG__) -# define GMQCC_WARN __attribute__((warn_unused_result)) -# define GMQCC_USED __attribute__((used)) -#else -# define GMQCC_WARN -# define GMQCC_USED -#endif /*! defined(__GNUC__) || defined (__CLANG__) */ - -/* - * Inline is not supported in < C90, however some compilers - * like gcc and clang might have an inline attribute we can - * use if present. - */ -#ifdef __STDC_VERSION__ -# if __STDC_VERSION__ < 199901L -# if defined(__GNUC__) || defined (__CLANG__) -# if __GNUC__ < 2 -# define GMQCC_INLINE -# else -# define GMQCC_INLINE __attribute__ ((always_inline)) -# endif /*! __GNUC__ < 2 */ -# else -# define GMQCC_INLINE -# endif /*! defined(__GNUC__) || defined (__CLANG__) */ -# else -# define GMQCC_INLINE inline -# endif /*! __STDC_VERSION < 199901L */ -/* - * Visual studio has __forcinline we can use. So lets use that - * I suspect it also has just __inline of some sort, but our use - * of inline is correct (not guessed), WE WANT IT TO BE INLINE - */ -#elif defined(_MSC_VER) -# define GMQCC_INLINE __forceinline -#else -# define GMQCC_INLINE -#endif /*! __STDC_VERSION__ */ - -/* - * noreturn is present in GCC and clang - * it's required for _ast_node_destory otherwise -Wmissing-noreturn - * in clang complains about there being no return since abort() is - * called. - */ -#if (defined(__GNUC__) && __GNUC__ >= 2) || defined(__CLANG__) -# define GMQCC_NORETURN __attribute__ ((noreturn)) -#else -# define GMQCC_NORETURN -#endif /*! (defined(__GNUC__) && __GNUC__ >= 2) || defined (__CLANG__) */ - -#if (defined(__GNUC__)) || defined(__CLANG__) +# include +# if (__GNUC__ >= 2) || defined(__CLANG__) +# define GMQCC_NORETURN __attribute__((noreturn)) +# define GMQCC_FORCEINLINE __attribute__((always_inline)) +# define GMQCC_INLINE __inline +# endif # define GMQCC_LIKELY(X) __builtin_expect((X), 1) # define GMQCC_UNLIKELY(X) __builtin_expect((X), 0) +# define GMQCC_WARN __attribute__((warn_unused_result)) +# define GMQCC_USED __attribute__((used)) +# define GMQCC_RESTRICT __restrict__ #else +# ifdef _MSC_VER + /* conversion from 'int' to 'float', possible loss of data */ +# pragma warning(disable : 4244) + + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int64 uint64_t; + typedef __int16 int16_t; + typedef __int32 int32_t; + typedef __int64 int64_t; +# define GMQCC_NORETURN __declspec(noreturn) +# define GMQCC_FORCEINLINE __forceinline +# define GMQCC_INLINE __inline +# define GMQCC_RESTRICT __restrict +# else +# define GMQCC_NORETURN +# define GMQCC_FORCEINLINE +# define GMQCC_INLINE +# define GMQCC_RESTRICT +# endif # define GMQCC_LIKELY(X) (X) # define GMQCC_UNLIKELY(X) (X) +# define GMQCC_WARN +# define GMQCC_USED #endif -#define GMQCC_ARRAY_COUNT(X) (sizeof(X) / sizeof((X)[0])) - -#ifndef _MSC_VER -# include -#else - typedef unsigned __int8 uint8_t; - typedef unsigned __int16 uint16_t; - typedef unsigned __int32 uint32_t; - typedef unsigned __int64 uint64_t; - - typedef __int16 int16_t; - typedef __int32 int32_t; - typedef __int64 int64_t; -#endif /*! _MSC_VER */ - -/* - * Very roboust way at determining endianess at compile time: this handles - * almost every possible situation. Otherwise a runtime check has to be - * performed. - */ #define GMQCC_BYTE_ORDER_LITTLE 1234 #define GMQCC_BYTE_ORDER_BIG 4321 @@ -250,66 +174,22 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \ # else # define PLATFORM_BYTE_ORDER -1 # endif -#endif /*! !defined (PLATFORM_BYTE_ORDER) */ +#endif -/* - * On windows systems where we're not compiling with MING32 we need a - * little extra help on dependinces for implementing our own dirent.h - * in fs.c. - */ -#if defined(_WIN32) && !defined(__MINGW32__) -# define _WIN32_LEAN_AND_MEAN -# include -# include -# include - - struct dirent { - long d_ino; - unsigned short d_reclen; - unsigned short d_namlen; - char d_name[FILENAME_MAX]; - }; - - typedef struct { - struct _finddata_t dd_dta; - struct dirent dd_dir; - long dd_handle; - int dd_stat; - char dd_name[1]; - } DIR; - /* - * Visual studio also lacks S_ISDIR for sys/stat.h, so we emulate this as well - * which is not hard at all. - */ -# ifdef S_ISDIR -# undef S_ISDIR -# endif /*! S_ISDIR */ -# define S_ISDIR(X) ((X)&_S_IFDIR) -#else -# include -#endif /*! _WIN32 && !defined(__MINGW32__) */ - -/*===================================================================*/ -/*=========================== stat.c ================================*/ -/*===================================================================*/ -void stat_info (void); -char *stat_mem_strdup (const char *, size_t, const char *, bool); -void *stat_mem_reallocate(void *, size_t, size_t, const char *); -void stat_mem_deallocate(void *); -void *stat_mem_allocate (size_t, size_t, const char *); - -#define mem_a(SIZE) stat_mem_allocate ((SIZE), __LINE__, __FILE__) -#define mem_d(PTRN) stat_mem_deallocate((void*)(PTRN)) -#define mem_r(PTRN, SIZE) stat_mem_reallocate((void*)(PTRN), (SIZE), __LINE__, __FILE__) -#define mem_af(SIZE, FILE, LINE) stat_mem_allocate ((SIZE), (LINE), (FILE)) +#define GMQCC_ARRAY_COUNT(X) (sizeof(X) / sizeof((X)[0])) + +/* stat.c */ +char *stat_mem_strdup(const char *, bool); + +#define mem_a(SIZE) malloc(SIZE) +#define mem_d(PTRN) free((void*)PTRN) +#define mem_r(PTRN, SIZE) realloc((void*)PTRN, SIZE) /* TODO: rename to mem variations */ -#define util_strdup(SRC) stat_mem_strdup((char*)(SRC), __LINE__, __FILE__, false) -#define util_strdupe(SRC) stat_mem_strdup((char*)(SRC), __LINE__, __FILE__, true) +#define util_strdup(SRC) stat_mem_strdup((char*)(SRC), false) +#define util_strdupe(SRC) stat_mem_strdup((char*)(SRC), true) -/*===================================================================*/ -/*=========================== util.c ================================*/ -/*===================================================================*/ +/* util.c */ /* * Microsoft implements against the spec versions of ctype.h. Which @@ -329,10 +209,10 @@ void *stat_mem_allocate (size_t, size_t, const char *); #define util_isprint(a) (((unsigned)(a)-0x20) < 0x5F) #define util_isspace(a) (((a) >= 9 && (a) <= 13) || (a) == ' ') -bool util_filexists (const char *); -bool util_strupper (const char *); -bool util_strdigit (const char *); -void util_endianswap (void *, size_t, unsigned int); +bool util_strupper(const char *); +bool util_strdigit(const char *); + +void util_endianswap(void *, size_t, unsigned int); size_t util_strtocmd (const char *, char *, size_t); size_t util_strtononcmd (const char *, char *, size_t); @@ -343,18 +223,20 @@ uint16_t util_crc16(uint16_t crc, const char *data, size_t len); void util_seed(uint32_t); uint32_t util_rand(void); -/* - * String functions (formatting, copying, concatenating, errors). These are wrapped - * to use the MSVC _safe_ versions when using MSVC, plus some implementations of - * these are non-conformant or don't exist such as asprintf and snprintf, which are - * not supported in C90, but do exist in C99. - */ -int util_vasprintf(char **ret, const char *fmt, va_list); -int util_asprintf (char **ret, const char *fmt, ...); -int util_snprintf (char *src, size_t bytes, const char *format, ...); -char *util_strcat (char *dest, const char *src); -char *util_strncpy (char *dest, const char *src, size_t num); -const char *util_strerror (int num); +int util_asprintf (char **ret, const char *fmt, ...); +int util_sscanf (const char *str, const char *format, ...); +char *util_strncpy (char *dest, const char *src, size_t n); +char *util_strncat (char *dest, const char *src, size_t n); +char *util_strcat (char *dest, const char *src); +const char *util_strerror(int err); + +const struct tm *util_localtime(const time_t *timer); +const char *util_ctime (const time_t *timer); + +typedef struct fs_file_s fs_file_t; + +bool util_isatty(fs_file_t *); +size_t hash(const char *key); /* * A flexible vector implementation: all vector pointers contain some @@ -372,15 +254,17 @@ typedef struct { /* hidden interface */ void _util_vec_grow(void **a, size_t i, size_t s); -#define GMQCC_VEC_WILLGROW(X,Y) ( \ +void _util_vec_delete(void *vec, size_t line, const char *file); + +#define GMQCC_VEC_WILLGROW(X, Y) ( \ ((!(X) || vec_meta(X)->used + Y >= vec_meta(X)->allocated)) ? \ (void)_util_vec_grow(((void**)&(X)), (Y), sizeof(*(X))) : \ (void)0 \ ) /* exposed interface */ -#define vec_meta(A) (((vector_t*)((void*)A)) - 1) -#define vec_free(A) ((void)((A) ? (mem_d((void*)vec_meta(A)), (A) = NULL) : 0)) +#define vec_meta(A) ((vector_t*)(((char *)(A)) - sizeof(vector_t))) +#define vec_free(A) ((void)((A) ? (_util_vec_delete((void *)(A), __LINE__, __FILE__), (A) = NULL) : 0)) #define vec_push(A,V) (GMQCC_VEC_WILLGROW((A),1), (A)[vec_meta(A)->used++] = (V)) #define vec_size(A) ((A) ? vec_meta(A)->used : 0) #define vec_add(A,N) (GMQCC_VEC_WILLGROW((A),(N)), vec_meta(A)->used += (N), &(A)[vec_meta(A)->used-(N)]) @@ -391,13 +275,6 @@ void _util_vec_grow(void **a, size_t i, size_t s); #define vec_append(A,N,S) ((void)(memcpy(vec_add((A), (N)), (S), (N) * sizeof(*(S))))) #define vec_remove(A,I,N) ((void)(memmove((A)+(I),(A)+((I)+(N)),sizeof(*(A))*(vec_meta(A)->used-(I)-(N))),vec_meta(A)->used-=(N))) -typedef struct correct_trie_s { - void *value; - struct correct_trie_s *entries; -} correct_trie_t; - -correct_trie_t* correct_trie_new(void); - typedef struct hash_table_s { size_t size; struct hash_node_t **table; @@ -445,48 +322,40 @@ void util_htrm (hash_table_t *ht, const char *key, void (*cb)(void*)); void *util_htget (hash_table_t *ht, const char *key); void *util_htgeth(hash_table_t *ht, const char *key, size_t hash); -/*===================================================================*/ -/*============================ file.c ===============================*/ -/*===================================================================*/ -/* file handling */ -void fs_file_close (FILE *); -int fs_file_error (FILE *); -int fs_file_getc (FILE *); -int fs_file_printf (FILE *, const char *, ...); -int fs_file_puts (FILE *, const char *); -int fs_file_seek (FILE *, long int, int); -long int fs_file_tell (FILE *); - -size_t fs_file_read (void *, size_t, size_t, FILE *); -size_t fs_file_write (const void *, size_t, size_t, FILE *); - -FILE *fs_file_open (const char *, const char *); -int fs_file_getline(char **, size_t *, FILE *); - -/* directory handling */ -int fs_dir_make (const char *); -DIR *fs_dir_open (const char *); -int fs_dir_close (DIR *); -struct dirent *fs_dir_read (DIR *); +int util_snprintf(char *str, size_t, const char *fmt, ...); -/*===================================================================*/ -/*=========================== correct.c =============================*/ -/*===================================================================*/ -typedef struct { - char ***edits; - size_t **lens; -} correction_t; +/* fs.c */ +#define FS_FILE_SEEK_SET 0 +#define FS_FILE_SEEK_CUR 1 +#define FS_FILE_SEEK_END 2 +#define FS_FILE_EOF -1 -void correct_del (correct_trie_t*, size_t **); -void correct_add (correct_trie_t*, size_t ***, const char *); -char *correct_str (correction_t *, correct_trie_t*, const char *); -void correct_init(correction_t *); -void correct_free(correction_t *); +typedef struct fs_dir_s fs_dir_t; +/*typedef struct fs_file_s fs_file_t;*/ +typedef struct dirent fs_dirent_t; -/*===================================================================*/ -/*=========================== code.c ================================*/ -/*===================================================================*/ +void fs_file_close (fs_file_t *); +int fs_file_error (fs_file_t *); +int fs_file_getc (fs_file_t *); +int fs_file_printf (fs_file_t *, const char *, ...); +int fs_file_puts (fs_file_t *, const char *); +int fs_file_seek (fs_file_t *, long int, int); +long fs_file_tell (fs_file_t *); +int fs_file_flush (fs_file_t *); + +size_t fs_file_read (void *, size_t, size_t, fs_file_t *); +size_t fs_file_write (const void *, size_t, size_t, fs_file_t *); + +fs_file_t *fs_file_open (const char *, const char *); +int fs_file_getline(char **, size_t *, fs_file_t *); + +int fs_dir_make (const char *); +fs_dir_t *fs_dir_open (const char *); +int fs_dir_close (fs_dir_t *); +fs_dirent_t *fs_dir_read (fs_dir_t *); + +/* code.c */ /* Note: if you change the order, fix type_sizeof in ir.c */ enum { @@ -712,6 +581,7 @@ enum { VINSTR_PHI, VINSTR_JUMP, VINSTR_COND, + /* A never returning CALL. * Creating this causes IR blocks to be marked as 'final'. * No-Return-Call @@ -726,12 +596,19 @@ enum { VINSTR_BITXOR, VINSTR_BITXOR_V, VINSTR_BITXOR_VF, - VINSTR_CROSS + VINSTR_CROSS, + VINSTR_NEG_F, + VINSTR_NEG_V }; /* TODO: elide */ extern const char *util_instr_str[VINSTR_END]; +void util_swap_header (prog_header_t *code_header); +void util_swap_statements (prog_section_statement_t *statements); +void util_swap_defs_fields(prog_section_both_t *section); +void util_swap_functions (prog_section_function_t *functions); +void util_swap_globals (int32_t *globals); typedef float qcfloat_t; typedef int32_t qcint_t; @@ -780,9 +657,7 @@ void code_push_statement(code_t *, prog_section_statement_t *stmt, lex_ctx_ void code_pop_statement (code_t *); -/*===================================================================*/ -/*============================ con.c ================================*/ -/*===================================================================*/ +/* conout.c */ enum { CON_BLACK = 30, CON_RED, @@ -801,8 +676,8 @@ enum { LVL_ERROR }; -FILE *con_default_out(void); -FILE *con_default_err(void); +fs_file_t *con_default_out(void); +fs_file_t *con_default_err(void); void con_vprintmsg (int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, va_list ap); void con_printmsg (int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, ...); @@ -830,10 +705,8 @@ bool GMQCC_WARN compile_warning (lex_ctx_t ctx, int warntype, const char *fmt, . bool GMQCC_WARN vcompile_warning(lex_ctx_t ctx, int warntype, const char *fmt, va_list ap); void compile_show_werrors(void); -/*===================================================================*/ -/*============================= ir.c ================================*/ -/*===================================================================*/ - +/* ir.c */ +/* TODO: cleanup */ enum store_types { store_global, store_local, /* local, assignable for now, should get promoted later */ @@ -846,9 +719,7 @@ typedef struct { qcfloat_t x, y, z; } vec3_t; -/*===================================================================*/ -/*============================= exec.c ==============================*/ -/*===================================================================*/ +/* exec.c */ /* TODO: cleanup */ /* @@ -893,17 +764,17 @@ typedef struct { } qc_exec_stack_t; typedef struct qc_program_s { - char *filename; + char *filename; prog_section_statement_t *code; prog_section_def_t *defs; prog_section_def_t *fields; prog_section_function_t *functions; - char *strings; - qcint_t *globals; - qcint_t *entitydata; - bool *entitypool; + char *strings; + qcint_t *globals; + qcint_t *entitydata; + bool *entitypool; - const char* *function_stack; + const char* *function_stack; uint16_t crc16; @@ -929,6 +800,20 @@ typedef struct qc_program_s { size_t xflags; int argc; /* current arg count for debugging */ + + /* cached fields */ + struct { + qcint_t frame; + qcint_t nextthink; + qcint_t think; + } cached_fields; + + struct { + qcint_t self; + qcint_t time; + } cached_globals; + + bool supports_state; /* is INSTR_STATE supported? */ } qc_program_t; qc_program_t* prog_load (const char *filename, bool ignoreversion); @@ -941,9 +826,7 @@ qcany_t* prog_getedict (qc_program_t *prog, qcint_t e); qcint_t prog_tempstring(qc_program_t *prog, const char *_str); -/*===================================================================*/ -/*===================== parser.c commandline ========================*/ -/*===================================================================*/ +/* parser.c */ struct parser_s; struct parser_s *parser_create (void); bool parser_compile_file (struct parser_s *parser, const char *); @@ -951,9 +834,7 @@ bool parser_compile_string(struct parser_s *parser, const char *, co bool parser_finish (struct parser_s *parser, const char *); void parser_cleanup (struct parser_s *parser); -/*===================================================================*/ -/*====================== ftepp.c commandline ========================*/ -/*===================================================================*/ +/* ftepp.c */ struct ftepp_s; struct ftepp_s *ftepp_create (void); bool ftepp_preprocess_file (struct ftepp_s *ftepp, const char *filename); @@ -964,9 +845,7 @@ void ftepp_flush (struct ftepp_s *ftepp); void ftepp_add_define (struct ftepp_s *ftepp, const char *source, const char *name); void ftepp_add_macro (struct ftepp_s *ftepp, const char *name, const char *value); -/*===================================================================*/ -/*======================= main.c commandline ========================*/ -/*===================================================================*/ +/* main.c */ #if 1 /* Helpers to allow for a whole lot of flags. Otherwise we'd limit @@ -984,21 +863,12 @@ typedef uint32_t longbit; #define LONGBIT_SET(B, I) ((B) = (I)) #endif -/*===================================================================*/ -/*=========================== utf8lib.c =============================*/ -/*===================================================================*/ -typedef uint32_t uchar_t; - -bool u8_analyze (const char *_s, size_t *_start, size_t *_len, uchar_t *_ch, size_t _maxlen); -size_t u8_strlen (const char*); -size_t u8_strnlen (const char*, size_t); -uchar_t u8_getchar (const char*, const char**); -uchar_t u8_getnchar(const char*, const char**, size_t); -int u8_fromchar(uchar_t w, char *to, size_t maxlen); - -/*===================================================================*/ -/*============================= opts.c ==============================*/ -/*===================================================================*/ +/* utf.8 */ +typedef long utf8ch_t; +int utf8_from(char *, utf8ch_t); +int utf8_to(utf8ch_t *, const unsigned char *, size_t); + +/* opts.c */ typedef struct { const char *name; longbit bit; @@ -1063,11 +933,19 @@ typedef enum { COMPILER_GMQCC /* this QuakeC */ } opts_std_t; -typedef union { - bool B; - uint16_t U16; - uint32_t U32; - char *STR; +typedef struct { + union { + bool b; + uint16_t u16; + uint32_t u32; + + union { + char *p; + const char *c; + } str; + } data; + + bool allocated; } opt_value_t; @@ -1084,14 +962,18 @@ typedef struct { extern opts_cmd_t opts; -#define OPTS_GENERIC(f,i) (!! (((f)[(i)/32]) & (1<< (unsigned)((i)%32)))) +#define OPTS_GENERIC(f,i) (!! (((f)[(i)/32]) & (1U << (unsigned)((i)%32)))) + #define OPTS_FLAG(i) OPTS_GENERIC(opts.flags, (i)) #define OPTS_WARN(i) OPTS_GENERIC(opts.warn, (i)) #define OPTS_WERROR(i) OPTS_GENERIC(opts.werror, (i)) #define OPTS_OPTIMIZATION(i) OPTS_GENERIC(opts.optimization, (i)) -#define OPTS_OPTION_BOOL(X) (opts.options[X].B) -#define OPTS_OPTION_U16(X) (opts.options[X].U16) -#define OPTS_OPTION_U32(X) (opts.options[X].U32) -#define OPTS_OPTION_STR(X) (opts.options[X].STR) + +#define OPTS_OPTION_DUPED(X) (opts.options[X].allocated) +#define OPTS_OPTION_BOOL(X) (opts.options[X].data.b) +#define OPTS_OPTION_U16(X) (opts.options[X].data.u16) +#define OPTS_OPTION_U32(X) (opts.options[X].data.u32) +#define OPTS_OPTION_STR(X) (opts.options[X].data.str.c) +#define OPTS_OPTION_DUP(X) *(OPTS_OPTION_DUPED(X)=true, &(opts.options[X].data.str.p)) #endif /*! GMQCC_HDR */