checkAndWriteIfNeeded() public static method

Checks if the content of the file on the disk is the same as the content.
public static checkAndWriteIfNeeded ( $content, $path ) : boolean
$content
$path
return boolean
Esempio n. 1
0
 /**
  * Create project.c and project.h according to the current extension
  *
  * @param string $project
  *
  * @throws Exception
  * @return boolean
  * TODO: Move the part of the logic which depends on templates (backend-specific) to backend?
  */
 public function createProjectFiles($project)
 {
     $needConfigure = $this->checkKernelFiles();
     $templatePath = $this->backend->getInternalTemplatePath();
     /**
      * project.c
      */
     $content = file_get_contents($templatePath . '/project.c');
     if (empty($content)) {
         throw new Exception("Template project.c doesn't exist");
     }
     $includes = '';
     $destructors = '';
     $files = array_merge($this->files, $this->anonymousFiles);
     /**
      * Round 1. Calculate the dependency rank
      */
     $this->calculateDependencies($files);
     $classEntries = array();
     $classInits = array();
     $interfaceEntries = array();
     $interfaceInits = array();
     /**
      * Round 2. Generate the ZEPHIR_INIT calls according to the dependency rank
      */
     foreach ($files as $file) {
         if (!$file->isExternal()) {
             $classDefinition = $file->getClassDefinition();
             if ($classDefinition) {
                 $dependencyRank = $classDefinition->getDependencyRank();
                 if ($classDefinition->getType() == 'class') {
                     if (!isset($classInits[$dependencyRank])) {
                         $classEntries[$dependencyRank] = array();
                         $classInits[$dependencyRank] = array();
                     }
                     $classEntries[$dependencyRank][] = 'zend_class_entry *' . $classDefinition->getClassEntry() . ';';
                     $classInits[$dependencyRank][] = 'ZEPHIR_INIT(' . $classDefinition->getCNamespace() . '_' . $classDefinition->getName() . ');';
                 } else {
                     if (!isset($interfaceInits[$dependencyRank])) {
                         $interfaceEntries[$dependencyRank] = array();
                         $interfaceInits[$dependencyRank] = array();
                     }
                     $interfaceEntries[$dependencyRank][] = 'zend_class_entry *' . $classDefinition->getClassEntry() . ';';
                     $interfaceInits[$dependencyRank][] = 'ZEPHIR_INIT(' . $classDefinition->getCNamespace() . '_' . $classDefinition->getName() . ');';
                 }
             }
         }
     }
     krsort($classInits);
     krsort($classEntries);
     krsort($interfaceInits);
     krsort($interfaceEntries);
     $completeInterfaceInits = array();
     foreach ($interfaceInits as $rankInterfaceInits) {
         asort($rankInterfaceInits, SORT_STRING);
         $completeInterfaceInits = array_merge($completeInterfaceInits, $rankInterfaceInits);
     }
     $completeInterfaceEntries = array();
     foreach ($interfaceEntries as $rankInterfaceEntries) {
         asort($rankInterfaceEntries, SORT_STRING);
         $completeInterfaceEntries = array_merge($completeInterfaceEntries, $rankInterfaceEntries);
     }
     $completeClassInits = array();
     foreach ($classInits as $rankClassInits) {
         asort($rankClassInits, SORT_STRING);
         $completeClassInits = array_merge($completeClassInits, $rankClassInits);
     }
     $completeClassEntries = array();
     foreach ($classEntries as $rankClassEntries) {
         asort($rankClassEntries, SORT_STRING);
         $completeClassEntries = array_merge($completeClassEntries, $rankClassEntries);
     }
     /**
      * Round 3. Process extension globals
      */
     list($globalCode, $globalStruct, $globalsDefault, $initEntries) = $this->processExtensionGlobals($project);
     if ($project == 'zend') {
         $safeProject = 'zend_';
     } else {
         $safeProject = $project;
     }
     /**
      * Round 4. Process extension info
      */
     $phpInfo = $this->processExtensionInfo();
     /**
      * Round 5. Generate Function entries (FE)
      */
     list($feHeader, $feEntries) = $this->generateFunctionInformation();
     /**
      * Check if there are module/request/global destructors
      */
     $destructors = $this->config->get('destructors');
     if (is_array($destructors)) {
         $invokeDestructors = $this->processCodeInjection($destructors);
         $includes = $invokeDestructors[0];
         $destructors = $invokeDestructors[1];
     }
     /**
      * Check if there are module/request/global initializers
      */
     $initializers = $this->config->get('initializers');
     if (is_array($initializers)) {
         $invokeInitializers = $this->processCodeInjection($initializers);
         $includes = $invokeInitializers[0];
         $initializers = $invokeInitializers[1];
     }
     /**
      * Append extra details
      */
     $extraClasses = $this->config->get('extra-classes');
     if (is_array($extraClasses)) {
         foreach ($extraClasses as $value) {
             if (isset($value['init'])) {
                 $completeClassInits[] = 'ZEPHIR_INIT(' . $value['init'] . ')';
             }
             if (isset($value['entry'])) {
                 $completeClassEntries[] = 'zend_class_entry *' . $value['entry'] . ';';
             }
         }
     }
     $toReplace = array('%PROJECT_LOWER_SAFE%' => strtolower($safeProject), '%PROJECT_LOWER%' => strtolower($project), '%PROJECT_UPPER%' => strtoupper($project), '%PROJECT_CAMELIZE%' => ucfirst($project), '%CLASS_ENTRIES%' => implode(PHP_EOL, array_merge($completeInterfaceEntries, $completeClassEntries)), '%CLASS_INITS%' => implode(PHP_EOL . "\t", array_merge($completeInterfaceInits, $completeClassInits)), '%INIT_GLOBALS%' => $globalsDefault, '%EXTENSION_INFO%' => $phpInfo, '%EXTRA_INCLUDES%' => $includes, '%DESTRUCTORS%' => $destructors, '%INITIALIZERS%' => implode(PHP_EOL, array_merge($this->internalInitializers, array($initializers))), '%FE_HEADER%' => $feHeader, '%FE_ENTRIES%' => $feEntries, '%PROJECT_INI_ENTRIES%' => implode(PHP_EOL . "\t", $initEntries));
     foreach ($toReplace as $mark => $replace) {
         $content = str_replace($mark, $replace, $content);
     }
     /**
      * Round 5. Generate and place the entry point of the project
      */
     Utils::checkAndWriteIfNeeded($content, 'ext/' . $safeProject . '.c');
     unset($content);
     /**
      * Round 6. Generate the project main header
      */
     $content = file_get_contents($templatePath . '/project.h');
     if (empty($content)) {
         throw new Exception("Template project.h doesn't exists");
     }
     $includeHeaders = array();
     foreach ($this->compiledFiles as $file) {
         if ($file) {
             $fileH = str_replace(".c", ".zep.h", $file);
             $include = '#include "' . $fileH . '"';
             $includeHeaders[] = $include;
         }
     }
     /**
      * Append extra headers
      */
     $extraClasses = $this->config->get('extra-classes');
     if (is_array($extraClasses)) {
         foreach ($extraClasses as $value) {
             if (isset($value['header'])) {
                 $include = '#include "' . $value['header'] . '"';
                 $includeHeaders[] = $include;
             }
         }
     }
     $toReplace = array('%INCLUDE_HEADERS%' => implode(PHP_EOL, $includeHeaders));
     foreach ($toReplace as $mark => $replace) {
         $content = str_replace($mark, $replace, $content);
     }
     Utils::checkAndWriteIfNeeded($content, 'ext/' . $safeProject . '.h');
     unset($content);
     /**
      * Round 7. Create php_project.h
      */
     $content = file_get_contents($templatePath . '/php_project.h');
     if (empty($content)) {
         throw new Exception('Template php_project.h doesn`t exist');
     }
     $toReplace = array('%PROJECT_LOWER_SAFE%' => strtolower($safeProject), '%PROJECT_LOWER%' => strtolower($project), '%PROJECT_UPPER%' => strtoupper($project), '%PROJECT_EXTNAME%' => strtolower($project), '%PROJECT_NAME%' => utf8_decode($this->config->get('name')), '%PROJECT_AUTHOR%' => utf8_decode($this->config->get('author')), '%PROJECT_VERSION%' => utf8_decode($this->config->get('version')), '%PROJECT_DESCRIPTION%' => utf8_decode($this->config->get('description')), '%PROJECT_ZEPVERSION%' => self::VERSION, '%EXTENSION_GLOBALS%' => $globalCode, '%EXTENSION_STRUCT_GLOBALS%' => $globalStruct);
     foreach ($toReplace as $mark => $replace) {
         $content = str_replace($mark, $replace, $content);
     }
     Utils::checkAndWriteIfNeeded($content, 'ext/php_' . $safeProject . '.h');
     unset($content);
     return $needConfigure;
 }
