diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/wee-string.c | 83 |
1 files changed, 62 insertions, 21 deletions
diff --git a/src/core/wee-string.c b/src/core/wee-string.c index e8f9ed589..7dfcd3219 100644 --- a/src/core/wee-string.c +++ b/src/core/wee-string.c @@ -2578,9 +2578,11 @@ string_input_for_buffer (const char *string) } /* - * Replaces ${codes} using a callback that returns replacement value (this value + * Replaces ${vars} using a callback that returns replacement value (this value * must be newly allocated because it will be freed in this function). * + * Nested variables are supported, for example: "${var1:${var2}}". + * * Argument "errors" is set with number of keys not found by callback. * * Note: result must be freed after use. @@ -2595,8 +2597,8 @@ string_replace_with_callback (const char *string, int *errors) { int length_prefix, length_suffix, length, length_value, index_string; - int index_result; - char *result, *result2, *key, *value; + int index_result, sub_count, sub_level, sub_errors; + char *result, *result2, *key, *key2, *value; const char *pos_end_name; *errors = 0; @@ -2623,43 +2625,82 @@ string_replace_with_callback (const char *string, } else if (strncmp (string + index_string, prefix, length_prefix) == 0) { - pos_end_name = strstr (string + index_string + length_prefix, suffix); - if (pos_end_name) + sub_count = 0; + sub_level = 0; + pos_end_name = string + index_string + length_prefix; + while (pos_end_name[0]) { - key = string_strndup (string + index_string + length_prefix, - pos_end_name - (string + index_string + length_prefix)); - if (key) + if (strncmp (pos_end_name, suffix, length_suffix) == 0) + { + if (sub_level == 0) + break; + sub_level--; + } + if ((pos_end_name[0] == '\\') + && (pos_end_name[1] == prefix[0])) + { + pos_end_name++; + } + else if (strncmp (pos_end_name, prefix, length_prefix) == 0) + { + sub_count++; + sub_level++; + } + pos_end_name++; + } + /* prefix without matching suffix => error! */ + if (!pos_end_name[0]) + { + result[index_result] = '\0'; + (*errors)++; + return result; + } + key = string_strndup (string + index_string + length_prefix, + pos_end_name - (string + index_string + length_prefix)); + if (key) + { + if (sub_count > 0) + { + sub_errors = 0; + key2 = string_replace_with_callback (key, prefix, + suffix, callback, + callback_data, + &sub_errors); + (*errors) += sub_errors; + free (key); + key = key2; + } + value = (*callback) (callback_data, (key) ? key : ""); + if (value) { - value = (*callback) (callback_data, key); - if (value) + length_value = strlen (value); + if (length_value > 0) { - length_value = strlen (value); length += length_value; result2 = realloc (result, length); if (!result2) { if (result) free (result); - free (key); + if (key) + free (key); free (value); return NULL; } result = result2; strcpy (result + index_result, value); index_result += length_value; - index_string += pos_end_name - string - - index_string + length_suffix; - free (value); - } - else - { - result[index_result++] = string[index_string++]; - (*errors)++; } - free (key); + index_string = pos_end_name - string + length_suffix; + free (value); } else + { result[index_result++] = string[index_string++]; + (*errors)++; + } + if (key) + free (key); } else result[index_result++] = string[index_string++]; |