/* * Perforce Extension for PHP * * Copyright 2004-2008 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#22 $ */ #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 these symbols. */ #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" #include <new> /* {{{ Globals */ static zend_object_handlers perforce_object_handlers; static zend_class_entry *perforce_client_ce; static zend_class_entry *perforce_clientuser_ce; /* }}} */ /* {{{ php_perforce_object */ typedef struct _php_perforce_object { zend_object base; ClientApi *client; PHPClientUser *user; } php_perforce_object; /* }}} */ /* {{{ PHP_PERFORCE_FETCH(p) */ #define PHP_PERFORCE_FETCH(name, zv) \ php_perforce_object *name = (php_perforce_object *)zend_object_store_get_object(zv TSRMLS_CC) /* }}} */ /* Helpers */ /* {{{ 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, const 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 *tags, *value; MAKE_STD_ZVAL(tags); if (array_init(tags) != SUCCESS) { php_error(E_ERROR, "Failed to initialize tags array"); return; } int i = 0; StrRef var, val; /* Copy all of the tags from the dictionary into an array. */ while (varList->GetVar(i++, var, val)) { MAKE_STD_ZVAL(value); ZVAL_STRINGL(value, val.Text(), val.Length(), 1); zend_hash_update(HASH_OF(tags), var.Text(), var.Length() + 1, (void *)&value, sizeof(zval *), NULL); } call_method1(mpObject, "OutputStat", 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 __construct(object ui) */ PHP_METHOD(PerforceClient, __construct) { PHP_PERFORCE_FETCH(perforce, getThis()); zend_class_entry *ce; zval *ui; /* 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; } /* Allocate and construct the Perforce Client objects. */ perforce->user = (PHPClientUser *)emalloc(sizeof(PHPClientUser)); perforce->user = new(perforce->user) PHPClientUser(ui); perforce->client = (ClientApi *)emalloc(sizeof(ClientApi)); perforce->client = new(perforce->client) ClientApi(perforce->user); } /* }}} */ /* {{{ proto bool setPort(string port) */ PHP_METHOD(PerforceClient, setPort) { PHP_PERFORCE_FETCH(perforce, getThis()); char *port; int len; if (zend_parse_parameters(1 TSRMLS_CC, "s", &port, &len) == FAILURE) { return; } perforce->client->SetPort(port); RETURN_TRUE; } /* }}} */ /* {{{ proto string getPort() */ PHP_METHOD(PerforceClient, getPort) { PHP_PERFORCE_FETCH(perforce, getThis()); const StrPtr port(perforce->client->GetPort()); RETURN_STRINGL(port.Text(), port.Length(), 1); } /* }}} */ /* {{{ proto bool setUser(string user) */ PHP_METHOD(PerforceClient, setUser) { PHP_PERFORCE_FETCH(perforce, getThis()); char *user; int len; if (zend_parse_parameters(1 TSRMLS_CC, "s", &user, &len) == FAILURE) { return; } perforce->client->SetUser(user); RETURN_TRUE; } /* }}} */ /* {{{ proto string getUser() */ PHP_METHOD(PerforceClient, getUser) { PHP_PERFORCE_FETCH(perforce, getThis()); const StrPtr user(perforce->client->GetUser()); RETURN_STRINGL(user.Text(), user.Length(), 1); } /* }}} */ /* {{{ proto bool setPassword(string password) */ PHP_METHOD(PerforceClient, setPassword) { PHP_PERFORCE_FETCH(perforce, getThis()); char *password; int len; if (zend_parse_parameters(1 TSRMLS_CC, "s", &password, &len) == FAILURE) { return; } perforce->client->SetPassword(password); RETURN_TRUE; } /* }}} */ /* {{{ proto string getPassword() */ PHP_METHOD(PerforceClient, getPassword) { PHP_PERFORCE_FETCH(perforce, getThis()); const StrPtr password(perforce->client->GetPassword()); RETURN_STRINGL(password.Text(), password.Length(), 1); } /* }}} */ /* {{{ proto bool setClient(string client) */ PHP_METHOD(PerforceClient, setClient) { PHP_PERFORCE_FETCH(perforce, getThis()); char *client; int len; if (zend_parse_parameters(1 TSRMLS_CC, "s", &client, &len) == FAILURE) { return; } perforce->client->SetClient(client); RETURN_TRUE; } /* }}} */ /* {{{ proto string getClient() */ PHP_METHOD(PerforceClient, getClient) { PHP_PERFORCE_FETCH(perforce, getThis()); const StrPtr client(perforce->client->GetClient()); RETURN_STRINGL(client.Text(), client.Length(), 1); } /* }}} */ /* {{{ proto bool setProtocol(string protocol, string value) */ PHP_METHOD(PerforceClient, setProtocol) { PHP_PERFORCE_FETCH(perforce, getThis()); char *protocol, *value; int protocol_len, value_len; if (zend_parse_parameters(2 TSRMLS_CC, "ss", &protocol, &protocol_len, &value, &value_len) == FAILURE) { return; } perforce->client->SetProtocol(protocol, value); RETURN_TRUE; } /* }}} */ /* {{{ proto string getProtocol(string protocol) */ PHP_METHOD(PerforceClient, getProtocol) { PHP_PERFORCE_FETCH(perforce, getThis()); char *protocol; int len; if (zend_parse_parameters(1 TSRMLS_CC, "s", &protocol, &len) == FAILURE) { return; } 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_FETCH(perforce, getThis()); char *cwd; int len; if (zend_parse_parameters(1 TSRMLS_CC, "s", &cwd, &len) == FAILURE) { return; } perforce->client->SetCwd(cwd); RETURN_TRUE; } /* }}} */ /* {{{ proto string getCwd() */ PHP_METHOD(PerforceClient, getCwd) { PHP_PERFORCE_FETCH(perforce, getThis()); const StrPtr cwd(perforce->client->GetCwd()); RETURN_STRINGL(cwd.Text(), cwd.Length(), 1); } /* }}} */ /* {{{ proto bool setCharset(string charset) */ PHP_METHOD(PerforceClient, setCharset) { PHP_PERFORCE_FETCH(perforce, getThis()); char *charset; int len; if (zend_parse_parameters(1 TSRMLS_CC, "s", &charset, &len) == FAILURE) { return; } perforce->client->SetCharset(charset); RETURN_TRUE; } /* }}} */ /* {{{ proto string getCharset() */ PHP_METHOD(PerforceClient, getCharset) { PHP_PERFORCE_FETCH(perforce, getThis()); const StrPtr charset(perforce->client->GetCharset()); RETURN_STRINGL(charset.Text(), charset.Length(), 1); } /* }}} */ /* {{{ proto bool setHost(string host) */ PHP_METHOD(PerforceClient, setHost) { PHP_PERFORCE_FETCH(perforce, getThis()); char *host; int len; if (zend_parse_parameters(1 TSRMLS_CC, "s", &host, &len) == FAILURE) { return; } perforce->client->SetHost(host); RETURN_TRUE; } /* }}} */ /* {{{ proto string getHost() */ PHP_METHOD(PerforceClient, getHost) { PHP_PERFORCE_FETCH(perforce, getThis()); const StrPtr host(perforce->client->GetHost()); RETURN_STRINGL(host.Text(), host.Length(), 1); } /* }}} */ /* {{{ proto bool setProg(string name) */ PHP_METHOD(PerforceClient, setProg) { PHP_PERFORCE_FETCH(perforce, getThis()); char *name; int len; if (zend_parse_parameters(1 TSRMLS_CC, "s", &name, &len) == FAILURE) { return; } perforce->client->SetProg(name); RETURN_TRUE; } /* }}} */ /* {{{ proto string getConfig() */ PHP_METHOD(PerforceClient, getConfig) { PHP_PERFORCE_FETCH(perforce, getThis()); const StrPtr config(perforce->client->GetConfig()); RETURN_STRINGL(config.Text(), config.Length(), 1); } /* }}} */ /* {{{ proto bool setTicketFile(string filename) */ PHP_METHOD(PerforceClient, setTicketFile) { PHP_PERFORCE_FETCH(perforce, getThis()); char *filename; int len; if (zend_parse_parameters(1 TSRMLS_CC, "s", &filename, &len) == FAILURE) { return; } perforce->client->SetTicketFile(filename); RETURN_TRUE; } /* }}} */ /* {{{ proto bool setLanguage(string language) */ PHP_METHOD(PerforceClient, setLanguage) { PHP_PERFORCE_FETCH(perforce, getThis()); char *language; int len; if (zend_parse_parameters(1 TSRMLS_CC, "s", &language, &len) == FAILURE) { return; } perforce->client->SetLanguage(language); RETURN_TRUE; } /* }}} */ /* {{{ proto string getLanguage() */ PHP_METHOD(PerforceClient, getLanguage) { PHP_PERFORCE_FETCH(perforce, getThis()); const StrPtr language(perforce->client->GetLanguage()); RETURN_STRINGL(language.Text(), language.Length(), 1); } /* }}} */ /* {{{ proto string getOs() */ PHP_METHOD(PerforceClient, getOs) { PHP_PERFORCE_FETCH(perforce, getThis()); const StrPtr os(perforce->client->GetOs()); RETURN_STRINGL(os.Text(), os.Length(), 1); } /* }}} */ /* {{{ proto bool init() Establish the connection. */ PHP_METHOD(PerforceClient, init) { PHP_PERFORCE_FETCH(perforce, getThis()); Error error; 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_FETCH(perforce, getThis()); int error_count = 0; Error error; 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_FETCH(perforce, getThis()); RETURN_BOOL(perforce->client->Dropped() != 0); } /* }}} */ /* {{{ proto bool setArgs(string $arg1[, string ...]) Set the arguments for the next Perforce command. */ PHP_METHOD(PerforceClient, setArgs) { PHP_PERFORCE_FETCH(perforce, getThis()); zval ***args, **arg; char **argv; int argc, i = 0; argc = ZEND_NUM_ARGS(); if (argc < 1) { WRONG_PARAM_COUNT; } /* Copy all of the PHP arguments into local storage. */ args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0); if (zend_get_parameters_array_ex(argc, args) == FAILURE) { efree(args); WRONG_PARAM_COUNT; } if (argc == 1 && Z_TYPE_PP(args[0]) == IS_ARRAY) { zval *array = *args[0]; /* Allocate the argument array that will be passed to Perforce. */ argc = zend_hash_num_elements(Z_ARRVAL_P(array)); argv = (char **) emalloc(sizeof(char *) * argc); /* * We've been passed an array of values. Iterate over the array's * contents and copy string representations of the values into the * arguments array. */ while (zend_hash_get_current_data(Z_ARRVAL_P(array), (void **)&arg) == SUCCESS) { convert_to_string_ex(arg); argv[i++] = Z_STRVAL_PP(arg); zend_hash_move_forward(Z_ARRVAL_P(array)); } } else { /* Allocate the argument array that will be passed to Perforce. */ argv = (char **) emalloc(sizeof(char *) * argc); /* * Simply copy string representations of the PHP values into the * arguments array. */ for (; i < argc; ++i) { arg = args[i]; convert_to_string_ex(arg); argv[i] = Z_STRVAL_PP(arg); } } perforce->client->SetArgv(argc, argv); efree(args); efree(argv); RETURN_TRUE; } /* }}} */ /* {{{ proto bool run(string command) Run a Perforce command. */ PHP_METHOD(PerforceClient, run) { PHP_PERFORCE_FETCH(perforce, getThis()); char *command; int len; if (zend_parse_parameters(1 TSRMLS_CC, "s", &command, &len) == FAILURE) { return; } perforce->client->Run(command); RETURN_TRUE; } /* }}} */ /* {{{ Argument Info */ ZEND_BEGIN_ARG_INFO_EX(arginfo_none, 0, 0, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_ui, 0, 0, 1) ZEND_ARG_INFO(0, ui) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_port, 0, 0, 1) ZEND_ARG_INFO(0, port) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_user, 0, 0, 1) ZEND_ARG_INFO(0, user) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_password, 0, 0, 1) ZEND_ARG_INFO(0, password) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_client, 0, 0, 1) ZEND_ARG_INFO(0, client) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_protocol_value, 0, 0, 2) ZEND_ARG_INFO(0, protocol) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_protocol, 0, 0, 1) ZEND_ARG_INFO(0, protocol) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_cwd, 0, 0, 1) ZEND_ARG_INFO(0, cwd) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_charset, 0, 0, 1) ZEND_ARG_INFO(0, charset) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_host, 0, 0, 1) ZEND_ARG_INFO(0, host) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_name, 0, 0, 1) ZEND_ARG_INFO(0, name) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_language, 0, 0, 1) ZEND_ARG_INFO(0, language) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_filename, 0, 0, 1) ZEND_ARG_INFO(0, filename) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_command, 0, 0, 1) ZEND_ARG_INFO(0, command) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_message, 0, 0, 1) ZEND_ARG_INFO(0, message) ZEND_END_ARG_INFO() 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() 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() ZEND_BEGIN_ARG_INFO_EX(arginfo_data, 0, 0, 1) ZEND_ARG_INFO(0, data) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_tags, 0, 0, 1) ZEND_ARG_INFO(0, tags) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_file, 0, 0, 1) ZEND_ARG_INFO(0, file) ZEND_END_ARG_INFO() 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() 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, arginfo_ui, 0) PHP_ME(PerforceClient, setPort, arginfo_port, 0) PHP_ME(PerforceClient, getPort, arginfo_none, 0) PHP_ME(PerforceClient, setUser, arginfo_user, 0) PHP_ME(PerforceClient, getUser, arginfo_none, 0) PHP_ME(PerforceClient, setPassword, arginfo_password, 0) PHP_ME(PerforceClient, getPassword, arginfo_none, 0) PHP_ME(PerforceClient, setClient, arginfo_client, 0) PHP_ME(PerforceClient, getClient, arginfo_none, 0) PHP_ME(PerforceClient, setProtocol, arginfo_protocol_value, 0) PHP_ME(PerforceClient, getProtocol, arginfo_protocol, 0) PHP_ME(PerforceClient, setCwd, arginfo_cwd, 0) PHP_ME(PerforceClient, getCwd, arginfo_none, 0) PHP_ME(PerforceClient, setCharset, arginfo_charset, 0) PHP_ME(PerforceClient, getCharset, arginfo_none, 0) PHP_ME(PerforceClient, setHost, arginfo_host, 0) PHP_ME(PerforceClient, getHost, arginfo_none, 0) PHP_ME(PerforceClient, setProg, arginfo_name, 0) PHP_ME(PerforceClient, getConfig, arginfo_none, 0) PHP_ME(PerforceClient, setTicketFile, arginfo_filename, 0) PHP_ME(PerforceClient, setLanguage, arginfo_language, 0) PHP_ME(PerforceClient, getLanguage, arginfo_none, 0) PHP_ME(PerforceClient, getOs, arginfo_none, 0) PHP_ME(PerforceClient, init, arginfo_none, 0) PHP_ME(PerforceClient, final, arginfo_none, 0) PHP_ME(PerforceClient, dropped, arginfo_none, 0) PHP_ME(PerforceClient, setArgs, NULL, 0) PHP_ME(PerforceClient, run, arginfo_command, 0) {NULL, NULL, NULL, 0} }; /* }}} */ /* {{{ perforce_clientuser_methods[] */ static zend_function_entry perforce_clientuser_methods[] = { PHP_ABSTRACT_ME(PerforceClientUser, InputData, NULL) PHP_ABSTRACT_ME(PerforceClientUser, HandleError,arginfo_message_severity) PHP_ABSTRACT_ME(PerforceClientUser, Message, arginfo_message_severity) PHP_ABSTRACT_ME(PerforceClientUser, OutputError, arginfo_message) PHP_ABSTRACT_ME(PerforceClientUser, OutputInfo, arginfo_level_data) PHP_ABSTRACT_ME(PerforceClientUser, OutputBinary, arginfo_data) PHP_ABSTRACT_ME(PerforceClientUser, OutputText, arginfo_data) PHP_ABSTRACT_ME(PerforceClientUser, OutputStat, arginfo_tags) PHP_ABSTRACT_ME(PerforceClientUser, Prompt, arginfo_message) PHP_ABSTRACT_ME(PerforceClientUser, ErrorPause, arginfo_message) PHP_ABSTRACT_ME(PerforceClientUser, Edit, arginfo_file) PHP_ABSTRACT_ME(PerforceClientUser, Diff, arginfo_diff) PHP_ABSTRACT_ME(PerforceClientUser, Merge, arginfo_merge) PHP_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), "1.0", STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_PERFORCE BEGIN_EXTERN_C() ZEND_GET_MODULE(perforce) END_EXTERN_C() #endif /* }}} */ /* {{{ perforce_object_destroy(void *object, zend_object_handle handle TSRMLS_DC) */ static void perforce_object_destroy(void *object, zend_object_handle handle TSRMLS_DC) { php_perforce_object *perforce = (php_perforce_object *)object; if (perforce->client) { perforce->client->~ClientApi(); efree(perforce->client); } if (perforce->user) { perforce->user->~PHPClientUser(); efree(perforce->user); } } /* }}} */ /* {{{ perforce_object_free(void *object TSRMLS_DC) */ static void perforce_object_free(void *object TSRMLS_DC) { php_perforce_object *perforce = (php_perforce_object *)object; efree(perforce); } /* }}} */ /* {{{ perforce_object_create(zend_class_entry *ce TSRMLS_DC) */ static zend_object_value perforce_object_create(zend_class_entry *ce TSRMLS_DC) { zval *tmp; php_perforce_object *perforce; zend_object_value retval; /* Allocate and initialize the PHP Perforce object structure. */ perforce = (php_perforce_object *)emalloc(sizeof(php_perforce_object)); memset(&perforce->base, 0, sizeof(zend_object)); perforce->client = NULL; perforce->user = NULL; zend_object_std_init(&perforce->base, ce TSRMLS_CC); zend_hash_copy(perforce->base.properties, &ce->default_properties, (copy_ctor_func_t)zval_add_ref, (void *) &tmp, sizeof(zval *)); /* Add this instance to the objects store using the Zend Objects API. */ retval.handle = zend_objects_store_put(perforce, perforce_object_destroy, perforce_object_free, NULL TSRMLS_CC); retval.handlers = &perforce_object_handlers; /* Return the object reference to the caller. */ return retval; } /* }}} */ /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(perforce) { zend_class_entry ce; memcpy(&perforce_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); perforce_object_handlers.clone_obj = NULL; INIT_CLASS_ENTRY(ce, "PerforceClient", perforce_methods); perforce_client_ce = zend_register_internal_class(&ce TSRMLS_CC); perforce_client_ce->create_object = perforce_object_create; 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; 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. |