/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2012 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008-2013 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2012-2017 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2017 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2017-2022 IBM Corporation. All rights reserved. * Copyright (c) 2018 Amazon.com, Inc. or its affiliates. All Rights reserved. * Copyright (c) 2022 Computer Architecture and VLSI Systems (CARV) * Laboratory, ICS Forth. All rights reserved. * Copyright (c) 2023 Jeffrey M. Squyres. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "opal_config.h" #include "opal/mca/base/base.h" #include "opal/mca/base/mca_base_var_enum.h" #include "opal/mca/base/mca_base_vari.h" #include "opal/util/argv.h" #include "opal/util/printf.h" #include #include #include static void mca_base_var_enum_constructor(mca_base_var_enum_t *enumerator); static void mca_base_var_enum_destructor(mca_base_var_enum_t *enumerator); OBJ_CLASS_INSTANCE(mca_base_var_enum_t, opal_object_t, mca_base_var_enum_constructor, mca_base_var_enum_destructor); static void mca_base_var_enum_flag_constructor(mca_base_var_enum_flag_t *enumerator); static void mca_base_var_enum_flag_destructor(mca_base_var_enum_flag_t *enumerator); static OBJ_CLASS_INSTANCE(mca_base_var_enum_flag_t, opal_object_t, mca_base_var_enum_flag_constructor, mca_base_var_enum_flag_destructor); static int enum_dump(mca_base_var_enum_t *self, char **out, mca_base_var_enum_dump_type_t output_type); static int enum_get_count(mca_base_var_enum_t *self, int *count); static int enum_get_value(mca_base_var_enum_t *self, int index, int *value, const char **string_value); static int mca_base_var_enum_bool_get_count(mca_base_var_enum_t *enumerator, int *count) { *count = 2; return OPAL_SUCCESS; } static int mca_base_var_enum_bool_get_value(mca_base_var_enum_t *self, int index, int *value, const char **string_value) { if (1 < index) { return OPAL_ERR_VALUE_OUT_OF_BOUNDS; } *value = index ? 1 : 0; *string_value = index ? "true" : "false"; return OPAL_SUCCESS; } static int mca_base_var_enum_bool_vfs(mca_base_var_enum_t *self, const char *string_value, int *value) { char *tmp; long v; /* skip whitespace */ string_value += strspn(string_value, " \t\n\v\f\r"); v = strtol(string_value, &tmp, 10); if (*tmp != '\0') { if (0 == strcmp(string_value, "true") || 0 == strcmp(string_value, "t") || 0 == strcmp(string_value, "enabled") || 0 == strcmp(string_value, "yes") || 0 == strcmp(string_value, "y")) { v = 1; } else if (0 == strcmp(string_value, "false") || 0 == strcmp(string_value, "f") || 0 == strcmp(string_value, "disabled") || 0 == strcmp(string_value, "no") || 0 == strcmp(string_value, "n")) { v = 0; } else { return OPAL_ERR_VALUE_OUT_OF_BOUNDS; } } *value = !!v; return OPAL_SUCCESS; } static int mca_base_var_enum_bool_sfv(mca_base_var_enum_t *self, const int value, char **string_value) { if (string_value) { *string_value = strdup(value ? "true" : "false"); } return OPAL_SUCCESS; } static int mca_base_var_enum_bool_dump(mca_base_var_enum_t *self, char **out, mca_base_var_enum_dump_type_t output_type) { int ret; char *color_vv = "", *color_reset = ""; if (MCA_BASE_VAR_ENUM_DUMP_READABLE_COLOR == output_type) { color_vv = opal_var_dump_color[OPAL_VAR_DUMP_COLOR_VALID_VALUES]; color_reset = "\033[0m"; } ret = opal_asprintf(out, "%s0%s|%sf%s|%sfalse%s|%sdisabled%s|%sno%s|%sn%s, " "%s1%s|%st%s|%strue%s|%senabled%s|%syes%s|%sy%s", color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset); if (ret < 0) { *out = NULL; return OPAL_ERR_OUT_OF_RESOURCE; } return OPAL_SUCCESS; } mca_base_var_enum_t mca_base_var_enum_bool = {.super = OPAL_OBJ_STATIC_INIT(opal_object_t), .enum_is_static = true, .enum_name = "boolean", .get_count = mca_base_var_enum_bool_get_count, .get_value = mca_base_var_enum_bool_get_value, .value_from_string = mca_base_var_enum_bool_vfs, .string_from_value = mca_base_var_enum_bool_sfv, .dump = mca_base_var_enum_bool_dump}; static int mca_base_var_enum_auto_bool_get_count(mca_base_var_enum_t *enumerator, int *count) { *count = 3; return OPAL_SUCCESS; } static int mca_base_var_enum_auto_bool_get_value(mca_base_var_enum_t *self, int index, int *value, const char **string_value) { const int values[3] = {0, 1, -1}; const char *strings[3] = {"false", "true", "auto"}; if (2 < index) { return OPAL_ERR_VALUE_OUT_OF_BOUNDS; } *value = values[index]; *string_value = strings[index]; return OPAL_SUCCESS; } static int mca_base_var_enum_auto_bool_vfs(mca_base_var_enum_t *self, const char *string_value, int *value) { char *tmp; long v; /* skip whitespace */ string_value += strspn(string_value, " \t\n\v\f\r"); v = strtol(string_value, &tmp, 10); if (*tmp != '\0') { if (0 == strcasecmp(string_value, "true") || 0 == strcasecmp(string_value, "t") || 0 == strcasecmp(string_value, "enabled") || 0 == strcasecmp(string_value, "yes") || 0 == strcasecmp(string_value, "y")) { v = 1; } else if (0 == strcasecmp(string_value, "false") || 0 == strcasecmp(string_value, "f") || 0 == strcasecmp(string_value, "disabled") || 0 == strcasecmp(string_value, "no") || 0 == strcasecmp(string_value, "n")) { v = 0; } else if (0 == strcasecmp(string_value, "auto")) { v = -1; } else { return OPAL_ERR_VALUE_OUT_OF_BOUNDS; } } if (v > 1) { *value = 1; } else if (v < -1) { *value = -1; } else { *value = (int) v; } return OPAL_SUCCESS; } static int mca_base_var_enum_auto_bool_sfv(mca_base_var_enum_t *self, const int value, char **string_value) { if (string_value) { if (value < 0) { *string_value = strdup("auto"); } else if (value > 0) { *string_value = strdup("true"); } else { *string_value = strdup("false"); } } return OPAL_SUCCESS; } static int mca_base_var_enum_auto_bool_dump(mca_base_var_enum_t *self, char **out, mca_base_var_enum_dump_type_t output_type) { int ret; char *color_vv = "", *color_reset = ""; if (MCA_BASE_VAR_ENUM_DUMP_READABLE_COLOR == output_type) { color_vv = opal_var_dump_color[OPAL_VAR_DUMP_COLOR_VALID_VALUES]; color_reset = "\033[0m"; } ret = opal_asprintf(out, "%s-1%s|%sauto%s, " "%s0%s|%sf%s|%sfalse%s|%sdisabled%s|%sno%s|%sn%s, " "%s1%s|%st%s|%strue%s|%senabled%s|%syes%s|%sy%s", color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset, color_vv, color_reset); if (ret < 0) { *out = NULL; return OPAL_ERR_OUT_OF_RESOURCE; } return OPAL_SUCCESS; } mca_base_var_enum_t mca_base_var_enum_auto_bool = {.super = OPAL_OBJ_STATIC_INIT(opal_object_t), .enum_is_static = true, .enum_name = "auto_boolean", .get_count = mca_base_var_enum_auto_bool_get_count, .get_value = mca_base_var_enum_auto_bool_get_value, .value_from_string = mca_base_var_enum_auto_bool_vfs, .string_from_value = mca_base_var_enum_auto_bool_sfv, .dump = mca_base_var_enum_auto_bool_dump}; /* verbosity enumerator */ static mca_base_var_enum_value_t verbose_values[] = {{MCA_BASE_VERBOSE_NONE, "none"}, {MCA_BASE_VERBOSE_ERROR, "error"}, {MCA_BASE_VERBOSE_COMPONENT, "component"}, {MCA_BASE_VERBOSE_WARN, "warn"}, {MCA_BASE_VERBOSE_INFO, "info"}, {MCA_BASE_VERBOSE_TRACE, "trace"}, {MCA_BASE_VERBOSE_DEBUG, "debug"}, {MCA_BASE_VERBOSE_MAX, "max"}, {-1, NULL}}; static int mca_base_var_enum_verbose_vfs(mca_base_var_enum_t *self, const char *string_value, int *value) { char *tmp; int v; /* skip whitespace */ string_value += strspn(string_value, " \t\n\v\f\r"); v = strtol(string_value, &tmp, 10); if (*tmp != '\0') { for (int i = 0; verbose_values[i].string; ++i) { if (0 == strcmp(verbose_values[i].string, string_value)) { *value = verbose_values[i].value; return OPAL_SUCCESS; } } return OPAL_ERR_NOT_FOUND; } else if (v < MCA_BASE_VERBOSE_NONE) { v = MCA_BASE_VERBOSE_NONE; } else if (v > MCA_BASE_VERBOSE_MAX) { v = MCA_BASE_VERBOSE_MAX; } *value = v; return OPAL_SUCCESS; } static int mca_base_var_enum_verbose_sfv(mca_base_var_enum_t *self, const int value, char **string_value) { int ret; if (value < 0 || value > 100) { return OPAL_ERR_VALUE_OUT_OF_BOUNDS; } for (int i = 0; verbose_values[i].string; ++i) { if (verbose_values[i].value == value) { if (string_value) { *string_value = strdup(verbose_values[i].string); } return OPAL_SUCCESS; } } if (string_value) { ret = opal_asprintf(string_value, "%d", value); if (0 > ret) { return OPAL_ERR_OUT_OF_RESOURCE; } } return OPAL_SUCCESS; } static int mca_base_var_enum_verbose_dump(mca_base_var_enum_t *self, char **out, mca_base_var_enum_dump_type_t output_type) { char *tmp; int ret; char *color_vv = "", *color_reset = ""; ret = enum_dump(self, out, output_type); if (OPAL_SUCCESS != ret) { return ret; } if (MCA_BASE_VAR_ENUM_DUMP_READABLE_COLOR == output_type) { color_vv = opal_var_dump_color[OPAL_VAR_DUMP_COLOR_VALID_VALUES]; color_reset = "\033[0m"; } ret = opal_asprintf(&tmp, "%s, %s0%s-%s100%s", *out, color_vv, color_reset, color_vv, color_reset); free(*out); if (0 > ret) { *out = NULL; return OPAL_ERR_OUT_OF_RESOURCE; } *out = tmp; return OPAL_SUCCESS; } mca_base_var_enum_t mca_base_var_enum_verbose = { .super = OPAL_OBJ_STATIC_INIT(opal_object_t), .enum_is_static = true, .enum_name = "verbosity", .get_count = enum_get_count, .get_value = enum_get_value, .value_from_string = mca_base_var_enum_verbose_vfs, .string_from_value = mca_base_var_enum_verbose_sfv, .dump = mca_base_var_enum_verbose_dump, .enum_value_count = 8, .enum_values = verbose_values, }; int mca_base_var_enum_create(const char *name, const mca_base_var_enum_value_t *values, mca_base_var_enum_t **enumerator) { mca_base_var_enum_t *new_enum; int i; *enumerator = NULL; new_enum = OBJ_NEW(mca_base_var_enum_t); if (NULL == new_enum) { return OPAL_ERR_OUT_OF_RESOURCE; } new_enum->enum_name = strdup(name); if (NULL == new_enum->enum_name) { return OPAL_ERR_OUT_OF_RESOURCE; } for (i = 0; values[i].string; ++i) { } new_enum->enum_value_count = i; /* make a copy of the values */ new_enum->enum_values = calloc(new_enum->enum_value_count + 1, sizeof(*new_enum->enum_values)); if (NULL == new_enum->enum_values) { OBJ_RELEASE(new_enum); return OPAL_ERR_OUT_OF_RESOURCE; } for (i = 0; i < new_enum->enum_value_count; ++i) { new_enum->enum_values[i].value = values[i].value; new_enum->enum_values[i].string = strdup(values[i].string); } *enumerator = new_enum; return OPAL_SUCCESS; } int mca_base_var_enum_create_flag(const char *name, const mca_base_var_enum_value_flag_t *flags, mca_base_var_enum_flag_t **enumerator) { mca_base_var_enum_flag_t *new_enum; int i; int __opal_attribute_unused__ all_flags = 0; *enumerator = NULL; new_enum = OBJ_NEW(mca_base_var_enum_flag_t); if (NULL == new_enum) { return OPAL_ERR_OUT_OF_RESOURCE; } new_enum->super.enum_name = strdup(name); if (NULL == new_enum->super.enum_name) { OBJ_RELEASE(new_enum); return OPAL_ERR_OUT_OF_RESOURCE; } for (i = 0; flags[i].string; ++i) { } new_enum->super.enum_value_count = i; /* make a copy of the values */ new_enum->enum_flags = calloc(new_enum->super.enum_value_count + 1, sizeof(*new_enum->enum_flags)); if (NULL == new_enum->enum_flags) { OBJ_RELEASE(new_enum); return OPAL_ERR_OUT_OF_RESOURCE; } for (i = 0; i < new_enum->super.enum_value_count; ++i) { new_enum->enum_flags[i].flag = flags[i].flag; new_enum->enum_flags[i].string = strdup(flags[i].string); new_enum->enum_flags[i].conflicting_flag = flags[i].conflicting_flag; /* ensure flags are only set a single bit, doesn't conflict with itself, and * hasn't already been specified. */ assert(!(flags[i].flag & (flags[i].flag - 1))); assert(!(flags[i].flag & flags[i].conflicting_flag)); assert(!(all_flags & flags[i].flag)); assert(flags[i].flag); all_flags |= flags[i].flag; } *enumerator = new_enum; return OPAL_SUCCESS; } static int enum_dump(mca_base_var_enum_t *self, char **out, mca_base_var_enum_dump_type_t output_type) { int i; char *tmp; int ret; char *color_vv = "", *color_reset = ""; *out = NULL; if (NULL == self) { return OPAL_ERROR; } if (MCA_BASE_VAR_ENUM_DUMP_READABLE_COLOR == output_type) { color_vv = opal_var_dump_color[OPAL_VAR_DUMP_COLOR_VALID_VALUES]; color_reset = "\033[0m"; } tmp = NULL; for (i = 0; i < self->enum_value_count && self->enum_values[i].string; ++i) { ret = opal_asprintf(out, "%s%s%s%d%s|%s%s%s", tmp ? tmp : "", tmp ? ", " : "", color_vv, self->enum_values[i].value, color_reset, color_vv, self->enum_values[i].string, color_reset); if (tmp) { free(tmp); } if (0 > ret) { return OPAL_ERR_OUT_OF_RESOURCE; } tmp = *out; } return OPAL_SUCCESS; } static int enum_get_count(mca_base_var_enum_t *self, int *count) { *count = self->enum_value_count; return OPAL_SUCCESS; } static int enum_get_value(mca_base_var_enum_t *self, int index, int *value, const char **string_value) { int count, ret; ret = self->get_count(self, &count); if (OPAL_SUCCESS != ret) { return ret; } if (index >= count) { return OPAL_ERR_VALUE_OUT_OF_BOUNDS; } if (value) { *value = self->enum_values[index].value; } if (string_value) { *string_value = strdup(self->enum_values[index].string); } return OPAL_SUCCESS; } static int enum_value_from_string(mca_base_var_enum_t *self, const char *string_value, int *value_out) { int value, count, ret, i; bool is_int; char *tmp; ret = self->get_count(self, &count); if (OPAL_SUCCESS != ret) { return ret; } value = strtol(string_value, &tmp, 0); /* Check if the string is an integer */ is_int = tmp[0] == '\0'; for (i = 0; i < count; ++i) { if ((is_int && value == self->enum_values[i].value) || 0 == strcasecmp(string_value, self->enum_values[i].string)) { break; } } if (i == count) { return OPAL_ERR_VALUE_OUT_OF_BOUNDS; } *value_out = self->enum_values[i].value; return OPAL_SUCCESS; } static int enum_string_from_value(mca_base_var_enum_t *self, const int value, char **string_value) { int count, ret, i; ret = self->get_count(self, &count); if (OPAL_SUCCESS != ret) { return ret; } for (i = 0; i < count; ++i) { if (value == self->enum_values[i].value) { break; } } if (i == count) { return OPAL_ERR_VALUE_OUT_OF_BOUNDS; } if (string_value) { *string_value = strdup(self->enum_values[i].string); } return OPAL_SUCCESS; } static void mca_base_var_enum_constructor(mca_base_var_enum_t *enumerator) { memset((char *) enumerator + sizeof(enumerator->super), 0, sizeof(*enumerator) - sizeof(enumerator->super)); enumerator->get_value = enum_get_value; enumerator->get_count = enum_get_count; enumerator->value_from_string = enum_value_from_string; enumerator->string_from_value = enum_string_from_value; enumerator->dump = enum_dump; enumerator->enum_is_static = false; } static void mca_base_var_enum_destructor(mca_base_var_enum_t *enumerator) { if (enumerator->enum_name) { free(enumerator->enum_name); } /* release the copy of the values */ if (enumerator->enum_values) { for (int i = 0; i < enumerator->enum_value_count; ++i) { free((void *) enumerator->enum_values[i].string); } free(enumerator->enum_values); } } static int enum_get_value_flag(mca_base_var_enum_t *self, int index, int *value, const char **string_value) { mca_base_var_enum_flag_t *flag_enum = (mca_base_var_enum_flag_t *) self; int count, ret; ret = self->get_count(self, &count); if (OPAL_SUCCESS != ret) { return ret; } if (index >= count) { return OPAL_ERR_VALUE_OUT_OF_BOUNDS; } if (value) { *value = flag_enum->enum_flags[index].flag; } if (string_value) { *string_value = strdup(flag_enum->enum_flags[index].string); } return OPAL_SUCCESS; } static int enum_value_from_string_flag(mca_base_var_enum_t *self, const char *string_value, int *value_out) { mca_base_var_enum_flag_t *flag_enum = (mca_base_var_enum_flag_t *) self; int value, count, ret, flag; char **flags; bool is_int; char *tmp; ret = self->get_count(self, &count); if (OPAL_SUCCESS != ret) { return ret; } flags = opal_argv_split(string_value, ','); if (NULL == flags) { return OPAL_ERR_BAD_PARAM; } flag = 0; for (int i = 0; flags[i]; ++i) { value = strtol(flags[i], &tmp, 0); is_int = tmp[0] == '\0'; bool found = false, conflict = false; for (int j = 0; j < count; ++j) { if ((is_int && (value & flag_enum->enum_flags[j].flag)) || 0 == strcasecmp(flags[i], flag_enum->enum_flags[j].string)) { found = true; if (flag & flag_enum->enum_flags[j].conflicting_flag) { conflict = true; } else { flag |= flag_enum->enum_flags[j].flag; } if (is_int) { value &= ~flag_enum->enum_flags[j].flag; if (0 == value) { break; } } else { break; } } } if (!found || conflict || (is_int && value)) { opal_argv_free(flags); return !found ? OPAL_ERR_VALUE_OUT_OF_BOUNDS : OPAL_ERR_BAD_PARAM; } } opal_argv_free(flags); *value_out = flag; return OPAL_SUCCESS; } static int enum_string_from_value_flag(mca_base_var_enum_t *self, const int value, char **string_value) { mca_base_var_enum_flag_t *flag_enum = (mca_base_var_enum_flag_t *) self; int count, ret, current; char *out = NULL, *tmp; ret = self->get_count(self, &count); if (OPAL_SUCCESS != ret) { return ret; } current = value; for (int i = 0; i < count; ++i) { if (!(flag_enum->enum_flags[i].flag & current)) { continue; } tmp = out; ret = opal_asprintf(&out, "%s%s%s", tmp ? tmp : "", tmp ? "," : "", flag_enum->enum_flags[i].string); free(tmp); if (0 > ret) { return OPAL_ERR_OUT_OF_RESOURCE; } if (value & flag_enum->enum_flags[i].conflicting_flag) { free(out); return OPAL_ERR_BAD_PARAM; } current &= ~flag_enum->enum_flags[i].flag; } if (current) { free(out); return OPAL_ERR_VALUE_OUT_OF_BOUNDS; } if (string_value) { *string_value = out ? out : strdup(""); } else { free(out); } return OPAL_SUCCESS; } static int enum_dump_flag(mca_base_var_enum_t *self, char **out, mca_base_var_enum_dump_type_t output_type) { mca_base_var_enum_flag_t *flag_enum = (mca_base_var_enum_flag_t *) self; char *tmp; int ret; char *color_vv = "", *color_reset = ""; *out = NULL; if (NULL == self) { return OPAL_ERROR; } if (MCA_BASE_VAR_ENUM_DUMP_READABLE_COLOR == output_type) { color_vv = opal_var_dump_color[OPAL_VAR_DUMP_COLOR_VALID_VALUES]; color_reset = "\033[0m"; } *out = strdup("Comma-delimited list of: "); if (NULL == *out) { return OPAL_ERR_OUT_OF_RESOURCE; } for (int i = 0; i < self->enum_value_count; ++i) { tmp = *out; ret = opal_asprintf(out, "%s%s%s0x%x%s|%s%s%s", tmp, i ? ", " : " ", color_vv, flag_enum->enum_flags[i].flag, color_reset, color_vv, flag_enum->enum_flags[i].string, color_reset); free(tmp); if (0 > ret) { return OPAL_ERR_OUT_OF_RESOURCE; } } return OPAL_SUCCESS; } static void mca_base_var_enum_flag_constructor(mca_base_var_enum_flag_t *enumerator) { enumerator->enum_flags = NULL; enumerator->super.get_value = enum_get_value_flag; enumerator->super.get_count = enum_get_count; enumerator->super.value_from_string = enum_value_from_string_flag; enumerator->super.string_from_value = enum_string_from_value_flag; enumerator->super.dump = enum_dump_flag; enumerator->super.enum_is_static = false; enumerator->super.enum_name = NULL; } static void mca_base_var_enum_flag_destructor(mca_base_var_enum_flag_t *enumerator) { /* release the copy of the values */ if (enumerator->enum_flags) { for (int i = 0; i < enumerator->super.enum_value_count; ++i) { free((void *) enumerator->enum_flags[i].string); } free(enumerator->enum_flags); } if (NULL != enumerator->super.enum_name) { free(enumerator->super.enum_name); } } int mca_base_var_enum_register(const char *project_name, const char *framework_name, const char *component_name, const char *enum_name, void *storage) { int group_index; /* Developer error. Storage can not be NULL */ assert(NULL != storage); /* Create a new parameter entry */ group_index = mca_base_var_group_register(project_name, framework_name, component_name, NULL); if (-1 > group_index) { return group_index; } if (0 <= group_index) { mca_base_var_group_add_enum(group_index, storage); } return OPAL_SUCCESS; /* All done */ }