Fix some bugs in the smoketests, fix up TODO.
[xhtml-compiler.git] / XHTMLCompiler / Directory.php
blob57ade737fdce334a52629fb372d137a9f620daa6
1 <?php
3 /**
4 * Represents a directory in the filesystem
5 */
6 class XHTMLCompiler_Directory
9 /** Location of directory this object represents, w/o trailing slash */
10 protected $name;
12 /** Non-blank location of directory, safe for directory handling functions */
13 protected $safeName;
15 /**
16 * Path to directory you wish to instantiate.
18 public function __construct($name) {
19 $name = str_replace('\\', '/', $name); // normalize \ to /
20 $l = strlen($name) - 1; // index of last character
21 if ($l >= 0 && $name[$l] == '/') $name = substr($name, 0, $l); // truncate trailing slash
22 $safe_name = ($name === '') ? '.' : $name;
23 if (!is_dir($safe_name)) {
24 throw new Exception("Directory $safe_name does not exist");
26 $this->name = $name;
27 $this->safeName = $safe_name;
30 /** Returns name of directory without trailing slash */
31 public function getName() {return $this->safeName;}
32 /**
33 * Returns name of directory with trailing slash, prepared for
34 * a filename to be appended (s = slash, not safe)
35 * @note If the directory is the current working directory, a blank
36 * string is returned instead
38 public function getSName() {
39 return ($this->name === '') ? '' : $this->name . '/';
42 /**
43 * Recursively scans directory for files
44 * @return Tree of files in the directory, file => size
46 public function getTree() {
47 $dir = new RecursiveDirectoryIterator($this->safeName);
48 $tree = array();
49 $dirs = array(array($dir, &$tree));
51 for($i = 0; $i < count($dirs); ++$i) {
52 $d =& $dirs[$i][0]; // current directory iterator
53 $tier =& $dirs[$i][1]; // current directory tree to write to
54 for($d->rewind(); $d->valid(); $d->next()) {
55 if ($d->isDir()) {
56 // initialize new directory tree
57 $tier[$d->getFilename()] = array();
58 // file away another directory to process
59 $dirs[] = array($d->getChildren(), &$tier[$d->getFilename()]);
60 } else {
61 // add the file to the directory tree
62 $tier[$d->getFilename()] = $d->getSize();
67 return $tree;
70 /**
71 * Scans directory recursively for files with a certain file extension
72 * @param $ext_match Extension with period to look for, cannot have
73 * more than one period within it
74 * @return List of matching files, with fully qualified relative
75 * paths (not tree format)
77 public function scanRecursively($ext_match) {
78 $tree = $this->getTree();
79 $dirs = array(array('', &$tree));
80 $ret = array();
81 for ($i = 0; $i < count($dirs); ++$i) {
82 $base = $dirs[$i][0]; // base directory prefix
83 $tier = $dirs[$i][1]; // tree node we're reading from
84 foreach ($tier as $name => $contents) {
85 if (is_array($contents)) {
86 // directory
87 $dirs[] = array($base . $name . '/', $contents);
88 } else {
89 // name
90 $ext = strrchr($name, '.');
91 if ($ext != $ext_match) continue;
92 $ret[] = $this->getSName() . $base . $name;
96 return $ret;
99 /**
100 * Scans just the current directory for files matching extension
101 * @param $ext_match Extension with period to look for, cannot have
102 * more than one period within it
103 * @return List of matching files
105 public function scanFlat($ext_match) {
106 $files = scandir($this->safeName);
107 $ret = array();
108 foreach ($files as $name) {
109 if (empty($name) || $name[0] == '.') continue;
110 $ext = strrchr($name, '.');
111 if ($ext != $ext_match) continue;
112 $ret[] = $this->getSName() . $name;
114 return $ret;
118 * Scans directory for files with matching extension
119 * @param $ext_match File extension to match
120 * @param $recursive Whether or not to search recursively
122 public function scan($ext, $recursive) {
123 if ($recursive) return $this->scanRecursively($ext);
124 else return $this->scanFlat($ext);