diff options
Diffstat (limited to 'src/libstrongswan/utils')
-rw-r--r-- | src/libstrongswan/utils/enum.c | 93 | ||||
-rw-r--r-- | src/libstrongswan/utils/enum.h | 35 |
2 files changed, 122 insertions, 6 deletions
diff --git a/src/libstrongswan/utils/enum.c b/src/libstrongswan/utils/enum.c index f96fe2989..089bebb79 100644 --- a/src/libstrongswan/utils/enum.c +++ b/src/libstrongswan/utils/enum.c @@ -60,20 +60,103 @@ bool enum_from_name_as_int(enum_name_t *e, const char *name, int *val) } /** + * Get the position of a flag name using offset calculation + */ +static int find_flag_pos(u_int val, u_int first) +{ + int offset = 0; + + while (val != 0x01) + { + val = val >> 1; + offset++; + } + return first - offset; +} + +/** * Described in header. */ +char *enum_flags_to_string(enum_name_t *e, u_int val, char *buf, size_t len) +{ + char *pos = buf, *delim = ""; + int i, wr; + + if (e->next != ENUM_FLAG_MAGIC) + { + if (snprintf(buf, len, "(%d)", (int)val) >= len) + { + return NULL; + } + return buf; + } + + if (snprintf(buf, len, "(unset)") >= len) + { + return NULL; + } + + for (i = 0; val; i++) + { + u_int flag = 1 << i; + + if (val & flag) + { + char *name = NULL, hex[32]; + + if (flag >= (u_int)e->first && flag <= (u_int)e->last) + { + name = e->names[find_flag_pos(e->first, i)]; + } + else + { + snprintf(hex, sizeof(hex), "(0x%X)", flag); + name = hex; + } + if (name) + { + wr = snprintf(pos, len, "%s%s", delim, name); + if (wr >= len) + { + return NULL; + } + len -= wr; + pos += wr; + delim = " | "; + } + val &= ~flag; + } + } + return buf; +} + +/** + * See header. + */ int enum_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, const void *const *args) { enum_name_t *ed = *((enum_name_t**)(args[0])); int val = *((int*)(args[1])); - char *name, buf[32]; + char *name, buf[512]; - name = enum_to_name(ed, val); - if (name == NULL) + if (ed->next == ENUM_FLAG_MAGIC) + { + name = enum_flags_to_string(ed, val, buf, sizeof(buf)); + if (name == NULL) + { + snprintf(buf, sizeof(buf), "(0x%X)", val); + name = buf; + } + } + else { - snprintf(buf, sizeof(buf), "(%d)", val); - name = buf; + name = enum_to_name(ed, val); + if (name == NULL) + { + snprintf(buf, sizeof(buf), "(%d)", val); + name = buf; + } } if (spec->minus) { diff --git a/src/libstrongswan/utils/enum.h b/src/libstrongswan/utils/enum.h index 3c03c2a7b..b45ed4b43 100644 --- a/src/libstrongswan/utils/enum.h +++ b/src/libstrongswan/utils/enum.h @@ -27,6 +27,11 @@ typedef struct enum_name_t enum_name_t; /** + * Magic enum_name_t pointer indicating this is an enum name for flags + */ +#define ENUM_FLAG_MAGIC ((enum_name_t*)~(uintptr_t)0) + +/** * Struct to store names for enums. * * To print the string representation of enumeration values, the strings @@ -58,7 +63,7 @@ struct enum_name_t { int first; /** value of the last enum string */ int last; - /** next enum_name_t in list */ + /** next enum_name_t in list, or ENUM_FLAG_MAGIC */ enum_name_t *next; /** array of strings containing names from first to last */ char *names[]; @@ -107,6 +112,23 @@ struct enum_name_t { #define ENUM(name, first, last, ...) ENUM_BEGIN(name, first, last, __VA_ARGS__); ENUM_END(name, last) /** + * Define a enum name with only one range for flags. + * + * Using an enum list for flags would be overkill. Hence we use a single + * range with all values in range. The next pointer is abused to mark + * that the enum name is for flags only. Use NULL if a particular flag + * is not meant to be printed. + * + * @param name name of the enum_name list + * @param first enum value of the first enum string + * @param last enum value of the last enum string + * @param ... a list of strings + */ +#define ENUM_FLAGS(name, first, last, ...) \ + static enum_name_t name##last = {first, last, ENUM_FLAG_MAGIC, { __VA_ARGS__ }}; \ + ENUM_END(name, last) + +/** * Convert a enum value to its string representation. * * @param e enum names for this enum value @@ -146,6 +168,17 @@ char *enum_to_name(enum_name_t *e, int val); bool enum_from_name_as_int(enum_name_t *e, const char *name, int *val); /** + * Convert a enum value containing flags to its string representation. + * + * @param e enum names for this enum value suitable for flags + * @param val enum value to get string for + * @param buf buffer to write flag string to + * @param len buffer size + * @return buf, NULL if buffer too small + */ +char *enum_flags_to_string(enum_name_t *e, u_int val, char *buf, size_t buflen); + +/** * printf hook function for enum_names_t. * * Arguments are: |