Esempio n. 2
0
 public function genFcallCode()
 {
     $codePrinter = new CodePrinter();
     $codePrinter->output('#ifndef ZEPHIR_KERNEL_FCALL_INTERNAL_H');
     $codePrinter->output('#define ZEPHIR_KERNEL_FCALL_INTERNAL_H');
     $codePrinter->increaseLevel();
     ksort($this->requiredMacros);
     foreach ($this->requiredMacros as $name => $info) {
         list($scope, $mode, $paramCount) = $info;
         $paramsStr = '';
         $retParam = '';
         $retValueUsed = '0';
         $params = array();
         $zvals = array();
         $initStatements = array();
         $postStatements = array();
         for ($i = 0; $i < $paramCount; ++$i) {
             $params[] = 'p' . $i;
         }
         if ($paramCount) {
             $paramsStr = ', ' . implode(', ', $params);
         }
         if ($mode == 'CALL_INTERNAL_METHOD_P') {
             $retValueUsed = '1';
             $retParam = 'return_value_ptr';
             $initStatements[] = 'ZEPHIR_INIT_NVAR(*(return_value_ptr)); \\';
         }
         $objParam = $scope ? 'scope_ce, ' : 'object, ';
         $macroName = $name . '(' . ($retParam ? $retParam . ', ' : '') . $objParam . 'method' . $paramsStr . ')';
         $codePrinter->output('#define ' . $macroName . ' \\');
         if (!$retParam) {
             $retParam = 'return_value';
         }
         $codePrinter->increaseLevel();
         $codePrinter->output('do { \\');
         $codePrinter->increaseLevel();
         if ($mode == 'CALL_INTERNAL_METHOD_NORETURN_P') {
             $codePrinter->output('zval *rv = NULL; \\');
             $codePrinter->output('zval **rvp = &rv; \\');
             $codePrinter->output('ALLOC_INIT_ZVAL(rv); \\');
             $retParam = 'rvp';
         }
         $codePrinter->output('ZEPHIR_BACKUP_SCOPE() \\');
         $codePrinter->output('ZEPHIR_BACKUP_THIS_PTR() \\');
         if (!$scope) {
             $codePrinter->output('ZEPHIR_SET_THIS(object); \\');
             $codePrinter->output('ZEPHIR_SET_SCOPE((Z_TYPE_P(object) == IS_OBJECT ? Z_OBJCE_P(object) : NULL), (Z_TYPE_P(object) == IS_OBJECT ? Z_OBJCE_P(object) : NULL)); \\');
         } else {
             $codePrinter->output('ZEPHIR_SET_THIS(NULL); \\');
             $codePrinter->output('ZEPHIR_SET_SCOPE(scope_ce, scope_ce); \\');
         }
         /* Create new zval's for parameters */
         for ($i = 0; $i < $paramCount; ++$i) {
             //$zv = '_' . $params[$i];
             //$zvals[] = $zv;
             //$initStatements[] = 'ALLOC_ZVAL(' . $zv . '); \\';
             //$initStatements[] = 'INIT_PZVAL_COPY(' . $zv . ', ' . $params[$i] . '); \\';
             //$postStatements[] = 'zval_ptr_dtor(&' . $zv . '); \\';
             $zv = $params[$i];
             $zvals[] = $zv;
             $initStatements[] = 'Z_ADDREF_P(' . $zv . '); \\';
             $postStatements[] = 'Z_DELREF_P(' . $zv . '); \\';
         }
         if ($i) {
             //$codePrinter->output('zval *' . implode(', *', $zvals) . '; \\');
         }
         foreach ($initStatements as $statement) {
             $codePrinter->output($statement);
         }
         $zvalStr = $i ? ', ' . implode(', ', $zvals) : '';
         $retExpr = '';
         if ($retParam) {
             if ($retParam == 'return_value') {
                 $retExpr = ', return_value, return_value_ptr';
             } else {
                 $retExpr = ', *' . $retParam . ', ' . $retParam;
             }
         }
         $codePrinter->output('method(0' . $retExpr . ', ' . ($scope ? 'NULL, ' : $objParam) . $retValueUsed . $zvalStr . ' TSRMLS_CC); \\');
         if ($mode == 'CALL_INTERNAL_METHOD_NORETURN_P') {
             $postStatements[] = 'zval_ptr_dtor(rvp); \\';
         }
         foreach ($postStatements as $statement) {
             $codePrinter->output($statement);
         }
         $codePrinter->output('ZEPHIR_LAST_CALL_STATUS = EG(exception) ? FAILURE : SUCCESS; \\');
         $codePrinter->output('ZEPHIR_RESTORE_THIS_PTR(); \\');
         $codePrinter->output('ZEPHIR_RESTORE_SCOPE(); \\');
         $codePrinter->decreaseLevel();
         $codePrinter->output('} while (0)');
         $codePrinter->decreaseLevel();
         $codePrinter->output('');
     }
     $codePrinter->decreaseLevel();
     $codePrinter->output("#endif");
     Utils::checkAndWriteIfNeeded($codePrinter->getOutput(), 'ext/kernel/fcall_internal.h');
 }
