0028654: Existed tool (gendoc) for generation documentation does not take into accoun...
[occt.git] / adm / gendoc.tcl
1 # =======================================================================
2 # Created on: 2014-03-21
3 # Created by: OMY
4 # Copyright (c) 1996-1999 Matra Datavision
5 # Copyright (c) 1999-2014 OPEN CASCADE SAS
6 #
7 # This file is part of Open CASCADE Technology software library.
8 #
9 # This library is free software; you can redistribute it and/or modify it under
10 # the terms of the GNU Lesser General Public License version 2.1 as published
11 # by the Free Software Foundation, with special exception defined in the file
12 # OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
13 # distribution for complete text of the license and disclaimer of any warranty.
14 #
15 # Alternatively, this file may be used under the terms of Open CASCADE
16 # commercial license or contractual agreement.
17  
18 # =======================================================================
19 # This script defines command gendoc compiling OCCT documents 
20 # from *.md files to HTML pages
21 # =======================================================================
22
23 # load auxiliary tools
24 source [file join [file dirname [info script]] occaux.tcl]
25
26 # ======================================
27 #  Common functions
28 # ======================================
29
30 # Prints help message
31 proc OCCDoc_PrintHelpMessage {} {
32     puts "\nUsage: gendoc \[-h\] {-refman|-overview} \[-html|-pdf|-chm\] \[-m=<list of modules>|-ug=<list of docs>\] \[-v\] \[-s=<search_mode>\] \[-mathjax=<path>\]"
33     puts ""
34     puts "Options are:"
35     puts ""
36     puts "choice of documentation to be generated:"
37     puts "  -overview          : To generate Overview and User Guides"
38     puts "                       (cannot be used with -refman)"
39     puts "  -refman            : To generate class Reference Manual"
40     puts "                       (cannot be used with -overview)"
41     puts ""
42     puts "choice of output format:"
43     puts "  -html              : To generate HTML files"
44     puts "                       (default, cannot be used with -pdf or -chm)"
45     puts "  -pdf               : To generate PDF files"
46     puts "                       (cannot be used with -refman, -html, or -chm)"
47     puts "  -chm               : To generate CHM files"
48     puts "                       (cannot be used with -html or -pdf)"
49     puts ""
50     puts "additional options:"
51     puts "  -m=<modules_list>  : List of OCCT modules (separated with comma),"
52     puts "                       for generation of Reference Manual"
53     puts "  -ug=<docs_list>    : List of MarkDown documents (separated with comma),"
54     puts "                       to use for generation of Overview / User Guides"
55     puts "  -mathjax=<path>    : To use local or alternative copy of MathJax"
56     puts "  -s=<search_mode>   : Specifies the Search mode of HTML documents"
57     puts "                       Can be: none | local | server | external"
58     puts "  -h                 : Prints this help message"
59     puts "  -v                 : Enables more verbose output"
60 }
61
62 # A command for User Documentation compilation
63 proc gendoc {args} {
64
65   # Parameters
66   set DOC_TYPE                  "REFMAN"
67   set GEN_MODE                  "HTML_ONLY"
68   set DOCFILES                  {}
69   set MODULES                   {}
70   set DOCLABEL                  ""
71   set VERB_MODE                 "NO"
72   set SEARCH_MODE               "none"
73   set MATHJAX_LOCATION          "https://cdn.mathjax.org/mathjax/latest"
74   set mathjax_js_name           "MathJax.js"
75   set DOCTYPE_COMBO_FLAG        0
76   set GENMODE_COMBO_FLAG        0
77   set GENERATE_PRODUCTS_REFMAN "NO"
78
79   global available_docfiles;   # The full list of md files for HTML or CHM generation
80   global available_pdf;        # The full list of md files for PDF generation
81   global tcl_platform
82   global args_names
83   global args_values
84   global env
85
86   # Load list of docfiles
87   if { [OCCDoc_LoadFilesList] != 0 } {
88     puts "Error: File FILES_HTML.txt or FILES_PDF.txt was not found on this computer.\nAborting..."
89     return -1
90   }
91
92   # Parse CL arguments
93   if {[OCCDoc_ParseArguments $args] == 1} {
94     return -1
95   }
96
97   # Print help message if no arguments provided
98   if {[llength $args_names] == 0} {
99     OCCDoc_PrintHelpMessage
100     return 0
101   }
102
103   foreach arg_n $args_names {
104     if {$arg_n == "h"} {
105       OCCDoc_PrintHelpMessage
106       return 0
107     } elseif {$arg_n == "html"} {
108       if { ([ lsearch $args_names "refman" ]   == -1) &&
109            ([ lsearch $args_names "overview" ] == -1) } {
110         puts "Warning: Please specify -refman or -overview argument."
111         return -1
112       }
113       if { [ lsearch $args_names "refman" ] != -1 } {
114         continue
115       }
116       if { $GENMODE_COMBO_FLAG != 1 } {
117         set GEN_MODE "HTML_ONLY"
118         set GENMODE_COMBO_FLAG 1
119       } else {
120         puts "Error: Options -html, -pdf and -chm can not be combined."
121         return -1
122       }
123     } elseif {$arg_n == "chm"} {
124       if { ([ lsearch $args_names "refman" ]   == -1) &&
125            ([ lsearch $args_names "overview" ] == -1) } {
126         puts "Warning: Please specify -refman or -overview argument."
127         return -1
128       }
129       if { [ lsearch $args_names "refman" ] != -1 } {
130         continue
131       }
132       if { $GENMODE_COMBO_FLAG != 1 } { 
133         set GEN_MODE "CHM_ONLY"
134         set GENMODE_COMBO_FLAG 1
135       } else {
136         puts "Error: Options -html, -pdf and -chm cannot be combined."
137         return -1
138       }
139     } elseif {$arg_n == "pdf"} {
140       if { ([ lsearch $args_names "refman" ]   == -1) &&
141            ([ lsearch $args_names "overview" ] == -1) } {
142         puts "Warning: Please specify -refman or -overview argument."
143         return -1
144       }
145       if { [ lsearch $args_names "refman" ] != -1 } {
146         continue
147       }
148       if { $GENMODE_COMBO_FLAG != 1 } { 
149         set GEN_MODE "PDF_ONLY"
150         set GENMODE_COMBO_FLAG 1
151       } else {
152         puts "Error: Options -html, -pdf and -chm cannot be combined."
153         return -1
154       }
155     } elseif {$arg_n == "overview"} {
156       if { $DOCTYPE_COMBO_FLAG != 1 } {
157         set DOC_TYPE "OVERVIEW"
158         set DOCTYPE_COMBO_FLAG 1
159       } else {
160         puts "Error: Options -refman and -overview cannot be combined."
161         return -1
162       }
163
164       # Print ignored options
165       if { [ lsearch $args_names "m" ] != -1 } {
166         puts "\nInfo: The following options will be ignored: \n"
167         puts "  * -m"
168       }
169       puts ""
170     } elseif {$arg_n == "refman"} {
171       if { $DOCTYPE_COMBO_FLAG != 1 } { 
172         set DOC_TYPE "REFMAN"
173         set DOCTYPE_COMBO_FLAG 1
174         if { [file exists [OCCDoc_GetProdRootDir]/src/VAS/Products.tcl] } {
175           set GENERATE_PRODUCTS_REFMAN "YES"
176         }
177       } else {
178         puts "Error: Options -refman and -overview cannot be combined."
179         return -1
180       }
181       # Print ignored options
182       if { ([ lsearch $args_names "pdf" ]     != -1) || 
183            ([ lsearch $args_names "chm" ]     != -1) || 
184            ([ lsearch $args_names "ug" ]      != -1) } {
185         puts "\nInfo: The following options will be ignored: \n"
186         if { [ lsearch $args_names "pdf" ] != -1 } {
187           puts "  * -pdf"
188         }
189         if { [ lsearch $args_names "chm" ] != -1 } {
190           puts "  * -chm"
191         }
192         if { [ lsearch $args_names "ug" ] != -1 } {
193           puts "  * -ug"
194         }
195         puts ""
196       }
197       
198     } elseif {$arg_n == "v"} {
199       set VERB_MODE "YES"
200     } elseif {$arg_n == "ug"} {
201       if { ([ lsearch $args_names "refman" ]   != -1) } {
202         continue
203       }
204       if {$args_values(ug) != "NULL"} {
205         set DOCFILES $args_values(ug)
206       } else {
207         puts "Error in argument ug."
208         return -1
209       }
210       # Check if all chosen docfiles are correct
211       foreach docfile $DOCFILES {
212         if { [ lsearch $args_names "pdf" ] == -1 } {
213           # Check to generate HTMLs
214           if { [lsearch $available_docfiles $docfile] == -1 } {
215             puts "Error: File \"$docfile\" is not presented in the list of available docfiles."
216             puts "       Please specify the correct docfile name."
217             return -1
218           } 
219         } else {
220           # Check to generate PDFs
221           if { [lsearch $available_pdf $docfile] == -1 } {
222             puts "Error: File \"$docfile\" is not presented in the list of generic PDFs."
223             puts "       Please specify the correct pdf name."
224             return -1
225           }
226         }
227       }
228     } elseif {$arg_n == "m"} {
229       if { [ lsearch $args_names "overview" ] != -1 } {
230         continue
231       }
232       if {$args_values(m) != "NULL"} {
233         set MODULES $args_values(m)
234       } else {
235         puts "Error in argument m."
236         return -1
237       }
238     } elseif {$arg_n == "s"} {
239       if { [ lsearch $args_names "pdf" ] != -1 } {
240         continue
241       }
242       if {$args_values(s) != "NULL"} {
243         set SEARCH_MODE $args_values(s)
244       } else {
245         puts "Error in argument s."
246         return -1
247       }
248     } elseif {$arg_n == "mathjax"} {
249       if { [ lsearch $args_names "pdf" ] != -1 } {
250         set possible_mathjax_loc $args_values(mathjax)
251         if {[file exist [file join $possible_mathjax_loc $mathjax_js_name]]} {
252           set MATHJAX_LOCATION $args_values(mathjax)
253           puts "$MATHJAX_LOCATION"
254         } else {
255           puts "Warning: $mathjax_js_name is not found in $possible_mathjax_loc."
256           puts "         MathJax will be used from $MATHJAX_LOCATION"
257         }
258       } else {
259         puts "Warning: MathJax is not used with pdf and will be ignored."
260       }
261     } else {
262       puts "\nWrong argument: $arg_n"
263       OCCDoc_PrintHelpMessage
264       return -1
265     }
266   }
267
268   # Check the existence of the necessary tools
269   set DOXYGEN_PATH  ""
270   set GRAPHVIZ_PATH ""
271   set INKSCAPE_PATH ""
272   set PDFLATEX_PATH ""
273   set HHC_PATH      ""
274
275   OCCDoc_DetectNecessarySoftware $DOXYGEN_PATH $GRAPHVIZ_PATH $INKSCAPE_PATH $HHC_PATH $PDFLATEX_PATH
276
277   if {$DOXYGEN_PATH == ""} {
278     puts " Aborting..."
279     return -1
280   }
281
282   if {"$::tcl_platform(platform)" == "windows"} {
283     if { ($GEN_MODE == "CHM_ONLY") && ($HHC_PATH == "") } {
284       puts " Aborting..."
285       return -1
286     }
287   }
288
289   if { ($PDFLATEX_PATH == "") && ($GEN_MODE == "PDF_ONLY") } {
290     puts " Aborting..."
291     return -1
292   }
293
294   # If we do not specify list for docfiles with -m argument,
295   # we assume that we have to generate all docfiles
296   if { [llength $DOCFILES] == 0 } {
297     if { $GEN_MODE != "PDF_ONLY" } {
298       set DOCFILES $available_docfiles
299     } else {
300       set DOCFILES $available_pdf
301     }
302   }
303
304   puts ""
305
306   # Clean logfiles
307   set DOXYLOG [OCCDoc_GetRootDir]/doc/doxygen_warnings_and_errors.log
308   set PDFLOG  [OCCDoc_GetRootDir]/doc/pdflatex_warnings_and_errors.log
309
310   file delete -force $PDFLOG
311   file delete -force $DOXYLOG
312   
313   # Start main activities
314   if { $GEN_MODE != "PDF_ONLY" } {
315     if { [OCCDoc_GetProdRootDir] == ""} {
316       OCCDoc_Main $DOC_TYPE $DOCFILES $MODULES $GEN_MODE $VERB_MODE $SEARCH_MODE $MATHJAX_LOCATION $GENERATE_PRODUCTS_REFMAN $DOXYGEN_PATH $GRAPHVIZ_PATH $INKSCAPE_PATH $HHC_PATH
317     } else {
318       if { $DOC_TYPE == "REFMAN" } {
319         if { $MODULES != "" } {
320           foreach module $MODULES {
321             OCCDoc_Main $DOC_TYPE $DOCFILES $module $GEN_MODE $VERB_MODE $SEARCH_MODE $MATHJAX_LOCATION $GENERATE_PRODUCTS_REFMAN $DOXYGEN_PATH $GRAPHVIZ_PATH $INKSCAPE_PATH $HHC_PATH
322           }
323         } else {
324           OCCDoc_Main $DOC_TYPE $DOCFILES $MODULES $GEN_MODE $VERB_MODE $SEARCH_MODE $MATHJAX_LOCATION $GENERATE_PRODUCTS_REFMAN $DOXYGEN_PATH $GRAPHVIZ_PATH $INKSCAPE_PATH $HHC_PATH
325         }
326       } else {
327         foreach md $DOCFILES {
328           OCCDoc_Main $DOC_TYPE $md $MODULES $GEN_MODE $VERB_MODE $SEARCH_MODE $MATHJAX_LOCATION $GENERATE_PRODUCTS_REFMAN $DOXYGEN_PATH $GRAPHVIZ_PATH $INKSCAPE_PATH $HHC_PATH
329         }
330       }
331     }
332   } else {
333     puts "Generating OCCT User Guides in PDF format...\n"
334     foreach pdf $DOCFILES {
335
336       puts "Info: Processing file $pdf\n"
337
338       # Some values are hardcoded because they are related only to PDF generation
339       OCCDoc_Main "OVERVIEW" [list $pdf] {} "PDF_ONLY" $VERB_MODE "none" $MATHJAX_LOCATION "NO" $DOXYGEN_PATH $GRAPHVIZ_PATH $INKSCAPE_PATH $HHC_PATH
340     }
341     puts "[clock format [clock seconds] -format {%Y-%m-%d %H:%M}] Generation completed."
342   }
343 }
344
345 # Main procedure for documents compilation
346 proc OCCDoc_Main {docType {docfiles {}} {modules {}} generatorMode verboseMode searchMode mathjaxLocation generateProductsRefman DOXYGEN_PATH GRAPHVIZ_PATH INKSCAPE_PATH HHC_PATH} {
347
348   global available_docfiles
349   global available_pdf
350
351   set ROOTDIR    [OCCDoc_GetRootDir [OCCDoc_GetProdRootDir]]
352   set INDIR      [OCCDoc_GetDoxDir]
353   set OUTDIR     $ROOTDIR/doc
354   set PDFDIR     $OUTDIR/pdf
355   set UGDIR      $PDFDIR/user_guides
356   set DGDIR      $PDFDIR/dev_guides
357   set TAGFILEDIR $OUTDIR/refman
358   set HTMLDIR    $OUTDIR/overview/html
359   set LATEXDIR   $OUTDIR/overview/latex
360   set DOXYFILE   $OUTDIR/OCCT.cfg
361
362   # OUTDIR for products documentation should be separate directories for each components
363   if { [OCCDoc_GetProdRootDir] != ""} {
364     if { $docType == "REFMAN" } {
365       if { "$modules" != "" } {
366         source "[OCCDoc_GetSourceDir [OCCDoc_GetProdRootDir]]/VAS/${modules}.tcl"
367         set doc_component_name [${modules}:documentation_name]
368         set OUTDIR     $OUTDIR/$doc_component_name
369       }
370     } else {
371       if {[regexp {([^/]+)/([^/]+)/([^/]+)} $docfiles dump doc_type doc_component doc_name]} {
372         set PDFNAME [file rootname $doc_name]
373         set OUTDIR     $OUTDIR/$doc_component
374       } else {
375         error "Could not parse input path to *.md file: \"${docfiles}\""
376       }
377     }
378     set HTMLDIR    $OUTDIR/html
379     set LATEXDIR   $OUTDIR/latex
380     set DOXYFILE   $OUTDIR/OCCT.cfg
381     set TAGFILEDIR $OUTDIR/refman
382   }
383
384   # Create or cleanup the output folders
385   if { [string compare -nocase $generateProductsRefman "YES"] != 0 } {
386     if { ![file exists $OUTDIR] } {
387       file mkdir $OUTDIR
388     } 
389     if { ![file exists $HTMLDIR] } {
390       file mkdir $HTMLDIR
391     }
392     if { [OCCDoc_GetProdRootDir] == ""} {
393       if { ![file exists $PDFDIR] } {
394         file mkdir $PDFDIR
395       }
396       if { ![file exists $UGDIR] } {
397         file mkdir $UGDIR
398       }
399       if { ![file exists $DGDIR] } {
400         file mkdir $DGDIR
401       }
402     }
403
404     if { $generatorMode == "PDF_ONLY" } {
405       if { [file exists $LATEXDIR] } {
406         file delete -force $LATEXDIR
407       }
408       file mkdir $LATEXDIR
409     }
410   }
411   if { $docType == "REFMAN" } {
412     if { ![file exists $TAGFILEDIR] } {
413       file mkdir $TAGFILEDIR
414     }
415   }
416
417   # is MathJax HLink?
418   set mathjax_relative_location $mathjaxLocation
419   if { [file isdirectory "$mathjaxLocation"] } {
420     if { $generatorMode == "HTML_ONLY" } {
421       # related path
422       set mathjax_relative_location [OCCDoc_GetRelPath $HTMLDIR $mathjaxLocation]
423     } elseif { $generatorMode == "CHM_ONLY" } {
424       # absolute path
425       set mathjax_relative_location [file normalize $mathjaxLocation]
426     }
427   }
428
429   if { $generateProductsRefman == "YES" } {
430     set DOCDIR "$OUTDIR/refman"
431     puts "\nGenerating OCC Products Reference Manual\n"
432   } else {
433     if { $docType == "REFMAN"} {
434       set DOCDIR "$OUTDIR/refman"
435       puts "\nGenerating Open CASCADE Reference Manual\n"
436     } elseif { $docType == "OVERVIEW" } {
437       if { [OCCDoc_GetProdRootDir] == ""} {
438         set DOCDIR "$OUTDIR/overview"
439       } else {
440         set DOCDIR "$OUTDIR"
441       }
442       set FORMAT ""
443       if { ($generatorMode == "HTML_ONLY") || ($generatorMode == "CHM_ONLY") } {
444         if { $generatorMode == "HTML_ONLY" } { 
445           set FORMAT " in HTML format..."
446         } elseif { $generatorMode == "CHM_ONLY" } {
447           set FORMAT " in CHM format..."
448         }
449         puts "Generating OCCT User Guides$FORMAT\n"
450       }
451     } else {
452       puts "Error: Invalid documentation type: $docType. Can not process."
453       return -1
454     }
455   }
456
457   # Generate Doxyfile
458   puts "[clock format [clock seconds] -format {%Y-%m-%d %H:%M}] Generating Doxyfile..."
459
460   if { [OCCDoc_MakeDoxyfile $docType $DOCDIR $TAGFILEDIR $DOXYFILE $generatorMode $docfiles $modules $verboseMode $searchMode $HHC_PATH $mathjax_relative_location $GRAPHVIZ_PATH [OCCDoc_GetProdRootDir]] == -1 } {
461     return -1
462   }
463
464   # Run doxygen tool
465   set starttimestamp [clock format [clock seconds] -format {%Y-%m-%d %H:%M}]
466
467   if { ($generatorMode == "HTML_ONLY") || ($docType == "REFMAN") } {
468     puts "$starttimestamp Generating HTML files..."
469
470     # Copy index file to provide fast access to HTML documentation
471     file copy -force $INDIR/resources/index.html $DOCDIR/index.html
472   } elseif { $generatorMode == "CHM_ONLY" } {
473     puts "$starttimestamp Generating CHM file..."
474   } elseif { $generatorMode == "PDF_ONLY" } {
475     puts "$starttimestamp Generating PDF file..."
476   }
477
478   set DOXYLOG $OUTDIR/doxygen_warnings_and_errors.log
479   set RESULT [catch {exec $DOXYGEN_PATH $DOXYFILE >> $OUTDIR/doxygen_out.log} DOX_ERROR] 
480   if {$RESULT != 0} {
481     set NbErrors [regexp -all -line {^\s*[^\s]+} $DOX_ERROR]
482     if {$NbErrors > 0} {
483       puts "\nWarning: Doxygen reported $NbErrors messages."
484       puts "See log in $DOXYLOG\n"
485       set DOX_ERROR_FILE [open $DOXYLOG "a"]
486       if {$generatorMode == "PDF_ONLY"} {
487         puts $DOX_ERROR_FILE "\n===================================================="
488         puts $DOX_ERROR_FILE "Logfile for $docfiles"
489         puts $DOX_ERROR_FILE "====================================================\n"
490       }
491       puts $DOX_ERROR_FILE $DOX_ERROR
492       close $DOX_ERROR_FILE
493     }
494   }
495
496   # Close the Doxygen application
497   after 300
498
499   # Start Post Processing
500   set curtime [clock format [clock seconds] -format {%Y-%m-%d %H:%M}]
501   if { $docType == "REFMAN" } {
502     # Post Process generated HTML pages and draw dependency graphs
503     if {[OCCDoc_PostProcessor $DOCDIR] == 0} {
504       puts "$curtime Generation completed."
505       puts "\nInfo: doxygen log file is located in:"
506       puts "$OUTDIR/doxygen_out.log."
507       puts "\nReference Manual is generated in \n$DOCDIR"
508     }
509   } elseif { $docType == "OVERVIEW" } {
510     # Start PDF generation routine
511     if { $generatorMode == "PDF_ONLY" } {
512       set OS $::tcl_platform(platform)
513       if { $OS == "unix" } {
514         set PREFIX ".sh"
515       } elseif { $OS == "windows" } {
516         set PREFIX ".bat"
517       }
518
519       # Prepare a list of TeX files, generated by Doxygen
520       cd $LATEXDIR
521
522       set TEXFILES   [glob $LATEXDIR -type f -directory $LATEXDIR -tails "*.tex" ]
523       foreach path $TEXFILES {
524         if { [string compare -nocase $path $LATEXDIR] == 0 } {
525           set DEL_IDX [lsearch $TEXFILES $path]
526           if { $DEL_IDX != -1 } {
527             set TEXFILES [lreplace $TEXFILES $DEL_IDX $DEL_IDX]
528           }
529         }
530       }
531       set TEXFILES   [string map [list refman.tex ""] $TEXFILES]
532       if {$verboseMode == "YES"} {
533         puts "Info: Preprocessing generated TeX files..."
534       }
535       OCCDoc_ProcessTex $TEXFILES $LATEXDIR $verboseMode
536
537       if {$verboseMode == "YES"} {
538         puts "Info: Converting SVG images to PNG format..."
539       }
540
541       if { $INKSCAPE_PATH != "" } {
542         OCCDoc_ProcessSvg $LATEXDIR $verboseMode
543       } else {
544         puts "Warning: SVG images will be lost in PDF documents."
545       }
546
547       if {$verboseMode == "YES"} {
548         puts "Info: Generating PDF file from TeX files..."
549       }
550       foreach TEX $TEXFILES {
551         # Rewrite existing REFMAN.tex file...
552         set TEX [lindex [split $TEX "."] 0]
553
554         if {$verboseMode == "YES"} {
555           puts "Info: Generating PDF file from $TEX..."
556         }
557
558         OCCDoc_MakeRefmanTex $TEX $LATEXDIR $verboseMode $available_pdf
559
560         if {"$::tcl_platform(platform)" == "windows"} {
561           set is_win "yes"
562         } else {
563           set is_win "no"
564         }
565         if {$verboseMode == "YES"} {
566           # ...and use it to generate PDF from TeX...
567           if {$is_win == "yes"} {
568             puts "Info: Executing $LATEXDIR/make.bat..."
569           } else {
570             puts "Info: Executing $LATEXDIR/Makefile..."
571           }
572         }
573         set PDFLOG $OUTDIR/pdflatex_warnings_and_errors.log
574
575         if {"$is_win" == "yes"} {
576           set RESULT [catch {eval exec [auto_execok $LATEXDIR/make.bat] >> "$OUTDIR/pdflatex_out.log"} LaTeX_ERROR]
577         } else {
578           set RESULT [catch {eval exec "make -f $LATEXDIR/Makefile" >> "$OUTDIR/pdflatex_out.log"} LaTeX_ERROR]
579
580           # Small workaround for *nix stations
581           set prev_loc [pwd]
582           cd $LATEXDIR
583           set RESULT [catch {eval exec "pdflatex refman.tex" >> "$OUTDIR/pdflatex_out.log"} LaTeX_ERROR]
584           cd $prev_loc
585         }
586
587         if {$RESULT != 0} {
588           set NbErrors [regexp -all -line {^\s*[^\s]+} $LaTeX_ERROR]
589           if {$NbErrors > 0} {
590             puts "\nWarning: PDFLaTeX reported $NbErrors messages.\nSee log in $PDFLOG\n"
591             set LaTeX_ERROR_FILE [open $PDFLOG "a"]
592             puts $LaTeX_ERROR_FILE "\n===================================================="
593             puts $LaTeX_ERROR_FILE "Logfile of file $TEX:"
594             puts $LaTeX_ERROR_FILE "====================================================\n"
595             puts $LaTeX_ERROR_FILE $LaTeX_ERROR
596             close $LaTeX_ERROR_FILE
597           }
598         }
599
600         # ...and place it to the specific folder
601         if {![file exists "$LATEXDIR/refman.pdf"]} {
602           puts "Fatal: PDFLaTeX failed to create output file, stopping!"
603           return -1
604         }
605
606         set destFolder $PDFDIR
607         set parsed_string [split $TEX "_"]
608         if { [OCCDoc_GetProdRootDir] == ""} {
609           if { [lsearch $parsed_string "tutorial"] != -1 } {
610             set TEX [string map [list occt__ occt_] $TEX]
611             set destFolder $PDFDIR
612           } elseif { [lsearch $parsed_string "user"] != -1 } {
613             set TEX [string map [list user_guides__ ""] $TEX]
614             set destFolder $UGDIR
615           } elseif { [lsearch $parsed_string "dev"]  != -1 } {
616             set TEX [string map [list dev_guides__ ""] $TEX]
617             set destFolder $DGDIR
618           }
619         } else {
620           set destFolder $OUTDIR
621           set TEX "$PDFNAME"
622         }
623         file rename -force $LATEXDIR/refman.pdf "$destFolder/$TEX.pdf"
624       }
625     } elseif { $generatorMode == "CHM_ONLY" } {
626       if { [OCCDoc_GetProdRootDir] == ""} {
627         file rename $OUTDIR/overview.chm $OUTDIR/occt_overview.chm
628       } else {
629         file rename -force $ROOTDIR/doc/overview.chm $OUTDIR/occt_overview.chm
630       }
631     }
632     cd $INDIR
633
634     if { $generatorMode == "HTML_ONLY" } {
635       puts "\nHTML documentation is generated in \n$DOCDIR"
636     }
637     if { $generatorMode == "CHM_ONLY" } {
638       puts "\nGenerated CHM documentation is in \n$OUTDIR/overview.chm"
639     }
640
641     puts ""
642   }
643
644   # Remove temporary Doxygen files
645   set deleteList [glob -nocomplain -type f "*.tmp"]
646   foreach file $deleteList {
647     file delete $file
648   }
649
650   puts "\nPDF files are generated in \n[file normalize $OUTDIR]"
651
652   return 0
653 }
654
655 # Generates Doxygen configuration file for Overview documentation
656 proc OCCDoc_MakeDoxyfile {docType outDir tagFileDir {doxyFileName} {generatorMode ""} {DocFilesList {}} {ModulesList {}} verboseMode searchMode hhcPath mathjaxLocation graphvizPath productsPath} {
657   set inputDir      [OCCDoc_GetDoxDir [OCCDoc_GetProdRootDir]]
658
659   set TEMPLATES_DIR [OCCDoc_GetDoxDir]/resources
660   set occt_version  [OCCDoc_DetectCasVersion]
661
662   # Delete existent doxyfile
663   file delete $doxyFileName
664
665   # Copy specific template to the target folder
666   if { $docType == "REFMAN" } {
667     file copy "$TEMPLATES_DIR/occt_rm.doxyfile" $doxyFileName
668   } elseif { $docType == "OVERVIEW" } {
669     if { $generatorMode == "HTML_ONLY" || $generatorMode == "CHM_ONLY" } {
670       file copy "$TEMPLATES_DIR/occt_ug_html.doxyfile" $doxyFileName
671     } elseif { $generatorMode == "PDF_ONLY"} {
672       file copy "$TEMPLATES_DIR/occt_ug_pdf.doxyfile" $doxyFileName
673     } else {
674       puts "Error: Unknown generation mode"
675       return -1
676     }
677   } else {
678     puts "Error: Cannot generate unknown document type"
679     return -1
680   }
681
682   set doxyFile [open $doxyFileName "a"]
683   # Write specific options
684   if { $docType == "REFMAN" } {
685
686     # Load lists of modules scripts
687     if { $productsPath == "" } {
688       set modules_scripts [glob -nocomplain -type f -directory "[OCCDoc_GetSourceDir $productsPath]/OS/" *.tcl]
689     } else {
690       set modules_scripts [glob -nocomplain -type f -directory "[OCCDoc_GetSourceDir $productsPath]/VAS/" *.tcl]
691     }
692     if { [llength $modules_scripts] != 0} {
693       foreach module_file $modules_scripts {
694         source $module_file
695       }
696     }
697
698     set ALL_MODULES [OCCDoc_GetModulesList $productsPath]
699     if { [llength $ModulesList] == 0 } {
700       # by default take all modules
701       set modules $ALL_MODULES
702     } else {
703       set modules $ModulesList
704     }
705
706     # Detect invalid names of modules
707     foreach module $modules {
708       if { $module == "" } {
709         continue
710       }
711       if {[lsearch $ALL_MODULES $module] == -1 } {
712         puts "Error: No module $module is known. Aborting..."
713         return -1
714       }
715     }
716
717     # Set context
718     set one_module [expr [llength $modules] == 1]
719     if { $one_module } {
720       set title "OCCT [$modules:name]"
721       set name $modules
722     } else {
723       set title "Open CASCADE Technology"
724       set name OCCT
725     }
726
727     # Get list of header files in the specified modules
728     set filelist {}
729     foreach module $modules {
730       if { $module == "" } {
731         continue
732       }
733       foreach tk [$module:toolkits] {
734         foreach pk [split [OCCDoc_GetPackagesList [OCCDoc_Locate $tk $productsPath]]] {
735           if { [llength $pk] != "{}" } {
736             lappend filelist [OCCDoc_GetHeadersList "p" "$pk" "$productsPath"]
737           }
738         }
739       }
740     }
741
742     # Filter out files Handle_*.hxx and *.lxx
743     set hdrlist {}
744     foreach fileset $filelist {
745       set hdrset {}
746       foreach hdr $fileset {
747         if { ! [regexp {Handle_.*[.]hxx} $hdr] && ! [regexp {.*[.]lxx} $hdr] } {
748           lappend hdrset $hdr
749         }
750       }
751       lappend hdrlist $hdrset
752     }
753     set filelist $hdrlist
754
755     set doxyFile [open $doxyFileName "a"]
756   
757     puts $doxyFile "PROJECT_NAME           = \"$title\""
758     puts $doxyFile "PROJECT_NUMBER         = $occt_version"
759     puts $doxyFile "OUTPUT_DIRECTORY       = $outDir/."
760     puts $doxyFile "GENERATE_TAGFILE       = $outDir/${name}.tag"
761
762     if { [string tolower $searchMode] == "none" } {
763       puts $doxyFile "SEARCHENGINE           = NO"
764       puts $doxyFile "SERVER_BASED_SEARCH    = NO"
765       puts $doxyFile "EXTERNAL_SEARCH        = NO"
766     } else {
767       puts $doxyFile "SEARCHENGINE           = YES"
768       if { [string tolower $searchMode] == "local" } {
769         puts $doxyFile "SERVER_BASED_SEARCH    = NO"
770         puts $doxyFile "EXTERNAL_SEARCH        = NO"
771       } elseif { [string tolower $searchMode] == "server" } {
772         puts $doxyFile "SERVER_BASED_SEARCH    = YES"
773         puts $doxyFile "EXTERNAL_SEARCH        = NO"
774       } elseif { [string tolower $searchMode] == "external" } {
775         puts $doxyFile "SERVER_BASED_SEARCH    = YES"
776         puts $doxyFile "EXTERNAL_SEARCH        = YES"
777       } else {
778         puts "Error: Wrong search engine type: $searchMode."
779         close $doxyFile 
780         return -1
781       }
782     }
783
784     puts $doxyFile "DOTFILE_DIRS             = $outDir/html"
785     puts $doxyFile "DOT_PATH                 = $graphvizPath"
786     puts $doxyFile "INCLUDE_PATH             = [OCCDoc_GetSourceDir $productsPath]"
787     
788     # list of files to generate
789     set mainpage [OCCDoc_MakeMainPage $outDir $outDir/$name.dox $modules $productsPath]
790     puts $doxyFile ""
791     puts $doxyFile "INPUT    = $mainpage \\"
792     foreach header $filelist {
793       puts $doxyFile "               $header \\"
794     }
795
796     puts $doxyFile "MATHJAX_FORMAT         = HTML-CSS"
797     puts $doxyFile "MATHJAX_RELPATH        = ${mathjaxLocation}"
798
799     puts $doxyFile ""
800
801   } elseif { $docType == "OVERVIEW" } {
802
803     # Add common options for generation of Overview and User Guides
804     puts $doxyFile "PROJECT_NUMBER         = $occt_version"
805     puts $doxyFile "OUTPUT_DIRECTORY       = $outDir/."
806     puts $doxyFile "PROJECT_LOGO           = [OCCDoc_GetDoxDir]/resources/occ_logo.png"
807
808     set PARAM_INPUT "INPUT                 ="
809     set PARAM_IMAGEPATH "IMAGE_PATH        = [OCCDoc_GetDoxDir]/resources/ "
810     foreach docFile $DocFilesList {
811       set NEW_IMG_PATH "$inputDir/$docFile"
812       if { [string compare $NEW_IMG_PATH [OCCDoc_GetRootDir $productsPath]] != 0 } {
813         set img_string [file dirname $NEW_IMG_PATH]/images
814         if { [file exists $img_string] } {
815           append PARAM_IMAGEPATH " $img_string"
816         }
817       }
818       append PARAM_INPUT " " $inputDir/$docFile
819     }
820     puts $doxyFile $PARAM_INPUT
821     puts $doxyFile $PARAM_IMAGEPATH
822
823     # Add document type-specific options
824     if { $generatorMode == "HTML_ONLY"} {
825       # generate tree view
826       puts $doxyFile "GENERATE_TREEVIEW      = YES"
827
828       # Set a reference to a TAGFILE
829       if { $tagFileDir != "" } {
830         if {[file exists $tagFileDir/OCCT.tag] == 1} {
831           #set tagPath [OCCDoc_GetRelPath $tagFileDir $outDir/html]
832           set tagPath $tagFileDir
833           puts $doxyFile "TAGFILES               = $tagFileDir/OCCT.tag=../../refman/html"
834         }
835       }
836       # HTML Search engine options
837       if { [string tolower $searchMode] == "none" } {
838         puts $doxyFile "SEARCHENGINE           = NO"
839         puts $doxyFile "SERVER_BASED_SEARCH    = NO"
840         puts $doxyFile "EXTERNAL_SEARCH        = NO"
841       } else {
842         puts $doxyFile "SEARCHENGINE           = YES"
843         if { [string tolower $searchMode] == "local" } {
844           puts $doxyFile "SERVER_BASED_SEARCH    = NO"
845           puts $doxyFile "EXTERNAL_SEARCH        = NO"
846         } elseif { [string tolower $searchMode] == "server" } {
847           puts $doxyFile "SERVER_BASED_SEARCH    = YES"
848           puts $doxyFile "EXTERNAL_SEARCH        = NO"
849         } elseif { [string tolower $searchMode] == "external" } {
850           puts $doxyFile "SERVER_BASED_SEARCH    = YES"
851           puts $doxyFile "EXTERNAL_SEARCH        = YES"
852         } else {
853           puts "Error: Wrong search engine type: $searchMode."
854           close $doxyFile 
855           return -1
856         }
857       }
858     } elseif { $generatorMode == "CHM_ONLY"} {
859       # specific options for CHM file generation
860       puts $doxyFile "GENERATE_TREEVIEW      = NO"
861       puts $doxyFile "SEARCHENGINE           = NO"
862       puts $doxyFile "GENERATE_HTMLHELP      = YES"
863       puts $doxyFile "CHM_FILE               = ../../overview.chm"
864       puts $doxyFile "HHC_LOCATION           = \"$hhcPath\""
865       puts $doxyFile "DISABLE_INDEX          = YES"
866     }
867
868     # Formula options
869     puts $doxyFile "MATHJAX_RELPATH        = ${mathjaxLocation}"
870   }
871
872   close $doxyFile
873   return 0
874 }