Skip to content

Commit

Permalink
Implement chaining support and prep.command2.
Browse files Browse the repository at this point in the history
  • Loading branch information
andreiz committed Jul 8, 2010
1 parent c6a8645 commit 9b6ce42
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 118 deletions.
6 changes: 3 additions & 3 deletions TODO
Expand Up @@ -6,15 +6,15 @@
* - Change prep.command to be a formattable string:
* - %s: source, %o: original
* - error out if %s is not found
* - Allow multiple prep.command INI registrations
* - result of one command feeds back into the same tempfile for the next
* (if there's > 1)
*
* FIXME:
* - Add tmpfile handle to PREP_G that gets cleared out on RSHUTDOWN
* - (to keep the file from auto-deleting, so scripts can introspect/debug)
*
* DONE:
* - Allow multiple prep.command INI registrations
* - result of one command feeds back into the same tempfile for the next
* (if there's > 1)
* - Add optional module dependencies on APC, xdebug, xhprof, and whatever else screws
* with the compile_file()
* - Handle shebang (only in CLI):
Expand Down
8 changes: 7 additions & 1 deletion examples/ws-decode.php 100644 → 100755
@@ -1,8 +1,14 @@
#!/usr/bin/env php
<?php
define('ZERO', chr(9));
define('ONE', chr(32));
define('WIDTH', 8);
$dat = str_replace("\n", '', file_get_contents('php://stdin'));
if (isset($argv[1])) {
$source = $argv[1];
} else {
$source = 'php://stdin';
}
$dat = str_replace("\n", '', file_get_contents($source));
$max = strlen($dat);
for ($i=0; $i<$max; $i+=WIDTH) {
$chr = substr($dat, $i, WIDTH);
Expand Down
8 changes: 7 additions & 1 deletion examples/ws-encode.php 100644 → 100755
@@ -1,8 +1,14 @@
#!/usr/bin/env php
<?php
define('ZERO', chr(9));
define('ONE', chr(32));
define('WIDTH', 8);
$dat = file_get_contents('php://stdin');
if (isset($argv[1])) {
$source = $argv[1];
} else {
$source = 'php://stdin';
}
$dat = file_get_contents($source);
$max = strlen($dat);
$buf = '';
for ($i=0; $i<$max; $i++) {
Expand Down
253 changes: 140 additions & 113 deletions prep.c
Expand Up @@ -61,7 +61,7 @@ ZEND_GET_MODULE(prep)
/* {{{ INI entries */
static PHP_INI_MH(OnUpdateCommand)
{
char **p;
HashTable *commands;
#ifndef ZTS
char *base = (char *) mh_arg2;
#else
Expand All @@ -74,173 +74,200 @@ static PHP_INI_MH(OnUpdateCommand)
return FAILURE;
}

p = (char **) (base+(size_t) mh_arg1);
commands = (HashTable *) (base+(size_t) mh_arg1);
zend_hash_next_index_insert(commands, &new_value, sizeof(char *), NULL);

*p = new_value;
return SUCCESS;
}

PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("prep.command", "", PHP_INI_PERDIR, OnUpdateString, prep_command, zend_prep_globals, prep_globals)
STD_PHP_INI_ENTRY("prep.command", "", PHP_INI_PERDIR, OnUpdateCommand, commands, zend_prep_globals, prep_globals)
STD_PHP_INI_ENTRY("prep.command2","", PHP_INI_PERDIR, OnUpdateCommand, commands, zend_prep_globals, prep_globals)
PHP_INI_END()
/* }}} */


static zend_op_array *prep_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC) /* {{{ */
{
zend_op_array *res;
char *resolved_path = NULL;
zend_file_handle f;
zend_file_handle orig_file_handle;
int failed = 0;
char *new_file = NULL, *command = NULL;
char *output_file = NULL, *command = NULL;
php_stream *tmp_stream = NULL;
char *err_extra = NULL;
char *env_suppress = NULL;
char *prep_command;
char **prep_command = NULL;
HashTable *commands = &PREP_G(commands);

env_suppress = getenv("PHP_SUPPRESS_PREP");

if (!(prep_command && prep_command[0]) ||
env_suppress != NULL ||
if (zend_hash_num_elements(commands) == 0 || env_suppress != NULL ||
!file_handle || !file_handle->filename) {

return prep_orig_compile_file(file_handle, type TSRMLS_CC);
}

putenv("PHP_SUPPRESS_PREP=1");
f = *file_handle;
orig_file_handle = *file_handle;
resolved_path = zend_resolve_path(file_handle->filename, strlen(file_handle->filename) TSRMLS_CC);
if (resolved_path) {
char *input_file;
FILE *fp;
char *result = NULL;
char *output = NULL;
int num_written = 0;
long maxlen = PHP_STREAM_COPY_ALL, result_len;
long maxlen = PHP_STREAM_COPY_ALL, output_len;
php_stream *in_stream;
long offset = 0;
int exit_status = 0;
int command_len;
int replace_count = 0;

command = php_str_to_str_ex(prep_command, strlen(prep_command), "%s", sizeof("%s")-1,
resolved_path, strlen(resolved_path), &command_len, 0, &replace_count);
if (replace_count > 0) {
char *tmp = command;
/* XXX modify to use temp file in chain */
command = php_str_to_str_ex(tmp, command_len, "%o", sizeof("%o")-1,
resolved_path, strlen(resolved_path), &command_len, 0, NULL);
efree(tmp);
} else {
efree(command);
command = NULL;
spprintf(&command, 0, "%s %s", prep_command, resolved_path);
}
input_file = estrdup(resolved_path);
zend_hash_internal_pointer_reset(commands);
while (zend_hash_get_current_data(commands, (void **)&prep_command) == SUCCESS) {

fp = VCWD_POPEN(command, "r");
if (!fp) {
failed = 1;
goto prep_skip;
}
in_stream = php_stream_fopen_from_pipe(fp, "r");
if (command) {
efree(command);
}
command = php_str_to_str_ex(*prep_command, strlen(*prep_command), "%s", sizeof("%s")-1,
input_file, strlen(input_file), &command_len, 0, &replace_count);
if (replace_count > 0) {
char *tmp = command;
command = php_str_to_str_ex(tmp, command_len, "%o", sizeof("%o")-1,
resolved_path, strlen(resolved_path), &command_len, 0, NULL);
efree(tmp);
} else {
efree(command);
command = NULL;
spprintf(&command, 0, "%s %s", *prep_command, input_file);
}

if (in_stream == NULL) {
failed = 1;
goto prep_skip;
}
fp = VCWD_POPEN(command, "r");
if (!fp) {
failed = 1;
break;
}
in_stream = php_stream_fopen_from_pipe(fp, "r");

result_len = php_stream_copy_to_mem(in_stream, &result, maxlen, 0);
exit_status = php_stream_close(in_stream);
if (in_stream == NULL) {
failed = 1;
break;
}

if (!result) {
/* could not read file (e.g. might be a directory);
* skip preprocessing */
goto prep_skip;
}
output_len = php_stream_copy_to_mem(in_stream, &output, maxlen, 0);
exit_status = php_stream_close(in_stream);

if (PREP_EXIT_PHP_FALE == exit_status) {
failed = 1;
err_extra = result;
goto prep_skip;
} else if (PREP_EXIT_SKIP == exit_status) {
if (result) {
efree(result);
if (!output) {
/* could not read file (e.g. might be a directory);
* skip preprocessing */
break;
}
goto prep_skip;
}

/* eat up shebang in CLI mode */
if (!strcmp(sapi_module.name, "cli")) {
char *ptr = result;

CG(start_lineno) = 1;
if (*ptr == '#' && *++ptr == '!') {
do {
ptr++;
} while (*ptr != '\n' && *ptr != '\r' && *ptr != 0);
if (PREP_EXIT_PHP_FALE == exit_status) {
failed = 1;
err_extra = output;
break;
} else if (PREP_EXIT_SKIP == exit_status) {
if (output) {
efree(output);
}
break;
}

/* handle situations where line is terminated by \r\n */
if (*ptr++ == '\r' && *ptr++ != '\n') {
ptr--;
/* eat up shebang in CLI mode */
if (!strcmp(sapi_module.name, "cli")) {
char *ptr = output;

CG(start_lineno) = 1;
if (*ptr == '#' && *++ptr == '!') {
do {
ptr++;
} while (*ptr != '\n' && *ptr != '\r' && *ptr != 0);

/* handle situations where line is terminated by \r\n */
if (*ptr++ == '\r' && *ptr++ != '\n') {
ptr--;
}
offset = ptr-output;
}
offset = ptr-result;
}
}

tmp_stream = php_stream_fopen_tmpfile();
num_written = php_stream_write(tmp_stream, result+offset, result_len-offset);
efree(result);
if (num_written != result_len-offset) {
failed = 1;
goto prep_skip;
}
new_file = estrdup(tmp_stream->orig_path);

/* add entry to hashtable */
/* XXX
if (zend_hash_add(&PREP_G(orig_files), real_path, strlen(real_path),
(void*)&new_file, sizeof(char *), NULL) == FAILURE) {
failed = 1;
goto prep_skip;
}
*/
if (tmp_stream) {
php_stream_close(tmp_stream);
}
tmp_stream = php_stream_fopen_tmpfile();
num_written = php_stream_write(tmp_stream, output+offset, output_len-offset);
efree(output);
if (num_written != output_len-offset) {
failed = 1;
break;
}

if (SUCCESS == zend_stream_open_function((const char *)new_file, file_handle TSRMLS_CC)) {
file_handle->filename = f.filename;
if (file_handle->opened_path) {
efree(file_handle->opened_path);
if (output_file) {
efree(output_file);
}
file_handle->opened_path = estrdup(resolved_path);
file_handle->free_filename = f.free_filename;
if (f.opened_path) {
efree(f.opened_path);
if (input_file) {
efree(input_file);
}
} else {
*file_handle = f;
}
}
output_file = estrdup(tmp_stream->orig_path);
input_file = estrdup(output_file);

prep_skip:
if (tmp_stream) {
php_stream_close(tmp_stream);
}
zend_hash_move_forward(commands);
}

if (failed) {
unsetenv("PHP_SUPPRESS_PREP");
if (err_extra) {
php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Could not run preprocessor %s on %s: %s", prep_command, resolved_path, err_extra);
efree(err_extra);
if (failed) {
unsetenv("PHP_SUPPRESS_PREP");
if (err_extra) {
php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Could not run preprocessor command %s: %s", command, err_extra);
efree(err_extra);
} else {
php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Could not run preprocessor command %s", command);
}
} else {
php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Could not run preprocessor %s on %s", prep_command, resolved_path);
/* add entry to hashtable */
/* XXX
if (zend_hash_add(&PREP_G(orig_files), real_path, strlen(real_path),
(void*)&output_file, sizeof(char *), NULL) == FAILURE) {
failed = 1;
goto prep_skip;
}
*/

if (output_file) {
if (SUCCESS == zend_stream_open_function((const char *)output_file, file_handle TSRMLS_CC)) {
file_handle->filename = orig_file_handle.filename;
if (file_handle->opened_path) {
efree(file_handle->opened_path);
}
file_handle->opened_path = estrdup(resolved_path);
file_handle->free_filename = orig_file_handle.free_filename;
if (orig_file_handle.opened_path) {
efree(orig_file_handle.opened_path);
}
} else {
*file_handle = orig_file_handle;
}
}
}
}

if (new_file) {
efree(new_file);
}
if (resolved_path) {
efree(resolved_path);
if (input_file) {
efree(input_file);
}
if (output_file) {
efree(output_file);
}
if (tmp_stream) {
php_stream_close(tmp_stream);
}
if (command) {
efree(command);
}

}
if (command) {
efree(command);
}

/* XXX register a clean up handler on script shutdown to remove the temporary file */

zend_try {
failed = 0;
Expand All @@ -260,7 +287,7 @@ static zend_op_array *prep_compile_file(zend_file_handle *file_handle, int type

static void prep_init_globals(zend_prep_globals *prep_globals_p TSRMLS_DC) /* {{{ */
{
zend_hash_init(&PREP_G(commands), 1, NULL, (dtor_func_t)free, 1);
zend_hash_init(&PREP_G(commands), 1, NULL, NULL, 1);
}
/* }}} */

Expand Down

0 comments on commit 9b6ce42

Please sign in to comment.