* @link http://wiki.cs50.net/render50 * @package render50 * @version 0.93 * * GNU General Public License, version 2 * http://www.gnu.org/licenses/gpl-2.0.html */ // report all errors error_reporting(E_ALL); ini_set("display_errors", true); // GeSHi require_once(dirname(__FILE__) . "/../lib/geshi/geshi.php"); // mPDF require_once(dirname(__FILE__) . "/../lib/mpdf50/mpdf.php"); // override mPDF's error handling class _mPDF extends mPDF { function Error($msg) { die("Error: $msg\n"); } } // ensure proper usage if ($argc < 2 || in_array("-h", $argv) || in_array("--help", $argv)) die("Usage: php /path/to/render50.php output [inputs] [-i includes] [-x excludes]\n"); // filename for output $output = preg_match("/\.pdf$/i", $argv[1]) ? $argv[1] : $argv[1] . ".pdf"; // check for includes for ($i = 2; $i < $argc; $i++) { if ($argv[$i] == "-i") $includes = array(); else if ($argv[$i][0] == "-" && isset($includes)) break; else if (isset($includes)) array_push($includes, str_replace("*", ".*", preg_replace("/({|}|\||\.)/", '\\\$1', $argv[$i]))); } if (isset($includes)) $includes = "{^" . join("|", $includes) . "$}"; // check for excludes for ($i = 2; $i < $argc; $i++) { if ($argv[$i] == "-x") $excludes = array(); else if ($argv[$i][0] == "-" && isset($excludes)) break; else if (isset($excludes)) array_push($excludes, str_replace("*", ".*", preg_replace("/({|}|\||\.)/", '\\\$1', $argv[$i]))); } if (isset($excludes)) $excludes = "{^" . join("|", $excludes) . "$}"; // check STDIN else command line for inputs if ($argc == 2 || ($argc > 2 && $argv[2][0] == "-")) { echo "Taking inputs from STDIN, one per line... Hit Ctrl-D when done else Ctrl-C to cancel.\n"; $patterns = file("php://stdin", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); } else { $patterns = array(); for ($i = 2; $i < $argc; $i++) { if ($argv[$i][0] == "-") break; array_push($patterns, $argv[$i]); } } // glob patterns $inputs = array(); foreach ($patterns as $pattern) $inputs = array_merge($inputs, glob($pattern, GLOB_BRACE)); // files to render $files = array(); // directories into which to descend $directories = array(); // parse command line for files and directories foreach ($inputs as $input) { // ensure file (or directory) exists if (!file_exists($input)) die("File does not exist: {$input}\n"); // ensure file (or directory) is readable if (!is_readable($input)) die("File cannot be read: {$input}\n"); // push file or directory onto array if (is_dir($input)) array_push($directories, $input); else array_push($files, $input); } // descend into directories while (count($directories) > 0) { $directory = array_pop($directories); foreach (scandir($directory) as $child) { // ignore . and .. if ($child == "." || $child == "..") continue; // prepare path $path = rtrim($directory, "/") . DIRECTORY_SEPARATOR . $child; // push path onto array if (is_dir($path)) array_push($directories, $path); else array_push($files, $path); } } // create PDF $mpdf = new _mPDF("c", "Letter-L", 8); // create highlighter $geshi = new GeSHi(); $geshi->enable_classes(); $geshi->enable_keyword_links(false); $geshi->enable_line_numbers(GESHI_NORMAL_LINE_NUMBERS); $geshi->set_header_type(GESHI_HEADER_DIV); $geshi->set_tab_width(4); // prepare to count pages $pages = 0; // iterate over files foreach ($files as $file) { // decide whether to exclude if (isset($includes) && !preg_match($includes, $file) || (isset($excludes) && preg_match($excludes, $file))) continue; // infer language $language = $geshi->get_language_name_from_extension(pathinfo($file, PATHINFO_EXTENSION)); // ignore unknown languages if (!$language) { // whitelist Makefile, README, and *.txt if (preg_match("/^(?:Makefile|README|.*\.txt)$/i", pathinfo($file, PATHINFO_FILENAME))) $language = "txt"; else continue; } // load file echo "Rendering $file...\n"; $geshi->set_source(file_get_contents($file)); $geshi->set_language($language, true); // set header $properties = array( "border-bottom: 1px solid #808080", "color: #808080", "font-family: monospace", "text-align: right" ); $mpdf->SetHTMLHeader("