]> git.lyx.org Git - lyx.git/blob - lib/configure.py
093b2867442dd1dbb6b79aa9ae0814c3bf621ab5
[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     checkViewer('an OpenDocument viewer', ['oowriter'],
299         rc_entry = [r'\Format odt        odt     OpenDocument           "" "%%" "%%"    "document,vector"'])
300     #
301     # entried that do not need checkProg
302     addToRC(r'''\Format date       ""     "date command"          "" "" ""      ""
303 \Format fax        ""      Fax                    "" "" ""      "document"
304 \Format lyx        lyx     LyX                    "" "" ""      ""
305 \Format lyx13x     lyx13  "LyX 1.3.x"             "" "" ""      "document"
306 \Format lyx14x     lyx14  "LyX 1.4.x"             "" "" ""      "document"
307 \Format clyx       cjklyx "CJK LyX 1.4.x (big5)"  "" "" ""      "document"
308 \Format jlyx       cjklyx "CJK LyX 1.4.x (euc-jp)" "" ""        ""      "document"
309 \Format klyx       cjklyx "CJK LyX 1.4.x (euc-kr)" "" ""        ""      "document"
310 \Format lyxpreview lyxpreview "LyX Preview"       "" "" ""      ""
311 \Format pdftex     pdftex_t PDFTEX                "" "" ""      ""
312 \Format program    ""      Program                "" "" ""      ""
313 \Format pstex      pstex_t PSTEX                  "" "" ""      ""
314 \Format rtf        rtf    "Rich Text Format"      "" "" ""      "document,vector"
315 \Format sxw        sxw    "OpenOffice.Org (sxw)"  ""  ""        ""      "document,vector"
316 \Format wmf        wmf    "Windows Metafile"      "" "" ""      "vector"
317 \Format emf        emf    "Enhanced Metafile"     "" "" ""      "vector"
318 \Format word       doc    "MS Word"               W  "" ""      "document,vector"
319 \Format wordhtml   html   "HTML (MS Word)"        "" ""        ""       "document"
320 ''')
321
322
323 def checkConverterEntries():
324     ''' Check all converters (\converter entries) '''
325     checkProg('the pdflatex program', ['pdflatex $$i'],
326         rc_entry = [ r'\converter pdflatex   pdf2       "%%"    "latex"' ])
327     
328     ''' If we're running LyX in-place then tex2lyx will be found in
329             ../src/tex2lyx. Add this directory to the PATH temporarily and
330             search for tex2lyx.
331             Use PATH to avoid any problems with paths-with-spaces.
332     '''
333     path_orig = os.environ["PATH"]
334     os.environ["PATH"] = os.path.join('..', 'src', 'tex2lyx') + \
335         os.pathsep + path_orig
336
337     checkProg('a LaTeX/Noweb -> LyX converter', ['tex2lyx', 'tex2lyx' + version_suffix],
338         rc_entry = [r'''\converter latex      lyx        "%% -f $$i $$o"        ""
339 \converter literate   lyx        "%% -n -f $$i $$o"     ""'''])
340
341     os.environ["PATH"] = path_orig
342
343     #
344     checkProg('a Noweb -> LaTeX converter', ['noweave -delay -index $$i > $$o'],
345         rc_entry = [ r'\converter literate   latex      "%%"    ""' ])
346     #
347     checkProg('an HTML -> LaTeX converter', ['html2latex $$i'],
348         rc_entry = [ r'\converter html       latex      "%%"    ""' ])
349     #
350     checkProg('an MS Word -> LaTeX converter', ['wvCleanLatex $$i $$o'],
351         rc_entry = [ r'\converter word       latex      "%%"    ""' ])
352     #
353     path, htmlconv = checkProg('a LaTeX -> HTML converter', ['htlatex $$i', 'tth  -t -e2 -L$$b < $$i > $$o', \
354         'latex2html -no_subdir -split 0 -show_section_numbers $$i', 'hevea -s $$i'],
355         rc_entry = [ r'\converter latex      html       "%%"    "needaux"' ])
356     if htmlconv == 'htlatex' or htmlconv == 'latex2html':
357       addToRC(r'''\copier    html       "python -tt $$s/scripts/ext_copy.py -e html,png,css $$i $$o"''')
358     else:
359       addToRC(r'''\copier    html       "python -tt $$s/scripts/ext_copy.py $$i $$o"''')
360
361     #
362     path, htmlconv = checkProg('a LaTeX -> MS Word converter', ["htlatex $$i 'html,word' 'symbol/!' '-cvalidate'"],
363         rc_entry = [ r'\converter latex      wordhtml   "%%"    "needaux"' ])
364     if htmlconv == 'htlatex':
365       addToRC(r'''\copier    wordhtml       "python -tt $$s/scripts/ext_copy.py -e html,png,css $$i $$o"''')
366     #
367     checkProg('an OpenOffice.org -> LaTeX converter', ['w2l -clean $$i'],
368         rc_entry = [ r'\converter sxw        latex      "%%"    ""' ])
369     #
370     checkProg('an OpenDocument -> LaTeX converter', ['w2l -clean $$i'],
371         rc_entry = [ r'\converter odt        latex      "%%"    ""' ])
372     #
373     checkProg('a LaTeX -> Open Document converter', ['oolatex $$i', 'oolatex.sh $$i', 'htlatex $$i \'xhtml,ooffice\' \'ooffice/! -cmozhtf\' \'-coo\' \'-cvalidate\''],
374         rc_entry = [ r'\converter latex      odt        "%%"    "needaux"' ])
375     # On windows it is called latex2rt.exe
376     checkProg('a LaTeX -> RTF converter', ['latex2rtf -p -S -o $$o $$i', 'latex2rt -p -S -o $$o $$i'],
377         rc_entry = [ r'\converter latex      rtf        "%%"    "needaux"' ])
378     #
379     checkProg('a PS to PDF converter', ['ps2pdf13 $$i $$o'],
380         rc_entry = [ r'\converter ps         pdf        "%%"    ""' ])
381     #
382     checkProg('a PS to TXT converter', ['pstotext $$i > $$o'],
383         rc_entry = [ r'\converter ps         text2      "%%"    ""' ])
384     #
385     checkProg('a PS to TXT converter', ['ps2ascii $$i $$o'],
386         rc_entry = [ r'\converter ps         text3      "%%"    ""' ])
387     #
388     checkProg('a DVI to TXT converter', ['catdvi $$i > $$o'],
389         rc_entry = [ r'\converter dvi        text4      "%%"    ""' ])
390     #
391     checkProg('a DVI to PS converter', ['dvips -o $$o $$i'],
392         rc_entry = [ r'\converter dvi        ps         "%%"    ""' ])
393     #
394     checkProg('a DVI to PDF converter', ['dvipdfmx -o $$o $$i', 'dvipdfm -o $$o $$i'],
395         rc_entry = [ r'\converter dvi        pdf3       "%%"    ""' ])
396     #
397     path, dvipng = checkProg('dvipng', ['dvipng'])
398     if dvipng == "dvipng":
399         addToRC(r'\converter lyxpreview png        "python -tt $$s/scripts/lyxpreview2bitmap.py"        ""')
400     else:
401         addToRC(r'\converter lyxpreview png        ""   ""')
402     #  
403     checkProg('a fax program', ['kdeprintfax $$i', 'ksendfax $$i'],
404         rc_entry = [ r'\converter ps         fax        "%%"    ""'])
405     #
406     checkProg('a FIG -> EPS/PPM converter', ['fig2dev'],
407         rc_entry = [
408             r'''\converter fig        eps        "fig2dev -L eps $$i $$o"       ""
409 \converter fig        ppm        "fig2dev -L ppm $$i $$o"       ""
410 \converter fig        png        "fig2dev -L png $$i $$o"       ""''',
411             ''])
412     #
413     checkProg('a TIFF -> PS converter', ['tiff2ps $$i > $$o'],
414         rc_entry = [ r'\converter tiff       eps        "%%"    ""', ''])
415     #
416     checkProg('a TGIF -> EPS/PPM converter', ['tgif'],
417         rc_entry = [
418             r'''\converter tgif       eps        "tgif -stdout -print -color -eps $$i > $$o"    ""
419 \converter tgif       ppm        "tgif -stdout -print -color -ppm $$i > $$o"    ""
420 \converter tgif       png        "tgif -stdout -print -color -png $$i > $$o"    ""
421 \converter tgif       pdf        "tgif -stdout -print -color -pdf $$i > $$o"    ""''',
422             ''])
423     #
424     checkProg('a WMF -> EPS converter', ['metafile2eps $$i $$o', 'wmf2eps -o $$o $$i'],
425         rc_entry = [ r'\converter wmf        eps        "%%"    ""'])
426     #
427     checkProg('an EMF -> EPS converter', ['metafile2eps $$i $$o', 'wmf2eps -o $$o $$i'],
428         rc_entry = [ r'\converter emf        eps        "%%"    ""'])
429     #
430     checkProg('an EPS -> PDF converter', ['epstopdf'],
431         rc_entry = [ r'\converter eps        pdf        "epstopdf --outfile=$$o $$i"    ""', ''])
432     #
433     # no agr -> pdf converter, since the pdf library used by gracebat is not
434     # free software and therefore not compiled in in many installations.
435     # Fortunately, this is not a big problem, because we will use epstopdf to
436     # convert from agr to pdf via eps without loss of quality.
437     checkProg('a Grace -> Image converter', ['gracebat'],
438         rc_entry = [
439             r'''\converter agr        eps        "gracebat -hardcopy -printfile $$o -hdevice EPS $$i 2>/dev/null"       ""
440 \converter agr        png        "gracebat -hardcopy -printfile $$o -hdevice PNG $$i 2>/dev/null"       ""
441 \converter agr        jpg        "gracebat -hardcopy -printfile $$o -hdevice JPEG $$i 2>/dev/null"      ""
442 \converter agr        ppm        "gracebat -hardcopy -printfile $$o -hdevice PNM $$i 2>/dev/null"       ""''',
443             ''])
444     #
445     #
446     path, lilypond = checkProg('a LilyPond -> EPS/PDF/PNG converter', ['lilypond'])
447     if (lilypond != ''):
448         version_string = cmdOutput("lilypond --version")
449         match = re.match('GNU LilyPond (\S+)', version_string)
450         if match:
451             version_number = match.groups()[0]
452             version = version_number.split('.')
453             if int(version[0]) > 2 or (len(version) > 1 and int(version[0]) == 2 and int(version[1]) >= 6):
454                 addToRC(r'''\converter lilypond   eps        "lilypond -b eps --ps $$i" ""
455 \converter lilypond   png        "lilypond -b eps --png $$i"    ""''')
456                 if int(version[0]) > 2 or (len(version) > 1 and int(version[0]) == 2 and int(version[1]) >= 9):
457                     addToRC(r'\converter lilypond   pdf        "lilypond -b eps --pdf $$i"      ""')
458                 print '+  found LilyPond version %s.' % version_number
459             else:
460                 print '+  found LilyPond, but version %s is too old.' % version_number
461         else:
462             print '+  found LilyPond, but could not extract version number.'
463     #
464     checkProg('a Noteedit -> LilyPond converter', ['noteedit --export-lilypond $$i'],
465         rc_entry = [ r'\converter noteedit   lilypond   "%%"    ""', ''])
466     #
467     # FIXME: no rc_entry? comment it out
468     # checkProg('Image converter', ['convert $$i $$o'])
469     #
470     # Entries that do not need checkProg
471     addToRC(r'''\converter lyxpreview ppm        "python -tt $$s/scripts/lyxpreview2bitmap.py"  ""
472 \converter date       dateout    "python -tt $$s/scripts/date.py %d-%m-%Y > $$o"        ""
473 \converter docbook    docbook-xml "cp $$i $$o"  "xml"
474 \converter fen        asciichess "python -tt $$s/scripts/fen2ascii.py $$i $$o"  ""
475 \converter fig        pdftex     "python -tt $$s/scripts/fig2pdftex.py $$i $$o" ""
476 \converter fig        pstex      "python -tt $$s/scripts/fig2pstex.py $$i $$o"  ""
477 \converter lyx        lyx13x     "python -tt $$s/lyx2lyx/lyx2lyx -t 221 $$i > $$o"      ""
478 \converter lyx        lyx14x     "python -tt $$s/lyx2lyx/lyx2lyx -t 245 $$i > $$o"      ""
479 \converter lyx        clyx       "python -tt $$s/lyx2lyx/lyx2lyx -c big5 -t 245 $$i > $$o"      ""
480 \converter lyx        jlyx       "python -tt $$s/lyx2lyx/lyx2lyx -c euc_jp -t 245 $$i > $$o"    ""
481 \converter lyx        klyx       "python -tt $$s/lyx2lyx/lyx2lyx -c euc_kr -t 245 $$i > $$o"    ""
482 \converter clyx       lyx        "python -tt $$s/lyx2lyx/lyx2lyx -c big5 $$i > $$o"     ""
483 \converter jlyx       lyx        "python -tt $$s/lyx2lyx/lyx2lyx -c euc_jp $$i > $$o"   ""
484 \converter klyx       lyx        "python -tt $$s/lyx2lyx/lyx2lyx -c euc_kr $$i > $$o"   ""
485 ''')
486
487
488 def checkLinuxDoc():
489     ''' Check linuxdoc '''
490     #
491     path, LINUXDOC = checkProg('SGML-tools 1.x (LinuxDoc)', ['sgml2lyx'],
492         rc_entry = [
493         r'''\converter linuxdoc   lyx        "sgml2lyx $$i"     ""
494 \converter linuxdoc   latex      "sgml2latex $$i"       ""
495 \converter linuxdoc   dvi        "sgml2latex -o dvi $$i"        ""
496 \converter linuxdoc   html       "sgml2html $$i"        ""''',
497         r'''\converter linuxdoc   lyx        "" ""
498 \converter linuxdoc   latex      ""     ""
499 \converter linuxdoc   dvi        ""     ""
500 \converter linuxdoc   html       ""     ""''' ])
501     if LINUXDOC != '':
502         return ('yes', 'true', '\\def\\haslinuxdoc{yes}')
503     else:
504         return ('no', 'false', '')
505
506
507 def checkDocBook():
508     ''' Check docbook '''
509     path, DOCBOOK = checkProg('SGML-tools 2.x (DocBook) or db2x scripts', ['sgmltools', 'db2dvi'],
510         rc_entry = [
511             r'''\converter docbook    dvi        "sgmltools -b dvi $$i" ""
512 \converter docbook    html       "sgmltools -b html $$i"        ""''',
513             r'''\converter docbook    dvi        "db2dvi $$i"   ""
514 \converter docbook    html       "db2html $$i"  ""''',
515             r'''\converter docbook    dvi        ""     ""
516 \converter docbook    html       ""     ""'''])
517     #
518     if DOCBOOK != '':
519         return ('yes', 'true', '\\def\\hasdocbook{yes}')
520     else:
521         return ('no', 'false', '')
522
523
524 def checkOtherEntries():
525     ''' entries other than Format and Converter '''
526     checkProg('a *roff formatter', ['groff', 'nroff'],
527         rc_entry = [
528             r'\plaintext_roff_command "groff -t -Tlatin1 $$FName"',
529             r'\plaintext_roff_command "tbl $$FName | nroff"',
530             r'\plaintext_roff_command ""' ])
531     checkProg('ChkTeX', ['chktex -n1 -n3 -n6 -n9 -n22 -n25 -n30 -n38'],
532         rc_entry = [ r'\chktex_command "%%"' ])
533     checkProg('a spellchecker', ['ispell'],
534         rc_entry = [ r'\spell_command "%%"' ])
535     ## FIXME: OCTAVE is not used anywhere
536     # path, OCTAVE = checkProg('Octave', ['octave'])
537     ## FIXME: MAPLE is not used anywhere
538     # path, MAPLE = checkProg('Maple', ['maple'])
539     checkProg('a spool command', ['lp', 'lpr'],
540         rc_entry = [
541             r'''\print_spool_printerprefix "-d "
542 \print_spool_command "lp"''',
543             r'''\print_spool_printerprefix "-P",
544 \print_spool_command "lpr"''',
545             ''])
546     # Add the rest of the entries (no checkProg is required)
547     addToRC(r'''\copier    fig        "python -tt $$s/scripts/fig_copy.py $$i $$o"
548 \copier    pstex      "python -tt $$s/scripts/tex_copy.py $$i $$o $$l"
549 \copier    pdftex     "python -tt $$s/scripts/tex_copy.py $$i $$o $$l"
550 \copier    program    "python -tt $$s/scripts/ext_copy.py $$i $$o"
551 ''')
552
553
554 def processLayoutFile(file, bool_docbook, bool_linuxdoc):
555     ''' process layout file and get a line of result
556         
557         Declare lines look like this: (article.layout, scrbook.layout, svjog.layout)
558         
559         \DeclareLaTeXClass{article}
560         \DeclareLaTeXClass[scrbook]{book (koma-script)}
561         \DeclareLaTeXClass[svjour,svjog.clo]{article (Springer - svjour/jog)}
562
563         we expect output:
564         
565         "article" "article" "article" "false"
566         "scrbook" "scrbook" "book (koma-script)" "false"
567         "svjog" "svjour" "article (Springer - svjour/jog)" "false"
568     '''
569     classname = file.split(os.sep)[-1].split('.')[0]
570     # return ('LaTeX', '[a,b]', 'a', ',b,c', 'article') for \DeclareLaTeXClass[a,b,c]{article}
571     p = re.compile(r'\Declare(LaTeX|DocBook|LinuxDoc)Class\s*(\[([^,]*)(,.*)*\])*\s*{(.*)}')
572     for line in open(file).readlines():
573         res = p.search(line)
574         if res != None:
575             (classtype, optAll, opt, opt1, desc) = res.groups()
576             avai = {'LaTeX':'false', 'DocBook':bool_docbook, 'LinuxDoc':bool_linuxdoc}[classtype]
577             if opt == None:
578                 opt = classname
579             return '"%s" "%s" "%s" "%s"\n' % (classname, opt, desc, avai)
580     print "Layout file without \DeclareXXClass line. "
581     sys.exit(2)
582
583     
584 def checkLatexConfig(check_config, bool_docbook, bool_linuxdoc):
585     ''' Explore the LaTeX configuration '''
586     print 'checking LaTeX configuration... ',
587     # First, remove the files that we want to re-create
588     removeFiles(['textclass.lst', 'packages.lst', 'chkconfig.sed'])
589     #
590     if not check_config:
591         print ' default values'
592         print '+checking list of textclasses... '
593         tx = open('textclass.lst', 'w')
594         tx.write('''
595 # This file declares layouts and their associated definition files
596 # (include dir. relative to the place where this file is).
597 # It contains only default values, since chkconfig.ltx could not be run
598 # for some reason. Run ./configure.py if you need to update it after a
599 # configuration change.
600 ''')
601         # build the list of available layout files and convert it to commands
602         # for chkconfig.ltx
603         foundClasses = []
604         for file in glob.glob( os.path.join('layouts', '*.layout') ) + \
605             glob.glob( os.path.join(srcdir, 'layouts', '*.layout' ) ) :
606             # valid file?
607             if not os.path.isfile(file): 
608                 continue
609             # get stuff between /xxxx.layout .
610             classname = file.split(os.sep)[-1].split('.')[0]
611             #  tr ' -' '__'`
612             cleanclass = classname.replace(' ', '_')
613             cleanclass = cleanclass.replace('-', '_')
614             # make sure the same class is not considered twice
615             if foundClasses.count(cleanclass) == 0: # not found before
616                 foundClasses.append(cleanclass)
617                 tx.write(processLayoutFile(file, bool_docbook, bool_linuxdoc))
618         tx.close()
619         print '\tdone'
620     else:
621         print '\tauto'
622         removeFiles(['wrap_chkconfig.ltx', 'chkconfig.vars', \
623             'chkconfig.classes', 'chklayouts.tex'])
624         rmcopy = False
625         if not os.path.isfile( 'chkconfig.ltx' ):
626             shutil.copy( os.path.join(srcdir, 'chkconfig.ltx'),  'chkconfig.ltx' )
627             rmcopy = True
628         writeToFile('wrap_chkconfig.ltx', '%s\n%s\n\\input{chkconfig.ltx}\n' \
629             % (linuxdoc_cmd, docbook_cmd) )
630         # Construct the list of classes to test for.
631         # build the list of available layout files and convert it to commands
632         # for chkconfig.ltx
633         p1 = re.compile(r'\Declare(LaTeX|DocBook)Class')
634         testclasses = list()
635         for file in glob.glob( os.path.join('layouts', '*.layout') ) + \
636             glob.glob( os.path.join(srcdir, 'layouts', '*.layout' ) ) :
637             if not os.path.isfile(file):
638                 continue
639             classname = file.split(os.sep)[-1].split('.')[0]
640             for line in open(file).readlines():
641                 if p1.search(line) == None:
642                     continue
643                 if line[0] != '#':
644                     print "Wrong input layout file with line '" + line
645                     sys.exit(3)
646                 testclasses.append("\\TestDocClass{%s}{%s}" % (classname, line[1:].strip()))
647                 break
648         testclasses.sort()
649         cl = open('chklayouts.tex', 'w')
650         for line in testclasses:
651             cl.write(line + '\n')
652         cl.close()
653         #
654         # we have chklayouts.tex, then process it
655         fout = os.popen(LATEX + ' wrap_chkconfig.ltx')
656         while True:
657             line = fout.readline()
658             if not line:
659                 break;
660             if re.match('^\+', line):
661                 print line,
662         fout.close()
663         #
664         # currently, values in chhkconfig are only used to set
665         # \font_encoding
666         values = {}
667         for line in open('chkconfig.vars').readlines():
668             key, val = re.sub('-', '_', line).split('=')
669             val = val.strip()
670             values[key] = val.strip("'")
671         # chk_fontenc may not exist 
672         try:
673             addToRC(r'\font_encoding "%s"' % values["chk_fontenc"])
674         except:
675             pass
676         if rmcopy:   # remove the copied file
677             removeFiles( [ 'chkconfig.ltx' ] )
678
679
680 def createLaTeXConfig():
681     ''' create LaTeXConfig.lyx '''
682     # if chkconfig.sed does not exist (because LaTeX did not run),
683     # then provide a standard version.
684     if not os.path.isfile('chkconfig.sed'):
685         writeToFile('chkconfig.sed', 's!@.*@!???!g\n')
686     print "creating packages.lst"
687     # if packages.lst does not exist (because LaTeX did not run),
688     # then provide a standard version.
689     if not os.path.isfile('packages.lst'):
690         writeToFile('packages.lst', '''
691 ### This file should contain the list of LaTeX packages that have been
692 ### recognized by LyX. Unfortunately, since configure could not find
693 ### your LaTeX2e program, the tests have not been run. Run ./configure.py
694 ### if you need to update it after a configuration change.
695 ''')
696     print 'creating doc/LaTeXConfig.lyx'
697     #
698     # This is originally done by sed, using a
699     # tex-generated file chkconfig.sed
700     ##sed -f chkconfig.sed ${srcdir}/doc/LaTeXConfig.lyx.in
701     ##  >doc/LaTeXConfig.lyx
702     # Now, we have to do it by hand (python).
703     #
704     # add to chekconfig.sed
705     writeToFile('chkconfig.sed', '''s!@chk_linuxdoc@!%s!g
706 s!@chk_docbook@!%s!g
707     ''' % (chk_linuxdoc, chk_docbook) , append=True)
708     # process this sed file!!!!
709     lyxin = open( os.path.join(srcdir, 'doc', 'LaTeXConfig.lyx.in')).readlines()
710     # get the rules
711     p = re.compile(r's!(.*)!(.*)!g')
712     # process each sed replace.
713     for sed in open('chkconfig.sed').readlines():
714         if sed.strip() == '':
715             continue
716         try:
717             fr, to = p.match(sed).groups()
718             # if latex did not run, change all @name@ to '???'
719             if fr == '@.*@':
720                 for line in range(len(lyxin)):
721                     lyxin[line] = re.sub('@.*@', to, lyxin[line])
722             else:
723                 for line in range(len(lyxin)):
724                     lyxin[line] = lyxin[line].replace(fr, to)
725         except:  # wrong sed entry?
726             print "Wrong sed entry in chkconfig.sed: '" + sed + "'"
727             sys.exit(4)
728     # 
729     writeToFile( os.path.join('doc', 'LaTeXConfig.lyx'),
730         ''.join(lyxin))
731
732
733 def checkTeXAllowSpaces():
734     ''' Let's check whether spaces are allowed in TeX file names '''
735     tex_allows_spaces = 'false'
736     if lyx_check_config:
737         print "Checking whether TeX allows spaces in file names... ",
738         writeToFile('a b.tex', r'\message{working^^J}' )
739         if os.name == 'nt':
740             latex_out = cmdOutput(LATEX + r""" "\nonstopmode\input{\"a b\"}" """)
741         else:
742             latex_out = cmdOutput(LATEX + r""" '\nonstopmode\input{"a b"}' """)
743         if 'working' in latex_out:
744             print 'yes'
745             tex_allows_spaces = 'true'
746         else:
747             print 'no'
748             tex_allows_spaces = 'false'
749         addToRC(r'\tex_allows_spaces ' + tex_allows_spaces)
750         removeFiles( [ 'a b.tex', 'a b.log', 'texput.log' ])
751
752
753 def removeTempFiles():
754     # Final clean-up
755     if not lyx_keep_temps:
756         removeFiles(['chkconfig.sed', 'chkconfig.vars',  \
757             'wrap_chkconfig.ltx', 'wrap_chkconfig.log', \
758             'chklayouts.tex', 'missfont.log', 
759             'chklatex.ltx', 'chklatex.log'])
760
761
762 if __name__ == '__main__':
763     lyx_check_config = True
764     outfile = 'lyxrc.defaults'
765     rc_entries = ''
766     lyx_keep_temps = False
767     version_suffix = ''
768     logfile = 'configure.log'
769     ## Parse the command line
770     for op in sys.argv[1:]:   # default shell/for list is $*, the options
771         if op in [ '-help', '--help', '-h' ]:
772             print '''Usage: configure [options]
773 Options:
774     --help                   show this help lines
775     --keep-temps             keep temporary files (for debug. purposes)
776     --without-latex-config   do not run LaTeX to determine configuration
777     --with-version-suffix=suffix suffix of binary installed files
778 '''
779             sys.exit(0)
780         elif op == '--without-latex-config':
781             lyx_check_config = False
782         elif op == '--keep-temps':
783             lyx_keep_temps = True
784         elif op[0:22] == '--with-version-suffix=':  # never mind if op is not long enough
785             version_suffix = op[22:]
786         else:
787             print "Unknown option", op
788             sys.exit(1)
789     #
790     # set up log file for stdout and stderr
791     log = open(logfile, 'w')
792     sys.stdout = Tee(sys.stdout, log)
793     sys.stderr = Tee(sys.stderr, log)
794     # check if we run from the right directory
795     srcdir = os.path.dirname(sys.argv[0])
796     if srcdir == '':
797         srcdir = '.'
798     if not os.path.isfile( os.path.join(srcdir, 'chkconfig.ltx') ):
799         print "configure: error: cannot find chkconfig.ltx script"
800         sys.exit(1)
801     setEnviron()
802     createDirectories()
803     windows_style_tex_paths = checkTeXPaths()
804     dtl_tools = checkDTLtools()
805     ## Write the first part of outfile
806     writeToFile(outfile, '''# This file has been automatically generated by LyX' lib/configure.py
807 # script. It contains default settings that have been determined by
808 # examining your system. PLEASE DO NOT MODIFY ANYTHING HERE! If you
809 # want to customize LyX, use LyX' Preferences dialog or modify directly 
810 # the "preferences" file instead. Any setting in that file will
811 # override the values given here.
812 ''')
813     # check latex
814     LATEX = checkLatex(dtl_tools)
815     checkFormatEntries(dtl_tools)
816     checkConverterEntries()
817     (chk_linuxdoc, bool_linuxdoc, linuxdoc_cmd) = checkLinuxDoc()
818     (chk_docbook, bool_docbook, docbook_cmd) = checkDocBook()
819     checkTeXAllowSpaces()
820     if windows_style_tex_paths != '':
821         addToRC(r'\tex_expects_windows_paths %s' % windows_style_tex_paths)
822     checkOtherEntries()
823     # --without-latex-config can disable lyx_check_config
824     checkLatexConfig( lyx_check_config and LATEX != '', bool_docbook, bool_linuxdoc)
825     createLaTeXConfig()
826     removeTempFiles()