Esempio n. 3
0
 /**
  * Create project.c and project.h by compiled files to test extension
  *
  * @param string $project
  *
  * @throws Exception
  * @return boolean
  */
 public function createProjectFiles($project)
 {
     $needConfigure = $this->checkKernelFiles();
     /**
      * project.c
      */
     $content = file_get_contents(__DIR__ . '/../templates/project.c');
     if (empty($content)) {
         throw new Exception("Template project.c doesn't exist");
     }
     $files = $this->files;
     /**
      * Round 1. Calculate the dependency rank
      * Classes are ordered according to a dependency ranking
      * Classes that are dependencies of classes that are dependency of other classes
      * have more weight
      */
     foreach ($files as $file) {
         $classDefinition = $file->getClassDefinition();
         if ($classDefinition) {
             $classDefinition->calculateDependencyRank();
         }
     }
     /**
      * Round 1.5 Make a second pass to ensure classes will have the correct weight
      */
     foreach ($files as $file) {
         $classDefinition = $file->getClassDefinition();
         if ($classDefinition) {
             $classDefinition->calculateDependencyRank();
         }
     }
     $classEntries = array();
     $classInits = array();
     $interfaceEntries = array();
     $interfaceInits = array();
     /**
      * Round 2. Generate the ZEPHIR_INIT calls according to the dependency rank
      */
     foreach ($files as $file) {
         $classDefinition = $file->getClassDefinition();
         if ($classDefinition) {
             $dependencyRank = $classDefinition->getDependencyRank();
             if ($classDefinition->getType() == 'class') {
                 if (!isset($classInits[$dependencyRank])) {
                     $classEntries[$dependencyRank] = array();
                     $classInits[$dependencyRank] = array();
                 }
                 $classEntries[$dependencyRank][] = 'zend_class_entry *' . $classDefinition->getClassEntry() . ';';
                 $classInits[$dependencyRank][] = 'ZEPHIR_INIT(' . $classDefinition->getCNamespace() . '_' . $classDefinition->getName() . ');';
             } else {
                 if (!isset($interfaceInits[$dependencyRank])) {
                     $interfaceEntries[$dependencyRank] = array();
                     $interfaceInits[$dependencyRank] = array();
                 }
                 $interfaceEntries[$dependencyRank][] = 'zend_class_entry *' . $classDefinition->getClassEntry() . ';';
                 $interfaceInits[$dependencyRank][] = 'ZEPHIR_INIT(' . $classDefinition->getCNamespace() . '_' . $classDefinition->getName() . ');';
             }
         }
     }
     krsort($classInits);
     krsort($classEntries);
     krsort($interfaceInits);
     krsort($interfaceEntries);
     $completeInterfaceInits = array();
     foreach ($interfaceInits as $rankInterfaceInits) {
         asort($rankInterfaceInits, SORT_STRING);
         $completeInterfaceInits = array_merge($completeInterfaceInits, $rankInterfaceInits);
     }
     $completeInterfaceEntries = array();
     foreach ($interfaceEntries as $rankInterfaceEntries) {
         asort($rankInterfaceEntries, SORT_STRING);
         $completeInterfaceEntries = array_merge($completeInterfaceEntries, $rankInterfaceEntries);
     }
     $completeClassInits = array();
     foreach ($classInits as $rankClassInits) {
         asort($rankClassInits, SORT_STRING);
         $completeClassInits = array_merge($completeClassInits, $rankClassInits);
     }
     $completeClassEntries = array();
     foreach ($classEntries as $rankClassEntries) {
         asort($rankClassEntries, SORT_STRING);
         $completeClassEntries = array_merge($completeClassEntries, $rankClassEntries);
     }
     /**
      * Round 3. Process extension globals
      */
     list($globalCode, $globalStruct, $globalsDefault) = $this->processExtensionGlobals($project);
     if ($project == 'zend') {
         $safeProject = 'zend_';
     } else {
         $safeProject = $project;
     }
     /**
      * Round 4. Process extension info
      */
     $phpInfo = $this->processExtensionInfo();
     $toReplace = array('%PROJECT_LOWER_SAFE%' => strtolower($safeProject), '%PROJECT_LOWER%' => strtolower($project), '%PROJECT_UPPER%' => strtoupper($project), '%PROJECT_CAMELIZE%' => ucfirst($project), '%CLASS_ENTRIES%' => implode(PHP_EOL, array_merge($completeInterfaceEntries, $completeClassEntries)), '%CLASS_INITS%' => implode(PHP_EOL . "\t", array_merge($completeInterfaceInits, $completeClassInits)), '%INIT_GLOBALS%' => $globalsDefault, '%EXTENSION_INFO%' => $phpInfo);
     foreach ($toReplace as $mark => $replace) {
         $content = str_replace($mark, $replace, $content);
     }
     /**
      * Round 5. Generate and place the entry point of the project
      */
     Utils::checkAndWriteIfNeeded($content, 'ext/' . $safeProject . '.c');
     unset($content);
     /**
      * Round 6. Generate the project main header
      */
     $content = file_get_contents(__DIR__ . '/../templates/project.h');
     if (empty($content)) {
         throw new Exception("Template project.h doesn't exists");
     }
     $includeHeaders = array();
     foreach ($this->compiledFiles as $file) {
         if ($file) {
             $fileH = str_replace(".c", ".zep.h", $file);
             $include = '#include "' . $fileH . '"';
             $includeHeaders[] = $include;
         }
     }
     $toReplace = array('%INCLUDE_HEADERS%' => implode(PHP_EOL, $includeHeaders));
     foreach ($toReplace as $mark => $replace) {
         $content = str_replace($mark, $replace, $content);
     }
     Utils::checkAndWriteIfNeeded($content, 'ext/' . $safeProject . '.h');
     unset($content);
     /**
      * Round 7. Create php_project.h
      */
     $content = file_get_contents(__DIR__ . '/../templates/php_project.h');
     if (empty($content)) {
         throw new Exception('Template php_project.h doesn`t exist');
     }
     $toReplace = array('%PROJECT_LOWER_SAFE%' => strtolower($safeProject), '%PROJECT_LOWER%' => strtolower($project), '%PROJECT_UPPER%' => strtoupper($project), '%PROJECT_EXTNAME%' => strtolower($project), '%PROJECT_NAME%' => utf8_decode($this->config->get('name')), '%PROJECT_AUTHOR%' => utf8_decode($this->config->get('author')), '%PROJECT_VERSION%' => utf8_decode($this->config->get('version')), '%PROJECT_DESCRIPTION%' => utf8_decode($this->config->get('description')), '%PROJECT_ZEPVERSION%' => self::VERSION, '%EXTENSION_GLOBALS%' => $globalCode, '%EXTENSION_STRUCT_GLOBALS%' => $globalStruct);
     foreach ($toReplace as $mark => $replace) {
         $content = str_replace($mark, $replace, $content);
     }
     Utils::checkAndWriteIfNeeded($content, 'ext/php_' . $safeProject . '.h');
     unset($content);
     return $needConfigure;
 }
