Skip to content

Commit

Permalink
lib: improve getenv() and split() implementations
Browse files Browse the repository at this point in the history
 - getenv(): Allow querying the entire environment by omiting variable name
 - split(): Properly handle null bytes in subject and separator strings

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
  • Loading branch information
jow- committed Aug 29, 2022
1 parent bcdd2cb commit 89452b2
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 17 deletions.
5 changes: 3 additions & 2 deletions README.md
Expand Up @@ -736,9 +736,10 @@ a = filter(["foo", 1, true, null, 2.2], function(v) {
// a = [1, 2.2]
```

#### 6.10. `getenv(name)`
#### 6.10. `getenv([name])`

Return the value of the given environment variable.
Return the value of the given environment variable. If the variable name is
omitted, returns a dictionary containing all environment variables.

#### 6.11. `hex(x)`

Expand Down
67 changes: 54 additions & 13 deletions lib.c
Expand Up @@ -560,11 +560,34 @@ uc_exit(uc_vm_t *vm, size_t nargs)
static uc_value_t *
uc_getenv(uc_vm_t *vm, size_t nargs)
{
uc_value_t *key = uc_fn_arg(0);
char *k = ucv_string_get(key);
char *val = k ? getenv(k) : NULL;
uc_value_t *key = uc_fn_arg(0), *rv = NULL;
extern char **environ;
char *k, *v;

return val ? ucv_string_new(val) : NULL;
if (!key) {
rv = ucv_object_new(vm);

while (*environ) {
v = strchr(*environ, '=');

if (v) {
xasprintf(&k, "%.*s", (int)(v - *environ), *environ);
ucv_object_add(rv, k, ucv_string_new(v + 1));
free(k);
}

environ++;
}
}
else if (ucv_type(key) == UC_STRING) {
k = ucv_string_get(key);
v = getenv(k);

if (v)
rv = ucv_string_new(v);
}

return rv;
}

static uc_value_t *
Expand Down Expand Up @@ -1002,16 +1025,17 @@ uc_split(uc_vm_t *vm, size_t nargs)
uc_value_t *sep = uc_fn_arg(1);
uc_value_t *arr = NULL;
const char *p, *sepstr, *splitstr;
size_t seplen, splitlen;
int eflags = 0, res;
regmatch_t pmatch;
uc_regexp_t *re;
size_t seplen;

if (!sep || ucv_type(str) != UC_STRING)
return NULL;

arr = ucv_array_new(vm);
splitstr = ucv_string_get(str);
splitlen = ucv_string_length(str);
p = splitstr = ucv_string_get(str);

if (ucv_type(sep) == UC_REGEXP) {
re = (uc_regexp_t *)sep;
Expand Down Expand Up @@ -1041,18 +1065,35 @@ uc_split(uc_vm_t *vm, size_t nargs)
}
else if (ucv_type(sep) == UC_STRING) {
sepstr = ucv_string_get(sep);
seplen = ucv_string_length(sep);

for (p = splitstr, seplen = strlen(sepstr); *p; p++) {
if (!strncmp(p, sepstr, seplen)) {
if (*sepstr || p > splitstr)
ucv_array_push(arr, ucv_string_new_length(splitstr, p - splitstr));
if (splitlen == 0) {
ucv_array_push(arr, ucv_string_new_length("", 0));
}
else if (seplen == 0) {
while (splitlen > 0) {
ucv_array_push(arr, ucv_string_new_length(p, 1));

splitstr = p + seplen;
p = splitstr - (*sepstr ? 1 : 0);
splitlen--;
p++;
}
}
else {
while (splitlen >= seplen) {
if (!memcmp(p, sepstr, seplen)) {
ucv_array_push(arr, ucv_string_new_length(splitstr, p - splitstr));

ucv_array_push(arr, ucv_string_new_length(splitstr, p - splitstr));
p = splitstr = p + seplen;
splitlen -= seplen;
continue;
}

splitlen--;
p++;
}

ucv_array_push(arr, ucv_string_new_length(splitstr, p - splitstr + splitlen));
}
}
else {
ucv_put(arr);
Expand Down
7 changes: 5 additions & 2 deletions tests/custom/03_stdlib/05_getenv
Expand Up @@ -2,14 +2,17 @@ The `getenv()` function returns the value of the given environment variable
or `null` if either the given variable does not exist or if the given name
argument is not a string.

If the variable name argument is omitted, getenv() returns a dictionary
containing all environment variables.

-- Testcase --
{%
printf("%.J\n", [
getenv("TEST_VARIABLE"),
getenv("EMPTY_VARIABLE"),
getenv("THIS_LIKELY_DOES_NOT_EXIST"),
getenv(123),
getenv(null)
type(getenv())
]);
%}
-- End --
Expand All @@ -25,6 +28,6 @@ EMPTY_VARIABLE=
"",
null,
null,
null
"object"
]
-- End --
4 changes: 4 additions & 0 deletions tests/custom/03_stdlib/18_split
Expand Up @@ -40,6 +40,9 @@ argument is neither a string nor a regular expression.
// leading and trailing empty substrings are retained
split("|abc|def|", "|"),
split(",foo;bar:", /[,;:]/),

// subject and split strings handle embedded \0
split("foo=1\0bar=2\0baz=3", "\0"),
]), "\n");
%}
-- End --
Expand All @@ -58,6 +61,7 @@ argument is neither a string nor a regular expression.
[ "foo", "bar", "", "baz" ]
[ "", "abc", "def", "" ]
[ "", "foo", "bar", "" ]
[ "foo=1", "bar=2", "baz=3" ]
-- End --


Expand Down

0 comments on commit 89452b2

Please sign in to comment.