enabletoc = 1; $x->enableinclude = 1; $x->snippets['**'] = "%s"; # instead of # run all processing $x->go(); # get the complete HTML output including $html = $x->fullhtml; # alternatively, get some other variables: $body = $x->bodyhtml; # only the part inside the tags $fullconfig = $x->config; # what was in the "config" area of the file? == Notes == - This is an early public release, ready to be tested. - Including disk files is disabled out of the box, because of potential vulnerabilities. Enabling it on systems where untrusted people could edit the t2t content is not recommended. A future version may allow the inclusion of files from the current directory or only with *.t2t extension. To enable inclusions, use $x->enableinclude = 1; */ class T2T { # these variables could be read or forced var $title = ''; # the document title var $content = ''; # the content of the t2t file var $headers = ''; # the first 3 lines of the t2t file var $enableheaders = 0; # enables the first 3 lines headers (default=1) var $enableproc = 1; # enables the pre and post processor (default=1) var $enabletagged = 1; # enables the tagged mark (''tagged'') (default=1) var $enableraw = 1; # enables the raw mark (""raw"") (default=1) var $enableverbatim = 1; # enables the verbatim mark (``raw``) (default=1) var $enablehotlinks = 1; # enables hotlinks [http://www.externalserver.com/images.jpg] (default=1) (note: it's not enabled in the python implementation of txt2tags) var $config = ''; # the full config area, including ext.ref. var $bodytext = ''; # the full body text after inclusions var $bodyhtml = ''; # the innerHTML of the body of the output, no ... var $fullhtml = ''; # the full ... output var $enabletoc = 0; # automatically enabled if %%toc or %!options: --toc var $enableinclude = 1; # allow file inclusions var $maxtoclevels = 5; # h1-h? titles go into toc, same as %!options: --toc-level 1 var $mtime; # last modified timestamp of the input file var $date; # timestamp of the current date var $cssfile = ''; # the css file to be included in the HTML header var $maskemail = 0; # rewrite plaintext e-mail links var $encoding = "UTF-8"; # assume default encoding if none in file var $parsetargets = "html|xhtml"; # accept %!command(html) and %!command(xhtml) var $snippets = array( 'header1' => "

%s

\n", # text (first line of file) 'header2' => "

%s

\n", # text 'header3' => "

%s

\n", # text 'headerwrap' => "
\n%s
\n", # headers 'title' => '%s', # level, id, text 'hrule' => '
', # light|heavy 'verbatim' => "
\n%s
", # content 'mono' => '%s', # content 'center' => "
%s
", # content 'img' => '', # align, url 'link' => '%s', # url, text 'cssfile' => '', '**' => '%s', # bold content '//' => '%s', # italics content '__' => '%s', # underlined content '--' => '%s', # striked content 'tableopen' => "\n", # align, border 'tableclose' => "
\n", 'tablerow' => " \n%s \n", # tagged cells 'tablehead' => " %s\n", # align, content 'tablecell' => " %s\n", # align, content # special 'blockquoteopen' => '
', 'blockquoteclose' => '
', 'paraopen' => '

', 'paraclose' => '

', '+listopen' => "
    \n", '+listclose' => "
