]> git.lyx.org Git - lyx.git/blob - lib/lyx2lyx/lyx_2_4.py
typo
[lyx.git] / lib / lyx2lyx / lyx_2_4.py
1 # -*- coding: utf-8 -*-
2 # This file is part of lyx2lyx
3 # Copyright (C) 2018 The LyX team
4 #
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 """ Convert files to the file format generated by lyx 2.4"""
20
21 import re, string
22 import unicodedata
23 import sys, os
24
25 from datetime import (datetime, date, time)
26
27 # Uncomment only what you need to import, please.
28
29 from parser_tools import (count_pars_in_inset, find_end_of_inset, find_end_of_layout,
30 find_token, get_bool_value, get_option_value, get_value, get_quoted_value)
31 #    del_token, del_value, del_complete_lines,
32 #    find_complete_lines, find_end_of,
33 #    find_re, find_substring, find_token_backwards,
34 #    get_containing_inset, get_containing_layout,
35 #    is_in_inset, set_bool_value
36 #    find_tokens, find_token_exact, check_token
37
38 from lyx2lyx_tools import (put_cmd_in_ert, add_to_preamble)
39 #  revert_font_attrs, insert_to_preamble, latex_length
40 #  get_ert, lyx2latex, lyx2verbatim, length_in_bp, convert_info_insets
41 #  revert_flex_inset, hex2ratio, str2bool
42
43 ####################################################################
44 # Private helper functions
45
46
47
48 ###############################################################################
49 ###
50 ### Conversion and reversion routines
51 ###
52 ###############################################################################
53
54 def removeFrontMatterStyles(document):
55     " Remove styles Begin/EndFromatter"
56
57     layouts = ['BeginFrontmatter', 'EndFrontmatter']
58     for layout in layouts:
59         i = 0
60         while True:
61             i = find_token(document.body, '\\begin_layout ' + layout, i)
62             if i == -1:
63                 break
64             j = find_end_of_layout(document.body, i)
65             if j == -1:
66                 document.warning("Malformed LyX document: Can't find end of layout at line %d" % i)
67                 i += 1
68                 continue
69             while i > 0 and document.body[i-1].strip() == '':
70                 i -= 1
71             while document.body[j+1].strip() == '':
72                 j = j + 1
73             document.body[i:j+1] = ['']
74
75 def addFrontMatterStyles(document):
76     " Use styles Begin/EndFrontmatter for elsarticle"
77
78     def insertFrontmatter(prefix, line):
79         above = line
80         while above > 0 and document.body[above-1].strip() == '':
81             above -= 1
82         below = line
83         while document.body[below].strip() == '':
84             below += 1
85         document.body[above:below] = ['', '\\begin_layout ' + prefix + 'Frontmatter',
86                                     '\\begin_inset Note Note',
87                                     'status open', '',
88                                     '\\begin_layout Plain Layout',
89                                     'Keep this empty!',
90                                     '\\end_layout', '',
91                                     '\\end_inset', '', '',
92                                     '\\end_layout', '']
93
94     if document.textclass == "elsarticle":
95         layouts = ['Title', 'Title footnote', 'Author', 'Author footnote',
96                    'Corresponding author', 'Address', 'Email', 'Abstract', 'Keywords']
97         first = -1
98         last = -1
99         for layout in layouts:
100             i = 0
101             while True:
102                 i = find_token(document.body, '\\begin_layout ' + layout, i)
103                 if i == -1:
104                     break
105                 k = find_end_of_layout(document.body, i)
106                 if k == -1:
107                     document.warning("Malformed LyX document: Can't find end of layout at line %d" % i)
108                     i += 1;
109                     continue
110                 if first == -1 or i < first:
111                     first = i
112                 if last == -1 or last <= k:
113                     last = k+1
114                 i = k+1
115         if first == -1:
116             return
117         insertFrontmatter('End', last)
118         insertFrontmatter('Begin', first)
119
120 def convert_lst_literalparam(document):
121     " Add param literal to include inset "
122
123     i = 0
124     while True:
125         i = find_token(document.body, '\\begin_inset CommandInset include', i)
126         if i == -1:
127             break
128         j = find_end_of_inset(document.body, i)
129         if j == -1:
130             document.warning("Malformed LyX document: Can't find end of command inset at line %d" % i)
131             i += 1
132             continue
133         while i < j and document.body[i].strip() != '':
134             i += 1
135         document.body.insert(i, "literal \"true\"")
136
137
138 def revert_lst_literalparam(document):
139     " Remove param literal from include inset "
140
141     i = 0
142     while True:
143         i = find_token(document.body, '\\begin_inset CommandInset include', i)
144         if i == -1:
145             break
146         j = find_end_of_inset(document.body, i)
147         if j == -1:
148             document.warning("Malformed LyX document: Can't find end of include inset at line %d" % i)
149             i += 1
150             continue
151         k = find_token(document.body, 'literal', i, j)
152         if k == -1:
153             i += 1
154             continue
155         del document.body[k]
156
157
158 def revert_paratype(document):
159     " Revert ParaType font definitions to LaTeX "
160
161     if find_token(document.header, "\\use_non_tex_fonts false", 0) != -1:
162         preamble = ""
163         i1 = find_token(document.header, "\\font_roman \"PTSerif-TLF\"", 0)
164         i2 = find_token(document.header, "\\font_sans \"default\"", 0)
165         i3 = find_token(document.header, "\\font_typewriter \"default\"", 0)
166         j = find_token(document.header, "\\font_sans \"PTSans-TLF\"", 0)
167         sfval = get_value(document.header, "\\font_sf_scale", 0)
168         # cutoff " 100"
169         sfval = sfval[:-4]
170         sfoption = ""
171         if sfval != "100":
172             sfoption = "scaled=" + format(float(sfval) / 100, '.2f')
173         k = find_token(document.header, "\\font_typewriter \"PTMono-TLF\"", 0)
174         ttval = get_value(document.header, "\\font_tt_scale", 0)
175         # cutoff " 100"
176         ttval = ttval[:-4]
177         ttoption = ""
178         if ttval != "100":
179             ttoption = "scaled=" + format(float(ttval) / 100, '.2f')
180         if i1 != -1 and i2 != -1 and i3!= -1:
181             add_to_preamble(document, ["\\usepackage{paratype}"])
182         else:
183             if i1!= -1:
184                 add_to_preamble(document, ["\\usepackage{PTSerif}"])
185                 document.header[i1] = document.header[i1].replace("PTSerif-TLF", "default")
186             if j!= -1:
187                 if sfoption != "":
188                     add_to_preamble(document, ["\\usepackage[" + sfoption + "]{PTSans}"])
189                 else:
190                     add_to_preamble(document, ["\\usepackage{PTSans}"])
191                 document.header[j] = document.header[j].replace("PTSans-TLF", "default")
192             if k!= -1:
193                 if ttoption != "":
194                     add_to_preamble(document, ["\\usepackage[" + ttoption + "]{PTMono}"])
195                 else:
196                     add_to_preamble(document, ["\\usepackage{PTMono}"])
197                 document.header[k] = document.header[k].replace("PTMono-TLF", "default")
198
199
200 def revert_xcharter(document):
201     " Revert XCharter font definitions to LaTeX "
202
203     i = find_token(document.header, "\\font_roman \"xcharter\"", 0)
204     if i == -1:
205         return
206
207     # replace unsupported font setting
208     document.header[i] = document.header[i].replace("xcharter", "default")
209     # no need for preamble code with system fonts
210     if get_bool_value(document.header, "\\use_non_tex_fonts"):
211         return
212
213     # transfer old style figures setting to package options
214     j = find_token(document.header, "\\font_osf true")
215     if j != -1:
216         options = "[osf]"
217         document.header[j] = "\\font_osf false"
218     else:
219         options = ""
220     if i != -1:
221         add_to_preamble(document, ["\\usepackage%s{XCharter}"%options])
222
223
224 def revert_lscape(document):
225     " Reverts the landscape environment (Landscape module) to TeX-code "
226
227     if not "landscape" in document.get_module_list():
228         return
229
230     i = 0
231     while True:
232         i = find_token(document.body, "\\begin_inset Flex Landscape", i)
233         if i == -1:
234             return
235         j = find_end_of_inset(document.body, i)
236         if j == -1:
237             document.warning("Malformed LyX document: Can't find end of Landscape inset")
238             i += 1
239             continue
240
241         if document.body[i] == "\\begin_inset Flex Landscape (Floating)":
242             document.body[j - 2 : j + 1] = put_cmd_in_ert("\\end{landscape}}")
243             document.body[i : i + 4] = put_cmd_in_ert("\\afterpage{\\begin{landscape}")
244             add_to_preamble(document, ["\\usepackage{afterpage}"])
245         else:
246             document.body[j - 2 : j + 1] = put_cmd_in_ert("\\end{landscape}")
247             document.body[i : i + 4] = put_cmd_in_ert("\\begin{landscape}")
248
249         add_to_preamble(document, ["\\usepackage{pdflscape}"])
250         # no need to reset i
251
252
253 def convert_fontenc(document):
254     " Convert default fontenc setting "
255
256     i = find_token(document.header, "\\fontencoding global", 0)
257     if i == -1:
258         return
259
260     document.header[i] = document.header[i].replace("global", "auto")
261
262
263 def revert_fontenc(document):
264     " Revert default fontenc setting "
265
266     i = find_token(document.header, "\\fontencoding auto", 0)
267     if i == -1:
268         return
269
270     document.header[i] = document.header[i].replace("auto", "global")
271
272
273 def revert_nospellcheck(document):
274     " Remove nospellcheck font info param "
275
276     i = 0
277     while True:
278         i = find_token(document.body, '\\nospellcheck', i)
279         if i == -1:
280             return
281         del document.body[i]
282
283
284 def revert_floatpclass(document):
285     " Remove float placement params 'document' and 'class' "
286
287     i = 0
288     i = find_token(document.header, "\\float_placement class", 0)
289     if i != -1:
290         del document.header[i]
291
292     i = 0
293     while True:
294         i = find_token(document.body, '\\begin_inset Float', i)
295         if i == -1:
296             break
297         j = find_end_of_inset(document.body, i)
298         k = find_token(document.body, 'placement class', i, i + 2)
299         if k == -1:
300             k = find_token(document.body, 'placement document', i, i + 2)
301             if k != -1:
302                 del document.body[k]
303             i = j
304             continue
305         del document.body[k]
306
307
308 def revert_floatalignment(document):
309     " Remove float alignment params "
310
311     i = 0
312     i = find_token(document.header, "\\float_alignment", 0)
313     galignment = ""
314     if i != -1:
315         galignment = get_value(document.header, "\\float_alignment", i)
316         del document.header[i]
317
318     i = 0
319     while True:
320         i = find_token(document.body, '\\begin_inset Float', i)
321         if i == -1:
322             break
323         j = find_end_of_inset(document.body, i)
324         if j == -1:
325             document.warning("Malformed LyX document: Can't find end of inset at line " + str(i))
326             i += 1
327         k = find_token(document.body, 'alignment', i, i + 4)
328         if k == -1:
329             i = j
330             continue
331         alignment = get_value(document.body, "alignment", k)
332         if alignment == "document":
333             alignment = galignment
334         del document.body[k]
335         l = find_token(document.body, "\\begin_layout Plain Layout", i, j)
336         if l == -1:
337             document.warning("Can't find float layout!")
338             i = j
339             continue
340         alcmd = []
341         if alignment == "left":
342             alcmd = put_cmd_in_ert("\\raggedright{}")
343         elif alignment == "center":
344             alcmd = put_cmd_in_ert("\\centering{}")
345         elif alignment == "right":
346             alcmd = put_cmd_in_ert("\\raggedleft{}")
347         if len(alcmd) > 0:
348             document.body[l+1:l+1] = alcmd
349         i = j 
350
351
352 def revert_tuftecite(document):
353     " Revert \cite commands in tufte classes "
354
355     tufte = ["tufte-book", "tufte-handout"]
356     if document.textclass not in tufte:
357         return
358
359     i = 0
360     while (True):
361         i = find_token(document.body, "\\begin_inset CommandInset citation", i)
362         if i == -1:
363             break
364         j = find_end_of_inset(document.body, i)
365         if j == -1:
366             document.warning("Can't find end of citation inset at line %d!!" %(i))
367             i += 1
368             continue
369         k = find_token(document.body, "LatexCommand", i, j)
370         if k == -1:
371             document.warning("Can't find LatexCommand for citation inset at line %d!" %(i))
372             i = j + 1
373             continue
374         cmd = get_value(document.body, "LatexCommand", k)
375         if cmd != "cite":
376             i = j + 1
377             continue
378         pre = get_quoted_value(document.body, "before", i, j)
379         post = get_quoted_value(document.body, "after", i, j)
380         key = get_quoted_value(document.body, "key", i, j)
381         if not key:
382             document.warning("Citation inset at line %d does not have a key!" %(i))
383             key = "???"
384         # Replace command with ERT
385         res = "\\cite"
386         if pre:
387             res += "[" + pre + "]"
388         if post:
389             res += "[" + post + "]"
390         elif pre:
391             res += "[]"
392         res += "{" + key + "}"
393         document.body[i:j+1] = put_cmd_in_ert([res])
394         i = j + 1
395
396
397 def revert_stretchcolumn(document):
398     " We remove the column varwidth flags or everything else will become a mess. "
399     i = 0
400     while True:
401         i = find_token(document.body, "\\begin_inset Tabular", i)
402         if i == -1:
403             return
404         j = find_end_of_inset(document.body, i + 1)
405         if j == -1:
406             document.warning("Malformed LyX document: Could not find end of tabular.")
407             continue
408         for k in range(i, j):
409             if re.search('^<column.*varwidth="[^"]+".*>$', document.body[k]):
410                 document.warning("Converting 'tabularx'/'xltabular' table to normal table.")
411                 document.body[k] = document.body[k].replace(' varwidth="true"', '')
412         i = i + 1
413
414
415 def revert_vcolumns(document):
416     " Revert standard columns with line breaks etc. "
417     i = 0
418     needvarwidth = False
419     needarray = False
420     try:
421         while True:
422             i = find_token(document.body, "\\begin_inset Tabular", i)
423             if i == -1:
424                 return
425             j = find_end_of_inset(document.body, i)
426             if j == -1:
427                 document.warning("Malformed LyX document: Could not find end of tabular.")
428                 i += 1
429                 continue
430
431             # Collect necessary column information
432             m = i + 1
433             nrows = int(document.body[i+1].split('"')[3])
434             ncols = int(document.body[i+1].split('"')[5])
435             col_info = []
436             for k in range(ncols):
437                 m = find_token(document.body, "<column", m)
438                 width = get_option_value(document.body[m], 'width')
439                 varwidth = get_option_value(document.body[m], 'varwidth')
440                 alignment = get_option_value(document.body[m], 'alignment')
441                 special = get_option_value(document.body[m], 'special')
442                 col_info.append([width, varwidth, alignment, special, m])
443
444             # Now parse cells
445             m = i + 1
446             lines = []
447             for row in range(nrows):
448                 for col in range(ncols):
449                     m = find_token(document.body, "<cell", m)
450                     multicolumn = get_option_value(document.body[m], 'multicolumn')
451                     multirow = get_option_value(document.body[m], 'multirow')
452                     width = get_option_value(document.body[m], 'width')
453                     rotate = get_option_value(document.body[m], 'rotate')
454                     # Check for: linebreaks, multipars, non-standard environments
455                     begcell = m
456                     endcell = find_token(document.body, "</cell>", begcell)
457                     vcand = False
458                     if find_token(document.body, "\\begin_inset Newline", begcell, endcell) != -1:
459                         vcand = True
460                     elif count_pars_in_inset(document.body, begcell + 2) > 1:
461                         vcand = True
462                     elif get_value(document.body, "\\begin_layout", begcell) != "Plain Layout":
463                         vcand = True
464                     if vcand and rotate == "" and ((multicolumn == "" and multirow == "") or width == ""):
465                         if col_info[col][0] == "" and col_info[col][1] == "" and col_info[col][3] == "":
466                             needvarwidth = True
467                             alignment = col_info[col][2]
468                             col_line = col_info[col][4]
469                             vval = ""
470                             if alignment == "center":
471                                 vval = ">{\\centering}"
472                             elif  alignment == "left":
473                                 vval = ">{\\raggedright}"
474                             elif alignment == "right":
475                                 vval = ">{\\raggedleft}"
476                             if vval != "":
477                                 needarray = True
478                             vval += "V{\\linewidth}"
479                 
480                             document.body[col_line] = document.body[col_line][:-1] + " special=\"" + vval + "\">"
481                             # ERT newlines and linebreaks (since LyX < 2.4 automatically inserts parboxes
482                             # with newlines, and we do not want that)
483                             while True:
484                                 endcell = find_token(document.body, "</cell>", begcell)
485                                 linebreak = False
486                                 nl = find_token(document.body, "\\begin_inset Newline newline", begcell, endcell)
487                                 if nl == -1:
488                                     nl = find_token(document.body, "\\begin_inset Newline linebreak", begcell, endcell)
489                                     if nl == -1:
490                                          break
491                                     linebreak = True
492                                 nle = find_end_of_inset(document.body, nl)
493                                 del(document.body[nle:nle+1])
494                                 if linebreak:
495                                     document.body[nl:nl+1] = put_cmd_in_ert("\\linebreak{}")
496                                 else:
497                                     document.body[nl:nl+1] = put_cmd_in_ert("\\\\")
498                     m += 1
499
500             i = j + 1
501
502     finally:
503         if needarray == True:
504             add_to_preamble(document, ["\\usepackage{array}"])
505         if needvarwidth == True:
506             add_to_preamble(document, ["\\usepackage{varwidth}"])
507
508
509 def revert_bibencoding(document):
510     " Revert bibliography encoding "
511
512     # Get cite engine
513     engine = "basic"
514     i = find_token(document.header, "\\cite_engine", 0)
515     if i == -1:
516         document.warning("Malformed document! Missing \\cite_engine")
517     else:
518         engine = get_value(document.header, "\\cite_engine", i)
519
520     # Check if biblatex
521     biblatex = False
522     if engine in ["biblatex", "biblatex-natbib"]:
523         biblatex = True
524
525     # Map lyx to latex encoding names 
526     encodings = {
527         "utf8" : "utf8",
528         "utf8x" : "utf8x",
529         "armscii8" : "armscii8",
530         "iso8859-1" : "latin1",
531         "iso8859-2" : "latin2",
532         "iso8859-3" : "latin3",
533         "iso8859-4" : "latin4",
534         "iso8859-5" : "iso88595",
535         "iso8859-6" : "8859-6",
536         "iso8859-7" : "iso-8859-7",
537         "iso8859-8" : "8859-8",
538         "iso8859-9" : "latin5",
539         "iso8859-13" : "latin7",
540         "iso8859-15" : "latin9",
541         "iso8859-16" : "latin10",
542         "applemac" : "applemac",
543         "cp437" : "cp437",
544         "cp437de" : "cp437de",
545         "cp850" : "cp850",
546         "cp852" : "cp852",
547         "cp855" : "cp855",
548         "cp858" : "cp858",
549         "cp862" : "cp862",
550         "cp865" : "cp865",
551         "cp866" : "cp866",
552         "cp1250" : "cp1250",
553         "cp1251" : "cp1251",
554         "cp1252" : "cp1252",
555         "cp1255" : "cp1255",
556         "cp1256" : "cp1256",
557         "cp1257" : "cp1257",
558         "koi8-r" : "koi8-r",
559         "koi8-u" : "koi8-u",
560         "pt154" : "pt154",
561         "utf8-platex" : "utf8",
562         "ascii" : "ascii"
563     }
564
565     i = 0
566     bibresources = []
567     while (True):
568         i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
569         if i == -1:
570             break
571         j = find_end_of_inset(document.body, i)
572         if j == -1:
573             document.warning("Can't find end of bibtex inset at line %d!!" %(i))
574             i += 1
575             continue
576         encoding = get_quoted_value(document.body, "encoding", i, j)
577         if not encoding:
578             i += 1
579             continue
580         # remove encoding line
581         k = find_token(document.body, "encoding", i, j)
582         if k != -1:
583             del document.body[k]
584         # Re-find inset end line
585         j = find_end_of_inset(document.body, i)
586         if biblatex:
587             biblio_options = ""
588             h = find_token(document.header, "\\biblio_options", 0)
589             if h != -1:
590                 biblio_options = get_value(document.header, "\\biblio_options", h)
591                 if not "bibencoding" in biblio_options:
592                      document.header[h] += ",bibencoding=%s" % encodings[encoding]
593             else:
594                 bs = find_token(document.header, "\\biblatex_bibstyle", 0)
595                 if bs == -1:
596                     # this should not happen
597                     document.warning("Malformed LyX document! No \\biblatex_bibstyle header found!")
598                 else:
599                     document.header[bs-1 : bs-1] = ["\\biblio_options bibencoding=" + encodings[encoding]]
600         else:
601             document.body[j+1:j+1] = put_cmd_in_ert("\\egroup")
602             document.body[i:i] = put_cmd_in_ert("\\bgroup\\inputencoding{" + encodings[encoding] + "}")
603
604         i = j + 1
605
606
607
608 def convert_vcsinfo(document):
609     " Separate vcs Info inset from buffer Info inset. "
610
611     types = {
612         "vcs-revision" : "revision",
613         "vcs-tree-revision" : "tree-revision",
614         "vcs-author" : "author",
615         "vcs-time" : "time",
616         "vcs-date" : "date"
617     }
618     i = 0
619     while True:
620         i = find_token(document.body, "\\begin_inset Info", i)
621         if i == -1:
622             return
623         j = find_end_of_inset(document.body, i + 1)
624         if j == -1:
625             document.warning("Malformed LyX document: Could not find end of Info inset.")
626             i = i + 1
627             continue
628         tp = find_token(document.body, 'type', i, j)
629         tpv = get_quoted_value(document.body, "type", tp)
630         if tpv != "buffer":
631             i = i + 1
632             continue
633         arg = find_token(document.body, 'arg', i, j)
634         argv = get_quoted_value(document.body, "arg", arg)
635         if argv not in list(types.keys()):
636             i = i + 1
637             continue
638         document.body[tp] = "type \"vcs\""
639         document.body[arg] = "arg \"" + types[argv] + "\""
640         i = i + 1
641
642
643 def revert_vcsinfo(document):
644     " Merge vcs Info inset to buffer Info inset. "
645
646     args = ["revision", "tree-revision", "author", "time", "date" ]
647     i = 0
648     while True:
649         i = find_token(document.body, "\\begin_inset Info", i)
650         if i == -1:
651             return
652         j = find_end_of_inset(document.body, i + 1)
653         if j == -1:
654             document.warning("Malformed LyX document: Could not find end of Info inset.")
655             i = i + 1
656             continue
657         tp = find_token(document.body, 'type', i, j)
658         tpv = get_quoted_value(document.body, "type", tp)
659         if tpv != "vcs":
660             i = i + 1
661             continue
662         arg = find_token(document.body, 'arg', i, j)
663         argv = get_quoted_value(document.body, "arg", arg)
664         if argv not in args:
665             document.warning("Malformed Info inset. Invalid vcs arg.")
666             i = i + 1
667             continue
668         document.body[tp] = "type \"buffer\""
669         document.body[arg] = "arg \"vcs-" + argv + "\""
670         i = i + 1
671
672
673 def revert_dateinfo(document):
674     " Revert date info insets to static text. "
675
676 # FIXME This currently only considers the main language and uses the system locale
677 # Ideally, it should honor context languages and switch the locale accordingly.
678
679     # The date formats for each language using strftime syntax:
680     # long, short, loclong, locmedium, locshort
681     dateformats = {
682         "afrikaans" : ["%A, %d %B %Y", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%Y/%m/%d"],
683         "albanian" : ["%A, %d %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
684         "american" : ["%A, %B %d, %Y", "%m/%d/%y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
685         "amharic" : ["%A ፣%d %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
686         "ancientgreek" : ["%A, %d %B %Y", "%d %b %Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
687         "arabic_arabi" : ["%A، %d %B، %Y", "%d‏/%m‏/%Y", "%d %B، %Y", "%d/%m/%Y", "%d/%m/%Y"],
688         "arabic_arabtex" : ["%A، %d %B، %Y", "%d‏/%m‏/%Y", "%d %B، %Y", "%d/%m/%Y", "%d/%m/%Y"],
689         "armenian" : ["%Y թ. %B %d, %A", "%d.%m.%y", "%d %B، %Y", "%d %b، %Y", "%d/%m/%Y"],
690         "asturian" : ["%A, %d %B de %Y", "%d/%m/%y", "%d de %B de %Y", "%d %b %Y", "%d/%m/%Y"],
691         "australian" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
692         "austrian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
693         "bahasa" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
694         "bahasam" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
695         "basque" : ["%Y(e)ko %B %d, %A", "%y/%m/%d", "%Y %B %d", "%Y %b %d", "%Y/%m/%d"],
696         "belarusian" : ["%A, %d %B %Y г.", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
697         "bosnian" : ["%A, %d. %B %Y.", "%d.%m.%y.", "%d. %B %Y", "%d. %b %Y", "%Y-%m-%d"],
698         "brazilian" : ["%A, %d de %B de %Y", "%d/%m/%Y", "%d de %B de %Y", "%d de %b de %Y", "%d/%m/%Y"],
699         "breton" : ["%Y %B %d, %A", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"],
700         "british" : ["%A, %d %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
701         "bulgarian" : ["%A, %d %B %Y г.", "%d.%m.%y г.", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"],
702         "canadian" : ["%A, %B %d, %Y", "%Y-%m-%d", "%B %d, %Y", "%d %b %Y", "%Y-%m-%d"],
703         "canadien" : ["%A %d %B %Y", "%y-%m-%d", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"],
704         "catalan" : ["%A, %d %B de %Y", "%d/%m/%y", "%d / %B / %Y", "%d / %b / %Y", "%d/%m/%Y"],
705         "chinese-simplified" : ["%Y年%m月%d日%A", "%Y/%m/%d", "%Y年%m月%d日", "%Y-%m-%d", "%y-%m-%d"],
706         "chinese-traditional" : ["%Y年%m月%d日 %A", "%Y/%m/%d", "%Y年%m月%d日", "%Y年%m月%d日", "%y年%m月%d日"],
707         "coptic" : ["%A, %d %B %Y", "%d %b %Y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
708         "croatian" : ["%A, %d. %B %Y.", "%d. %m. %Y.", "%d. %B %Y.", "%d. %b. %Y.", "%d.%m.%Y."],
709         "czech" : ["%A %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b. %Y", "%d.%m.%Y"],
710         "danish" : ["%A den %d. %B %Y", "%d/%m/%Y", "%d. %B %Y", "%d. %b %Y", "%d/%m/%Y"],
711         "divehi" : ["%Y %B %d, %A", "%Y-%m-%d", "%Y %B %d", "%Y %b %d", "%d/%m/%Y"],
712         "dutch" : ["%A %d %B %Y", "%d-%m-%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
713         "english" : ["%A, %B %d, %Y", "%m/%d/%y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
714         "esperanto" : ["%A, %d %B %Y", "%d %b %Y", "la %d de %B %Y", "la %d de %b %Y", "%m/%d/%Y"],
715         "estonian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
716         "farsi" : ["%A %d %B %Y", "%Y/%m/%d", "%d %B %Y", "%d %b %Y", "%Y/%m/%d"],
717         "finnish" : ["%A %d. %B %Y", "%d.%m.%Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
718         "french" : ["%A %d %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
719         "friulan" : ["%A %d di %B dal %Y", "%d/%m/%y", "%d di %B dal %Y", "%d di %b dal %Y", "%d/%m/%Y"],
720         "galician" : ["%A, %d de %B de %Y", "%d/%m/%y", "%d de %B de %Y", "%d de %b de %Y", "%d/%m/%Y"],
721         "georgian" : ["%A, %d %B, %Y", "%d.%m.%y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
722         "german" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
723         "german-ch" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
724         "german-ch-old" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
725         "greek" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
726         "hebrew" : ["%A, %d ב%B %Y", "%d.%m.%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
727         "hindi" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
728         "icelandic" : ["%A, %d. %B %Y", "%d.%m.%Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
729         "interlingua" : ["%Y %B %d, %A", "%Y-%m-%d", "le %d de %B %Y", "le %d de %b %Y", "%Y-%m-%d"],
730         "irish" : ["%A %d %B %Y", "%d/%m/%Y", "%d. %B %Y", "%d. %b %Y", "%d/%m/%Y"],
731         "italian" : ["%A %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d/%b/%Y", "%d/%m/%Y"],
732         "japanese" : ["%Y年%m月%d日%A", "%Y/%m/%d", "%Y年%m月%d日", "%Y/%m/%d", "%y/%m/%d"],
733         "japanese-cjk" : ["%Y年%m月%d日%A", "%Y/%m/%d", "%Y年%m月%d日", "%Y/%m/%d", "%y/%m/%d"],
734         "kannada" : ["%A, %B %d, %Y", "%d/%m/%y", "%d %B %Y", "%d %B %Y", "%d-%m-%Y"],
735         "kazakh" : ["%Y ж. %d %B, %A", "%d.%m.%y", "%d %B %Y", "%d %B %Y", "%Y-%d-%m"],
736         "khmer" : ["%A %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %B %Y", "%d/%m/%Y"],
737         "korean" : ["%Y년 %m월 %d일 %A", "%y. %m. %d.", "%Y년 %m월 %d일", "%Y. %m. %d.", "%y. %m. %d."],
738         "kurmanji" : ["%A, %d %B %Y", "%d %b %Y", "%d. %B %Y", "%d. %m. %Y", "%Y-%m-%d"],
739         "lao" : ["%A ທີ %d %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %B %Y", "%d/%m/%Y"],
740         "latin" : ["%A, %d %B %Y", "%d %b %Y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
741         "latvian" : ["%A, %Y. gada %d. %B", "%d.%m.%y", "%Y. gada %d. %B", "%Y. gada %d. %b", "%d.%m.%Y"],
742         "lithuanian" : ["%Y m. %B %d d., %A", "%Y-%m-%d", "%Y m. %B %d d.", "%Y m. %B %d d.", "%Y-%m-%d"],
743         "lowersorbian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
744         "macedonian" : ["%A, %d %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
745         "magyar" : ["%Y. %B %d., %A", "%Y. %m. %d.", "%Y. %B %d.", "%Y. %b %d.", "%Y.%m.%d."],
746         "marathi" : ["%A, %d %B, %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
747         "mongolian" : ["%A, %Y оны %m сарын %d", "%Y-%m-%d", "%Y оны %m сарын %d", "%d-%m-%Y", "%d-%m-%Y"],
748         "naustrian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
749         "newzealand" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
750         "ngerman" : ["%A, %d. %B %Y", "%d.%m.%y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
751         "norsk" : ["%A %d. %B %Y", "%d.%m.%Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
752         "nynorsk" : ["%A %d. %B %Y", "%d.%m.%Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
753         "occitan" : ["%Y %B %d, %A", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
754         "piedmontese" : ["%A, %d %B %Y", "%d %b %Y", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
755         "polish" : ["%A, %d %B %Y", "%d.%m.%Y", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"],
756         "polutonikogreek" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
757         "portuguese" : ["%A, %d de %B de %Y", "%d/%m/%y", "%d de %B de %Y", "%d de %b de %Y", "%Y/%m/%d"],
758         "romanian" : ["%A, %d %B %Y", "%d.%m.%Y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
759         "romansh" : ["%A, ils %d da %B %Y", "%d-%m-%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
760         "russian" : ["%A, %d %B %Y г.", "%d.%m.%Y", "%d %B %Y г.", "%d %b %Y г.", "%d.%m.%Y"],
761         "samin" : ["%Y %B %d, %A", "%Y-%m-%d", "%B %d. b. %Y", "%b %d. b. %Y", "%d.%m.%Y"],
762         "sanskrit" : ["%Y %B %d, %A", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
763         "scottish" : ["%A, %dmh %B %Y", "%d/%m/%Y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
764         "serbian" : ["%A, %d. %B %Y.", "%d.%m.%y.", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
765         "serbian-latin" : ["%A, %d. %B %Y.", "%d.%m.%y.", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
766         "slovak" : ["%A, %d. %B %Y", "%d. %m. %Y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
767         "slovene" : ["%A, %d. %B %Y", "%d. %m. %y", "%d. %B %Y", "%d. %b %Y", "%d.%m.%Y"],
768         "spanish" : ["%A, %d de %B de %Y", "%d/%m/%y", "%d de %B %de %Y", "%d %b %Y", "%d/%m/%Y"],
769         "spanish-mexico" : ["%A, %d de %B %de %Y", "%d/%m/%y", "%d de %B de %Y", "%d %b %Y", "%d/%m/%Y"],
770         "swedish" : ["%A %d %B %Y", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%Y-%m-%d"],
771         "syriac" : ["%Y %B %d, %A", "%Y-%m-%d", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
772         "tamil" : ["%A, %d %B, %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
773         "telugu" : ["%d, %B %Y, %A", "%d-%m-%y", "%d %B %Y", "%d %b %Y", "%d-%m-%Y"],
774         "thai" : ["%Aที่ %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
775         "tibetan" : ["%Y %Bའི་ཚེས་%d, %A", "%Y-%m-%d", "%B %d, %Y", "%b %d, %Y", "%m/%d/%Y"],
776         "turkish" : ["%d %B %Y %A", "%d.%m.%Y", "%d %B %Y", "%d.%b.%Y", "%d.%m.%Y"],
777         "turkmen" : ["%d %B %Y %A", "%d.%m.%Y", "%Y ý. %B %d", "%d.%m.%Y ý.", "%d.%m.%y ý."],
778         "ukrainian" : ["%A, %d %B %Y р.", "%d.%m.%y", "%d %B %Y", "%d %m %Y", "%d.%m.%Y"],
779         "uppersorbian" : ["%A, %d. %B %Y", "%d.%m.%y", "%d %B %Y", "%d %b %Y", "%d.%m.%Y"],
780         "urdu" : ["%A، %d %B، %Y", "%d/%m/%y", "%d %B, %Y", "%d %b %Y", "%d/%m/%Y"],
781         "vietnamese" : ["%A, %d %B, %Y", "%d/%m/%Y", "%d tháng %B %Y", "%d-%m-%Y", "%d/%m/%Y"],
782         "welsh" : ["%A, %d %B %Y", "%d/%m/%y", "%d %B %Y", "%d %b %Y", "%d/%m/%Y"],
783     }
784
785     types = ["date", "fixdate", "moddate" ]
786     i = 0
787     i = find_token(document.header, "\\language", 0)
788     if i == -1:
789         # this should not happen
790         document.warning("Malformed LyX document! No \\language header found!")
791         return
792     lang = get_value(document.header, "\\language", i)
793
794     i = 0
795     while True:
796         i = find_token(document.body, "\\begin_inset Info", i)
797         if i == -1:
798             return
799         j = find_end_of_inset(document.body, i + 1)
800         if j == -1:
801             document.warning("Malformed LyX document: Could not find end of Info inset.")
802             i = i + 1
803             continue
804         tp = find_token(document.body, 'type', i, j)
805         tpv = get_quoted_value(document.body, "type", tp)
806         if tpv not in types:
807             i = i + 1
808             continue
809         arg = find_token(document.body, 'arg', i, j)
810         argv = get_quoted_value(document.body, "arg", arg)
811         isodate = ""
812         dte = date.today()
813         if tpv == "fixdate":
814             datecomps = argv.split('@')
815             if len(datecomps) > 1:
816                 argv = datecomps[0]
817                 isodate = datecomps[1]
818                 m = re.search('(\d\d\d\d)-(\d\d)-(\d\d)', isodate)
819                 if m:
820                     dte = date(int(m.group(1)), int(m.group(2)), int(m.group(3)))
821 # FIXME if we had the path to the original document (not the one in the tmp dir),
822 #        we could use the mtime.
823 #        elif tpv == "moddate":
824 #            dte = date.fromtimestamp(os.path.getmtime(document.dir))
825         result = ""
826         if argv == "ISO":
827             result = dte.isodate()
828         elif argv == "long":
829             result = dte.strftime(dateformats[lang][0])
830         elif argv == "short":
831             result = dte.strftime(dateformats[lang][1])
832         elif argv == "loclong":
833             result = dte.strftime(dateformats[lang][2])
834         elif argv == "locmedium":
835             result = dte.strftime(dateformats[lang][3])
836         elif argv == "locshort":
837             result = dte.strftime(dateformats[lang][4])
838         else:
839             fmt = argv.replace("MMMM", "%b").replace("MMM", "%b").replace("MM", "%m").replace("M", "%m")
840             fmt = fmt.replace("yyyy", "%Y").replace("yy", "%y")
841             fmt = fmt.replace("dddd", "%A").replace("ddd", "%a").replace("dd", "%d")
842             fmt = re.sub('[^\'%]d', '%d', fmt)
843             fmt = fmt.replace("'", "")
844             result = dte.strftime(fmt)
845         document.body[i : j+1] = result
846         i = i + 1
847
848
849 def revert_timeinfo(document):
850     " Revert time info insets to static text. "
851
852 # FIXME This currently only considers the main language and uses the system locale
853 # Ideally, it should honor context languages and switch the locale accordingly.
854 # Also, the time object is "naive", i.e., it does not know of timezones (%Z will
855 # be empty).
856
857     # The time formats for each language using strftime syntax:
858     # long, short
859     timeformats = {
860         "afrikaans" : ["%H:%M:%S %Z", "%H:%M"],
861         "albanian" : ["%I:%M:%S %p, %Z", "%I:%M %p"],
862         "american" : ["%I:%M:%S %p %Z", "%I:%M %p"],
863         "amharic" : ["%I:%M:%S %p %Z", "%I:%M %p"],
864         "ancientgreek" : ["%H:%M:%S %Z", "%H:%M:%S"],
865         "arabic_arabi" : ["%I:%M:%S %p %Z", "%I:%M %p"],
866         "arabic_arabtex" : ["%I:%M:%S %p %Z", "%I:%M %p"],
867         "armenian" : ["%H:%M:%S %Z", "%H:%M"],
868         "asturian" : ["%H:%M:%S %Z", "%H:%M"],
869         "australian" : ["%I:%M:%S %p %Z", "%I:%M %p"],
870         "austrian" : ["%H:%M:%S %Z", "%H:%M"],
871         "bahasa" : ["%H.%M.%S %Z", "%H.%M"],
872         "bahasam" : ["%I:%M:%S %p %Z", "%I:%M %p"],
873         "basque" : ["%H:%M:%S (%Z)", "%H:%M"],
874         "belarusian" : ["%H:%M:%S, %Z", "%H:%M"],
875         "bosnian" : ["%H:%M:%S %Z", "%H:%M"],
876         "brazilian" : ["%H:%M:%S %Z", "%H:%M"],
877         "breton" : ["%H:%M:%S %Z", "%H:%M"],
878         "british" : ["%H:%M:%S %Z", "%H:%M"],
879         "bulgarian" : ["%H:%M:%S %Z", "%H:%M"],
880         "canadian" : ["%I:%M:%S %p %Z", "%I:%M %p"],
881         "canadien" : ["%H:%M:%S %Z", "%H h %M"],
882         "catalan" : ["%H:%M:%S %Z", "%H:%M"],
883         "chinese-simplified" : ["%Z %p%I:%M:%S", "%p%I:%M"],
884         "chinese-traditional" : ["%p%I:%M:%S [%Z]", "%p%I:%M"],
885         "coptic" : ["%H:%M:%S %Z", "%H:%M:%S"],
886         "croatian" : ["%H:%M:%S (%Z)", "%H:%M"],
887         "czech" : ["%H:%M:%S %Z", "%H:%M"],
888         "danish" : ["%H.%M.%S %Z", "%H.%M"],
889         "divehi" : ["%H:%M:%S %Z", "%H:%M"],
890         "dutch" : ["%H:%M:%S %Z", "%H:%M"],
891         "english" : ["%I:%M:%S %p %Z", "%I:%M %p"],
892         "esperanto" : ["%H:%M:%S %Z", "%H:%M:%S"],
893         "estonian" : ["%H:%M:%S %Z", "%H:%M"],
894         "farsi" : ["%H:%M:%S (%Z)", "%H:%M"],
895         "finnish" : ["%H.%M.%S %Z", "%H.%M"],
896         "french" : ["%H:%M:%S %Z", "%H:%M"],
897         "friulan" : ["%H:%M:%S %Z", "%H:%M"],
898         "galician" : ["%H:%M:%S %Z", "%H:%M"],
899         "georgian" : ["%H:%M:%S %Z", "%H:%M"],
900         "german" : ["%H:%M:%S %Z", "%H:%M"],
901         "german-ch" : ["%H:%M:%S %Z", "%H:%M"],
902         "german-ch-old" : ["%H:%M:%S %Z", "%H:%M"],
903         "greek" : ["%I:%M:%S %p %Z", "%I:%M %p"],
904         "hebrew" : ["%H:%M:%S %Z", "%H:%M"],
905         "hindi" : ["%I:%M:%S %p %Z", "%I:%M %p"],
906         "icelandic" : ["%H:%M:%S %Z", "%H:%M"],
907         "interlingua" : ["%H:%M:%S %Z", "%H:%M"],
908         "irish" : ["%H:%M:%S %Z", "%H:%M"],
909         "italian" : ["%H:%M:%S %Z", "%H:%M"],
910         "japanese" : ["%H時%M分%S秒 %Z", "%H:%M"],
911         "japanese-cjk" : ["%H時%M分%S秒 %Z", "%H:%M"],
912         "kannada" : ["%I:%M:%S %p %Z", "%I:%M %p"],
913         "kazakh" : ["%H:%M:%S %Z", "%H:%M"],
914         "khmer" : ["%I:%M:%S %p %Z", "%I:%M %p"],
915         "korean" : ["%p %I시%M분 %S초 %Z", "%p %I:%M"],
916         "kurmanji" : ["%H:%M:%S %Z", "%H:%M:%S"],
917         "lao" : ["%H ໂມງ%M ນາທີ  %S ວິນາທີ %Z", "%H:%M"],
918         "latin" : ["%H:%M:%S %Z", "%H:%M:%S"],
919         "latvian" : ["%H:%M:%S %Z", "%H:%M"],
920         "lithuanian" : ["%H:%M:%S %Z", "%H:%M"],
921         "lowersorbian" : ["%H:%M:%S %Z", "%H:%M"],
922         "macedonian" : ["%H:%M:%S %Z", "%H:%M"],
923         "magyar" : ["%H:%M:%S %Z", "%H:%M"],
924         "marathi" : ["%I:%M:%S %p %Z", "%I:%M %p"],
925         "mongolian" : ["%H:%M:%S %Z", "%H:%M"],
926         "naustrian" : ["%H:%M:%S %Z", "%H:%M"],
927         "newzealand" : ["%I:%M:%S %p %Z", "%I:%M %p"],
928         "ngerman" : ["%H:%M:%S %Z", "%H:%M"],
929         "norsk" : ["%H:%M:%S %Z", "%H:%M"],
930         "nynorsk" : ["kl. %H:%M:%S %Z", "%H:%M"],
931         "occitan" : ["%H:%M:%S %Z", "%H:%M"],
932         "piedmontese" : ["%H:%M:%S %Z", "%H:%M:%S"],
933         "polish" : ["%H:%M:%S %Z", "%H:%M"],
934         "polutonikogreek" : ["%I:%M:%S %p %Z", "%I:%M %p"],
935         "portuguese" : ["%H:%M:%S %Z", "%H:%M"],
936         "romanian" : ["%H:%M:%S %Z", "%H:%M"],
937         "romansh" : ["%H:%M:%S %Z", "%H:%M"],
938         "russian" : ["%H:%M:%S %Z", "%H:%M"],
939         "samin" : ["%H:%M:%S %Z", "%H:%M"],
940         "sanskrit" : ["%H:%M:%S %Z", "%H:%M"],
941         "scottish" : ["%H:%M:%S %Z", "%H:%M"],
942         "serbian" : ["%H:%M:%S %Z", "%H:%M"],
943         "serbian-latin" : ["%H:%M:%S %Z", "%H:%M"],
944         "slovak" : ["%H:%M:%S %Z", "%H:%M"],
945         "slovene" : ["%H:%M:%S %Z", "%H:%M"],
946         "spanish" : ["%H:%M:%S (%Z)", "%H:%M"],
947         "spanish-mexico" : ["%H:%M:%S %Z", "%H:%M"],
948         "swedish" : ["kl. %H:%M:%S %Z", "%H:%M"],
949         "syriac" : ["%H:%M:%S %Z", "%H:%M"],
950         "tamil" : ["%p %I:%M:%S %Z", "%p %I:%M"],
951         "telugu" : ["%I:%M:%S %p %Z", "%I:%M %p"],
952         "thai" : ["%H นาฬิกา %M นาที  %S วินาที %Z", "%H:%M"],
953         "tibetan" : ["%I:%M:%S %p %Z", "%I:%M %p"],
954         "turkish" : ["%H:%M:%S %Z", "%H:%M"],
955         "turkmen" : ["%H:%M:%S %Z", "%H:%M"],
956         "ukrainian" : ["%H:%M:%S %Z", "%H:%M"],
957         "uppersorbian" : ["%H:%M:%S %Z", "%H:%M hodź."],
958         "urdu" : ["%I:%M:%S %p %Z", "%I:%M %p"],
959         "vietnamese" : ["%H:%M:%S %Z", "%H:%M"],
960         "welsh" : ["%H:%M:%S %Z", "%H:%M"]
961     }
962
963     types = ["time", "fixtime", "modtime" ]
964     i = 0
965     i = find_token(document.header, "\\language", 0)
966     if i == -1:
967         # this should not happen
968         document.warning("Malformed LyX document! No \\language header found!")
969         return
970     lang = get_value(document.header, "\\language", i)
971
972     i = 0
973     while True:
974         i = find_token(document.body, "\\begin_inset Info", i)
975         if i == -1:
976             return
977         j = find_end_of_inset(document.body, i + 1)
978         if j == -1:
979             document.warning("Malformed LyX document: Could not find end of Info inset.")
980             i = i + 1
981             continue
982         tp = find_token(document.body, 'type', i, j)
983         tpv = get_quoted_value(document.body, "type", tp)
984         if tpv not in types:
985             i = i + 1
986             continue
987         arg = find_token(document.body, 'arg', i, j)
988         argv = get_quoted_value(document.body, "arg", arg)
989         isotime = ""
990         dtme = datetime.now()
991         tme = dtme.time()
992         if tpv == "fixtime":
993             timecomps = argv.split('@')
994             if len(timecomps) > 1:
995                 argv = timecomps[0]
996                 isotime = timecomps[1]
997                 m = re.search('(\d\d):(\d\d):(\d\d)', isotime)
998                 if m:
999                     tme = time(int(m.group(1)), int(m.group(2)), int(m.group(3)))
1000                 else:
1001                     m = re.search('(\d\d):(\d\d)', isotime)
1002                     if m:
1003                         tme = time(int(m.group(1)), int(m.group(2)))
1004 # FIXME if we had the path to the original document (not the one in the tmp dir),
1005 #        we could use the mtime.
1006 #        elif tpv == "moddate":
1007 #            dte = date.fromtimestamp(os.path.getmtime(document.dir))
1008         result = ""
1009         if argv == "ISO":
1010             result = tme.isoformat()
1011         elif argv == "long":
1012             result = tme.strftime(timeformats[lang][0])
1013         elif argv == "short":
1014             result = tme.strftime(timeformats[lang][1])
1015         else:
1016             fmt = argv.replace("HH", "%H").replace("H", "%H").replace("hh", "%I").replace("h", "%I")
1017             fmt = fmt.replace("mm", "%M").replace("m", "%M").replace("ss", "%S").replace("s", "%S")
1018             fmt = fmt.replace("zzz", "%f").replace("z", "%f").replace("t", "%Z")
1019             fmt = fmt.replace("AP", "%p").replace("ap", "%p").replace("A", "%p").replace("a", "%p")
1020             fmt = fmt.replace("'", "")
1021             result = dte.strftime(fmt)
1022         document.body[i : j+1] = result
1023         i = i + 1
1024
1025
1026 def revert_namenoextinfo(document):
1027     " Merge buffer Info inset type name-noext to name. "
1028
1029     i = 0
1030     while True:
1031         i = find_token(document.body, "\\begin_inset Info", i)
1032         if i == -1:
1033             return
1034         j = find_end_of_inset(document.body, i + 1)
1035         if j == -1:
1036             document.warning("Malformed LyX document: Could not find end of Info inset.")
1037             i = i + 1
1038             continue
1039         tp = find_token(document.body, 'type', i, j)
1040         tpv = get_quoted_value(document.body, "type", tp)
1041         if tpv != "buffer":
1042             i = i + 1
1043             continue
1044         arg = find_token(document.body, 'arg', i, j)
1045         argv = get_quoted_value(document.body, "arg", arg)
1046         if argv != "name-noext":
1047             i = i + 1
1048             continue
1049         document.body[arg] = "arg \"name\""
1050         i = i + 1
1051
1052
1053 ##
1054 # Conversion hub
1055 #
1056
1057 supported_versions = ["2.4.0", "2.4"]
1058 convert = [
1059            [545, [convert_lst_literalparam]],
1060            [546, []],
1061            [547, []],
1062            [548, []],
1063            [549, []],
1064            [550, [convert_fontenc]],
1065            [551, []],
1066            [552, []],
1067            [553, []],
1068            [554, []],
1069            [555, []],
1070            [556, []],
1071            [557, [convert_vcsinfo]],
1072            [558, [removeFrontMatterStyles]],
1073            [559, []],
1074            [560, []]
1075           ]
1076
1077 revert =  [
1078            [559, [revert_timeinfo, revert_namenoextinfo]],
1079            [558, [revert_dateinfo]],
1080            [557, [addFrontMatterStyles]],
1081            [556, [revert_vcsinfo]],
1082            [555, [revert_bibencoding]],
1083            [554, [revert_vcolumns]],
1084            [553, [revert_stretchcolumn]],
1085            [552, [revert_tuftecite]],
1086            [551, [revert_floatpclass, revert_floatalignment]],
1087            [550, [revert_nospellcheck]],
1088            [549, [revert_fontenc]],
1089            [548, []],# dummy format change
1090            [547, [revert_lscape]],
1091            [546, [revert_xcharter]],
1092            [545, [revert_paratype]],
1093            [544, [revert_lst_literalparam]]
1094           ]
1095
1096
1097 if __name__ == "__main__":
1098     pass