diff --git a/cmd/nvedit.c b/cmd/nvedit.c index 4033d90c8e..060e38dbb0 100644 --- a/cmd/nvedit.c +++ b/cmd/nvedit.c @@ -297,6 +297,222 @@ int env_set(const char *varname, const char *varvalue) return _do_env_set(0, 3, (char * const *)argv, H_PROGRAMMATIC); } +static int env_append(const char *varname, const char *varvalue) +{ + int len = 0; + char *oldvalue, *newvalue; + + /* before import into hashtable */ + if (!(gd->flags & GD_FLG_ENV_READY) || !varname) + return 1; + + if (varvalue) + len += strlen(varvalue); + + oldvalue = env_get(varname); + if (oldvalue) { + len += strlen(oldvalue); + /* Exist ! */ + if (strstr(oldvalue, varvalue)) + return 0; + } + + newvalue = malloc(len + 2); + if (!newvalue) { + printf("Error: malloc in %s failed!\n", __func__); + return 1; + } + + *newvalue = '\0'; + + if (oldvalue) { + strcpy(newvalue, oldvalue); + strcat(newvalue, " "); + } + + if (varvalue) + strcat(newvalue, varvalue); + + env_set(varname, newvalue); + free(newvalue); + + return 0; +} + +static int env_replace(const char *varname, const char *substr, + const char *replacement) +{ + char *oldvalue, *newvalue, *dst, *sub; + int substr_len, replace_len, oldvalue_len, len; + + /* before import into hashtable */ + if (!(gd->flags & GD_FLG_ENV_READY) || !varname) + return 1; + + oldvalue = env_get(varname); + if (!oldvalue) + return 1; + + sub = strstr(oldvalue, substr); + if (!sub) + return 1; + + oldvalue_len = strlen(oldvalue) + 1; + substr_len = strlen(substr); + replace_len = strlen(replacement); + + if (replace_len >= substr_len) + len = oldvalue_len + replace_len - substr_len; + else + len = oldvalue_len + substr_len - replace_len; + + newvalue = malloc(len); + if (!newvalue) { + printf("Error: malloc in %s failed!\n", __func__); + return 1; + } + + *newvalue = '\0'; + + /* + * Orignal string is splited like format: [str1.. substr str2..] + */ + + /* str1.. */ + dst = newvalue; + dst = strncat(dst, oldvalue, sub - oldvalue); + + /* substr */ + dst += sub - oldvalue; + dst = strncat(dst, replacement, replace_len); + + /* str2.. */ + dst += replace_len; + len = oldvalue_len - substr_len - (sub - oldvalue); + dst = strncat(dst, sub + substr_len, len); + + env_set(varname, newvalue); + free(newvalue); + + return 0; +} + +#define ARGS_ITEM_NUM 50 + +int env_update(const char *varname, char *varvalue) +{ + /* 'a_' means "varargs_'; 'v_' means 'varvalue_' */ + char *varargs; + char *a_title, *v_title; + char *a_string_tok, *a_item_tok = NULL; + char *v_string_tok, *v_item_tok = NULL; + char *a_item, *a_items[ARGS_ITEM_NUM] = { NULL }; + char *v_item, *v_items[ARGS_ITEM_NUM] = { NULL }; + bool match = false; + int i = 0, j = 0; + + /* Before import into hashtable */ + if (!(gd->flags & GD_FLG_ENV_READY) || !varname) + return 1; + + /* If varname doesn't exist, create it and set varvalue */ + varargs = env_get(varname); + if (!varargs) { + env_set(varname, varvalue); + return 0; + } + + /* Malloc a temporary varargs for strtok */ + a_string_tok = strdup(varargs); + if (!a_string_tok) { + printf("Error: strdup in failed, line=%d\n", __LINE__); + return 1; + } + + /* Malloc a temporary varvalue for strtok */ + v_string_tok = strdup(varvalue); + if (!v_string_tok) { + free(a_string_tok); + printf("Error: strdup in failed, line=%d\n", __LINE__); + return 1; + } + + /* Splite varargs into items containing "=" by the blank */ + a_item = strtok(a_string_tok, " "); + while (a_item && i < ARGS_ITEM_NUM) { + debug("%s: [a_item %d]: %s\n", __func__, i, a_item); + if (strstr(a_item, "=")) + a_items[i++] = a_item; + a_item = strtok(NULL, " "); + } + + /* + * Splite varvalue into items containing "=" by the blank. + * parse varvalue title, eg: "bootmode=emmc", title is "bootmode" + */ + v_item = strtok(v_string_tok, " "); + while (v_item && j < ARGS_ITEM_NUM) { + debug("%s: : %s\n", __func__, j, v_item); + if (strstr(v_item, "=")) + v_items[j++] = v_item; + else + env_append(varname, v_item); + v_item = strtok(NULL, " "); + } + + /* For every v_item, search its title */ + for (j = 0; j < ARGS_ITEM_NUM && v_items[j]; j++) { + v_item = v_items[j]; + /* Malloc a temporary a_item for strtok */ + v_item_tok = strdup(v_item); + if (!v_item_tok) { + printf("Error: strdup in failed, line=%d\n", __LINE__); + free(a_string_tok); + free(v_string_tok); + return 1; + } + v_title = strtok(v_item_tok, "="); + debug("%s: : %s\n", __func__, v_title); + + /* For every a_item, search its title */ + for (i = 0; i < ARGS_ITEM_NUM && a_items[i]; i++) { + a_item = a_items[i]; + /* Malloc a temporary a_item for strtok */ + a_item_tok = strdup(a_item); + if (!a_item_tok) { + printf("Error: strdup in failed, line=%d\n", __LINE__); + free(a_string_tok); + free(v_string_tok); + free(v_item_tok); + return 1; + } + + a_title = strtok(a_item_tok, "="); + debug("%s: [a_title]: %s\n", __func__, a_title); + if (!strcmp(a_title, v_title)) { + /* Find! replace it */ + env_replace(varname, a_item, v_item); + free(a_item_tok); + match = true; + break; + } + free(a_item_tok); + } + + /* Not find, just append */ + if (!match) + env_append(varname, v_item); + + match = false; + free(v_item_tok); + } + + free(v_string_tok); + free(a_string_tok); + + return 0; +} + /** * Set an environment variable to an integer value * diff --git a/include/common.h b/include/common.h index aaed131671..0f386e9db2 100644 --- a/include/common.h +++ b/include/common.h @@ -378,6 +378,17 @@ int env_get_yesno(const char *var); */ int env_set(const char *varname, const char *value); +/** + * env_update() - update sub value of an environment variable + * + * This add/append/replace the sub value of an environment variable. + * + * @varname: Variable to adjust + * @valude: Value to append/replace + * @return 0 if OK, 1 on error + */ +int env_update(const char *varname, char *varvalue); + /** * env_set_ulong() - set an environment variable to an integer *