1<?php
2/**
3 * Renderer for LaTeX output
4 * Copyright (C) ???? Harry Fuecks, Andreas Gohr, Danjer
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library 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 GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 * --------------------------------------------------------------------
20 *
21 * @author Harry Fuecks <hfuecks@gmail.com>
22 * @author Andreas Gohr <andi@splitbrain.org>
23 * @author Danjer <danjer@doudouke.org>
24 *
25 */
26
27if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
28
29if ( !defined('DOKU_LF') ) {
30  // Some whitespace to help View > Source
31  define ('DOKU_LF',"\n");
32}
33
34if ( !defined('DOKU_TAB') ) {
35  // Some whitespace to help View > Source
36  define ('DOKU_TAB',"\t");
37}
38
39require_once DOKU_INC . 'inc/parser/renderer.php';
40require_once DOKU_INC . 'inc/html.php';
41
42class Doku_Renderer_latex extends Doku_Renderer {
43
44  var $doc = '';
45
46
47  var $acronyms = array();
48  var $smileys = array();
49  var $badwords = array();
50  var $entities = array();
51  var $interwiki = array();
52  var $state = array();
53  var $latexentities = array();
54  var $headers = array();
55  var $dokulinks = array();
56  var $smileys_ps = array();
57  var $interwiki_ps = array();
58  var $_quote_level = 0;
59  var $_section_level = 0;
60  var $_footnotes = array();
61  var $_footnote_index = 0;
62  var $_num_titles = 0;
63  var $_current_table_mode = NULL;
64  var $_current_table_args = array();
65  var $_current_table = array();
66  var $_current_table_maxcols_size = array();
67  var $_current_table_cols_size = 0;
68  var $_acronyms_used = array();
69  var $_tmphandle = NULL;
70  var $_tmp_put = array();
71
72  function label_document() { //For links
73    if (isset($this->info['current_file_id']))
74      $cleanid = $this->info['current_file_id'];
75    else
76      $cleanid = noNS(cleanID($this->info['current_id'], TRUE));
77    $this->putcmd("label{" . md5($cleanid) . "}");
78    if (isset($this->info['current_file_id']))
79      $this->putnl("%%Start: " . $cleanid . ' => '
80           . $this->info['current_file_id']);
81    else
82      $this->putnl("%%Start: " . $cleanid . ' => ' . wikiFN($cleanid));
83  }
84
85  function getFormat() {
86    return 'latex';
87  }
88
89  function document_start() {
90    //    ob_start();
91    $this->headers = array();
92    //msg("Memory Usage doc start: ". memory_get_usage(), -1);
93    //memory managment
94    //$this->_tmphandle = tmpfile();
95
96  }
97
98  function document_end() {
99    //    $this->doc .= ob_get_contents();
100    //ob_end_clean();
101    //    msg("Memory Usage doc close: ". memory_get_usage(), -1);
102    $this->info['dokulinks'] = $this->dokulinks;
103    if (is_null($this->_tmphandle))
104      return $this->doc;
105    //    if (function_exists('stream_get_contents')) {
106    //      $this->doc = stream_get_contents($this->_tmphandle, -1, 0);
107    //} else {
108    //    msg("tmpfile mode");
109    rewind($this->_tmphandle);
110    while (!feof($this->_tmphandle))
111      $this->doc .= fgets($this->_tmphandle);
112    //}
113    fclose($this->_tmphandle);
114  }
115
116  function header($text, $level) {
117    global $conf;
118    $levels = array(
119            1=>'dokutitlelevelone',
120            2=>'dokutitleleveltwo',
121            3=>'dokutitleleveltree',
122            4=>'dokutitlelevelfour',
123            5=>'dokutitlelevelfive',
124            );
125
126    if ( isset($levels[$level]) ) {
127      $token = $levels[$level];
128    } else {
129      $token = $levels[1];
130    }
131    $text = trim($text);
132    $this->nlputcmdnl("$token{" . $this->_latexEntities($text) . "}");
133    $cleanid = noNS(cleanID($text, TRUE));
134    if ($conf['maxtoclevel'] >= $level) {   // Don't label too high
135      $this->putcmd("label{" . md5($cleanid) . "}"); //label for links on headers
136      $this->putnl("%% " . $cleanid);
137    }
138    if ($this->_num_titles == 0) { //label for links on document/page
139      $this->label_document();
140    }
141    $this->_num_titles++;
142    if ($level == 1) {//Reset footnotes used each chapter
143      $this->_acronyms_used = array();
144      $this->_footnote_index = 0;
145    }
146  }
147
148  function section_open($level) {
149    $this->_section_level = $level;
150  }
151
152  function section_close() {
153
154  }
155
156  function cdata($text) {
157    $this->putent($text);
158  }
159
160  function p_open() {
161
162  }
163
164  function p_close() {
165    $this->put(DOKU_LF.DOKU_LF);
166  }
167
168  function linebreak() {
169    $this->put('\\\\ ');
170  }
171
172  function hr() {
173    $this->nlputcmdnl("dokuhline");
174    $this->putnl();
175  }
176
177  function strong_open() {
178    $this->putcmd("dokubold{");
179  }
180
181  function strong_close() {
182    $this->put('}');
183  }
184
185  function emphasis_open() {
186    $this->putcmd("dokuitalic{");
187  }
188
189  function emphasis_close() {
190    $this->put('}');
191  }
192
193  function underline_open() {
194    $this->putcmd("dokuunderline{");
195    $this->state['format'] = 1;
196  }
197
198  function underline_close() {
199    $this->state['format'] = 0;
200    $this->put('}');
201  }
202
203  function monospace_open() {
204    $this->putcmd("dokumonospace{");
205    $this->state['format'] = 1;
206  }
207
208  function monospace_close() {
209    $this->state['format'] = 0;
210    $this->put('}');
211  }
212
213  function subscript_open() {
214    $this->putcmd("dokusubscript{");
215  }
216
217  function subscript_close() {
218    $this->put('}');
219  }
220
221  function superscript_open() {
222    $this->putcmd("dokusupscript{");
223  }
224
225  function superscript_close() {
226    $this->put('}');
227  }
228
229  function deleted_open() {
230    $this->putcmd("dokuoverline{");
231  }
232
233  function deleted_close() {
234    $this->put('}');
235  }
236
237  function footnote_open() {
238    $this->_footnote_index++;
239    $this->putcmd("dokufootnote{");
240  }
241
242  function footnote_close() {
243    $this->put('}');
244  }
245
246  function footnotemark_open() {
247    $this->putcmd("dokufootmark{");
248  }
249
250  function footnotemark_close() {
251    $this->put('}');
252  }
253
254  /**
255   * @TODO Problem here with nested lists
256   */
257  function listu_open() {
258    $this->nlputcmdnl("begin{itemize}");  //need to overload that
259  }
260
261  function listu_close() {
262    $this->putcmdnl("end{itemize}");
263  }
264
265  function listo_open() {
266    $this->nlputcmd("begin{enumerate}");  //need to overload that
267  }
268
269  function listo_close() {
270    $this->putcmdnl("end{enumerate}");
271  }
272
273  function listitem_open($level) {
274    $this->putcmd("dokuitem ");
275  }
276
277  function listitem_close() {
278    $this->putnl();
279  }
280
281  function listcontent_open() {
282
283  }
284
285  function listcontent_close() {
286
287  }
288
289  function unformatted($text) {
290    $this->cdata($text);
291  }
292
293  function php($text) {
294    $this->code("\n<php>\n$text\n</php>\n", 'php'); //Need to do smth ?!?
295  }
296
297  function html($text) {
298    $this->code("\n<html>\n$text\n</html>\n", 'html'); //Any Ideas ?
299  }
300
301  /**
302   * Indent?
303   */
304  function preformatted($text) {
305    $this->nlputcmdnl("small");
306    $this->putcmdnl("begin{verbatimtab}");        //need overload
307    $this->put(wordwrap(str_replace('verbatimtab', 'verbatim',
308                    $text), $this->info['wrapcodelength'], "\n"));
309    $this->nlputcmdnl("end{verbatimtab}");        //need overload
310    $this->putcmdnl("normalsize");
311  }
312
313  function file($text) {
314    $this->preformatted($text);
315  }
316
317  /**
318   * Problem here with nested quotes
319   */
320  function quote_open() {
321    $this->_quote_level++;
322    $this->putcmd_protect("dokuquoting");
323  }
324
325  function quote_close() {
326    $this->_quote_level--;
327    if ($this->_quote_level == 0) {
328      $this->putnl();
329      $this->putnl();
330    }
331  }
332
333  function code($text, $lang = NULL) {
334    if ( !$lang ) {
335      $this->preformatted($text);
336    } else {
337      switch ($lang) { //Latex syntax hightlight is quite old...
338        case "shell":
339          $lang = "sh";
340          break;
341        case "bash":
342          $lang = "sh";
343          break;
344        case "latex":
345          $lang = "TeX";
346          break;
347      }
348      $this->nlputcmdnl("lstset{language=$lang}");    //need overload
349      $this->putcmd("begin{lstlisting}");        //need overload
350      $this->put(wordwrap($text, $this->info['wrapcodelength'], DOKU_LF));
351      $this->nlputcmdnl("end{lstlisting}");        //need overload
352    }
353  }
354
355  function acronym($acronym) {
356    $this->put($acronym);
357    if (!isset($this->_acronyms_used[$this->acronyms[$acronym]])) {
358      $this->footnote_open();
359      $this->putent($this->acronyms[$acronym], 1);
360      $this->footnote_close();
361      $this->_acronyms_used[$this->acronyms[$acronym]] = $this->_footnote_index;
362    } else {
363      $this->footnotemark_open();
364      $this->put($this->_acronyms_used[$this->acronyms[$acronym]]);
365      $this->footnotemark_close();
366    }
367  }
368
369  function smiley($smiley) {
370    if ( array_key_exists($smiley, $this->smileys) ) {
371      $this->putcmd("dokusmiley{");
372      $this->put(DOKU_INC.'lib/images/smileys/'.$this->smileys[$smiley]);
373      $this->put("}");
374    } else {
375      $this->put($smiley);
376    }
377  }
378
379  function wordblock($word) {
380    $this->put($word);
381  }
382
383  function entity($entity) {
384    $this->put($this->latexentities[$entity], 1);
385  }
386
387  // 640x480 ($x=640, $y=480)
388  function multiplyentity($x, $y) {
389    if ($this->_current_table_mode == 'table_analyse') { //try think something better
390      $this->cdata($x . "x" . $y);
391      return;
392    }
393    $this->put($x);
394    $this->put("{\\texttimes}", 1); //Need Overload
395    $this->put($y);
396  }
397
398  function singlequoteopening() {
399    $this->put("'");
400  }
401
402  function singlequoteclosing() {
403    $this->put("'");
404  }
405
406  function apostrophe() {
407    $this->singlequoteopening();
408  }
409
410  function doublequoteopening() {
411    $this->put('"');
412  }
413
414  function doublequoteclosing() {
415    $this->put('"');
416  }
417
418  // $link like 'SomePage'
419  function camelcaselink($link) {
420    $this->put($link);
421  }
422
423  function locallink($hash, $name = NULL) {
424    global $ID;
425    list($page, $section) = split('#', $hash, 2);
426    //    $md5 = md5(cleanID($section, TRUE));
427    $cleanid = noNS(cleanID($hash, TRUE));
428    $md5 = md5($cleanid);
429    $name  = $this->_getLinkTitle($name, $hash, $isImage);
430    $hash  = $this->_headerToLink($hash);
431    array_push($this->dokulinks, array('id' => $hash, 'name' => $name, 'type' => 'local', ));
432    $this->putcmd('hyperref[' . $md5 . ']{');
433    $this->putent($name);
434    $this->put('}');
435    //    $this->putnl('%% '. $cleanid);
436  }
437
438
439  function internallink($id, $name = NULL, $search=NULL, $returnonly=false) {
440    global $ID;
441    // default name is based on $id as given
442    $default = $this->_simpleTitle($id);
443    // now first resolve and clean up the $id
444    $orgname = $name;
445    resolve_pageid(getNS($ID),$id,$exists);
446    $name = $this->_getLinkTitle($name, $default, $isImage, $id);
447    list($page, $section) = split('#', $id, 2);
448    if (isset($section))
449      $cleanid = noNS(cleanID($section, TRUE));
450    else
451      $cleanid = noNS(cleanID($id, TRUE));
452
453    $md5 = md5($cleanid);
454    array_push($this->dokulinks, array('id' => $id, 'name' => $name,
455                       'type' => 'internal',
456                       'hash' => $md5));
457    $hash = NULL;
458    $this->putcmd('hyperref[');
459    //    if (is_null($hash))
460    //      $this->put(str_replace('_', ' ', $id));
461    //    else
462    //      $this->put(str_replace('_', ' ', $hash));
463    $this->put($md5);
464    $this->put(']{');
465    $this->putent($name);
466    $this->put('}');
467    //    $this->putnl('%% '. $cleanid);
468  }
469
470
471  // $link like 'wiki:syntax', $title could be an array (media)
472  function internallink_old($link, $title = NULL) {
473    $this->putent('[['.$link.'|'.$title.']]');
474  }
475
476  function internallink_xhtml($id, $name = NULL, $search=NULL, $returnonly=false) {
477    global $conf;
478    global $ID;
479    // default name is based on $id as given
480    $default = $this->_simpleTitle($id);
481    // now first resolve and clean up the $id
482    resolve_pageid(getNS($ID),$id,$exists);
483    $name = $this->_getLinkTitle($name, $default, $isImage, $id);
484    if ( !$isImage ) {
485      if ( $exists ) {
486    $class='wikilink1';
487    // do some recurse
488      } else {
489    $class='wikilink2';
490      }
491    } else {
492      $class='media';
493    }
494
495    //keep hash anchor
496    list($id,$hash) = split('#',$id,2);
497    if (isset($hash)) {
498      $this->putcmd('href{' . $id . '#' . $hash . '}{' . $name . '}');
499    } else {
500      $this->putcmd('hyperlink{' . $id . '}{' . $name . '}');
501    }
502  }
503
504  // $link is full URL with scheme, $title could be an array (media)
505  function externallink($link, $title = NULL) {
506    $title_org = $title;
507    $title = $this->_getLinkTitle($title, $link, $isImage);
508    if ($isImage) {
509      $this->put($title);
510    } else {
511      if ( $title ) {
512        $this->put($this->_formatLink(array('url' => $link,
513                        'title' => $title)));
514      } else {
515        $this->putcmd('url{'.$link.'}');
516      }
517    }
518  }
519
520  // $link is the original link - probably not much use
521  // $wikiName is an indentifier for the wiki
522  // $wikiUri is the URL fragment to append to some known URL
523  function interwikilink($link, $title = NULL, $wikiName, $wikiUri) {
524    if (is_array($title)) {
525      $url = '';
526      if ( isset($this->interwiki[$wikiName]) ) {
527    $url = $this->interwiki[$wikiName];
528      }
529      $title['caption'] = $url.$wikiUri;
530    }
531    $linkname = $this->_getLinkTitle($title, $wikiUri, $isImage);
532    if ( !$isImage ) {
533      $class = preg_replace('/[^_\-a-z0-9]+/i','_',$wikiName);
534      $imagefile = DOKU_INC . 'lib/images/interwiki/' . $class . '.gif';
535      if (!(isset($this->interwiki_ps[$class])
536        && @file_exists($this->interwiki_ps[$class]))
537      && @file_exists($imagefile)) {
538    $img = new TexItImage($imagefile);
539    if ($img->is_error) {
540      msg('img error: '. $imagefile, -1);
541      $this->unformatted('img error: '. $imagefile);
542      return ;
543    }
544    $filename = $img->get_output_filename();
545    $this->interwiki_ps[$class] = $filename;
546      }
547      if (isset($this->interwiki_ps[$class])) {
548    $this->putcmd("includegraphics[height=1em]{"); // need config for that
549    $this->put($this->interwiki_ps[$class], 1);
550    $this->put("}", 1);
551      }
552    } else {
553      $this->put($linkname); //link is an image
554##      $this->putcmd('breakup');
555      return ;
556    }
557    if ( isset($this->interwiki[$wikiName]) ) {
558      $url = $this->interwiki[$wikiName];
559      $this->put($this->_formatLink(array('url' => $url,
560                'title' => $linkname)));
561    } else {
562      $this->putcmd('url{');
563      $this->put($link);
564      $this->put('}', 1);
565    }
566
567  }
568
569  // Link to file on users OS, $title could be an array (media)
570  function filelink($link, $title = NULL) {
571    array_push($this->dokulinks, array('id' => $link, 'name' => $title, 'type' => 'filelink'));
572    $this->unformatted('[['.$link.'|'.$title.']]');
573  }
574
575  // Link to a Windows share, , $title could be an array (media)
576  function windowssharelink($link, $title = NULL) {
577    $this->unformatted('[['.$link.'|'.$title.']]');
578  }
579
580  function emaillink($address, $title = NULL) {
581    $this->putent($address);
582  }
583
584  // @TODO
585  function internalmedialink (
586                  $src,$title=NULL,$align=NULL,$width=NULL,$height=NULL,$cache=NULL
587                  ) {
588
589  }
590
591  // @TODO
592  function externalmedialink(
593                 $src,$title=NULL,$align=NULL,$width=NULL,$height=NULL,$cache=NULL
594                 ) {
595    if ( $title ) {
596      $this->doc .= '{{'.$src.'|'.$title.'}}';
597    } else {
598      $this->doc .= '{{'.$src.'}}';
599    }
600  }
601
602  // Need analyse table before choose a table mode
603
604    /**
605     * Renders an RSS feed
606     *
607     * @author Andreas Gohr <andi@splitbrain.org>
608     */
609    function rss ($url,$params){
610        global $lang;
611        global $conf;
612
613        require_once(DOKU_INC.'inc/FeedParser.php');
614        $feed = new FeedParser();
615        $feed->feed_url($url);
616
617        //disable warning while fetching
618        if (!defined('DOKU_E_LEVEL')) { $elvl = error_reporting(E_ERROR); }
619        $rc = $feed->init();
620        if (!defined('DOKU_E_LEVEL')) { error_reporting($elvl); }
621
622        //decide on start and end
623        if($params['reverse']){
624            $mod = -1;
625            $start = $feed->get_item_quantity()-1;
626            $end   = $start - ($params['max']);
627            $end   = ($end < -1) ? -1 : $end;
628        }else{
629            $mod   = 1;
630            $start = 0;
631            $end   = $feed->get_item_quantity();
632            $end   = ($end > $params['max']) ? $params['max'] : $end;;
633        }
634
635    //$this->doc .= '<ul class="rss">';
636    $this->listu_open();
637        if($rc){
638            for ($x = $start; $x != $end; $x += $mod) {
639                $item = $feed->get_item($x);
640                //$this->doc .= '<li><div class="li">';
641        $this->listitem_open(1);
642                $this->externallink($item->get_permalink(),
643                                    $item->get_title());
644                if($params['author']){
645                    $author = $item->get_author(0);
646                    if($author){
647                        $name = $author->get_name();
648                        if(!$name) $name = $author->get_email();
649                        if($name)
650              $this->cdata(' '.$lang['by'].' '.$name);
651            //$this->doc .= ' '.$lang['by'].' '.$name;
652                    }
653                }
654                if($params['date']){
655          $this->cdata(' ('.$item->get_date($conf['dformat']).')');
656          //$this->doc .= ' ('.$item->get_date($conf['dformat']).')';
657                }
658                if($params['details']){
659          //$this->doc .= '<div class="detail">';
660                    if($htmlok){
661                        $this->cdata($item->get_description());
662                    }else{
663                        $this->cdata(strip_tags($item->get_description()));
664                    }
665                    //$this->doc .= '</div>';
666                }
667
668                //$this->doc .= '</div></li>';
669        $this->listitem_close();
670            }
671        }else{
672      //$this->doc .= '<li><div class="li">';
673        $this->listitem_open(1);
674        $this->emphasis_open();
675            //$this->doc .= '<em>'.$lang['rssfailed'].'</em>';
676            $this->cdata($lang['rssfailed']);
677        $this->emphasis_close();
678            $this->externallink($url);
679//             if($conf['allowdebug']){
680//                 $this->doc .= '<!--'.hsc($feed->error).'-->';
681//             }
682        //  $this->doc .= '</div></li>';
683        $this->listitem_close();
684        }
685    //        $this->doc .= '</ul>';
686    $this->listu_close();
687    }
688
689  function table_open($maxcols = NULL, $numrows = NULL) {
690    $this->_current_table_mode = 'table_analyse';
691    $table_mode = $this->_current_table_mode . '_open';
692    $this->$table_mode($maxcols, $numrows);
693  }
694
695  function table_close() {
696    $table_mode = $this->_current_table_mode . '_close';
697    $this->$table_mode();
698  }
699
700  function tablerow_open() {
701    $table_mode = $this->_current_table_mode . 'row_open';
702    $this->$table_mode();
703
704  }
705
706  function tablerow_close() {
707    $table_mode = $this->_current_table_mode . 'row_close';
708    $this->$table_mode();
709  }
710
711  function tableheader_open($colspan = 1, $align = NULL) {
712    $table_mode = $this->_current_table_mode . 'header_open';
713    $this->$table_mode($colspan, $align);
714  }
715
716  function tableheader_close() {
717    $table_mode = $this->_current_table_mode . 'header_close';
718    $this->$table_mode();
719  }
720
721  function tablecell_open($colspan = 1, $align = NULL) {
722    $table_mode = $this->_current_table_mode . 'cell_open';
723    $this->$table_mode($colspan, $align);
724  }
725
726  function tablecell_close() {
727    $table_mode = $this->_current_table_mode . 'cell_close';
728    $this->$table_mode();
729  }
730
731  function table_analyse_open($maxcols = NULL, $numrows = NULL) {
732    $this->_current_table_args = array($maxcols, $numrows);
733    array_push($this->_current_table,
734           array('type' => '_open',
735             'args' => array($maxcols, $numrows)));
736  }
737
738  function table_analyse_size() { //calculate max aprox size of each cell
739    $longest_row = 0;      //and find the longest row
740    $row_len = 0;
741    $cell_len = 0;
742    $cell_word = 0;
743    $cell_text = '';
744    $i = 0;
745    $j = 0;
746    $maxcols_len = NULL;
747    $maxcols_text = NULL;
748    $maxcols_word = NULL;
749    //    msg("Memory Usage Table open: ". memory_get_usage(), -1);
750    foreach ( $this->_current_table as $action ) {
751      if ($action['type'] == 'put') {
752    $row_len += $action['size'];
753    $cell_len += $action['size'];
754    $cell_text .= $action['text'];
755    $cell_word = $action['word_size'];
756      }
757      if ($action['type'] == 'row_open') {
758    $row_len = 0;
759    $i++;
760      }
761      if ($action['type'] == 'row_close') {
762    if ($longest_row < $row_len)
763      $longest_row = $row_len;
764    $row_len = 0;
765    $j = 0;
766      }
767      if ($action['type'] == 'cell_open' || $action['type'] == 'header_open') {
768    $j++;
769      }
770      if ($action['type'] == 'cell_close' || $action['type'] == 'header_close') {
771    if ($maxcols_len[$j] < $cell_len) {
772      $maxcols_len[$j] = $cell_len;
773      $maxcols_word[$j] = $this->biggest_word_size($cell_text);
774      $maxcols_text[$j] = trim($cell_text);
775    }
776    $cell_len = 0;
777    $cell_word = 0;
778    $cell_text = '';
779      }
780    }
781    //    msg("longest row: " . $longest_row);
782    list($maxcols, $numrows) = $this->_current_table_args;
783    $max_i = 0;
784    $max = 0;
785    for ($i = 1; $i <= $maxcols; $i++) { // Make some adjustment
786      if ($max < $maxcols_len[$i]) {
787    $max = $maxcols_len[$i];
788    $max_i = $i;
789      }
790    }
791    $maxcols_word[$max_i] = NULL;
792    $this->_current_table_maxcols_size = $maxcols_word;
793    return $longest_row;
794  }
795
796  function table_analyse_close() {
797    // choose mode
798    $i = 0;
799    $j = 0;
800    list($maxcols, $numrows) = $this->_current_table_args;
801    $longest_row = $this->table_analyse_size();
802    $this->_current_table_mode = 'tabular';
803    //    msg("Memory Usage Table close: ". memory_get_usage(), -1);
804    if ($numrows > $this->info['tablemaxrows']) { // need config
805      if ($longest_row < $this->info['tablerowlength'])  //need config
806    $this->_current_table_mode = 'supertabular';
807      else
808    $this->_current_table_mode = 'supertabular_landscape';
809    } else {
810      if ($longest_row < $this->info['tablerowlength']) { //need config
811    $this->_current_table_mode = 'tabular';
812      } else {
813    $this->_current_table_mode = 'tabularx';
814      }
815    }
816    $this->putnl("%% Table analyse:");
817    $this->putnl("%%    Numrows: " . $numrows);
818    $this->putnl("%%    Longest row size: " . $longest_row);
819    $this->putnl("%%    Choose table mode: " . $this->_current_table_mode);
820
821    foreach ( $this->_current_table as $action ) { //Ouput analysed table
822      if ($action['type'] == 'row_open')
823    $i++;
824      if ($action['type'] == 'cell_open' || $action['type'] == 'header_open') {
825    $j++;
826    $this->_current_table_cols_size = $this->_current_table_maxcols_size[$j];
827      }
828      if ($action['type'] == 'row_close')
829    $j = 0;
830      if ($action['type'] == 'put') {
831    $this->put($action['text']);
832    unset($action['text']);
833      } else {
834    $table_mode = $this->_current_table_mode . $action['type'];
835    list($arg1, $arg2) = $action['args'];
836    $this->$table_mode($arg1, $arg2);
837      }
838    }
839    //msg("Memory Usage B: ". memory_get_usage(), -1);
840    $table_mode = $this->_current_table_mode . '_close';
841    $this->$table_mode($arg1, $arg2);
842    $this->_current_table_mode = NULL;
843    $this->_current_table_args = array();
844    $this->_current_table = array();
845    $this->_current_table_maxcols_size = array();
846    $this->_current_table_cols_size = 0;
847  }
848
849  function table_analyserow_open() {
850    array_push($this->_current_table,
851           array('type' => 'row_open',
852             'args' => array()));
853  }
854
855  function table_analyserow_close() {
856    array_push($this->_current_table,
857           array('type' => 'row_close',
858             'args' => array()));
859  }
860
861  function table_analyseheader_open($colspan = 1, $align = NULL) {
862    array_push($this->_current_table,
863           array('type' => 'header_open',
864             'args' => array($colspan, $align)));
865  }
866
867  function table_analyseheader_close() {
868    array_push($this->_current_table,
869           array('type' => 'header_close',
870             'args' => array()));
871  }
872
873  function table_analysecell_open($colspan = 1, $align = NULL) {
874    array_push($this->_current_table,
875           array('type' => 'cell_open',
876             'args' => array($colspan, $align)));
877  }
878
879  function table_analysecell_close() {
880    array_push($this->_current_table,
881           array('type' => 'cell_close',
882             'args' => array()));
883  }
884
885  // Table tabular way
886  function tabular_open($maxcols = NULL, $numrows = NULL) {
887    $this->_current_tab_cols = 0;
888    if ($this->info['usetablefigure'])
889      $this->putcmdnl("begin{figure}[h]");
890    else
891      $this->putcmdnl("vspace{0.8em}");
892    $this->putcmd("begin{tabular}");
893    $this->put("{");
894    for ($i = 0; $i < $maxcols; $i++) {
895      $this->put("l");
896    }
897    $this->putnl("}");
898  }
899
900  function tabular_close() {
901    $this->putcmdnl("hline");
902    $this->putcmdnl("end{tabular}");
903    if ($this->info['usetablefigure'])
904      $this->putcmdnl("end{figure}");
905    else
906      $this->putcmdnl("vspace{0.8em}");
907    $this->putnl(); //Prevent Break
908  }
909
910  function tabularrow_open() {
911    $this->putcmdnl("hline");
912    $this->_current_tab_cols = 0;
913  }
914
915  function tabularrow_close() {
916    $this->linebreak();
917    $this->putnl();
918  }
919
920  function tabularheader_open($colspan = 1, $align = NULL) {
921    $this->tablecell_open($colspan, $align);
922    $this->putcmd("dokuheadingstyle{");
923    $this->putcmd("color{dokuheadingcolor}");
924  }
925
926  function tabularheader_close() {
927    $this->putcmd("normalcolor");
928    $this->put("}");
929    $this->tablecell_close();
930  }
931
932  function tabularcell_open($colspan = 1, $align = NULL) {
933    if ($this->_current_tab_cols)
934      $this->put("&");
935    if ($colspan > 0) {
936      $this->_current_tab_colspan = 1;
937      $this->putcmd("multicolumn{". $colspan . "}");
938      $this->put("{");
939      if ($this->_current_tab_cols == 0)
940    $this->put("|");
941      switch ($align) {
942      case "right" :
943    $this->put("r");
944    break;
945      case "left" :
946    $this->put("l");
947    break;
948      case "center" :
949    $this->put("c");
950    break;
951      default:
952    $this->put("l");
953      }
954      $this->put("|}");
955      $this->put("{");
956    }
957    $this->_current_tab_cols++;
958  }
959
960  function tabularcell_close() {
961    if ($this->_current_tab_colspan = 1) {
962      $this->_current_tab_colspan = 0;
963      $this->put("}");
964    }
965  }
966
967  // Table tabularx way
968
969  function tabularx_open($maxcols = NULL, $numrows = NULL) {
970    $this->_current_tab_cols = 0;
971    if ($this->info['usetablefigure'])
972      $this->putcmdnl("begin{figure}[h]");
973    else
974      $this->putcmdnl("vspace{0.8em}");
975    $this->putcmd("begin{tabularx}{");
976    $this->putcmd("dokutabularwidth");
977    $this->put("}{|");
978    for ($i = 1; $i <= $maxcols; $i++) {
979      //      $this->put("X|");
980      if (is_null($this->_current_table_maxcols_size[$i])
981      || $this->_current_table_maxcols_size[$i] == 0
982      || $this->_current_table_maxcols_size[$i] > $this->info['biggesttableword'])
983    $this->put("X|");
984      else
985    $this->put("p{" . ($this->_current_table_maxcols_size[$i] * 0.80). "em}|");
986    }
987    $this->put("}");
988    $this->put("%% ");
989    for ($i = 1; $i <= $maxcols; $i++) {
990      if (is_null($this->_current_table_maxcols_size[$i]))
991    $this->put("X");
992      else
993    $this->put($this->_current_table_maxcols_size[$i]);
994      $this->put(" | ");
995    }
996    $this->putnl();
997  }
998
999  function tabularx_close() {
1000    $this->putcmdnl("hline");
1001    $this->putcmdnl("end{tabularx}");
1002    if ($this->info['usetablefigure'])
1003      $this->putcmdnl("end{figure}");
1004    else
1005      $this->putcmdnl("vspace{0.8em}");
1006    $this->putnl(); //Prevent Break
1007  }
1008
1009  function tabularxrow_open() {
1010    $this->putcmdnl("hline");
1011    $this->_current_tab_cols = 0;
1012  }
1013
1014  function tabularxrow_close() {
1015    $this->linebreak();
1016    $this->putnl();
1017  }
1018
1019  function tabularxheader_open($colspan = 1, $align = NULL) {
1020    $this->tablecell_open($colspan, $align);
1021    $this->putcmd("dokuheadingstyle{");
1022    $this->putcmd("color{dokuheadingcolor}");
1023  }
1024
1025  function tabularxheader_close() {
1026    $this->putcmd("normalcolor");
1027    $this->put("}");
1028    $this->tablecell_close();
1029  }
1030
1031  function tabularxcell_open($colspan = 1, $align = NULL) {
1032    if ($this->_current_tab_cols)
1033      $this->put("&");
1034    if ($colspan > 1) {
1035      $this->_current_tab_colspan = 1;
1036      $this->putcmd("multicolumn{". $colspan . "}");
1037      $this->put("{");
1038      if ($this->_current_tab_cols == 0)
1039    $this->put("|");
1040      switch ($align) {
1041      case "right" :
1042    $this->put("r");
1043    break;
1044      case "left" :
1045    $this->put("l");
1046    break;
1047      case "center" :
1048    $this->put("c");
1049    break;
1050      default:
1051    $this->put("l");
1052      }
1053      $this->put("|}");
1054      $this->put("{");
1055    } else {
1056      $this->put("{");
1057    }
1058    $this->_current_tab_cols++;
1059  }
1060
1061  function tabularxcell_close() {
1062    if ($this->_current_tab_colspan = 1) {
1063      $this->_current_tab_colspan = 0;
1064      $this->put("}");
1065    }
1066  }
1067
1068  // Table supertabular way
1069
1070  function supertabular_open($maxcols = NULL, $numrows = NULL) {
1071    $this->_current_tab_cols = 0;
1072    $this->putcmdnl('par');
1073    $this->putcmd('tablefirsthead{');
1074    $this->putcmdnl('hline}');
1075    $this->putcmd('tablehead{');
1076    $this->putcmd('hline');
1077    $this->putcmd('multicolumn{'.($maxcols).'}{|l|}{');
1078    $this->putcmd('dokusupertabularheadbreak{}');
1079    $this->put('}');
1080    $this->linebreak();
1081    $this->nlputcmd('hline');
1082    $this->putnl('}');
1083    $this->putcmd('tabletail{');
1084    $this->putcmd('hline');
1085    $this->putcmd('multicolumn{'.($maxcols).'}{|r|}{');
1086    $this->putcmd('dokusupertabulartailbreak{}');
1087    $this->put('}');
1088    $this->linebreak();
1089    $this->nlputcmd('hline');
1090    $this->putnl('}');
1091    $this->putcmdnl('tablelasttail{\hline}');
1092    $this->putcmdnl('par');
1093    //    $this->putcmd('begin{supertabular}{');
1094    //    for ($i = 0; $i < $maxcols; $i++) {
1095    //      $this->put('|p{'.((int)(14 / $maxcols * 1000)).'mm}');
1096    //    } // 14 c'est pour une feuille a4 avec les marges... il faut trouver mieux ca sux
1097    //    $this->putnl('|}');
1098    $this->putcmd("begin{supertabular}");
1099    $this->put("{");
1100    for ($i = 0; $i < $maxcols; $i++) {
1101      $this->put("l");
1102    }
1103    $this->putnl("}");
1104  }
1105
1106  function supertabular_close() {
1107    $this->putcmdnl("hline");
1108    $this->putcmdnl("end{supertabular}");
1109    $this->putcmdnl('par');
1110    $this->putnl(); //Prevent Break
1111  }
1112
1113  function supertabularrow_open() {
1114    $this->putcmdnl("hline");
1115    $this->_current_tab_cols = 0;
1116  }
1117
1118  function supertabularrow_close() {
1119    $this->linebreak();
1120    $this->putnl();
1121  }
1122
1123  function supertabularheader_open($colspan = 1, $align = NULL) {
1124    $this->tablecell_open($colspan, $align);
1125    $this->putcmd("dokuheadingstyle{");
1126    $this->putcmd("color{dokuheadingcolor}");
1127  }
1128
1129  function supertabularheader_close() {
1130    $this->putcmd("normalcolor");
1131    $this->put("}");
1132    $this->tablecell_close();
1133  }
1134
1135  function supertabularcell_open($colspan = 1, $align = NULL) {
1136    if ($this->_current_tab_cols)
1137      $this->put("&");
1138    if ($colspan > 0) {
1139      $this->_current_tab_colspan = 1;
1140      $this->putcmd("multicolumn{". $colspan . "}");
1141      $this->put("{");
1142      if ($this->_current_tab_cols == 0)
1143    $this->put("|");
1144      switch ($align) {
1145      case "right" :
1146    $this->put("r");
1147    break;
1148      case "left" :
1149    $this->put("l");
1150    break;
1151      case "center" :
1152    $this->put("c");
1153    break;
1154      default:
1155    $this->put("l");
1156      }
1157      $this->put("|}");
1158      $this->put("{");
1159    }
1160    $this->_current_tab_cols++;
1161  }
1162
1163  function supertabularcell_close() {
1164    if ($this->_current_tab_colspan = 1) {
1165      $this->_current_tab_colspan = 0;
1166      $this->put("}");
1167    }
1168  }
1169
1170
1171  // Table supertabular_landscape way
1172
1173  function supertabular_landscape_open($maxcols = NULL, $numrows = NULL) {
1174    $this->putcmdnl("begin{landscape}");
1175    $this->supertabular_open($maxcols, $numrows);
1176  }
1177
1178  function supertabular_landscape_close() {
1179    $this->putcmdnl("hline");
1180    $this->putcmdnl("end{supertabular}");
1181    $this->putcmdnl("end{landscape}");
1182  }
1183
1184  function supertabular_landscaperow_open() {
1185    $this->supertabularrow_open();
1186  }
1187
1188  function supertabular_landscaperow_close() {
1189    $this->supertabularrow_close();
1190  }
1191
1192  function supertabular_landscapeheader_open($colspan = 1, $align = NULL) {
1193    $this->supertabularheader_open($colspan, $align);
1194  }
1195
1196  function supertabular_landscapeheader_close() {
1197    $this->supertabularheader_close();
1198  }
1199
1200  function supertabular_landscapecell_open($colspan = 1, $align = NULL) {
1201    $this->supertabularcell_open($colspan, $align);
1202  }
1203
1204  function supertabular_landscapecell_close() {
1205    $this->supertabularcell_close();
1206  }
1207
1208  function mediatops($filename, $title=NULL, $align=NULL, $width=NULL,
1209             $height=NULL, $cache=NULL, $linking=NULL) {
1210    //    if ((is_null($align) || $align == 'center') && is_null($title)) {
1211    if ((is_null($align) || $align == 'center') || !is_null($title)) {
1212      return $this->mediatops_old($filename, $title, $align, $width, $height,
1213               $cache, $linking);
1214    }
1215    $img = new TexItImage($filename);
1216    if ($img->is_error) {
1217      $this->unformatted('img '. $filename . '('. $mime . '=>' . $ext . ')');
1218      return ;
1219    }
1220    $ps_filename = $img->get_output_filename();
1221    if ($ps_filename == '') {
1222      $this->unformatted('img '. $filename);
1223      return;
1224    } else {
1225      $this->putcmd("begin{wrapfigure}{", -1);
1226      if ($align == "left")
1227    $align = 'l';
1228      else if ($align == "right")
1229    $align = 'r';
1230      else if ($align == "center")
1231    $align = 'c';
1232      else
1233    $align = 'l';
1234      $this->putnl($align . "}{0pt}", -1);
1235      $this->putcmd("includegraphics", -1); // need config for that
1236      if ($width || $height) {
1237    $this->put("[", -1);
1238    if ($height)
1239      $this->put("height=" . $height. "pt", -1);
1240    if ($width && $height)
1241      $this->put(",", -1);
1242    if ($width)
1243      $this->put("width=" . $width . "pt", -1);
1244    $this->put("]", -1);
1245      }
1246      $this->put("{", -1);
1247      $this->put($img->get_output_filename(), -1);
1248      $this->put("}\n", -1);
1249      if (isset($title)) {
1250    $this->putcmd("caption{", -1);
1251    if (substr($title, 0, 5) == 'http:')
1252      $this->_formatLink(array('url' => $title,
1253                   'title' => $title,
1254                   'noflush' => 1));
1255    else
1256      $this->putent($title, -1);
1257    $this->putnl("}", -1);
1258      }
1259      $this->putcmdnl("end{wrapfigure}", -1);
1260      return $this->put_flush();
1261    }
1262  }
1263
1264  function mediatops_old($filename, $title=NULL, $align=NULL, $width=NULL,
1265             $height=NULL, $cache=NULL, $linking=NULL) {
1266      if (!empty($align) || !empty($title)) {
1267    $this->putcmdnl("begin{figure*}[h]", -1);
1268    if ($align == "left") {
1269      $align = 'flushleft';
1270      $this->putcmdnl("raggedright", -1);
1271    }
1272    if ($align == "right") {
1273      $align = 'flushright';
1274      $this->putcmdnl("raggedleft", -1);
1275    }
1276    if ($align == "center")
1277      $this->putcmdnl("centering", -1);
1278      }
1279      $this->putcmd("includegraphics", -1); // need config for that
1280      if ($width || $height) {
1281    $this->put("[", -1);
1282    if ($height)
1283      $this->put("height=" . $height. "pt", -1);
1284    if ($width && $height)
1285      $this->put(",", -1);
1286    if ($width)
1287      $this->put("width=" . $width . "pt", -1);
1288    $this->put("]", -1);
1289      }
1290      $this->put("{", -1);
1291      $this->put($filename, -1);
1292      $this->put("}\n", -1);
1293      if (!empty($title)) {
1294    $this->putcmd("caption{", -1);
1295    if (substr($title, 0, 5) == 'http:')
1296      $this->_formatLink(array('url' => $title,
1297                   'title' => $title,
1298                   'noflush' => 1));
1299    else
1300      $this->putent($title, -1);
1301    $this->putnl("}", -1);
1302      }
1303      if (!empty($align) || !empty($title)) {
1304    // if ($align != 'center') {
1305//       $this->putcmdnl("end{" . $align. "}", -1);
1306//       $this->putcmdnl("hfill", -1);
1307//     }
1308    $this->putcmdnl("end{figure*}", -1);
1309      }
1310      return $this->put_flush();
1311  }
1312
1313  function internalmedia ($src, $title=NULL, $align=NULL, $width=NULL,
1314              $height=NULL, $cache=NULL, $linking=NULL) {
1315    global $conf;
1316    global $ID;
1317    $filename = mediaFN($src);
1318    resolve_mediaid(getNS($ID),$src, $exists);
1319    list($ext,$mime) = mimetype($src);
1320    if(substr($mime,0,5) == 'image') {
1321      $img = $this->mediatops($filename, $title, $align, $width,
1322               $height, $cache, $linking);
1323      $this->put($img);
1324      return;
1325    }
1326    if ($title == NULL)
1327      $title = basename($filename);
1328    array_push($this->dokulinks, array('id' => $filename , 'name' => $title, 'type' => 'file'));
1329    $this->putcmd('hyperref[');
1330    $this->put(md5($filename));
1331    $this->put(']{');
1332    $this->putent($title);
1333    $this->put('}');
1334    //    $this->unformatted('unkown '. $filename . '('. $mime . '=>' . $ext . ')');
1335  }
1336
1337  /**
1338   * Returns the wanted cachetime in seconds
1339   *
1340   * Resolves named constants
1341   *
1342   * @author  Andreas Gohr <andi@splitbrain.org>
1343   */
1344  function calc_cache($cache) {
1345    global $conf;
1346
1347    if(strtolower($cache) == 'nocache') return 0; //never cache
1348    if(strtolower($cache) == 'recache') return $conf['cachetime']; //use standard cache
1349    return -1; //cache endless
1350  }
1351
1352  /**
1353   * Download a remote file and return local filename
1354   *
1355   * returns false if download fails. Uses cached file if available and
1356   * wanted
1357   *
1358   * @author  Andreas Gohr <andi@splitbrain.org>
1359   * @author  Pavel Vitis <Pavel.Vitis@seznam.cz>
1360   */
1361  function get_from_URL($url,$ext,$cache) {
1362    global $conf;
1363
1364    $local = getCacheName(strtolower($url),".media.$ext");
1365    $mtime = @filemtime($local); // 0 if not exists
1366
1367    //decide if download needed:
1368    if( $cache == 0 ||                             // never cache
1369    ($mtime != 0 && $cache != -1) ||           // exists but no endless cache
1370    ($mtime == 0) ||                           // not exists
1371    ($cache != -1 && $mtime < time()-$cache)   // expired
1372    ) {
1373      if(io_download($url,$local)) {
1374        return $local;
1375      }else{
1376        return false;
1377      }
1378    }
1379
1380    //if cache exists use it else
1381    if($mtime) return $local;
1382
1383    //else return false
1384    return false;
1385  }
1386
1387
1388  /**
1389   * @todo don't add link for flash
1390   */
1391  function externalmedia ($src, $title=NULL, $align=NULL, $width=NULL,
1392              $height=NULL, $cache=NULL, $linking=NULL) {
1393    global $conf;
1394
1395    list($ext,$mime) = mimetype($src);
1396    if(substr($mime,0,5) == 'image') {
1397      $filename = $this->get_from_URL($src,$ext,$this->calc_cache($cache));
1398      if(!$filename) {
1399    //download failed - redirect to original URL
1400    //make default images.
1401    $this->unformatted('externalmedia dnl error: ' . $src . ' ext: ' . $ext. ' cache: '. $cache);
1402      } else {
1403    $img = $this->mediatops($filename, $title, $align, $width,
1404                $height, $cache, $linking);
1405    $this->put($img);
1406      }
1407      return;
1408    }else{
1409      // add file icons
1410      $this->unformatted('externalmedia ' . $src);
1411    }
1412
1413    //output formatted
1414    if ($linking == 'nolink' || $noLink) $this->doc .= $link['name'];
1415    else $this->doc .= $this->_formatLink($link);
1416  }
1417
1418
1419  /**
1420   * Construct a title and handle images in titles
1421   *
1422   * @author Harry Fuecks <hfuecks@gmail.com>
1423   */
1424
1425  function _getLinkTitle($title, $default, & $isImage, $id=NULL) {
1426    global $conf;
1427
1428    $isImage = false;
1429    if ( is_null($title) ) {
1430      if ($conf['useheading'] && $id) {
1431    $heading = p_get_first_heading($id);
1432    if ($heading) {
1433      return $this->_latexEntities($heading);
1434    }
1435      }
1436      return $this->_latexEntities($default);
1437    } else if ( is_string($title) ) {
1438      return $this->_latexEntities($title);
1439    } else if ( is_array($title) ) {
1440      $isImage = true;
1441      if (isset($title['caption'])) {
1442    $title['title'] = $title['caption'];
1443      } else {
1444    $title['title'] = $default;
1445      }
1446      $title['align'] = 'center';
1447      return $this->_imageTitle($title);
1448    }
1449  }
1450
1451  function _xmlEntities($string) {
1452    return htmlspecialchars($string);
1453  }
1454
1455  function _latexEntities($string,$ent=NULL) {
1456    static $doku_ent = NULL;
1457    static $latex_ent = NULL;
1458    if (is_null($ent)) {
1459      $ent = $this->latexentities;
1460    }
1461    if ($doku_ent == NULL && $latex_ent == NULL && is_array($ent)) {
1462      $doku_ent = array_keys($ent);
1463      $latex_ent = array_values($ent);
1464    }
1465    return str_replace($doku_ent, $latex_ent, $string);
1466  }
1467
1468
1469
1470  /**
1471   * Creates a linkid from a headline
1472   *
1473   * @param string  $title   The headline title
1474   * @param boolean $create  Create a new unique ID?
1475   * @author Andreas Gohr <andi@splitbrain.org>
1476   */
1477  function _headerToLink($title,$create=false) {
1478    $title = str_replace(':','',cleanID($title,true)); //force ASCII
1479    $title = ltrim($title,'0123456789._-');
1480    if(empty($title)) $title='section';
1481
1482    if($create) {
1483      // make sure tiles are unique
1484      $num = '';
1485      while(in_array($title.$num,$this->headers)) {
1486    ($num) ? $num++ : $num = 1;
1487      }
1488      $title = $title.$num;
1489      $this->headers[] = $title;
1490    }
1491
1492    return $title;
1493  }
1494
1495
1496  /**
1497   * Renders internal and external media
1498   *
1499   * @author Andreas Gohr <andi@splitbrain.org>
1500   */
1501  function _media_test ($src, $title=NULL, $align=NULL, $width=NULL,
1502            $height=NULL, $cache=NULL) {
1503
1504    $ret = '';
1505    list($ext,$mime) = mimetype($src);
1506    if(substr($mime,0,5) == 'image') {
1507      //add image tag
1508      $ret .= ml($src,array('w'=>$width,'h'=>$height,'cache'=>$cache));
1509    } elseif(!is_null($title)) {
1510      // well at least we have a title to display
1511      $ret .= $this->_xmlEntities($title);
1512    } else {
1513      // just show the sourcename
1514      $ret .= $this->_xmlEntities(noNS($src));
1515    }
1516    return $ret;
1517  }
1518
1519  function _media($src, $title=NULL, $align=NULL, $width=NULL,
1520           $height=NULL, $cache=NULL) {
1521
1522    $ret = '';
1523    list($ext,$mime) = mimetype($src);
1524    if(substr($mime,0,5) == 'image') {
1525      $filename = mediaFN($src);
1526      if (!file_exists($filename)) {
1527    $filename = $this->get_from_URL($src,$ext,$this->calc_cache($cache));
1528    if(!$filename) {
1529      $this->unformatted('externalmedia dnl error: ' . $src . ' ext: ' . $ext. ' cache: '. $cache);
1530    }
1531      }
1532      $ret .= $this->mediatops_old($filename, $title, $align, $width,
1533                   $height, $cache, $linking);
1534
1535      //$ret .= '\\hyperimage{';
1536      //$ret .= ml($src,array('w'=>$width,'h'=>$height,'cache'=>$cache), true, '&', true);
1537      //$ret .= '}';
1538
1539    }elseif($mime == 'application/x-shockwave-flash') {
1540      $ret .= '';
1541
1542    }elseif(!is_null($title)) {
1543      // well at least we have a title to display
1544      $ret .= $this->_latexEntities($title);
1545    }else{
1546      // just show the sourcename
1547      $ret .= $this->latexEntities(noNS($src));
1548    }
1549
1550    return $ret;
1551  }
1552
1553
1554  function _media_xhtml ($src, $title=NULL, $align=NULL, $width=NULL,
1555           $height=NULL, $cache=NULL) {
1556
1557    $ret = '';
1558
1559    list($ext,$mime) = mimetype($src);
1560    if(substr($mime,0,5) == 'image') {
1561      //add image tag
1562      $ret .= '<img src="'.ml($src,array('w'=>$width,'h'=>$height,'cache'=>$cache)).'"';
1563      $ret .= ' class="media'.$align.'"';
1564
1565      if (!is_null($title)) {
1566    $ret .= ' title="'.$this->_xmlEntities($title).'"';
1567    $ret .= ' alt="'.$this->_xmlEntities($title).'"';
1568      }elseif($ext == 'jpg' || $ext == 'jpeg') {
1569    //try to use the caption from IPTC/EXIF
1570    require_once(DOKU_INC.'inc/JpegMeta.php');
1571    $jpeg =& new JpegMeta(mediaFN($src));
1572    if($jpeg !== false) $cap = $jpeg->getTitle();
1573    if($cap) {
1574      $ret .= ' title="'.$this->_xmlEntities($cap).'"';
1575      $ret .= ' alt="'.$this->_xmlEntities($cap).'"';
1576    }
1577      }else{
1578    $ret .= ' alt=""';
1579      }
1580
1581      if ( !is_null($width) )
1582    $ret .= ' width="'.$this->_xmlEntities($width).'"';
1583
1584      if ( !is_null($height) )
1585    $ret .= ' height="'.$this->_xmlEntities($height).'"';
1586
1587      $ret .= ' />';
1588
1589    }elseif($mime == 'application/x-shockwave-flash') {
1590      $ret .= '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'.
1591    ' codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"';
1592      if ( !is_null($width) ) $ret .= ' width="'.$this->_xmlEntities($width).'"';
1593      if ( !is_null($height) ) $ret .= ' height="'.$this->_xmlEntities($height).'"';
1594      $ret .= '>'.DOKU_LF;
1595      $ret .= '<param name="movie" value="'.ml($src).'" />'.DOKU_LF;
1596      $ret .= '<param name="quality" value="high" />'.DOKU_LF;
1597      $ret .= '<embed src="'.ml($src).'"'.
1598    ' quality="high"';
1599      if ( !is_null($width) ) $ret .= ' width="'.$this->_xmlEntities($width).'"';
1600      if ( !is_null($height) ) $ret .= ' height="'.$this->_xmlEntities($height).'"';
1601      $ret .= ' type="application/x-shockwave-flash"'.
1602    ' pluginspage="http://www.macromedia.com/go/getflashplayer"></embed>'.DOKU_LF;
1603      $ret .= '</object>'.DOKU_LF;
1604
1605    }elseif(!is_null($title)) {
1606      // well at least we have a title to display
1607      $ret .= $this->_xmlEntities($title);
1608    }else{
1609      // just show the sourcename
1610      $ret .= $this->_xmlEntities(noNS($src));
1611    }
1612
1613    return $ret;
1614  }
1615
1616
1617  /**
1618   * Build a link
1619   *
1620   * Assembles all parts defined in $link returns HTML for the link
1621   *
1622   * @author Andreas Gohr <andi@splitbrain.org>
1623   */
1624  function _formatLink_xhtml($link) {
1625    //make sure the url is XHTML compliant (skip mailto)
1626    if(substr($link['url'],0,7) != 'mailto:') {
1627      $link['url'] = str_replace('&','&amp;',$link['url']);
1628      $link['url'] = str_replace('&amp;amp;','&amp;',$link['url']);
1629    }
1630    //remove double encodings in titles
1631    $link['title'] = str_replace('&amp;amp;','&amp;',$link['title']);
1632
1633    // be sure there are no bad chars in url or title
1634    // (we can't do this for name because it can contain an img tag)
1635    $link['url']   = strtr($link['url'],array('>'=>'%3E','<'=>'%3C','"'=>'%22'));
1636    $link['title'] = strtr($link['title'],array('>'=>'&gt;','<'=>'&lt;','"'=>'&quot;'));
1637
1638    $ret  = '';
1639    $ret .= $link['pre'];
1640    $ret .= '<a href="'.$link['url'].'"';
1641    if($link['class'])  $ret .= ' class="'.$link['class'].'"';
1642    if($link['target']) $ret .= ' target="'.$link['target'].'"';
1643    if($link['title'])  $ret .= ' title="'.$link['title'].'"';
1644    if($link['style'])  $ret .= ' style="'.$link['style'].'"';
1645    if($link['more'])   $ret .= ' '.$link['more'];
1646    $ret .= '>';
1647    $ret .= $link['name'];
1648    $ret .= '</a>';
1649    $ret .= $link['suf'];
1650    return $ret;
1651  }
1652
1653  function _formatLink($link) {
1654    //make sure the url is XHTML compliant (skip mailto)
1655    if(substr($link['url'],0,7) != 'mailto:') {
1656
1657    }
1658
1659    $link['url'] = str_replace('#','\#',$link['url']);
1660
1661    $this->putcmd('href{'.$link['url'].'}', -1);
1662    if (isset($link['title'])) {
1663      $this->put('{', -1);
1664      $this->putent($link['title'], -1);
1665      $this->put('}', -1);
1666    }
1667
1668    if (isset($link['noflush']) && $link['noflush'] == 1)
1669      return;
1670    return $this->put_flush();
1671  }
1672
1673
1674  /**
1675   * Returns an HTML code for images used in link titles
1676   *
1677   * @todo Resolve namespace on internal images
1678   * @author Andreas Gohr <andi@splitbrain.org>
1679   */
1680  function _imageTitle($img) {
1681    return $this->_media($img['src'],
1682             $img['title'],
1683             $img['align'],
1684             $img['width'],
1685             $img['height'],
1686             $img['cache']);
1687  }
1688
1689  function _simpleTitle($name) {
1690    global $conf;
1691
1692    if($conf['useslash']) {
1693      $nssep = '[:;/]';
1694    }else{
1695      $nssep = '[:;]';
1696    }
1697    $name = preg_replace('!.*'.$nssep.'!','',$name);
1698    //if there is a hash we use the ancor name only
1699    $name = preg_replace('!.*#!','',$name);
1700    return $name;
1701  }
1702
1703
1704  //latex utils
1705
1706  function biggest_word_size($str) {
1707    $m = strlen($str) / 2;
1708    $a = 1;
1709    while ($a < $m) {
1710      $str = str_replace("  "," ",$str);
1711      $a++;
1712    }
1713    $b = explode(" ", $str);
1714    $max = 0;
1715    foreach ($b as $w) {
1716      $len = strlen($w);
1717      if ($max < $len)
1718    $max = $len;
1719    }
1720    return $max;
1721  }
1722
1723  function put_flush() {
1724    $ret = join('', $this->_tmp_put);
1725    $this->_tmp_put = array();
1726    return $ret;
1727  }
1728
1729  function put($text, $mode=0) {
1730    if ($mode == -1) {
1731      array_push($this->_tmp_put, $text);
1732      return ;
1733    }
1734    if ($this->_current_table_mode == 'table_analyse') {
1735      array_push($this->_current_table,
1736         array('type' => 'put',
1737               'text' => $text,
1738               'size' => $mode == 0 ? strlen($text) : $mode
1739               ));
1740      return;
1741    }
1742    if (is_null($this->_tmphandle))
1743      $this->doc .= $text;
1744    else
1745      fwrite($this->_tmphandle, $text);
1746  }
1747  function putent($text, $mode=0) {
1748    if ($mode != -1)
1749      $mode = strlen($text);
1750    return $this->put($this->_latexEntities($text), $mode);
1751  }
1752  function putcmd($cmd, $mode=1) {
1753    return $this->put('\\' . $cmd, $mode);
1754  }
1755  function putcmd_protect($cmd, $mode=1) {
1756    return $this->put('{\\' . $cmd . '}', $mode);
1757  }
1758  function putcmdnl($cmd, $mode=1) {
1759    $this->putcmd($cmd . DOKU_LF, $mode);
1760  }
1761  function nlputcmdnl($cmd) {
1762    $this->putnl();
1763    $this->putcmd($cmd . DOKU_LF);
1764  }
1765  function nlputcmd($cmd) {
1766    $this->putnl();
1767    $this->putcmd($cmd);
1768  }
1769  function putnl($text = NULL, $mode = 0) {
1770    if (!is_null($text)) {
1771      $this->put($text, $mode);
1772    }
1773    $this->put(DOKU_LF, $mode);
1774  }
1775  function putmathcmd($cmd) {
1776    $this->put('$'. $cmd . '$');
1777  }
1778  function putverb($text) {
1779    if ($this->state['format'] == 0)
1780      $this->putcmd("begin{verbatim}");
1781    $this->put($text);
1782    if ($this->state['format'] == 0)
1783      $this->putcmd("end{verbatim}");
1784  }
1785
1786  function add_command($text) {
1787    $this->info['command_hook'] .= $text;
1788  }
1789
1790  function add_footer($text) {
1791    $this->info['footer_hook'] .= $text;
1792  }
1793
1794  function get_info() {
1795    return $this->info;
1796  }
1797
1798  function get_clevel() { // for include plugins.
1799    return $this->_section_level;
1800  }
1801
1802}
1803
1804
1805