From d68db74049f93805060e555b13d5f9a1b372517a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 24 Apr 2022 15:12:56 +0900 Subject: [PATCH] [cexpr] Add a flags type Based on the flags type used in vkparse (difference is the lack of support for plists). Having this will make supporting named flags in cvars much easier (though setting up the enum type is a bit of a chore). --- include/QF/cexpr.h | 3 +++ libs/util/cexpr-type.c | 50 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/include/QF/cexpr.h b/include/QF/cexpr.h index 665595d92..c0d608f80 100644 --- a/include/QF/cexpr.h +++ b/include/QF/cexpr.h @@ -117,6 +117,7 @@ binop_t *cexpr_find_cast (exprtype_t *dst_type, exprtype_t *src_type) __attribut exprval_t *cexpr_value (exprtype_t *type, exprctx_t *ctx); exprval_t *cexpr_value_reference (exprtype_t *type, void *data, exprctx_t *ctx); const char *cexpr_enum_get_string (const exprval_t *val, struct va_ctx_s *va_ctx) __attribute__((pure)); +const char *cexpr_flags_get_string (const exprval_t *val, struct va_ctx_s *va_ctx) __attribute__((pure)); int cexpr_eval_string (const char *str, exprctx_t *context); void cexpr_error(exprctx_t *ctx, const char *fmt, ...) __attribute__((format(PRINTF,2,3))); @@ -151,6 +152,8 @@ extern exprtype_t cexpr_plitem; extern binop_t cexpr_array_binops[]; extern binop_t cexpr_struct_binops[]; extern binop_t cexpr_struct_pointer_binops[]; +extern binop_t cexpr_flag_binops[]; +extern unop_t cexpr_flag_unops[]; extern exprsym_t cexpr_lib_symbols[]; diff --git a/libs/util/cexpr-type.c b/libs/util/cexpr-type.c index 2df8bfdce..cf622e786 100644 --- a/libs/util/cexpr-type.c +++ b/libs/util/cexpr-type.c @@ -815,3 +815,53 @@ cexpr_enum_get_string (const exprval_t *val, va_ctx_t *va_ctx) } return ""; } + +BINOP(flag, and, int, &) +BINOP(flag, or, int, |) +BINOP(flag, xor, int, ^) + +UNOP(flag, not, int, ~) + +binop_t cexpr_flag_binops[] = { + { '&', 0, 0, flag_and }, + { '|', 0, 0, flag_or }, + { '^', 0, 0, flag_xor }, + { '=', &cexpr_int, 0, uint_cast_int }, + {} +}; + +unop_t cexpr_flag_unops[] = { + { '~', 0, flag_not }, + {} +}; + +VISIBLE const char * +cexpr_flags_get_string (const exprval_t *val, va_ctx_t *va_ctx) +{ + exprenum_t *enm = val->type->data; + exprsym_t *symbols = enm->symtab->symbols; + const char *val_str = 0; + + if (val->type->size != 4) { + Sys_Error ("cexpr_flags_get_string: only 32-bit values supported"); + } + uint32_t flags = *(uint32_t *) val->value; + for (exprsym_t *sym = symbols; sym->name; sym++) { + uint32_t sym_flags = *(uint32_t *) sym->value; + // if there are duplicate values, choose the *later* value + if (sym[1].name && sym_flags == *(uint32_t *) sym[1].value) { + continue; + } + if ((flags & sym_flags) && !(sym_flags & ~flags)) { + if (val_str) { + val_str = va (va_ctx, "%s | %s", val_str, sym->name); + } else { + val_str = sym->name; + } + } + } + if (!val_str) { + val_str = "0"; + } + return val_str; +}