]> git.sur5r.net Git - bacula/docs/blob - docs/tools/translatedoc.pl
4b11848e4074932647f6ca7bf0db49834973ca57
[bacula/docs] / docs / tools / translatedoc.pl
1 #!/usr/bin/perl -w
2 #
3 # Bacula Systems - Philippe Chauvat
4 # 27 jul 2012
5 #
6 # This script is designed to translate Bacula enterprise LaTeX2HTML
7 # documentation files to something more "tunable" / "adaptable" from a CSS
8 # point of view.
9 #
10 # $1 is an HTML file to analyze and translate
11 # The output is automatically send to $1.out
12 #
13 # - add some ids, class
14 # - re-order some piece of HTML code
15 #
16 # This script is based on HTML::Parser module
17 #
18 # args:
19 # -i: HTML input file
20 # -o: HTML output file
21 # -j: javascript directory
22 # -c: css directory
23 # -p: images (pictures) directory
24 # -n: Manual name
25 # -e: Request a menu extraction
26 # -r: Source directory (ako part of -i arg)
27 # -?: help / usage
28 # -d: debug requested
29 use HTML::Parser ;
30 use HTML::TreeBuilder ;
31 use HTML::PullParser ;
32 use Getopt::Long ;
33 use File::Basename ;
34 use Data::Dumper ;
35 sub usage {
36     print "translatedoc.pl -i | --input html-source-file
37  [ -o | --output html-destination-file ]
38  [ -j | --javascript javascript-diretory ]
39  [ -c | --css css-directory ]
40  [ -p | --pictures pictures-directory ]
41  [ -n | --name manual_name ]
42  [ -e | --extract ]
43  [ -d | --debug ]
44  [ -r | --source-directory the_original_root_directory ]
45  [ --help | -? ]\n" ;
46     exit 1 ;
47 }
48 #
49 # Send message to output in case of debug only
50 # ======================
51 sub debugdump {
52     my ($what,$msg) = @_ ;
53     if ($debug) {
54         print "\n===============================\nBegin of $msg\n" ;
55         $what->dump ;
56         print "\n===============================\nEnd of $msg\n\n" ;
57     }
58 }
59 #
60 # Build a references list
61 # Needed to link text and tables, images and so on (see figure xxx)
62 # with an HTML href
63 # IN: root dir and reference filename
64 # OUT: a reference file (ako hash)
65 # =======================
66 sub build_references {
67     my $root = $_[0] ;
68     my $referencefile = $_[1] ;
69     print "Root dir: $root\n" ;
70     print "References file: $referencefile" ;
71     my %references ;
72     my @content ;
73     local *FH ;
74     for my $i (`find $root -iname "[a-zA-Z0-9]*.aux"`) {
75         print "Building references for $i\n" ;
76         open FH, "< $i" or die "Unable to open file $i\n" ;
77         @content = <FH> ;
78         close FH ;
79         for $l (@content) {
80             if ($l =~ /newlabel/) {
81 ### \newlabel{figbs6:fdstorageaddress}{{2.1}{15}{Backup Over WAN\relax \relax }{figure.caption.15}{}}
82                 my @elts = split('{|}',$l) ;
83                 if ($#elts >4) {
84                     if ($elts[1] ne "" and $elts[4] ne "") {
85                         print "Clef: $elts[1]\n" ;
86                         chomp($i) ;
87                         chomp($elts[1]) ;
88                         chomp($elts[4]) ;
89                         $references{$elts[1]}{anchor} = $elts[4] ;
90                         $references{$elts[1]}{file} = "" ;
91                         $references{$elts[4]}{latexref} = $elts[1] ;
92                     }
93                 }
94             }
95         }
96     }
97     for my $i (`find $root -iname "[a-zA-Z0-9]*.html"`) {
98         print "Building anchors for $i\n" ;
99         open FH, "< $i" or die "Unable to open file $i\n" ;
100         @content = <FH> ;
101         close FH ;
102         foreach $l (@content) {
103 #           print "ligne: $l\n" ;
104             if ($l =~ m/<A [^>]*NAME *= *"([^>]*)"/) {
105                 chomp($l) ;
106                 print "L matche: $l / $1\n" ;
107                 if (exists $references{$1}{latexref}) {
108                     print "Bingo: $i --- " . $references{$1}{latexref} . "\n" ;
109                     $references{$references{$1}{latexref}}{file} = $i ;
110                 }
111             }
112         }
113     }
114     print "Writing references\n" ;
115     open FH,"> $referencefile" or die "Unable to create file $referencefile\n" ;
116     foreach $k (keys %references) {
117         if ($references{$k}{file} ne "") {
118             print "Key: $k\n" ;
119             print FH $k . " " . $references{$k}{file} . " " . $references{$k}{anchor} . "\n" ;
120         }
121     }
122     close FH ;
123     return %references ;
124 }
125 #
126 # References reading method
127 # To be able to handle references accross HTML files
128 # =========================
129 sub read_references {
130     my $referencefile = $_[0] ;
131     my %references ;
132     local *FH ;
133     open FH, "< $referencefile" or die "Unable to open $referencefile\n" ;
134     while (<FH>) {
135         our($k,$f,$v) = split / /,$_ ;
136         $refences{$k}{file} = $f ;
137         $refences{$k}{anchor} = $v ;
138     }
139     close FH ;
140     return %refences ;
141 }
142 #
143 # Args to Vars
144 our($inputfile,$outputfile,$help,$debug,$mytree,$extractmenu,$picturesdir,
145     $cssdir,$javascriptdir,$manualname,$sourcedir) ;
146 #
147 # Usage in case of missing arguments
148 usage() unless($#ARGV > -1) ;
149 #
150 # Input file / Output file
151 GetOptions("input|i=s" => \$inputfile,
152            "output|o=s" => \$outputfile,
153            "extract|e" => \$extractmenu,
154            "pictures|p=s" => \$picturesdir,
155            "css|c=s" => \$cssdir,
156            "source-directory|r=s" => \$sourcedir,
157            "javascript|j=s" => \$javascriptdir,
158            "name|n=s" => \$manualname,
159            "debug|d" => \$debug,
160            "help|?" => \$help) or usage() ;
161 usage() if ($help) ;
162 usage() unless (defined $inputfile) ;
163
164 die "$inputfile does not exists.\n" unless -e $inputfile ;
165
166 if (! defined $outputfile ) {
167     $outputfile = "./" . basename($inputfile) . ".out" ;
168 }
169
170 if (! defined $picturesdir ) {
171     $picturesdir = "../images" ;
172 }
173
174 if (! defined $cssdir ) {
175     $cssdir = "../css" ;
176 }
177
178 if (! defined $javascriptdir ) {
179     $javascriptdir = "../js" ;
180 }
181 if (! defined $manualname) {
182     $manualname = "main" ;
183 }
184 my $MENUFILE="./wholemenu_" . $manualname . ".html" ;
185 # my $REFERENCEFILE="./references_to_build.txt" ;
186 # my %references ;
187 # if (defined $sourcedir) {
188 #     %references = build_references($sourcedir,$REFERENCEFILE) ;
189 # }
190 # else {
191 #     %references = read_references($REFERENCEFILE) ;
192 # }
193 #
194 # Build HTML Tree of existing page
195 $mytree = HTML::TreeBuilder->new ;
196 $mytree->parse_file($inputfile) ;
197 #
198 # Find the beginning of the content
199 # Which is also a point where to put
200 # the menu
201 $beginning_of_content = $mytree->look_down('_tag','h1') ;
202 $beginning_of_content = $mytree->look_down('_tag','h2') unless ($beginning_of_content) ;
203 die "The only thing we could test is a <H1> / <H2> tags, which does not exist there...:$!\n"  unless($beginning_of_content) ;
204
205 #
206 # Look for the table of contents
207 # we must translate it at a position before the content itself
208 my $thecopy ;
209 if ($thecopy = $mytree->look_down('_tag', 'ul', 'class','ChildLinks')) {
210     $childlinks = $thecopy->detach() ;
211     debugdump($thecopy,"Navigation system copy 1") ;
212 #
213 # Clean up the content of table of contents
214     while ($d = $thecopy->look_down('_tag','br')) {
215         $d->detach() ;
216         $d->delete() ;
217     }
218     debugdump($thecopy,"Navigation system copy 2") ;
219 }
220 if ($childlinks = $mytree->look_down('_tag','a','name','CHILD_LINKS')) {
221     $childlinks->detach() ;
222     $childlinks->delete() ;
223     debugdump($thecopy,"Navigation system copy 3") ;
224 }
225 #
226 # Remove old navigation part.... (next, up, previous, and so on)
227 if ($childlinks = $mytree->look_down('_tag', 'div', 'class', 'navigation')) {
228     $childlinks->detach_content() ;
229     $childlinks->detach() ;
230     $childlinks->delete_content() ;
231     $childlinks->delete ;
232     debugdump($thecopy,"Navigation system copy 4") ;
233 }
234 # End removing navigation
235 #
236 #
237 # Remove every 'dirty' lines
238 # between <body> and <h1> tag
239 # What is "before" the <h1> tag (between <body> and <h1>) is just dropped
240 my @lefts = $beginning_of_content->left() ;
241 foreach my $l (@lefts) {
242     $l->detach_content() ;
243     $l->delete_content() ;
244     $l->detach() ;
245     $l->delete() ;
246 }
247 debugdump($thecopy,"Navigation system copy 5") ;
248 #
249 # Remove Bacula community logo
250 if ($childlinks = $beginning_of_content->look_down('_tag','img','alt','\\includegraphics{bacula-logo.eps}')) {
251     $childlinks->detach() ;
252     $childlinks->delete() ;
253 }
254 # End remove Bacula logo
255 #
256 # Remove 'address' tag
257 if ($childlinks = $mytree->look_down('_tag','address')) {
258     $childlinks->detach() ;
259     $childlinks->delete() ;
260 }
261 # End remove address
262 #
263 my $thebody = $mytree->look_down('_tag','body') ;
264 $thebody->attr('onload','menuonload(this);') ;
265 debugdump($thebody,"The body BEFORE") ; 
266 my @content = $thebody->detach_content() ;
267 # End remove dirty lines
268 #
269 # What do we do with the menu?
270 # If the menu file exists then just use it
271 if (-e $MENUFILE) {
272     #
273     # Build the menu file
274     $thecopy = HTML::TreeBuilder->new ;
275     $thecopy->parse_file($MENUFILE) ;
276 }
277 debugdump($thecopy,"Navigation system copy 6") ;
278
279 #
280 #
281 # Create a div to manage the whole page
282 my $mainpage = HTML::Element->new_from_lol(
283     ['div', { 'class' => "bsys_mainpageclass", 'id' => "bsys_mainpageid" },
284      [ 'div', {'class' => 'bsys_topclass', 'id' => 'bsys_topid'},
285        [ 'img', { 'src' => $picturesdir . '/bsys-logo.png', 'id' => 'bsys_logo','alt' => 'Bacula Systems Logo' }],
286        [ 'img', { 'src' => $picturesdir . '/bsys-doctitle.png', 'id' => 'bsys_doctitle', 'alt' => 'Bacula Enterprise Documentation text image'}]
287      ],
288      [ 'div', {'id' => 'bsys_breadnsearchid', 'class' => 'bsys_breadnsearchclass'},
289        ['div', { 'class' => 'bsys_searchclass', 'id' => 'bsys_searchid'},
290         ['span','Search' , {'class' => 'bsys_searchtitleclass','id' => 'bsys_searchtitleid'}],
291         [ 'input', { 'class' => 'bsys_searchfieldclass', 'id' => 'bsys_searchfieldid', 'type' => 'text', 'value' => 'Type your text here' }]
292        ],
293        [ 'div', { 'class' => 'bsys_breadcrumbsclass', 'id' => 'bsys_breadcrumbsid'},
294          [ 'p', { 'class' => 'bsys_breadcrumbscontentclass', 'id' => 'bsys_breadcrumbscontentid' }, 'Main' ],
295        ]
296      ],
297      [ 'div', { 'class' => "bsys_pageclass", 'id' => "bsys_pageid"},
298        [ 'div', { 'class' => "bsys_leftnavigationclass", 'id' => "bsys_leftnavigationid" },
299          $thecopy
300        ],
301        [ 'div', { 'class ' => 'bsys_contentclass', 'id' => 'bsys_contentid' },
302          # foreach (@content) {
303          #     ['div', {'class' => 'bsys_truecontent'}, $_ ]
304          # }
305          [ map (('div', {'class' => 'bsys_truecontent' }), $_ ), @content ]
306        ]
307      ]
308     ]
309     ) ;
310 debugdump($mainpage,"Main page build") ;
311 $beginning_of_content = $thebody->push_content($mainpage) ;
312 # Remove "Contents" links
313 if ($childlinks = $mytree->look_down('_tag','a','href','Contents.html')) {
314     $childlinks = $childlinks->parent() ;
315     $childlinks->delete() ;
316 }
317 debugdump($thecopy,"Navigation system copy 7") ;
318 #
319 # Now begins the modification for navigation
320 # ==========================================
321 # We must analyze what is below <ul class="Child_Links">
322 # At first level, we consider each <li> as part of the main menu
323 # At other levels, we consider each <li> as sub(sub | ...)menus
324 $childlinks = $mytree->look_down('_tag','ul','class','ChildLinks') ;
325 $childlinks->attr('id','childlinksid') ;
326 #
327 # This counter is for generating unique identifiers
328 my $ulcounter = 1 ;
329 my $ullevelcounter = 0 ;
330 my $ulpreviousdepth = 0 ;
331 #
332 # Browse all the <ul name="ChildLinks"> node
333 # ------------------------------------------
334 foreach my $d ($childlinks->descendants()) {
335     #
336     # Which tag are we checking ?
337     my $tag = $d->tag() ;
338     #
339     # Nothing to do with <a> tags
340     if ($tag =~ /a/) {
341         $d->attr('onclick',"menuonclick(this);") ;
342     }
343     #
344     # <ul>s represent "openable" menus
345     elsif ($tag =~ /ul/) {
346         if ($d->depth() > $ulpreviousdepth) {
347             $ullevelcounter++ ;
348         }
349         else {
350             $ullevelcounter-- ;
351         }
352         $ulpreviousdepth=$d->depth() ;
353         #
354         # We need to identify uniquely this <ul> start tag to be able to "open" or "close" it
355         my $ullevel= 'level' . $ullevelcounter ;
356         my $idf = 'bsys_ul_' . $ulcounter++ ;
357         $d->attr('class',$ullevel . ' expandingMenu expandingMenuNotSelected') ;
358         $d->attr('id', $idf) ;
359 #       $d->attr('style','display: none;') ;
360         #
361         # We now are knowing the previous <li> tag is a (sub)menu header too
362         # Adding the "onclick" behavior
363         my $previoustagli = $d->look_up('_tag','li') ; # <li> just above
364         $previoustagli->attr('pct_onmouseover',"over_expandingMenuHeader(this,\'" . $idf . "\')") ;
365         $previoustagli->attr('pct_onmouseout',"out_expandingMenuHeader(this,\'" . $idf . "\')") ;
366         my $previoustaga = $d->left('_tag','a') ; # <a> just above
367         $previoustaga->attr('onclick',"menuonclick(this);") ;
368         #
369         # Do not forgot what we defined earlier...
370         my $class = $previoustagli->attr('class') ;
371         $class = $class . ' expandingMenuHeader' ;
372         $previoustagli->attr('class', $class) ;
373     }
374     #
375     # <li>s represent at least menu items
376     # and sometimes menu headers (see <ul> treatment)
377     elsif ($tag =~ /li/) {
378         #
379         # At this stage we only know <li> is a menu item.
380         # nothing more...
381         $d->attr('class', 'expandingMenuItem') ;
382     }
383 }
384 #
385 # <head> treatment
386 # Add some stuff
387 if ($manualname eq "main") {
388     if ($childlinks = $mytree->look_down('_tag','meta','name','description')) {
389         $childlinks->attr('content','Bacula Systems Enterprise Main Reference Manual') ;
390     }
391     if ($childlinks = $mytree->look_down('_tag','meta','name','keywords')) {
392         $childlinks->attr('content','Bacula Systems, Bacula Enterprise 6, Main Reference Manual') ;
393     }
394     if ($childlinks = $mytree->look_down('_tag','link','href','main.css')) {
395         $childlinks->attr('href',$cssdir . '/main.css') ;
396         $childlinks->postinsert(
397             HTML::Element->new_from_lol(
398                 ['link',{ 'href' => $cssdir . '/bsys.css', 'rel' => 'stylesheet' } ],
399                 ['script',{ 'type' => 'text/javascript', 'src' => $javascriptdir . '/bsys.js' } ]
400             )
401             ) ;
402     }
403 }
404 elsif ($manualname eq "developers") {
405     if ($childlinks = $mytree->look_down('_tag','meta','name','description')) {
406         $childlinks->attr('content','Bacula Systems Enterprise Developer\'s Guide') ;
407     }
408     if ($childlinks = $mytree->look_down('_tag','meta','name','keywords')) {
409         $childlinks->attr('content','Bacula Systems, Bacula Enterprise 6, Developer\'s Guide') ;
410     }
411     if ($childlinks = $mytree->look_down('_tag','link','href','developers.css')) {
412         $childlinks->attr('href',$cssdir . '/developers.css') ;
413         $childlinks->postinsert(
414             HTML::Element->new_from_lol(
415                 ['link',{ 'href' => $cssdir . '/bsys.css', 'rel' => 'stylesheet' } ],
416                 ['script',{ 'type' => 'text/javascript', 'src' => $javascriptdir . '/bsys.js' } ]
417             )
418             ) ;
419     }
420 }
421 elsif ($manualname eq "console") {
422     if ($childlinks = $mytree->look_down('_tag','meta','name','description')) {
423         $childlinks->attr('content','Bacula Enterprise Command Console and Operators Guide') ;
424     }
425     if ($childlinks = $mytree->look_down('_tag','meta','name','keywords')) {
426         $childlinks->attr('content','Bacula Systems, Bacula Enterprise 6, Command Console and Operators Guide') ;
427     }
428     if ($childlinks = $mytree->look_down('_tag','link','href','console.css')) {
429         $childlinks->attr('href',$cssdir . '/console.css') ;
430         $childlinks->postinsert(
431             HTML::Element->new_from_lol(
432                 ['link',{ 'href' => $cssdir . '/bsys.css', 'rel' => 'stylesheet' } ],
433                 ['script',{ 'type' => 'text/javascript', 'src' => $javascriptdir . '/bsys.js' } ]
434             )
435             ) ;
436     }
437 }
438 elsif ($manualname eq "utility") {
439     if ($childlinks = $mytree->look_down('_tag','meta','name','description')) {
440         $childlinks->attr('content','Bacula Enterprise Utility Programs') ;
441     }
442     if ($childlinks = $mytree->look_down('_tag','meta','name','keywords')) {
443         $childlinks->attr('content','Bacula Systems, Bacula Enterprise 6, Utility Programs') ;
444     }
445     if ($childlinks = $mytree->look_down('_tag','link','href','utility.css')) {
446         $childlinks->attr('href',$cssdir . '/utility.css') ;
447         $childlinks->postinsert(
448             HTML::Element->new_from_lol(
449                 ['link',{ 'href' => $cssdir . '/bsys.css', 'rel' => 'stylesheet' } ],
450                 ['script',{ 'type' => 'text/javascript', 'src' => $javascriptdir . '/bsys.js' } ]
451             )
452             ) ;
453     }
454 }
455 elsif ($manualname eq "problems") {
456     if ($childlinks = $mytree->look_down('_tag','meta','name','description')) {
457         $childlinks->attr('content','Bacula Enterprise Problem Resolution Guide') ;
458     }
459     if ($childlinks = $mytree->look_down('_tag','meta','name','keywords')) {
460         $childlinks->attr('content','Bacula Systems, Bacula Enterprise 6, Problem Resolution Guide') ;
461     }
462     if ($childlinks = $mytree->look_down('_tag','link','href','problems.css')) {
463         $childlinks->attr('href',$cssdir . '/problems.css') ;
464         $childlinks->postinsert(
465             HTML::Element->new_from_lol(
466                 ['link',{ 'href' => $cssdir . '/bsys.css', 'rel' => 'stylesheet' } ],
467                 ['script',{ 'type' => 'text/javascript', 'src' => $javascriptdir . '/bsys.js' } ]
468             )
469             ) ;
470     }
471 }
472 elsif ($manualname eq "misc") {
473     if ($childlinks = $mytree->look_down('_tag','meta','name','description')) {
474         $childlinks->attr('content','Bacula Enterprise Miscellaneous Guide') ;
475     }
476     if ($childlinks = $mytree->look_down('_tag','meta','name','keywords')) {
477         $childlinks->attr('content','Bacula Systems, Bacula Enterprise 6, Miscellaneous Guide') ;
478     }
479     if ($childlinks = $mytree->look_down('_tag','link','href','misc.css')) {
480         $childlinks->attr('href',$cssdir . '/misc.css') ;
481         $childlinks->postinsert(
482             HTML::Element->new_from_lol(
483                 ['link',{ 'href' => $cssdir . '/bsys.css', 'rel' => 'stylesheet' } ],
484                 ['script',{ 'type' => 'text/javascript', 'src' => $javascriptdir . '/bsys.js' } ]
485             )
486             ) ;
487     }
488 }
489 #
490 # Replace textregistered images with the HTML special char
491 my @images = $mytree->look_down('_tag','img') ;
492 foreach $childlinks (@images) {
493     my $alttext = $childlinks->attr('alt') ;
494 #    print "Alt: $alttext\n" ;
495     if ($alttext =~ /.*registe.*/) {
496         $childlinks->preinsert(HTML::Element->new_from_lol(['span', {'class' => 'expochar' }, '&reg;'])) ;
497         $childlinks->detach() ;
498         $childlinks->delete() ;
499     }
500     if ($alttext =~ /.*bacula.*-logo.*/) {
501         $childlinks->detach() ;
502         $childlinks->delete() ;
503     }
504 }
505 @images = $mytree->look_down('_tag','img') ;
506 foreach $childlinks (@images) {
507     my $img = $childlinks->attr('src') ;
508     if ($img =~ /^\.\//) {
509         $img =~ s/\.\/// ;
510         $img = $picturesdir . '/' . $img ;
511         $childlinks->attr('src',$img) ;
512         print "img: " . $img . "\n" ;
513     }
514 }
515 # This li is at first level
516 if ($outputfile) {
517     local *FH ;
518     open FH, ">" . $outputfile or die "Unable to create $outputfile: $!\n" ;
519     print FH $mytree->as_HTML("<>","\t",{}) ;
520     close FH ;
521 #     open FH, "< $outputfile" or die "Unable to open $outputfile\n" ;
522 #     my @content ;
523 #     while (my $l = <FH>) {
524 #       foreach my $k (keys %references) {
525 # #         print "==> The Clef: $k\n" ;
526 #           my $anchor = sprintf("<a href=\"%s#%s\">%s</a>",
527 #                                $references{$k}{file},
528 #                                $references{$k}{anchor},
529 #                                $k) ;
530 #           $l =~ s/$k/$anchor/g ;
531 #       }
532 #       push @content,$l ;
533 #     }
534 #     close FH ;
535 #     open FH, ">" . $outputfile or die "Unable to create $outputfile: $!\n" ;
536 #     for $l (@content) {
537 #       print FH $l ;
538 #     }
539 #     close FH ;
540 }
541 else {
542     print $mytree->as_HTML("","\t",{}) ;
543 }
544 debugdump($thecopy,"TOC Copy") ;
545 if ($extractmenu) {
546     local *FH ;
547     open FH, ">" . $MENUFILE or die "Unable to create the menu file: $!\n" ;
548     print FH $thecopy->as_HTML("","\t",{}) ;
549     close FH ;
550 }
551
552 1;