Source for file Io.inc
Documentation is available at Io.inc
* File and input handling routines
* This class parses command-line options, and works with files to
* generate lists of files to parse based on the ignore/include options
* phpDocumentor :: automatic documentation generator
* Copyright (c) 2000-2006 Joshua Eichorn, Gregory Beaver
* This library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General
* Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* @copyright 2000-2006 Joshua Eichorn, Gregory Beaver
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version CVS: $Id: Io.inc 286921 2009-08-08 05:01:24Z ashnazg $
* @link http://www.phpdoc.org
* @link http://pear.php.net/PhpDocumentor
* Class to handle file and user io opperations
* @version $Id: Io.inc 286921 2009-08-08 05:01:24Z ashnazg $
* Holds all the options that are avaible to the cmd line interface
* and to the different web interfaces
* Format: array(array(regexp-ready string to search for whole path,
* regexp-ready string to search for basename of ignore strings),...)
* A specific array of values that boolean-based arguments can understand,
* aided by the {@link decideOnOrOff()} helper method.
* Use lowercase letters always, to simplify string comparisons
'', ' ', 'on', 'y', 'yes', 'true', '1',
'off', 'n', 'no', 'false', '0'
* creates an array $this->phpDocOptions and sets program options in it.
* Array is in the format of:
* [filename][tag][] = "f";
* [filename][tag][] = "-file";
* [filename][desc] "name of file to parse"
$this->phpDocOptions['filename']['tag'] = array( "-f", "--filename");
$this->phpDocOptions['filename']['desc'] = "name of file(s) to parse ',' file1,file2. Can contain complete path and * ? wildcards";
$this->phpDocOptions['directory']['tag'] = array( "-d", "--directory");
$this->phpDocOptions['directory']['desc'] = "name of a directory(s) to parse directory1,directory2";
$this->phpDocOptions['examplesdir']['tag'] = array( "-ed", "--examplesdir");
$this->phpDocOptions['examplesdir']['desc'] = "full path of the directory to look for example files from @example tags";
$this->phpDocOptions['templatebase']['tag'] = array( "-tb", "--templatebase");
$this->phpDocOptions['templatebase']['desc'] = "base location of all templates for this parse.";
$this->phpDocOptions['target']['desc'] = "path where to save the generated files";
$this->phpDocOptions['ignore']['desc'] = "file(s) that will be ignored, multiple separated by ','. Wildcards * and ? are ok";
$this->phpDocOptions['ignoresymlinks']['tag'] = array("-is", "--ignoresymlinks");
$this->phpDocOptions['ignoresymlinks']['desc'] = "ignore symlinks to other files or directories, default is off";
$this->phpDocOptions['ignoretags']['tag'] = array("-it", "--ignore-tags");
$this->phpDocOptions['ignoretags']['desc'] = "tags to ignore for this parse. @package, @subpackage, @access and @ignore may not be ignored.";
$this->phpDocOptions['hidden']['tag'] = array("-dh", "--hidden");
$this->phpDocOptions['hidden']['desc'] = "set equal to on (-dh on) to descend into hidden directories (directories starting with '.'), default is off";
$this->phpDocOptions['quiet']['desc'] = "do not display parsing/conversion messages. Useful for cron jobs on/off default off";
$this->phpDocOptions['undocumentedelements']['tag'] = array("-ue", "--undocumentedelements");
$this->phpDocOptions['undocumentedelements']['desc'] = "Control whether or not warnings will be shown for undocumented elements. Useful for identifying classes and methods that haven't yet been documented on/off default off";
$this->phpDocOptions['title']['desc'] = "title of generated documentation, default is 'Generated Documentation'";
$this->phpDocOptions['help']['desc'] = " show this help message";
$this->phpDocOptions['useconfig']['tag'] = array("-c","--useconfig");
$this->phpDocOptions['useconfig']['desc'] = "Use a Config file in the users/ subdirectory for all command-line options";
$this->phpDocOptions['parseprivate']['tag'] = array("-pp","--parseprivate");
$this->phpDocOptions['parseprivate']['desc'] = "parse @internal and elements marked private with @access. Use on/off, default off";
$this->phpDocOptions['parseprivate']['validvalues'] = array('on', 'off');
$this->phpDocOptions['packageoutput']['tag'] = array("-po","--packageoutput");
$this->phpDocOptions['packageoutput']['desc'] = "output documentation only for selected packages. Use a comma-delimited list";
$this->phpDocOptions['defaultpackagename']['tag'] = array("-dn","--defaultpackagename");
$this->phpDocOptions['defaultpackagename']['desc'] = "name to use for the default package. If not specified, uses 'default'";
$this->phpDocOptions['defaultcategoryname']['tag'] = array("-dc","--defaultcategoryname");
$this->phpDocOptions['defaultcategoryname']['desc'] = "name to use for the default category. If not specified, uses 'default'";
$this->phpDocOptions['output']['desc'] = "output information to use separated by ','. Format: output:converter:templatedir like \"HTML:frames:phpedit\"";
$this->phpDocOptions['converterparams']['tag'] = array("-cp","--converterparams");
$this->phpDocOptions['converterparams']['desc'] = "dynamic parameters for a converter, separate values with commas";
$this->phpDocOptions['customtags']['tag'] = array("-ct","--customtags");
$this->phpDocOptions['customtags']['desc'] = "custom tags, will be recognized and put in tags[] instead of unknowntags[]";
$this->phpDocOptions['sourcecode']['tag'] = array("-s","--sourcecode");
$this->phpDocOptions['sourcecode']['desc'] = "generate highlighted sourcecode for every parsed file (PHP 4.3.0+ only) on/off default off";
$this->phpDocOptions['sourcecode']['validvalues'] = array('on', 'off');
$this->phpDocOptions['javadocdesc']['tag'] = array("-j","--javadocdesc");
$this->phpDocOptions['javadocdesc']['desc'] = "JavaDoc-compliant description parsing. Use on/off, default off (more flexibility)";
$this->phpDocOptions['javadocdesc']['validvalues'] = array('on', 'off');
$this->phpDocOptions['pear']['desc'] = "Parse a PEAR-style repository (package is directory, _members are @access private) on/off default off";
$this->phpDocOptions['pear']['validvalues'] = array('on', 'off');
$this->phpDocOptions['readmeinstallchangelog']['tag'] = array("-ric","--readmeinstallchangelog");
$this->phpDocOptions['readmeinstallchangelog']['desc'] = "Specify custom filenames to parse like README, INSTALL or CHANGELOG files";
$this->phpDocOptions['readmeinstallchangelog']['type'] = "value";
$this->phpDocOptions['general']['message'] = "You can have multiple directories and multiple files, as well as a combination of both options";
* create the help message for display on the command-line
* @return string a string containing a help message
foreach($data['tag'] as $param) {
$tmp = " ". trim($tag). $tagspace;
$tmp = substr($tmp,0,$taglen);
for($i= 1;$i< count($dt);$i++ )
$dt[$i] = $tagspace. $dt[$i];
$ret .= "\n". wordwrap($data['message'],$outputwidth). "\n";
* calls {@link file_exists()} for each value in include_path,
* then calls {@link is_readable()} when it finds the file
return true; // for absolute paths
if ($a = realpath($path . DIRECTORY_SEPARATOR . $filename))
* Parses $_SERVER['argv'] and creates a setup array
* @return array a setup array
* @global array command-line arguments
* @todo replace with Console_* ?
$setting['hidden'] = "off";
$setting['ignoresymlinks'] = 'off';
if ($cmd == '-h' || $cmd == '--help')
// at first, set the arg value as if we
// already know it's formatted normally, e.g.
$setting[$valnext] = $cmd;
if (isset ($data['type']) && $data['type'] == 'set') {
if ($valnext !== 'junk' && strpos(trim($cmd),'-') === 0) {
// if valnext isn't 'junk' (i.e it was an arg option)
// then the first arg needs an implicit "" as its value, e.g.
// ... -q -pp ... ===> ... -q '' -pp ...
// the arg value is not a valid value
'(' . implode(', ', $data['validvalues']) . ')');
if (!empty($data['tag']))
if ($valnext == 'junk' && (strpos(trim($cmd),'-') === 0)) {
// this indicates the last arg of the command
// is an arg option (-) that was preceded by unrecognized "junk"
} else if ($valnext != 'junk' && (strpos(trim($cmd),'-') === 0)) {
// this indicates the last arg of the command
// is an arg option (-) without an arg value
// add an empty arg "value" for this arg "option"
echo "Please use php-cli.exe in windows, or set register_argc_argv On";
/* $setting will always have at least 3 elements
[ignoresymlinks] => 'off'
[template] => templates/default
if (count($setting) < 4) {
echo $this->displayhelpMsg();
* @return array list of files in a directory
* @param string $directory full path to the directory you want the list of
* @param bool whether to list files that begin with . like .bash_history
* @param bool whether to ignore symlinks
function dirList($orig_directory, $hidden = false, $ignore_symlinks = false)
die("directory: '$directory' not found\n");
while($d && ($entry= $d->read()) !== false) {
// skip hidden files, if we're supposed to
if (substr($entry,0,1) == ".")
// skip symlink files, if we're supposed to
* Retrieve common directory (case-insensitive in windows)
* takes the list of files, and returns the subdirectory they share in common,
* "/dir1/dir2/subdir/dir3/filename.ext",
* "/dir1/dir2/subdir/dir4/filename.ext",
* "/dir1/dir2/mydir/dir5/filename.ext");
* getBase will return "/dir1/dir2"
* @param array array of strings
foreach($filelist as $path)
if ($mp[$i] != $np[$i]) $found = $i;
* Retrieve tutorial subdirectories and their contents from the list of
* @param array array of paths (strings)
* @return array array(filelist - tutorials, tutorials)
$list = $tutorials = array();
foreach($filelist as $file)
if (strpos($file,'tutorials/') !== false)
if (count($tutedir) <= 3)
// kludge - will need to fix for 2.0
$res['category'] = $GLOBALS['phpDocumentor_DefaultCategoryName'];
if ($res['tutetype'] == 'ini') continue;
return array($list,$tutorials);
* @param string base directory from {@link getBase()}
* @param array file list from {@link dirList()}
* @return array array(filelist - README/INSTALL/CHANGELOG,
* README/INSTALL/CHANGELOG)
$names = $GLOBALS['_phpDocumentor_RIC_files'];
foreach($filelist as $file)
{ // be sure to change $this->checkIgnore() if any other files are added here!!
return array($list,$ric);
* @param string directory
* @param string base directory
* @param array array of ignored items
* @param boolean the "hidden" flag
* @param boolean the "ignoresymlinks" flag
function getDirTree($dir, $base_dir, $ignore = array(), $hidden = false, $ignoresymlinks = false)
$allfiles = $this->dirList($dir,$hidden,$ignoresymlinks);
foreach($allfiles as $file)
if (!isset ($parts['extension']))
$parts['extension'] = '';
'file' => $parts['basename'],
'ext' => $parts['extension'],
uksort($struc,'strnatcasecmp');
foreach($struc as $key => $ind)
usort($ind,'Ioinc_sortfiles');
if (isset ($struc[join('/',$key)]))
foreach($struc as $key => $ind)
$struc['/'][$key] = $struc[$key];
foreach($leftover_dirs as $dir)
$leftover_dirs = array();
foreach($splitdirs as $dir)
$struc['/'] = setup_dirs($struc['/'], $dir, $tempstruc[$save]);
@uksort($struc['/'],'Ioinc_mystrucsort');
* Reads a file and returns it as a string
* Does basic error checking
* file extensions are set in {@link phpdoc.inc}
* @global array PHP File extensions, used to validate that $path is a PHP File
* @global array PHP File extensions in a CVS repository, used to validate that $path is a PHP File
global $_phpDocumentor_cvsphpfile_exts, $_phpDocumentor_phpfile_exts;
$cvsExt = $_phpDocumentor_cvsphpfile_exts;
$ext = $_phpDocumentor_phpfile_exts;
* Tell whether to ignore a file or a directory
* allows * and ? wildcards
* @param string $file just the file name of the file or directory,
* in the case of directories this is the last dir
* @param string $path the path to consider (should be checked by
* realpath() before, and may be relative)
* @param bool Ignore symlinks?
* @return bool true if $path should be ignored, false if it should not
function checkIgnore($file,$path,$ignore,$ignore_no_ext = true,$ignoresymlinks = false)
global $_phpDocumentor_RIC_files;
if (!count($ignore)) return false;
foreach($this->ignore as $match)
// match is an array if the ignore parameter was a /path/to/pattern
// check to see if the path matches with a path delimiter appended
// check to see if it matches without an appended path delimiter
// check to see if the file matches the file portion of the regex string
// check to see if the full path matches the regex
strtoupper($path . DIRECTORY_SEPARATOR . $file), $find);
// ignore parameter was just a pattern with no path delimiters
// check it against the path
// check it against the file only
* Construct the {@link $ignore} array
* @param array strings of files/paths/wildcards to ignore
for($i= 0; $i< count($ignore);$i++ )
$ignore[$i] = strtr($ignore[$i], '\\', '/');
* Converts $s into a string that can be used with preg_match
* @param string $s string with wildcards ? and *
* @return string converts * to .*, ? to ., etc.
if (DIRECTORY_SEPARATOR == '\\')
$x = strtr($s, array('?' => '.','*' => '.*','.' => '\\.','\\' => '\\\\','/' => '\\/',
'[' => '\\[',']' => '\\]','-' => '\\-'));
if (strpos($s, DIRECTORY_SEPARATOR) !== false &&
$x = "(?:.*$y$x?.*|$x.*)";
* Removes files from the $dir array that do not match the search string in
* @param array $dir array of filenames (full path)
* @param string $match search string with wildcards
* @return string|arraylisting of every file in a directory that matches
foreach($dir as $i => $file)
if (!count($find)) unset ($dir[$i]);
if ($nodir) return $dir[0];
* Take a filename with wildcards and return all files that match the
* @param string $file a full path from the -f command-line parameter, with
* potential * and ? wildcards.
* @return mixed if $file contains wildcards, returns an array of matching
* files, otherwise returns false
* Sorting functions for the file list
* Recursively add all the subdirectories of $contents to $dir without erasing anything in
* @return array processed $dir
while(list ($one,$two) = each($contents))
$dir[$one] = set_dir($dir[$one],$contents[$one]);
} else $dir[$one] = $two;
* Recursively move contents of $struc into associative array
* The contents of $struc have many indexes like 'dir/subdir/subdir2'.
* This function converts them to
* array('dir' => array('subdir' => array('subdir2')))
* @param array struc is array('dir' => array of files in dir,'dir/subdir' => array of files in dir/subdir,...)
* @param array array form of 'dir/subdir/subdir2' array('dir','subdir','subdir2')
* @return array same as struc but with array('dir' => array(file1,file2,'subdir' => array(file1,...)))
foreach($contents as $dir => $files)
if (isset ($contents[$c]))
if (!isset ($struc[$me])) $struc[$me] = array();
$struc[$me] = setup_dirs($struc[$me],$dir,$contents);
|