patch 9.1.1669: Vim script: no support for URI de-/encoding

Problem:  Vim script: no support for URI de-/encoding
          (ubaldot)
Solution: Add the uri_encode() and uri_decode() functions
          (Yegappan Lakshmanan)

fixes: #17861
closes: #18034

Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Yegappan Lakshmanan
2025-08-23 06:26:16 -04:00
committed by Christian Brabandt
parent da34f84847
commit 454c7ea484
9 changed files with 271 additions and 0 deletions

View File

@ -2310,6 +2310,151 @@ f_trim(typval_T *argvars, typval_T *rettv)
rettv->vval.v_string = vim_strnsave(head, tail - head);
}
/*
* Decodes a URI-encoded string.
*
* Parameters:
* str - The URI-encoded input string (may contain %XX sequences and '+').
*
* Returns:
* A newly allocated string with URI encoding decoded:
* - %XX sequences are converted to the corresponding character.
* - If the input is malformed (e.g., incomplete % sequence), the original
* characters are copied.
* The output string will never be longer than the input string.
* The caller is responsible for freeing the returned string.
*
* Returns NULL if input is NULL or memory allocation fails.
*/
static char_u *
uri_decode(char_u *str)
{
if (str == NULL)
return NULL;
size_t len = STRLEN(str);
char_u *decoded = alloc(len + 1);
if (!decoded)
return NULL;
char_u *p = decoded;
size_t i = 0;
while (i < len)
{
if (str[i] == '%')
{
if (i + 2 >= len)
{
// Malformed encoding
*p++ = str[i++];
if (str[i] != NUL)
*p++ = str[i++];
}
else
{
int val = hexhex2nr(&str[i + 1]);
if (val != -1)
{
*p++ = (char_u)val;
i += 3;
}
else
{
// invalid hex digits following "%"
for (int j = 0; j < 3; j++)
*p++ = str[i++];
}
}
}
else
*p++ = str[i++];
}
*p = NUL;
return decoded;
}
/*
* "uri_decode({str})" function
*/
void
f_uridecode(typval_T *argvars, typval_T *rettv)
{
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
if (check_for_string_arg(argvars, 0) == FAIL)
return;
rettv->vval.v_string = uri_decode(tv_get_string(&argvars[0]));
}
/*
* Encodes a string for safe use in a URI.
*
* Parameters:
* str - The input string to encode.
*
* Returns:
* A newly allocated string where:
* - Alphanumeric characters and '-', '_', '.', '~' are left unchanged.
* - All other bytes are encoded as %XX (uppercase hex).
* The caller is responsible for freeing the returned string.
*
* Returns NULL if input is NULL or memory allocation fails.
*/
static char_u *
uri_encode(char_u *str)
{
if (str == NULL)
return NULL;
size_t len = STRLEN(str);
// Worst case: every character needs encoding => 3x size + 1 for null
// terminator
char_u *encoded = alloc(len * 3 + 1);
if (encoded == NULL)
return NULL;
char_u *p = encoded;
for (size_t i = 0; i < len; ++i)
{
char_u c = str[i];
if (ASCII_ISALNUM(c) || c == '-' || c == '_' || c == '.' || c == '~')
*p++ = c;
else
{
sprintf((char *)p, "%%%02X", c);
p += 3;
}
}
*p = NUL;
return encoded;
}
/*
* "uri_encode({str})" function
*/
void
f_uriencode(typval_T *argvars, typval_T *rettv)
{
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
if (check_for_string_arg(argvars, 0) == FAIL)
return;
rettv->vval.v_string = uri_encode(tv_get_string(&argvars[0]));
}
static char *e_printf = N_(e_insufficient_arguments_for_printf);
/*