\n", '+itemopen' => "
  • ", '+itemmiddle' => "", '+itemclose' => "
  • \n", '-listopen' => "
      \n", '-listclose' => "
    \n", '-itemopen' => "
  • ", '-itemmiddle' => "", '-itemclose' => "
  • \n", ':listopen' => "
    \n", ':listclose' => "
    \n", ':itemopen' => "
    ", ':itemmiddle' => "
    \n", ':itemclose' => "
    \n", 'listindent' => ' ', # nicer HTML output # title, encoding, version, styles, body 'html' => ' %s %s %s '); # used internally var $infile = array(); var $outfile = array(); var $preproc = array(); var $postproc = array(); var $KPV = array(); var $KPCount = 0; var $csslink = ''; function T2T($input, $isfile = 0) { $this->set_macros($input, $isfile); # macros # get content $this->content = $isfile ? $this->read($input, true) : str_replace("\r", '', $input); # get header, config, body $this->R = $this->head_conf_body($this->content); # public variables $this->headers = implode("\n", $this->R['header']); $this->config = implode("\n", $this->R['config']); $this->bodytext = implode("\n", $this->R['body']); } function go($output = '') { # run the full processing $this->parse_config($this->R['config']); # read config settings $lines = $this->run_preproc($this->R['body']); # run %!preproc replacements # strip comments, identify areas and titles, tables and horizontal rules (bars) $lines = $this->firstpass($lines); # second pass $lines = $this->secondpass($this->R['header'], $lines); # restore $body = implode("\n", $lines); $body = $this->Restore($body); $body = str_replace(array("\032\032", "\033\033"), '', $body); # public variables $this->title = $this->esc($this->run_macros($this->R['header'][0])); $this->bodyhtml = $this->run_postproc($body); # %!postproc replacements $html = sprintf($this->snippets['html'], $this->title, $this->encoding, $GLOBALS['T2TVersion'], $this->csslink, $body); $this->fullhtml = $this->run_postproc($html); # %!postproc replacements if($output=='body') return $this->bodyhtml; if($output=='html') return $this->fullhtml; return; } function parse_config($lines) { # try to read the supported configuration options $opts = "encoding|style|postproc|preproc|options"; $tgts = $this->parsetargets; foreach($lines as $c){ if(preg_match("/^%!\\s*({$opts})(?:\\((?:{$tgts})\\))?\\s*:\\s*(.*)$/i", $c, $m)) { # options, preproc and postproc are cumulative list(, $setting, $val) = $m; switch(strtolower($setting)) { case "encoding" : $this->encoding = trim($val); break; case "style" : $this->csslink = sprintf($this->snippets['cssfile'], trim($val)); case "preproc" : if ($this->enableproc == 1) { $this->preproc[] = $this->add_proc($setting, trim($val)); break; } case "postproc" : if ($this->enableproc == 1) { $this->postproc[] = $this->add_proc($setting, trim($val)); break; } case "options": if(strpos(" $val", '--mask-email')) $this->maskemail = 1; if(preg_match('/--toc(?!-)/', $val)) $this->enabletoc = 1; if(preg_match('/--toc-level[= ]+([1-5])/', $val, $n)) $this->maxtoclevels = $n[1]; if(preg_match('/--encoding[= ]+(\\S+)/', $val, $n)) $this->encoding = $n[1]; if(preg_match('/--style[= ]+(\\S+)/', $val, $n)) $this->csslink = sprintf($this->snippets['cssfile'], trim($val)); break; } } } } function add_proc($when, $x) { # add a pre-processor or a postprocessor if(! preg_match("/^ *(\"[^\"]+\"|'[^']+'|\\S+)\\s*(.*)$/", $x, $m)) return; $s = preg_replace('/^("|\')(.*?)\\1$/', '$2', trim($m[1])); $r = preg_replace('/^("|\')(.*?)\\1$/', '$2', trim(@$m[2])); $r = preg_replace('/\\\\(?=[0-9])/', '$', $r); $r = str_replace(array('\\n', '\\t'), array("\n", "\t"), $r); return array("\032$s\032m", $r); } function run_preproc($lines) { # make the replacements $body = implode("\n", $lines); foreach($this->preproc as $a) { $body = preg_replace($a[0], $a[1], $body); } return explode("\n", $body); } function run_postproc($body) { # make the replacements foreach($this->postproc as $a) { $body = preg_replace($a[0], $a[1], $body); } return $body; # end of processing } function firstpass($lines) { # strip comments, identify areas, titles, toc $snippets = $this->snippets; $toc = array(); $postoc = 0; $lines2 = array(); $openarea = ''; $areacontent = ''; $toccnt = 0; $tocnbs = array(0, 0, 0, 0, 0, 0); $table = ''; foreach($lines as $line) { # special areas raw, tagged, verbatim, comments if($openarea) { if($line == $openarea) { # close area if(rtrim($line) != "%%%") # comment areas $lines2[] = $this->closeRTV($openarea, $areacontent); } else { # fill area $areacontent .= "$line\n"; } continue; } if(preg_match('/^("""|```|\'\'\'|%%%) *$/', $line)) { # open area $openarea = trim($line); continue; } if($line!='' && $line{0}=='%' && ! preg_match('/^%%(infile|outfile|date|mtime|rand|toc\\s*$)/i', $line) ) continue; # remove comment lines # special lines raw, tagged, verbatim if(preg_match('/^("""|```|\'\'\') /', $line, $m)) { $lines2[] = $this->closeRTV($m[1], substr($line, 4)); continue; } # Title, Numbered Title if(preg_match('/^ *((=){1,5})(?!=)\\s*(\\S.*[^=]|[^\\s=])\\1(?:\\[([\\w-]+)\\])?\\s*$/', $line, $m) || preg_match('/^ *((\\+){1,5})(?!\\+)\\s*(\\S.*[^+]|[^\\s=])\\1(?:\\[([\\w-]+)\\])?\\s*$/', $line, $m) ) { $toccnt++; $anchor = @$m[4] ? $m[4] : "toc$toccnt"; $txt = $this->esc(trim($m[3])); $level = strlen($m[1]); if($m[2]=='+') { if($level>$tocnbs[0])$tocnbs[$level] = 1; else $tocnbs[$level]++; if($level<$tocnbs[0])for($i=$level+1; $i<6; $i++) $tocnbs[$i] = 0; $prefix = implode(".", array_slice($tocnbs, 1, $level)); $prefix = preg_replace('/^(0\\.)+/', '', $prefix); $txt = "$prefix. $txt"; $tocnbs[0] = $level; } $txt = $this->Keep($txt); $lines2[] = "\032\032".sprintf($snippets['title'], $level, $anchor, $txt); # \032: block that cannot be nested in lists # collect toc entries if($this->maxtoclevels>=$level) $toc[] = $this->sp($level) . "- [$txt #$anchor]"; continue; } # tables if(preg_match('/^ *(\\|\\|?) /', $line, $m)) { if(!$table) { # open table $attr = ($line{0}==' ')? ' align="center"' : ""; if(preg_match('/\\|\\s*$/', $line)) { $attr .= ' border="1"'; } $table = sprintf($snippets['tableopen'], $attr); } # fill table if($m[1]=='||') $fmt = $snippets['tablehead']; else $fmt = $snippets['tablecell']; $line = $this->run_inline($line); $row = substr($line, strlen($m[0])); if(! preg_match('/\\|\\s*$/', $row)) $row .= ' | '; $m = preg_split('/( \\|+(?: |$))/', $row, -1, PREG_SPLIT_DELIM_CAPTURE); $cells = ''; for($i=1; $i1) $attr .= " colspan=\"$span\""; $cells .= sprintf($fmt, $attr, $c); } $table .= sprintf($snippets['tablerow'], $cells); continue; } elseif($table) { # close table $lines2[] = "\033\033". $this->Keep($table . $snippets['tableclose']); # \033: block that can be nested in lists $table = ''; } # horizontal rule (bar1, bar2) if(preg_match('/^ *(=|-|_){20,}\\s*$/', $line, $m)) { $class = $m[1] == "=" ? 'heavy':'light'; $lines2[] = "\032\032".$this->Keep(sprintf($snippets['hrule'], $class)); continue; } if(preg_match("/^ +\\[([\034\\w_,.+%$#@!?+~\\/-]+\\.(?:png|jpe?g|gif|bmp|svg))\\] +$/i", $line)) { $lines2[] = "\033\033". $this->Keep(sprintf($snippets['center'], $this->run_inline($line))); continue; } if(trim(strtolower($line))=='%%toc') { $this->enabletoc = $postoc = 1; $line = '%%toc'; } $lines2[] = $line; } # end foreach line # close ALL if($openarea && $openarea != '%%%') # close all areas $lines2[] = $this->closeRTV($openarea, $areacontent); if($table) $lines2[] = "\033\033". $this->Keep($table . $snippets['tableclose']."\n"); if($this->enabletoc && count($toc)) { if($postoc) { # there is %%toc in the page array_unshift($toc, "\032\032"); $toc[] = "\032\032"; foreach($lines2 as $k=>$v) { if($v=='%%toc') array_splice($lines2, $k, 1, $toc); } } else { # before the body: bar, toc-list, bar $bar = "\032\032".$this->Keep(sprintf($snippets['hrule'], 'light')); array_unshift($toc, $bar); $toc[] = $bar; $lines2 = array_merge($toc, $lines2); } } return $lines2; } function secondpass($headers, $lines) { # all other marks $snippets = $this->snippets; $lines2 = array(); $html = ''; for($i=0; $i<3; $i++) { $j = $i+1; $h = $this->esc($headers[$i]); if($h) $html .= sprintf($snippets["header$j"], $this->run_macros($h)); } if($html) $lines2[] = $this->Keep(sprintf($snippets["headerwrap"], $html)); $blockquote = 0; $blockquotecontent = ''; $para = false; $openlist = 0; $listcontent = ''; $ListLevels = array(array(-1, '', '')); # $level, $spaces, $type foreach($lines as $line) { # blockquote if(preg_match('/^(\\t+)([^\\t].*)$/', $line, $m)) { if($para) { $para = false; $lines2[] = $snippets['paraclose']; } $level = strlen($m[1]); $blockquotecontent .= $this->fixblockquote($blockquote, $level) . $m[1]. $this->run_inline($m[2])."\n"; continue; } elseif($blockquote) { # close bq $lines2[] = "\032\032".$blockquotecontent . $this->fixblockquote($blockquote, 0); $blockquotecontent = ''; } # List, Numbered List, Definition List if(preg_match('/^( *)([+-]) (\\S.*)$/', $line, $m) || preg_match( '/^( *)(:) ( *\\S.*)$/', $line, $m)) { $openlist = 2; if($para) { $para = false; $lines2[] = $snippets['paraclose']; } list(, $spaces, $type, $text) = $m; $text = $this->run_inline($text); $upped = 0; while(count($ListLevels)>0) { list($plevel, $pspaces, $ptype) = array_pop($ListLevels); ## close previous list if($plevel>=0 && strcmp($spaces, $pspaces)<0) { $listcontent .= "\n".$this->sp($plevel).$snippets["{$ptype}itemclose"] . $this->sp($plevel).$snippets["{$ptype}listclose"]; $upped ++; continue; } if($upped) $pspaces = $spaces; $ListLevels[] = array($plevel, $pspaces, $ptype); # restore ## open list if($plevel<0 || strcmp($spaces, $pspaces)>0) { # new list/sublist $level = $plevel+1; $listcontent .= "\n" . $this->sp($level). $snippets["{$type}listopen"]; $ListLevels[] = array($level, $spaces, $type); } else { ## close prev item $listcontent .= "\n".$this->sp($plevel).$snippets["{$ptype}itemclose"]; $level = $plevel; if($ptype!=$type) { $listcontent .= "\n".$this->sp($level).$snippets["{$ptype}listclose"] ."\n".$this->sp($level).$snippets["{$type}listopen"]; $ListLevels[count($ListLevels)-1][2] = $type; # restore } } ## open item $listcontent .= $this->sp($level).$snippets["{$type}itemopen"]; ## fill content $listcontent .= $text . $snippets["{$type}itemmiddle"]; break; } continue; } elseif($openlist) { if(trim($line)=='' || strpos($line, "\032\032")===0 ) { $openlist --; if(!$openlist || strpos($line, "\032\032")===0) { # second empty line, close ALL while(count($ListLevels)>1) { list($plevel, $pspaces, $ptype) = array_pop($ListLevels); $listcontent .= "\n".$this->sp($plevel).$snippets["{$ptype}itemclose"] .$this->sp($plevel).$snippets["{$ptype}listclose"]; } $lines2[] = $this->Keep($listcontent); $lines2[] = $line; $listcontent = "";$openlist=0; continue; } else { list($plevel, ,) = $ListLevels[count($ListLevels)-1]; $listcontent .= $this->sp($plevel+1)."{$snippets["paraopen"]}{$snippets["paraclose"]}\n"; } } else { list($plevel, $pspaces, $ptype) = array_pop($ListLevels); if(preg_match('/^(( *)([+-:])) *$/', $line, $m) && $m[1]== "$pspaces$ptype") { # close $listcontent .= "\n".$this->sp($plevel).$snippets["{$ptype}itemclose"] . $this->sp($plevel).$snippets["{$ptype}listclose"]; if($plevel) $openlist = 2; else { $lines2[] = $this->Keep($listcontent); $listcontent = "";$openlist=0; continue; } } else { if($openlist==1) $listcontent .= $this->sp($plevel+1)."{$snippets["paraopen"]}{$snippets["paraclose"]}\n"; $openlist = 2; $ListLevels[] = array($plevel, $pspaces, $ptype); $listcontent .= $this->sp($plevel+1).$this->run_inline($line)."\n"; } } continue; } if(preg_match("/^[\032\033]{2}/", $line)) { if($para) { $para = false; $lines2[] = $snippets['paraclose']; } $lines2[] = $line; continue; } if($para) { if(trim($line)=='') { $para = false; $lines2[] = $snippets['paraclose']; } else { $lines2[] = $this->run_inline($line); } continue; } # $para = false; if(trim($line)!='') { $lines2[] = $snippets['paraopen']; $lines2[] = $this->run_inline($line); $para = true; continue; } $lines2[] = $line; } # close ALL if($blockquote) $lines2[] = $this->Keep($blockquotecontent . $this->fixblockquote($blockquote, 0)); if($openlist) { while(count($ListLevels)>1) { list($plevel, $pspaces, $ptype) = array_pop($ListLevels); $listcontent .= "\n".$this->sp($plevel).$snippets["{$ptype}itemclose"] .$this->sp($plevel).$snippets["{$ptype}listclose"]; } $lines2[] = $this->Keep($listcontent); } if($para) { $para = false; $lines2[] = $snippets['paraclose']; } return $lines2; } function run_inline($line) { # inline transformations (links, images, bold, mono...) $snippets = $this->snippets; # inline Raw, Mono, Tagged if(preg_match_all('/(\'|"|`){2}([^\\s](.*?[^\\s])?\\1*)\\1\\1/', $line, $m, PREG_SET_ORDER)) { foreach($m as $a) { $type = $a[1].$a[1]; $c = $this->PSS($a[2]); $tmp = $this->closeRTV($type, $c); $line = preg_replace('/(\'|"|`){2}([^\\s](.*?[^\\s])?\\1*)\\1\\1/', $tmp, $line, 1); } } # macros $line = $this->run_macros($line); # <[img]> $imgrx = "\\[([\034\\w_,.+%$#@!?+~\\/-]+\\.(?:png|jpe?g|gif|bmp))\\]"; $line = preg_replace("/^$imgrx(?=.)/ei", "\$this->Keep(sprintf(\$snippets['img'], 'left', '$1'))", $line); $line = preg_replace("/(?<=.)$imgrx$/ei", "\$this->Keep(sprintf(\$snippets['img'], 'right', '$1'))", $line); $line = preg_replace("/$imgrx/ei", "\$this->Keep(sprintf(\$snippets['img'], 'middle', '$1', 'middle'))", $line); $UEX = '<>"{}|\\\\^`()\\[\\]\''; # UrlExcludeChars $PRT = '(?:https?|ftp|news|telnet|gopher|wais|mailto):'; if ($this->enablehotlinks == 0) { $Links = array( "{$PRT}[^\\s$UEX]+" =>'', "www\\d?\\.[^\\s$UEX]+" =>'http://', # lazy links "ftp\\d?\\.[^\\s$UEX]+" =>'ftp://', # lazy links "\\w[\\w.-]+@[\\w-.]+[^\\s$UEX]+" =>'mailto:', # lazy links ); # } else { $Links = array( //"{$PRT}[^\\s$UEX]+" =>'', # allows hotlinks by disabling this part //"www\\d?\\.[^\\s$UEX]+" =>'http://', # lazy links won't work here "ftp\\d?\\.[^\\s$UEX]+" =>'ftp://', # lazy links "\\w[\\w.-]+@[\\w-.]+[^\\s$UEX]+" =>'mailto:', # lazy links ); # } # [txt link], [txt #anchor] foreach($Links as $k=>$v) { $line = preg_replace("/\\[([^\\]]+?) +($k)\\]/ei", "\$this->Keep(sprintf(\$snippets['link'], \$this->esc('$v$2'), \$this->esc('$1', 1)))", $line); } # local links $line = preg_replace("/\\[([^\\]]+?) +([^\\s$UEX]+)\\]/ei", "\$this->Keep(sprintf(\$snippets['link'], \$this->esc('$2'), \$this->esc('$1', 1)))", $line); # free links www.link, e@mail, http://link foreach($Links as $k=>$v) { if($v=='mailto:' && $this->maskemail) { $line = preg_replace("/\\b({$k}[^\\s.,?!$UEX])/ei", "\$this->Keep('<' . str_replace(array('@', '.'), array(' (a) ', ' '), '$1') . '>$2')", $line); } else { $line = preg_replace("/\\b({$k}[^\\s.,?!$UEX])/ei", "\$this->Keep(sprintf(\$snippets['link'], \$this->esc('$v$1'), \$this->esc('$1')))", $line); } } $line = $this->esc($line); # Bold, Italic, Underline, Strike $b = array('*', '/', '_', '-'); foreach($b as $c) { $q = preg_quote($c, '/'); $line = preg_replace("/($q){2}([^\s](?:.*?\\S)?\\1*)\\1\\1/e", "sprintf(\$snippets['$c$c'], \$this->PSS('$2'))", $line); } return $line; } function set_macros($input, $isfile = 0) { $this->date=time(); if($isfile && file_exists($input)) { $this->mtime = filemtime($input); $this->infile = $this->fileattr($input); } else { $this->mtime = time(); $this->infile = $this->fileattr('-'); } $this->outfile = $this->fileattr('-'); } function run_macros($line) { $line = preg_replace('/%%(date|mtime)(\\((.+?)\\))?/ie', 'strftime("$2"? $this->PSS("$3"):"%Y%m%d", $this->$1)', $line); $line = preg_replace('/%%infile(?:\\((.*?)\\))?/ie', '"$1" ? str_replace(array_keys($this->infile), array_values($this->infile), "$1") : $this->infile["%f"]', $line); $line = preg_replace('/%%outfile(?:\\((.*?)\\))?/ie', '"$1" ? str_replace(array_keys($this->outfile), array_values($this->outfile), "$1") : $this->outfile["%f"]', $line); /*$line = preg_replace_callback('/%%rand\([0-9]+,[0-9]+\)/', 'create_function(return(rand($1,$2);))', $line); $line = preg_replace('/%%rand\([0-9]+,[0-9]+\)/i', '', $line); $line = preg_replace_callback('/%%rand\\(([0-9]+),([0-9]+)\\)/', 'return(rand($1,$2);)', $line); */ return $line; } function fixblockquote(&$prev, $curr) { # close open blocks, open sub-blocks $s = $this->snippets; $x = ''; while ($prev<$curr) $x .= str_repeat("\t", ++$prev) . $s['blockquoteopen'] . "\n"; while ($prev>$curr) $x .= str_repeat("\t", $prev--) . $s['blockquoteclose'] . "\n"; return $x; } function closeRTV(&$type, &$x) { # Raw, Tagged or Verbadim lines/areas switch($type{0}) { case '%': $type = $x = ''; return ''; case "'": if ($this->enabletagged == 1) { $y = $x; break; } case '"': # raw if ($this->enableraw == 1) { $y = $this->esc($x); break; } case '`': # verbatim, mono if ($this->enableverbatim == 1) { $s = $this->snippets; $fmt = (strlen($type)==2) ? $s['mono'] : $s['verbatim']; $y = sprintf($fmt, $this->esc($x)); break; } else { $y = $this->esc($x); } } $block = (strlen($type)==3) ? "\033\033" : ''; $type = $x = ''; return $block. $this->Keep($y); } function PSS($x) { return str_replace('\\"','"',$x); } # Strip RegExp slashes function Keep($x) { # preserves a string from being processed by wiki markups $x = $this->Restore($x); $this->KPCount++; $this->KPV[$this->KPCount]=$x; return "\034\034{$this->KPCount}\034\034"; } function Restore($x) { # recovers all hidden strings return preg_replace("/\034\034(\\d.*?)\034\034/e", "\$this->KPV['\$1']", $x); } function sp($n){ # add spaces for nicer indented HTML source code return str_repeat($this->snippets['listindent'], $n); } function esc($x, $pss=0) { # htmlspecialchars if($pss) $x = $this->PSS($x); return str_replace( array('&', '<', '>', '$'), array('&', '<', '>', '$'), $x); } function fileattr($fname) { # variables that can be in %%infile() if($fname == '-') return array( '' => '-', '%f'=> '-', '%F'=> '-', '%e'=> '', '%p'=> '-', '%d'=> '.', '%D'=> '.', '%%'=>'%'); preg_match('/\\.([^.\\/]+)$/',$fname, $m); $ext=@$m[1]; return array( '' => basename($fname), '%f'=> basename($fname), '%F'=> preg_replace('/\\.[^.]+$/', '', basename($fname)), '%e'=> $m[1], '%p'=>realpath($fname), '%d'=>dirname(realpath($fname)), '%D'=>basename(dirname(realpath($fname))), '%%'=>'%'); } function read($filename, $allowed = false) { # get a file content if(!$allowed) return ''; if(!file_exists($filename)) return ''; return str_replace("\r", '', implode('', @file($filename))); } # get the Header, Config area and Body of a t2t file # the function will include the content of any included files function head_conf_body($content) { $lines = explode("\n", $content); $R = array(); $R['header'] = $R['config'] = $R['body'] = array(); # headers if ($this->enableheaders == 0) { $R['header'][0] = $R['header'][1] = $R['header'][2] = ''; } else if($lines[0]=='') { $R['header'][0] = $R['header'][1] = $R['header'][2] = ''; array_shift($lines); } else { for ($i=0; $i<3 && isset($lines[0]); $i++) { $R["header"][$i] = array_shift($lines); } } # config $mlcomment = false; while(isset($lines[0])) { $line = array_shift($lines); if(rtrim($line) == '%%%') { # comment areas in Config $mlcomment = ! $mlcomment; continue; } if($mlcomment || trim($line)=='') continue; if(preg_match('/^%!\\s*includeconf\\s*:\\s*(.+)$/', $line, $m)) { $f = trim($m[1]); if($f{0}!='/') $f = $this->infile['%d'] . DIRECTORY_SEPARATOR . $f; $r = $this->head_conf_body($this->read($f, $this->enableinclude)); for($i=count($r['config'])-1; $i>=0; $i--) array_unshift($lines, $r['config'][$i]); continue; } if($line{0} != '%' || preg_match('/^%(%(date|mtime|toc|infile|outfile|rand)|! *include)/i', $line)) { array_unshift($lines, $line); break; } $R["config"][] = $line; } # body $mlcomment = false; while(isset($lines[0])) { $line = array_shift($lines); if(rtrim($line) == '%%%') { # comment areas $mlcomment = ! $mlcomment; continue; } if($mlcomment) continue; if(preg_match('/^%!\\s*include(?:\\(x?html\\))?\\s*:\\s*(``|\'\'|""|)(.+)\\1\\s*$/', $line, $m)) { $f = trim($m[2]); if($f{0}!='/') $f = $this->infile['%d'] . DIRECTORY_SEPARATOR . $f; $r = $this->head_conf_body($this->read($f, $this->enableinclude)); if($m[1]) { $q = implode("\n", $r['body'])."\n"; $type = str_repeat($m[1]{1}, 3); $line = $this->closeRTV($type, $q); } else { for($i=count($r['body'])-1; $i>=0; $i--) array_unshift($lines, $r['body'][$i]); continue; } } $R['body'][] = $line; } return $R; } }