Commit 05af75541f61a446c199ce55d0bce2d502b728de

Authored by Brad Shuttleworth
1 parent ce5876ea

basic graphviz support.


git-svn-id: https://kt-dms.svn.sourceforge.net/svnroot/kt-dms/trunk@5998 c91229c3-7414-0410-bfa2-8a42b809f60b
thirdparty/pear/Console/Getopt.php 0 → 100644
  1 +<?php
  2 +/* vim: set expandtab tabstop=4 shiftwidth=4: */
  3 +// +----------------------------------------------------------------------+
  4 +// | PHP Version 4 |
  5 +// +----------------------------------------------------------------------+
  6 +// | Copyright (c) 1997-2003 The PHP Group |
  7 +// +----------------------------------------------------------------------+
  8 +// | This source file is subject to version 3.0 of the PHP license, |
  9 +// | that is bundled with this package in the file LICENSE, and is |
  10 +// | available through the world-wide-web at the following url: |
  11 +// | http://www.php.net/license/3_0.txt. |
  12 +// | If you did not receive a copy of the PHP license and are unable to |
  13 +// | obtain it through the world-wide-web, please send a note to |
  14 +// | license@php.net so we can mail you a copy immediately. |
  15 +// +----------------------------------------------------------------------+
  16 +// | Author: Andrei Zmievski <andrei@php.net> |
  17 +// +----------------------------------------------------------------------+
  18 +//
  19 +// $Id: Getopt.php,v 1.21.4.7 2003/12/05 21:57:01 andrei Exp $
  20 +
  21 +require_once 'PEAR.php';
  22 +
  23 +/**
  24 + * Command-line options parsing class.
  25 + *
  26 + * @author Andrei Zmievski <andrei@php.net>
  27 + *
  28 + */
  29 +class Console_Getopt {
  30 + /**
  31 + * Parses the command-line options.
  32 + *
  33 + * The first parameter to this function should be the list of command-line
  34 + * arguments without the leading reference to the running program.
  35 + *
  36 + * The second parameter is a string of allowed short options. Each of the
  37 + * option letters can be followed by a colon ':' to specify that the option
  38 + * requires an argument, or a double colon '::' to specify that the option
  39 + * takes an optional argument.
  40 + *
  41 + * The third argument is an optional array of allowed long options. The
  42 + * leading '--' should not be included in the option name. Options that
  43 + * require an argument should be followed by '=', and options that take an
  44 + * option argument should be followed by '=='.
  45 + *
  46 + * The return value is an array of two elements: the list of parsed
  47 + * options and the list of non-option command-line arguments. Each entry in
  48 + * the list of parsed options is a pair of elements - the first one
  49 + * specifies the option, and the second one specifies the option argument,
  50 + * if there was one.
  51 + *
  52 + * Long and short options can be mixed.
  53 + *
  54 + * Most of the semantics of this function are based on GNU getopt_long().
  55 + *
  56 + * @param array $args an array of command-line arguments
  57 + * @param string $short_options specifies the list of allowed short options
  58 + * @param array $long_options specifies the list of allowed long options
  59 + *
  60 + * @return array two-element array containing the list of parsed options and
  61 + * the non-option arguments
  62 + *
  63 + * @access public
  64 + *
  65 + */
  66 + function getopt2($args, $short_options, $long_options = null)
  67 + {
  68 + return Console_Getopt::doGetopt(2, $args, $short_options, $long_options);
  69 + }
  70 +
  71 + /**
  72 + * This function expects $args to start with the script name (POSIX-style).
  73 + * Preserved for backwards compatibility.
  74 + * @see getopt2()
  75 + */
  76 + function getopt($args, $short_options, $long_options = null)
  77 + {
  78 + return Console_Getopt::doGetopt(1, $args, $short_options, $long_options);
  79 + }
  80 +
  81 + /**
  82 + * The actual implementation of the argument parsing code.
  83 + */
  84 + function doGetopt($version, $args, $short_options, $long_options = null)
  85 + {
  86 + // in case you pass directly readPHPArgv() as the first arg
  87 + if (PEAR::isError($args)) {
  88 + return $args;
  89 + }
  90 + if (empty($args)) {
  91 + return array(array(), array());
  92 + }
  93 + $opts = array();
  94 + $non_opts = array();
  95 +
  96 + settype($args, 'array');
  97 +
  98 + if ($long_options) {
  99 + sort($long_options);
  100 + }
  101 +
  102 + /*
  103 + * Preserve backwards compatibility with callers that relied on
  104 + * erroneous POSIX fix.
  105 + */
  106 + if ($version < 2) {
  107 + if (isset($args[0]{0}) && $args[0]{0} != '-') {
  108 + array_shift($args);
  109 + }
  110 + }
  111 +
  112 + reset($args);
  113 + while (list($i, $arg) = each($args)) {
  114 +
  115 + /* The special element '--' means explicit end of
  116 + options. Treat the rest of the arguments as non-options
  117 + and end the loop. */
  118 + if ($arg == '--') {
  119 + $non_opts = array_merge($non_opts, array_slice($args, $i + 1));
  120 + break;
  121 + }
  122 +
  123 + if ($arg{0} != '-' || (strlen($arg) > 1 && $arg{1} == '-' && !$long_options)) {
  124 + $non_opts = array_merge($non_opts, array_slice($args, $i));
  125 + break;
  126 + } elseif (strlen($arg) > 1 && $arg{1} == '-') {
  127 + $error = Console_Getopt::_parseLongOption(substr($arg, 2), $long_options, $opts, $args);
  128 + if (PEAR::isError($error))
  129 + return $error;
  130 + } else {
  131 + $error = Console_Getopt::_parseShortOption(substr($arg, 1), $short_options, $opts, $args);
  132 + if (PEAR::isError($error))
  133 + return $error;
  134 + }
  135 + }
  136 +
  137 + return array($opts, $non_opts);
  138 + }
  139 +
  140 + /**
  141 + * @access private
  142 + *
  143 + */
  144 + function _parseShortOption($arg, $short_options, &$opts, &$args)
  145 + {
  146 + for ($i = 0; $i < strlen($arg); $i++) {
  147 + $opt = $arg{$i};
  148 + $opt_arg = null;
  149 +
  150 + /* Try to find the short option in the specifier string. */
  151 + if (($spec = strstr($short_options, $opt)) === false || $arg{$i} == ':')
  152 + {
  153 + return PEAR::raiseError("Console_Getopt: unrecognized option -- $opt");
  154 + }
  155 +
  156 + if (strlen($spec) > 1 && $spec{1} == ':') {
  157 + if (strlen($spec) > 2 && $spec{2} == ':') {
  158 + if ($i + 1 < strlen($arg)) {
  159 + /* Option takes an optional argument. Use the remainder of
  160 + the arg string if there is anything left. */
  161 + $opts[] = array($opt, substr($arg, $i + 1));
  162 + break;
  163 + }
  164 + } else {
  165 + /* Option requires an argument. Use the remainder of the arg
  166 + string if there is anything left. */
  167 + if ($i + 1 < strlen($arg)) {
  168 + $opts[] = array($opt, substr($arg, $i + 1));
  169 + break;
  170 + } else if (list(, $opt_arg) = each($args))
  171 + /* Else use the next argument. */;
  172 + else
  173 + return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt");
  174 + }
  175 + }
  176 +
  177 + $opts[] = array($opt, $opt_arg);
  178 + }
  179 + }
  180 +
  181 + /**
  182 + * @access private
  183 + *
  184 + */
  185 + function _parseLongOption($arg, $long_options, &$opts, &$args)
  186 + {
  187 + @list($opt, $opt_arg) = explode('=', $arg);
  188 + $opt_len = strlen($opt);
  189 +
  190 + for ($i = 0; $i < count($long_options); $i++) {
  191 + $long_opt = $long_options[$i];
  192 + $opt_start = substr($long_opt, 0, $opt_len);
  193 +
  194 + /* Option doesn't match. Go on to the next one. */
  195 + if ($opt_start != $opt)
  196 + continue;
  197 +
  198 + $opt_rest = substr($long_opt, $opt_len);
  199 +
  200 + /* Check that the options uniquely matches one of the allowed
  201 + options. */
  202 + if ($opt_rest != '' && $opt{0} != '=' &&
  203 + $i + 1 < count($long_options) &&
  204 + $opt == substr($long_options[$i+1], 0, $opt_len)) {
  205 + return PEAR::raiseError("Console_Getopt: option --$opt is ambiguous");
  206 + }
  207 +
  208 + if (substr($long_opt, -1) == '=') {
  209 + if (substr($long_opt, -2) != '==') {
  210 + /* Long option requires an argument.
  211 + Take the next argument if one wasn't specified. */;
  212 + if (!strlen($opt_arg) && !(list(, $opt_arg) = each($args))) {
  213 + return PEAR::raiseError("Console_Getopt: option --$opt requires an argument");
  214 + }
  215 + }
  216 + } else if ($opt_arg) {
  217 + return PEAR::raiseError("Console_Getopt: option --$opt doesn't allow an argument");
  218 + }
  219 +
  220 + $opts[] = array('--' . $opt, $opt_arg);
  221 + return;
  222 + }
  223 +
  224 + return PEAR::raiseError("Console_Getopt: unrecognized option --$opt");
  225 + }
  226 +
  227 + /**
  228 + * Safely read the $argv PHP array across different PHP configurations.
  229 + * Will take care on register_globals and register_argc_argv ini directives
  230 + *
  231 + * @access public
  232 + * @return mixed the $argv PHP array or PEAR error if not registered
  233 + */
  234 + function readPHPArgv()
  235 + {
  236 + global $argv;
  237 + if (!is_array($argv)) {
  238 + if (!@is_array($_SERVER['argv'])) {
  239 + if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) {
  240 + return PEAR::raiseError("Console_Getopt: Could not read cmd args (register_argc_argv=Off?)");
  241 + }
  242 + return $GLOBALS['HTTP_SERVER_VARS']['argv'];
  243 + }
  244 + return $_SERVER['argv'];
  245 + }
  246 + return $argv;
  247 + }
  248 +
  249 +}
  250 +
  251 +?>