Esempio n. 4
0
    /**
     * Generates the concatenation code
     *
     * @return array
     */
    public function genConcatCode()
    {
        $code = '
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <php.h>
#include "php_ext.h"
#include <ext/standard/php_string.h>
#include "ext.h"
#include "kernel/main.h"
#include "kernel/memory.h"
#include "kernel/concat.h"' . PHP_EOL . PHP_EOL;
        $pcodeh = '
#ifndef ZEPHIR_KERNEL_CONCAT_H
#define ZEPHIR_KERNEL_CONCAT_H
#include <php.h>
#include <Zend/zend.h>
#include "kernel/main.h"
';
        $codeh = '';
        $macros = array();
        ksort($this->concatKeys, SORT_STRING);
        foreach ($this->concatKeys as $key => $one) {
            $len = strlen($key);
            $params = array();
            $zvalCopy = array();
            $useCopy = array();
            $avars = array();
            $zvars = array();
            $svars = array();
            $lengths = array();
            $sparams = array();
            $lparams = array();
            for ($i = 0; $i < $len; $i++) {
                $n = $i + 1;
                $t = substr($key, $i, 1);
                $sparams[] = 'op' . $n;
                if ($t == 's') {
                    $params[] = 'const char *op' . $n . ', zend_uint op' . $n . '_len';
                    $lparams[] = 'op' . $n . ', sizeof(op' . $n . ')-1';
                    $lengths[] = 'op' . $n . '_len';
                    $svars[] = $n;
                    $avars[$n] = 's';
                } else {
                    $params[] = 'zval *op' . $n;
                    $lparams[] = 'op' . $n;
                    $zvalCopy[] = 'op' . $n . '_copy';
                    $useCopy[] = 'use_copy' . $n . ' = 0';
                    $lengths[] = 'Z_STRLEN_P(op' . $n . ')';
                    $zvars[] = $n;
                    $avars[$n] = 'v';
                }
            }
            $macros[] = '#define ZEPHIR_CONCAT_' . strtoupper($key) . '(result, ' . join(', ', $sparams) . ') \\' . PHP_EOL . "\t" . ' zephir_concat_' . $key . '(result, ' . join(', ', $lparams) . ', 0);';
            $macros[] = '#define ZEPHIR_SCONCAT_' . strtoupper($key) . '(result, ' . join(', ', $sparams) . ') \\' . PHP_EOL . "\t" . ' zephir_concat_' . $key . '(result, ' . join(', ', $lparams) . ', 1);';
            $macros[] = '';
            $proto = 'void zephir_concat_' . $key . '(zval *result, ' . join(', ', $params) . ', int self_var)';
            $proto = 'void zephir_concat_' . $key . '(zval *result, ' . join(', ', $params) . ', int self_var)';
            $codeh .= '' . $proto . ';' . PHP_EOL;
            $code .= $proto . '{' . PHP_EOL . PHP_EOL;
            if (count($zvalCopy)) {
                $code .= "\t" . 'zval result_copy, ' . join(', ', $zvalCopy) . ';' . PHP_EOL;
                $code .= "\t" . 'int use_copy = 0, ' . join(', ', $useCopy) . ';' . PHP_EOL;
            } else {
                $code .= "\t" . 'zval result_copy;' . PHP_EOL;
                $code .= "\t" . 'int use_copy = 0;' . PHP_EOL;
            }
            $code .= "\t" . 'uint offset = 0, length;' . PHP_EOL . PHP_EOL;
            foreach ($zvars as $zvar) {
                $code .= "\t" . 'if (Z_TYPE_P(op' . $zvar . ') != IS_STRING) {' . PHP_EOL;
                $code .= "\t" . '   use_copy' . $zvar . ' = zend_make_printable_zval(op' . $zvar . ', &op' . $zvar . '_copy);' . PHP_EOL;
                $code .= "\t" . '   if (use_copy' . $zvar . ') {' . PHP_EOL;
                $code .= "\t" . '       op' . $zvar . ' = &op' . $zvar . '_copy;' . PHP_EOL;
                $code .= "\t" . '   }' . PHP_EOL;
                $code .= "\t" . '}' . PHP_EOL . PHP_EOL;
            }
            $code .= "\t" . 'length = ' . join(' + ', $lengths) . ';' . PHP_EOL;
            $code .= "\t" . 'if (self_var) {' . PHP_EOL;
            $code .= '' . PHP_EOL;
            $code .= "\t\t" . 'if (Z_TYPE_P(result) != IS_STRING) {' . PHP_EOL;
            $code .= "\t\t\t" . 'use_copy = zend_make_printable_zval(result, &result_copy);' . PHP_EOL;
            $code .= "\t\t\t" . 'if (use_copy) {' . PHP_EOL;
            $code .= "\t\t\t\t" . 'ZEPHIR_CPY_WRT_CTOR(result, (&result_copy));' . PHP_EOL;
            $code .= "\t\t\t" . '}' . PHP_EOL;
            $code .= "\t\t" . '}' . PHP_EOL . PHP_EOL;
            $code .= "\t\t" . 'offset = Z_STRLEN_P(result);' . PHP_EOL;
            $code .= "\t\t" . 'length += offset;' . PHP_EOL;
            $code .= "\t\t" . 'Z_STR_P(result) = zend_string_realloc(Z_STR_P(result), length, 0);' . PHP_EOL;
            $code .= '' . PHP_EOL;
            $code .= "\t" . '} else {' . PHP_EOL;
            $code .= "\t\t" . 'ZVAL_STR(result, zend_string_alloc(length, 0));' . PHP_EOL;
            $code .= "\t" . '}' . PHP_EOL . PHP_EOL;
            $position = '';
            foreach ($avars as $n => $type) {
                if ($type == 's') {
                    $code .= "\t" . 'memcpy(Z_STRVAL_P(result) + offset' . $position . ', op' . $n . ', op' . $n . '_len);' . PHP_EOL;
                    $position .= ' + op' . $n . '_len';
                } else {
                    $code .= "\t" . 'memcpy(Z_STRVAL_P(result) + offset' . $position . ', Z_STRVAL_P(op' . $n . '), Z_STRLEN_P(op' . $n . '));' . PHP_EOL;
                    $position .= ' + Z_STRLEN_P(op' . $n . ')';
                }
            }
            $code .= "\t" . 'Z_STRVAL_P(result)[length] = 0;' . PHP_EOL;
            $code .= "\t" . 'zend_string_forget_hash_val(Z_STR_P(result));' . PHP_EOL;
            foreach ($zvars as $zvar) {
                $code .= "\t" . 'if (use_copy' . $zvar . ') {' . PHP_EOL;
                $code .= "\t" . '   zval_dtor(op' . $zvar . ');' . PHP_EOL;
                $code .= "\t" . '}' . PHP_EOL . PHP_EOL;
            }
            $code .= "\t" . 'if (use_copy) {' . PHP_EOL;
            $code .= "\t" . '   zval_dtor(&result_copy);' . PHP_EOL;
            $code .= "\t" . '}' . PHP_EOL . PHP_EOL;
            $code .= "}" . PHP_EOL . PHP_EOL;
        }
        $code .= <<<EOF
void zephir_concat_function(zval *result, zval *op1, zval *op2) /* {{{ */
{
    zval tmp;
    /* Force separate zval, if op2=result will be reallocated */
    if (unlikely(result == op2)) {
        ZVAL_COPY_VALUE(&tmp, op2);
        op2 = &tmp;
    }

    concat_function(result, op1, op2 TSRMLS_CC);
}
EOF;
        $codeh .= "void zephir_concat_function(zval *result, zval *op1, zval *op2);\n#endif /* ZEPHIR_KERNEL_CONCAT_H */\n";
        Utils::checkAndWriteIfNeeded($pcodeh . join(PHP_EOL, $macros) . PHP_EOL . PHP_EOL . $codeh, 'ext/kernel/concat.h');
        Utils::checkAndWriteIfNeeded($code, 'ext/kernel/concat.c');
    }
