]> git.mjollnir.org Git - s9y.git/commitdiff
updating bundled libs.
authornohn <nohn>
Wed, 13 Jul 2005 15:02:58 +0000 (15:02 +0000)
committernohn <nohn>
Wed, 13 Jul 2005 15:02:58 +0000 (15:02 +0000)
12 files changed:
bundled-libs/.current_version
bundled-libs/Cache/Lite.php
bundled-libs/Cache/Lite/Function.php
bundled-libs/Cache/Lite/Output.php
bundled-libs/HTTP/Request.php
bundled-libs/HTTP/Request/Listener.php
bundled-libs/Net/CheckIP.php
bundled-libs/Net/Socket.php
bundled-libs/Net/URL.php
bundled-libs/PEAR.php
bundled-libs/Text/Wiki.php
docs/NEWS

index a32af840cd9d9e96956534a9fd0824a0178beca5..7879f990f46dc885f70e0efce484188db6ec29d1 100644 (file)
@@ -1 +1,8 @@
-PEAR::XML_RPC          1.3.2
\ No newline at end of file
+Cache_Lite             1.5.1
+HTTP_Request           1.2.4
+Net_CheckIP            1.1
+Net_Socket             1.0.6
+Net_URL                1.0.14
+PEAR                   1.3.5
+Text_Wiki              1.0.0
+XML_RPC                1.3.2
\ No newline at end of file
index 9b393422c8346c5f9f2df7947b5522e67354570e..34e5bcd0284c0f4e8c5cd602d10afe7c642e7162 100644 (file)
 * There are some examples in the 'docs/examples' file
 * Technical choices are described in the 'docs/technical' file
 *
-* A tutorial is available in english at this url :
-* http://www.pearfr.org/index.php/en/article/cache_lite
-* (big thanks to Pierre-Alain Joye for the translation)
-*
-* The same tutorial is also available in french at this url :
-* http://www.pearfr.org/index.php/fr/article/cache_lite
-*
 * Memory Caching is from an original idea of
 * Mike BENOIT <ipso@snappymail.ca>
 *
+* Nota : A chinese documentation (thanks to RainX <china_1982@163.com>) is
+* available at :
+* http://rainx.phpmore.com/manual/cache_lite.html
+*
 * @package Cache_Lite
 * @category Caching
-* @version $Id: Lite.php,v 1.1 2004/12/02 14:23:52 nohn Exp $
+* @version $Id: Lite.php,v 1.30 2005/06/13 20:50:48 fab Exp $
 * @author Fabien MARTY <fab@php.net>
 */
 
@@ -80,6 +77,13 @@ class Cache_Lite
     * @var string $_file
     */
     var $_file;
+    
+    /**
+    * File name (without path)
+    *
+    * @var string $_fileName
+    */
+    var $_fileName;
 
     /**
     * Enable / disable write control (the cache is read just after writing to detect corrupt entries)
@@ -197,6 +201,39 @@ class Cache_Lite
     */
     var $_automaticSerialization = false;
     
+    /**
+    * Disable / Tune the automatic cleaning process
+    *
+    * The automatic cleaning process destroy too old (for the given life time)
+    * cache files when a new cache file is written.
+    * 0               => no automatic cache cleaning
+    * 1               => systematic cache cleaning
+    * x (integer) > 1 => automatic cleaning randomly 1 times on x cache write
+    *
+    * @var int $_automaticCleaning
+    */
+    var $_automaticCleaningFactor = 0;
+    
+    /**
+    * Nested directory level
+    *
+    * Set the hashed directory structure level. 0 means "no hashed directory 
+    * structure", 1 means "one level of directory", 2 means "two levels"... 
+    * This option can speed up Cache_Lite only when you have many thousands of 
+    * cache file. Only specific benchs can help you to choose the perfect value 
+    * for you. Maybe, 1 or 2 is a good start.
+    *
+    * @var int $_hashedDirectoryLevel
+    */
+    var $_hashedDirectoryLevel = 0;
+    
+    /**
+    * Umask for hashed directory structure
+    *
+    * @var int $_hashedDirectoryUmask
+    */
+    var $_hashedDirectoryUmask = 0700;
+    
     // --- Public methods ---
 
     /**
@@ -217,6 +254,9 @@ class Cache_Lite
     *     'memoryCachingLimit' => max nbr of records to store into memory caching (int),
     *     'fileNameProtection' => enable / disable automatic file name protection (boolean),
     *     'automaticSerialization' => enable / disable automatic serialization (boolean)
+    *     'automaticCleaningFactor' => distable / tune automatic cleaning process (int)
+    *     'hashedDirectoryLevel' => level of the hashed directory system (int)
+    *     'hashedDirectoryUmask' => umask for hashed directory structure (int)
     * );
     *
     * @param array $options options
@@ -224,7 +264,7 @@ class Cache_Lite
     */
     function Cache_Lite($options = array(NULL))
     {
-        $availableOptions = array('automaticSerialization', 'fileNameProtection', 'memoryCaching', 'onlyMemoryCaching', 'memoryCachingLimit', 'cacheDir', 'caching', 'lifeTime', 'fileLocking', 'writeControl', 'readControl', 'readControlType', 'pearErrorMode');
+        $availableOptions = array('hashedDirectoryUmask', 'hashedDirectoryLevel', 'automaticCleaningFactor', 'automaticSerialization', 'fileNameProtection', 'memoryCaching', 'onlyMemoryCaching', 'memoryCachingLimit', 'cacheDir', 'caching', 'lifeTime', 'fileLocking', 'writeControl', 'readControl', 'readControlType', 'pearErrorMode');
         foreach($options as $key => $value) {
             if(in_array($key, $availableOptions)) {
                 $property = '_'.$key;
@@ -307,6 +347,12 @@ class Cache_Lite
                     return true;
                 }
             }
+           if ($this->_automaticCleaningFactor>0) {
+                $rand = rand(1, $this->_automaticCleaningFactor);
+               if ($rand==1) {
+                   $this->clean(false, 'old');
+               }
+            }
             if ($this->_writeControl) {
                 if (!$this->_writeAndControl($data)) {
                     @touch($this->_file, time() - 2*abs($this->_lifeTime));
@@ -315,8 +361,8 @@ class Cache_Lite
                     return true;
                 }
             } else {
-                return $this->_write($data);
-            }
+               return $this->_write($data);
+           }
         }
         return false;
     }
@@ -341,11 +387,7 @@ class Cache_Lite
                 return true;
             }
         }
-        if (!@unlink($this->_file)) {
-            $this->raiseError('Cache_Lite : Unable to remove cache !', -3);   
-            return false;
-        }
-        return true;
+        return $this->_unlink($this->_file);
     }
 
     /**
@@ -355,47 +397,16 @@ class Cache_Lite
     * else only cache files of the specified group will be destroyed
     *
     * @param string $group name of the cache group
+    * @param string $mode flush cache mode : 'old', 'ingroup', 'notingroup', 
+    *                                        'callback_myFunction'
     * @return boolean true if no problem
     * @access public
     */
-    function clean($group = false)     
+    function clean($group = false, $mode = 'ingroup')
     {
-        if ($this->_fileNameProtection) {
-            $motif = ($group) ? 'cache_'.md5($group).'_' : 'cache_';
-        } else {
-            $motif = ($group) ? 'cache_'.$group.'_' : 'cache_';
-        }
-        if ($this->_memoryCaching) {
-            while (list($key, $value) = each($this->_memoryCachingArray)) {
-                if (strpos($key, $motif, 0)) {
-                    unset($this->_memoryCachingArray[$key]);
-                    $this->_memoryCachingCounter = $this->_memoryCachingCounter - 1;
-                }
-            }
-            if ($this->_onlyMemoryCaching) {
-                return true;
-            }
-        }
-        if (!($dh = opendir($this->_cacheDir))) {
-            $this->raiseError('Cache_Lite : Unable to open cache directory !', -4);
-            return false;
-        }
-        while ($file = readdir($dh)) {
-            if (($file != '.') && ($file != '..')) {
-                $file = $this->_cacheDir . $file;
-                if (is_file($file)) {
-                    if (strpos($file, $motif, 0)) {
-                        if (!@unlink($file)) {
-                            $this->raiseError('Cache_Lite : Unable to remove cache !', -3);
-                            return false;
-                        }
-                    }
-                }
-            }
-        }
-        return true;
+        return $this->_cleanDir($this->_cacheDir, $group, $mode);
     }
-    
+       
     /**
     * Set to debug mode
     *
@@ -422,7 +433,10 @@ class Cache_Lite
     }
 
     /**
+    * Save the state of the caching memory array into a cache file cache
     *
+    * @param string $id cache id
+    * @param string $group name of the cache group
     * @access public
     */
     function saveMemoryCachingState($id, $group = 'default')
@@ -438,7 +452,11 @@ class Cache_Lite
     }
 
     /**
+    * Load the state of the caching memory array from a given cache file cache
     *
+    * @param string $id cache id
+    * @param string $group name of the cache group
+    * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
     * @access public
     */
     function getMemoryCachingState($id, $group = 'default', $doNotTestCacheValidity = false)
