radarrplexorganizrnginxsonarrdashboardembycouchpotatonzbgetbookmarkapplication-dashboardmuximuxlandingpagestartpagelandinghtpcserverhomepagesabnzbdheimdall
		
		
		
		
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							312 lines
						
					
					
						
							8.7 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							312 lines
						
					
					
						
							8.7 KiB
						
					
					
				
								#!/usr/bin/env php
							 | 
						|
								<?php
							 | 
						|
								
							 | 
						|
								/*
							 | 
						|
								 * This file is part of Psy Shell.
							 | 
						|
								 *
							 | 
						|
								 * (c) 2012-2017 Justin Hileman
							 | 
						|
								 *
							 | 
						|
								 * For the full copyright and license information, please view the LICENSE
							 | 
						|
								 * file that was distributed with this source code.
							 | 
						|
								 */
							 | 
						|
								
							 | 
						|
								define('WRAP_WIDTH', 100);
							 | 
						|
								
							 | 
						|
								$count = 0;
							 | 
						|
								
							 | 
						|
								if (count($argv) !== 3 || !is_dir($argv[1])) {
							 | 
						|
								    echo "usage: build_manual path/to/manual output_filename.db\n";
							 | 
						|
								    exit(1);
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								function htmlwrap($text, $width = null)
							 | 
						|
								{
							 | 
						|
								    if ($width === null) {
							 | 
						|
								        $width = WRAP_WIDTH;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    $len = strlen($text);
							 | 
						|
								
							 | 
						|
								    $return = array();
							 | 
						|
								    $lastSpace = null;
							 | 
						|
								    $inTag = false;
							 | 
						|
								    $i = $tagWidth = 0;
							 | 
						|
								    do {
							 | 
						|
								        switch (substr($text, $i, 1)) {
							 | 
						|
								            case "\n":
							 | 
						|
								                $return[] = trim(substr($text, 0, $i));
							 | 
						|
								                $text     = substr($text, $i);
							 | 
						|
								                $len      = strlen($text);
							 | 
						|
								
							 | 
						|
								                $i = $lastSpace = 0;
							 | 
						|
								                continue;
							 | 
						|
								
							 | 
						|
								            case ' ':
							 | 
						|
								                if (!$inTag) {
							 | 
						|
								                    $lastSpace = $i;
							 | 
						|
								                }
							 | 
						|
								                break;
							 | 
						|
								
							 | 
						|
								            case '<':
							 | 
						|
								                $inTag = true;
							 | 
						|
								                break;
							 | 
						|
								
							 | 
						|
								            case '>':
							 | 
						|
								                $inTag = false;
							 | 
						|
								                break;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if ($inTag) {
							 | 
						|
								            $tagWidth++;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        $i++;
							 | 
						|
								
							 | 
						|
								        if (!$inTag && ($i - $tagWidth > $width)) {
							 | 
						|
								            $lastSpace = $lastSpace ?: $width;
							 | 
						|
								
							 | 
						|
								            $return[] = trim(substr($text, 0, $lastSpace));
							 | 
						|
								            $text     = substr($text, $lastSpace);
							 | 
						|
								            $len      = strlen($text);
							 | 
						|
								
							 | 
						|
								            $i = $tagWidth = 0;
							 | 
						|
								        }
							 | 
						|
								    } while ($i < $len);
							 | 
						|
								
							 | 
						|
								    $return[] = trim($text);
							 | 
						|
								
							 | 
						|
								    return implode("\n", $return);
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								function extract_paragraphs($element)
							 | 
						|
								{
							 | 
						|
								    $paragraphs = array();
							 | 
						|
								    foreach ($element->getElementsByTagName('para') as $p) {
							 | 
						|
								        $text = '';
							 | 
						|
								        foreach ($p->childNodes as $child) {
							 | 
						|
								            // @todo figure out if there's something we can do with tables.
							 | 
						|
								            if ($child instanceof DOMElement && $child->tagName === 'table') {
							 | 
						|
								                continue;
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            // skip references, because ugh.
							 | 
						|
								            if (preg_match('{^\s*&[a-z][a-z\.]+;\s*$}', $child->textContent)) {
							 | 
						|
								                continue;
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            $text .= $child->ownerDocument->saveXML($child);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if ($text = trim(preg_replace('{\n[ \t]+}', ' ', $text))) {
							 | 
						|
								            $paragraphs[] = $text;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return implode("\n\n", $paragraphs);
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								function format_doc($doc)
							 | 
						|
								{
							 | 
						|
								    $chunks   = array();
							 | 
						|
								
							 | 
						|
								    if (!empty($doc['description'])) {
							 | 
						|
								        $chunks[] = '<comment>Description:</comment>';
							 | 
						|
								        $chunks[] = indent_text(htmlwrap(thunk_tags($doc['description']), WRAP_WIDTH - 2));
							 | 
						|
								        $chunks[] = '';
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (!empty($doc['params'])) {
							 | 
						|
								        $chunks[] = '<comment>Param:</comment>';
							 | 
						|
								
							 | 
						|
								        $typeMax = max(array_map(function ($param) {
							 | 
						|
								            return strlen($param['type']);
							 | 
						|
								        }, $doc['params']));
							 | 
						|
								
							 | 
						|
								        $max = max(array_map(function ($param) {
							 | 
						|
								            return strlen($param['name']);
							 | 
						|
								        }, $doc['params']));
							 | 
						|
								
							 | 
						|
								        $template  = '  <info>%-' . $typeMax . 's</info>  <strong>%-' . $max . 's</strong>  %s';
							 | 
						|
								        $indent    = str_repeat(' ', $typeMax + $max + 6);
							 | 
						|
								        $wrapWidth = WRAP_WIDTH - strlen($indent);
							 | 
						|
								
							 | 
						|
								        foreach ($doc['params'] as $param) {
							 | 
						|
								            $desc = indent_text(htmlwrap(thunk_tags($param['description']), $wrapWidth), $indent, false);
							 | 
						|
								            $chunks[] = sprintf($template, $param['type'], $param['name'], $desc);
							 | 
						|
								        }
							 | 
						|
								        $chunks[] = '';
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (isset($doc['return']) || isset($doc['return_type'])) {
							 | 
						|
								        $chunks[] = '<comment>Return:</comment>';
							 | 
						|
								
							 | 
						|
								        $type   = isset($doc['return_type']) ? $doc['return_type'] : 'unknown';
							 | 
						|
								        $desc   = isset($doc['return']) ? $doc['return'] : '';
							 | 
						|
								
							 | 
						|
								        $indent    = str_repeat(' ', strlen($type) + 4);
							 | 
						|
								        $wrapWidth = WRAP_WIDTH - strlen($indent);
							 | 
						|
								
							 | 
						|
								        if (!empty($desc)) {
							 | 
						|
								            $desc = indent_text(htmlwrap(thunk_tags($doc['return']), $wrapWidth), $indent, false);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        $chunks[] = sprintf('  <info>%s</info>  %s', $type, $desc);
							 | 
						|
								        $chunks[] = '';
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    array_pop($chunks); // get rid of the trailing newline
							 | 
						|
								
							 | 
						|
								    return implode("\n", $chunks);
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								function thunk_tags($text)
							 | 
						|
								{
							 | 
						|
								    $tagMap = array(
							 | 
						|
								        'parameter>' => 'strong>',
							 | 
						|
								        'function>'  => 'strong>',
							 | 
						|
								        'literal>'   => 'return>',
							 | 
						|
								        'type>'      => 'info>',
							 | 
						|
								        'constant>'  => 'info>',
							 | 
						|
								    );
							 | 
						|
								
							 | 
						|
								    $andBack = array(
							 | 
						|
								        '&'       => '&',
							 | 
						|
								        '&true;'  => '<return>true</return>',
							 | 
						|
								        '&false;' => '<return>false</return>',
							 | 
						|
								        '&null;'  => '<return>null</return>',
							 | 
						|
								    );
							 | 
						|
								
							 | 
						|
								    return strtr(strip_tags(strtr($text, $tagMap), '<strong><return><info>'), $andBack);
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								function indent_text($text, $indent = '  ', $leading = true)
							 | 
						|
								{
							 | 
						|
								    return ($leading ? $indent : '') . str_replace("\n", "\n" . $indent, $text);
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								function find_type($xml, $paramName)
							 | 
						|
								{
							 | 
						|
								    foreach ($xml->getElementsByTagName('methodparam') as $param) {
							 | 
						|
								        if ($type = $param->getElementsByTagName('type')->item(0)) {
							 | 
						|
								            if ($parameter = $param->getElementsByTagName('parameter')->item(0)) {
							 | 
						|
								                if ($paramName === $parameter->textContent) {
							 | 
						|
								                    return $type->textContent;
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								function format_function_doc($xml)
							 | 
						|
								{
							 | 
						|
								    $doc = array();
							 | 
						|
								    $refsect1s = $xml->getElementsByTagName('refsect1');
							 | 
						|
								    foreach ($refsect1s as $refsect1) {
							 | 
						|
								        $role = $refsect1->getAttribute('role');
							 | 
						|
								        switch ($role) {
							 | 
						|
								            case 'description':
							 | 
						|
								                $doc['description'] = extract_paragraphs($refsect1);
							 | 
						|
								
							 | 
						|
								                if ($synopsis = $refsect1->getElementsByTagName('methodsynopsis')->item(0)) {
							 | 
						|
								                    foreach ($synopsis->childNodes as $node) {
							 | 
						|
								                        if ($node instanceof DOMElement && $node->tagName === 'type') {
							 | 
						|
								                            $doc['return_type'] = $node->textContent;
							 | 
						|
								                            break;
							 | 
						|
								                        }
							 | 
						|
								                    }
							 | 
						|
								                }
							 | 
						|
								                break;
							 | 
						|
								
							 | 
						|
								            case 'returnvalues':
							 | 
						|
								                // do nothing.
							 | 
						|
								                $doc['return'] = extract_paragraphs($refsect1);
							 | 
						|
								                break;
							 | 
						|
								
							 | 
						|
								            case 'parameters':
							 | 
						|
								                $params = array();
							 | 
						|
								                $vars = $refsect1->getElementsByTagName('varlistentry');
							 | 
						|
								                foreach ($vars as $var) {
							 | 
						|
								                    if ($name = $var->getElementsByTagName('parameter')->item(0)) {
							 | 
						|
								                        $params[] = array(
							 | 
						|
								                            'name'        => '$' . $name->textContent,
							 | 
						|
								                            'type'        => find_type($xml, $name->textContent),
							 | 
						|
								                            'description' => extract_paragraphs($var),
							 | 
						|
								                        );
							 | 
						|
								                    }
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                $doc['params'] = $params;
							 | 
						|
								                break;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // and the purpose
							 | 
						|
								    if ($purpose = $xml->getElementsByTagName('refpurpose')->item(0)) {
							 | 
						|
								        $desc = htmlwrap($purpose->textContent);
							 | 
						|
								        if (isset($doc['description'])) {
							 | 
						|
								            $desc .= "\n\n" . $doc['description'];
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        $doc['description'] = trim($desc);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    $ids = array();
							 | 
						|
								    foreach ($xml->getElementsByTagName('refname') as $ref) {
							 | 
						|
								        $ids[] = $ref->textContent;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return array($ids, format_doc($doc));
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								function format_class_doc($xml)
							 | 
						|
								{
							 | 
						|
								    // @todo implement this
							 | 
						|
								    return array(array(), null);
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								$dir = new RecursiveDirectoryIterator($argv[1]);
							 | 
						|
								$filter = new RecursiveCallbackFilterIterator($dir, function ($current, $key, $iterator) {
							 | 
						|
								    return $current->getFilename()[0] !== '.' &&
							 | 
						|
								        ($current->isDir() || $current->getExtension() === 'xml') &&
							 | 
						|
								        strpos($current->getFilename(), 'entities.') !== 0 &&
							 | 
						|
								        $current->getFilename() !== 'pdo_4d'; // Temporarily blacklist this one, the docs are weird.
							 | 
						|
								});
							 | 
						|
								$iterator = new RecursiveIteratorIterator($filter);
							 | 
						|
								
							 | 
						|
								$docs = array();
							 | 
						|
								foreach ($iterator as $file) {
							 | 
						|
								    $xmlstr = str_replace('&', '&', file_get_contents($file));
							 | 
						|
								
							 | 
						|
								    $xml = new DOMDocument();
							 | 
						|
								    $xml->preserveWhiteSpace = false;
							 | 
						|
								
							 | 
						|
								    if (!@$xml->loadXml($xmlstr)) {
							 | 
						|
								        echo "XML Parse Error: $file\n";
							 | 
						|
								        continue;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if ($xml->getElementsByTagName('refentry')->length !== 0) {
							 | 
						|
								        list($ids, $doc) = format_function_doc($xml);
							 | 
						|
								    } elseif ($xml->getElementsByTagName('classref')->length !== 0) {
							 | 
						|
								        list($ids, $doc) = format_class_doc($xml);
							 | 
						|
								    } else {
							 | 
						|
								        $ids = array();
							 | 
						|
								        $doc = null;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    foreach ($ids as $id) {
							 | 
						|
								        $docs[$id] = $doc;
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								if (is_file($argv[2])) {
							 | 
						|
								    unlink($argv[2]);
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								$db = new PDO('sqlite:' . $argv[2]);
							 | 
						|
								
							 | 
						|
								$db->query('CREATE TABLE php_manual (id char(256) PRIMARY KEY, doc TEXT)');
							 | 
						|
								$cmd = $db->prepare('INSERT INTO php_manual (id, doc) VALUES (?, ?)');
							 | 
						|
								foreach ($docs as $id => $doc) {
							 | 
						|
								    $cmd->execute(array($id, $doc));
							 | 
						|
								}
							 | 
						|
								
							 |