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; +}