summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2021-06-04 10:04:26 +0200
committerJo-Philipp Wich <jo@mein.io>2021-06-04 10:13:02 +0200
commit42de7ab196a0cc82c1a40adffcea7b481a09e11c (patch)
tree539d03364364301620f6137d3cb0f335d8858e9f
parent05c80a78a3cc1371bd04575de01128b0a4bd16b0 (diff)
lib: implement `sourcepath()` function
The sourcepath() function allows querying the filesystem path of the source file currently being executed by ucode. The optional depth argument can be used to walk up the include stack to determine the path of the file that included the current file, the path of the parent file of the parent file and so on. By specifying a truish value as second argument, only the directory portion of the source file path is returned. This is useful to e.g. discover ressources relative to the current source file directory. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r--README.md19
-rw-r--r--lib.c46
2 files changed, 64 insertions, 1 deletions
diff --git a/README.md b/README.md
index fc3c1da..929d261 100644
--- a/README.md
+++ b/README.md
@@ -1173,3 +1173,22 @@ performed. If a non-string value is supplied as subject, it is converted into
a string before being matched.
Returns `true` when the subject matches the pattern or `false` when not.
+
+#### 6.59. `sourcepath([depth [, dironly]])`
+
+Determine the path of the source file currently being executed by ucode.
+
+The optional `depth` parameter allows walking up the call stack to determine
+the path of the parent sources including or requiring the current source file.
+If unspecified, the `depth` defaults to `0`, that is the currently executed
+file.
+
+If a truish value is passed in `dironly`, only the directory portion of the
+source file path is returned.
+
+If the ucode interpreter executes code from stdin or a code fragment passed
+via `-s` switch, the function returns `null` since there is no associated
+file path.
+
+If `depth` exceeds the size of the call stack, the function returns `null`
+as well.
diff --git a/lib.c b/lib.c
index f0f934d..89fb4d0 100644
--- a/lib.c
+++ b/lib.c
@@ -2523,6 +2523,49 @@ uc_wildcard(uc_vm *vm, size_t nargs)
return ucv_boolean_new(rv == 0);
}
+static uc_value_t *
+uc_sourcepath(uc_vm *vm, size_t nargs)
+{
+ uc_value_t *calldepth = uc_get_arg(0);
+ uc_value_t *dironly = uc_get_arg(1);
+ uc_value_t *rv = NULL;
+ uc_callframe *frame;
+ char *path = NULL;
+ int64_t depth;
+ size_t i;
+
+ depth = uc_cast_int64(calldepth);
+
+ if (errno)
+ depth = 0;
+
+ for (i = vm->callframes.count; i > 0; i--) {
+ frame = &vm->callframes.entries[i - 1];
+
+ if (!frame->closure)
+ continue;
+
+ if (depth > 0) {
+ depth--;
+ continue;
+ }
+
+ path = realpath(frame->closure->function->source->filename, NULL);
+ break;
+ }
+
+ if (path) {
+ if (uc_val_is_truish(dironly))
+ rv = ucv_string_new(dirname(path));
+ else
+ rv = ucv_string_new(path);
+
+ free(path);
+ }
+
+ return rv;
+}
+
static const uc_cfunction_list functions[] = {
{ "chr", uc_chr },
{ "die", uc_die },
@@ -2575,7 +2618,8 @@ static const uc_cfunction_list functions[] = {
{ "assert", uc_assert },
{ "render", uc_render },
{ "regexp", uc_regexp },
- { "wildcard", uc_wildcard }
+ { "wildcard", uc_wildcard },
+ { "sourcepath", uc_sourcepath }
};