/* * Perforce Extension for PHP * * Copyright 2004-2007 Jon Parise <jon@php.net>. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* $Header: //guest/jon_parise/api/php/perforce.cpp#12 $ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #include "php_ini.h" #include "zend_object_handlers.h" BEGIN_EXTERN_C() #include "ext/standard/info.h" END_EXTERN_C() /* Avoid colliding with PHP's definition of HAVE_MMAP. */ #undef HAVE_FORK #undef HAVE_GETHOSTNAME #undef HAVE_MMAP #undef HAVE_UTIME /* Avoid colliding with winspool.h's definition of SetPort. */ #ifdef SetPort #undef SetPort #endif #include "php_perforce.h" #include "php_clientuser.h" /* {{{ Globals */ static zend_class_entry *perforce_client_ce; static zend_class_entry *perforce_clientuser_ce; static int le_perforce = 0; /* }}} */ /* {{{ php_perforce_object */ struct php_perforce_object { ClientApi *client; PHPClientUser *user; }; /* }}} */ /* Helpers */ /* {{{ PHP_PERFORCE_FETCH(p) */ #define PHP_PERFORCE_FETCH(p) \ { \ zval **tmp; \ if (zend_hash_find(Z_OBJPROP_P(this_ptr), "perforce", sizeof("perforce"), \ (void **)&tmp) != FAILURE) { \ p = (php_perforce_object *)zend_fetch_resource(tmp TSRMLS_CC, -1, \ "perforce", NULL, 1, \ le_perforce); \ } else { \ php_error(E_ERROR, "Failed to retrieve Perforce connection resource");\ p = NULL; \ } \ } /* }}} */ /* {{{ implements_interface(zend_class_entry *interface, zend_class_entry *ce) */ static int implements_interface(zend_class_entry *interface, zend_class_entry *ce TSRMLS_DC) { zend_uint i; for (i = 0; i < ce->num_interfaces; ++i) { if (ce->interfaces[i] == interface) return SUCCESS; } return FAILURE; } /* }}} */ /* {{{ call_method(zval *object, char *method, int method_len, int arg_count, zval *arg1, zval *arg2, zval *arg3, zval *arg4) */ static zval * call_method(zval *object, char *method, int method_len, int arg_count, zval *arg1, zval *arg2, zval *arg3, zval *arg4) { zval *retval = NULL; zval *function_name; zval **args[4]; zend_class_entry *ce; HashTable *function_table; TSRMLS_FETCH(); ce = Z_OBJCE_P(object); function_table = &ce->function_table; MAKE_STD_ZVAL(function_name); ZVAL_STRINGL(function_name, method, method_len, 0); args[0] = &arg1; args[1] = &arg2; args[2] = &arg3; args[3] = &arg4; if ((call_user_function_ex(function_table, &object, function_name, &retval, arg_count, args, 0, NULL TSRMLS_CC) != SUCCESS) || (!retval)) { php_error(E_WARNING, "PerforceClient could not call %s::%s()", ce->name, method); ALLOC_INIT_ZVAL(retval); } return retval; } /* }}} */ /* {{{ call_method0(zval *object, char *method) */ #define call_method0(obj, name) \ call_method(obj, name, sizeof(name)-1, 0, NULL, NULL, NULL, NULL) /* }}} */ /* {{{ call_method1(zval *object, char *method, zval *arg1) */ #define call_method1(obj, name, a1) \ call_method(obj, name, sizeof(name)-1, 1, a1, NULL, NULL, NULL) /* }}} */ /* {{{ call_method2(zval *object, char *method, zval *arg1, zval *arg2) */ #define call_method2(obj, name, a1, a2) \ call_method(obj, name, sizeof(name)-1, 2, a1, a2, NULL, NULL) /* }}} */ /* {{{ call_method3(zval *object, char *method, zval *arg1, zval *arg2, zval *arg3) */ #define call_method3(obj, name, a1, a2, a3) \ call_method(obj, name, sizeof(name)-1, 3, a1, a2, a3, NULL) /* }}} */ /* {{{ call_method4(zval *object, char *method, zval *arg1, zval *arg2, zval *arg3, zval *arg4) */ #define call_method4(obj, name, a1, a2, a3, a4) \ call_method(obj, name, sizeof(name)-1, 4, a1, a2, a3, a4) /* }}} */ /* Perforce Client User */ /* {{{ PHPClientUser::PHPClientUser(zval *object) */ PHPClientUser::PHPClientUser(zval *object) : mpObject(object) { zval_copy_ctor(mpObject); } /* }}} */ /* {{{ PHPClientUser::~PHPClientUser() */ PHPClientUser::~PHPClientUser() { zval_dtor(mpObject); } /* }}} */ /* {{{ PHPClientUser::InputData(StrBuf *strbuf, Error *e) */ void PHPClientUser::InputData(StrBuf *strbuf, Error *e) { zval *retval = call_method0(mpObject, "InputData"); if (Z_TYPE_P(retval) == IS_STRING) { strbuf->Set(Z_STRVAL_P(retval)); } else { php_error(E_WARNING, "InputData must return a string"); } } /* }}} */ /* {{{ PHPClientUser::HandleError(Error *err) */ void PHPClientUser::HandleError(Error *err) { StrBuf msg; err->Fmt(&msg) ; zval *z_msg; MAKE_STD_ZVAL(z_msg); ZVAL_STRINGL(z_msg, msg.Text(), msg.Length(), 1); zval *z_severity; MAKE_STD_ZVAL(z_severity); ZVAL_LONG(z_severity, err->GetSeverity()); call_method2(mpObject, "HandleError", z_msg, z_severity); } /* }}} */ /* {{{ PHPClientUser::Message(Error *err) */ void PHPClientUser::Message(Error *err) { StrBuf msg; err->Fmt(&msg) ; zval *z_msg; MAKE_STD_ZVAL(z_msg); ZVAL_STRINGL(z_msg, msg.Text(), msg.Length(), 1); zval *z_severity; MAKE_STD_ZVAL(z_severity); ZVAL_LONG(z_severity, err->GetSeverity()); call_method2(mpObject, "Message", z_msg, z_severity); } /* }}} */ /* {{{ PHPClientUser::OutputError(const char *errBuf) */ void PHPClientUser::OutputError(const char *errBuf) { zval *z_error; MAKE_STD_ZVAL(z_error); ZVAL_STRING(z_error, const_cast<char *>(errBuf), 1); call_method1(mpObject, "OutputError", z_error); } /* }}} */ /* {{{ PHPClientUser::OutputInfo(char level, const char *data) */ void PHPClientUser::OutputInfo(char level, const char *data) { zval *z_level; MAKE_STD_ZVAL(z_level); ZVAL_LONG(z_level, level); zval *z_data; MAKE_STD_ZVAL(z_data); ZVAL_STRING(z_data, const_cast<char *>(data), 1); call_method2(mpObject, "OutputInfo", z_level, z_data); } /* }}} */ /* {{{ PHPClientUser::OutputBinary(const char *data, int length) */ void PHPClientUser::OutputBinary(const char *data, int length) { zval *z_data; MAKE_STD_ZVAL(z_data); ZVAL_STRINGL(z_data, const_cast<char *>(data), length, 1); call_method1(mpObject, "OutputBinary", z_data); } /* }}} */ /* {{{ PHPClientUser::OutputText(const char *data, int length) */ void PHPClientUser::OutputText(const char *data, int length) { zval *z_data; MAKE_STD_ZVAL(z_data); ZVAL_STRINGL(z_data, const_cast<char *>(data), length, 1); call_method1(mpObject, "OutputText", z_data); } /* }}} */ /* {{{ PHPClientUser::OutputStat(StrDict *varList) */ void PHPClientUser::OutputStat(StrDict *varList) { TSRMLS_FETCH(); zval *z_tags; MAKE_STD_ZVAL(z_tags); if (array_init(z_tags) != SUCCESS) { php_error(E_ERROR, "Failed to initialize array parameter value"); return; } static char * const vars[] = { "tag", "clientFile", "depotFile", "headAction", "headChange", "headRev", "headType", "headTime", "haveRev", "action", "change", "unresolved", "otherOpen", "otherLock", "ourLock", "client", "user", "time", "status", "desc", "dir", "path", "unmap" , 0 }; StrPtr *s; zval *v; MAKE_STD_ZVAL(v); /* Add the known variables to the array. */ for (int i = 0; vars[i]; ++i) { if (s = varList->GetVar(StrRef(vars[i]))) { ZVAL_STRINGL(v, s->Text(), s->Length(), 1); if (zend_hash_update(HASH_OF(z_tags), vars[i], strlen(vars[i]), (void *)&v, sizeof(zval *), NULL) == FAILURE) { php_error(E_ERROR, "Failed to insert ('%s' => '%s') into array", vars[i], s->Text()); } } } call_method1(mpObject, "OutputStat", z_tags); } /* }}} */ /* {{{ PHPClientUser::Prompt(const StrPtr &msg, StrBuf &buf, int bufsiz, Error *e) */ void PHPClientUser::Prompt(const StrPtr &msg, StrBuf &buf, int bufsiz, Error *e) { zval *z_msg; MAKE_STD_ZVAL(z_msg); ZVAL_STRINGL(z_msg, msg.Text(), msg.Length(), 1); zval *retval = call_method1(mpObject, "Prompt", z_msg); if (Z_TYPE_P(retval) == IS_STRING) { buf.Set(Z_STRVAL_P(retval)); } else { php_error(E_WARNING, "Prompt must return a string"); } } /* }}} */ /* {{{ PHPClientUser::ErrorPause(char *errBuf, Error *e) */ void PHPClientUser::ErrorPause(char *errBuf, Error *e) { zval *z_error; MAKE_STD_ZVAL(z_error); ZVAL_STRING(z_error, errBuf, 1); call_method1(mpObject, "ErrorPause", z_error); } /* }}} */ /* {{{ PHPClientUser::Edit(FileSys *f1, Error *e) */ void PHPClientUser::Edit(FileSys *f1, Error *e) { zval *z_filename; MAKE_STD_ZVAL(z_filename); ZVAL_STRING(z_filename, f1->Name(), 1); call_method1(mpObject, "Edit", z_filename); } /* }}} */ /* {{{ PHPClientUser::Diff(FileSys *f1, FileSys *f2, int doPage, char *diffFlags, Error *e) */ void PHPClientUser::Diff(FileSys *f1, FileSys *f2, int doPage, char *diffFlags, Error *e) { zval *z_filename1; MAKE_STD_ZVAL(z_filename1); ZVAL_STRING(z_filename1, f1->Name(), 1); zval *z_filename2; MAKE_STD_ZVAL(z_filename2); ZVAL_STRING(z_filename2, f2->Name(), 1); zval *z_do_page; MAKE_STD_ZVAL(z_do_page); ZVAL_LONG(z_do_page, doPage); zval *z_diff_flags; MAKE_STD_ZVAL(z_diff_flags); ZVAL_STRING(z_diff_flags, diffFlags, 1); call_method4(mpObject, "Diff", z_filename1, z_filename2, z_do_page, z_diff_flags); } /* }}} */ /* {{{ PHPClientUser::Merge(FileSys *base, FileSys *leg1, FileSys *leg2, FileSys *result, Error *e) */ void PHPClientUser::Merge(FileSys *base, FileSys *leg1, FileSys *leg2, FileSys *result, Error *e) { zval *z_base_filename; MAKE_STD_ZVAL(z_base_filename); ZVAL_STRING(z_base_filename, base->Name(), 1); zval *z_leg1_filename; MAKE_STD_ZVAL(z_leg1_filename); ZVAL_STRING(z_leg1_filename, leg1->Name(), 1); zval *z_leg2_filename; MAKE_STD_ZVAL(z_leg2_filename); ZVAL_STRING(z_leg2_filename, leg2->Name(), 1); zval *z_result_filename; MAKE_STD_ZVAL(z_result_filename); ZVAL_STRING(z_result_filename, result->Name(), 1); call_method4(mpObject, "Merge", z_base_filename, z_leg1_filename, z_leg2_filename, z_result_filename); } /* }}} */ /* {{{ PHPClientUser::Help(const char * const *help) */ void PHPClientUser::Help(const char * const *help) { TSRMLS_FETCH(); zval *z_help; MAKE_STD_ZVAL(z_help); if (array_init(z_help) != SUCCESS) { php_error(E_ERROR, "Failed to initialize array parameter value"); return; } zval *line; MAKE_STD_ZVAL(line); while (*help) { /* Read a full line of help text (until the NUL). */ ZVAL_STRING(line, (char *)help, 1); /* Insert this line of help text into the next slot of the array. */ if (zend_hash_next_index_insert(HASH_OF(z_help), (void *)&line, sizeof(zval *), NULL) == FAILURE) { php_error(E_ERROR, "Failed to insert new line into array"); } /* Jump over the NUL character. There may be more text waiting. */ help += 1; } call_method1(mpObject, "Help", z_help); } /* }}} */ /* PerforceClient Methods */ /* {{{ proto void __construct(object ui) */ PHP_METHOD(PerforceClient, __construct) { php_perforce_object *perforce = NULL; zend_class_entry *ce; zval *ui; int ret; /* We expect a single parameter: the PerforceClientUser UI object. */ if (zend_parse_parameters(1 TSRMLS_CC, "o", &ui) == FAILURE) { return; } /* Ensure that the UI object implements the PerforceClientUser interface. */ ce = Z_OBJCE_P(ui); if (implements_interface(perforce_clientuser_ce, ce TSRMLS_CC) == FAILURE) { php_error(E_ERROR, "%s must implement the %s interface", ce->name, perforce_clientuser_ce->name); return; } /* Initialize our new PerforceClient object. */ object_init_ex(this_ptr, perforce_client_ce); /* Create the Perforce Client objects. */ perforce = (php_perforce_object *)emalloc(sizeof(php_perforce_object)); perforce->user = new PHPClientUser(ui); perforce->client = new ClientApi(perforce->user); /* Register the structure as a resource of this PerforceClient object. */ ret = zend_list_insert(perforce, le_perforce); add_property_resource(this_ptr, "perforce", ret); zend_list_addref(ret); } /* }}} */ /* {{{ proto bool setPort(string port) */ PHP_METHOD(PerforceClient, setPort) { php_perforce_object *perforce; char *port; int len; if (zend_parse_parameters(1 TSRMLS_CC, "s", &port, &len) == FAILURE) { return; } PHP_PERFORCE_FETCH(perforce); if (!perforce) RETURN_FALSE; perforce->client->SetPort(port); RETURN_TRUE; } /* }}} */ /* {{{ proto string getPort() */ PHP_METHOD(PerforceClient, getPort) { php_perforce_object *perforce; PHP_PERFORCE_FETCH(perforce); if (!perforce) RETURN_FALSE; const StrPtr port(perforce->client->GetPort()); RETURN_STRINGL(port.Text(), port.Length(), 1); } /* }}} */ /* {{{ proto bool setUser(string user) */ PHP_METHOD(PerforceClient, setUser) { php_perforce_object *perforce; char *user; int len; if (zend_parse_parameters(1 TSRMLS_CC, "s", &user, &len) == FAILURE) { return; } PHP_PERFORCE_FETCH(perforce); if (!perforce) RETURN_FALSE; perforce->client->SetUser(user); RETURN_TRUE; } /* }}} */ /* {{{ proto string getUser() */ PHP_METHOD(PerforceClient, getUser) { php_perforce_object *perforce; PHP_PERFORCE_FETCH(perforce); if (!perforce) RETURN_FALSE; const StrPtr user(perforce->client->GetUser()); RETURN_STRINGL(user.Text(), user.Length(), 1); } /* }}} */ /* {{{ proto bool setPassword(string password) */ PHP_METHOD(PerforceClient, setPassword) { php_perforce_object *perforce; char *password; int len; if (zend_parse_parameters(1 TSRMLS_CC, "s", &password, &len) == FAILURE) { return; } PHP_PERFORCE_FETCH(perforce); if (!perforce) RETURN_FALSE; perforce->client->SetPassword(password); RETURN_TRUE; } /* }}} */ /* {{{ proto string getPassword() */ PHP_METHOD(PerforceClient, getPassword) { php_perforce_object *perforce; PHP_PERFORCE_FETCH(perforce); if (!perforce) RETURN_FALSE; const StrPtr password(perforce->client->GetPassword()); RETURN_STRINGL(password.Text(), password.Length(), 1); } /* }}} */ /* {{{ proto bool setClient(string client) */ PHP_METHOD(PerforceClient, setClient) { php_perforce_object *perforce; char *client; int len; if (zend_parse_parameters(1 TSRMLS_CC, "s", &client, &len) == FAILURE) { return; } PHP_PERFORCE_FETCH(perforce); if (!perforce) RETURN_FALSE; perforce->client->SetClient(client); RETURN_TRUE; } /* }}} */ /* {{{ proto string getClient() */ PHP_METHOD(PerforceClient, getClient) { php_perforce_object *perforce; PHP_PERFORCE_FETCH(perforce); if (!perforce) RETURN_FALSE; const StrPtr client(perforce->client->GetClient()); RETURN_STRINGL(client.Text(), client.Length(), 1); } /* }}} */ /* {{{ proto bool setProtocol(string protocol) */ PHP_METHOD(PerforceClient, setProtocol) { php_perforce_object *perforce; char *protocol, *value; int protocol_len, value_len; if (zend_parse_parameters(2 TSRMLS_CC, "ss", &protocol, &protocol_len, &value, &value_len) == FAILURE) { return; } PHP_PERFORCE_FETCH(perforce); if (!perforce) RETURN_FALSE; perforce->client->SetProtocol(protocol, value); RETURN_TRUE; } /* }}} */ /* {{{ proto string getProtocol(string protocol) */ PHP_METHOD(PerforceClient, getProtocol) { php_perforce_object *perforce; char *protocol; int len; if (zend_parse_parameters(1 TSRMLS_CC, "s", &protocol, &len) == FAILURE) { return; } PHP_PERFORCE_FETCH(perforce); if (!perforce) RETURN_FALSE; const StrPtr *value = perforce->client->GetProtocol(protocol); RETURN_STRINGL(value->Text(), value->Length(), 1); } /* }}} */ /* {{{ proto bool setCwd(string cwd) */ PHP_METHOD(PerforceClient, setCwd) { php_perforce_object *perforce; char *cwd; int len; if (zend_parse_parameters(1 TSRMLS_CC, "s", &cwd, &len) == FAILURE) { return; } PHP_PERFORCE_FETCH(perforce); if (!perforce) RETURN_FALSE; perforce->client->SetCwd(cwd); RETURN_TRUE; } /* }}} */ /* {{{ proto string getCwd() */ PHP_METHOD(PerforceClient, getCwd) { php_perforce_object *perforce; PHP_PERFORCE_FETCH(perforce); if (!perforce) RETURN_FALSE; const StrPtr cwd(perforce->client->GetCwd()); RETURN_STRINGL(cwd.Text(), cwd.Length(), 1); } /* }}} */ /* {{{ proto bool setCharset(string charset) */ PHP_METHOD(PerforceClient, setCharset) { php_perforce_object *perforce; char *charset; int len; if (zend_parse_parameters(1 TSRMLS_CC, "s", &charset, &len) == FAILURE) { return; } PHP_PERFORCE_FETCH(perforce); if (!perforce) RETURN_FALSE; perforce->client->SetCharset(charset); RETURN_TRUE; } /* }}} */ /* {{{ proto string getCharset() */ PHP_METHOD(PerforceClient, getCharset) { php_perforce_object *perforce; PHP_PERFORCE_FETCH(perforce); if (!perforce) RETURN_FALSE; const StrPtr charset(perforce->client->GetCharset()); RETURN_STRINGL(charset.Text(), charset.Length(), 1); } /* }}} */ /* {{{ proto bool setHost(string host) */ PHP_METHOD(PerforceClient, setHost) { php_perforce_object *perforce; char *host; int len; if (zend_parse_parameters(1 TSRMLS_CC, "s", &host, &len) == FAILURE) { return; } PHP_PERFORCE_FETCH(perforce); if (!perforce) RETURN_FALSE; perforce->client->SetHost(host); RETURN_TRUE; } /* }}} */ /* {{{ proto string getHost() */ PHP_METHOD(PerforceClient, getHost) { php_perforce_object *perforce; PHP_PERFORCE_FETCH(perforce); if (!perforce) RETURN_FALSE; const StrPtr host(perforce->client->GetHost()); RETURN_STRINGL(host.Text(), host.Length(), 1); } /* }}} */ /* {{{ proto bool setLanguage(string language) */ PHP_METHOD(PerforceClient, setLanguage) { php_perforce_object *perforce; char *language; int len; if (zend_parse_parameters(1 TSRMLS_CC, "s", &language, &len) == FAILURE) { return; } PHP_PERFORCE_FETCH(perforce); if (!perforce) RETURN_FALSE; perforce->client->SetLanguage(language); RETURN_TRUE; } /* }}} */ /* {{{ proto string getLanguage() */ PHP_METHOD(PerforceClient, getLanguage) { php_perforce_object *perforce; PHP_PERFORCE_FETCH(perforce); if (!perforce) RETURN_FALSE; const StrPtr language(perforce->client->GetLanguage()); RETURN_STRINGL(language.Text(), language.Length(), 1); } /* }}} */ /* {{{ proto string getOs() */ PHP_METHOD(PerforceClient, getOs) { php_perforce_object *perforce; PHP_PERFORCE_FETCH(perforce); if (!perforce) RETURN_FALSE; const StrPtr os(perforce->client->GetOs()); RETURN_STRINGL(os.Text(), os.Length(), 1); } /* }}} */ /* {{{ proto bool init() Establish the connection. */ PHP_METHOD(PerforceClient, init) { Error error; php_perforce_object *perforce = NULL; PHP_PERFORCE_FETCH(perforce); if (!perforce) RETURN_FALSE; if (perforce == NULL) { php_error(E_ERROR, "Failed to retrieve Perforce connection resource"); RETURN_FALSE; } perforce->client->Init(&error); if (error.Test()) { perforce->user->HandleError(&error); RETURN_FALSE; } RETURN_TRUE; } /* }}} */ /* {{{ proto int final() Close the connection and return the error count. */ PHP_METHOD(PerforceClient, final) { php_perforce_object *perforce; int error_count = 0; Error error; PHP_PERFORCE_FETCH(perforce); if (!perforce) RETURN_FALSE; error_count = perforce->client->Final(&error); if (error.Test()) { perforce->user->HandleError(&error); } RETURN_LONG(error_count); } /* }}} */ /* {{{ proto bool dropped() Check if the connection is still open. */ PHP_METHOD(PerforceClient, dropped) { php_perforce_object *perforce; PHP_PERFORCE_FETCH(perforce); if (!perforce) RETURN_FALSE; if (perforce == NULL) { php_error(E_ERROR, "Failed to retrieve Perforce connection resource"); RETURN_FALSE; } RETURN_BOOL(perforce->client->Dropped() != 0); } /* }}} */ /* {{{ proto bool setArgs() Set the arguments for the next Perforce command. */ PHP_METHOD(PerforceClient, setArgs) { php_perforce_object *perforce; zval *args; zval **item; int i = 0; if (zend_parse_parameters(1 TSRMLS_CC, "a", &args) == FAILURE) { return; } int argc = zend_hash_num_elements(Z_ARRVAL_P(args)); char **argv = (char **) emalloc(sizeof(char *) * argc); zend_hash_internal_pointer_reset(Z_ARRVAL_P(args)); /* Iterate over the array elements */ while (zend_hash_get_current_data(Z_ARRVAL_P(args), (void **)&item) == SUCCESS) { if (i > argc) { php_error(E_ERROR, "Encountered too many items in array"); break; } /* Add the string value of this item to the args and advance. */ convert_to_string_ex(item); argv[i++] = Z_STRVAL_PP(item); zend_hash_move_forward(Z_ARRVAL_P(args)); } PHP_PERFORCE_FETCH(perforce); if (!perforce) RETURN_FALSE; perforce->client->SetArgv(argc, argv); efree(argv); RETURN_TRUE; } /* }}} */ /* {{{ proto bool run(string command) Run a Perforce command. */ PHP_METHOD(PerforceClient, run) { php_perforce_object *perforce; char *command; int len; if (zend_parse_parameters(1 TSRMLS_CC, "s", &command, &len) == FAILURE) { return; } PHP_PERFORCE_FETCH(perforce); if (!perforce) RETURN_FALSE; perforce->client->Run(command); RETURN_TRUE; } /* }}} */ /* {{{ ARG_INFO */ static ZEND_BEGIN_ARG_INFO_EX(arginfo_message, 0, 0, 1) ZEND_ARG_INFO(0, message) ZEND_END_ARG_INFO() static ZEND_BEGIN_ARG_INFO_EX(arginfo_message_severity, 0, 0, 2) ZEND_ARG_INFO(0, message) ZEND_ARG_INFO(0, severity) ZEND_END_ARG_INFO() static ZEND_BEGIN_ARG_INFO_EX(arginfo_level_data, 0, 0, 2) ZEND_ARG_INFO(0, level) ZEND_ARG_INFO(0, data) ZEND_END_ARG_INFO() static ZEND_BEGIN_ARG_INFO_EX(arginfo_data, 0, 0, 1) ZEND_ARG_INFO(0, data) ZEND_END_ARG_INFO() static ZEND_BEGIN_ARG_INFO_EX(arginfo_tags, 0, 0, 1) ZEND_ARG_INFO(0, tags) ZEND_END_ARG_INFO() static ZEND_BEGIN_ARG_INFO_EX(arginfo_file, 0, 0, 1) ZEND_ARG_INFO(0, file) ZEND_END_ARG_INFO() static ZEND_BEGIN_ARG_INFO_EX(arginfo_diff, 0, 0, 4) ZEND_ARG_INFO(0, file1) ZEND_ARG_INFO(0, file2) ZEND_ARG_INFO(0, doPage) ZEND_ARG_INFO(0, flags) ZEND_END_ARG_INFO() static ZEND_BEGIN_ARG_INFO_EX(arginfo_merge, 0, 0, 4) ZEND_ARG_INFO(0, base) ZEND_ARG_INFO(0, leg1) ZEND_ARG_INFO(0, leg2) ZEND_ARG_INFO(0, result) ZEND_END_ARG_INFO() /* }}} */ /* {{{ perforce_methods[] */ static function_entry perforce_methods[] = { PHP_ME(PerforceClient, __construct, NULL, 0) PHP_ME(PerforceClient, setPort, NULL, 0) PHP_ME(PerforceClient, getPort, NULL, 0) PHP_ME(PerforceClient, setUser, NULL, 0) PHP_ME(PerforceClient, getUser, NULL, 0) PHP_ME(PerforceClient, setPassword, NULL, 0) PHP_ME(PerforceClient, getPassword, NULL, 0) PHP_ME(PerforceClient, setClient, NULL, 0) PHP_ME(PerforceClient, getClient, NULL, 0) PHP_ME(PerforceClient, setProtocol, NULL, 0) PHP_ME(PerforceClient, getProtocol, NULL, 0) PHP_ME(PerforceClient, setCwd, NULL, 0) PHP_ME(PerforceClient, getCwd, NULL, 0) PHP_ME(PerforceClient, setCharset, NULL, 0) PHP_ME(PerforceClient, getCharset, NULL, 0) PHP_ME(PerforceClient, setHost, NULL, 0) PHP_ME(PerforceClient, getHost, NULL, 0) PHP_ME(PerforceClient, setLanguage, NULL, 0) PHP_ME(PerforceClient, getLanguage, NULL, 0) PHP_ME(PerforceClient, getOs, NULL, 0) PHP_ME(PerforceClient, init, NULL, 0) PHP_ME(PerforceClient, final, NULL, 0) PHP_ME(PerforceClient, dropped, NULL, 0) PHP_ME(PerforceClient, setArgs, NULL, 0) PHP_ME(PerforceClient, run, NULL, 0) {NULL, NULL, NULL} }; /* }}} */ /* {{{ perforce_clientuser_methods[] */ static zend_function_entry perforce_clientuser_methods[] = { ZEND_ABSTRACT_ME(PerforceClientUser, InputData, NULL) ZEND_ABSTRACT_ME(PerforceClientUser, HandleError, arginfo_message_severity) ZEND_ABSTRACT_ME(PerforceClientUser, Message, arginfo_message_severity) ZEND_ABSTRACT_ME(PerforceClientUser, OutputError, arginfo_message) ZEND_ABSTRACT_ME(PerforceClientUser, OutputInfo, arginfo_level_data) ZEND_ABSTRACT_ME(PerforceClientUser, OutputBinary, arginfo_data) ZEND_ABSTRACT_ME(PerforceClientUser, OutputText, arginfo_data) ZEND_ABSTRACT_ME(PerforceClientUser, OutputStat, arginfo_tags) ZEND_ABSTRACT_ME(PerforceClientUser, Prompt, arginfo_message) ZEND_ABSTRACT_ME(PerforceClientUser, ErrorPause, arginfo_message) ZEND_ABSTRACT_ME(PerforceClientUser, Edit, arginfo_file) ZEND_ABSTRACT_ME(PerforceClientUser, Diff, arginfo_diff) ZEND_ABSTRACT_ME(PerforceClientUser, Merge, arginfo_merge) ZEND_ABSTRACT_ME(PerforceClientUser, Help, arginfo_message) { NULL, NULL, NULL } }; /* }}} */ /* {{{ perforce_module_entry */ zend_module_entry perforce_module_entry = { STANDARD_MODULE_HEADER, "perforce", NULL, PHP_MINIT(perforce), PHP_MSHUTDOWN(perforce), NULL, NULL, PHP_MINFO(perforce), NO_VERSION_YET, STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_PERFORCE BEGIN_EXTERN_C() ZEND_GET_MODULE(perforce) END_EXTERN_C() #endif /* }}} */ /* {{{ perforce_destructor(void *object) */ static void perforce_destructor(void *object) { php_perforce_object *perforce = (php_perforce_object *)object; delete perforce->user; delete perforce->client; efree(object); } /* }}} */ /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(perforce) { zend_class_entry ce; INIT_CLASS_ENTRY(ce, "PerforceClient", perforce_methods); perforce_client_ce = zend_register_internal_class(&ce TSRMLS_CC); INIT_CLASS_ENTRY(ce, "PerforceClientUser", perforce_clientuser_methods); perforce_clientuser_ce = zend_register_internal_interface(&ce TSRMLS_CC); perforce_clientuser_ce->interface_gets_implemented = implements_interface; le_perforce = register_list_destructors(perforce_destructor, NULL); return SUCCESS; } /* }}} */ /* {{{ PHP_MSHUTDOWN_FUNCTION */ PHP_MSHUTDOWN_FUNCTION(perforce) { return SUCCESS; } /* }}} */ /* {{{ PHP_MINFO_FUNCTION */ PHP_MINFO_FUNCTION(perforce) { php_info_print_table_start(); php_info_print_table_row(2, "Perforce Support", "enabled"); php_info_print_table_end(); } /* }}} */ /* * Local variables: * c-basic-offset: 4 * tab-width: 4 * End: * vim600: fdm=marker * vim: sw=4 ts=4 noet */
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#22 | 7624 | Jon Parise | Avoiding a warning about string literal to char* conversion. | ||
#21 | 7623 | Jon Parise |
The ZEND_BEGIN_ARG_INFO_EX macro now specifies the 'static' keyword itself, so don't want to specific it ourself. |
||
#20 | 6169 | Jon_Parise |
The internal object code has been rewritten to take advantage of the PHP5-specific object model. |
||
#19 | 6168 | Jon_Parise | Bumping copyright years. | ||
#18 | 6148 | Jon_Parise | Tagging the module with the 1.0 version number. | ||
#17 | 6129 | Jon_Parise |
Removing the runTag() and waitTag() methods because support for them has been deprecated in the official P4API. Also, the C++ object memory allocation approach has been simplified. |
||
#16 | 6094 | Jon_Parise | setArgs() now accepts either an array of arguments or individual arguments. | ||
#15 | 6092 | Jon_Parise |
Fixing support for tagged output. We also now return all of the tags (unfiltered) to the user's OutputStat() implementation. |
||
#14 | 6087 | Jon_Parise | Wrapping the rest of the client API and adding argument info to the native PerforceClient methods. | ||
#13 | 6082 | Jon_Parise | Allocate memory for our C++ objects using PHP's memory manager. | ||
#12 | 6081 | Jon_Parise |
Simplifying the method calling code a little bit so that it only searches within the known clientuser class entry's function table. We can also get rid of the get_class_name() helper function. |
||
#11 | 6080 | Jon_Parise | Rewriting the method calling routines to avoid heap allocation for arguments. | ||
#10 | 6079 | Jon_Parise |
We now use a formal interface to define the UI object. This requires PHP5 so all PHP4 support has been removed. A number of other small code improvements are also included. |
||
#9 | 6078 | Jon_Parise | Updating copyright years. | ||
#8 | 6065 | Jon_Parise | Removing PHP 4 (pre- Zend Engine 2) compatibility. | ||
#7 | 6055 | Jon_Parise | Updating to work with the Perforce 2007.2 API. | ||
#6 | 4427 | Jon_Parise |
Corrected some compilation issues with older versions of PHP under Windows. Submitted by: ken@demarest.com |
||
#5 | 4349 | Jon_Parise |
Apparently, Visual C++ 6 doesn't like this initializer. Rewrite this line as an assignment. |
||
#4 | 4324 | Jon_Parise |
Adding Win32 support. This includes the addition of a config.w32 Win32 build file, a handful of ZTS fixes, the extraction of the PHPClientUser class (and its p4api header dependency) to a separate header file, and the removal of the p4api_version.h auto-generated file (which may return should I figure out how to generate it using JScript). |
||
#3 | 4293 | Jon_Parise | Use $Header$ keywords instead of $Id$. | ||
#2 | 4292 | Jon_Parise |
Changing these files to the 'ktext' filetype so that the RCS keywords will be expanded. |
||
#1 | 4291 | Jon_Parise | Initial version of the Perforce extension for PHP. |