diff options
-rw-r--r-- | src/BBCodeParser.php | 62 | ||||
-rw-r--r-- | test/unbbcodeTest.php | 54 |
2 files changed, 42 insertions, 74 deletions
diff --git a/src/BBCodeParser.php b/src/BBCodeParser.php index 0131dde..9c7be2c 100644 --- a/src/BBCodeParser.php +++ b/src/BBCodeParser.php @@ -3,9 +3,10 @@ class BBCodeParser { const TEXT = 0; - const CTAG = 1; - const OTAG = 2; - const DONE = 3; + const WHSP = 1; + const CTAG = 2; + const OTAG = 3; + const DONE = 4; function parse($in, $uid) { # decode HTML entities before parsing @@ -58,13 +59,18 @@ class BBCodeParser { } break; + case self::WHSP: + while ($in[$i] == "\n" || $in[$i] == "\t" || $in[$i] == ' ') ++$i; + $state = self::TEXT; + break; + case self::OTAG: # split tag into tag name and argument, if any - $arg = false; - $epos = strpos($tag, '='); - if ($epos !== false) { - $tag = substr($tag, 0, $epos); - $arg = substr($tag, $epos+1); + if (strpos($tag, '=') !== false) { + list($tag, $arg) = explode('=', $tag, 2); + } + else { + $arg = false; } $arg_stack[] = $arg; @@ -72,69 +78,76 @@ class BBCodeParser { switch ($tag) { case 'b': $out .= '__'; + $state = self::TEXT; break; case 'u': case 'i': $out .= '_'; + $state = self::TEXT; break; case 'url': case 'email': # nothing to do on opening + $state = self::TEXT; break; case 'quote': $text_stack[] = $out . "\n"; $out = ''; + $state = self::TEXT; break; case 'code': $out .= "\n"; + $state = self::TEXT; break; case 'list': - + if ($out[strlen($out)-1] != "\n") $out .= "\n"; + switch ($arg) { case '1': $list_counter_stack[] = 1; break; case 'a': $list_counter_stack[] = 'a'; break; default: $list_counter_stack[] = '*'; break; } + $state = self::WHSP; break; case '*': + if ($out[strlen($out)-1] != "\n") $out .= "\n"; $out .= str_repeat(' ', 2*count($list_counter_stack)); $c = array_pop($list_counter_stack); if (is_int($c)) { - $out .= $c . '.'; + $out .= $c . '. '; $list_counter_stack[] = $c + 1; } else if ($c == '*') { - $out .= $c; + $out .= $c . ' '; $list_counter_stack[] = '*'; } else { - $out .= $c . '.'; + $out .= $c . '. '; $list_counter_stack[] = chr(ord($c)+1); } - if ($in[$i] != ' ') { - # add space after item label only if there is not one already - $out .= ' '; - } + $state = self::WHSP; break; case 'img': $text_stack[] = $out; $out = ''; + $state = self::TEXT; break; case 'attachment': # TODO: unimplemented + $state = self::TEXT; break; case 'color': case 'size': # ignored + $state = self::TEXT; break; default: throw new Exception('Unrecognized open tag: ' . $tag); } - $state = self::TEXT; break; case self::CTAG: @@ -143,10 +156,12 @@ class BBCodeParser { switch ($tag) { case 'b': $out .= '__'; + $state = self::TEXT; break; case 'u': case 'i': $out .= '_'; + $state = self::TEXT; break; case 'url': case 'email': @@ -156,6 +171,7 @@ class BBCodeParser { $out .= '[' . $fn_number++ .']'; $fn[] = $arg; } + $state = self::TEXT; break; case 'quote': $level = count($text_stack); @@ -163,38 +179,44 @@ class BBCodeParser { $out = str_replace("\n", "\n> ", $out); $out = '> ' . $out; $out = array_pop($text_stack) . $out . "\n"; + $state = self::TEXT; break; case 'code': # TODO: untested # FIXME: don't wordwrap code! $out .= "\n"; + $state = self::TEXT; break; case 'list': case 'list:o': case 'list:u': -# TODO: untested array_pop($list_counter_stack); + $out .= "\n\n"; + $state = self::WHSP; break; case '*': case '*:m': -# TODO: untested + if ($out[strlen($out)-1] == "\n") $out = substr($out, 0, -1); + $state = self::WHSP; break; case 'img': # TODO: untested $fn[] = $out; $out = array_pop($text_stack) . '[' . $fn_number++ . ']'; + $state = self::TEXT; break; case 'attachment': + $state = self::TEXT; break; case 'color': case 'size': # ignored + $state = self::TEXT; break; default: throw new Exception('Unrecognized close tag: ' . $tag); } - $state = self::TEXT; break; } } diff --git a/test/unbbcodeTest.php b/test/unbbcodeTest.php deleted file mode 100644 index 4933490..0000000 --- a/test/unbbcodeTest.php +++ /dev/null @@ -1,54 +0,0 @@ -<?php - -require_once('PHPUnit/Framework.php'); - -class unbbcodeTest extends PHPUnit_Framework_TestCase { - /** - * @dataProvider provider_bbcode_second_pass - */ - public function test_bbcode_second_pass($msg, $uid, $bitfield, - $expected, $ex) { - if ($ex) $this->setExpectedException($ex); - - /** - * phpBB3 uses many globals; due to the way tests are run, we cannot - * easily get these globals into the right scope so that the methods - * called by our tests can see them. Therefore, we run tests externally - * and report back on the results. - */ - $prog = <<<EOF -try { - require_once("src/unbbcode.php"); - - \$msg = "$msg"; - \$uid = "$uid"; - \$bitfield = "$bitfield"; - - \$unbbcode = new unbbcode(); - \$unbbcode->bbcode_second_pass(\$msg, \$uid, \$bitfield); - \$result = serialize(\$msg); -} -catch (Exception \$e) { - \$result = serialize(\$e); -} - -print \$result; -EOF; - - $result = unserialize(exec('php -r \'' . $prog . '\'')); - - if ($result instanceof Exception) { - throw $result; - } - - $this->assertEquals($expected, $result); - } - - public function provider_bbcode_second_pass() { - return array( - array('[b]Test[/b]', '', false, '<b>Test</b>', null) - ); - } -} - -?> |