@@ -460,7 +478,7 @@ class Cache_Lite
     * @return int last modification time
     */
     function lastModified() {
-        return filemtime($this->_file);
+        return @filemtime($this->_file);
     }
     
     /**
@@ -479,11 +497,104 @@ class Cache_Lite
         include_once('PEAR.php');
         PEAR::raiseError($msg, $code, $this->_pearErrorMode);
     }
-
+    
     // --- Private methods ---
 
     /**
+    * Remove a file
+    * 
+    * @param string $file complete file path and name
+    * @return boolean true if no problem
+    * @access private
+    */
+    function _unlink($file)
+    {
+        if (!@unlink($file)) {
+            $this->raiseError('Cache_Lite : Unable to remove cache !', -3);
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    /**
+    * Recursive function for cleaning cache file in the given directory
+    *
+    * @param string $dir directory complete path (with a trailing slash)
+    * @param string $group name of the cache group
+    * @param string $mode flush cache mode : 'old', 'ingroup', 'notingroup',
+                                             'callback_myFunction'
+    * @return boolean true if no problem
+    * @access private
+    */
+    function _cleanDir($dir, $group = false, $mode = 'ingroup')     
+    {
+        if ($this->_fileNameProtection) {
+            $motif = ($group) ? 'cache_'.md5($group).'_' : 'cache_';
+        } else {
+            $motif = ($group) ? 'cache_'.$group.'_' : 'cache_';
+        }
+        if ($this->_memoryCaching) {
+            while (list($key, $value) = each($this->_memoryCachingArray)) {
+                if (strpos($key, $motif, 0)) {
+                    unset($this->_memoryCachingArray[$key]);
+                    $this->_memoryCachingCounter = $this->_memoryCachingCounter - 1;
+                }
+            }
+            if ($this->_onlyMemoryCaching) {
+                return true;
+            }
+        }
+        if (!($dh = opendir($dir))) {
+            $this->raiseError('Cache_Lite : Unable to open cache directory !', -4);
+            return false;
+        }
+        $result = true;
+        while ($file = readdir($dh)) {
+            if (($file != '.') && ($file != '..')) {
+                if (substr($file, 0, 6)=='cache_') {
+                    $file2 = $dir . $file;
+                    if (is_file($file2)) {
+                        switch (substr($mode, 0, 9)) {
+                            case 'old':
+                                // files older than lifeTime get deleted from cache
+                                if ((mktime() - filemtime($file2)) > $this->_lifeTime) {
+                                    $result = ($result and ($this->_unlink($file2)));
+                                }
+                                break;
+                            case 'notingrou':
+                                if (!strpos($file2, $motif, 0)) {
+                                    $result = ($result and ($this->_unlink($file2)));
+                                }
+                                break;
+                            case 'callback_':
+                                $func = substr($mode, 9, strlen($mode) - 9);
+                                if ($func($file2, $group)) {
+                                    $result = ($result and ($this->_unlink($file2)));
+                                }
+                                break;
+                            case 'ingroup':
+                            default:
+                                if (strpos($file2, $motif, 0)) {
+                                    $result = ($result and ($this->_unlink($file2)));
+                                }
+                                break;
+                        }
+                    }
+                    if ((is_dir($file2)) and ($this->_hashedDirectoryLevel>0)) {
+                        $result = ($result and ($this->_cleanDir($file2 . '/', $group, $mode)));
+                    }
+                }
+            }
+        }
+        return $result;
+    }
+      
+    /**
+    * Add some date in the memory caching array
     *
+    * @param string $id cache id
+    * @param string $data data to cache
     * @access private
     */
     function _memoryCacheAdd($id, $data)
@@ -506,11 +617,21 @@ class Cache_Lite
     */
     function _setFileName($id, $group)
     {
+        
         if ($this->_fileNameProtection) {
-            $this->_file = ($this->_cacheDir.'cache_'.md5($group).'_'.md5($id));
+            $suffix = 'cache_'.md5($group).'_'.md5($id);
         } else {
-            $this->_file = $this->_cacheDir.'cache_'.$group.'_'.$id;
+            $suffix = 'cache_'.$group.'_'.$id;
+        }
+        $root = $this->_cacheDir;
+        if ($this->_hashedDirectoryLevel>0) {
+            $hash = md5($suffix);
+            for ($i=0 ; $i<$this->_hashedDirectoryLevel ; $i++) {
+                $root = $root . 'cache_' . substr($hash, 0, $i + 1) . '/';
+            }   
         }
+        $this->_fileName = $suffix;
+        $this->_file = $root.$suffix;
     }
     
     /**
@@ -532,7 +653,11 @@ class Cache_Lite
                 $hashControl = @fread($fp, 32);
                 $length = $length - 32;
             } 
-            $data = @fread($fp, $length);
+            if ($length) {
+                $data = @fread($fp, $length);
+            } else {
+                $data = '';
+            }
             set_magic_quotes_runtime($mqr);
             if ($this->_fileLocking) @flock($fp, LOCK_UN);
             @fclose($fp);
@@ -558,19 +683,34 @@ class Cache_Lite
     */
     function _write($data)
     {
-        $fp = @fopen($this->_file, "wb");
-        if ($fp) {
-            if ($this->_fileLocking) @flock($fp, LOCK_EX);
-            if ($this->_readControl) {
-                @fwrite($fp, $this->_hash($data, $this->_readControlType), 32);
+        $try = 1;
+        while ($try<=2) {
+            $fp = @fopen($this->_file, "wb");
+            if ($fp) {
+                if ($this->_fileLocking) @flock($fp, LOCK_EX);
+                if ($this->_readControl) {
+                    @fwrite($fp, $this->_hash($data, $this->_readControlType), 32);
+                }
+                $len = strlen($data);
+                @fwrite($fp, $data, $len);
+                if ($this->_fileLocking) @flock($fp, LOCK_UN);
+                @fclose($fp);
+                return true;
+            } else {
+                if (($try==1) and ($this->_hashedDirectoryLevel>0)) {
+                    $hash = md5($this->_fileName);
+                    $root = $this->_cacheDir;
+                    for ($i=0 ; $i<$this->_hashedDirectoryLevel ; $i++) {
+                        $root = $root . 'cache_' . substr($hash, 0, $i + 1) . '/';
+                        @mkdir($root, $this->_hashedDirectoryUmask);
+                    }
+                    $try = 2;
+                } else {
+                    $try = 999;
+                }
             }
-            $len = strlen($data);
-            @fwrite($fp, $data, $len);
-            if ($this->_fileLocking) @flock($fp, LOCK_UN);
-            @fclose($fp);
-            return true;
         }
-        $this->raiseError('Cache_Lite : Unable to write cache !', -1);
+        $this->raiseError('Cache_Lite : Unable to write cache file : '.$this->_file, -1);
         return false;
     }
     
index a72023f8f6360b76818156a54f9d240c80508faf..0d69e22bfd61475b0e13d7e6be43bdfb084b8079 100644 (file)
@@ -11,7 +11,7 @@
 * Technical choices are described in the 'docs/technical' file
 *
 * @package Cache_Lite
-* @version $Id: Function.php,v 1.1 2004/12/02 14:23:52 nohn Exp $
+* @version $Id: Function.php,v 1.6 2004/02/03 17:07:13 fab Exp $
 * @author Sebastian BERGMANN <sb@sebastian-bergmann.de>
 * @author Fabien MARTY <fab@php.net>
 */
index d6d2460d7fab6fa05494afe6db98a70feda72eb7..14466418babaa6957fa90f708ac532933e386f6f 100644 (file)
@@ -7,7 +7,7 @@
 * Technical choices are described in the 'docs/technical' file
 *
 * @package Cache_Lite
-* @version $Id: Output.php,v 1.1 2004/12/02 14:23:52 nohn Exp $
+* @version $Id: Output.php,v 1.3 2005/04/17 21:40:18 fab Exp $
 * @author Fabien MARTY <fab@php.net>
 */
 
@@ -37,12 +37,13 @@ class Cache_Lite_Output extends Cache_Lite
     *
     * @param string $id cache id
     * @param string $group name of the cache group
+    * @param boolean $doNotTestCacheValidity if set to true, the cache validity won't be tested
     * @return boolean true if the cache is hit (false else)
     * @access public
     */
-    function start($id, $group = 'default')
+    function start($id, $group = 'default', $doNotTestCacheValidity = false)
     {
-        $data = $this->get($id, $group);
+        $data = $this->get($id, $group, $doNotTestCacheValidity);
         if ($data !== false) {
             echo($data);
             return true;
index ce918fb1935f712afce6e5179017aa7829020eba..581dbc6607b6d4bb22d3de7d8192376e2a8abb67 100644 (file)
@@ -32,7 +32,7 @@
 // | Author: Richard Heyes <richard@phpguru.org>                           |
 // +-----------------------------------------------------------------------+
 //
-// $Id: Request.php,v 1.1 2004/12/06 09:18:15 nohn Exp $
+// $Id: Request.php,v 1.41 2004/12/10 14:42:57 avb Exp $
 //
 // HTTP_Request Class
 //
@@ -62,7 +62,7 @@ class HTTP_Request {
 
     /**
     * Instance of Net_URL
-    * @var object    
+    * @var object Net_URL
     */
     var $_url;
 
@@ -98,7 +98,7 @@ class HTTP_Request {
 
     /**
     * Socket object
-    * @var object
+    * @var object Net_Socket
     */
     var $_sock;
     
@@ -140,13 +140,13 @@ class HTTP_Request {
 
     /**
     * Connection timeout.
-    * @var integer
+    * @var float
     */
     var $_timeout;
     
     /**
     * HTTP_Response object
-    * @var object
+    * @var object HTTP_Response
     */
     var $_response;
     
@@ -202,21 +202,25 @@ class HTTP_Request {
     * Constructor
     *
     * Sets up the object
-    * @param $url The url to fetch/access
-    * @param $params Associative array of parameters which can be:
-    *                  method         - Method to use, GET, POST etc
-    *                  http           - HTTP Version to use, 1.0 or 1.1
-    *                  user           - Basic Auth username
-    *                  pass           - Basic Auth password
-    *                  proxy_host     - Proxy server host
-    *                  proxy_port     - Proxy server port
-    *                  proxy_user     - Proxy auth username
-    *                  proxy_pass     - Proxy auth password
-    *                  timeout        - Connection timeout in seconds.
-    *                  allowRedirects - Whether to follow redirects or not
-    *                  maxRedirects   - Max number of redirects to follow
-    *                  useBrackets    - Whether to append [] to array variable names
-    *                  saveBody       - Whether to save response body in response object property
+    * @param    string  The url to fetch/access
+    * @param    array   Associative array of parameters which can have the following keys:
+    * <ul>
+    *   <li>method         - Method to use, GET, POST etc (string)</li>
+    *   <li>http           - HTTP Version to use, 1.0 or 1.1 (string)</li>
+    *   <li>user           - Basic Auth username (string)</li>
+    *   <li>pass           - Basic Auth password (string)</li>
+    *   <li>proxy_host     - Proxy server host (string)</li>
+    *   <li>proxy_port     - Proxy server port (integer)</li>
+    *   <li>proxy_user     - Proxy auth username (string)</li>
+    *   <li>proxy_pass     - Proxy auth password (string)</li>
+    *   <li>timeout        - Connection timeout in seconds (float)</li>
+    *   <li>allowRedirects - Whether to follow redirects or not (bool)</li>
+    *   <li>maxRedirects   - Max number of redirects to follow (integer)</li>
+    *   <li>useBrackets    - Whether to append [] to array variable names (bool)</li>
+    *   <li>saveBody       - Whether to save response body in response object property (bool)</li>
+    *   <li>readTimeout    - Timeout for reading / writing data over the socket (array (seconds, microseconds))</li>
+    *   <li>socketOptions  - Options to pass to Net_Socket object (array)</li>
+    * </ul>
     * @access public
     */
     function HTTP_Request($url = '', $params = array())
@@ -1068,7 +1072,12 @@ class HTTP_Response
             $cookie['value'] = trim(substr($elements[0], $pos + 1));
 
             for ($i = 1; $i < count($elements); $i++) {
-                list ($elName, $elValue) = array_map('trim', explode('=', $elements[$i]));
+                if (false === strpos($elements[$i], '=')) {
+                    $elName  = trim($elements[$i]);
+                    $elValue = null;
+                } else {
+                    list ($elName, $elValue) = array_map('trim', explode('=', $elements[$i]));
+                }
                 $elName = strtolower($elName);
                 if ('secure' == $elName) {
                     $cookie['secure'] = true;
@@ -1103,6 +1112,8 @@ class HTTP_Response
                     $this->_sock->readAll(); // make this an eof()
                     return '';
                 }
+            } elseif ($this->_sock->eof()) {
+                return '';
             }
         }
         $data = $this->_sock->read($this->_chunkLength);
index 70d473127cb65abbaee199ce4035cbd687d21a0c..38b115a61aa168913a0c6f935252086683870ac7 100644 (file)
@@ -32,7 +32,7 @@
 // | Author: Alexey Borzov <avb@php.net>                                  |
 // +-----------------------------------------------------------------------+
 //
-// $Id: Listener.php,v 1.1 2004/12/06 09:18:23 nohn Exp $
+// $Id: Listener.php,v 1.2 2003/10/26 10:28:29 avb Exp $
 //
 
 /**
@@ -42,7 +42,7 @@
  *
  * @package HTTP_Request
  * @author  Alexey Borzov <avb@php.net>
- * @version $Revision: 1.1 $
+ * @version $Revision: 1.2 $
  */
 class HTTP_Request_Listener 
 {
index 2e3f15a26eb70181c9738cbe9adf63c11c26f0ff..b0fbc73e5078a466c7672173dd129cb14d8584bf 100644 (file)
@@ -17,7 +17,7 @@
 // |          Guido Haeger <gh-lists@ecora.de>                            |
 // +----------------------------------------------------------------------+
 //
-// $Id: CheckIP.php,v 1.2 2004/11/19 11:05:24 garvinhicking Exp $
+// $Id: CheckIP.php,v 1.5 2002/08/17 09:41:24 mj Exp $
 
 /**
 * Class to validate the syntax of IPv4 adresses
index 9d73e06d2a99039a623ac336afd2666aa435fbf8..7c4ff1d4e21646ce33507dce2ad2a78e5c13831b 100644 (file)
 // |          Chuck Hagenbuch <chuck@horde.org>                           |
 // +----------------------------------------------------------------------+
 //
-// $Id: Socket.php,v 1.1 2004/12/06 09:18:23 nohn Exp $
-//
+// $Id: Socket.php,v 1.24 2005/02/03 20:40:16 chagenbu Exp $
 
 require_once 'PEAR.php';
 
+define('NET_SOCKET_READ',  1);
+define('NET_SOCKET_WRITE', 2);
+define('NET_SOCKET_ERROR', 3);
+
 /**
- * Generalized Socket class. More docs to be written.
+ * Generalized Socket class.
  *
- * @version 1.0
+ * @version 1.1
  * @author Stig Bakken <ssb@php.net>
  * @author Chuck Hagenbuch <chuck@horde.org>
  */
 class Net_Socket extends PEAR {
-    // {{{ properties
 
-    /** Socket file pointer. */
+    /**
+     * Socket file pointer.
+     * @var resource $fp
+     */
     var $fp = null;
 
-    /** Whether the socket is blocking. */
+    /**
+     * Whether the socket is blocking. Defaults to true.
+     * @var boolean $blocking
+     */
     var $blocking = true;
 
-    /** Whether the socket is persistent. */
+    /**
+     * Whether the socket is persistent. Defaults to false.
+     * @var boolean $persistent
+     */
     var $persistent = false;
 
-    /** The IP address to connect to. */
+    /**
+     * The IP address to connect to.
+     * @var string $addr
+     */
     var $addr = '';
 
-    /** The port number to connect to. */
+    /**
+     * The port number to connect to.
+     * @var integer $port
+     */
     var $port = 0;
 
-    /** Number of seconds to wait on socket connections before
-        assuming there's no more data. */
+    /**
+     * Number of seconds to wait on socket connections before assuming
+     * there's no more data. Defaults to no timeout.
+     * @var integer $timeout
+     */
     var $timeout = false;
 
-    /** Number of bytes to read at a time in readLine() and
-        readAll(). */
-    var $lineLength = 2048;
-    // }}}
-
-    // {{{ constructor
     /**
-     * Constructs a new Net_Socket object.
-     *
-     * @access public
+     * Number of bytes to read at a time in readLine() and
+     * readAll(). Defaults to 2048.
+     * @var integer $lineLength
      */
-    function Net_Socket()
-    {
-        $this->PEAR();
-    }
-    // }}}
+    var $lineLength = 2048;
 
-    // {{{ connect()
     /**
      * Connect to the specified port. If called when the socket is
      * already connected, it disconnects and connects again.
      *
-     * @param $addr string IP address or host name
-     * @param $port int TCP port number
-     * @param $persistent bool (optional) whether the connection is
-     *        persistent (kept open between requests by the web server)
-     * @param $timeout int (optional) how long to wait for data
-     * @param $options array see options for stream_context_create
+     * @param string  $addr        IP address or host name.
+     * @param integer $port        TCP port number.
+     * @param boolean $persistent  (optional) Whether the connection is
+     *                             persistent (kept open between requests
+     *                             by the web server).
+     * @param integer $timeout     (optional) How long to wait for data.
+     * @param array   $options     See options for stream_context_create.
+     *
      * @access public
-     * @return mixed true on success or error object
+     *
+     * @return boolean | PEAR_Error  True on success or a PEAR_Error on failure.
      */
-    function connect($addr, $port, $persistent = null, $timeout = null, $options = null)
+    function connect($addr, $port = 0, $persistent = null, $timeout = null, $options = null)
     {
         if (is_resource($this->fp)) {
             @fclose($this->fp);
             $this->fp = null;
         }
 
-        if (strspn($addr, '.0123456789') == strlen($addr)) {
+        if (!$addr) {
+            return $this->raiseError('$addr cannot be empty');
+        } elseif (strspn($addr, '.0123456789') == strlen($addr) ||
+                  strstr($addr, '/') !== false) {
             $this->addr = $addr;
         } else {
-            $this->addr = gethostbyname($addr);
+            $this->addr = @gethostbyname($addr);
         }
+
         $this->port = $port % 65536;
+
         if ($persistent !== null) {
             $this->persistent = $persistent;
         }
+
         if ($timeout !== null) {
             $this->timeout = $timeout;
         }
+
         $openfunc = $this->persistent ? 'pfsockopen' : 'fsockopen';
         $errno = 0;
         $errstr = '';
@@ -111,7 +130,7 @@ class Net_Socket extends PEAR {
                 $timeout = 0;
             }
             $context = stream_context_create($options);
-            $fp = $openfunc($this->addr, $this->port, $errno, $errstr, $timeout, $context);
+            $fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $timeout, $context);
         } else {
             if ($this->timeout) {
                 $fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $this->timeout);
@@ -128,9 +147,7 @@ class Net_Socket extends PEAR {
 
         return $this->setBlocking($this->blocking);
     }
-    // }}}
 
-    // {{{ disconnect()
     /**
      * Disconnects from the peer, closes the socket.
      *
@@ -139,71 +156,65 @@ class Net_Socket extends PEAR {
      */
     function disconnect()
     {
-        if (is_resource($this->fp)) {
-            fclose($this->fp);
-            $this->fp = null;
-            return true;
+        if (!is_resource($this->fp)) {
+            return $this->raiseError('not connected');
         }
-        return $this->raiseError("not connected");
+
+        @fclose($this->fp);
+        $this->fp = null;
+        return true;
     }
-    // }}}
 
-    // {{{ isBlocking()
     /**
      * Find out if the socket is in blocking mode.
      *
      * @access public
-     * @return bool the current blocking mode.
+     * @return boolean  The current blocking mode.
      */
     function isBlocking()
     {
         return $this->blocking;
     }
-    // }}}
 
-    // {{{ setBlocking()
     /**
      * Sets whether the socket connection should be blocking or
      * not. A read call to a non-blocking socket will return immediately
      * if there is no data available, whereas it will block until there
      * is data for blocking sockets.
      *
-     * @param $mode bool true for blocking sockets, false for nonblocking
+     * @param boolean $mode  True for blocking sockets, false for nonblocking.
      * @access public
      * @return mixed true on success or an error object otherwise
      */
     function setBlocking($mode)
     {
-        if (is_resource($this->fp)) {
-            $this->blocking = $mode;
-            socket_set_blocking($this->fp, $this->blocking);
-            return true;
+        if (!is_resource($this->fp)) {
+            return $this->raiseError('not connected');
         }
-        return $this->raiseError("not connected");
+
+        $this->blocking = $mode;
+        socket_set_blocking($this->fp, $this->blocking);
+        return true;
     }
-    // }}}
 
-    // {{{ setTimeout()
     /**
      * Sets the timeout value on socket descriptor,
      * expressed in the sum of seconds and microseconds
      *
-     * @param $seconds int seconds
-     * @param $microseconds int microseconds
+     * @param integer $seconds  Seconds.
+     * @param integer $microseconds  Microseconds.
      * @access public
      * @return mixed true on success or an error object otherwise
      */
     function setTimeout($seconds, $microseconds)
     {
-        if (is_resource($this->fp)) {
-            socket_set_timeout($this->fp, $seconds, $microseconds);
-            return true;
+        if (!is_resource($this->fp)) {
+            return $this->raiseError('not connected');
         }
-        return $this->raiseError("not connected");
+
+        return socket_set_timeout($this->fp, $seconds, $microseconds);
     }
-    // }}}
 
-    // {{{ getStatus()
     /**
      * Returns information about an existing socket resource.
      * Currently returns four entries in the result array:
@@ -220,14 +231,13 @@ class Net_Socket extends PEAR {
      */
     function getStatus()
     {
-        if (is_resource($this->fp)) {
-            return socket_get_status($this->fp);
+        if (!is_resource($this->fp)) {
+            return $this->raiseError('not connected');
         }
-        return $this->raiseError("not connected");
+
+        return socket_get_status($this->fp);
     }
-    // }}}
 
-    // {{{ gets()
     /**
      * Get a specified line of data
      *
@@ -237,69 +247,87 @@ class Net_Socket extends PEAR {
      */
     function gets($size)
     {
-        if (is_resource($this->fp)) {
-            return fgets($this->fp, $size);
+        if (!is_resource($this->fp)) {
+            return $this->raiseError('not connected');
         }
-        return $this->raiseError("not connected");
+
+        return @fgets($this->fp, $size);
     }
-    // }}}
 
-    // {{{ read()
     /**
      * Read a specified amount of data. This is guaranteed to return,
      * and has the added benefit of getting everything in one fread()
      * chunk; if you know the size of the data you're getting
      * beforehand, this is definitely the way to go.
      *
-     * @param $size The number of bytes to read from the socket.
+     * @param integer $size  The number of bytes to read from the socket.
      * @access public
      * @return $size bytes of data from the socket, or a PEAR_Error if
      *         not connected.
      */
     function read($size)
     {
-        if (is_resource($this->fp)) {
-            return fread($this->fp, $size);
+        if (!is_resource($this->fp)) {
+            return $this->raiseError('not connected');
         }
-        return $this->raiseError("not connected");
+
+        return @fread($this->fp, $size);
     }
-    // }}}
 
-    // {{{ write()
     /**
      * Write a specified amount of data.
      *
+     * @param string  $data       Data to write.
+     * @param integer $blocksize  Amount of data to write at once.
+     *                            NULL means all at once.
+     *
      * @access public
      * @return mixed true on success or an error object otherwise
      */
-    function write($data)
+    function write($data, $blocksize = null)
     {
-        if (is_resource($this->fp)) {
+        if (!is_resource($this->fp)) {
+            return $this->raiseError('not connected');
+        }
+
+        if (is_null($blocksize) && !OS_WINDOWS) {
             return fwrite($this->fp, $data);
+        } else {
+            if (is_null($blocksize)) {
+                $blocksize = 1024;
+            }
+
+            $pos = 0;
+            $size = strlen($data);
+            while ($pos < $size) {
+                $written = @fwrite($this->fp, substr($data, $pos, $blocksize));
+                if ($written === false) {
+                    return false;
+                }
+                $pos += $written;
+            }
+
+            return $pos;
         }
-        return $this->raiseError("not connected");
     }
-    // }}}
 
-    // {{{ writeLine()
     /**
      * Write a line of data to the socket, followed by a trailing "\r\n".
      *
      * @access public
      * @return mixed fputs result, or an error
      */
-    function writeLine ($data)
+    function writeLine($data)
     {
-        if (is_resource($this->fp)) {
-            return $this->write($data . "\r\n");
+        if (!is_resource($this->fp)) {
+            return $this->raiseError('not connected');
         }
-        return $this->raiseError("not connected");
+
+        return fwrite($this->fp, $data . "\r\n");
     }
-    // }}}
 
-    // {{{ eof()
     /**
-     * Tests for end-of-file on a socket descriptor
+     * Tests for end-of-file on a socket descriptor.
      *
      * @access public
      * @return bool
@@ -308,9 +336,7 @@ class Net_Socket extends PEAR {
     {
         return (is_resource($this->fp) && feof($this->fp));
     }
-    // }}}
 
-    // {{{ readByte()
     /**
      * Reads a byte of data
      *
@@ -320,14 +346,13 @@ class Net_Socket extends PEAR {
      */
     function readByte()
     {
-        if (is_resource($this->fp)) {
-            return ord($this->read(1));
+        if (!is_resource($this->fp)) {
+            return $this->raiseError('not connected');
         }
-        return $this->raiseError("not connected");
+
+        return ord(@fread($this->fp, 1));
     }
-    // }}}
 
-    // {{{ readWord()
     /**
      * Reads a word of data
      *
@@ -337,36 +362,34 @@ class Net_Socket extends PEAR {
      */
     function readWord()
     {
-        if (is_resource($this->fp)) {
-            $buf = $this->read(2);
-            return (ord($buf[0]) + (ord($buf[1]) << 8));
+        if (!is_resource($this->fp)) {
+            return $this->raiseError('not connected');
         }
-        return $this->raiseError("not connected");
+
+        $buf = @fread($this->fp, 2);
+        return (ord($buf[0]) + (ord($buf[1]) << 8));
     }
-    // }}}
 
-    // {{{ readInt()
     /**
      * Reads an int of data
      *
      * @access public
-     * @return 1 int of data from the socket, or a PEAR_Error if
-     *         not connected.
+     * @return integer  1 int of data from the socket, or a PEAR_Error if
+     *                  not connected.
      */
     function readInt()
     {
-        if (is_resource($this->fp)) {
-            $buf = $this->read(4);
-            return (ord($buf[0]) + (ord($buf[1]) << 8) +
-                    (ord($buf[2]) << 16) + (ord($buf[3]) << 24));
+        if (!is_resource($this->fp)) {
+            return $this->raiseError('not connected');
         }
-        return $this->raiseError("not connected");
+
+        $buf = @fread($this->fp, 4);
+        return (ord($buf[0]) + (ord($buf[1]) << 8) +
+                (ord($buf[2]) << 16) + (ord($buf[3]) << 24));
     }
-    // }}}
 
-    // {{{ readString()
     /**
-     * Reads a zeroterminated string of data
+     * Reads a zero-terminated string of data
      *
      * @access public
      * @return string, or a PEAR_Error if
@@ -374,18 +397,17 @@ class Net_Socket extends PEAR {
      */
     function readString()
     {
-        if (is_resource($this->fp)) {
-            $string = '';
-            while (($char = $this->read(1)) != "\x00")  {
-                $string .= $char;
-            }
-            return $string;
+        if (!is_resource($this->fp)) {
+            return $this->raiseError('not connected');
         }
-        return $this->raiseError("not connected");
+
+        $string = '';
+        while (($char = @fread($this->fp, 1)) != "\x00")  {
+            $string .= $char;
+        }
+        return $string;
     }
-    // }}}
 
-    // {{{ readIPAddress()
     /**
      * Reads an IP Address and returns it in a dot formated string
      *
@@ -395,16 +417,15 @@ class Net_Socket extends PEAR {
      */
     function readIPAddress()
     {
-        if (is_resource($this->fp)) {
-            $buf = $this->read(4);
-            return sprintf("%s.%s.%s.%s", ord($buf[0]), ord($buf[1]),
-                           ord($buf[2]), ord($buf[3]));
+        if (!is_resource($this->fp)) {
+            return $this->raiseError('not connected');
         }
-        return $this->raiseError("not connected");
+
+        $buf = @fread($this->fp, 4);
+        return sprintf("%s.%s.%s.%s", ord($buf[0]), ord($buf[1]),
+                       ord($buf[2]), ord($buf[3]));
     }
-    // }}}
 
-    // {{{ readLine()
     /**
      * Read until either the end of the socket or a newline, whichever
      * comes first. Strips the trailing newline from the returned data.
@@ -416,41 +437,92 @@ class Net_Socket extends PEAR {
      */
     function readLine()
     {
-        if (is_resource($this->fp)) {
-            $line = '';
-            $timeout = time() + $this->timeout;
-            while (!$this->eof() && (!$this->timeout || time() < $timeout)) {
-                $line .= $this->gets($this->lineLength);
-                if (substr($line, -2) == "\r\n" ||
-                    substr($line, -1) == "\n") {
-                    return rtrim($line, "\r\n");
-                }
+        if (!is_resource($this->fp)) {
+            return $this->raiseError('not connected');
+        }
+
+        $line = '';
+        $timeout = time() + $this->timeout;
+        while (!feof($this->fp) && (!$this->timeout || time() < $timeout)) {
+            $line .= @fgets($this->fp, $this->lineLength);
+            if (substr($line, -1) == "\n") {
+                return rtrim($line, "\r\n");
             }
-            return $line;
         }
-        return $this->raiseError("not connected");
+        return $line;
     }
-    // }}}
 
-    // {{{ readAll()
     /**
-     * Read until the socket closes. THIS FUNCTION WILL NOT EXIT if the
-     * socket is in blocking mode until the socket closes.
+     * Read until the socket closes, or until there is no more data in
+     * the inner PHP buffer. If the inner buffer is empty, in blocking
+     * mode we wait for at least 1 byte of data. Therefore, in
+     * blocking mode, if there is no data at all to be read, this
+     * function will never exit (unless the socket is closed on the
+     * remote end).
      *
      * @access public
-     * @return All data until the socket closes, or a PEAR_Error if
-     *         not connected.
+     *
+     * @return string  All data until the socket closes, or a PEAR_Error if
+     *                 not connected.
      */
     function readAll()
     {
-        if (is_resource($this->fp)) {
-            $data = '';
-            while (!$this->eof())
-                $data .= $this->read($this->lineLength);
-            return $data;
+        if (!is_resource($this->fp)) {
+            return $this->raiseError('not connected');
+        }
+
+        $data = '';
+        while (!feof($this->fp)) {
+            $data .= @fread($this->fp, $this->lineLength);
+        }
+        return $data;
+    }
+
+    /**
+     * Runs the equivalent of the select() system call on the socket
+     * with a timeout specified by tv_sec and tv_usec.
+     *
+     * @param integer $state    Which of read/write/error to check for.
+     * @param integer $tv_sec   Number of seconds for timeout.
+     * @param integer $tv_usec  Number of microseconds for timeout.
+     *
+     * @access public
+     * @return False if select fails, integer describing which of read/write/error
+     *         are ready, or PEAR_Error if not connected.
+     */
+    function select($state, $tv_sec, $tv_usec = 0)
+    {
+        if (!is_resource($this->fp)) {
+            return $this->raiseError('not connected');
+        }
+
+        $read = null;
+        $write = null;
+        $except = null;
+        if ($state & NET_SOCKET_READ) {
+            $read[] = $this->fp;
+        }
+        if ($state & NET_SOCKET_WRITE) {
+            $write[] = $this->fp;
+        }
+        if ($state & NET_SOCKET_ERROR) {
+            $except[] = $this->fp;
+        }
+        if (false === ($sr = stream_select($read, $write, $except, $tv_sec, $tv_usec))) {
+            return false;
+        }
+
+        $result = 0;
+        if (count($read)) {
+            $result |= NET_SOCKET_READ;
+        }
+        if (count($write)) {
+            $result |= NET_SOCKET_WRITE;
+        }
+        if (count($except)) {
+            $result |= NET_SOCKET_ERROR;
         }
-        return $this->raiseError("not connected");
+        return $result;
     }
-    // }}}
 
 }
index 349c59c5f7ef6a8bd0a34cffd396279810999542..6331fc0ac94f6ef63a35df9ebd21ca0290179c38 100644 (file)
@@ -32,7 +32,7 @@
 // | Author: Richard Heyes <richard at php net>                            |
 // +-----------------------------------------------------------------------+
 //
-// $Id: URL.php,v 1.1 2004/12/06 09:18:23 nohn Exp $
+// $Id: URL.php,v 1.36 2004/06/19 18:58:50 richard Exp $
 //
 // Net_URL Class
 
index 5ed8eacda9263ae544d309eb69317e972c87ca72..6f4d65251ffdbd6e34d00aca88c5a4954533a466 100644 (file)
@@ -1,24 +1,24 @@
 <?php
 //
-// +----------------------------------------------------------------------+
-// | PEAR, the PHP Extension and Application Repository                   |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2003 The PHP Group                                |
-// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.0 of the PHP license,       |
-// | that is bundled with this package in the file LICENSE, and is        |
-// | available at through the world-wide-web at                           |
-// | http://www.php.net/license/2_02.txt.                                 |
-// | If you did not receive a copy of the PHP license and are unable to   |
-// | obtain it through the world-wide-web, please send a note to          |
-// | license@php.net so we can mail you a copy immediately.               |
-// +----------------------------------------------------------------------+
-// | Authors: Sterling Hughes <sterling@php.net>                          |
-// |          Stig Bakken <ssb@fast.no>                                   |
-// |          Tomas V.V.Cox <cox@idecnet.com>                             |
-// +----------------------------------------------------------------------+
+// +--------------------------------------------------------------------+
+// | PEAR, the PHP Extension and Application Repository                 |
+// +--------------------------------------------------------------------+
+// | Copyright (c) 1997-2004 The PHP Group                              |
+// +--------------------------------------------------------------------+
+// | This source file is subject to version 3.0 of the PHP license,     |
+// | that is bundled with this package in the file LICENSE, and is      |
+// | available through the world-wide-web at the following url:         |
+// | http://www.php.net/license/3_0.txt.                                |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to        |
+// | license@php.net so we can mail you a copy immediately.             |
+// +--------------------------------------------------------------------+
+// | Authors: Sterling Hughes <sterling@php.net>                        |
+// |          Stig Bakken <ssb@php.net>                                 |
+// |          Tomas V.V.Cox <cox@idecnet.com>                           |
+// +--------------------------------------------------------------------+
 //
-// $Id: PEAR.php,v 1.1.1.1 2003/03/28 20:05:27 sterling Exp $
+// $Id: PEAR.php,v 1.83 2005/03/28 16:38:58 cellog Exp $
 //
 
 define('PEAR_ERROR_RETURN',     1);
@@ -26,6 +26,10 @@ define('PEAR_ERROR_PRINT',      2);
 define('PEAR_ERROR_TRIGGER',    4);
 define('PEAR_ERROR_DIE',        8);
 define('PEAR_ERROR_CALLBACK',  16);
+/**
+ * WARNING: obsolete
+ * @deprecated
+ */
 define('PEAR_ERROR_EXCEPTION', 32);
 define('PEAR_ZE2', (function_exists('version_compare') &&
                     version_compare(zend_version(), "2-dev", "ge")));
@@ -40,13 +44,22 @@ if (substr(PHP_OS, 0, 3) == 'WIN') {
     define('PEAR_OS',    'Unix'); // blatant assumption
 }
 
+// instant backwards compatibility
+if (!defined('PATH_SEPARATOR')) {
+    if (OS_WINDOWS) {
+        define('PATH_SEPARATOR', ';');
+    } else {
+        define('PATH_SEPARATOR', ':');
+    }
+}
+
 $GLOBALS['_PEAR_default_error_mode']     = PEAR_ERROR_RETURN;
 $GLOBALS['_PEAR_default_error_options']  = E_USER_NOTICE;
 $GLOBALS['_PEAR_destructor_object_list'] = array();
 $GLOBALS['_PEAR_shutdown_funcs']         = array();
 $GLOBALS['_PEAR_error_handler_stack']    = array();
 
-ini_set('track_errors', true);
+@ini_set('track_errors', true);
 
 /**
  * Base class for other PEAR classes.  Provides rudimentary
@@ -63,10 +76,10 @@ ini_set('track_errors', true);
  * destructor, use error_log(), syslog() or something similar.
  *
  * IMPORTANT! To use the emulated destructors you need to create the
- * objects by reference, ej: $obj =& new PEAR_child;
+ * objects by reference: $obj =& new PEAR_child;
  *
  * @since PHP 4.0.2
- * @author Stig Bakken <ssb@fast.no>
+ * @author Stig Bakken <ssb@php.net>
  * @see http://pear.php.net/manual/
  */
 class PEAR
@@ -139,18 +152,22 @@ class PEAR
      */
     function PEAR($error_class = null)
     {
-        $classname = get_class($this);
+        $classname = strtolower(get_class($this));
         if ($this->_debug) {
             print "PEAR constructor called, class=$classname\n";
         }
         if ($error_class !== null) {
             $this->_error_class = $error_class;
         }
-        while ($classname) {
+        while ($classname && strcasecmp($classname, "pear")) {
             $destructor = "_$classname";
             if (method_exists($this, $destructor)) {
                 global $_PEAR_destructor_object_list;
                 $_PEAR_destructor_object_list[] = &$this;
+                if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) {
+                    register_shutdown_function("_PEAR_call_destructors");
+                    $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true;
+                }
                 break;
             } else {
                 $classname = get_parent_class($classname);
@@ -174,7 +191,7 @@ class PEAR
      */
     function _PEAR() {
         if ($this->_debug) {
-            printf("PEAR destructor called, class=%s\n", get_class($this));
+            printf("PEAR destructor called, class=%s\n", strtolower(get_class($this)));
         }
     }
 
@@ -184,7 +201,7 @@ class PEAR
     /**
     * If you have a class that's mostly/entirely static, and you need static
     * properties, you can use this method to simulate them. Eg. in your method(s)
-    * do this: $myVar = &PEAR::getStaticProperty('myVar');
+    * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar');
     * You MUST use a reference, or they will not persist!
     *
     * @access public
@@ -224,15 +241,22 @@ class PEAR
      *
      * @param   mixed $data   the value to test
      * @param   int   $code   if $data is an error object, return true
-     *                        only if $obj->getCode() == $code
+     *                        only if $code is a string and
+     *                        $obj->getMessage() == $code or
+     *                        $code is an integer and $obj->getCode() == $code
      * @access  public
      * @return  bool    true if parameter is an error
      */
     function isError($data, $code = null)
     {
-        if (is_object($data) && (get_class($data) == 'pear_error' ||
-                                 is_subclass_of($data, 'pear_error'))) {
-            return $code === null ? true : $data->getCode() == $code;
+        if (is_a($data, 'PEAR_Error')) {
+            if (is_null($code)) {
+                return true;
+            } elseif (is_string($code)) {
+                return $data->getMessage() == $code;
+            } else {
+                return $data->getCode() == $code;
+            }
         }
         return false;
     }
@@ -281,7 +305,7 @@ class PEAR
 
     function setErrorHandling($mode = null, $options = null)
     {
-        if (isset($this)) {
+        if (isset($this) && is_a($this, 'PEAR')) {
             $setmode     = &$this->_default_error_mode;
             $setoptions  = &$this->_default_error_options;
         } else {
@@ -290,11 +314,11 @@ class PEAR
         }
 
         switch ($mode) {
+            case PEAR_ERROR_EXCEPTION:
             case PEAR_ERROR_RETURN:
             case PEAR_ERROR_PRINT:
             case PEAR_ERROR_TRIGGER:
             case PEAR_ERROR_DIE:
-            case PEAR_ERROR_EXCEPTION:
             case null:
                 $setmode = $mode;
                 $setoptions = $options;
@@ -302,9 +326,8 @@ class PEAR
 
             case PEAR_ERROR_CALLBACK:
                 $setmode = $mode;
-                if ((is_string($options) && function_exists($options)) ||
-                    (is_array($options) && method_exists(@$options[0], @$options[1])))
-                {
+                // class/object method callback
+                if (is_callable($options)) {
                     $setoptions = $options;
                 } else {
                     trigger_error("invalid error callback", E_USER_WARNING);
@@ -408,7 +431,7 @@ class PEAR
             // $error_code is a non-empty array here;
             // we walk through it trying to unset all
             // values
-            foreach($error_code AS $key => $error) {
+            foreach($error_code as $key => $error) {
                 if ($this->_checkDelExpect($error)) {
                     $deleted =  true;
                 } else {
@@ -469,7 +492,7 @@ class PEAR
      * @see PEAR::setErrorHandling
      * @since PHP 4.0.5
      */
-    function &raiseError($message = null,
+    function raiseError($message = null,
                          $code = null,
                          $mode = null,
                          $options = null,
@@ -482,6 +505,7 @@ class PEAR
             $code        = $message->getCode();
             $userinfo    = $message->getUserInfo();
             $error_class = $message->getType();
+            $message->error_message_prefix = '';
             $message     = $message->getMessage();
         }
 
@@ -529,11 +553,11 @@ class PEAR
      * @param string $message
      *
      */
-    function &throwError($message = null,
+    function throwError($message = null,
                          $code = null,
                          $userinfo = null)
     {
-        if (isset($this)) {
+        if (isset($this) && is_a($this, 'PEAR')) {
             return $this->raiseError($message, $code, null, null, $userinfo);
         } else {
             return PEAR::raiseError($message, $code, null, null, $userinfo);
@@ -541,6 +565,77 @@ class PEAR
     }
 
     // }}}
+    function staticPushErrorHandling($mode, $options = null)
+    {
+        $stack = &$GLOBALS['_PEAR_error_handler_stack'];
+        $def_mode    = &$GLOBALS['_PEAR_default_error_mode'];
+        $def_options = &$GLOBALS['_PEAR_default_error_options'];
+        $stack[] = array($def_mode, $def_options);
+        switch ($mode) {
+            case PEAR_ERROR_EXCEPTION:
+            case PEAR_ERROR_RETURN:
+            case PEAR_ERROR_PRINT:
+            case PEAR_ERROR_TRIGGER:
+            case PEAR_ERROR_DIE:
+            case null:
+                $def_mode = $mode;
+                $def_options = $options;
+                break;
+
+            case PEAR_ERROR_CALLBACK:
+                $def_mode = $mode;
+                // class/object method callback
+                if (is_callable($options)) {
+                    $def_options = $options;
+                } else {
+                    trigger_error("invalid error callback", E_USER_WARNING);
+                }
+                break;
+
+            default:
+                trigger_error("invalid error mode", E_USER_WARNING);
+                break;
+        }
+        $stack[] = array($mode, $options);
+        return true;
+    }
+
+    function staticPopErrorHandling()
+    {
+        $stack = &$GLOBALS['_PEAR_error_handler_stack'];
+        $setmode     = &$GLOBALS['_PEAR_default_error_mode'];
+        $setoptions  = &$GLOBALS['_PEAR_default_error_options'];
+        array_pop($stack);
+        list($mode, $options) = $stack[sizeof($stack) - 1];
+        array_pop($stack);
+        switch ($mode) {
+            case PEAR_ERROR_EXCEPTION:
+            case PEAR_ERROR_RETURN:
+            case PEAR_ERROR_PRINT:
+            case PEAR_ERROR_TRIGGER:
+            case PEAR_ERROR_DIE:
+            case null:
+                $setmode = $mode;
+                $setoptions = $options;
+                break;
+
+            case PEAR_ERROR_CALLBACK:
+                $setmode = $mode;
+                // class/object method callback
+                if (is_callable($options)) {
+                    $setoptions = $options;
+                } else {
+                    trigger_error("invalid error callback", E_USER_WARNING);
+                }
+                break;
+
+            default:
+                trigger_error("invalid error mode", E_USER_WARNING);
+                break;
+        }
+        return true;
+    }
+
     // {{{ pushErrorHandling()
 
     /**
@@ -558,7 +653,7 @@ class PEAR
     function pushErrorHandling($mode, $options = null)
     {
         $stack = &$GLOBALS['_PEAR_error_handler_stack'];
-        if (isset($this)) {
+        if (isset($this) && is_a($this, 'PEAR')) {
             $def_mode    = &$this->_default_error_mode;
             $def_options = &$this->_default_error_options;
         } else {
@@ -567,7 +662,7 @@ class PEAR
         }
         $stack[] = array($def_mode, $def_options);
 
-        if (isset($this)) {
+        if (isset($this) && is_a($this, 'PEAR')) {
             $this->setErrorHandling($mode, $options);
         } else {
             PEAR::setErrorHandling($mode, $options);
@@ -592,7 +687,7 @@ class PEAR
         array_pop($stack);
         list($mode, $options) = $stack[sizeof($stack) - 1];
         array_pop($stack);
-        if (isset($this)) {
+        if (isset($this) && is_a($this, 'PEAR')) {
             $this->setErrorHandling($mode, $options);
         } else {
             PEAR::setErrorHandling($mode, $options);
@@ -613,6 +708,10 @@ class PEAR
     function loadExtension($ext)
     {
         if (!extension_loaded($ext)) {
+            // if either returns true dl() will produce a FATAL error, stop that
+            if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) {
+                return false;
+            }
             if (OS_WINDOWS) {
                 $suffix = '.dll';
             } elseif (PHP_OS == 'HP-UX') {
@@ -641,6 +740,9 @@ function _PEAR_call_destructors()
         sizeof($_PEAR_destructor_object_list))
     {
         reset($_PEAR_destructor_object_list);
+        if (@PEAR::getStaticProperty('PEAR', 'destructlifo')) {
+            $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list);
+        }
         while (list($k, $objref) = each($_PEAR_destructor_object_list)) {
             $classname = get_class($objref);
             while ($classname) {
@@ -714,7 +816,9 @@ class PEAR_Error
         $this->mode      = $mode;
         $this->userinfo  = $userinfo;
         if (function_exists("debug_backtrace")) {
-            $this->backtrace = debug_backtrace();
+            if (@!PEAR::getStaticProperty('PEAR_Error', 'skiptrace')) {
+                $this->backtrace = debug_backtrace();
+            }
         }
         if ($mode & PEAR_ERROR_CALLBACK) {
             $this->level = E_USER_NOTICE;
@@ -750,18 +854,13 @@ class PEAR_Error
             die(sprintf($format, $msg));
         }
         if ($this->mode & PEAR_ERROR_CALLBACK) {
-            if (is_string($this->callback) && strlen($this->callback)) {
+            if (is_callable($this->callback)) {
                 call_user_func($this->callback, $this);
-            } elseif (is_array($this->callback) &&
-                      sizeof($this->callback) == 2 &&
-                      is_object($this->callback[0]) &&
-                      is_string($this->callback[1]) &&
-                      strlen($this->callback[1])) {
-                      @call_user_func($this->callback, $this);
             }
         }
-        if (PEAR_ZE2 && $this->mode & PEAR_ERROR_EXCEPTION) {
-            eval('throw $this;');
+        if ($this->mode & PEAR_ERROR_EXCEPTION) {
+            trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_ErrorStack for exceptions", E_USER_WARNING);
+            eval('$e = new Exception($this->message, $this->code);$e->PEAR_Error = $this;throw($e);');
         }
     }
 
@@ -910,14 +1009,16 @@ class PEAR_Error
                         E_USER_ERROR   => 'error');
         if ($this->mode & PEAR_ERROR_CALLBACK) {
             if (is_array($this->callback)) {
-                $callback = get_class($this->callback[0]) . '::' .
+                $callback = (is_object($this->callback[0]) ?
+                    strtolower(get_class($this->callback[0])) :
+                    $this->callback[0]) . '::' .
                     $this->callback[1];
             } else {
                 $callback = $this->callback;
             }
             return sprintf('[%s: message="%s" code=%d mode=callback '.
                            'callback=%s prefix="%s" info="%s"]',
-                           get_class($this), $this->message, $this->code,
+                           strtolower(get_class($this)), $this->message, $this->code,
                            $callback, $this->error_message_prefix,
                            $this->userinfo);
         }
@@ -935,7 +1036,7 @@ class PEAR_Error
         }
         return sprintf('[%s: message="%s" code=%d mode=%s level=%s '.
                        'prefix="%s" info="%s"]',
-                       get_class($this), $this->message, $this->code,
+                       strtolower(get_class($this)), $this->message, $this->code,
                        implode("|", $modes), $levels[$this->level],
                        $this->error_message_prefix,
                        $this->userinfo);
@@ -944,8 +1045,6 @@ class PEAR_Error
     // }}}
 }
 
-register_shutdown_function("_PEAR_call_destructors");
-
 /*
  * Local Variables:
  * mode: php
index 72f805e63466ce20297c716ee3ec2c28bf7a7986..291650a23a5587ba10af7166bcea7328200054a3 100644 (file)
 <?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-// +----------------------------------------------------------------------+
-// | PHP version 4                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2003 The PHP Group                                |
-// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.0 of the PHP license,       |
-// | that is bundled with this package in the file LICENSE, and is        |
-// | available through the world-wide-web at                              |
-// | http://www.php.net/license/2_02.txt.                                 |
-// | If you did not receive a copy of the PHP license and are unable to   |
-// | obtain it through the world-wide-web, please send a note to          |
-// | license@php.net so we can mail you a copy immediately.               |
-// +----------------------------------------------------------------------+
-// | Authors: Paul M. Jones <pmjones@ciaweb.net>                          |
-// +----------------------------------------------------------------------+
-//
-// $Id: Wiki.php,v 1.3 2004/12/02 10:54:30 nohn Exp $
 
-require_once 'Text/Wiki/Rule.php';
+/**
+* 
+* Parse structured wiki text and render into arbitrary formats such as XHTML.
+* 
+* @category Text
+* 
+* @package Text_Wiki
+* 
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @license LGPL
+* 
+* @version $Id: Wiki.php,v 1.29 2005/02/24 17:26:29 pmjones Exp $
+* 
+*/
+
+/**
+* The baseline abstract parser class.
+*/
+
+require_once 'Text/Wiki/Parse.php';
+
+/**
+* The baseline abstract render class.
+*/
+
+require_once 'Text/Wiki/Render.php';
 
 
 /**
 * 
+* Parse structured wiki text and render into arbitrary formats such as XHTML.
+* 
 * This is the "master" class for handling the management and convenience
 * functions to transform Wiki-formatted text.
 * 
-* @author Paul M. Jones <pmjones@ciaweb.net>
+* @category Text
+* 
+* @package Text_Wiki
 * 
-* @version 0.15 alpha
+<<<<<<< Wiki.php
+* @version 0.25.0
+*
+* @license LGPL
+=======
+* @author Paul M. Jones <pmjones@php.net>
+* 
+* @version 1.0.0
+>>>>>>> 1.28
 * 
 */
 
 class Text_Wiki {
-       
-       
-       /**
-       * 
-       * The array of rules to apply to the source text, in order.
-       * 
-       * @access public
-       * 
-       * @var array
-       * 
-       */
-       
-       var $rules = array();
-
+    
+    /**
+    * 
+    * The default list of rules, in order, to apply to the source text.
+    * 
+    * @access public
+    * 
+    * @var array
+    * 
+    */
+    
+    var $rules = array(
+        'Prefilter',
+        'Delimiter',
+        'Code',
+        'Function',
+        'Html',
+        'Raw',
+        'Include',
+        'Embed',
+        'Anchor',
+        'Heading',
+        'Toc',
+        'Horiz',
+        'Break',
+        'Blockquote',
+        'List',
+        'Deflist',
+        'Table',
+        'Image',
+        'Phplookup',
+        'Center',
+        'Newline',
+        'Paragraph',
+        'Url',
+        'Freelink',
+        'Interwiki',
+        'Wikilink',
+        'Colortext',
+        'Strong',
+        'Bold',
+        'Emphasis',
+        'Italic',
+        'Tt',
+        'Superscript',
+        'Subscript',
+        'Revise',
+        'Tighten'
+    );
+    
+    
+    /**
+    * 
+    * The list of rules to not-apply to the source text.
+    * 
+    * @access public
+    * 
+    * @var array
+    * 
+    */
+    
+    var $disable = array(
+        'Html',
+        'Include',
+        'Embed'
+    );
+    
+    
+    /**
+    * 
+    * Custom configuration for rules at the parsing stage.
+    *
+    * In this array, the key is the parsing rule name, and the value is
+    * an array of key-value configuration pairs corresponding to the $conf
+    * property in the target parsing rule.
+    * 
+    * For example:
+    * 
+    * <code>
+    * $parseConf = array(
+    *     'Include' => array(
+    *         'base' => '/path/to/scripts/'
+    *     )
+    * );
+    * </code>
+    * 
+    * Note that most default rules do not need any parsing configuration.
+    * 
+    * @access public
+    * 
+    * @var array
+    * 
+    */
+    
+    var $parseConf = array();
+    
+    
+    /**
+    * 
+    * Custom configuration for rules at the rendering stage.
+    *
+    * Because rendering may be different for each target format, the
+    * first-level element in this array is always a format name (e.g.,
+    * 'Xhtml').
+    * 
+    * Within that first level element, the subsequent elements match the
+    * $parseConf format. That is, the sub-key is the rendering rule name,
+    * and the sub-value is an array of key-value configuration pairs
+    * corresponding to the $conf property in the target rendering rule.
+    * 
+    * @access public
+    * 
+    * @var array
+    * 
+    */
+    
+    var $renderConf = array(
+        'Docbook' => array(),
+        'Latex' => array(),
+        'Pdf' => array(),
+        'Plain' => array(),
+        'Rtf' => array(),
+        'Xhtml' => array()
+    );
+    
+    
+    /**
+    * 
+    * Custom configuration for the output format itself.
+    *
+    * Even though Text_Wiki will render the tokens from parsed text,
+    * the format itself may require some configuration.  For example,
+    * RTF needs to know font names and sizes, PDF requires page layout
+    * information, and DocBook needs a section hierarchy.  This array
+    * matches the $conf property of the the format-level renderer
+    * (e.g., Text_Wiki_Render_Xhtml).
+    * 
+    * In this array, the key is the rendering format name, and the value is
+    * an array of key-value configuration pairs corresponding to the $conf
+    * property in the rendering format rule.
+    * 
+    * @access public
+    * 
+    * @var array
+    * 
+    */
+    
+    var $formatConf = array(
+        'Docbook' => array(),
+        'Latex' => array(),
+        'Pdf' => array(),
+        'Plain' => array(),
+        'Rtf' => array(),
+        'Xhtml' => array()
+    );
+    
+    
+    /**
+    * 
+    * The delimiter for token numbers of parsed elements in source text.
+    * 
+    * @access public
+    * 
+    * @var string
+    * 
+    */
+    
+    var $delim = "\xFF"; 
+    
+    
+    /**
+    * 
+    * The tokens generated by rules as the source text is parsed.
+    * 
+    * As Text_Wiki applies rule classes to the source text, it will
+    * replace portions of the text with a delimited token number.  This
+    * is the array of those tokens, representing the replaced text and
+    * any options set by the parser for that replaced text.
+    * 
+    * The tokens array is sequential; each element is itself a sequential
+    * array where element 0 is the name of the rule that generated the
+    * token, and element 1 is an associative array where the key is an
+    * option name and the value is an option value.
+    * 
+    * @access private
+    * 
+    * @var array
+    * 
+    */
+    
+    var $tokens = array();
+    
+    
+    /**
+    * 
+    * The source text to which rules will be applied.
+    * 
+    * This text will be transformed in-place, which means that it will
+    * change as the rules are applied.
+    * 
+    * @access private
+    * 
+    * @var string
+    * 
+    */
+    
+    var $source = '';
+    
+    
+    /**
+    * 
+    * Array of rule parsers.
+    * 
+    * Text_Wiki creates one instance of every rule that is applied to
+    * the source text; this array holds those instances.  The array key
+    * is the rule name, and the array value is an instance of the rule
+    * class.
+    * 
+    * @access private
+    * 
+    * @var array
+    * 
+    */
+    
+    var $parseObj = array();
+    
+    
+    /**
+    * 
+    * Array of rule renderers.
+    * 
+    * Text_Wiki creates one instance of every rule that is applied to
+    * the source text; this array holds those instances.  The array key
+    * is the rule name, and the array value is an instance of the rule
+    * class.
+    * 
+    * @access private
+    * 
+    * @var array
+    * 
+    */
+    
+    var $renderObj = array();
+    
+    
+    /**
+    * 
+    * Array of format renderers.
+    * 
+    * @access private
+    * 
+    * @var array
+    * 
+    */
+    
+    var $formatObj = array();
+    
+    
+    /**
+    * 
+    * Array of paths to search, in order, for parsing and rendering rules.
+    * 
+    * @access private
+    * 
+    * @var array
+    * 
+    */
+    
+    var $path = array(
+        'parse' => array(),
+        'render' => array()
+    );
+    
+    
+    
+    /**
+    * 
+    * The directory separator character.
+    * 
+    * @access private
+    * 
+    * @var string
+    * 
+    */
+    
+    var $_dirSep = DIRECTORY_SEPARATOR;
+    
+    
+    /**
+    * 
+    * Constructor.
+    * 
+    * @access public
+    * 
+    * @param array $rules The set of rules to load for this object.
+    *     
+    */
+    
+    function Text_Wiki($rules = null)
+    {
+        if (is_array($rules)) {
+            $this->rules = $rules;
+        }
+        
+        $this->addPath(
+            'parse',
+            $this->fixPath(dirname(__FILE__)) . 'Wiki/Parse/Default/'
+        );
+        
+        $this->addPath(
+            'render',
+            $this->fixPath(dirname(__FILE__)) . 'Wiki/Render/'
+        );
+        
+    }
+    
+    
+    /**
+    * 
+    * Set parser configuration for a specific rule and key.
+    * 
+    * @access public
+    * 
+    * @param string $rule The parse rule to set config for.
+    * 
+    * @param array|string $arg1 The full config array to use for the
+    * parse rule, or a conf key in that array.
+    * 
+    * @param string $arg2 The config value for the key.
+    * 
+    * @return void
+    *
+    */
+    
+    function setParseConf($rule, $arg1, $arg2 = null)
+    {
+        $rule = ucwords(strtolower($rule));
+        
+        if (! isset($this->parseConf[$rule])) {
+            $this->parseConf[$rule] = array();
+        }
+        
+        // if first arg is an array, use it as the entire
+        // conf array for the rule.  otherwise, treat arg1
+        // as a key and arg2 as a value for the rule conf.
+        if (is_array($arg1)) {
+            $this->parseConf[$rule] = $arg1;
+        } else {
+            $this->parseConf[$rule][$arg1] = $arg2;
+        }
+    }
+    
+    
+    /**
+    * 
+    * Get parser configuration for a specific rule and key.
+    * 
+    * @access public
+    * 
+    * @param string $rule The parse rule to get config for.
+    * 
+    * @param string $key A key in the conf array; if null,
+    * returns the entire conf array.
+    * 
+    * @return mixed The whole conf array if no key is specified,
+    * or the specific conf key value.
+    *
+    */
+    
+    function getParseConf($rule, $key = null)
+    {
+        $rule = ucwords(strtolower($rule));
+        
+        // the rule does not exist
+        if (! isset($this->parseConf[$rule])) {
+            return null;
+        }
+        
+        // no key requested, return the whole array
+        if (is_null($key)) {
+            return $this->parseConf[$rule];
+        }
+        
+        // does the requested key exist?
+        if (isset($this->parseConf[$rule][$key])) {
+            // yes, return that value
+            return $this->parseConf[$rule][$key];
+        } else {
+            // no
+            return null;
+        }
+    }
+    
+    
+    /**
+    * 
+    * Set renderer configuration for a specific format, rule, and key.
+    * 
+    * @access public
+    * 
+    * @param string $format The render format to set config for.
+    * 
+    * @param string $rule The render rule to set config for in the format.
+    * 
+    * @param array|string $arg1 The config array, or the config key
+    * within the render rule.
+    * 
+    * @param string $arg2 The config value for the key.
+    * 
+    * @return void
+    *
+    */
+    
+    function setRenderConf($format, $rule, $arg1, $arg2 = null)
+    {
+        $format = ucwords(strtolower($format));
+        $rule = ucwords(strtolower($rule));
+        
+        if (! isset($this->renderConf[$format])) {
+            $this->renderConf[$format] = array();
+        }
+        
+        if (! isset($this->renderConf[$format][$rule])) {
+            $this->renderConf[$format][$rule] = array();
+        }
+        
+        // if first arg is an array, use it as the entire
+        // conf array for the render rule.  otherwise, treat arg1
+        // as a key and arg2 as a value for the render rule conf.
+        if (is_array($arg1)) {
+            $this->renderConf[$format][$rule] = $arg1;
+        } else {
+            $this->renderConf[$format][$rule][$arg1] = $arg2;
+        }
+    }
+    
+    
+    /**
+    * 
+    * Get renderer configuration for a specific format, rule, and key.
+    * 
+    * @access public
+    * 
+    * @param string $format The render format to get config for.
+    * 
+    * @param string $rule The render format rule to get config for.
+    * 
+    * @param string $key A key in the conf array; if null,
+    * returns the entire conf array.
+    * 
+    * @return mixed The whole conf array if no key is specified,
+    * or the specific conf key value.
+    *
+    */
+    
+    function getRenderConf($format, $rule, $key = null)
+    {
+        $format = ucwords(strtolower($format));
+        $rule = ucwords(strtolower($rule));
+        
+        if (! isset($this->renderConf[$format]) ||
+            ! isset($this->renderConf[$format][$rule])) {
+            return null;
+        }
+        
+        // no key requested, return the whole array
+        if (is_null($key)) {
+            return $this->renderConf[$format][$rule];
+        }
+        
+        // does the requested key exist?
+        if (isset($this->renderConf[$format][$rule][$key])) {
+            // yes, return that value
+            return $this->renderConf[$format][$rule][$key];
+        } else {
+            // no
+            return null;
+        }
+        
+    }
+    
+    /**
+    * 
+    * Set format configuration for a specific rule and key.
+    * 
+    * @access public
+    * 
+    * @param string $format The format to set config for.
+    * 
+    * @param string $key The config key within the format.
+    * 
+    * @param string $val The config value for the key.
+    * 
+    * @return void
+    *
+    */
+    
+    function setFormatConf($format, $arg1, $arg2 = null)
+    {
+        if (! is_array($this->formatConf[$format])) {
+            $this->formatConf[$format] = array();
+        }
+        
+        // if first arg is an array, use it as the entire
+        // conf array for the format.  otherwise, treat arg1
+        // as a key and arg2 as a value for the format conf.
+        if (is_array($arg1)) {
+            $this->formatConf[$format] = $arg1;
+        } else {
+            $this->formatConf[$format][$arg1] = $arg2;
+        }
+    }
+    
+    
+    
+    /**
+    * 
+    * Get configuration for a specific format and key.
+    * 
+    * @access public
+    * 
+    * @param string $format The format to get config for.
+    * 
+    * @param mixed $key A key in the conf array; if null,
+    * returns the entire conf array.
+    * 
+    * @return mixed The whole conf array if no key is specified,
+    * or the specific conf key value.
+    *
+    */
+    
+    function getFormatConf($format, $key = null)
+    {
+        // the format does not exist
+        if (! isset($this->formatConf[$format])) {
+            return null;
+        }
+        
+        // no key requested, return the whole array
+        if (is_null($key)) {
+            return $this->formatConf[$format];
+        }
+        
+        // does the requested key exist?
+        if (isset($this->formatConf[$format][$key])) {
+            // yes, return that value
+            return $this->formatConf[$format][$key];
+        } else {
+            // no
+            return null;
+        }
+    }
+    
+    
+    /**
+    * 
+    * Inserts a rule into to the rule set.
+    * 
+    * @access public
+    * 
+    * @param string $name The name of the rule.  Should be different from
+    * all other keys in the rule set.
+    * 
+    * @param string $tgt The rule after which to insert this new rule.  By
+    * default (null) the rule is inserted at the end; if set to '', inserts
+    * at the beginning.
+    * 
+    * @return void
+    * 
+    */
+    
+    function insertRule($name, $tgt = null)
+    {
+        $name = ucwords(strtolower($name));
+        if (! is_null($tgt)) {
+            $tgt = ucwords(strtolower($tgt));
+        }
+        
+        // does the rule name to be inserted already exist?
+        if (in_array($name, $this->rules)) {
+            // yes, return
+            return null;
+        }
+        
+        // the target name is not null, and not '', but does not exist
+        // in the list of rules. this means we're trying to insert after
+        // a target key, but the target key isn't there.
+        if (! is_null($tgt) && $tgt != '' &&
+            ! in_array($tgt, $this->rules)) {
+            return false;
+        }
+        
+        // if $tgt is null, insert at the end.  We know this is at the
+        // end (instead of resetting an existing rule) becuase we exited
+        // at the top of this method if the rule was already in place.
+        if (is_null($tgt)) {
+            $this->rules[] = $name;
+            return true;
+        }
+        
+        // save a copy of the current rules, then reset the rule set
+        // so we can insert in the proper place later.
+        // where to insert the rule?
+        if ($tgt == '') {
+            // insert at the beginning
+            array_unshift($this->rules, $name);
+            return true;
+        }
+        
+        // insert after the named rule
+        $tmp = $this->rules;
+        $this->rules = array();
+        
+        foreach ($tmp as $val) {
+            $this->rules[] = $val;
+            if ($val == $tgt) {
+                $this->rules[] = $name;
+            }
+        }
+        
+        return true;
+        
+    }
+    
+    
+    /**
+    * 
+    * Delete (remove or unset) a rule from the $rules property.
+    * 
+    * @access public
+    * 
+    * @param string $rule The name of the rule to remove.
+    * 
+    * @return void
+    *     
+    */
+    
+    function deleteRule($name)
+    {
+        $name = ucwords(strtolower($name));
+        $key = array_search($name, $this->rules);
+        if ($key !== false) {
+            unset($this->rules[$key]);
+        }
+    }
+    
+    
+    /**
+    * 
+    * Change from one rule to another in-place.
+    * 
+    * @access public
+    * 
+    * @param string $old The name of the rule to change from.
+    * 
+    * @param string $new The name of the rule to change to.
+    * 
+    * @return void
+    *     
+    */
+    
+    function changeRule($old, $new)
+    {
+        $old = ucwords(strtolower($old));
+        $new = ucwords(strtolower($new));
+        $key = array_search($old, $this->rules);
+        if ($key !== false) {
+            $this->rules[$old] = $new;
+        }
+    }
+    
+    
+    /**
+    * 
+    * Enables a rule so that it is applied when parsing.
+    * 
+    * @access public
+    * 
+    * @param string $rule The name of the rule to enable.
+    * 
+    * @return void
+    *     
+    */
+    
+    function enableRule($name)
+    {
+        $name = ucwords(strtolower($name));
+        $key = array_search($name, $this->disable);
+        if ($key !== false) {
+            unset($this->disable[$key]);
+        }
+    }
+    
+    
+    /**
+    * 
+    * Disables a rule so that it is not applied when parsing.
+    * 
+    * @access public
+    * 
+    * @param string $rule The name of the rule to disable.
+    * 
+    * @return void
+    *     
+    */
+    
+    function disableRule($name)
+    {
+        $name = ucwords(strtolower($name));
+        $key = array_search($name, $this->disable);
+        if ($key === false) {
+            $this->disable[] = $name;
+        }
+    }
+    
+    
+    /**
+    * 
+    * Parses and renders the text passed to it, and returns the results.
+    * 
+    * First, the method parses the source text, applying rules to the
+    * text as it goes.  These rules will modify the source text
+    * in-place, replacing some text with delimited tokens (and
+    * populating the $this->tokens array as it goes).
+    * 
+    * Next, the method renders the in-place tokens into the requested
+    * output format.
+    * 
+    * Finally, the method returns the transformed text.  Note that the
+    * source text is transformed in place; once it is transformed, it is
+    * no longer the same as the original source text.
+    * 
+    * @access public
+    * 
+    * @param string $text The source text to which wiki rules should be
+    * applied, both for parsing and for rendering.
+    * 
+    * @param string $format The target output format, typically 'xhtml'.
+    *  If a rule does not support a given format, the output from that
+    * rule is rule-specific.
+    * 
+    * @return string The transformed wiki text.
+    * 
+    */
+    
+    function transform($text, $format = 'Xhtml')
+    {
+        $this->parse($text);
+        return $this->render($format);
+    }
+    
+    
+    /**
+    * 
+    * Sets the $_source text property, then parses it in place and
+    * retains tokens in the $_tokens array property.
+    * 
+    * @access public
+    * 
+    * @param string $text The source text to which wiki rules should be
+    * applied, both for parsing and for rendering.
+    * 
+    * @return void
+    * 
+    */
+    
+    function parse($text)
+    {
+        // set the object property for the source text
+        $this->source = $text;
+        
+        // reset the tokens.
+        $this->tokens = array();
+        
+        // apply the parse() method of each requested rule to the source
+        // text.
+        foreach ($this->rules as $name) {
+            // do not parse the rules listed in $disable
+            if (! in_array($name, $this->disable)) {
+                
+                // load the parsing object
+                $this->loadParseObj($name);
+                
+                // load may have failed; only parse if
+                // an object is in the array now
+                if (is_object($this->parseObj[$name])) {
+                    $this->parseObj[$name]->parse();
+                }
+            }
+        }
+    }
+    
+    
+    /**
+    * 
+    * Renders tokens back into the source text, based on the requested format.
+    * 
+    * @access public
+    * 
+    * @param string $format The target output format, typically 'xhtml'. 
+    * If a rule does not support a given format, the output from that
+    * rule is rule-specific.
+    * 
+    * @return string The transformed wiki text.
+    * 
+    */
+    
+    function render($format = 'Xhtml')
+    {
+        // the rendering method we're going to use from each rule
+        $format = ucwords(strtolower($format));
+        
+        // the eventual output text
+        $output = '';
+        
+        // when passing through the parsed source text, keep track of when
+        // we are in a delimited section
+        $in_delim = false;
+        
+        // when in a delimited section, capture the token key number
+        $key = '';
+        
+        // load the format object
+        $this->loadFormatObj($format);
+        
+        // pre-rendering activity
+        if (is_object($this->formatObj[$format])) {
+            $output .= $this->formatObj[$format]->pre();
+        }
+        
+        // load the render objects
+        foreach (array_keys($this->parseObj) as $rule) {
+            $this->loadRenderObj($format, $rule);
+        }
+        
+        // pass through the parsed source text character by character
+        $k = strlen($this->source);
+        for ($i = 0; $i < $k; $i++) {
+            
+            // the current character
+            $char = $this->source{$i};
+            
+            // are alredy in a delimited section?
+            if ($in_delim) {
+            
+                // yes; are we ending the section?
+                if ($char == $this->delim) {
+                    
+                    // yes, get the replacement text for the delimited
+                    // token number and unset the flag.
+                    $key = (int)$key;
+                    $rule = $this->tokens[$key][0];
+                    $opts = $this->tokens[$key][1];
+                    $output .= $this->renderObj[$rule]->token($opts);
+                    $in_delim = false;
+                    
+                } else {
+                
+                    // no, add to the dlimited token key number
+                    $key .= $char;
+                    
+                }
+                
+            } else {
+                
+                // not currently in a delimited section.
+                // are we starting into a delimited section?
+                if ($char == $this->delim) {
+                    // yes, reset the previous key and
+                    // set the flag.
+                    $key = '';
+                    $in_delim = true;
+                } else {
+                    // no, add to the output as-is
+                    $output .= $char;
+                }
+            }
+        }
+        
+        // post-rendering activity
+        if (is_object($this->formatObj[$format])) {
+            $output .= $this->formatObj[$format]->post();
+        }
+        
+        // return the rendered source text.
+        return $output;
+    }
+    
+    
+    /**
+    * 
+    * Returns the parsed source text with delimited token placeholders.
+    * 
+    * @access public
+    * 
+    * @return string The parsed source text.
+    * 
+    */
+    
+    function getSource()
+    {
+        return $this->source;
+    }
+    
+    
+    /**
+    * 
+    * Returns tokens that have been parsed out of the source text.
+    * 
+    * @access public
+    * 
+    * @param array $rules If an array of rule names is passed, only return
+    * tokens matching these rule names.  If no array is passed, return all
+    * tokens.
+    * 
+    * @return array An array of tokens.
+    * 
+    */
+    
+    function getTokens($rules = null)
+    {
+        if (is_null($rules)) {
+            return $this->tokens;
+        } else {
+            settype($rules, 'array');
+            $result = array();
+            foreach ($this->tokens as $key => $val) {
+                if (in_array($val[0], $rules)) {
+                    $result[] = $val;
+                }
+            }
+            return $result;
+        }
+    }
+    
+    
+    /**
+    * 
+    * Add a token to the Text_Wiki tokens array, and return a delimited
+    * token number.
+    * 
+    * @access public
+    * 
+    * @param array $options An associative array of options for the new
+    * token array element.  The keys and values are specific to the
+    * rule, and may or may not be common to other rule options.  Typical
+    * options keys are 'text' and 'type' but may include others.
+    * 
+    * @param boolean $id_only If true, return only the token number, not
+    * a delimited token string.
+    * 
+    * @return string|int By default, return the number of the
+    * newly-created token array element with a delimiter prefix and
+    * suffix; however, if $id_only is set to true, return only the token
+    * number (no delimiters).
+    * 
+    */
+    
+    function addToken($rule, $options = array(), $id_only = false)
+    {
+        // increment the token ID number.  note that if you parse
+        // multiple times with the same Text_Wiki object, the ID number
+        // will not reset to zero.
+        static $id;
+        if (! isset($id)) {
+            $id = 0;
+        } else {
+            $id ++;
+        }
+        
+        // force the options to be an array
+        settype($options, 'array');
+        
+        // add the token
+        $this->tokens[$id] = array(
+            0 => $rule,
+            1 => $options
+        );
+        
+        // return a value
+        if ($id_only) {
+            // return the last token number
+            return $id;
+        } else {
+            // return the token number with delimiters
+            return $this->delim . $id . $this->delim;
+        }
+    }
+    
+    
+    /**
+    * 
+    * Set or re-set a token with specific information, overwriting any
+    * previous rule name and rule options.
+    * 
+    * @access public
+    * 
+    * @param int $id The token number to reset.
+    * 
+    * @param int $rule The rule name to use.
+    * 
+    * @param array $options An associative array of options for the
+    * token array element.  The keys and values are specific to the
+    * rule, and may or may not be common to other rule options.  Typical
+    * options keys are 'text' and 'type' but may include others.
+    * 
+    * @return void
+    * 
+    */
+    
+    function setToken($id, $rule, $options = array())
+    {
+        // reset the token
+        $this->tokens[$id] = array(
+            0 => $rule,
+            1 => $options
+        );
+    }
+    
+    
+    /**
+    * 
+    * Load a rule parser class file.
+    * 
+    * @access public
+    * 
+    * @return bool True if loaded, false if not.
+    * 
+    */
+    
+    function loadParseObj($rule)
+    {
+        $rule = ucwords(strtolower($rule));
+        $file = $rule . '.php';
+        $class = "Text_Wiki_Parse_$rule";
+        
+        if (! class_exists($class)) {
+            $loc = $this->findFile('parse', $file);
+            if ($loc) {
+                // found the class
+                include_once $loc;
+            } else {
+                // can't find the class
+                $this->parseObj[$rule] = null;
+                return false;
+            }
+        }
+        
+        $this->parseObj[$rule] =& new $class($this);
 
-       /**
-       * 
-       * The delimiter that surrounds a token number embedded in the source
-       * wiki text.
-       * 
-       * @access public
-       * 
-       * @var string
-       * 
-       */
-       
-       var $delim = "\xFF"; 
-       
-       
-       /**
-       * 
-       * An array of tokens generated by rules as the source text is
-       * parsed.
-       * 
-       * As Text_Wiki applies rule classes to the source text, it will
-       * replace portions of the text with a delimited token number.  This
-       * is the array of those tokens, representing the replaced text and
-       * any options set by the parser for that replaced text.
-       * 
-       * The tokens array is seqential; each element is itself a sequential
-       * array where element 0 is the name of the rule that generated the
-       * token, and element 1 is an associative array where the key is an
-       * option name and the value is an option value.
-       * 
-       * @access private
-       * 
-       * @var string
-       * 
-       */
-       
-       var $_tokens = array();
-       
-       
-       /**
-       * 
-       * The source text to which rules will be applied.  This text will be
-       * transformed in-place, which means that it will change as the rules
-       * are applied.
-       * 
-       * @access private
-       * 
-       * @var string
-       * 
-       */
-       
-       var $_source = '';
-       
-       
-       /**
-       * 
-       * Text_Wiki creates one instance of every rule that is applied to
-       * the source text; this array holds those instances.  The array key
-       * is the rule name, and the array value is an instance of the rule
-       * class.
-       * 
-       * @access private
-       * 
-       * @var string
-       * 
-       */
-       
-       var $_rule_obj = array();
-       
-       
-       /**
-       * 
-       * Constructor.  Loads the rule objects.
-       * 
-       * @access public
-       * 
-       * @param array $rules The set of rules to load for this object.
-       *        
-       */
-       
-       function Text_Wiki($rules = null)
-       {
-               // set up the list of rules
-               if (is_array($rules)) {
-                       $this->rules = $rules;
-               }
-       }
-       
-       
-       /**
-       * 
-       * Inserts a rule into to the rule set.
-       * 
-       * @access public
-       * 
-       * @param string $key The key name for the rule.  Should be different from
-       * all other keys in the rule set.
-       * 
-       * @param string $val The rule values; should be an associative array with 
-       * the keys 'file', 'name', 'flag', and 'conf'.
-       * 
-       * @param string $tgt The rule after which to insert this new rule.  By
-       * default (null) the rule is inserted at the end; if set to '', inserts
-       * at the beginning.
-       * 
-       * @return void
-       * 
-       */
-       
-       function insertRule($key, $val, $tgt = null)
-       {
-               // does the rule key to be inserted already exist?
-               if (isset($this->rules[$key])) {
-                       // yes, return
-                       return false;
-               }
-               
-               // the target name is not null, not '', but does not exist. this
-               // means we're trying to insert after a target key, but the
-               // target key isn't there.
-               if (! is_null($tgt) && $tgt != '' && ! isset($this->rules[$tgt])) {
-                       return false;
-               }
-               
-               // if $tgt is null, insert at the end.  We know this is at the
-               // end (instead of resetting an existing rule) becuase we exited
-               // at the top of this method if the rule was already in place.
-               if (is_null($tgt)) {
-                       $this->rules[$key] = $val;
-                       return true;
-               }
-               
-               // save a copy of the current rules, then reset the rule set
-               // so we can insert in the proper place later.
-               $tmp = $this->rules;
-               $this->rules = array();
-               
-               // where to insert the rule?
-               if ($tgt == '') {
-                       // insert at the beginning
-                       $this->rules[$key] = $val;
-                       foreach ($tmp as $k => $v) {
-                               $this->rules[$k] = $v;
-                       }
-                       return true;
-               } else {
-                       // insert after the named rule
-                       foreach ($tmp as $k => $v) {
-                               $this->rules[$k] = $v;
-                               if ($k == $tgt) {
-                                       $this->rules[$key] = $val;
-                               }
-                       }
-               }
-               return true;
-       }
-       
-       
-       /**
-       * 
-       * Delete (remove or unset) a rule from the $rules property.
-       * 
-       * @access public
-       * 
-       * @param string $rule The name of the rule to remove.
-       * 
-       * @return void
-       *        
-       */
-       
-       function deleteRule($key)
-       {
-               unset($this->rules[$key]);
-       }
-       
-       
-       /**
-       * 
-       * Sets the value of a rule's configuration keys.
-       * 
-       * @access public
-       * 
-       * @param string $rule The name of the rule for which to set
-       * configuration keys.
-       * 
-       * @param array|string $arg1 If an array, sets the entire 'conf' key
-       * for the rule; if a string, specifies which 'conf' subkey to set.
-       * 
-       * @param mixed $arg2 If $arg1 is a string, the 'conf' subkey
-       * specified by $arg1 is set to this value.
-       * 
-       * @return void
-       *        
-       */
-       
-       function setRuleConf($rule, $arg1, $arg2 = null)
-       {
-               if (! isset($this->rules[$rule])) {
-                       return;
-               }
-               
-               if (! isset($this->rules[$rule]['conf'])) {
-                       $this->rules[$rule]['conf'] = array();
-               }
-               
-               if (is_array($arg1)) {
-                       $this->rules[$rule]['conf'] = $arg1;
-               } else {
-                       $this->rules[$rule]['conf'][$arg1] = $arg2;
-               }
-       }
-       
-       
-       /**
-       * 
-       * Sets the value of a rule's configuration keys.
-       * 
-       * @access public
-       * 
-       * @param string $rule The name of the rule from which to get
-       * configuration keys.
-       * 
-       * @param string $key Which 'conf' subkey to retrieve.  If null,
-       * gets the entire 'conf' key for the rule.
-       * 
-       * @return void
-       *        
-       */
-       
-       function getRuleConf($rule, $key = null)
-       {
-               if (! isset($this->rules[$rule])) {
-                       return null;
-               }
-               
-               if (! isset($this->rules[$rule]['conf'])) {
-                       $this->rules[$rule]['conf'] = array();
-               }
-               
-               if (is_null($key)) {
-                       return $this->rules[$rule]['conf'];
-               }
-               
-               if (! isset($this->rules[$rule]['conf'][$key])) {
-                       return null;
-               } else {
-                       return $this->rules[$rule]['conf'][$key];
-               }
-               
-       }
-       
-       
-       /**
-       * 
-       * Enables a rule so that it is applied when parsing.
-       * 
-       * @access public
-       * 
-       * @param string $rule The name of the rule to enable.
-       * 
-       * @return void
-       *        
-       */
-       
-       function enableRule($rule)
-       {
-               if (isset($this->rules[$rule])) {
-                       $this->rules[$rule]['flag'] = true;
-               }
-       }
-       
-       
-       /**
-       * 
-       * Disables a rule so that it is not applied when parsing.
-       * 
-       * @access public
-       * 
-       * @param string $rule The name of the rule to disable.
-       * 
-       * @return void
-       *        
-       */
-       
-       function disableRule($rule)
-       {
-               if (isset($this->rules[$rule])) {
-                       $this->rules[$rule]['flag'] = false;
-               }
-       }
-       
-       
-       /**
-       * 
-       * Parses and renders the text passed to it, and returns the results.
-       * 
-       * First, the method parses the source text, applying rules to the
-       * text as it goes.  These rules will modify the source text
-       * in-place, replacing some text with delimited tokens (and
-       * populating the $this->_tokens array as it goes).
-       * 
-       * Next, the method renders the in-place tokens into the requested
-       * output format.
-       * 
-       * Finally, the method returns the transformed text.  Note that the
-       * source text is transformed in place; once it is transformed, it is
-       * no longer the same as the original source text.
-       * 
-       * @access public
-       * 
-       * @param string $text The source text to which wiki rules should be
-       * applied, both for parsing and for rendering.
-       * 
-       * @param string $format The target output format, typically 'xhtml'.
-       *  If a rule does not support a given format, the output from that
-       * rule is rule-specific.
-       * 
-       * @return string The transformed wiki text.
-       * 
-       */
-       
-       function transform($text, $format = 'Xhtml')
-       {
-               $this->parse($text);
-               return $this->render($format);
-       }
-       
-       
-       /**
-       * 
-       * Sets the $_source text property, then parses it in place and
-       * retains tokens in the $_tokens array property.
-       * 
-       * @access public
-       * 
-       * @param string $text The source text to which wiki rules should be
-       * applied, both for parsing and for rendering.
-       * 
-       * @return void
-       * 
-       */
-       
-       function parse($text)
-       {
-               // set the object property for the source text
-               $this->_source = $text;
-               
-               // apply the parse() method of each requested rule to the source
-               // text.
-               foreach ($this->rules as $key => $val) {
-                       // if flag is not set to 'true' (active),
-                       // do not parse under this rule.  assume
-                       // that if a rule exists, but has no flag,
-                       // that it wants to be parsed with.
-                       if (! isset($val['flag']) || $val['flag'] == true) {
-                               $this->_loadRuleObject($key);
-                               $this->_rule_obj[$key]->parse();
-                       }
-               }
-       }
-       
-       
-       /**
-       * 
-       * Renders tokens back into the source text, based on the requested format.
-       * 
-       * @access public
-       * 
-       * @param string $format The target output format, typically 'xhtml'.
-       *  If a rule does not support a given format, the output from that
-       * rule is rule-specific.
-       * 
-       * @return string The transformed wiki text.
-       * 
-       */
-       
-       function render($format = 'Xhtml')
-       {
-               // the rendering method we're going to use from each rule
-               $method = "render$format";
-               
-               // the eventual output text
-               $output = '';
-               
-               // when passing through the parsed source text, keep track of when
-               // we are in a delimited section
-               $in_delim = false;
-               
-               // when in a delimited section, capture the token key number
-               $key = '';
-               
-               // pass through the parsed source text character by character
-               $k = strlen($this->_source);
-               for ($i = 0; $i < $k; $i++) {
-                       
-                       // the current character
-                       $char = $this->_source{$i};
-                       
-                       // are alredy in a delimited section?
-                       if ($in_delim) {
-                       
-                               // yes; are we ending the section?
-                               if ($char == $this->delim) {
-                                       
-                                       // yes, get the replacement text for the delimited
-                                       // token number and unset the flag.
-                                       $key = (int)$key;
-                                       $rule = $this->_tokens[$key][0];
-                                       $opts = $this->_tokens[$key][1];
-                                       $output .= $this->_rule_obj[$rule]->$method($opts);
-                                       $in_delim = false;
-                                       
-                               } else {
-                               
-                                       // no, add to the dlimited token key number
-                                       $key .= $char;
-                                       
-                               }
-                               
-                       } else {
-                               
-                               // not currently in a delimited section.
-                               // are we starting into a delimited section?
-                               if ($char == $this->delim) {
-                                       // yes, reset the previous key and
-                                       // set the flag.
-                                       $key = '';
-                                       $in_delim = true;
-                               } else {
-                                       // no, add to the output as-is
-                                       $output .= $char;
-                               }
-                       }
-               }
-               
-               // return the rendered source text
-               return $output;
-       }
-       
-       
-       /**
-       * 
-       * Returns the parsed source text with delimited token placeholders.
-       * 
-       * @access public
-       * 
-       * @return string The parsed source text.
-       * 
-       */
-       
-       function getSource()
-       {
-               return $this->_source;
-       }
-       
-       
-       /**
-       * 
-       * Returns tokens that have been parsed out of the source text.
-       * 
-       * @access public
-       * 
-       * @param array $rules If an array of rule names is passed, only return
-       * tokens matching these rule names.  If no array is passed, return all
-       * tokens.
-       * 
-       * @return array An array of tokens.
-       * 
-       */
-       
-       function getTokens($rules = null)
-       {
-               if (is_null($rules)) {
-                       return $this->_tokens;
-               } else {
-                       settype($rules, 'array');
-                       $result = array();
-                       foreach ($this->_tokens as $key => $val) {
-                               if (in_array($val[0], $rules)) {
-                                       $result[] = $val;
-                               }
-                       }
-                       return $result;
-               }
-       }
-       
-       
-       /**
-       * 
-       * Loads a rule class file and creates an instance of it.
-       * 
-       * @access public
-       * 
-       * @return void
-       * 
-       */
-       
-       function _loadRuleObject($key)
-       {
-               $name = $this->rules[$key]['name'];
-               if (! class_exists($name)) {
-                       include_once $this->rules[$key]['file'];
-               }
-               $this->_rule_obj[$key] =& new $name($this, $key);
-       }
+    }
+    
+    
+    /**
+    * 
+    * Load a rule-render class file.
+    * 
+    * @access public
+    * 
+    * @return bool True if loaded, false if not.
+    * 
+    */
+    
+    function loadRenderObj($format, $rule)
+    {
+        $format = ucwords(strtolower($format));
+        $rule = ucwords(strtolower($rule));
+        $file = "$format/$rule.php";
+        $class = "Text_Wiki_Render_$format" . "_$rule";
+        
+        if (! class_exists($class)) {
+            // load the class
+            $loc = $this->findFile('render', $file);
+            if ($loc) {
+                // found the class
+                include_once $loc;
+            } else {
+                // can't find the class
+                return false;
+            }
+        }
+        
+        $this->renderObj[$rule] =& new $class($this);
+    }
+    
+    
+    /**
+    * 
+    * Load a format-render class file.
+    * 
+    * @access public
+    * 
+    * @return bool True if loaded, false if not.
+    * 
+    */
+    
+    function loadFormatObj($format)
+    {
+        $format = ucwords(strtolower($format));
+        $file = $format . '.php';
+        $class = "Text_Wiki_Render_$format";
+        
+        if (! class_exists($class)) {
+            $loc = $this->findFile('render', $file);
+            if ($loc) {
+                // found the class
+                include_once $loc;
+            } else {
+                // can't find the class
+                return false;
+            }
+        }
+        
+        $this->formatObj[$format] =& new $class($this);
+    }
+    
+    
+    /**
+    * 
+    * Add a path to a path array.
+    * 
+    * @access public
+    * 
+    * @param string $type The path-type to add (parse or render).
+    * 
+    * @param string $dir The directory to add to the path-type.
+    * 
+    * @return void
+    * 
+    */
+    
+    function addPath($type, $dir)
+    {
+        $dir = $this->fixPath($dir);
+        if (! isset($this->path[$type])) {
+            $this->path[$type] = array($dir);
+        } else {
+            array_unshift($this->path[$type], $dir);
+        }
+    }
+    
+    
+    /**
+    * 
+    * Get the current path array for a path-type.
+    * 
+    * @access public
+    * 
+    * @param string $type The path-type to look up (plugin, filter, or
+    * template).  If not set, returns all path types.
+    * 
+    * @return array The array of paths for the requested type.
+    * 
+    */
+    
+    function getPath($type = null)
+    {
+        if (is_null($type)) {
+            return $this->path;
+        } elseif (! isset($this->path[$type])) {
+            return array();
+        } else {
+            return $this->path[$type];
+        }
+    }
+    
+    
+    /**
+    * 
+    * Searches a series of paths for a given file.
+    * 
+    * @param array $type The type of paths to search (template, plugin,
+    * or filter).
+    * 
+    * @param string $file The file name to look for.
+    * 
+    * @return string|bool The full path and file name for the target file,
+    * or boolean false if the file is not found in any of the paths.
+    *
+    */
+    
+    function findFile($type, $file)
+    {
+        // get the set of paths
+        $set = $this->getPath($type);
+        
+        // start looping through them
+        foreach ($set as $path) {
+            $fullname = $path . $file;
+            if (file_exists($fullname) && is_readable($fullname)) {
+                return $fullname;
+            }
+        }
+        
+        // could not find the file in the set of paths
+        return false;
+    }
+    
+    
+    /**
+    * 
+    * Append a trailing '/' to paths, unless the path is empty.
+    * 
+    * @access private
+    * 
+    * @param string $path The file path to fix
+    * 
+    * @return string The fixed file path
+    * 
+    */
+    
+    function fixPath($path)
+    {
+        $len = strlen($this->_dirSep);
+        
+        if (! empty($path) &&
+            substr($path, -1 * $len, $len) != $this->_dirSep)    {
+            return $path . $this->_dirSep;
+        } else {
+            return $path;
+        }
+    }
 }
 
-?>
+?>
\ No newline at end of file
index b5330ca088de616e7d6785cbb6289644b14e1ac0..9c525cb9b034b3e33ac301194e0e91d1ae338829 100644 (file)
--- a/docs/NEWS
+++ b/docs/NEWS
@@ -149,15 +149,24 @@ Version 0.9 ()
 
 Version 0.8.3 ()
 ------------------------------------------------------------------------
+   * Upgraded bundled libs:
+       Cache_Lite      to 1.5.1
+       HTTP_Request    to 1.2.4
+       Net_CheckIP     to 1.1
+       Net_Socket      to 1.0.6
+       Net_URL         to 1.0.14
+       PEAR            to 1.3.5
+       Text_Wiki       to 1.0.0
+       XML_RPC         to 1.3.2
+     Fixing several bugs and vulnerabilities. (nohn)
+
+   * Fix editing a draft article to be properly displayed as draft
+     in PostgreSQL setups. Thanks to Penny Leach! (garvinhicking)
 
    * Fixed possible XSS in comment input validation, thanks to 
      Ilia  Alshanetsky
 
-   * XML_RPC: Eliminate path disclosure vulnerabilities by suppressing
-     error messages when eval()'ing. Eliminate path disclosure
-     vulnerability by catching bogus parameters submitted
-     to XML_RPC_Value::serializeval(). (nohn)
-
 
 Version 0.8.2 (June 29th, 2005)
 ------------------------------------------------------------------------