function plugin_pre_convert() { if (file_exists(PLUGIN_DIR . 'code/codehighlight.php')) { require_once PLUGIN_DIR . 'code/codehighlight.php'; } else { die_message('file ' . PLUGIN_DIR . 'code/codehighlight.php not exist or not readable.'); } static $id_number = 0; // プラグインが呼ばれた回数(IDに利用) $id_number++; $option = array('number' => false, 'nonumber' => false, 'vervatim' => false, 'novervatim' => false, 'icon' => false, 'noicon' => false, 'link' => false, 'nolink' => false); $num_of_arg = func_num_args(); $args = func_get_args(); $text = ''; $number = ''; $style = ''; $stylecnt = 0; $begin = 1; $end = null; $a = array(); // オプションを調べる for ($i = 0; $i < $num_of_arg - 1; ++$i) { if (!_plugin_code_check_argment($args[$i], $option)) { if (!_plugin_code_get_region($args[$i], $begin, $end)) { // style if ($stylecnt == 0) { $color = $args[$i]; ++$stylecnt; } else { $bgcolor = $args[$i]; } } } } if ($stylecnt) { // Invalid color foreach (array($color, $bgcolor) as $col) { if ($col != '' && !preg_match(PLUGIN_PRE_COLOR_REGEX, $col)) { return '<p class="error">#pre():Invalid color: ' . htmlspecialchars($col) . ';</p>'; } } if ($color != '') { $style = ' style="color:' . $color; if ($bgcolor != '') { $style .= ';background-color:' . $bgcolor . '"'; } else { $style .= '"'; } } else { if ($bgcolor != '') { $style .= ' style="background-color:' . $bgcolor . '"'; } else { $style = ''; } } } _plugin_code_multiline_argment($args[$num_of_arg - 1], $data, $option, $begin, $end); if (isset($data['_error']) && $data['_error'] != '') { return $data['_error']; } $text = $data['data']; $title = $data['title']; if ($end === null) { $end = substr_count($text, "\n") + $begin - 1; } if (PLUGIN_PRE_VERVATIM && !$option['novervatim'] || $option['vervatim']) { $text = htmlspecialchars($text); } else { $text = make_link($text); } $html = '<pre class="' . PLUGIN_PRE_HEADER . 'body" ' . $style . '>' . $text . '</pre>'; if (PLUGIN_PRE_NUMBER && !$option['nonumber'] || $option['number']) { $number = '<pre class="' . PLUGIN_PRE_HEADER . 'number">' . _plugin_code_makeNumber($end, $begin) . '</pre>'; $html = '<div id="' . PLUGIN_PRE_HEADER . $id_number . '" class="' . PLUGIN_PRE_HEADER . 'table">' . _plugin_code_column($html, $number, null) . '</div>'; } return $title . $html; }
/** * ソースからHTML生成 */ function srcToHTML(&$string, &$lang, $id_number, &$option) { // テーブルジャンプ用ハッシュ $switchHash = array(); $capital = false; // 大文字小文字を区別しない $mkoutline = $option['outline']; $mknumber = $option['number']; // 改行 $switchHash["\n"] = PLUGIN_CODE_CARRIAGERETURN; $switchHash['\\'] = PLUGIN_CODE_ESCAPE; // 識別子開始文字 for ($i = ord('a'); $i <= ord('z'); ++$i) { $switchHash[chr($i)] = PLUGIN_CODE_IDENTIFIRE; } for ($i = ord('A'); $i <= ord('Z'); ++$i) { $switchHash[chr($i)] = PLUGIN_CODE_IDENTIFIRE; } $switchHash['_'] = PLUGIN_CODE_IDENTIFIRE; // 文字列開始文字 $switchHash['"'] = PLUGIN_CODE_STRING_LITERAL; // 言語定義ファイル読み込み include PLUGIN_DIR . 'code/keyword.' . $lang . '.php'; // 文字->html変換用ハッシュ $htmlHash = array('"' => '"', '\'' => ''', '<' => '<', '>' => '>', '&' => '&', "\t" => PLUGIN_CODE_WIDTHOFTAB); $html = ''; $str_len = strlen($string); $str_pos = 0; $line = 0; // 行数をカウント // for outline $outline = array(); // $outline[lineno][nest] $outline[lineno][blockno]がある。 $nest = 1; // ネスト $blockno = 0; // 何番目のブロックか?IDをユニークにするために用いる $last_start = false; // 最後にブロック開始だったか、、、。 $commentno = 0; // 最初の検索用に読み込み if ($str_len == $str_pos) { $code = false; } else { $code = $string[$str_pos++]; } // getc while ($code !== false) { switch ($switchHash[$code]) { case PLUGIN_CODE_CARRIAGERETURN: // 改行 ++$line; $html .= "\n"; // 次の検索用に読み込み if ($str_len == $str_pos) { $code = false; } else { $code = $string[$str_pos++]; } // getc continue 2; case PLUGIN_CODE_ESCAPE: // escape charactor $start = $code; // 判定用にもう1文字読み込む if ($str_len == $str_pos) { $code = false; } else { $code = $string[$str_pos++]; } // getc if (ctype_alnum($code)) { // 文字(変数)なら終端まで見付ける --$str_pos; // エラー処理したくないからpreg_matchで必ず見つかるようにする $result = substr($string, $str_pos); preg_match('/[A-Za-z0-9_]+/', $result, $matches); $str_pos += strlen($matches[0]); $result = $matches[0]; } else { // 記号なら1文字だけ切り出す $result = $code; if ($code == "\n") { ++$line; } } // htmlに追加 $html .= htmlspecialchars($start . $result, ENT_QUOTES); // 次の検索用に読み込み if ($str_len == $str_pos) { $code = false; } else { $code = $string[$str_pos++]; } // getc continue 2; case PLUGIN_CODE_COMMENT: // コメント --$str_pos; $result = substr($string, $str_pos); foreach ($code_comment[$code] as $pattern) { if (preg_match($pattern[0], $result)) { //if (!strncmp($pattern[1], $result, $pattern[0])) { $pos = strpos($result, $pattern[1]); if ($pos === false) { // 見つからないときは終わりまで $str_pos = $str_len; //$result = $result; ってことで何もしない } else { $pos += $pattern[2]; $str_pos += $pos; $result = substr($result, 0, $pos); } // ライン数カウント $line += substr_count($result, "\n"); ++$commentno; // htmlに追加 $result = str_replace('\\t', PLUGIN_CODE_WIDTHOFTAB, htmlspecialchars($result, ENT_QUOTES)); if ($option['link']) { $result = preg_replace('/(s?https?:\\/\\/|ftp:\\/\\/|mailto:)([-_.!~*()a-zA-Z0-9;\\/:@?=+$,%#]|&)+/', '<a href="$0">$0</a>', $result); } $html .= '<span class="' . PLUGIN_CODE_HEADER . 'comment" id="' . PLUGIN_CODE_HEADER . $id_number . '_cmt_' . $commentno . '">' . $result . '</span>'; // 次の検索用に読み込み if ($str_len == $str_pos) { $code = false; } else { $code = $string[$str_pos++]; } // getc continue 3; } } // コメントではない ++$str_pos; break; case PLUGIN_CODE_COMMENT_WORD: // 文字列から始まるコメント // 出来る限り長く識別子を得る --$str_pos; $result = substr($string, $str_pos); foreach ($code_comment[$code] as $pattern) { if (preg_match($pattern[0], $result)) { $pos = strpos($result, $pattern[1]); if ($pos === false) { // 見つからないときは終わりまで $str_pos = $str_len; //$result = $result; ってことで何もしない } else { $pos += $pattern[2]; $str_pos += $pos; $result = substr($result, 0, $pos); } // ライン数カウント $line += substr_count($result, "\n"); ++$commentno; // htmlに追加 $result = str_replace('\\t', PLUGIN_CODE_WIDTHOFTAB, htmlspecialchars($result, ENT_QUOTES)); if ($option['link']) { $result = preg_replace('/(s?https?:\\/\\/|ftp:\\/\\/|mailto:)([-_.!~*()a-zA-Z0-9;\\/:@?=+$,%#]|&)+/', '<a href="$0">$0</a>', $result); } $html .= '<span class="' . PLUGIN_CODE_HEADER . 'comment" id="' . PLUGIN_CODE_HEADER . $id_number . '_cmt_' . $commentno . '">' . $result . '</span>'; // 次の検索用に読み込み if ($str_len == $str_pos) { $code = false; } else { $code = $string[$str_pos++]; } // getc continue 3; } } ++$str_pos; // コメントでなければ文字列 break を使わない // コメントでなければ文字列 break を使わない case PLUGIN_CODE_IDENTIFIRE: // 識別子(アルファベットから始まっている) // 出来る限り長く識別子を得る --$str_pos; // エラー処理したくないからpreg_matchで必ず見つかるようにする $result = substr($string, $str_pos); preg_match('/[A-Za-z0-9_\\-]+/', $result, $matches); $str_pos += strlen($matches[0]); $result = $matches[0]; // htmlに追加 if ($capital) { $index = $code_keyword[strtolower($result)]; } else { $index = $code_keyword[$result]; } $result = htmlspecialchars($result, ENT_QUOTES); if ($index != '') { $html .= '<span class="' . PLUGIN_CODE_HEADER . $code_css[$index - 1] . '">' . $result . '</span>'; } else { $html .= $result; } // 次の検索用に読み込み if ($str_len == $str_pos) { $code = false; } else { $code = $string[$str_pos++]; } // getc continue 2; case PLUGIN_CODE_SPECIAL_IDENTIFIRE: // 特殊文字から始まる識別子 // 次の文字が英字か判定 if (!ctype_alpha($string[$str_pos])) { break; } $result = substr($string, $str_pos); preg_match('/[A-Za-z0-9_\\-]+/', $result, $matches); $str_pos += strlen($matches[0]); $result = $code . $matches[0]; // htmlに追加 if ($capital) { $index = $code_keyword[strtolower($result)]; } else { $index = $code_keyword[$result]; } $result = htmlspecialchars($result, ENT_QUOTES); if ($index != '') { $html .= '<span class="' . PLUGIN_CODE_HEADER . $code_css[$index - 1] . '">' . $result . '</span>'; } else { $html .= $result; } // 次の検索用に読み込み if ($str_len == $str_pos) { $code = false; } else { $code = $string[$str_pos++]; } // getc continue 2; case PLUGIN_CODE_STRING_LITERAL: // 文字列 // 文字列リテラルを得る $pos = $str_pos; do { $result = substr($string, $str_pos); $pos1 = strpos($result, $code); // 文字列終了文字検索 if ($pos1 === false) { // 文字列が終わらなかったので全部文字列とする $str_pos = $str_len - 1; break; } $str_pos += $pos1 + 1; } while ($string[$str_pos - 2] == '\\'); // 前の文字がエスケープ文字なら続ける $result = $code . substr($string, $pos, $str_pos - $pos); // ライン数カウント $line += substr_count($result, "\n"); // htmlに追加 $result = htmlspecialchars($result, ENT_QUOTES); if ($option['link']) { $result = preg_replace('/(s?https?:\\/\\/|ftp:\\/\\/|mailto:)([-_.!~*()a-zA-Z0-9;\\/:@?=+$,%#]|&)+/', '<a href="$0">$0</a>', $result); } $html .= '<span class="' . PLUGIN_CODE_HEADER . 'string">' . $result . '</span>'; // 次の検索用に読み込み if ($str_len == $str_pos) { $code = false; } else { $code = $string[$str_pos++]; } // getc continue 2; case PLUGIN_CODE_NONESCAPE_LITERAL: // エスケープ文字と式展開を無視した文字列 // 文字列リテラルを得る $pos = $str_pos; $result = substr($string, $str_pos); $pos1 = strpos($result, $code); // 文字列終了文字検索 if ($pos1 === false) { // 文字列が終わらなかったので全部文字列とする $str_pos = $str_len - 1; } else { $str_pos += $pos1 + 1; } $result = $code . substr($string, $pos, $str_pos - $pos); // ライン数カウント $line += substr_count($result, "\n"); // htmlに追加 $result = htmlspecialchars($result, ENT_QUOTES); if ($option['link']) { $result = preg_replace('/(s?https?:\\/\\/|ftp:\\/\\/|mailto:)([-_.!~*()a-zA-Z0-9;\\/:@?=+$,%#]|&)+/', '<a href="$0">$0</a>', $result); } $html .= '<span class="' . PLUGIN_CODE_HEADER . 'string">' . $result . '</span>'; // 次の検索用に読み込み if ($str_len == $str_pos) { $code = false; } else { $code = $string[$str_pos++]; } // getc continue 2; case PLUGIN_CODE_PAIR_LITERAL: // 対記号で囲まれた文字列リテラルを得る PostScript $pos = $str_pos; do { $result = substr($string, $str_pos); $pos1 = strpos($result, $literal_delimiter); // 文字列終了文字検索 if ($pos1 === false) { // 文字列が終わらなかったので全部文字列とする $str_pos = $str_len - 1; break; } $str_pos += $pos1 + 1; } while ($string[$str_pos - 2] == '\\'); // 前の文字がエスケープ文字なら続ける $result = $code . substr($string, $pos, $str_pos - $pos); // ライン数カウント $line += substr_count($result, "\n"); // htmlに追加 $result = htmlspecialchars($result, ENT_QUOTES); if ($option['link']) { $result = preg_replace('/(s?https?:\\/\\/|ftp:\\/\\/|mailto:)([-_.!~*()a-zA-Z0-9;\\/:@?=+$,%#]|&)+/', '<a href="$0">$0</a>', $result); } $html .= '<span class="' . PLUGIN_CODE_HEADER . 'string">' . $result . '</span>'; // 次の検索用に読み込み if ($str_len == $str_pos) { $code = false; } else { $code = $string[$str_pos++]; } // getc continue 2; case PLUGIN_CODE_FORMULA: // TeXの数式に使用 将来的には汎用性を持たせる $pos = $str_pos; $result = substr($string, $str_pos); $pos1 = strpos($result, $code); // 文字列終了文字検索 if ($pos1 === false) { // 文字列が終わらなかったので全部文字列とする $str_pos = $str_len - 1; } else { $str_pos += $pos1 + 1; } $result = $code . substr($string, $pos, $str_pos - $pos); // htmlに追加 $result = htmlspecialchars($result, ENT_QUOTES); if ($option['link']) { $result = preg_replace('/(s?https?:\\/\\/|ftp:\\/\\/|mailto:)([-_.!~*()a-zA-Z0-9;\\/:@?=+$,%#]|&)+/', '<a href="$0">$0</a>', $result); } $html .= '<span class="' . PLUGIN_CODE_HEADER . 'formula">' . $result . '</span>'; // 次の検索用に読み込み if ($str_len == $str_pos) { $code = false; } else { $code = $string[$str_pos++]; } // getc continue 2; case PLUGIN_CODE_BLOCK_START: // outline 表示用開始文字 {, ( ++$blockno; ++$nest; //if(! array_key_exists($line,$outline)) { if (!isset($outline[$line])) { $outline[$line] = array(); } array_push($outline[$line], array('nest' => $nest, 'blockno' => $blockno)); // アウトラインが閉じた時に表示する画像を埋め込む場所 $html .= $code . '<span id="' . PLUGIN_CODE_HEADER . $id_number . _ . $blockno . '_img" display="none"></span>' . '<span id="' . PLUGIN_CODE_HEADER . $id_number . _ . $blockno . '">'; if ($str_len == $str_pos) { $code = false; } else { $code = $string[$str_pos++]; } // getc continue 2; case PLUGIN_CODE_BLOCK_END: // outline 表示終了文字 }, ) --$nest; //if(! array_key_exists($line,$outline)) { if (!isset($outline[$line])) { $outline[$line] = array(); array_push($outline[$line], array('nest' => $nest, 'blockno' => 0)); } else { $old = array_pop($outline[$line]); if ($old['blockno'] != 0 && $nest + 1 == $old['nest']) { } else { if (!is_null($old)) { array_push($outline[$line], $old); } array_push($outline[$line], array('nest' => $nest, 'blockno' => 0)); } } $last_start = false; $html .= '</span>' . $code; if ($str_len == $str_pos) { $code = false; } else { $code = $string[$str_pos++]; } // getc continue 2; } // switch // その他の文字 $result = $htmlHash[$code]; if ($result) { $html .= $result; } else { $html .= $code; } // 次の検索用に読み込み if ($str_len == $str_pos) { $code = false; } else { $code = $string[$str_pos++]; } // getc } // while // 最後の余分な改行を削除 if ($html[strlen($html) - 2] == ' ') { $html = substr($html, 0, -2); } else { $html = substr($html, 0, -1); } $html = array('src' => $html, 'number' => '', 'outline' => '', 'blocknum' => $blockno, 'commentnum' => $commentno); if ($mkoutline) { return $this->makeOutline($html, $line - 1, $nest, $mknumber, $outline, $blockno, $id_number); } if ($mknumber) { $html['number'] = _plugin_code_makeNumber($line - 1); } return $html; }