Esempio n. 5
0
    /**
     * Generates the concatenation code
     *
     * @return array
     */
    public function genConcatCode()
    {
        $code = '
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <php.h>
#include "php_ext.h"
#include <ext/standard/php_string.h>
#include "ext.h"

#include "kernel/main.h"
#include "kernel/memory.h"
#include "kernel/concat.h"' . PHP_EOL . PHP_EOL;
        $pcodeh = '
#ifndef ZEPHIR_KERNEL_CONCAT_H
#define ZEPHIR_KERNEL_CONCAT_H

#include <php.h>
#include <Zend/zend.h>

#include "kernel/main.h"

';
        $codeh = '';
        $macros = array();
        ksort($this->concatKeys, SORT_STRING);
        foreach ($this->concatKeys as $key => $one) {
            $len = strlen($key);
            $params = array();
            $zvalCopy = array();
            $useCopy = array();
            $avars = array();
            $zvars = array();
            $svars = array();
            $lengths = array();
            $sparams = array();
            $lparams = array();
            for ($i = 0; $i < $len; $i++) {
                $n = $i + 1;
                $t = substr($key, $i, 1);
                $sparams[] = 'op' . $n;
                if ($t == 's') {
                    $params[] = 'const char *op' . $n . ', zend_uint op' . $n . '_len';
                    $lparams[] = 'op' . $n . ', sizeof(op' . $n . ')-1';
                    $lengths[] = 'op' . $n . '_len';
                    $svars[] = $n;
                    $avars[$n] = 's';
                } else {
                    $params[] = 'zval *op' . $n;
                    $lparams[] = 'op' . $n;
                    $zvalCopy[] = 'op' . $n . '_copy';
                    $useCopy[] = 'use_copy' . $n . ' = 0';
                    $lengths[] = 'Z_STRLEN_P(op' . $n . ')';
                    $zvars[] = $n;
                    $avars[$n] = 'v';
                }
            }
            $macros[] = '#define ZEPHIR_CONCAT_' . strtoupper($key) . '(result, ' . join(', ', $sparams) . ') \\' . PHP_EOL . "\t" . ' zephir_concat_' . $key . '(&result, ' . join(', ', $lparams) . ', 0 TSRMLS_CC);';
            $macros[] = '#define ZEPHIR_SCONCAT_' . strtoupper($key) . '(result, ' . join(', ', $sparams) . ') \\' . PHP_EOL . "\t" . ' zephir_concat_' . $key . '(&result, ' . join(', ', $lparams) . ', 1 TSRMLS_CC);';
            $macros[] = '';
            $proto = 'void zephir_concat_' . $key . '(zval **result, ' . join(', ', $params) . ', int self_var TSRMLS_DC)';
            $proto = 'void zephir_concat_' . $key . '(zval **result, ' . join(', ', $params) . ', int self_var TSRMLS_DC)';
            $codeh .= '' . $proto . ';' . PHP_EOL;
            $code .= $proto . '{' . PHP_EOL . PHP_EOL;
            if (count($zvalCopy)) {
                $code .= "\t" . 'zval result_copy, ' . join(', ', $zvalCopy) . ';' . PHP_EOL;
                $code .= "\t" . 'int use_copy = 0, ' . join(', ', $useCopy) . ';' . PHP_EOL;
            } else {
                $code .= "\t" . 'zval result_copy;' . PHP_EOL;
                $code .= "\t" . 'int use_copy = 0;' . PHP_EOL;
            }
            $code .= "\t" . 'uint offset = 0, length;' . PHP_EOL . PHP_EOL;
            foreach ($zvars as $zvar) {
                $code .= "\t" . 'if (Z_TYPE_P(op' . $zvar . ') != IS_STRING) {' . PHP_EOL;
                $code .= "\t" . '   zend_make_printable_zval(op' . $zvar . ', &op' . $zvar . '_copy, &use_copy' . $zvar . ');' . PHP_EOL;
                $code .= "\t" . '   if (use_copy' . $zvar . ') {' . PHP_EOL;
                $code .= "\t" . '       op' . $zvar . ' = &op' . $zvar . '_copy;' . PHP_EOL;
                $code .= "\t" . '   }' . PHP_EOL;
                $code .= "\t" . '}' . PHP_EOL . PHP_EOL;
            }
            $code .= "\t" . 'length = ' . join(' + ', $lengths) . ';' . PHP_EOL;
            $code .= "\t" . 'if (self_var) {' . PHP_EOL;
            $code .= '' . PHP_EOL;
            $code .= "\t\t" . 'if (Z_TYPE_PP(result) != IS_STRING) {' . PHP_EOL;
            $code .= "\t\t\t" . 'zend_make_printable_zval(*result, &result_copy, &use_copy);' . PHP_EOL;
            $code .= "\t\t\t" . 'if (use_copy) {' . PHP_EOL;
            $code .= "\t\t\t\t" . 'ZEPHIR_CPY_WRT_CTOR(*result, (&result_copy));' . PHP_EOL;
            $code .= "\t\t\t" . '}' . PHP_EOL;
            $code .= "\t\t" . '}' . PHP_EOL . PHP_EOL;
            $code .= "\t\t" . 'offset = Z_STRLEN_PP(result);' . PHP_EOL;
            $code .= "\t\t" . 'length += offset;' . PHP_EOL;
            $code .= "\t\t" . 'Z_STRVAL_PP(result) = (char *) str_erealloc(Z_STRVAL_PP(result), length + 1);' . PHP_EOL;
            $code .= '' . PHP_EOL;
            $code .= "\t" . '} else {' . PHP_EOL;
            $code .= "\t\t" . 'Z_STRVAL_PP(result) = (char *) emalloc(length + 1);' . PHP_EOL;
            $code .= "\t" . '}' . PHP_EOL . PHP_EOL;
            $position = '';
            foreach ($avars as $n => $type) {
                if ($type == 's') {
                    $code .= "\t" . 'memcpy(Z_STRVAL_PP(result) + offset' . $position . ', op' . $n . ', op' . $n . '_len);' . PHP_EOL;
                    $position .= ' + op' . $n . '_len';
                } else {
                    $code .= "\t" . 'memcpy(Z_STRVAL_PP(result) + offset' . $position . ', Z_STRVAL_P(op' . $n . '), Z_STRLEN_P(op' . $n . '));' . PHP_EOL;
                    $position .= ' + Z_STRLEN_P(op' . $n . ')';
                }
            }
            $code .= "\t" . 'Z_STRVAL_PP(result)[length] = 0;' . PHP_EOL;
            $code .= "\t" . 'Z_TYPE_PP(result) = IS_STRING;' . PHP_EOL;
            $code .= "\t" . 'Z_STRLEN_PP(result) = length;' . PHP_EOL . PHP_EOL;
            foreach ($zvars as $zvar) {
                $code .= "\t" . 'if (use_copy' . $zvar . ') {' . PHP_EOL;
                $code .= "\t" . '   zval_dtor(op' . $zvar . ');' . PHP_EOL;
                $code .= "\t" . '}' . PHP_EOL . PHP_EOL;
            }
            $code .= "\t" . 'if (use_copy) {' . PHP_EOL;
            $code .= "\t" . '   zval_dtor(&result_copy);' . PHP_EOL;
            $code .= "\t" . '}' . PHP_EOL . PHP_EOL;
            $code .= "}" . PHP_EOL . PHP_EOL;
        }
        $code .= <<<EOF
void zephir_concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
{
#if PHP_VERSION_ID < 50400
\tzval op1_copy, op2_copy;
\tint use_copy1 = 0, use_copy2 = 0;

\tif (Z_TYPE_P(op1) != IS_STRING) {
\t\tzend_make_printable_zval(op1, &op1_copy, &use_copy1);
\t}
\tif (Z_TYPE_P(op2) != IS_STRING) {
\t\tzend_make_printable_zval(op2, &op2_copy, &use_copy2);
\t}

\tif (use_copy1) {
\t\t/* We have created a converted copy of op1. Therefore, op1 won't become the result so
\t\t * we have to free it.
\t\t */
\t\tif (result == op1) {
\t\t\tzval_dtor(op1);
\t\t}
\t\top1 = &op1_copy;
\t}
\tif (use_copy2) {
\t\top2 = &op2_copy;
\t}
\tif (result == op1 && !IS_INTERNED(Z_STRVAL_P(op1))) {\t/* special case, perform operations on result */
\t\tuint res_len = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);

\t\tif (Z_STRLEN_P(result) < 0 || (int) (Z_STRLEN_P(op1) + Z_STRLEN_P(op2)) < 0) {
\t\t\tstr_efree(Z_STRVAL_P(result));
\t\t\tZVAL_EMPTY_STRING(result);
\t\t\tzend_error(E_ERROR, "String size overflow");
\t\t}

\t\tZ_STRVAL_P(result) = str_erealloc(Z_STRVAL_P(result), res_len+1);

\t\tmemcpy(Z_STRVAL_P(result) + Z_STRLEN_P(result), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
\t\tZ_STRVAL_P(result)[res_len] = 0;
\t\tZ_STRLEN_P(result) = res_len;
\t} else {
\t\tint length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
\t\tchar *buf = (char *) emalloc(length + 1);

\t\tmemcpy(buf, Z_STRVAL_P(op1), Z_STRLEN_P(op1));
\t\tmemcpy(buf + Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
\t\tbuf[length] = 0;
\t\tZVAL_STRINGL(result, buf, length, 0);
\t}
\tif (use_copy1) {
\t\tzval_dtor(op1);
\t}
\tif (use_copy2) {
\t\tzval_dtor(op2);
\t}
#else
    concat_function(result, op1, op2 TSRMLS_CC);
#endif
}
EOF;
        $codeh .= "void zephir_concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);\n\n#endif /* ZEPHIR_KERNEL_CONCAT_H */\n\n";
        Utils::checkAndWriteIfNeeded($pcodeh . join(PHP_EOL, $macros) . PHP_EOL . PHP_EOL . $codeh, 'ext/kernel/concat.h');
        Utils::checkAndWriteIfNeeded($code, 'ext/kernel/concat.c');
    }