diff --git a/context.c b/context.c index bc8ebc4..8e45d75 100644 --- a/context.c +++ b/context.c @@ -36,7 +36,7 @@ engine_context *context_new() { return context; } -void context_exec(engine_context *context, char *filename) { +void context_exec(engine_context *context, char *filename, int *exit) { int ret; // Attempt to execute script file. @@ -48,9 +48,11 @@ void context_exec(engine_context *context, char *filename) { script.opened_path = NULL; script.free_filename = 0; - ret = php_execute_script(&script); + ret = zend_execute_scripts(ZEND_REQUIRE, NULL, 1, &script); + *exit = -1; } zend_catch { - errno = 1; + errno = 0; + *exit = EG(exit_status); return; } zend_end_try(); @@ -63,7 +65,7 @@ void context_exec(engine_context *context, char *filename) { return; } -void *context_eval(engine_context *context, char *script) { +void *context_eval(engine_context *context, char *script, int *exit) { zval *str = _value_init(); _value_set_string(&str, script); @@ -84,7 +86,13 @@ void *context_eval(engine_context *context, char *script) { // Attempt to execute compiled string. zval tmp; - _context_eval(op, &tmp); + _context_eval(op, &tmp, exit); + + // Script called exit() + if (*exit != -1) { + errno = 0; + return NULL; + } // Allocate result value and copy temporary execution result in. zval *result = malloc(sizeof(zval)); diff --git a/context.go b/context.go index ca51427..a167679 100644 --- a/context.go +++ b/context.go @@ -34,6 +34,14 @@ type Context struct { values []*Value } +type ExitError struct { + Status int +} + +func (e *ExitError) Error() string { + return fmt.Sprintf("Exitcode %d", e.Status) +} + // Bind allows for binding Go values into the current execution context under // a certain name. Bind returns an error if attempting to bind an invalid value // (check the documentation for NewValue for what is considered to be a "valid" @@ -59,12 +67,18 @@ func (c *Context) Bind(name string, val interface{}) error { func (c *Context) Exec(filename string) error { f := C.CString(filename) defer C.free(unsafe.Pointer(f)) + var e C.int - _, err := C.context_exec(c.context, f) + _, err := C.context_exec(c.context, f, &e) if err != nil { return fmt.Errorf("Error executing script '%s' in context", filename) } + code := int(e) + if code != -1 { + return &ExitError{code} + } + return nil } @@ -74,12 +88,18 @@ func (c *Context) Exec(filename string) error { func (c *Context) Eval(script string) (*Value, error) { s := C.CString(script) defer C.free(unsafe.Pointer(s)) + var e C.int - result, err := C.context_eval(c.context, s) + result, err := C.context_eval(c.context, s, &e) if err != nil { return nil, fmt.Errorf("Error executing script '%s' in context", script) } + code := int(e) + if code != -1 { + return nil, &ExitError{code} + } + defer C.free(result) val, err := NewValueFromPtr(result) diff --git a/context_test.go b/context_test.go index a2948da..5024216 100644 --- a/context_test.go +++ b/context_test.go @@ -283,6 +283,75 @@ func TestContextBind(t *testing.T) { c.Destroy() } +var exitTests = []struct { + code int + script string +}{ + { + 0, + "exit(0);", + }, + { + 1, + "exit(1);", + }, + { + 255, + "exit(255);", + }, + { + 255, + "trigger_error('test', E_USER_ERROR);", + }, +} + +func TestContextExecExit(t *testing.T) { + c, _ := e.NewContext() + + for _, tt := range exitTests { + script, err := NewScript("exit", "