Ejemplo n.º 1
0
function parse_indents($text)
{
    global $MaxNesting;
    static $last_prefix = '';
    // Last line's prefix.
    static $steal = '';
    // Stealing the next line?
    // Locate the indent prefix characters.
    preg_match('/^([:\\*#]*)(;([^:]*):)?(.*\\n?$)/', $text, $result);
    if ($result[2] != '') {
        $result[1] = $result[1] . ';';
    }
    // No list on last line, no list on this line.  Bail out:
    if ($steal == '' && $last_prefix == '' && $result[1] == '') {
        return $text;
    }
    // Common case fast.
    // Remember lengths of strings.
    $last_len = strlen($last_prefix);
    $prefix_len = strlen($result[1]);
    if ($steal == '') {
        $text = $result[4];
        $fixup = '';
        // Loop through and look for prefix characters in common with the
        // previous line.
        for ($i = 0; $i < $MaxNesting && ($i < $last_len || $i < $prefix_len); $i++) {
            // If equal, continue.
            if ($i < $last_len && $i < $prefix_len && $last_prefix[$i] == $result[1][$i]) {
                continue;
            }
            // If we've gone deeper than the previous line, we're done.
            if ($i >= $last_len) {
                break;
            }
            // If last line goes further than us, end its dangling lists.
            if ($i >= $prefix_len || $last_prefix[$i] != $result[1][$i]) {
                for ($j = $i; $j < $MaxNesting && $j < $last_len; $j++) {
                    $fixup = entity_listitem($last_prefix[$j], 'end') . entity_list($last_prefix[$j], 'end') . $fixup;
                }
                break;
            }
        }
        // End the preceding line's list item if we're starting another one
        // at the same level.
        if ($i > 0 && $i >= $prefix_len) {
            $fixup = $fixup . entity_listitem($last_prefix[$i - 1], 'end');
        }
        // Start fresh new lists for this line as needed.
        // We start all but the last one as *indents* (definition lists)
        // instead of what they really may appear as, since their function is
        // really just to indent.
        for (; $i < $MaxNesting - 1 && $i + 1 < $prefix_len; $i++) {
            $result[1][$i] = ':';
            // Pretend to be an indent.
            $fixup = $fixup . entity_list(':', 'start') . entity_listitem(':', 'start');
        }
        if ($i < $prefix_len) {
            $fixup = $fixup . entity_list($result[1][$i], 'start');
        }
        // Start the list *item*.
        if ($result[2] != '') {
            $fixup = $fixup . new_entity(array('term_item_start')) . $result[3] . new_entity(array('term_item_end'));
        }
        if ($result[1] != '') {
            $text = entity_listitem(substr($result[1], -1), 'start') . $text;
        }
        $text = $fixup . $text;
        $last_prefix = $result[1];
    }
    if ($steal != '' || $result[1] != '') {
        // Check if a previous line used a trailing '\' to "steal" us;
        // i.e., to insert a new line while continuing with the same list item.
        if ($steal == '') {
            $steal = substr($result[1], -1);
        }
        // Check if *we* have a trailing '\' to "steal" the next line.  If not,
        // end ourselves right here.
        if (preg_match('/(^|[^\\\\])(\\\\\\\\)*\\\\$/', $text)) {
            $text = preg_replace('/\\\\$/', "\n", $text);
        } else {
            $text = str_replace("\n", '', $text);
            $steal = '';
        }
    }
    return $text;
}
Ejemplo n.º 2
0
function view_macro_titlesearch($args)
{
    // Description of TitleSearch macro:
    //   [[TitleSearch {options} search-pattern]]
    // This macro searches for page-titles matching the searchpattern,
    // and presents it according to options. The pattern may include
    // ^ or $ to lock it against start or end, and otherwise it must
    // only contain alpha-characters (or '/'). The special pattern '*'
    // matches every title.
    //
    // Legal options, capitalized unique prefix:
    //   Class      : Sets the class of the list used for results
    //   STyle      : Sets the style attribute
    //   Delimiter  : Choose delimiter between text entries
    //   Index      : Divides the list according to first character,
    //                or first character after value of option
    //   Oneline/List : Indicates to use line/list-markup
    //
    // Examples:  [[TitleSearch Pages$]]
    //            [[TitleSearch *]]
    //            [[TitleSearch {c=prelist} ^Tavi]]
    //            [[TitleSearch {i=5} ^Tavi]]
    global $pagestore, $AlphaPtn;
    // Check for CurlyOptions, and split them
    preg_match("/^(?:\\s*{([^]]*)})?\\s*(.*)\$/", $args, $arg);
    $options = split(',', $arg[1]);
    $search = $arg[2];
    // Some defaults
    $useDelim = '';
    // Empty delimiter at the start, changed by options
    // Parse options
    foreach ($options as $opt) {
        list($name, $value) = split('=', $opt);
        $name = strtolower($name);
        if (preg_match("/^st/", $name)) {
            // STyle - Adds a style-attribute
            $style = $value;
            $listAttr = "style=\"{$value}\" ";
        } else {
            if ($name[0] == 'c') {
                // Class - Adds a class-attribute
                $listAttr = "class=\"{$value}\" ";
                if ($value == "prelist") {
                    $useDelim = '';
                }
            } else {
                if ($name[0] == 'd') {
                    // Delimiter - Changes the delimiter used
                    $useDelim = $value;
                } else {
                    if ($name[0] == 'o') {
                        // Oneline - use line-markup
                        $useList = false;
                    } else {
                        if ($name[0] == 'l') {
                            // List - use list-markup
                            $useList = true;
                        } else {
                            if ($name[0] == 'i') {
                                // Index - Use heading to divide index
                                $showIndex = true;
                                $level = 2;
                                if (is_numeric($value)) {
                                    $indexCharNo = $value - 1;
                                } else {
                                    $indexCharNo = 0;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    // Check for illegal characters to make search pattern safer against exploits
    if ($search == '*') {
        // Match every title
        $pattern = ".";
    } else {
        if (!preg_match("/^\\^?(\\/|{$AlphaPtn})+\\\$?\$/", $search)) {
            // Search can be locked at ^start and/or end$, and elsewise only
            // contain Alpha-characters, digits not included
            return "[[TitleSearch {$args}]]";
        } else {
            // $search validates, so use as is
            $pattern = $search;
        }
    }
    if (!isset($useList) or !$useList) {
        $useList = false;
        $useDelim = $useDelim ? $useDelim : ', ';
    }
    if ($showIndex) {
        $lastIndexChar = '';
    } else {
        if ($useList) {
            $text = entity_list("*", 'start', $listAttr);
        }
    }
    // Loop through all pagetitles
    $list = $pagestore->allpages();
    foreach ($list as $page) {
        if (preg_match("|{$pattern}|", $page[1])) {
            if ($showIndex && $lastIndexChar != $page[1][$indexCharNo]) {
                if ($lastIndexChar != '') {
                    // End previous list
                    if ($useDelim) {
                        $text = preg_replace("/" . preg_quote($useDelim) . "\$/", "\n", $text);
                    }
                    if ($useList) {
                        $text .= entity_list("*", "end");
                    }
                }
                // Add index-header
                $text .= new_entity(array('head_start', $level)) . substr($page[1], 0, $indexCharNo + 1) . new_entity(array('head_end', $level));
                if ($useList) {
                    // Start list again
                    $text .= entity_list("*", 'start', $listAttr);
                }
                $lastIndexChar = $page[1][$indexCharNo];
            }
            if ($useList) {
                $text .= entity_listitem("*", "start");
            }
            $text .= sprintf("%s" . $useDelim, html_ref($page[1], $page[1]));
        }
    }
    if ($useDelim) {
        $text = preg_replace("/" . preg_quote($useDelim) . "\$/", "\n", $text);
    }
    if ($useList) {
        $text .= entity_list("*", "end");
    }
    return parse_elements($text);
}
Ejemplo n.º 3
0
function parse_indents($text)
{
    global $MaxNesting;
    static $indentPrevLevel = -1;
    static $indentPrefixString = '';
    static $indentPrevLineIsBlank = 0;
    static $indentStealLine = 0;
    static $pending_p = '';
    // Indentation increase of more than on level will be corrected to only one.
    $auto_fix_indent_leap = 1;
    // this value is boolean
    // Fix notation for ordered list, changes:
    //  - '[0-9].' to '#'
    //  - '[a-z].' to INDENTS_TYPE_A, i.e. ascii 182 (266 in octal)
    //  - 'ii.' to INDENTS_TYPE_I, i.e. ascii 187 (273 in octal)
    $text = preg_replace('/^(\\s*)[0-9]{1,2}\\.(.+\\n?$)/', '\\1#\\2', $text);
    $text = preg_replace('/^(\\s*)[a-z]\\.(.+\\n?$)/', '\\1' . INDENTS_TYPE_A . '\\2', $text);
    $text = preg_replace('/^(\\s*)ii\\.(.+\\n?$)/', '\\1' . INDENTS_TYPE_I . '\\2', $text);
    // Fix notation for citation
    $cite_pattern = '^(\\s*>)+';
    if (preg_match("/{$cite_pattern}/", $text, $matches)) {
        $auto_fix_indent_leap = 0;
        $cite_blank_line = preg_match("/{$cite_pattern}\\s*\$/", $text);
        $cite_level = preg_match_all('/>/', $matches[0], $dummy);
        $text = preg_replace("/{$cite_pattern}/", str_repeat(' ', $cite_level - 1) . '>', $text);
        if ($cite_blank_line) {
            $text = preg_replace('/^(.*)$/', '\\1<p>', $text);
        }
    }
    // Locate the indent prefix characters.
    $matched = preg_match('/^(\\s*)([:\\-\\*#>\\266\\273])([^:\\-\\*#>].*\\n?)$/', $text, $result);
    if (!$matched) {
        preg_match('/^(\\s*)(:)(-.*\\n?)$/', $text, $result);
    }
    if (array_key_exists(1, $result) && isset($result[1])) {
        $indentSpaces = $result[1];
    }
    if (array_key_exists(2, $result) && isset($result[2])) {
        $indentChar = $result[2];
    }
    if (array_key_exists(3, $result) && isset($result[3])) {
        $indentText = $result[3];
    }
    // No list on last line, no list on this line. Bail out:
    if ($indentPrevLevel == -1 && !isset($indentChar) && !$indentStealLine) {
        return $text;
    }
    // Common case fast.
    $isBlankLine = trim($text) == '' ? 1 : 0;
    if (!$indentStealLine) {
        if (isset($indentChar)) {
            if ($auto_fix_indent_leap) {
                $indentCurLevel = min($indentPrevLevel + 1, strlen($indentSpaces), $MaxNesting);
            } else {
                $indentCurLevel = min(strlen($indentSpaces), $MaxNesting);
            }
            $fixup = '';
            if ($indentCurLevel > $indentPrevLevel) {
                // add any pending <p>
                $fixup .= $pending_p;
                $pending_p = '';
                if ($auto_fix_indent_leap) {
                    $fixup .= entity_list($indentChar, 'start');
                } else {
                    $fixup .= str_repeat(entity_list($indentChar, 'start'), $indentCurLevel - $indentPrevLevel);
                }
            } else {
                // close previously openend levels, until current level
                for ($i = $indentPrevLevel; $i > $indentCurLevel; $i--) {
                    $fixup .= entity_listitem($indentPrefixString[$i], 'end') . entity_list($indentPrefixString[$i], 'end');
                }
                // close previous list item
                $fixup .= entity_listitem($indentPrefixString[$indentCurLevel], 'end');
                // if the indent type ([:#-*]) is different from previous at same level
                if ($indentPrefixString[$indentCurLevel] != $indentChar) {
                    $fixup .= entity_list($indentPrefixString[$indentCurLevel], 'end');
                }
                // add any pending <p>
                $fixup .= $pending_p;
                $pending_p = '';
                // if the indent type ([:#-*]) is different from previous at same level
                if ($indentPrefixString[$indentCurLevel] != $indentChar) {
                    $fixup .= entity_list($indentChar, 'start');
                }
            }
            // open new list item
            $fixup .= entity_listitem($indentChar, 'start');
            $text = $fixup . $indentText;
            if ($auto_fix_indent_leap || $indentCurLevel <= $indentPrevLevel) {
                $indentPrefixString = substr($indentPrefixString, 0, $indentCurLevel) . $indentChar;
            } else {
                $indentPrefixString = substr($indentPrefixString, 0, $indentPrevLevel + 1) . str_repeat($indentChar, $indentCurLevel - $indentPrevLevel);
            }
            $indentPrevLevel = $indentCurLevel;
        } else {
            // Note: Every parsing functions is called at the end of the page with
            // an empty string, i.e. without a carriage return, since some stateful
            // parsers need to perform final processing. This is the case for
            // indents and this is why $text is tested against ''.
            if ($isBlankLine && $text != '') {
                $text = $indentPrevLineIsBlank ? '' : '<p>';
            } else {
                if ($indentPrevLineIsBlank || $text == '') {
                    // Check if there's leading spaces, telling to stay in the same
                    // list item but to start a new paragraph.
                    // If no leading spaces, the indents are completely closed.
                    $i = 0;
                    // just in case...
                    if (preg_match('/^\\s*/', $text, $leadingSpaces)) {
                        $i = strlen($leadingSpaces[0]);
                    }
                    if ($i < strlen($indentPrefixString)) {
                        // We're at a lower nesting level, end dangling lists up
                        // to the nesting level specified by the leading spaces
                        // and add any pending <p> after the last list end.
                        for ($j = $i; $j < strlen($indentPrefixString); $j++) {
                            $text = entity_listitem($indentPrefixString[$j], 'end') . entity_list($indentPrefixString[$j], 'end') . $pending_p . $text;
                            $pending_p = '';
                        }
                        $indentPrefixString = substr($indentPrefixString, 0, $i);
                        $indentPrevLevel = $i - 1;
                    } else {
                        // $indentChar is set here to keep the line stealing working
                        $indentChar = ' ';
                        $text = $pending_p . $text;
                        $pending_p = '';
                    }
                } else {
                    $text = ' ' . trim($text);
                    $indentChar = ' ';
                    // same as above
                }
            }
        }
    }
    $indentPrevLineIsBlank = $isBlankLine;
    // Check if *we* have a trailing '\' to "steal" the next line.
    if (isset($indentChar) || isset($indentStealLine)) {
        if (preg_match('/(^|[^\\\\])(\\\\\\\\)*\\\\$/', $text)) {
            $text = preg_replace('/\\\\$/', "\n", $text);
            $indentStealLine = 1;
        } else {
            $indentStealLine = 0;
        }
    }
    // holds any single <p> and prints it later, see above
    if ($text == '<p>') {
        $pending_p = $text;
        $text = '';
    }
    return $text;
}