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