summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--README.md8
-rw-r--r--lib.c54
-rw-r--r--types.h1
-rw-r--r--vm.c8
4 files changed, 64 insertions, 7 deletions
diff --git a/README.md b/README.md
index 549459e..83bfc07 100644
--- a/README.md
+++ b/README.md
@@ -998,7 +998,7 @@ json('{"a":true, "b":123}') // { "a": true, "b": 123 }
json('[1,2,') // Throws exception
```
-#### 6.50. `include(path, scope)`
+#### 6.50. `include(path[, scope])`
Evaluate and include the file at the given path and optionally override the
execution scope with the given scope object.
@@ -1113,3 +1113,9 @@ an invalid value was passed, otherwise `true`.
Raise an exception with the given `message` parameter if the value in `cond`
is not truish. When `message` is omitted, the default value is `Assertion failed`.
+
+#### 6.57. `render(path[, scope])`
+
+Like `include()` but capture output of included file as string and return it.
+
+See `include()` for details on scoping.
diff --git a/lib.c b/lib.c
index c1583f9..453f976 100644
--- a/lib.c
+++ b/lib.c
@@ -292,7 +292,7 @@ uc_print_common(uc_vm *vm, size_t nargs, FILE *fh)
static uc_value_t *
uc_print(uc_vm *vm, size_t nargs)
{
- return uc_print_common(vm, nargs, stdout);
+ return uc_print_common(vm, nargs, vm->output);
}
static uc_value_t *
@@ -1495,7 +1495,7 @@ uc_printf(uc_vm *vm, size_t nargs)
uc_printf_common(vm, nargs, buf);
- len = fwrite(buf->buf, 1, printbuf_length(buf), stdout);
+ len = fwrite(buf->buf, 1, printbuf_length(buf), vm->output);
printbuf_free(buf);
@@ -2199,6 +2199,53 @@ uc_include(uc_vm *vm, size_t nargs)
}
static uc_value_t *
+uc_render(uc_vm *vm, size_t nargs)
+{
+ uc_string_t *ustr = NULL;
+ FILE *mem, *prev;
+ size_t len = 0;
+
+ mem = open_memstream((char **)&ustr, &len);
+
+ if (!mem)
+ goto out;
+
+ /* reserve space for uc_string_t header... */
+ if (fseek(mem, sizeof(*ustr), SEEK_SET))
+ goto out;
+
+ /* divert VM output to memory fd */
+ prev = vm->output;
+ vm->output = mem;
+
+ /* execute include */
+ (void) uc_include(vm, nargs);
+
+ /* restore previous VM output */
+ vm->output = prev;
+ fclose(mem);
+
+ /* update uc_string_t length */
+ ustr->header.type = UC_STRING;
+ ustr->header.refcount = 1;
+ ustr->length = len - sizeof(*ustr);
+
+ return &ustr->header;
+
+out:
+ uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
+ "Unable to initialize output memory: %s",
+ strerror(errno));
+
+ if (mem)
+ fclose(mem);
+
+ free(ustr);
+
+ return NULL;
+}
+
+static uc_value_t *
uc_warn(uc_vm *vm, size_t nargs)
{
return uc_print_common(vm, nargs, stderr);
@@ -2473,7 +2520,8 @@ static const uc_cfunction_list functions[] = {
{ "trace", uc_trace },
{ "proto", uc_proto },
{ "sleep", uc_sleep },
- { "assert", uc_assert }
+ { "assert", uc_assert },
+ { "render", uc_render }
};
diff --git a/types.h b/types.h
index 518248b..3aaf8bc 100644
--- a/types.h
+++ b/types.h
@@ -259,6 +259,7 @@ struct uc_vm {
size_t spread_values;
uint8_t trace;
uc_stringbuf_t *strbuf;
+ FILE *output;
};
diff --git a/vm.c b/vm.c
index 25b146a..5b7b5e8 100644
--- a/vm.c
+++ b/vm.c
@@ -118,6 +118,8 @@ void uc_vm_init(uc_vm *vm, uc_parse_config *config)
vm->strbuf = NULL;
+ vm->output = stdout;
+
uc_vm_reset_stack(vm);
}
@@ -1896,12 +1898,12 @@ uc_vm_insn_print(uc_vm *vm, enum insn_type insn)
case UC_OBJECT:
case UC_ARRAY:
p = ucv_to_jsonstring(vm, v);
- fwrite(p, 1, strlen(p), stdout);
+ fwrite(p, 1, strlen(p), vm->output);
free(p);
break;
case UC_STRING:
- fwrite(ucv_string_get(v), 1, ucv_string_length(v), stdout);
+ fwrite(ucv_string_get(v), 1, ucv_string_length(v), vm->output);
break;
case UC_NULL:
@@ -1909,7 +1911,7 @@ uc_vm_insn_print(uc_vm *vm, enum insn_type insn)
default:
p = ucv_to_string(vm, v);
- fwrite(p, 1, strlen(p), stdout);
+ fwrite(p, 1, strlen(p), vm->output);
free(p);
}