]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/BlockParser.php
More illegible hacks for the *bold* vs *list item heuristics.
[SourceForge/phpwiki.git] / lib / BlockParser.php
1 <?php rcs_id('$Id: BlockParser.php,v 1.16 2002-01-31 02:48:16 dairiki Exp $');
2 /* Copyright (C) 2002, Geoffrey T. Dairiki <dairiki@dairiki.org>
3  *
4  * This file is part of PhpWiki.
5  * 
6  * PhpWiki is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * 
11  * PhpWiki is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License
17  * along with PhpWiki; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 require_once('lib/HtmlElement.php');
21 require_once('lib/InlineParser.php');
22
23 require_once('lib/transform.php');
24 /*
25 class InlineTransform
26 extends WikiTransform {
27     function InlineTransform() {
28         global $WikiNameRegexp, $AllowedProtocols, $InterWikiLinkRegexp;
29
30         $this->WikiTransform();
31
32         // register functions
33         // functions are applied in order of registering
34
35         $this->register(WT_SIMPLE_MARKUP, 'wtm_plugin_link');
36  
37         $this->register(WT_TOKENIZER, 'wtt_doublebrackets', '\[\[');
38         //$this->register(WT_TOKENIZER, 'wtt_footnotes', '^\[\d+\]');
39         //$this->register(WT_TOKENIZER, 'wtt_footnoterefs', '\[\d+\]');
40         $this->register(WT_TOKENIZER, 'wtt_bracketlinks', '\[.+?\]');
41         $this->register(WT_TOKENIZER, 'wtt_urls',
42                         "!?\b($AllowedProtocols):[^\s<>\[\]\"'()]*[^\s<>\[\]\"'(),.?]");
43
44         if (function_exists('wtt_interwikilinks')) {
45             $this->register(WT_TOKENIZER, 'wtt_interwikilinks',
46                             pcre_fix_posix_classes("!?(?<![[:alnum:]])") .
47                             "$InterWikiLinkRegexp:[^\\s.,;?()]+");
48         }
49         $this->register(WT_TOKENIZER, 'wtt_bumpylinks', "!?$WikiNameRegexp");
50
51         $this->register(WT_SIMPLE_MARKUP, 'wtm_htmlchars');
52         $this->register(WT_SIMPLE_MARKUP, 'wtm_linebreak');
53         $this->register(WT_SIMPLE_MARKUP, 'wtm_bold_italics');
54     }
55 };
56
57 function TransformInline ($text) {
58     // The old transform code does funny things with trailing
59     // white space....
60
61     $trfm = new InlineTransform;
62     preg_match('/\s*$/', $text, $m);
63     $tail = $m[0];
64     // This "\n" -> "\r" hackage is to fool the old transform code
65     // into continuing italics across lines.
66     $in = str_replace("\n", "\r", $text);
67     $out = preg_replace('/\s*$/', '', AsXML($trfm->do_transform('', array($in))));
68     $out = str_replace("\r", "\n", $out);
69     $out .= $tail;
70
71     // DEBUGGING
72     if (false && $out != $text) {
73         echo(" IN <pre>'" . htmlspecialchars($text) . "'</pre><br>\n");
74         echo("OUT <pre>'" . htmlspecialchars($out) . "'</pre><br>\n");
75     }
76     return new RawXml($out);
77 }
78 */
79
80 ////////////////////////////////////////////////////////////////
81 //
82 //
83 define("BLOCK_NEVER_TIGHTEN", 0);
84 define("BLOCK_NOTIGHTEN_AFTER", 1);
85 define("BLOCK_NOTIGHTEN_BEFORE", 2);
86 define("BLOCK_NOTIGHTEN_EITHER", 3);
87
88 /**
89  * FIXME:
90  *  Still to do:
91  *    (old-style) tables
92  */
93
94 class BlockParser {
95     function parse (&$input, $tighten_mode = BLOCK_NEVER_TIGHTEN) {
96         $content = HTML();
97         
98         for ($block = BlockParser::_nextBlock($input); $block; $block = $nextBlock) {
99             while ($nextBlock = BlockParser::_nextBlock($input)) {
100                 // Attempt to merge current with following block.
101                 if (! $block->merge($nextBlock))
102                     break;      // can't merge
103             }
104
105             $content->pushContent($block->finish($tighten_mode));
106         }
107         return $content;
108     }
109
110     function _nextBlock (&$input) {
111         global $Block_BlockTypes;
112         
113         if ($input->atEof())
114             return false;
115         
116         foreach ($Block_BlockTypes as $type) {
117             if ($m = $input->match($type->_re)) {
118                 BlockParser::_debug('>', get_class($type), $input);
119                 
120                 $block = $type;
121                 $block->_followsBreak = $input->atBreak();
122                 if (!$block->_parse($input, $m)) {
123                     BlockParser::_debug('[', "_parse failed", $input);
124                     continue;
125                 }
126                 $block->_preceedsBreak = $input->eatSpace();
127                 BlockParser::_debug('<', get_class($type), $input);
128                 return $block;
129             }
130         }
131
132         if ($input->getDepth() == 0) {
133             // We should never get here.
134             //preg_match('/.*/A', substr($this->_text, $this->_pos), $m);// get first line
135             trigger_error("Couldn't match block: '".rawurlencode($m[0])."'", E_USER_NOTICE);
136         }
137         //FIXME:$this->_debug("no match");
138         return false;
139     }
140
141     function _debug ($tab, $msg, $input) {
142         return ;
143         
144         $tab = str_repeat($tab, $input->getDepth() + 1);
145         printXML(HTML::div("$tab $msg: at: '",
146                            HTML::tt($input->where()),
147                            "'"));
148     }
149     
150 }
151
152 class BlockParser_Match {
153     function BlockParser_Match ($match_data) {
154         $this->_m = $match_data;
155     }
156
157     function getPrefix () {
158         return $this->_m[1];
159     }
160
161     function getMatch ($n = 0) {
162         $text = $this->_m[$n + 2];
163         //if (preg_match('/\n./s', $text)) {
164             $prefix = $this->getPrefix();
165             $text = str_replace("\n$prefix", "\n", $text);
166         //}
167         return $text;
168     }
169 }
170
171     
172 class BlockParser_Input {
173
174     function BlockParser_Input ($text) {
175         $this->_text = $text;
176         $this->_pos = 0;
177         $this->_depth = 0;
178         
179         // Expand leading tabs.
180         // FIXME: do this better.
181         //
182         // We want to ensure the only characters matching \s are ' ' and "\n".
183         //
184         $this->_text = preg_replace('/(?![ \n])\s/', ' ', $this->_text);
185         assert(!preg_match('/(?![ \n])\s/', $this->_text));
186         if (!preg_match('/\n$/', $this->_text))
187             $this->_text .= "\n";
188
189         $this->_set_prefix ('');
190         $this->_atBreak = false;
191         $this->eatSpace();
192     }
193
194     function _set_prefix ($prefix, $next_prefix = false) {
195         if ($next_prefix === false)
196             $next_prefix = $prefix;
197
198         $this->_prefix = $prefix;
199         $this->_next_prefix = $next_prefix;
200
201         $this->_regexp_cache = array();
202
203         $blank = "(:?$prefix)?\s*\n";
204         $this->_blank_pat = "/$blank/A";
205         $this->_eof_pat = "/\\Z|(?!$blank|${prefix}.)/A";
206     }
207
208     function atEof () {
209         return preg_match($this->_eof_pat, substr($this->_text, $this->_pos));
210     }
211
212     function match ($regexp) {
213         $cache = &$this->_regexp_cache;
214         if (!isset($cache[$regexp])) {
215             // Fix up any '^'s in pattern (add our prefix)
216             $re = preg_replace('/(?<! [ [ \\\\ ]) \^ /x',
217                                '^' . $this->_next_prefix, $regexp);
218
219             // Fix any match  backreferences (like '\1').
220             $re = preg_replace('/(?<= [^ \\\\ ] [ \\\\ ] )( \\d+ )/ex', "'\\1' + 2", $re);
221
222             $re = "/(" . $this->_prefix . ")($re)/Am";
223             $cache[$regexp] = $re;
224         }
225         else
226             $re = $cache[$regexp];
227         
228         if (preg_match($re, substr($this->_text, $this->_pos), $m)) {
229             return new BlockParser_Match($m);
230         }
231         return false;
232     }
233
234     function accept ($match) {
235         $text = $match->_m[0];
236
237         assert(substr($this->_text, $this->_pos, strlen($text)) == $text);
238         $this->_pos += strlen($text);
239
240         // FIXME:
241         assert(preg_match("/\n$/", $text));
242             
243         if ($this->_next_prefix != $this->_prefix)
244             $this->_set_prefix($this->_next_prefix);
245
246         $this->_atBreak = false;
247         $this->eatSpace();
248     }
249     
250     /**
251      * Consume blank lines.
252      *
253      * @return bool True if any blank lines where comsumed.
254      */
255     function eatSpace () {
256         if (preg_match($this->_blank_pat, substr($this->_text, $this->_pos), $m)) {
257             $this->_pos += strlen($m[0]);
258             if ($this->_next_prefix != $this->_prefix)
259                 $this->_set_prefix($this->_next_prefix);
260             $this->_atBreak = true;
261
262             while (preg_match($this->_blank_pat, substr($this->_text, $this->_pos), $m)) {
263                 $this->_pos += strlen($m[0]);
264             }
265         }
266
267         return $this->_atBreak;
268     }
269     
270     function atBreak () {
271         return $this->_atBreak;
272     }
273
274     function getDepth () {
275         return $this->_depth;
276     }
277
278     // DEBUGGING
279     function where () {
280         if (($m = $this->match('.*\n')))
281             return sprintf('[%s]%s', $m->getPrefix(), $m->getMatch());
282         return '???';
283     }
284     
285     function subBlock ($initial_prefix, $subsequent_prefix = false) {
286         if ($subsequent_prefix === false)
287             $subsequent_prefix = $initial_prefix;
288         
289         return new BlockParser_InputSubBlock ($this, $initial_prefix, $subsequent_prefix);
290     }
291 }
292
293 class BlockParser_InputSubBlock extends BlockParser_Input
294 {
295     function BlockParser_InputSubBlock (&$block, $initial_prefix, $subsequent_prefix) {
296         $this->_text = &$block->_text;
297         $this->_pos = &$block->_pos;
298         $this->_atBreak = &$block->_atBreak;
299
300         $this->_depth = $block->_depth + 1;
301
302         $this->_set_prefix($block->_prefix . $initial_prefix,
303                            $block->_next_prefix . $subsequent_prefix);
304     }
305 }
306
307     
308
309 class Block {
310     var $_tag;
311     var $_attr = false;
312     var $_re;
313     var $_followsBreak = false;
314     var $_preceedsBreak = false;
315     var $_content = array();
316
317         
318     function _parse (&$input, $match) {
319         trigger_error('pure virtual', E_USER_ERROR);
320     }
321
322     function _pushContent ($c) {
323         if (!is_array($c))
324             $c = func_get_args();
325         foreach ($c as $x)
326             $this->_content[] = $x;
327     }
328
329     function isTerminal () {
330         return true;
331     }
332     
333     function merge ($followingBlock) {
334         return false;
335     }
336
337     function finish (/*$tighten*/) {
338         return new HtmlElement($this->_tag, $this->_attr, $this->_content);
339     }
340 }
341
342
343 class CompoundBlock extends Block
344 {
345     function isTerminal () {
346         return false;
347     }
348 }
349
350
351 class Block_blockquote extends CompoundBlock
352 {
353     var $_tag ='blockquote';
354     var $_depth;
355     var $_re = '\ +(?=\S)';
356     
357     function _parse (&$input, $m) {
358         $indent = $m->getMatch();
359         $this->_depth = strlen($indent);
360         $this->_content[] = BlockParser::parse($input->subBlock($indent),
361                                                BLOCK_NOTIGHTEN_EITHER);
362         return true;
363     }
364
365     function merge ($nextBlock) {
366         if (get_class($nextBlock) != 'block_blockquote')
367             return false;
368         assert ($nextBlock->_depth < $this->_depth);
369         
370         $content = $nextBlock->_content;
371         array_unshift($content, $this->finish());
372         $this->_content = $content;
373         return true;
374     }
375 }
376
377 class Block_list extends CompoundBlock
378 {
379     //var $_tag = 'ol' or 'ul';
380     var $_re = '\ {0,4}([+#]|-(?!-)|[o](?=\ )|[*](?!\S[^*]*(?<=\S)[*](?!\S)))\ *(?=\S)';
381
382     function _parse (&$input, $m) {
383         // A list as the first content in a list is not allowed.
384         // E.g.:
385         //   *  * Item
386         // Should markup as <ul><li>* Item</li></ul>,
387         // not <ul><li><ul><li>Item</li></ul>/li></ul>.
388         //
389         if (preg_match('/[-*o+#;]\s*$/', $m->getPrefix()))
390             return false;
391         
392         $prefix = $m->getMatch();
393         $leader = preg_quote($prefix, '/');
394         $indent = sprintf("\\ {%d}", strlen($prefix));
395
396         $bullet = $m->getMatch(1);
397         $this->_tag = $bullet == '#' ? 'ol' : 'ul';
398         
399         $text = $input->subBlock($leader, $indent);
400         $content = BlockParser::parse($text, BLOCK_NOTIGHTEN_AFTER);
401         $this->_pushContent(HTML::li(false, $content));
402         return true;
403     }
404     
405     function merge ($nextBlock) {
406         if (!isa($nextBlock, 'Block_list') || $this->_tag != $nextBlock->_tag)
407             return false;
408
409         $this->_pushContent($nextBlock->_content);
410         return true;
411     }
412 }
413
414 class Block_dl extends Block_list
415 {
416     var $_tag = 'dl';
417     var $_re = '(\ {0,4})([^\s!].*):\s*?\n(?=(?:\s*^)+(\1\ +)\S)';
418     //          1-------12--------2                   3-----3
419
420     function _parse (&$input, $m) {
421         $term = TransformInline(rtrim($m->getMatch(2)));
422         $indent = $m->getMatch(3);
423
424         $input->accept($m);
425         
426         $this->_pushContent(HTML::dt(false, $term),
427                             HTML::dd(false,
428                                      BlockParser::parse($input->subBlock($indent),
429                                                         BLOCK_NOTIGHTEN_AFTER)));
430         return true;
431     }
432 }
433
434
435
436 class Block_table_dl_defn extends XmlContent
437 {
438     var $nrows;
439     var $ncols;
440     
441     function Block_table_dl_defn ($term, $defn) {
442         $this->XmlContent();
443         if (!is_array($defn))
444             $defn = $defn->getContent();
445
446         $this->_ncols = $this->_ComputeNcols($defn);
447         
448         $this->_nrows = 0;
449         foreach ($defn as $item) {
450             if ($this->_IsASubtable($item))
451                 $this->_addSubtable($item);
452             else
453                 $this->_addToRow($item);
454         }
455         $this->_flushRow();
456
457         $th = HTML::th($term);
458         if ($this->_nrows > 1)
459             $th->setAttr('rowspan', $this->_nrows);
460         $this->_setTerm($th);
461     }
462
463     function _addToRow ($item) {
464         if (empty($this->_accum)) {
465             $this->_accum = HTML::td();
466             if ($this->_ncols > 2)
467                 $this->_accum->setAttr('colspan', $this->_ncols - 1);
468         }
469         $this->_accum->pushContent($item);
470     }
471
472     function _flushRow () {
473         if (!empty($this->_accum)) {
474             $this->pushContent(HTML::tr($this->_accum));
475             $this->_accum = false;
476             $this->_nrows++;
477         }
478     }
479
480     function _addSubtable ($table) {
481         $this->_flushRow();
482         foreach ($table->getContent() as $subdef) {
483             $this->pushContent($subdef);
484             $this->_nrows += $subdef->nrows();
485         }
486     }
487
488     function _setTerm ($th) {
489         $first_row = &$this->_content[0];
490         if (isa($first_row, 'Block_table_dl_defn'))
491             $first_row->_setTerm($th);
492         else
493             $first_row->unshiftContent($th);
494     }
495     
496     function _ComputeNcols ($defn) {
497         $ncols = 2;
498         foreach ($defn as $item) {
499             if ($this->_IsASubtable($item)) {
500                 $row = $this->_FirstDefn($item);
501                 $ncols = max($ncols, $row->ncols() + 1);
502             }
503         }
504         return $ncols;
505     }
506
507     function _IsASubtable ($item) {
508         return isa($item, 'HtmlElement')
509             && $item->getTag() == 'table'
510             && $item->getAttr('class') == 'wiki-dl-table';
511     }
512
513     function _FirstDefn ($subtable) {
514         $defs = $subtable->getContent();
515         return $defs[0];
516     }
517
518     function ncols () {
519         return $this->_ncols;
520     }
521
522     function nrows () {
523         return $this->_nrows;
524     }
525
526     function setWidth ($ncols) {
527         assert($ncols >= $this->_ncols);
528         if ($ncols <= $this->_ncols)
529             return;
530         $rows = &$this->_content;
531         for ($i = 0; $i < count($rows); $i++) {
532             $row = &$rows[$i];
533             if (isa($row, 'Block_table_dl_defn'))
534                 $row->setWidth($ncols - 1);
535             else {
536                 $n = count($row->_content);
537                 $lastcol = &$row->_content[$n - 1];
538                 $lastcol->setAttr('colspan', $ncols - 1);
539             }
540         }
541     }
542 }
543
544 class Block_table_dl extends Block_list
545 {
546     var $_tag = 'table';
547     var $_attr = array('class' => 'wiki-dl-table',
548                        'border' => 2, // FIXME: CSS?
549                        'cellspacing' => 0,
550                        'cellpadding' => 6);
551     
552
553     var $_re = '(\ {0,4})((?![\s!]).*)?[|]\s*?\n(?=(?:\s*^)+(\1\ +)\S)';
554     //          1-------12-----------2                      3-----3
555
556     function _parse (&$input, $m) {
557         $term = TransformInline(rtrim($m->getMatch(2)));
558         $indent = $m->getMatch(3);
559
560         $input->accept($m);
561         $defn = BlockParser::parse($input->subBlock($indent),
562                                    BLOCK_NOTIGHTEN_AFTER);
563
564         $this->_pushContent(new Block_table_dl_defn($term, $defn));
565         return true;
566     }
567             
568     function finish () {
569         $defs = &$this->_content;
570
571         $ncols = 0;
572         foreach ($defs as $defn)
573             $ncols = max($ncols, $defn->ncols());
574         foreach ($defs as $key => $defn)
575             $defs[$key]->setWidth($ncols);
576
577         return parent::finish();
578     }
579 }
580
581 class Block_oldlists extends Block_list
582 {
583     //var $_tag = 'ol', 'ul', or 'dl';
584     var $_re = '(?:([*](?!\S[^*]*(?<=\S)[*](?!\S))|[#])|;(.*):).*?(?=\S)';
585     //             1------------------------------1  2--2
586     
587     function _parse (&$input, $m) {
588         if (!preg_match('/[*#;]*$/A', $m->getPrefix()))
589             return false;
590
591         $prefix = $m->getMatch();
592
593         $leader = preg_quote($prefix, '/');
594
595         $oldindent = '[*#;](?=[#*]|;.*:.*?\S)';
596         $newindent = sprintf('\\ {%d}', strlen($prefix));
597         $indent = "(?:$oldindent|$newindent)";
598
599         $bullet = $m->getMatch(1);
600         if ($bullet) {
601             $this->_tag = $bullet == '*' ? 'ul' : 'ol';
602             $item = HTML::li();
603         }
604         else {
605             $this->_tag = 'dl';
606             $term = trim($m->getMatch(2));
607             if ($term)
608                 $this->_pushContent(HTML::dt(false, TransformInline($term)));
609             $item = HTML::dd();
610         }
611         
612         $item->pushContent(BlockParser::parse($input->subBlock($leader, $indent),
613                                               BLOCK_NOTIGHTEN_AFTER));
614         $this->_pushContent($item);
615         return true;
616     }
617 }
618
619 class Block_pre extends Block
620 {
621     var $_tag = 'pre';
622     var $_re = '<(pre|verbatim)>(.*?(?:\s*\n^.*?)*?)(?<!~)<\/\1>\s*?\n';
623     //           1------------1 2------------------2
624
625     function _parse (&$input, $m) {
626         $input->accept($m);
627
628         $text = $m->getMatch(2);
629         $tag = $m->getMatch(1);
630
631         if ($tag == 'pre')
632             $text = TransformInline($text);
633
634         $this->_pushContent($text);
635         return true;
636     }
637 }
638
639 class Block_plugin extends Block
640 {
641     var $_tag = 'div';
642     var $_attr = array('class' => 'plugin');
643     var $_re = '<\?plugin(?:-form)?.*?(?:\n^.*?)*?(?<!~)\?>\s*?\n';
644
645     function _parse (&$input, $m) {
646         global $request;
647         $loader = new WikiPluginLoader;
648         $input->accept($m);
649         $this->_pushContent($loader->expandPI($m->getMatch(), $request));
650         return true;
651     }
652 }
653
654 class Block_hr extends Block
655 {
656     var $_tag = 'hr';
657     var $_re = '-{4,}\s*?\n';
658
659     function _parse (&$input, $m) {
660         $input->accept($m);
661         return true;
662     }
663 }
664
665 class Block_heading extends Block
666 {
667     var $_re = '(!{1,3})(.*)\n';
668     
669     function _parse (&$input, $m) {
670         $input->accept($m);
671         $this->_tag = "h" . (5 - strlen($m->getMatch(1)));
672         $this->_pushContent(TransformInline(trim($m->getMatch(2))));
673         return true;
674     }
675 }
676
677 class Block_p extends Block
678 {
679     var $_tag = 'p';
680     var $_re = '\S.*\n';
681
682     function _parse (&$input, $m) {
683         $this->_text = $m->getMatch();
684         $input->accept($m);
685         return true;
686     }
687     
688     function merge ($nextBlock) {
689         if ($this->_preceedsBreak || get_class($nextBlock) != 'block_p')
690             return false;
691
692         $this->_text .= $nextBlock->_text;
693         $this->_preceedsBreak = $nextBlock->_preceedsBreak;
694         return true;
695     }
696             
697     function finish ($tighten) {
698         $this->_pushContent(TransformInline(trim($this->_text)));
699         
700         if ($this->_followsBreak && ($tighten & BLOCK_NOTIGHTEN_AFTER) != 0)
701             $tighten = 0;
702         elseif ($this->_preceedsBreak && ($tighten & BLOCK_NOTIGHTEN_BEFORE) != 0)
703             $tighten = 0;
704
705         return $tighten ? $this->_content : parent::finish();
706     }
707 }
708
709 class Block_email_blockquote extends CompoundBlock
710 {
711     // FIXME: move CSS to CSS.
712     var $_tag ='blockquote';
713     var $_attr = array('style' => 'border-left-width: medium; border-left-color: #0f0; border-left-style: ridge; padding-left: 1em; margin-left: 0em; margin-right: 0em;');
714     var $_depth;
715     var $_re = '>\ ?';
716     
717     function _parse (&$input, $m) {
718         $prefix = $m->getMatch();
719         $indent = "(?:$prefix|>(?=\s*?\n))";
720         $this->_content[] = BlockParser::parse($input->subBlock($indent),
721                                                BLOCK_NOTIGHTEN_EITHER);
722         return true;
723     }
724 }
725
726 ////////////////////////////////////////////////////////////////
727 //
728
729
730
731 $GLOBALS['Block_BlockTypes'] = array(new Block_oldlists,
732                                      new Block_list,
733                                      new Block_dl,
734                                      new Block_table_dl,
735                                      new Block_blockquote,
736                                      new Block_heading,
737                                      new Block_hr,
738                                      new Block_pre,
739                                      new Block_email_blockquote,
740                                      new Block_plugin,
741                                      new Block_p);
742
743 // FIXME: This is temporary, too...
744 function NewTransform ($text) {
745
746     //set_time_limit(2);
747     
748     // Expand leading tabs.
749     // FIXME: do this better. also move  it...
750     $text = preg_replace('/^\ *[^\ \S\n][^\S\n]*/me', "str_repeat(' ', strlen('\\0'))", $text);
751     assert(!preg_match('/^\ *\t/', $text));
752
753     $input = new BlockParser_Input($text);
754     return BlockParser::parse($input);
755 }
756
757
758 // FIXME: bad name
759 function TransformRevision ($revision) {
760     if ($revision->get('markup') == 'new') {
761         return NewTransform($revision->getPackedContent());
762     }
763     else {
764         return do_transform($revision->getContent());
765     }
766 }
767
768
769 // (c-file-style: "gnu")
770 // Local Variables:
771 // mode: php
772 // tab-width: 8
773 // c-basic-offset: 4
774 // c-hanging-comment-ender-p: nil
775 // indent-tabs-mode: nil
776 // End:   
777 ?>