]> git.lyx.org Git - lyx.git/blob - lib/configure.py
f9ace18d39a1a9dd727541681b2cc4e4a1a9dd55
[lyx.git] / lib / configure.py
1 #! /usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # file configure.py
5 # This file is part of LyX, the document processor.
6 # Licence details can be found in the file COPYING.
7
8 # \author Bo Peng
9 # Full author contact details are available in file CREDITS.
10
11 import sys, os, re, shutil, glob
12
13
14 class Tee:
15     ''' Writing to a Tee object will write to all file objects it keeps.
16         That is to say, writing to Tee(sys.stdout, open(logfile, 'w')) will
17         write to sys.stdout as well as a log file.
18     '''
19     def __init__(self, *args):
20         self.files = args
21
22     def write(self, data):
23         for f in self.files:
24             result = f.write(data)
25         return result
26
27     def writelines(self, seq):
28         for i in seq:
29             self.write(i)
30
31
32 def writeToFile(filename, lines, append = False):
33     " utility function: write or append lines to filename "
34     if append:
35         file = open(filename, 'a')
36     else:
37         file = open(filename, 'w')
38     file.write(lines)
39     file.close()
40
41
42 def addToRC(lines):
43     ''' utility function: shortcut for appending lines to outfile
44         add newline at the end of lines.
45     '''
46     if lines.strip() != '':
47         writeToFile(outfile, lines + '\n', append = True)
48
49
50 def removeFiles(filenames):
51     '''utility function: 'rm -f'
52         ignore errors when file does not exist, or is a directory.
53     '''
54     for file in filenames:
55         try:
56             os.remove(file)
57         except:
58             pass
59
60
61 def cmdOutput(cmd):
62     '''utility function: run a command and get its output as a string
63         cmd: command to run
64     '''
65     fout = os.popen(cmd)
66     output = fout.read()
67     fout.close()
68     return output.strip()
69
70
71 def setEnviron():
72     ''' I do not really know why this is useful, but we might as well keep it.
73         NLS nuisances.
74         Only set these to C if already set.  These must not be set unconditionally
75         because not all systems understand e.g. LANG=C (notably SCO).
76         Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
77         Non-C LC_CTYPE values break the ctype check.
78     '''
79     os.environ['LANG'] = os.getenv('LANG', 'C')
80     os.environ['LC'] = os.getenv('LC_ALL', 'C')
81     os.environ['LC_MESSAGE'] = os.getenv('LC_MESSAGE', 'C')
82     os.environ['LC_CTYPE'] = os.getenv('LC_CTYPE', 'C')
83
84
85 def createDirectories():
86     ''' Create the build directories if necessary '''
87     for dir in ['bind', 'clipart', 'doc', 'examples', 'images', 'kbd', \
88         'layouts', 'scripts', 'templates', 'ui' ]:
89         if not os.path.isdir( dir ):
90             try:
91                 os.mkdir( dir)
92             except:
93                 print "Failed to create directory ", dir
94                 sys.exit(1)
95
96
97 def checkTeXPaths():
98     ''' Determine the path-style needed by the TeX engine on Win32 (Cygwin) '''
99     windows_style_tex_paths = ''
100     if os.name == 'nt' or sys.platform == 'cygwin':
101         from tempfile import mkstemp
102         fd, tmpfname = mkstemp(suffix='.ltx')
103         if os.name == 'nt':
104             inpname = tmpfname.replace('\\', '/')
105         else:
106             inpname = cmdOutput('cygpath -m ' + tmpfname)
107         inpname = inpname.replace('~', '\\string~')
108         os.write(fd, r'\relax')
109         os.close(fd)
110         latex_out = cmdOutput(r'latex "\nonstopmode\input{%s}"' % inpname)
111         if 'Error' in latex_out:
112             print "configure: TeX engine needs posix-style paths in latex files"
113             windows_style_tex_paths = 'false'
114         else:
115             print "configure: TeX engine needs windows-style paths in latex files"
116             windows_style_tex_paths = 'true'
117         removeFiles([tmpfname, 'texput.log'])
118     return windows_style_tex_paths
119
120
121 ## Searching some useful programs
122 def checkProg(description, progs, rc_entry = [], path = [], not_found = ''):
123     '''
124         This function will search a program in $PATH plus given path
125         If found, return directory and program name (not the options).
126
127         description: description of the program
128
129         progs: check programs, for each prog, the first word is used
130             for searching but the whole string is used to replace
131             %% for a rc_entry. So, feel free to add '$$i' etc for programs.
132
133         path: additional pathes
134
135         rc_entry: entry to outfile, can be
136             1. emtpy: no rc entry will be added
137             2. one pattern: %% will be replaced by the first found program,
138                 or '' if no program is found.
139             3. several patterns for each prog and not_found. This is used 
140                 when different programs have different usages. If you do not 
141                 want not_found entry to be added to the RC file, you can specify 
142                 an entry for each prog and use '' for the not_found entry.
143
144         not_found: the value that should be used instead of '' if no program
145             was found
146
147     '''
148     # one rc entry for each progs plus not_found entry
149     if len(rc_entry) > 1 and len(rc_entry) != len(progs) + 1:
150         print "rc entry should have one item or item for each prog and not_found."
151         sys.exit(2)
152     print 'checking for ' + description + '...'
153     ## print '(' + ','.join(progs) + ')',
154     for idx in range(len(progs)):
155         # ac_prog may have options, ac_word is the command name
156         ac_prog = progs[idx]
157         ac_word = ac_prog.split(' ')[0]
158         print '+checking for "' + ac_word + '"... ',
159         path = os.environ["PATH"].split(os.pathsep) + path
160         for ac_dir in path:
161             # check both ac_word and ac_word.exe (for windows system)
162             if os.path.isfile( os.path.join(ac_dir, ac_word) ) or \
163                 os.path.isfile( os.path.join(ac_dir, ac_word + ".exe") ):
164                 print ' yes'
165                 # write rc entries for this command
166                 if len(rc_entry) == 1:
167                     addToRC(rc_entry[0].replace('%%', ac_prog))
168                 elif len(rc_entry) > 1:
169                     addToRC(rc_entry[idx].replace('%%', ac_prog))
170                 return [ac_dir, ac_word]
171         # if not successful
172         print ' no'
173     # write rc entries for 'not found'
174     if len(rc_entry) > 0:  # the last one.
175         addToRC(rc_entry[-1].replace('%%', not_found))
176     return ['', not_found]
177
178
179 def checkViewer(description, progs, rc_entry = [], path = []):
180     ''' The same as checkProg, but for viewers and editors '''
181     return checkProg(description, progs, rc_entry, path, not_found = 'auto')
182
183
184 def checkDTLtools():
185     ''' Check whether DTL tools are available (Windows only) '''
186     # Find programs! Returned path is not used now
187     if ((os.name == 'nt' or sys.platform == 'cygwin') and
188             checkProg('DVI to DTL converter', ['dv2dt']) != ['', ''] and
189             checkProg('DTL to DVI converter', ['dt2dv']) != ['', '']):
190         dtl_tools = True
191     else:
192         dtl_tools = False
193     return dtl_tools
194
195
196 def checkLatex(dtl_tools):
197     ''' Check latex, return lyx_check_config '''
198     if dtl_tools:
199         # Windows only: DraftDVI
200         converter_entry = r'''\converter latex      dvi2       "%%"     "latex"
201 \converter dvi2       dvi        "python -tt $$s/scripts/clean_dvi.py $$i $$o"  ""'''
202     else:
203         converter_entry = r'\converter latex      dvi        "%%"       "latex"'
204     path, LATEX = checkProg('a Latex2e program', ['pplatex $$i', 'latex $$i', 'latex2e $$i'],
205         rc_entry = [converter_entry])
206     # no latex
207     if LATEX != '':
208         # Check if latex is usable
209         writeToFile('chklatex.ltx', '''
210 \\nonstopmode\\makeatletter
211 \\ifx\\undefined\\documentclass\\else
212   \\message{ThisIsLaTeX2e}
213 \\fi
214 \\@@end
215 ''')
216         # run latex on chklatex.ltx and check result
217         if cmdOutput(LATEX + ' chklatex.ltx').find('ThisIsLaTeX2e') != -1:
218             # valid latex2e
219             return LATEX
220         else:
221             print "Latex not usable (not LaTeX2e) "
222         # remove temporary files
223         removeFiles(['chklatex.ltx', 'chklatex.log'])
224     return ''
225
226
227 def checkFormatEntries(dtl_tools):  
228     ''' Check all formats (\Format entries) '''
229     checkViewer('a Tgif viewer and editor', ['tgif'],
230         rc_entry = [r'\Format tgif       obj     Tgif                   "" "%%" "%%"    "vector"'])
231     #
232     checkViewer('a FIG viewer and editor', ['xfig'],
233         rc_entry = [r'\Format fig        fig     FIG                    "" "%%" "%%"    "vector"'])
234     #
235     checkViewer('a Grace viewer and editor', ['xmgrace'],
236         rc_entry = [r'\Format agr        agr     Grace                  "" "%%" "%%"    "vector"'])
237     #
238     checkViewer('a FEN viewer and editor', ['xboard -lpf $$i -mode EditPosition'],
239         rc_entry = [r'\Format fen        fen     FEN                    "" "%%" "%%"    ""'])
240     #
241     path, iv = checkViewer('a raster image viewer', ['xv', 'kview', 'gimp-remote', 'gimp'])
242     path, ie = checkViewer('a raster image editor', ['gimp-remote', 'gimp'])
243     addToRC(r'''\Format bmp        bmp     BMP                    "" "%s"       "%s"    ""
244 \Format gif        gif     GIF                    "" "%s"       "%s"    ""
245 \Format jpg        jpg     JPEG                   "" "%s"       "%s"    ""
246 \Format pbm        pbm     PBM                    "" "%s"       "%s"    ""
247 \Format pgm        pgm     PGM                    "" "%s"       "%s"    ""
248 \Format png        png     PNG                    "" "%s"       "%s"    ""
249 \Format ppm        ppm     PPM                    "" "%s"       "%s"    ""
250 \Format tiff       tif     TIFF                   "" "%s"       "%s"    ""
251 \Format xbm        xbm     XBM                    "" "%s"       "%s"    ""
252 \Format xpm        xpm     XPM                    "" "%s"       "%s"    ""''' % \
253         (iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie) )
254     #
255     checkViewer('a text editor', ['xemacs', 'gvim', 'kedit', 'kwrite', 'kate', \
256         'nedit', 'gedit', 'notepad'],
257         rc_entry = [r'''\Format asciichess asc    "Plain text (chess output)"  "" ""    "%%"    ""
258 \Format asciiimage asc    "Plain text (image)"         "" ""    "%%"    ""
259 \Format asciixfig  asc    "Plain text (Xfig output)"   "" ""    "%%"    ""
260 \Format dateout    tmp    "date (output)"         "" "" "%%"    ""
261 \Format docbook    sgml    DocBook                B  "" "%%"    "document"
262 \Format docbook-xml xml   "Docbook (XML)"         "" "" "%%"    "document"
263 \Format literate   nw      NoWeb                  N  "" "%%"    "document"
264 \Format lilypond   ly     "LilyPond music"        "" "" "%%"    "vector"
265 \Format latex      tex    "LaTeX (plain)"         L  "" "%%"    "document"
266 \Format linuxdoc   sgml    LinuxDoc               x  "" "%%"    "document"
267 \Format pdflatex   tex    "LaTeX (pdflatex)"      "" "" "%%"    "document"
268 \Format text       txt    "Plain text"            a  "" "%%"    "document"
269 \Format text2      txt    "Plain text (pstotext)" "" "" "%%"    "document"
270 \Format text3      txt    "Plain text (ps2ascii)" "" "" "%%"    "document"
271 \Format text4      txt    "Plain text (catdvi)"   "" "" "%%"    "document"
272 \Format textparagraph txt "Plain Text, Join Lines" "" ""        "%%"    "document"''' ])
273     #
274     #checkProg('a Postscript interpreter', ['gs'],
275     #  rc_entry = [ r'\ps_command "%%"' ])
276     checkViewer('a Postscript previewer', ['kghostview', 'evince', 'gv', 'ghostview -swap'],
277         rc_entry = [r'''\Format eps        eps     EPS                    "" "%%"       ""      "vector"
278 \Format ps         ps      Postscript             t  "%%"       ""      "document,vector"'''])
279     #
280     checkViewer('a PDF previewer', ['kpdf', 'evince', 'kghostview', 'xpdf', 'acrobat', 'acroread', \
281                     'gv', 'ghostview'],
282         rc_entry = [r'''\Format pdf        pdf    "PDF (ps2pdf)"          P  "%%"       ""      "document,vector"
283 \Format pdf2       pdf    "PDF (pdflatex)"        F  "%%"       ""      "document,vector"
284 \Format pdf3       pdf    "PDF (dvipdfm)"         m  "%%"       ""      "document,vector"'''])
285     #
286     checkViewer('a DVI previewer', ['xdvi', 'kdvi'],
287         rc_entry = [r'\Format dvi        dvi     DVI                    D  "%%" ""      "document,vector"'])
288     if dtl_tools:
289         # Windows only: DraftDVI
290         addToRC(r'\Format dvi2       dvi     DraftDVI               ""  ""      "document,vector"')
291     #
292     checkViewer('an HTML previewer', ['firefox', 'mozilla file://$$p$$i', 'netscape'],
293         rc_entry = [r'\Format html       html    HTML                   H  "%%" ""      "document"'])
294     #
295     checkViewer('Noteedit', ['noteedit'],
296         rc_entry = [r'\Format noteedit   not     Noteedit               "" "%%" "%%"    "vector"'])
297     #
298     # entried that do not need checkProg
299     addToRC(r'''\Format date       ""     "date command"          "" "" ""      ""
300 \Format fax        ""      Fax                    "" "" ""      "document"
301 \Format lyx        lyx     LyX                    "" "" ""      ""
302 \Format lyx13x     lyx13  "LyX 1.3.x"             "" "" ""      "document"
303 \Format lyx14x     lyx14  "LyX 1.4.x"             "" "" ""      "document"
304 \Format clyx       cjklyx "CJK LyX 1.4.x (big5)"  "" "" ""      "document"
305 \Format jlyx       cjklyx "CJK LyX 1.4.x (euc-jp)" "" ""        ""      "document"
306 \Format klyx       cjklyx "CJK LyX 1.4.x (euc-kr)" "" ""        ""      "document"
307 \Format lyxpreview lyxpreview "LyX Preview"       "" "" ""      ""
308 \Format pdftex     pdftex_t PDFTEX                "" "" ""      ""
309 \Format program    ""      Program                "" "" ""      ""
310 \Format pstex      pstex_t PSTEX                  "" "" ""      ""
311 \Format rtf        rtf    "Rich Text Format"      "" "" ""      "document,vector"
312 \Format sxw        sxw    "OpenOffice.Org (sxw)"  ""  ""        ""      "document,vector"
313 \Format odt        odt    "Open Document"         O   ""        ""      "document,vector"
314 \Format wmf        wmf    "Windows Metafile"      "" "" ""      "vector"
315 \Format emf        emf    "Enhanced Metafile"     "" "" ""      "vector"
316 \Format word       doc    "MS Word"               W  "" ""      "document,vector"
317 \Format wordhtml   html   "HTML (MS Word)"        "" ""        ""       "document"
318 ''')
319
320
321 def checkConverterEntries():
322     ''' Check all converters (\converter entries) '''
323     checkProg('the pdflatex program', ['pdflatex $$i'],
324         rc_entry = [ r'\converter pdflatex   pdf2       "%%"    "latex"' ])
325     
326     ''' If we're running LyX in-place then tex2lyx will be found in
327             ../src/tex2lyx. Add this directory to the PATH temporarily and
328             search for tex2lyx.
329             Use PATH to avoid any problems with paths-with-spaces.
330     '''
331     path_orig = os.environ["PATH"]
332     os.environ["PATH"] = os.path.join('..', 'src', 'tex2lyx') + \
333         os.pathsep + path_orig
334
335     checkProg('a LaTeX/Noweb -> LyX converter', ['tex2lyx', 'tex2lyx' + version_suffix],
336         rc_entry = [r'''\converter latex      lyx        "%% -f $$i $$o"        ""
337 \converter literate   lyx        "%% -n -f $$i $$o"     ""'''])
338
339     os.environ["PATH"] = path_orig
340
341     #
342     checkProg('a Noweb -> LaTeX converter', ['noweave -delay -index $$i > $$o'],
343         rc_entry = [ r'\converter literate   latex      "%%"    ""' ])
344     #
345     checkProg('an HTML -> LaTeX converter', ['html2latex $$i'],
346         rc_entry = [ r'\converter html       latex      "%%"    ""' ])
347     #
348     checkProg('an MS Word -> LaTeX converter', ['wvCleanLatex $$i $$o'],
349         rc_entry = [ r'\converter word       latex      "%%"    ""' ])
350     #
351     path, htmlconv = checkProg('a LaTeX -> HTML converter', ['htlatex $$i', 'tth  -t -e2 -L$$b < $$i > $$o', \
352         'latex2html -no_subdir -split 0 -show_section_numbers $$i', 'hevea -s $$i'],
353         rc_entry = [ r'\converter latex      html       "%%"    "needaux"' ])
354     if htmlconv == 'htlatex' or htmlconv == 'latex2html':
355       addToRC(r'''\copier    html       "python -tt $$s/scripts/ext_copy.py -e html,png,css $$i $$o"''')
356     else:
357       addToRC(r'''\copier    html       "python -tt $$s/scripts/ext_copy.py $$i $$o"''')
358
359     #
360     path, htmlconv = checkProg('a LaTeX -> MS Word converter', ["htlatex $$i 'html,word' 'symbol/!' '-cvalidate'"],
361         rc_entry = [ r'\converter latex      wordhtml   "%%"    "needaux"' ])
362     if htmlconv == 'htlatex':
363       addToRC(r'''\copier    wordhtml       "python -tt $$s/scripts/ext_copy.py -e html,png,css $$i $$o"''')
364     #
365     checkProg('an OpenOffice.org -> LaTeX converter', ['w2l -clean $$i'],
366         rc_entry = [ r'\converter sxw        latex      "%%"    ""' ])
367     #
368     checkProg('an OpenDocument -> LaTeX converter', ['w2l -clean $$i'],
369         rc_entry = [ r'\converter odt        latex      "%%"    ""' ])
370     #
371     checkProg('a LaTeX -> Open Document converter', ['oolatex $$i', 'oolatex.sh $$i'],
372         rc_entry = [ r'\converter latex      odt        "%%"    "latex"' ])
373     # On windows it is called latex2rt.exe
374     checkProg('a LaTeX -> RTF converter', ['latex2rtf -p -S -o $$o $$i', 'latex2rt -p -S -o $$o $$i'],
375         rc_entry = [ r'\converter latex      rtf        "%%"    "needaux"' ])
376     #
377     checkProg('a PS to PDF converter', ['ps2pdf13 $$i $$o'],
378         rc_entry = [ r'\converter ps         pdf        "%%"    ""' ])
379     #
380     checkProg('a PS to TXT converter', ['pstotext $$i > $$o'],
381         rc_entry = [ r'\converter ps         text2      "%%"    ""' ])
382     #
383     checkProg('a PS to TXT converter', ['ps2ascii $$i $$o'],
384         rc_entry = [ r'\converter ps         text3      "%%"    ""' ])
385     #
386     checkProg('a DVI to TXT converter', ['catdvi $$i > $$o'],
387         rc_entry = [ r'\converter dvi        text4      "%%"    ""' ])
388     #
389     checkProg('a DVI to PS converter', ['dvips -o $$o $$i'],
390         rc_entry = [ r'\converter dvi        ps         "%%"    ""' ])
391     #
392     checkProg('a DVI to PDF converter', ['dvipdfmx -o $$o $$i', 'dvipdfm -o $$o $$i'],
393         rc_entry = [ r'\converter dvi        pdf3       "%%"    ""' ])
394     #
395     path, dvipng = checkProg('dvipng', ['dvipng'])
396     if dvipng == "dvipng":
397         addToRC(r'\converter lyxpreview png        "python -tt $$s/scripts/lyxpreview2bitmap.py"        ""')
398     else:
399         addToRC(r'\converter lyxpreview png        ""   ""')
400     #  
401     checkProg('a fax program', ['kdeprintfax $$i', 'ksendfax $$i'],
402         rc_entry = [ r'\converter ps         fax        "%%"    ""'])
403     #
404     checkProg('a FIG -> EPS/PPM converter', ['fig2dev'],
405         rc_entry = [
406             r'''\converter fig        eps        "fig2dev -L eps $$i $$o"       ""
407 \converter fig        ppm        "fig2dev -L ppm $$i $$o"       ""
408 \converter fig        png        "fig2dev -L png $$i $$o"       ""''',
409             ''])
410     #
411     checkProg('a TIFF -> PS converter', ['tiff2ps $$i > $$o'],
412         rc_entry = [ r'\converter tiff       eps        "%%"    ""', ''])
413     #
414     checkProg('a TGIF -> EPS/PPM converter', ['tgif'],
415         rc_entry = [
416             r'''\converter tgif       eps        "tgif -stdout -print -color -eps $$i > $$o"    ""
417 \converter tgif       ppm        "tgif -stdout -print -color -ppm $$i > $$o"    ""
418 \converter tgif       png        "tgif -stdout -print -color -png $$i > $$o"    ""
419 \converter tgif       pdf        "tgif -stdout -print -color -pdf $$i > $$o"    ""''',
420             ''])
421     #
422     checkProg('a WMF -> EPS converter', ['metafile2eps $$i $$o', 'wmf2eps -o $$o $$i'],
423         rc_entry = [ r'\converter wmf        eps        "%%"    ""'])
424     #
425     checkProg('an EMF -> EPS converter', ['metafile2eps $$i $$o', 'wmf2eps -o $$o $$i'],
426         rc_entry = [ r'\converter emf        eps        "%%"    ""'])
427     #
428     checkProg('an EPS -> PDF converter', ['epstopdf'],
429         rc_entry = [ r'\converter eps        pdf        "epstopdf --outfile=$$o $$i"    ""', ''])
430     #
431     # no agr -> pdf converter, since the pdf library used by gracebat is not
432     # free software and therefore not compiled in in many installations.
433     # Fortunately, this is not a big problem, because we will use epstopdf to
434     # convert from agr to pdf via eps without loss of quality.
435     checkProg('a Grace -> Image converter', ['gracebat'],
436         rc_entry = [
437             r'''\converter agr        eps        "gracebat -hardcopy -printfile $$o -hdevice EPS $$i 2>/dev/null"       ""
438 \converter agr        png        "gracebat -hardcopy -printfile $$o -hdevice PNG $$i 2>/dev/null"       ""
439 \converter agr        jpg        "gracebat -hardcopy -printfile $$o -hdevice JPEG $$i 2>/dev/null"      ""
440 \converter agr        ppm        "gracebat -hardcopy -printfile $$o -hdevice PNM $$i 2>/dev/null"       ""''',
441             ''])
442     #
443     #
444     path, lilypond = checkProg('a LilyPond -> EPS/PDF/PNG converter', ['lilypond'])
445     if (lilypond != ''):
446         version_string = cmdOutput("lilypond --version")
447         match = re.match('GNU LilyPond (\S+)', version_string)
448         if match:
449             version_number = match.groups()[0]
450             version = version_number.split('.')
451             if int(version[0]) > 2 or (len(version) > 1 and int(version[0]) == 2 and int(version[1]) >= 6):
452                 addToRC(r'''\converter lilypond   eps        "lilypond -b eps --ps $$i" ""
453 \converter lilypond   png        "lilypond -b eps --png $$i"    ""''')
454                 if int(version[0]) > 2 or (len(version) > 1 and int(version[0]) == 2 and int(version[1]) >= 9):
455                     addToRC(r'\converter lilypond   pdf        "lilypond -b eps --pdf $$i"      ""')
456                 print '+  found LilyPond version %s.' % version_number
457             else:
458                 print '+  found LilyPond, but version %s is too old.' % version_number
459         else:
460             print '+  found LilyPond, but could not extract version number.'
461     #
462     checkProg('a Noteedit -> LilyPond converter', ['noteedit --export-lilypond $$i'],
463         rc_entry = [ r'\converter noteedit   lilypond   "%%"    ""', ''])
464     #
465     # FIXME: no rc_entry? comment it out
466     # checkProg('Image converter', ['convert $$i $$o'])
467     #
468     # Entries that do not need checkProg
469     addToRC(r'''\converter lyxpreview ppm        "python -tt $$s/scripts/lyxpreview2bitmap.py"  ""
470 \converter date       dateout    "python -tt $$s/scripts/date.py %d-%m-%Y > $$o"        ""
471 \converter docbook    docbook-xml "cp $$i $$o"  "xml"
472 \converter fen        asciichess "python -tt $$s/scripts/fen2ascii.py $$i $$o"  ""
473 \converter fig        pdftex     "python -tt $$s/scripts/fig2pdftex.py $$i $$o" ""
474 \converter fig        pstex      "python -tt $$s/scripts/fig2pstex.py $$i $$o"  ""
475 \converter lyx        lyx13x     "python -tt $$s/lyx2lyx/lyx2lyx -t 221 $$i > $$o"      ""
476 \converter lyx        lyx14x     "python -tt $$s/lyx2lyx/lyx2lyx -t 245 $$i > $$o"      ""
477 \converter lyx        clyx       "python -tt $$s/lyx2lyx/lyx2lyx -c big5 -t 245 $$i > $$o"      ""
478 \converter lyx        jlyx       "python -tt $$s/lyx2lyx/lyx2lyx -c euc_jp -t 245 $$i > $$o"    ""
479 \converter lyx        klyx       "python -tt $$s/lyx2lyx/lyx2lyx -c euc_kr -t 245 $$i > $$o"    ""
480 \converter clyx       lyx        "python -tt $$s/lyx2lyx/lyx2lyx -c big5 $$i > $$o"     ""
481 \converter jlyx       lyx        "python -tt $$s/lyx2lyx/lyx2lyx -c euc_jp $$i > $$o"   ""
482 \converter klyx       lyx        "python -tt $$s/lyx2lyx/lyx2lyx -c euc_kr $$i > $$o"   ""
483 ''')
484
485
486 def checkLinuxDoc():
487     ''' Check linuxdoc '''
488     #
489     path, LINUXDOC = checkProg('SGML-tools 1.x (LinuxDoc)', ['sgml2lyx'],
490         rc_entry = [
491         r'''\converter linuxdoc   lyx        "sgml2lyx $$i"     ""
492 \converter linuxdoc   latex      "sgml2latex $$i"       ""
493 \converter linuxdoc   dvi        "sgml2latex -o dvi $$i"        ""
494 \converter linuxdoc   html       "sgml2html $$i"        ""''',
495         r'''\converter linuxdoc   lyx        "" ""
496 \converter linuxdoc   latex      ""     ""
497 \converter linuxdoc   dvi        ""     ""
498 \converter linuxdoc   html       ""     ""''' ])
499     if LINUXDOC != '':
500         return ('yes', 'true', '\\def\\haslinuxdoc{yes}')
501     else:
502         return ('no', 'false', '')
503
504
505 def checkDocBook():
506     ''' Check docbook '''
507     path, DOCBOOK = checkProg('SGML-tools 2.x (DocBook) or db2x scripts', ['sgmltools', 'db2dvi'],
508         rc_entry = [
509             r'''\converter docbook    dvi        "sgmltools -b dvi $$i" ""
510 \converter docbook    html       "sgmltools -b html $$i"        ""''',
511             r'''\converter docbook    dvi        "db2dvi $$i"   ""
512 \converter docbook    html       "db2html $$i"  ""''',
513             r'''\converter docbook    dvi        ""     ""
514 \converter docbook    html       ""     ""'''])
515     #
516     if DOCBOOK != '':
517         return ('yes', 'true', '\\def\\hasdocbook{yes}')
518     else:
519         return ('no', 'false', '')
520
521
522 def checkOtherEntries():
523     ''' entries other than Format and Converter '''
524     checkProg('a *roff formatter', ['groff', 'nroff'],
525         rc_entry = [
526             r'\plaintext_roff_command "groff -t -Tlatin1 $$FName"',
527             r'\plaintext_roff_command "tbl $$FName | nroff"',
528             r'\plaintext_roff_command ""' ])
529     checkProg('ChkTeX', ['chktex -n1 -n3 -n6 -n9 -n22 -n25 -n30 -n38'],
530         rc_entry = [ r'\chktex_command "%%"' ])
531     checkProg('a spellchecker', ['ispell'],
532         rc_entry = [ r'\spell_command "%%"' ])
533     ## FIXME: OCTAVE is not used anywhere
534     # path, OCTAVE = checkProg('Octave', ['octave'])
535     ## FIXME: MAPLE is not used anywhere
536     # path, MAPLE = checkProg('Maple', ['maple'])
537     checkProg('a spool command', ['lp', 'lpr'],
538         rc_entry = [
539             r'''\print_spool_printerprefix "-d "
540 \print_spool_command "lp"''',
541             r'''\print_spool_printerprefix "-P",
542 \print_spool_command "lpr"''',
543             ''])
544     # Add the rest of the entries (no checkProg is required)
545     addToRC(r'''\copier    fig        "python -tt $$s/scripts/fig_copy.py $$i $$o"
546 \copier    pstex      "python -tt $$s/scripts/tex_copy.py $$i $$o $$l"
547 \copier    pdftex     "python -tt $$s/scripts/tex_copy.py $$i $$o $$l"
548 \copier    program    "python -tt $$s/scripts/ext_copy.py $$i $$o"
549 ''')
550
551
552 def processLayoutFile(file, bool_docbook, bool_linuxdoc):
553     ''' process layout file and get a line of result
554         
555         Declare lines look like this: (article.layout, scrbook.layout, svjog.layout)
556         
557         \DeclareLaTeXClass{article}
558         \DeclareLaTeXClass[scrbook]{book (koma-script)}
559         \DeclareLaTeXClass[svjour,svjog.clo]{article (Springer - svjour/jog)}
560
561         we expect output:
562         
563         "article" "article" "article" "false"
564         "scrbook" "scrbook" "book (koma-script)" "false"
565         "svjog" "svjour" "article (Springer - svjour/jog)" "false"
566     '''
567     classname = file.split(os.sep)[-1].split('.')[0]
568     # return ('LaTeX', '[a,b]', 'a', ',b,c', 'article') for \DeclareLaTeXClass[a,b,c]{article}
569     p = re.compile(r'\Declare(LaTeX|DocBook|LinuxDoc)Class\s*(\[([^,]*)(,.*)*\])*\s*{(.*)}')
570     for line in open(file).readlines():
571         res = p.search(line)
572         if res != None:
573             (classtype, optAll, opt, opt1, desc) = res.groups()
574             avai = {'LaTeX':'false', 'DocBook':bool_docbook, 'LinuxDoc':bool_linuxdoc}[classtype]
575             if opt == None:
576                 opt = classname
577             return '"%s" "%s" "%s" "%s"\n' % (classname, opt, desc, avai)
578     print "Layout file without \DeclareXXClass line. "
579     sys.exit(2)
580
581     
582 def checkLatexConfig(check_config, bool_docbook, bool_linuxdoc):
583     ''' Explore the LaTeX configuration '''
584     print 'checking LaTeX configuration... ',
585     # First, remove the files that we want to re-create
586     removeFiles(['textclass.lst', 'packages.lst', 'chkconfig.sed'])
587     #
588     if not check_config:
589         print ' default values'
590         print '+checking list of textclasses... '
591         tx = open('textclass.lst', 'w')
592         tx.write('''
593 # This file declares layouts and their associated definition files
594 # (include dir. relative to the place where this file is).
595 # It contains only default values, since chkconfig.ltx could not be run
596 # for some reason. Run ./configure.py if you need to update it after a
597 # configuration change.
598 ''')
599         # build the list of available layout files and convert it to commands
600         # for chkconfig.ltx
601         foundClasses = []
602         for file in glob.glob( os.path.join('layouts', '*.layout') ) + \
603             glob.glob( os.path.join(srcdir, 'layouts', '*.layout' ) ) :
604             # valid file?
605             if not os.path.isfile(file): 
606                 continue
607             # get stuff between /xxxx.layout .
608             classname = file.split(os.sep)[-1].split('.')[0]
609             #  tr ' -' '__'`
610             cleanclass = classname.replace(' ', '_')
611             cleanclass = cleanclass.replace('-', '_')
612             # make sure the same class is not considered twice
613             if foundClasses.count(cleanclass) == 0: # not found before
614                 foundClasses.append(cleanclass)
615                 tx.write(processLayoutFile(file, bool_docbook, bool_linuxdoc))
616         tx.close()
617         print '\tdone'
618     else:
619         print '\tauto'
620         removeFiles(['wrap_chkconfig.ltx', 'chkconfig.vars', \
621             'chkconfig.classes', 'chklayouts.tex'])
622         rmcopy = False
623         if not os.path.isfile( 'chkconfig.ltx' ):
624             shutil.copy( os.path.join(srcdir, 'chkconfig.ltx'),  'chkconfig.ltx' )
625             rmcopy = True
626         writeToFile('wrap_chkconfig.ltx', '%s\n%s\n\\input{chkconfig.ltx}\n' \
627             % (linuxdoc_cmd, docbook_cmd) )
628         # Construct the list of classes to test for.
629         # build the list of available layout files and convert it to commands
630         # for chkconfig.ltx
631         p1 = re.compile(r'\Declare(LaTeX|DocBook)Class')
632         testclasses = list()
633         for file in glob.glob( os.path.join('layouts', '*.layout') ) + \
634             glob.glob( os.path.join(srcdir, 'layouts', '*.layout' ) ) :
635             if not os.path.isfile(file):
636                 continue
637             classname = file.split(os.sep)[-1].split('.')[0]
638             for line in open(file).readlines():
639                 if p1.search(line) == None:
640                     continue
641                 if line[0] != '#':
642                     print "Wrong input layout file with line '" + line
643                     sys.exit(3)
644                 testclasses.append("\\TestDocClass{%s}{%s}" % (classname, line[1:].strip()))
645                 break
646         testclasses.sort()
647         cl = open('chklayouts.tex', 'w')
648         for line in testclasses:
649             cl.write(line + '\n')
650         cl.close()
651         #
652         # we have chklayouts.tex, then process it
653         fout = os.popen(LATEX + ' wrap_chkconfig.ltx')
654         while True:
655             line = fout.readline()
656             if not line:
657                 break;
658             if re.match('^\+', line):
659                 print line,
660         fout.close()
661         #
662         # currently, values in chhkconfig are only used to set
663         # \font_encoding
664         values = {}
665         for line in open('chkconfig.vars').readlines():
666             key, val = re.sub('-', '_', line).split('=')
667             val = val.strip()
668             values[key] = val.strip("'")
669         # chk_fontenc may not exist 
670         try:
671             addToRC(r'\font_encoding "%s"' % values["chk_fontenc"])
672         except:
673             pass
674         if rmcopy:   # remove the copied file
675             removeFiles( [ 'chkconfig.ltx' ] )
676
677
678 def createLaTeXConfig():
679     ''' create LaTeXConfig.lyx '''
680     # if chkconfig.sed does not exist (because LaTeX did not run),
681     # then provide a standard version.
682     if not os.path.isfile('chkconfig.sed'):
683         writeToFile('chkconfig.sed', 's!@.*@!???!g\n')
684     print "creating packages.lst"
685     # if packages.lst does not exist (because LaTeX did not run),
686     # then provide a standard version.
687     if not os.path.isfile('packages.lst'):
688         writeToFile('packages.lst', '''
689 ### This file should contain the list of LaTeX packages that have been
690 ### recognized by LyX. Unfortunately, since configure could not find
691 ### your LaTeX2e program, the tests have not been run. Run ./configure.py
692 ### if you need to update it after a configuration change.
693 ''')
694     print 'creating doc/LaTeXConfig.lyx'
695     #
696     # This is originally done by sed, using a
697     # tex-generated file chkconfig.sed
698     ##sed -f chkconfig.sed ${srcdir}/doc/LaTeXConfig.lyx.in
699     ##  >doc/LaTeXConfig.lyx
700     # Now, we have to do it by hand (python).
701     #
702     # add to chekconfig.sed
703     writeToFile('chkconfig.sed', '''s!@chk_linuxdoc@!%s!g
704 s!@chk_docbook@!%s!g
705     ''' % (chk_linuxdoc, chk_docbook) , append=True)
706     # process this sed file!!!!
707     lyxin = open( os.path.join(srcdir, 'doc', 'LaTeXConfig.lyx.in')).readlines()
708     # get the rules
709     p = re.compile(r's!(.*)!(.*)!g')
710     # process each sed replace.
711     for sed in open('chkconfig.sed').readlines():
712         if sed.strip() == '':
713             continue
714         try:
715             fr, to = p.match(sed).groups()
716             # if latex did not run, change all @name@ to '???'
717             if fr == '@.*@':
718                 for line in range(len(lyxin)):
719                     lyxin[line] = re.sub('@.*@', to, lyxin[line])
720             else:
721                 for line in range(len(lyxin)):
722                     lyxin[line] = lyxin[line].replace(fr, to)
723         except:  # wrong sed entry?
724             print "Wrong sed entry in chkconfig.sed: '" + sed + "'"
725             sys.exit(4)
726     # 
727     writeToFile( os.path.join('doc', 'LaTeXConfig.lyx'),
728         ''.join(lyxin))
729
730
731 def checkTeXAllowSpaces():
732     ''' Let's check whether spaces are allowed in TeX file names '''
733     tex_allows_spaces = 'false'
734     if lyx_check_config:
735         print "Checking whether TeX allows spaces in file names... ",
736         writeToFile('a b.tex', r'\message{working^^J}' )
737         if os.name == 'nt':
738             latex_out = cmdOutput(LATEX + r""" "\nonstopmode\input{\"a b\"}" """)
739         else:
740             latex_out = cmdOutput(LATEX + r""" '\nonstopmode\input{"a b"}' """)
741         if 'working' in latex_out:
742             print 'yes'
743             tex_allows_spaces = 'true'
744         else:
745             print 'no'
746             tex_allows_spaces = 'false'
747         addToRC(r'\tex_allows_spaces ' + tex_allows_spaces)
748         removeFiles( [ 'a b.tex', 'a b.log', 'texput.log' ])
749
750
751 def removeTempFiles():
752     # Final clean-up
753     if not lyx_keep_temps:
754         removeFiles(['chkconfig.sed', 'chkconfig.vars',  \
755             'wrap_chkconfig.ltx', 'wrap_chkconfig.log', \
756             'chklayouts.tex', 'missfont.log', 
757             'chklatex.ltx', 'chklatex.log'])
758
759
760 if __name__ == '__main__':
761     lyx_check_config = True
762     outfile = 'lyxrc.defaults'
763     rc_entries = ''
764     lyx_keep_temps = False
765     version_suffix = ''
766     logfile = 'configure.log'
767     ## Parse the command line
768     for op in sys.argv[1:]:   # default shell/for list is $*, the options
769         if op in [ '-help', '--help', '-h' ]:
770             print '''Usage: configure [options]
771 Options:
772     --help                   show this help lines
773     --keep-temps             keep temporary files (for debug. purposes)
774     --without-latex-config   do not run LaTeX to determine configuration
775     --with-version-suffix=suffix suffix of binary installed files
776 '''
777             sys.exit(0)
778         elif op == '--without-latex-config':
779             lyx_check_config = False
780         elif op == '--keep-temps':
781             lyx_keep_temps = True
782         elif op[0:22] == '--with-version-suffix=':  # never mind if op is not long enough
783             version_suffix = op[22:]
784         else:
785             print "Unknown option", op
786             sys.exit(1)
787     #
788     # set up log file for stdout and stderr
789     log = open(logfile, 'w')
790     sys.stdout = Tee(sys.stdout, log)
791     sys.stderr = Tee(sys.stderr, log)
792     # check if we run from the right directory
793     srcdir = os.path.dirname(sys.argv[0])
794     if srcdir == '':
795         srcdir = '.'
796     if not os.path.isfile( os.path.join(srcdir, 'chkconfig.ltx') ):
797         print "configure: error: cannot find chkconfig.ltx script"
798         sys.exit(1)
799     setEnviron()
800     createDirectories()
801     windows_style_tex_paths = checkTeXPaths()
802     dtl_tools = checkDTLtools()
803     ## Write the first part of outfile
804     writeToFile(outfile, '''# This file has been automatically generated by LyX' lib/configure.py
805 # script. It contains default settings that have been determined by
806 # examining your system. PLEASE DO NOT MODIFY ANYTHING HERE! If you
807 # want to customize LyX, use LyX' Preferences dialog or modify directly 
808 # the "preferences" file instead. Any setting in that file will
809 # override the values given here.
810 ''')
811     # check latex
812     LATEX = checkLatex(dtl_tools)
813     checkFormatEntries(dtl_tools)
814     checkConverterEntries()
815     (chk_linuxdoc, bool_linuxdoc, linuxdoc_cmd) = checkLinuxDoc()
816     (chk_docbook, bool_docbook, docbook_cmd) = checkDocBook()
817     checkTeXAllowSpaces()
818     if windows_style_tex_paths != '':
819         addToRC(r'\tex_expects_windows_paths %s' % windows_style_tex_paths)
820     checkOtherEntries()
821     # --without-latex-config can disable lyx_check_config
822     checkLatexConfig( lyx_check_config and LATEX != '', bool_docbook, bool_linuxdoc)
823     createLaTeXConfig()
824     removeTempFiles()