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