thirdparty/pear/GraphViz.php 0 → 100644
  1 +<?php
  2 +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3 +
  4 +/**
  5 + * Image_GraphViz
  6 + *
  7 + * Copyright (c) 2001-2006, Dr. Volker Göbbels <vmg@arachnion.de> and
  8 + * Sebastian Bergmann <sb@sebastian-bergmann.de>. All rights reserved.
  9 + *
  10 + * LICENSE: This source file is subject to version 3.0 of the PHP license
  11 + * that is available through the world-wide-web at the following URI:
  12 + * http://www.php.net/license/3_0.txt. If you did not receive a copy of
  13 + * the PHP License and are unable to obtain it through the web, please
  14 + * send a note to license@php.net so we can mail you a copy immediately.
  15 + *
  16 + * @category Image
  17 + * @package GraphViz
  18 + * @author Dr. Volker Göbbels <vmg@arachnion.de>
  19 + * @author Sebastian Bergmann <sb@sebastian-bergmann.de>
  20 + * @author Karsten Dambekalns <k.dambekalns@fishfarm.de>
  21 + * @author Michael Lively Jr. <mlively@ft11.net>
  22 + * @copyright 2001-2006 Sebastian Bergmann <sb@sebastian-bergmann.de>
  23 + * @license http://www.php.net/license/3_0.txt PHP License 3.0
  24 + * @version CVS: $Id: GraphViz.php,v 1.25 2006/05/16 15:49:19 sebastian Exp $
  25 + * @link http://pear.php.net/package/Image_GraphViz
  26 + * @since File available since Release 0.1
  27 + */
  28 +
  29 +require_once 'System.php';
  30 +
  31 +/**
  32 + * Interface to AT&T's GraphViz tools.
  33 + *
  34 + * The GraphViz class allows for the creation of and the work with directed
  35 + * and undirected graphs and their visualization with AT&T's GraphViz tools.
  36 + *
  37 + * <code>
  38 + * <?php
  39 + * require_once 'Image/GraphViz.php';
  40 + *
  41 + * $graph = new Image_GraphViz();
  42 + *
  43 + * $graph->addNode(
  44 + * 'Node1',
  45 + * array(
  46 + * 'URL' => 'http://link1',
  47 + * 'label' => 'This is a label',
  48 + * 'shape' => 'box'
  49 + * )
  50 + * );
  51 + *
  52 + * $graph->addNode(
  53 + * 'Node2',
  54 + * array(
  55 + * 'URL' => 'http://link2',
  56 + * 'fontsize' => '14'
  57 + * )
  58 + * );
  59 + *
  60 + * $graph->addNode(
  61 + * 'Node3',
  62 + * array(
  63 + * 'URL' => 'http://link3',
  64 + * 'fontsize' => '20'
  65 + * )
  66 + * );
  67 + *
  68 + * $graph->addEdge(
  69 + * array(
  70 + * 'Node1' => 'Node2'
  71 + * ),
  72 + * array(
  73 + * 'label' => 'Edge Label'
  74 + * )
  75 + * );
  76 + *
  77 + * $graph->addEdge(
  78 + * array(
  79 + * 'Node1' => 'Node2'
  80 + * ),
  81 + * array(
  82 + * 'color' => 'red'
  83 + * )
  84 + * );
  85 + *
  86 + * $graph->image();
  87 + * ?>
  88 + * </code>
  89 + *
  90 + * @category Image
  91 + * @package GraphViz
  92 + * @author Sebastian Bergmann <sb@sebastian-bergmann.de>
  93 + * @author Dr. Volker Göbbels <vmg@arachnion.de>
  94 + * @author Karsten Dambekalns <k.dambekalns@fishfarm.de>
  95 + * @author Michael Lively Jr. <mlively@ft11.net>
  96 + * @copyright Copyright &copy; 2001-2006 Dr. Volker Göbbels <vmg@arachnion.de> and Sebastian Bergmann <sb@sebastian-bergmann.de>
  97 + * @license http://www.php.net/license/3_0.txt The PHP License, Version 3.0
  98 + * @version Release: @package_version@
  99 + * @link http://pear.php.net/package/Image_GraphViz
  100 + * @since Class available since Release 0.1
  101 + */
  102 +class Image_GraphViz
  103 +{
  104 + /**
  105 + * Path to GraphViz/dot command
  106 + *
  107 + * @var string
  108 + */
  109 + var $dotCommand = 'dot';
  110 +
  111 + /**
  112 + * Path to GraphViz/neato command
  113 + *
  114 + * @var string
  115 + */
  116 + var $neatoCommand = 'neato';
  117 +
  118 + /**
  119 + * Representation of the graph
  120 + *
  121 + * @var array
  122 + */
  123 + var $graph;
  124 +
  125 + /**
  126 + * Constructor.
  127 + *
  128 + * Setting the name of the Graph is useful for including multiple image maps on
  129 + * one page. If not set, the graph will be named 'G'.
  130 + *
  131 + * @param boolean $directed Directed (TRUE) or undirected (FALSE) graph.
  132 + * @param array $attributes Attributes of the graph
  133 + * @param string $name Name of the Graph
  134 + * @access public
  135 + */
  136 + function Image_GraphViz($directed = TRUE, $attributes = array(), $name = NULL)
  137 + {
  138 + $this->setDirected($directed);
  139 + $this->setAttributes($attributes);
  140 + $this->graph['name'] = $name;
  141 + }
  142 +
  143 + /**
  144 + * Output image of the graph in a given format.
  145 + *
  146 + * @param string Format of the output image.
  147 + * This may be one of the formats supported by GraphViz.
  148 + * @access public
  149 + */
  150 + function image($format = 'svg')
  151 + {
  152 + if ($data = $this->fetch($format)) {
  153 + $sendContentLengthHeader = TRUE;
  154 +
  155 + switch ($format) {
  156 + case 'gif':
  157 + case 'png':
  158 + case 'wbmp': {
  159 + header('Content-Type: image/' . $format);
  160 + }
  161 + break;
  162 +
  163 + case 'jpg': {
  164 + header('Content-Type: image/jpeg');
  165 + }
  166 + break;
  167 +
  168 + case 'pdf': {
  169 + header('Content-Type: application/pdf');
  170 + }
  171 + break;
  172 +
  173 + case 'svg': {
  174 + header('Content-Type: image/svg+xml');
  175 + }
  176 + break;
  177 +
  178 + default: {
  179 + $sendContentLengthHeader = FALSE;
  180 + }
  181 + }
  182 +
  183 + if ($sendContentLengthHeader) {
  184 + header('Content-Length: ' . strlen($data));
  185 + }
  186 +
  187 + echo $data;
  188 + }
  189 + }
  190 +
  191 + /**
  192 + * Return image (data) of the graph in a given format.
  193 + *
  194 + * @param string Format of the output image.
  195 + * This may be one of the formats supported by GraphViz.
  196 + * @return string The image (data) created by GraphViz.
  197 + * @access public
  198 + * @since Method available since Release 1.1.0
  199 + */
  200 + function fetch($format = 'svg')
  201 + {
  202 + if ($file = $this->saveParsedGraph()) {
  203 + $outputfile = $file . '.' . $format;
  204 + $command = $this->graph['directed'] ? $this->dotCommand : $this->neatoCommand;
  205 + $command .= ' -T' . escapeshellarg($format) . ' -o' . escapeshellarg($outputfile) . ' ' . escapeshellarg($file);
  206 +
  207 + @`$command`;
  208 + @unlink($file);
  209 +
  210 + $fp = fopen($outputfile, 'rb');
  211 +
  212 + if ($fp) {
  213 + $data = fread($fp, filesize($outputfile));
  214 + fclose($fp);
  215 + @unlink($outputfile);
  216 + }
  217 +
  218 + return $data;
  219 + }
  220 +
  221 + return FALSE;
  222 + }
  223 +
  224 + /**
  225 + * Render a given dot file into another format.
  226 + *
  227 + * @param string The absolute path of the dot file to use.
  228 + * @param string The absolute path of the file to save to.
  229 + * @param string Format of the output image.
  230 + * This may be one of the formats supported by GraphViz.
  231 + * @return bool True if the file was saved, false otherwise.
  232 + * @access public
  233 + */
  234 + function renderDotFile($dotfile, $outputfile, $format = 'svg')
  235 + {
  236 + if (file_exists($dotfile)) {
  237 + $oldmtime = file_exists($outputfile) ? filemtime($outputfile) : 0;
  238 +
  239 + $command = $this->graph['directed'] ? $this->dotCommand : $this->neatoCommand;
  240 + $command .= ' -T' . escapeshellarg($format) . ' -o' . escapeshellarg($outputfile) . ' ' . escapeshellarg($dotfile);
  241 +
  242 + @`$command`;
  243 +
  244 + if (file_exists($outputfile) && filemtime($outputfile) > $oldmtime) {
  245 + return TRUE;
  246 + }
  247 + }
  248 +
  249 + return FALSE;
  250 + }
  251 +
  252 + /**
  253 + * Add a cluster to the graph.
  254 + *
  255 + * @param string ID.
  256 + * @param array Title.
  257 + * @param array Attributes of the cluster.
  258 + * @access public
  259 + */
  260 + function addCluster($id, $title, $attributes = array())
  261 + {
  262 + $this->graph['clusters'][$id]['title'] = $title;
  263 + $this->graph['clusters'][$id]['attributes'] = $attributes;
  264 + }
  265 +
  266 + /**
  267 + * Add a note to the graph.
  268 + *
  269 + * @param string Name of the node.
  270 + * @param array Attributes of the node.
  271 + * @param string Group of the node.
  272 + * @access public
  273 + */
  274 + function addNode($name, $attributes = array(), $group = 'default')
  275 + {
  276 + $this->graph['nodes'][$group][$name] = $attributes;
  277 + }
  278 +
  279 + /**
  280 + * Remove a node from the graph.
  281 + *
  282 + * @param Name of the node to be removed.
  283 + * @access public
  284 + */
  285 + function removeNode($name, $group = 'default')
  286 + {
  287 + if (isset($this->graph['nodes'][$group][$name])) {
  288 + unset($this->graph['nodes'][$group][$name]);
  289 + }
  290 + }
  291 +
  292 + /**
  293 + * Add an edge to the graph.
  294 + *
  295 + * Caveat! This cannot handle multiple identical edges. If you use non-numeric
  296 + * IDs for the nodes, this will not do (too much) harm. For numeric IDs the
  297 + * array_merge() that is used will change the keys when merging arrays, leading
  298 + * to new nodes appearing in the graph.
  299 + *
  300 + * @param array Start and End node of the edge.
  301 + * @param array Attributes of the edge.
  302 + * @access public
  303 + */
  304 + function addEdge($edge, $attributes = array())
  305 + {
  306 + if (is_array($edge)) {
  307 + $from = key($edge);
  308 + $to = $edge[$from];
  309 + $id = $from . '_' . $to;
  310 +
  311 + if (!isset($this->graph['edges'][$id])) {
  312 + $this->graph['edges'][$id] = $edge;
  313 + } else {
  314 + $this->graph['edges'][$id] = array_merge(
  315 + $this->graph['edges'][$id],
  316 + $edge
  317 + );
  318 + }
  319 +
  320 + if (is_array($attributes)) {
  321 + if (!isset($this->graph['edgeAttributes'][$id])) {
  322 + $this->graph['edgeAttributes'][$id] = $attributes;
  323 + } else {
  324 + $this->graph['edgeAttributes'][$id] = array_merge(
  325 + $this->graph['edgeAttributes'][$id],
  326 + $attributes
  327 + );
  328 + }
  329 + }
  330 + }
  331 + }
  332 +
  333 + /**
  334 + * Remove an edge from the graph.
  335 + *
  336 + * @param array Start and End node of the edge to be removed.
  337 + * @access public
  338 + */
  339 + function removeEdge($edge)
  340 + {
  341 + if (is_array($edge)) {
  342 + $from = key($edge);
  343 + $to = $edge[$from];
  344 + $id = $from . '_' . $to;
  345 +
  346 + if (isset($this->graph['edges'][$id])) {
  347 + unset($this->graph['edges'][$id]);
  348 + }
  349 +
  350 + if (isset($this->graph['edgeAttributes'][$id])) {
  351 + unset($this->graph['edgeAttributes'][$id]);
  352 + }
  353 + }
  354 + }
  355 +
  356 + /**
  357 + * Add attributes to the graph.
  358 + *
  359 + * @param array Attributes to be added to the graph.
  360 + * @access public
  361 + */
  362 + function addAttributes($attributes)
  363 + {
  364 + if (is_array($attributes)) {
  365 + $this->graph['attributes'] = array_merge(
  366 + $this->graph['attributes'],
  367 + $attributes
  368 + );
  369 + }
  370 + }
  371 +
  372 + /**
  373 + * Set attributes of the graph.
  374 + *
  375 + * @param array Attributes to be set for the graph.
  376 + * @access public
  377 + */
  378 + function setAttributes($attributes)
  379 + {
  380 + if (is_array($attributes)) {
  381 + $this->graph['attributes'] = $attributes;
  382 + }
  383 + }
  384 +
  385 + /**
  386 + * Set directed/undirected flag for the graph.
  387 + *
  388 + * @param boolean Directed (TRUE) or undirected (FALSE) graph.
  389 + * @access public
  390 + */
  391 + function setDirected($directed)
  392 + {
  393 + if (is_bool($directed)) {
  394 + $this->graph['directed'] = $directed;
  395 + }
  396 + }
  397 +
  398 + /**
  399 + * Load graph from file.
  400 + *
  401 + * @param string File to load graph from.
  402 + * @access public
  403 + */
  404 + function load($file)
  405 + {
  406 + if ($serializedGraph = implode('', @file($file))) {
  407 + $this->graph = unserialize($serializedGraph);
  408 + }
  409 + }
  410 +
  411 + /**
  412 + * Save graph to file.
  413 + *
  414 + * @param string File to save the graph to.
  415 + * @return mixed File the graph was saved to, FALSE on failure.
  416 + * @access public
  417 + */
  418 + function save($file = '')
  419 + {
  420 + $serializedGraph = serialize($this->graph);
  421 +
  422 + if (empty($file)) {
  423 + $file = System::mktemp('graph_');
  424 + }
  425 +
  426 + if ($fp = @fopen($file, 'w')) {
  427 + @fputs($fp, $serializedGraph);
  428 + @fclose($fp);
  429 +
  430 + return $file;
  431 + }
  432 +
  433 + return FALSE;
  434 + }
  435 +
  436 + /**
  437 + * Parse the graph into GraphViz markup.
  438 + *
  439 + * @return string GraphViz markup
  440 + * @access public
  441 + */
  442 + function parse()
  443 + {
  444 + if (isset($this->graph['name']) && is_string($this->graph['name'])) {
  445 + $parsedGraph = "digraph " . $this->graph['name'] . " {\n";
  446 + } else {
  447 + $parsedGraph = "digraph G {\n";
  448 + }
  449 +
  450 + if (isset($this->graph['attributes'])) {
  451 + foreach ($this->graph['attributes'] as $key => $value) {
  452 + $attributeList[] = $key . '="' . $value . '"';
  453 + }
  454 +
  455 + if (!empty($attributeList)) {
  456 + $parsedGraph .= 'graph [ '.implode(',', $attributeList) . " ];\n";
  457 + }
  458 + }
  459 +
  460 + if (isset($this->graph['nodes'])) {
  461 + foreach($this->graph['nodes'] as $group => $nodes) {
  462 + if ($group != 'default') {
  463 + $parsedGraph .= sprintf(
  464 + "subgraph \"cluster_%s\" {\nlabel=\"%s\";\n",
  465 +
  466 + $group,
  467 + isset($this->graph['clusters'][$group]) ? $this->graph['clusters'][$group]['title'] : ''
  468 + );
  469 +
  470 + if (isset($this->graph['clusters'][$group]['attributes'])) {
  471 + unset($attributeList);
  472 +
  473 + foreach ($this->graph['clusters'][$group]['attributes'] as $key => $value) {
  474 + $attributeList[] = $key . '="' . $value . '"';
  475 + }
  476 +
  477 + if (!empty($attributeList)) {
  478 + $parsedGraph .= implode(',', $attributeList) . ";\n";
  479 + }
  480 + }
  481 + }
  482 +
  483 + foreach($nodes as $node => $attributes) {
  484 + unset($attributeList);
  485 +
  486 + foreach($attributes as $key => $value) {
  487 + $attributeList[] = $key . '="' . $value . '"';
  488 + }
  489 +
  490 + if (!empty($attributeList)) {
  491 + $parsedGraph .= sprintf(
  492 + "\"%s\" [ %s ];\n",
  493 + addslashes(stripslashes($node)),
  494 + implode(',', $attributeList)
  495 + );
  496 + }
  497 + }
  498 +
  499 + if ($group != 'default') {
  500 + $parsedGraph .= "}\n";
  501 + }
  502 + }
  503 + }
  504 +
  505 + if (isset($this->graph['edges'])) {
  506 + foreach($this->graph['edges'] as $label => $node) {
  507 + unset($attributeList);
  508 +
  509 + $from = key($node);
  510 + $to = $node[$from];
  511 +
  512 + foreach($this->graph['edgeAttributes'][$label] as $key => $value) {
  513 + $attributeList[] = $key . '="' . $value . '"';
  514 + }
  515 +
  516 + $parsedGraph .= sprintf(
  517 + '"%s" -> "%s"',
  518 + addslashes(stripslashes($from)),
  519 + addslashes(stripslashes($to))
  520 + );
  521 +
  522 + if (!empty($attributeList)) {
  523 + $parsedGraph .= sprintf(
  524 + ' [ %s ]',
  525 + implode(',', $attributeList)
  526 + );
  527 + }
  528 +
  529 + $parsedGraph .= ";\n";
  530 + }
  531 + }
  532 +
  533 + return $parsedGraph . "}\n";
  534 + }
  535 +
  536 + /**
  537 + * Save GraphViz markup to file.
  538 + *
  539 + * @param string File to write the GraphViz markup to.
  540 + * @return mixed File to which the GraphViz markup was
  541 + * written, FALSE on failure.
  542 + * @access public
  543 + */
  544 + function saveParsedGraph($file = '')
  545 + {
  546 + $parsedGraph = $this->parse();
  547 +
  548 + if (!empty($parsedGraph)) {
  549 + if (empty($file)) {
  550 + $file = System::mktemp('graph_');
  551 + }
  552 +
  553 + if ($fp = @fopen($file, 'w')) {
  554 + @fputs($fp, $parsedGraph);
  555 + @fclose($fp);
  556 +
  557 + return $file;
  558 + }
  559 + }
  560 +
  561 + return FALSE;
  562 + }
  563 +}
  564 +
  565 +/*
  566 + * Local variables:
  567 + * tab-width: 4
  568 + * c-basic-offset: 4
  569 + * c-hanging-comment-ender-p: nil
  570 + * End:
  571 + */
  572 +?>
