summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xconvertsyntax.php43
-rw-r--r--it_auto_prepend.php183
-rwxr-xr-xit_syntaxconverter.class430
-rw-r--r--itools.lib1
4 files changed, 657 insertions, 0 deletions
diff --git a/convertsyntax.php b/convertsyntax.php
new file mode 100755
index 0000000..282b774
--- /dev/null
+++ b/convertsyntax.php
@@ -0,0 +1,43 @@
+#!/usr/bin/env php
+<?php
+
+php_sapi_name() == "cli" or exit("Can only be used from CLI\n");
+ini_set('include_path', dirname(__FILE__) . "/..:" . ini_get('include_path'));
+require "itools/itools.lib";
+
+$opts = it::getopt("
+ Usage: $argv[0] [OPTIONS]
+ -o, --old Convert to old syntax (default)
+ -n, --new Convert to new syntax
+ -t, --test Test if is old syntax
+ -v, --verbose Verbose output (otherwise -t only sets result code)
+");
+
+$mode = $opts['test'] ? 'test' : ($opts['new'] ? 'new' : 'old');
+$files = $opts['args'] ? $opts['args'] : array('php://stdin');
+$result = 0;
+
+foreach ($files as $file)
+{
+ $converter = new it_syntaxconverter(file_get_contents($file), $mode);
+
+ if ($mode == 'test')
+ {
+ if ($converter->changes)
+ {
+ if ($opts['verbose'])
+ echo "$file contains $converter->changes new syntax elements\n";
+
+ $result++;
+ }
+ }
+ else
+ {
+ echo $converter->output;
+
+ if ($opts['verbose'] && $converter->changes)
+ fputs(fopen("php://stderr", "w"), "$converter->changes changes made to $file\n");
+ }
+}
+
+exit($result);
diff --git a/it_auto_prepend.php b/it_auto_prepend.php
new file mode 100644
index 0000000..3f69096
--- /dev/null
+++ b/it_auto_prepend.php
@@ -0,0 +1,183 @@
+<?php
+/*
+** $Id$
+**
+** Copyright (C) 1995-2007 by the ITools Authors.
+** This file is part of ITools - the Internet Tools Library
+**
+** ITools is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 3 of the License, or
+** (at your option) any later version.
+**
+** ITools is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+define('IT_CONVERT_DIR', "/tmp/it_syntaxconverter");
+
+#$debug_itclassloader = true;
+it_initialize();
+
+function it_initialize()
+{
+ static $it_initrecursion;
+
+ if (!$it_initrecursion++)
+ {
+ if ($_SERVER['REMOTE_ADDR']) # Web?
+ {
+ $GLOBALS['ULTRAHOME'] = dirname($_SERVER['SCRIPT_FILENAME']);
+ umask(0002); # Work around bugs.php.net/bug.php?id=28401
+ $_SERVER['HTTP_HOST'] = strtolower($_SERVER['HTTP_HOST']);
+ }
+ else # Shell
+ $GLOBALS['ULTRAHOME'] = dirname(preg_match('|^/|', $argv[0]) ? $argv[0] : getcwd() . '/' . $argv[0]);
+
+ $needsconvert = !@eval("return is_array(42=>69,);"); # Check if PHP is patched to support our syntax, see http://cschneid.com/php/
+
+ $include_path = ini_get('include_path');
+ $it_path = dirname(__FILE__);
+
+ if ($autoloader = function_exists('spl_autoload_register') && spl_autoload_register('it_classloader'))
+ {
+ ini_set('include_path', "$it_path:$include_path");
+ require_once("$it_path/auto_prepend.php");
+ }
+ else
+ {
+ ini_set('include_path', "$it_path/..:$include_path");
+ require("itools.lib"); # PHP 4 fallback
+ }
+
+ @set_error_handler("it_errorhandler", E_USER_ERROR | E_RECOVERABLE_ERROR | E_WARNING | E_USER_WARNING | E_NOTICE | E_USER_NOTICE);
+ ini_set('include_path', IT_CONVERT_DIR . ":$it_path:$include_path");
+ $user_includes = explode(":", $include_path);
+
+ # XXX Note: Comment this out if you want system wide include path converted and auto_prepend.php considered
+ $user_includes = array_diff($user_includes, array_diff(explode(":", get_cfg_var('include_path')), array(".")));
+
+ foreach (array_reverse($user_includes) as $include)
+ {
+ if ($include == ".")
+ $include = dirname($_SERVER['SCRIPT_FILENAME']);
+
+ if ($needsconvert)
+ it_convert($include);
+
+ if (file_exists($autoprepend = "$include/auto_prepend.php"))
+ {
+ if ($needsconvert && ($include != $it_path))
+ $autoprepend = it_convert($autoprepend);
+
+ require_once($autoprepend);
+ }
+ }
+
+ if (!isset($GLOBALS['it_html']))
+ new it_html;
+
+ if ($needsconvert)
+ {
+ # Convert syntax and start
+ $converted = it_convert($_SERVER['SCRIPT_FILENAME']);
+
+ /* XXX Disabled as DB not always there
+ if (!$autoloader) # PHP 4 fallback
+ it_dbi::createclasses();
+ */
+
+ require($converted);
+ exit;
+ }
+ }
+}
+
+function it_convert($source)
+{
+ if (is_dir($source) && !is_link($source))
+ {
+ foreach (glob("$source/*") as $file)
+ it_convert($file);
+ }
+ else if (is_readable($source))
+ {
+ $converted = IT_CONVERT_DIR . "/$source";
+
+ if (@filemtime($converted) < filemtime($source))
+ {
+ $converter = new it_syntaxconverter(file_get_contents($source));
+ $parts = explode("/", dirname($converted));
+
+ for ($i = 1; $i <= count($parts); $i++)
+ @mkdir(join("/", array_slice($parts, 0, $i)));
+
+ if ($output = fopen($converted, "w"))
+ {
+ fputs($output, $converter->output);
+ fclose($output);
+ chmod($converted, 0666);
+ }
+
+ clearstatcache();
+ }
+ }
+
+ return $converted;
+}
+
+function it_classloader($classname)
+{
+ if ($file = @fopen("$classname.class", "r", true)) # Check for file in include path, do not use @include to get failures on inheritance
+ {
+ include("$classname.class");
+ fclose($file);
+ }
+ else
+ it_dbi::createclass($classname);
+
+ EDC('ultraclassloader', $classname, it_debug::backtrace());
+}
+
+function it_errorhandler($errno, $errstr, $errfile, $errline, $errcontext)
+{
+ if ($result = error_reporting() & $errno) # Is this error enabled?
+ {
+ static $it_errnames = array();
+
+ if (!$it_errnames)
+ {
+ foreach (get_defined_constants() as $name => $no)
+ {
+ if (preg_match('/^E_/', $name))
+ $it_errnames[$no] = "$name: ";
+ }
+ }
+
+ $error = array(
+ 'title' => $it_errnames[$errno] . $errstr,
+ 'locals' => $errcontext,
+ 'file' => $errfile,
+ 'line' => $errline,
+ 'backtraceskip' => 1,
+ );
+
+ switch ($errno)
+ {
+ case E_USER_ERROR: case E_RECOVERABLE_ERROR:
+ it::fatal($error);
+ break;
+
+ default:
+ it::error($error);
+ break;
+ }
+ }
+
+ return $result; # True means do not execute standard PHP error handler
+}
diff --git a/it_syntaxconverter.class b/it_syntaxconverter.class
new file mode 100755
index 0000000..ef0b5f3
--- /dev/null
+++ b/it_syntaxconverter.class
@@ -0,0 +1,430 @@
+<?php
+/*
+** $Id$
+**
+** Copyright (C) 1995-2007 by the ITools Authors.
+** This file is part of ITools - the Internet Tools Library
+**
+** ITools is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 3 of the License, or
+** (at your option) any later version.
+**
+** ITools is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+class it_syntaxconverter
+{
+ var $mode; # Either 'old', 'new', 'test'
+ var $changes = 0;
+
+ var $whitespace = array
+ (
+ T_WHITESPACE => true,
+ T_COMMENT => true,
+ );
+
+ var $arrayoptional = array
+ (
+ T_VARIABLE => true,
+ T_STRING => true,
+ );
+
+#
+# Constructor
+#
+function it_syntaxconverter($string, $mode = "old")
+{
+ if (defined('T_ML_COMMENT'))
+ $this->whitespace[T_ML_COMMENT] = true; # PHP4
+
+ if (defined('T_DOC_COMMENT'))
+ $this->whitespace[T_DOC_COMMENT] = true; # PHP5
+
+ $this->input = $string;
+ $this->mode = $mode;
+ $this->tokens = token_get_all($this->input);
+ $this->count = count($this->tokens);
+ $this->position = 0;
+ $this->old = $this->parse();
+ $this->new = $this->convert($this->old);
+ $this->output = $this->text($this->new);
+}
+
+#
+# Build parse tree from source string
+#
+function parse()
+{
+ $result = array();
+
+ while ($this->position < $this->count)
+ {
+ $token = $this->tokens[$this->position++];
+
+ if (is_string($token))
+ {
+ if ($token == '(')
+ $result[] = array('LIST', $this->parse_list());
+ else
+ $result[] = array('TEXT', $token);
+ }
+ else
+ $result[] = $token;
+ }
+
+ return $result;
+}
+
+function parse_list()
+{
+ $result = array();
+
+ while ($this->position < $this->count)
+ {
+ list($token, $element) = $this->parse_element();
+ $result[] = $element;
+
+ if ($token == ')')
+ break;
+ }
+
+ return $result;
+}
+
+function parse_element()
+{
+ $result = array();
+
+ while ($this->position < $this->count)
+ {
+ $token = $this->tokens[$this->position++];
+
+ if (is_string($token))
+ {
+ if ($token == '(')
+ $result[] = array('LIST', $this->parse_list());
+ else if (($token == ',') || ($token == ')'))
+ break;
+ else
+ $result[] = array('TEXT', $token);
+ }
+ else
+ $result[] = $token;
+ }
+
+ return array($token, $result);
+}
+
+
+#
+# Modify parse tree to old syntax
+#
+function convert($tokens)
+{
+ $result = array();
+ $op = '';
+
+ foreach ($tokens as $token)
+ {
+ list($id, $elements) = $token;
+
+ if ($id == 'LIST')
+ {
+ if (empty($this->arrayoptional[$op]))
+ {
+ $list = array();
+
+ foreach ($elements as $element)
+ $list[] = $this->convert($element);
+
+ $result[] = array($id, $list);
+ }
+ else
+ $result[] = array('LIST', $this->convert_list($elements));
+ }
+ else
+ $result[] = $token;
+
+ if (empty($this->whitespace[$id]))
+ $op = $id;
+ }
+
+ return $result;
+}
+
+function convert_list($elements)
+{
+ if ($this->mode != 'new')
+ {
+ $result = $this->convert_list_namedparameters($elements);
+ $result = $this->convert_list_trailingcomma($result);
+ }
+ else
+ $result = $this->convert_list_arrayparameters($elements);
+
+ return $result;
+}
+
+#
+# Remove array() around named parameter lists
+#
+function convert_list_arrayparameters($elements)
+{
+ $result = array();
+ $locked = false;
+
+ foreach ($elements as $element)
+ {
+ $element = $this->convert($element);
+
+ if ($locked)
+ {
+ $result[] = $element;
+ $locked = false;
+ }
+ else
+ {
+ $elementlist = $this->convert_pure_assoc_array($element);
+
+ foreach ($elementlist as $element)
+ $result[] = $element;
+
+ $locked = count($elementlist) != 1;
+ }
+ }
+
+ return $result;
+}
+
+function convert_pure_assoc_array($tokens)
+{
+ $result = array();
+ $element = array();
+ $array = false;
+ $locked = false;
+
+ foreach ($tokens as $token)
+ {
+ list($id, $elements) = $token;
+
+ if ($array)
+ {
+ if (($id == 'LIST') && $this->only_double_arrow($elements))
+ {
+ foreach ($elements as $listelements)
+ {
+ $listelements = $this->convert($listelements);
+
+ foreach ($listelements as $listelement)
+ $element[] = $listelement;
+
+ $result[] = $element;
+ $element = array();
+ }
+
+ # Continue with last element
+ $element = array_pop($result);
+ }
+ else
+ {
+ $element[] = $array;
+ $element[] = $token;
+ }
+
+ $array = false;
+ $locked = true;
+ }
+ else if (!$locked && ($id == T_ARRAY))
+ {
+ $array = $token;
+ }
+ else if (empty($this->whitespace[$id]))
+ {
+ if ($locked)
+ {
+ # Encountered something after array, abort
+ $result = array();
+ $element = $tokens;
+ break;
+ }
+ else
+ {
+ $element[] = $token;
+ $locked = true;
+ }
+ }
+ else
+ $element[] = $token;
+ }
+
+ if ($element)
+ $result[] = $element;
+
+ return $result;
+}
+
+function only_double_arrow($elements)
+{
+ $result = $elements; # Has to contain elements, empty is false
+
+ foreach ($elements as $element)
+ {
+ if (!$this->has_double_arrow($element))
+ {
+ $result = false;
+ break;
+ }
+ }
+
+ return $result;
+}
+
+#
+# Add array() around named parameter lists
+#
+function convert_list_namedparameters($elements)
+{
+ $namedparams = array();
+
+ foreach ($elements as $element)
+ {
+ $element = $this->convert($element);
+
+ if (!$this->has_double_arrow($element))
+ {
+ if ($namedparams)
+ {
+ $result[] = $this->make_array($namedparams);
+ $namedparams = array();
+ }
+
+ $result[] = $element;
+ }
+ else
+ $namedparams[] = $element;
+ }
+
+ if ($namedparams)
+ $result[] = $this->make_array($namedparams);
+
+ return $result;
+}
+
+#
+# Remove trailing comma by adding content to previous element
+#
+function convert_list_trailingcomma($elements)
+{
+ $result = $elements;
+ $last = count($result) - 1;
+
+ if (($last > 0) && $this->is_empty($result[$last]))
+ {
+ $this->changes++;
+ $element = array_pop($result);
+ $last--;
+ foreach ($element as $token)
+ $result[$last][] = $token;
+ }
+
+ return $result;
+}
+
+function has_double_arrow($element)
+{
+ $result = false;
+
+ foreach ($element as $token)
+ {
+ list($id, $text) = $token;
+
+ if ($id == T_DOUBLE_ARROW)
+ {
+ $result = true;
+ break;
+ }
+ }
+
+ return $result;
+}
+
+function make_array($namedparams)
+{
+ $result = array();
+ $head = array();
+ $body = array();
+
+ $this->changes++;
+ $namedparam = $namedparams[0];
+
+ foreach ($namedparam as $token)
+ {
+ list($id, $text) = $token;
+
+ if ($body || (($id != 'LIST') && empty($this->whitespace[$id])))
+ $body[] = $token;
+ else
+ $result[] = $token;
+ }
+
+ $namedparams[0] = $body;
+ $result[] = array(T_ARRAY, "array");
+ $result[] = array('LIST', $namedparams);
+
+ return $result;
+}
+
+function is_empty($element)
+{
+ $result = true;
+
+ foreach ($element as $token)
+ {
+ list($id, $text) = $token;
+
+ if (empty($this->whitespace[$id]))
+ {
+ $result = false;
+ break;
+ }
+ }
+
+ return $result;
+}
+
+
+#
+# Convert parse tree back to string
+#
+function text($tokens)
+{
+ $result = "";
+
+ foreach ($tokens as $token)
+ {
+ list($id, $data) = $token;
+
+ if ($id == 'LIST')
+ {
+ $list = array();
+
+ foreach ($data as $element)
+ $list[] .= $this->text($element);
+
+ $result .= "(" . join(",", $list) . ")";
+ }
+ else
+ $result .= $data;
+ }
+
+ return $result;
+}
+
+}
diff --git a/itools.lib b/itools.lib
index da3f0f5..3b6a2f1 100644
--- a/itools.lib
+++ b/itools.lib
@@ -27,6 +27,7 @@ require_once 'itools/it_html.class';
require_once 'itools/itjs.class';
require_once 'itools/it_mail.class';
require_once 'itools/it_session.class';
+require_once 'itools/it_syntaxconverter.class';
require_once 'itools/it_text.class';
require_once 'itools/it_url.class';
require_once 'itools/it_user.class';