diff --git a/.tests/bind.php b/.test/bind.php similarity index 100% rename from .tests/bind.php rename to .test/bind.php diff --git a/.tests/echo.php b/.test/echo.php similarity index 100% rename from .tests/echo.php rename to .test/echo.php diff --git a/context.h b/context.h deleted file mode 100644 index 9c057d4..0000000 --- a/context.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef CONTEXT_H -#define CONTEXT_H - -typedef struct _engine_context { - php_engine *engine; // Parent engine instance. - void *parent; // Pointer to parent Go context, used for passing to callbacks. -} engine_context; - -engine_context *context_new(php_engine *engine, void *parent); -void context_exec(engine_context *context, char *filename); -void context_bind(engine_context *context, char *name, void *zvalptr); -int context_write(engine_context *context, const char *message, unsigned int length); -void context_destroy(engine_context *context); - -#endif \ No newline at end of file diff --git a/context.c b/context/context.c similarity index 64% rename from context.c rename to context/context.c index 80b13ab..d7d6b02 100644 --- a/context.c +++ b/context/context.c @@ -4,26 +4,24 @@ #include
#include
-#include "engine.h" #include "context.h" -#include "_cgo_export.h" -engine_context *context_new(php_engine *engine, void *parent) { +engine_context *context_new(void *parent) { engine_context *context; - #ifdef ZTS - void ***tsrm_ls = engine->tsrm_ls; - #endif - // Initialize context. context = (engine_context *) malloc((sizeof(engine_context))); if (context == NULL) { - return_multi(NULL, 1); + errno = 1; + return NULL; } - context->engine = engine; - context->parent = parent; + #ifdef ZTS + TSRM_FETCH() + context->ptsrm_ls = &tsrm_ls; + #endif + context->parent = parent; SG(server_context) = (void *) context; // Initialize request lifecycle. @@ -31,15 +29,17 @@ engine_context *context_new(php_engine *engine, void *parent) { SG(server_context) = NULL; free(context); - return_multi(NULL, 1); + errno = 1; + return NULL; } - return_multi(context, 0); + errno = 0; + return context; } void context_exec(engine_context *context, char *filename) { #ifdef ZTS - void ***tsrm_ls = context->engine->tsrm_ls; + void ***tsrm_ls = *context->ptsrm_ls; #endif // Attempt to execute script file. @@ -54,27 +54,21 @@ void context_exec(engine_context *context, char *filename) { php_execute_script(&script TSRMLS_CC); } zend_end_try(); - return_multi(NULL, 0); + errno = 0; + return NULL; } void context_bind(engine_context *context, char *name, void *zvalptr) { zval *value = (zval *) zvalptr; #ifdef ZTS - void ***tsrm_ls = context->engine->tsrm_ls; + void ***tsrm_ls = *context->ptsrm_ls; #endif ZEND_SET_SYMBOL(EG(active_symbol_table), name, value); - return_multi(NULL, 0); -} -int context_write(engine_context *context, const char *message, unsigned int length) { - int written = contextWrite(context->parent, (void *) message, length); - if (written != length) { - php_handle_aborted_connection(); - } - - return written; + errno = 0; + return NULL; } void context_destroy(engine_context *context) { diff --git a/context.go b/context/context.go similarity index 52% rename from context.go rename to context/context.go index ae87c3b..e33dd3e 100644 --- a/context.go +++ b/context/context.go @@ -1,7 +1,10 @@ -package php +package context +// #cgo CFLAGS: -I/usr/include/php -I/usr/include/php/main -I/usr/include/php/TSRM +// #cgo CFLAGS: -I/usr/include/php/Zend +// #cgo LDFLAGS: -lphp5 +// // #include -// #include "engine.h" // #include "context.h" import "C" @@ -9,16 +12,18 @@ import ( "fmt" "io" "unsafe" + + "github.com/deuill/go-php/value" ) type Context struct { context *C.struct__engine_context writer io.Writer - values map[string]*Value + values map[string]*value.Value } -func (c *Context) Bind(name string, value interface{}) error { - v, err := NewValue(value) +func (c *Context) Bind(name string, val interface{}) error { + v, err := value.New(val) if err != nil { return err } @@ -28,7 +33,7 @@ func (c *Context) Bind(name string, value interface{}) error { if _, err = C.context_bind(c.context, n, v.Ptr()); err != nil { v.Destroy() - return fmt.Errorf("Binding value '%v' to context failed", value) + return fmt.Errorf("Binding value '%v' to context failed", val) } c.values[name] = v @@ -48,6 +53,10 @@ func (c *Context) Exec(filename string) error { return nil } +func (c *Context) Write(p []byte) (int, error) { + return c.writer.Write(p) +} + func (c *Context) Destroy() { for _, v := range c.values { v.Destroy() @@ -57,14 +66,15 @@ func (c *Context) Destroy() { c = nil } -//export contextWrite -func contextWrite(ctxptr unsafe.Pointer, buffer unsafe.Pointer, length C.uint) C.int { - context := (*Context)(ctxptr) +func New(w io.Writer) (*Context, error) { + ctx := &Context{writer: w, values: make(map[string]*value.Value)} - written, err := context.writer.Write(C.GoBytes(buffer, C.int(length))) + ptr, err := C.context_new(unsafe.Pointer(ctx)) if err != nil { - return C.int(-1) + return nil, fmt.Errorf("Failed to initialize context for PHP engine") } - return C.int(written) + ctx.context = ptr + + return ctx, nil } diff --git a/context/context.h b/context/context.h new file mode 100644 index 0000000..6553d2f --- /dev/null +++ b/context/context.h @@ -0,0 +1,17 @@ +#ifndef CONTEXT_H +#define CONTEXT_H + +typedef struct _engine_context { + #ifdef ZTS + void *ptsrm_ls; // Pointer to TSRM local storage. + #endif + + void *parent; // Pointer to parent Go context, used for passing to callbacks. +} engine_context; + +engine_context *context_new(void *parent); +void context_exec(engine_context *context, char *filename); +void context_bind(engine_context *context, char *name, void *zvalptr); +void context_destroy(engine_context *context); + +#endif \ No newline at end of file diff --git a/context_test.go b/context/context_test.go similarity index 90% rename from context_test.go rename to context/context_test.go index 35f7964..adbe74d 100644 --- a/context_test.go +++ b/context/context_test.go @@ -1,10 +1,12 @@ -package php +package context_test import ( "os" "path" "strconv" "testing" + + php "github.com/deuill/go-php" ) var testDir string @@ -59,8 +61,8 @@ func (m *MockWriter) Reset() { func TestContextExec(t *testing.T) { var w MockWriter - e, _ := New() - ctx, _ := e.NewContext(&w) + e, _ := php.New() + ctx, _ := php.NewContext(&w) defer e.Destroy() defer ctx.Destroy() @@ -83,8 +85,8 @@ func TestContextExec(t *testing.T) { func TestContextBind(t *testing.T) { var w MockWriter - e, _ := New() - ctx, _ := e.NewContext(&w) + e, _ := php.New() + ctx, _ := php.NewContext(&w) defer e.Destroy() defer ctx.Destroy() @@ -107,5 +109,5 @@ func TestContextBind(t *testing.T) { func init() { wd, _ := os.Getwd() - testDir = path.Join(wd, ".tests") + testDir = path.Join(wd, "..", ".test") } diff --git a/engine.c b/engine/engine.c similarity index 92% rename from engine.c rename to engine/engine.c index ffcc709..11f6aa1 100644 --- a/engine.c +++ b/engine/engine.c @@ -7,8 +7,9 @@ #include
#include -#include "engine.h" #include "context.h" +#include "engine.h" +#include "_cgo_export.h" const char engine_ini_defaults[] = "html_errors = 0\n" @@ -21,7 +22,13 @@ const char engine_ini_defaults[] = static int engine_ub_write(const char *str, uint str_length TSRMLS_DC) { engine_context *context = (engine_context *) SG(server_context); - return context_write(context, str, str_length); + + int written = uwrite(context->parent, (void *) str, str_length); + if (written != str_length) { + php_handle_aborted_connection(); + } + + return written; } static void engine_send_header(sapi_header_struct *sapi_header, void *server_context TSRMLS_DC) { @@ -99,7 +106,8 @@ php_engine *engine_init(void) { tsrm_shutdown(); #endif - return_multi(NULL, 1); + errno = 1; + return NULL; } engine = (php_engine *) malloc((sizeof(php_engine))); @@ -108,7 +116,8 @@ php_engine *engine_init(void) { engine->tsrm_ls = tsrm_ls; #endif - return_multi(engine, 0); + errno = 0; + return engine; } void engine_shutdown(php_engine *engine) { diff --git a/engine.go b/engine/engine.go similarity index 56% rename from engine.go rename to engine/engine.go index fd3e7c6..84b1436 100644 --- a/engine.go +++ b/engine/engine.go @@ -1,36 +1,24 @@ -package php +package engine // #cgo CFLAGS: -I/usr/include/php -I/usr/include/php/main -I/usr/include/php/TSRM -// #cgo CFLAGS: -I/usr/include/php/Zend -// #cgo LDFLAGS: -lphp5 +// #cgo CFLAGS: -I/usr/include/php/Zend -I../context +// #cgo LDFLAGS: -L${SRCDIR}/context -lphp5 // -// #include "engine.h" // #include "context.h" +// #include "engine.h" import "C" import ( "fmt" - "io" "unsafe" + + "github.com/deuill/go-php/context" ) type Engine struct { engine *C.struct__php_engine } -func (e *Engine) NewContext(w io.Writer) (*Context, error) { - ctx := &Context{writer: w, values: make(map[string]*Value)} - - ptr, err := C.context_new(e.engine, unsafe.Pointer(ctx)) - if err != nil { - return nil, fmt.Errorf("Failed to initialize context for PHP engine") - } - - ctx.context = ptr - - return ctx, nil -} - func (e *Engine) Destroy() { C.engine_shutdown(e.engine) e = nil @@ -44,3 +32,15 @@ func New() (*Engine, error) { return &Engine{engine: ptr}, nil } + +//export uwrite +func uwrite(ctxptr unsafe.Pointer, buffer unsafe.Pointer, length C.uint) C.int { + context := (*context.Context)(ctxptr) + + written, err := context.Write(C.GoBytes(buffer, C.int(length))) + if err != nil { + return C.int(-1) + } + + return C.int(written) +} diff --git a/engine.h b/engine/engine.h similarity index 79% rename from engine.h rename to engine/engine.h index 3d3dcc2..6be7602 100644 --- a/engine.h +++ b/engine/engine.h @@ -1,8 +1,6 @@ #ifndef ENGINE_H #define ENGINE_H -#define return_multi(value, error) errno = error; return value - typedef struct _php_engine { #ifdef ZTS void ***tsrm_ls; // Local storage for thread-safe operations, used across the PHP engine. diff --git a/engine_test.go b/engine/engine_test.go similarity index 66% rename from engine_test.go rename to engine/engine_test.go index 8524c04..3ae5adf 100644 --- a/engine_test.go +++ b/engine/engine_test.go @@ -1,19 +1,21 @@ -package php +package engine_test import ( "os" "testing" + + php "github.com/deuill/go-php" ) func TestNewEngineContext(t *testing.T) { - e, err := New() + e, err := php.New() if err != nil { t.Errorf("New(): %s", err) } defer e.Destroy() - ctx, err := e.NewContext(os.Stdout) + ctx, err := php.NewContext(os.Stdout) if err != nil { t.Errorf("NewContext(): %s", err) } diff --git a/php.go b/php.go new file mode 100644 index 0000000..ec9b485 --- /dev/null +++ b/php.go @@ -0,0 +1,16 @@ +package php + +import ( + "io" + + "github.com/deuill/go-php/context" + "github.com/deuill/go-php/engine" +) + +func New() (*engine.Engine, error) { + return engine.New() +} + +func NewContext(w io.Writer) (*context.Context, error) { + return context.New(w) +} diff --git a/value.c b/value/value.c similarity index 97% rename from value.c rename to value/value.c index 95f923c..7e09dd7 100644 --- a/value.c +++ b/value/value.c @@ -3,7 +3,6 @@ #include
-#include "engine.h" #include "value.h" void *value_create_long(long int value) { diff --git a/value.go b/value/value.go similarity index 86% rename from value.go rename to value/value.go index af89c97..1a27273 100644 --- a/value.go +++ b/value/value.go @@ -1,5 +1,9 @@ -package php +package value +// #cgo CFLAGS: -I/usr/include/php -I/usr/include/php/main -I/usr/include/php/TSRM +// #cgo CFLAGS: -I/usr/include/php/Zend +// #cgo LDFLAGS: -lphp5 +// // #include // #include // #include "value.h" @@ -26,7 +30,7 @@ func (v *Value) Destroy() { v = nil } -func NewValue(val interface{}) (*Value, error) { +func New(val interface{}) (*Value, error) { var ptr unsafe.Pointer // Determine value type and create PHP value from the concrete type. @@ -52,7 +56,7 @@ func NewValue(val interface{}) (*Value, error) { ptr = C.value_create_array(C.uint(v.Len())) for i := 0; i < v.Len(); i++ { - vs, err := NewValue(v.Index(i).Interface()) + vs, err := New(v.Index(i).Interface()) if err != nil { return nil, err } @@ -67,7 +71,7 @@ func NewValue(val interface{}) (*Value, error) { ptr = C.value_create_array(C.uint(v.Len())) for _, k := range v.MapKeys() { - vm, err := NewValue(v.MapIndex(k).Interface()) + vm, err := New(v.MapIndex(k).Interface()) if err != nil { return nil, err } diff --git a/value.h b/value/value.h similarity index 100% rename from value.h rename to value/value.h