thirdparty/pear/System.php 0 → 100644
  1 +<?php
  2 +//
  3 +// +----------------------------------------------------------------------+
  4 +// | PHP Version 5 |
  5 +// +----------------------------------------------------------------------+
  6 +// | Copyright (c) 1997-2004 The PHP Group |
  7 +// +----------------------------------------------------------------------+
  8 +// | This source file is subject to version 3.0 of the PHP license, |
  9 +// | that is bundled with this package in the file LICENSE, and is |
  10 +// | available through the world-wide-web at the following url: |
  11 +// | http://www.php.net/license/3_0.txt. |
  12 +// | If you did not receive a copy of the PHP license and are unable to |
  13 +// | obtain it through the world-wide-web, please send a note to |
  14 +// | license@php.net so we can mail you a copy immediately. |
  15 +// +----------------------------------------------------------------------+
  16 +// | Authors: Tomas V.V.Cox <cox@idecnet.com> |
  17 +// +----------------------------------------------------------------------+
  18 +//
  19 +// $Id: System.php,v 1.36 2004/06/15 16:33:46 pajoye Exp $
  20 +//
  21 +
  22 +require_once 'PEAR.php';
  23 +require_once 'Console/Getopt.php';
  24 +
  25 +$GLOBALS['_System_temp_files'] = array();
  26 +
  27 +/**
  28 +* System offers cross plattform compatible system functions
  29 +*
  30 +* Static functions for different operations. Should work under
  31 +* Unix and Windows. The names and usage has been taken from its respectively
  32 +* GNU commands. The functions will return (bool) false on error and will
  33 +* trigger the error with the PHP trigger_error() function (you can silence
  34 +* the error by prefixing a '@' sign after the function call).
  35 +*
  36 +* Documentation on this class you can find in:
  37 +* http://pear.php.net/manual/
  38 +*
  39 +* Example usage:
  40 +* if (!@System::rm('-r file1 dir1')) {
  41 +* print "could not delete file1 or dir1";
  42 +* }
  43 +*
  44 +* In case you need to to pass file names with spaces,
  45 +* pass the params as an array:
  46 +*
  47 +* System::rm(array('-r', $file1, $dir1));
  48 +*
  49 +* @package System
  50 +* @author Tomas V.V.Cox <cox@idecnet.com>
  51 +* @version $Revision: 1.36 $
  52 +* @access public
  53 +* @see http://pear.php.net/manual/
  54 +*/
  55 +class System
  56 +{
  57 + /**
  58 + * returns the commandline arguments of a function
  59 + *
  60 + * @param string $argv the commandline
  61 + * @param string $short_options the allowed option short-tags
  62 + * @param string $long_options the allowed option long-tags
  63 + * @return array the given options and there values
  64 + * @access private
  65 + */
  66 + function _parseArgs($argv, $short_options, $long_options = null)
  67 + {
  68 + if (!is_array($argv) && $argv !== null) {
  69 + $argv = preg_split('/\s+/', $argv);
  70 + }
  71 + return Console_Getopt::getopt2($argv, $short_options);
  72 + }
  73 +
  74 + /**
  75 + * Output errors with PHP trigger_error(). You can silence the errors
  76 + * with prefixing a "@" sign to the function call: @System::mkdir(..);
  77 + *
  78 + * @param mixed $error a PEAR error or a string with the error message
  79 + * @return bool false
  80 + * @access private
  81 + */
  82 + function raiseError($error)
  83 + {
  84 + if (PEAR::isError($error)) {
  85 + $error = $error->getMessage();
  86 + }
  87 + trigger_error($error, E_USER_WARNING);
  88 + return false;
  89 + }
  90 +
  91 + /**
  92 + * Creates a nested array representing the structure of a directory
  93 + *
  94 + * System::_dirToStruct('dir1', 0) =>
  95 + * Array
  96 + * (
  97 + * [dirs] => Array
  98 + * (
  99 + * [0] => dir1
  100 + * )
  101 + *
  102 + * [files] => Array
  103 + * (
  104 + * [0] => dir1/file2
  105 + * [1] => dir1/file3
  106 + * )
  107 + * )
  108 + * @param string $sPath Name of the directory
  109 + * @param integer $maxinst max. deep of the lookup
  110 + * @param integer $aktinst starting deep of the lookup
  111 + * @return array the structure of the dir
  112 + * @access private
  113 + */
  114 +
  115 + function _dirToStruct($sPath, $maxinst, $aktinst = 0)
  116 + {
  117 + $struct = array('dirs' => array(), 'files' => array());
  118 + if (($dir = @opendir($sPath)) === false) {
  119 + System::raiseError("Could not open dir $sPath");
  120 + return $struct; // XXX could not open error
  121 + }
  122 + $struct['dirs'][] = $sPath; // XXX don't add if '.' or '..' ?
  123 + $list = array();
  124 + while ($file = readdir($dir)) {
  125 + if ($file != '.' && $file != '..') {
  126 + $list[] = $file;
  127 + }
  128 + }
  129 + closedir($dir);
  130 + sort($list);
  131 + if ($aktinst < $maxinst || $maxinst == 0) {
  132 + foreach($list as $val) {
  133 + $path = $sPath . DIRECTORY_SEPARATOR . $val;
  134 + if (is_dir($path)) {
  135 + $tmp = System::_dirToStruct($path, $maxinst, $aktinst+1);
  136 + $struct = array_merge_recursive($tmp, $struct);
  137 + } else {
  138 + $struct['files'][] = $path;
  139 + }
  140 + }
  141 + }
  142 + return $struct;
  143 + }
  144 +
  145 + /**
  146 + * Creates a nested array representing the structure of a directory and files
  147 + *
  148 + * @param array $files Array listing files and dirs
  149 + * @return array
  150 + * @see System::_dirToStruct()
  151 + */
  152 + function _multipleToStruct($files)
  153 + {
  154 + $struct = array('dirs' => array(), 'files' => array());
  155 + settype($files, 'array');
  156 + foreach ($files as $file) {
  157 + if (is_dir($file)) {
  158 + $tmp = System::_dirToStruct($file, 0);
  159 + $struct = array_merge_recursive($tmp, $struct);
  160 + } else {
  161 + $struct['files'][] = $file;
  162 + }
  163 + }
  164 + return $struct;
  165 + }
  166 +
  167 + /**
  168 + * The rm command for removing files.
  169 + * Supports multiple files and dirs and also recursive deletes
  170 + *
  171 + * @param string $args the arguments for rm
  172 + * @return mixed PEAR_Error or true for success
  173 + * @access public
  174 + */
  175 + function rm($args)
  176 + {
  177 + $opts = System::_parseArgs($args, 'rf'); // "f" do nothing but like it :-)
  178 + if (PEAR::isError($opts)) {
  179 + return System::raiseError($opts);
  180 + }
  181 + foreach($opts[0] as $opt) {
  182 + if ($opt[0] == 'r') {
  183 + $do_recursive = true;
  184 + }
  185 + }
  186 + $ret = true;
  187 + if (isset($do_recursive)) {
  188 + $struct = System::_multipleToStruct($opts[1]);
  189 + foreach($struct['files'] as $file) {
  190 + if (!@unlink($file)) {
  191 + $ret = false;
  192 + }
  193 + }
  194 + foreach($struct['dirs'] as $dir) {
  195 + if (!@rmdir($dir)) {
  196 + $ret = false;
  197 + }
  198 + }
  199 + } else {
  200 + foreach ($opts[1] as $file) {
  201 + $delete = (is_dir($file)) ? 'rmdir' : 'unlink';
  202 + if (!@$delete($file)) {
  203 + $ret = false;
  204 + }
  205 + }
  206 + }
  207 + return $ret;
  208 + }
  209 +
  210 + /**
  211 + * Make directories. Note that we use call_user_func('mkdir') to avoid
  212 + * a problem with ZE2 calling System::mkDir instead of the native PHP func.
  213 + *
  214 + * @param string $args the name of the director(y|ies) to create
  215 + * @return bool True for success
  216 + * @access public
  217 + */
  218 + function mkDir($args)
  219 + {
  220 + $opts = System::_parseArgs($args, 'pm:');
  221 + if (PEAR::isError($opts)) {
  222 + return System::raiseError($opts);
  223 + }
  224 + $mode = 0777; // default mode
  225 + foreach($opts[0] as $opt) {
  226 + if ($opt[0] == 'p') {
  227 + $create_parents = true;
  228 + } elseif($opt[0] == 'm') {
  229 + // if the mode is clearly an octal number (starts with 0)
  230 + // convert it to decimal
  231 + if (strlen($opt[1]) && $opt[1]{0} == '0') {
  232 + $opt[1] = octdec($opt[1]);
  233 + } else {
  234 + // convert to int
  235 + $opt[1] += 0;
  236 + }
  237 + $mode = $opt[1];
  238 + }
  239 + }
  240 + $ret = true;
  241 + if (isset($create_parents)) {
  242 + foreach($opts[1] as $dir) {
  243 + $dirstack = array();
  244 + while (!@is_dir($dir) && $dir != DIRECTORY_SEPARATOR) {
  245 + array_unshift($dirstack, $dir);
  246 + $dir = dirname($dir);
  247 + }
  248 + while ($newdir = array_shift($dirstack)) {
  249 + if (!call_user_func('mkdir', $newdir, $mode)) {
  250 + $ret = false;
  251 + }
  252 + }
  253 + }
  254 + } else {
  255 + foreach($opts[1] as $dir) {
  256 + if (!@is_dir($dir) && !call_user_func('mkdir', $dir, $mode)) {
  257 + $ret = false;
  258 + }
  259 + }
  260 + }
  261 + return $ret;
  262 + }
  263 +
  264 + /**
  265 + * Concatenate files
  266 + *
  267 + * Usage:
  268 + * 1) $var = System::cat('sample.txt test.txt');
  269 + * 2) System::cat('sample.txt test.txt > final.txt');
  270 + * 3) System::cat('sample.txt test.txt >> final.txt');
  271 + *
  272 + * Note: as the class use fopen, urls should work also (test that)
  273 + *
  274 + * @param string $args the arguments
  275 + * @return boolean true on success
  276 + * @access public
  277 + */
  278 + function &cat($args)
  279 + {
  280 + $ret = null;
  281 + $files = array();
  282 + if (!is_array($args)) {
  283 + $args = preg_split('/\s+/', $args);
  284 + }
  285 + for($i=0; $i < count($args); $i++) {
  286 + if ($args[$i] == '>') {
  287 + $mode = 'wb';
  288 + $outputfile = $args[$i+1];
  289 + break;
  290 + } elseif ($args[$i] == '>>') {
  291 + $mode = 'ab+';
  292 + $outputfile = $args[$i+1];
  293 + break;
  294 + } else {
  295 + $files[] = $args[$i];
  296 + }
  297 + }
  298 + if (isset($mode)) {
  299 + if (!$outputfd = fopen($outputfile, $mode)) {
  300 + $err = System::raiseError("Could not open $outputfile");
  301 + return $err;
  302 + }
  303 + $ret = true;
  304 + }
  305 + foreach ($files as $file) {
  306 + if (!$fd = fopen($file, 'r')) {
  307 + System::raiseError("Could not open $file");
  308 + continue;
  309 + }
  310 + while ($cont = fread($fd, 2048)) {
  311 + if (isset($outputfd)) {
  312 + fwrite($outputfd, $cont);
  313 + } else {
  314 + $ret .= $cont;
  315 + }
  316 + }
  317 + fclose($fd);
  318 + }
  319 + if (@is_resource($outputfd)) {
  320 + fclose($outputfd);
  321 + }
  322 + return $ret;
  323 + }
  324 +
  325 + /**
  326 + * Creates temporary files or directories. This function will remove
  327 + * the created files when the scripts finish its execution.
  328 + *
  329 + * Usage:
  330 + * 1) $tempfile = System::mktemp("prefix");
  331 + * 2) $tempdir = System::mktemp("-d prefix");
  332 + * 3) $tempfile = System::mktemp();
  333 + * 4) $tempfile = System::mktemp("-t /var/tmp prefix");
  334 + *
  335 + * prefix -> The string that will be prepended to the temp name
  336 + * (defaults to "tmp").
  337 + * -d -> A temporary dir will be created instead of a file.
  338 + * -t -> The target dir where the temporary (file|dir) will be created. If
  339 + * this param is missing by default the env vars TMP on Windows or
  340 + * TMPDIR in Unix will be used. If these vars are also missing
  341 + * c:\windows\temp or /tmp will be used.
  342 + *
  343 + * @param string $args The arguments
  344 + * @return mixed the full path of the created (file|dir) or false
  345 + * @see System::tmpdir()
  346 + * @access public
  347 + */
  348 + function mktemp($args = null)
  349 + {
  350 + static $first_time = true;
  351 + $opts = System::_parseArgs($args, 't:d');
  352 + if (PEAR::isError($opts)) {
  353 + return System::raiseError($opts);
  354 + }
  355 + foreach($opts[0] as $opt) {
  356 + if($opt[0] == 'd') {
  357 + $tmp_is_dir = true;
  358 + } elseif($opt[0] == 't') {
  359 + $tmpdir = $opt[1];
  360 + }
  361 + }
  362 + $prefix = (isset($opts[1][0])) ? $opts[1][0] : 'tmp';
  363 + if (!isset($tmpdir)) {
  364 + $tmpdir = System::tmpdir();
  365 + }
  366 + if (!System::mkDir("-p $tmpdir")) {
  367 + return false;
  368 + }
  369 + $tmp = tempnam($tmpdir, $prefix);
  370 + if (isset($tmp_is_dir)) {
  371 + unlink($tmp); // be careful possible race condition here
  372 + if (!call_user_func('mkdir', $tmp, 0700)) {
  373 + return System::raiseError("Unable to create temporary directory $tmpdir");
  374 + }
  375 + }
  376 + $GLOBALS['_System_temp_files'][] = $tmp;
  377 + if ($first_time) {
  378 + PEAR::registerShutdownFunc(array('System', '_removeTmpFiles'));
  379 + $first_time = false;
  380 + }
  381 + return $tmp;
  382 + }
  383 +
  384 + /**
  385 + * Remove temporary files created my mkTemp. This function is executed
  386 + * at script shutdown time
  387 + *
  388 + * @access private
  389 + */
  390 + function _removeTmpFiles()
  391 + {
  392 + if (count($GLOBALS['_System_temp_files'])) {
  393 + $delete = $GLOBALS['_System_temp_files'];
  394 + array_unshift($delete, '-r');
  395 + System::rm($delete);
  396 + }
  397 + }
  398 +
  399 + /**
  400 + * Get the path of the temporal directory set in the system
  401 + * by looking in its environments variables.
  402 + * Note: php.ini-recommended removes the "E" from the variables_order setting,
  403 + * making unavaible the $_ENV array, that s why we do tests with _ENV
  404 + *
  405 + * @return string The temporal directory on the system
  406 + */
  407 + function tmpdir()
  408 + {
  409 + if (OS_WINDOWS) {
  410 + if ($var = isset($_ENV['TEMP']) ? $_ENV['TEMP'] : getenv('TEMP')) {
  411 + return $var;
  412 + }
  413 + if ($var = isset($_ENV['TMP']) ? $_ENV['TMP'] : getenv('TMP')) {
  414 + return $var;
  415 + }
  416 + if ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) {
  417 + return $var;
  418 + }
  419 + return getenv('SystemRoot') . '\temp';
  420 + }
  421 + if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) {
  422 + return $var;
  423 + }
  424 + return '/tmp';
  425 + }
  426 +
  427 + /**
  428 + * The "which" command (show the full path of a command)
  429 + *
  430 + * @param string $program The command to search for
  431 + * @return mixed A string with the full path or false if not found
  432 + * @author Stig Bakken <ssb@php.net>
  433 + */
  434 + function which($program, $fallback = false)
  435 + {
  436 + // is_executable() is not available on windows
  437 + if (OS_WINDOWS) {
  438 + $pear_is_executable = 'is_file';
  439 + } else {
  440 + $pear_is_executable = 'is_executable';
  441 + }
  442 +
  443 + // full path given
  444 + if (basename($program) != $program) {
  445 + return (@$pear_is_executable($program)) ? $program : $fallback;
  446 + }
  447 +
  448 + // XXX FIXME honor safe mode
  449 + $path_delim = OS_WINDOWS ? ';' : ':';
  450 + $exe_suffixes = OS_WINDOWS ? array('.exe','.bat','.cmd','.com') : array('');
  451 + $path_elements = explode($path_delim, getenv('PATH'));
  452 + foreach ($exe_suffixes as $suff) {
  453 + foreach ($path_elements as $dir) {
  454 + $file = $dir . DIRECTORY_SEPARATOR . $program . $suff;
  455 + if (@is_file($file) && @$pear_is_executable($file)) {
  456 + return $file;
  457 + }
  458 + }
  459 + }
  460 + return $fallback;
  461 + }
  462 +
  463 + /**
  464 + * The "find" command
  465 + *
  466 + * Usage:
  467 + *
  468 + * System::find($dir);
  469 + * System::find("$dir -type d");
  470 + * System::find("$dir -type f");
  471 + * System::find("$dir -name *.php");
  472 + * System::find("$dir -name *.php -name *.htm*");
  473 + * System::find("$dir -maxdepth 1");
  474 + *
  475 + * Params implmented:
  476 + * $dir -> Start the search at this directory
  477 + * -type d -> return only directories
  478 + * -type f -> return only files
  479 + * -maxdepth <n> -> max depth of recursion
  480 + * -name <pattern> -> search pattern (bash style). Multiple -name param allowed
  481 + *
  482 + * @param mixed Either array or string with the command line
  483 + * @return array Array of found files
  484 + *
  485 + */
  486 + function find($args)
  487 + {
  488 + if (!is_array($args)) {
  489 + $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY);
  490 + }
  491 + $dir = array_shift($args);
  492 + $patterns = array();
  493 + $depth = 0;
  494 + $do_files = $do_dirs = true;
  495 + for ($i = 0; $i < count($args); $i++) {
  496 + switch ($args[$i]) {
  497 + case '-type':
  498 + if (in_array($args[$i+1], array('d', 'f'))) {
  499 + if ($args[$i+1] == 'd') {
  500 + $do_files = false;
  501 + } else {
  502 + $do_dirs = false;
  503 + }
  504 + }
  505 + $i++;
  506 + break;
  507 + case '-name':
  508 + $patterns[] = "(" . preg_replace(array('/\./', '/\*/'),
  509 + array('\.', '.*'),
  510 + $args[$i+1])
  511 + . ")";
  512 + $i++;
  513 + break;
  514 + case '-maxdepth':
  515 + $depth = $args[$i+1];
  516 + break;
  517 + }
  518 + }
  519 + $path = System::_dirToStruct($dir, $depth);
  520 + if ($do_files && $do_dirs) {
  521 + $files = array_merge($path['files'], $path['dirs']);
  522 + } elseif ($do_dirs) {
  523 + $files = $path['dirs'];
  524 + } else {
  525 + $files = $path['files'];
  526 + }
  527 + if (count($patterns)) {
  528 + $patterns = implode('|', $patterns);
  529 + $ret = array();
  530 + for ($i = 0; $i < count($files); $i++) {
  531 + if (preg_match("#^$patterns\$#", $files[$i])) {
  532 + $ret[] = $files[$i];
  533 + }
  534 + }
  535 + return $ret;
  536 + }
  537 + return $files;
  538 + }
  539 +}
  540 +?>