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);