]> git.lyx.org Git - lyx.git/blob - lib/lyx2lyx/lyx_1_5.py
0eb9bb44a9d322d5af08ae31bd10ff06895384bb
[lyx.git] / lib / lyx2lyx / lyx_1_5.py
1 # This file is part of lyx2lyx
2 # -*- coding: utf-8 -*-
3 # Copyright (C) 2006 José Matos <jamatos@lyx.org>
4 # Copyright (C) 2004-2006 Georg Baum <Georg.Baum@post.rwth-aachen.de>
5 #
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19
20 """ Convert files to the file format generated by lyx 1.5"""
21
22 import re
23 from parser_tools import find_token, find_token_exact, find_tokens, find_end_of, get_value
24 from LyX import get_encoding
25
26
27 ####################################################################
28 # Private helper functions
29
30 def find_end_of_inset(lines, i):
31     " Find beginning of inset, where lines[i] is included."
32     return find_end_of(lines, i, "\\begin_inset", "\\end_inset")
33
34 # End of helper functions
35 ####################################################################
36
37
38 ##
39 #  Notes: Framed/Shaded
40 #
41
42 def revert_framed(document):
43     "Revert framed notes. "
44     i = 0
45     while 1:
46         i = find_tokens(document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i)
47
48         if i == -1:
49             return
50         document.body[i] = "\\begin_inset Note"
51         i = i + 1
52
53
54 ##
55 #  Fonts
56 #
57
58 roman_fonts      = {'default' : 'default', 'ae'       : 'ae',
59                     'times'   : 'times',   'palatino' : 'palatino',
60                     'helvet'  : 'default', 'avant'    : 'default',
61                     'newcent' : 'newcent', 'bookman'  : 'bookman',
62                     'pslatex' : 'times'}
63 sans_fonts       = {'default' : 'default', 'ae'       : 'default',
64                     'times'   : 'default', 'palatino' : 'default',
65                     'helvet'  : 'helvet',  'avant'    : 'avant',
66                     'newcent' : 'default', 'bookman'  : 'default',
67                     'pslatex' : 'helvet'}
68 typewriter_fonts = {'default' : 'default', 'ae'       : 'default',
69                     'times'   : 'default', 'palatino' : 'default',
70                     'helvet'  : 'default', 'avant'    : 'default',
71                     'newcent' : 'default', 'bookman'  : 'default',
72                     'pslatex' : 'courier'}
73
74 def convert_font_settings(document):
75     " Convert font settings. "
76     i = 0
77     i = find_token_exact(document.header, "\\fontscheme", i)
78     if i == -1:
79         document.warning("Malformed LyX document: Missing `\\fontscheme'.")
80         return
81     font_scheme = get_value(document.header, "\\fontscheme", i, i + 1)
82     if font_scheme == '':
83         document.warning("Malformed LyX document: Empty `\\fontscheme'.")
84         font_scheme = 'default'
85     if not font_scheme in roman_fonts.keys():
86         document.warning("Malformed LyX document: Unknown `\\fontscheme' `%s'." % font_scheme)
87         font_scheme = 'default'
88     document.header[i:i+1] = ['\\font_roman %s' % roman_fonts[font_scheme],
89                           '\\font_sans %s' % sans_fonts[font_scheme],
90                           '\\font_typewriter %s' % typewriter_fonts[font_scheme],
91                           '\\font_default_family default',
92                           '\\font_sc false',
93                           '\\font_osf false',
94                           '\\font_sf_scale 100',
95                           '\\font_tt_scale 100']
96
97
98 def revert_font_settings(document):
99     " Revert font settings. "
100     i = 0
101     insert_line = -1
102     fonts = {'roman' : 'default', 'sans' : 'default', 'typewriter' : 'default'}
103     for family in 'roman', 'sans', 'typewriter':
104         name = '\\font_%s' % family
105         i = find_token_exact(document.header, name, i)
106         if i == -1:
107             document.warning("Malformed LyX document: Missing `%s'." % name)
108             i = 0
109         else:
110             if (insert_line < 0):
111                 insert_line = i
112             fonts[family] = get_value(document.header, name, i, i + 1)
113             del document.header[i]
114     i = find_token_exact(document.header, '\\font_default_family', i)
115     if i == -1:
116         document.warning("Malformed LyX document: Missing `\\font_default_family'.")
117         font_default_family = 'default'
118     else:
119         font_default_family = get_value(document.header, "\\font_default_family", i, i + 1)
120         del document.header[i]
121     i = find_token_exact(document.header, '\\font_sc', i)
122     if i == -1:
123         document.warning("Malformed LyX document: Missing `\\font_sc'.")
124         font_sc = 'false'
125     else:
126         font_sc = get_value(document.header, '\\font_sc', i, i + 1)
127         del document.header[i]
128     if font_sc != 'false':
129         document.warning("Conversion of '\\font_sc' not yet implemented.")
130     i = find_token_exact(document.header, '\\font_osf', i)
131     if i == -1:
132         document.warning("Malformed LyX document: Missing `\\font_osf'.")
133         font_osf = 'false'
134     else:
135         font_osf = get_value(document.header, '\\font_osf', i, i + 1)
136         del document.header[i]
137     i = find_token_exact(document.header, '\\font_sf_scale', i)
138     if i == -1:
139         document.warning("Malformed LyX document: Missing `\\font_sf_scale'.")
140         font_sf_scale = '100'
141     else:
142         font_sf_scale = get_value(document.header, '\\font_sf_scale', i, i + 1)
143         del document.header[i]
144     if font_sf_scale != '100':
145         document.warning("Conversion of '\\font_sf_scale' not yet implemented.")
146     i = find_token_exact(document.header, '\\font_tt_scale', i)
147     if i == -1:
148         document.warning("Malformed LyX document: Missing `\\font_tt_scale'.")
149         font_tt_scale = '100'
150     else:
151         font_tt_scale = get_value(document.header, '\\font_tt_scale', i, i + 1)
152         del document.header[i]
153     if font_tt_scale != '100':
154         document.warning("Conversion of '\\font_tt_scale' not yet implemented.")
155     for font_scheme in roman_fonts.keys():
156         if (roman_fonts[font_scheme] == fonts['roman'] and
157             sans_fonts[font_scheme] == fonts['sans'] and
158             typewriter_fonts[font_scheme] == fonts['typewriter']):
159             document.header.insert(insert_line, '\\fontscheme %s' % font_scheme)
160             if font_default_family != 'default':
161                 document.preamble.append('\\renewcommand{\\familydefault}{\\%s}' % font_default_family)
162             if font_osf == 'true':
163                 document.warning("Ignoring `\\font_osf = true'")
164             return
165     font_scheme = 'default'
166     document.header.insert(insert_line, '\\fontscheme %s' % font_scheme)
167     if fonts['roman'] == 'cmr':
168         document.preamble.append('\\renewcommand{\\rmdefault}{cmr}')
169         if font_osf == 'true':
170             document.preamble.append('\\usepackage{eco}')
171             font_osf = 'false'
172     for font in 'lmodern', 'charter', 'utopia', 'beraserif', 'ccfonts', 'chancery':
173         if fonts['roman'] == font:
174             document.preamble.append('\\usepackage{%s}' % font)
175     for font in 'cmss', 'lmss', 'cmbr':
176         if fonts['sans'] == font:
177             document.preamble.append('\\renewcommand{\\sfdefault}{%s}' % font)
178     for font in 'berasans':
179         if fonts['sans'] == font:
180             document.preamble.append('\\usepackage{%s}' % font)
181     for font in 'cmtt', 'lmtt', 'cmtl':
182         if fonts['typewriter'] == font:
183             document.preamble.append('\\renewcommand{\\ttdefault}{%s}' % font)
184     for font in 'courier', 'beramono', 'luximono':
185         if fonts['typewriter'] == font:
186             document.preamble.append('\\usepackage{%s}' % font)
187     if font_default_family != 'default':
188         document.preamble.append('\\renewcommand{\\familydefault}{\\%s}' % font_default_family)
189     if font_osf == 'true':
190         document.warning("Ignoring `\\font_osf = true'")
191
192
193 def revert_booktabs(document):
194     " We remove the booktabs flag or everything else will become a mess. "
195     re_row = re.compile(r'^<row.*space="[^"]+".*>$')
196     re_tspace = re.compile(r'\s+topspace="[^"]+"')
197     re_bspace = re.compile(r'\s+bottomspace="[^"]+"')
198     re_ispace = re.compile(r'\s+interlinespace="[^"]+"')
199     i = 0
200     while 1:
201         i = find_token(document.body, "\\begin_inset Tabular", i)
202         if i == -1:
203             return
204         j = find_end_of_inset(document.body, i + 1)
205         if j == -1:
206             document.warning("Malformed LyX document: Could not find end of tabular.")
207             continue
208         for k in range(i, j):
209             if re.search('^<features.* booktabs="true".*>$', document.body[k]):
210                 document.warning("Converting 'booktabs' table to normal table.")
211                 document.body[k] = document.body[k].replace(' booktabs="true"', '')
212             if re.search(re_row, document.body[k]):
213                 document.warning("Removing extra row space.")
214                 document.body[k] = re_tspace.sub('', document.body[k])
215                 document.body[k] = re_bspace.sub('', document.body[k])
216                 document.body[k] = re_ispace.sub('', document.body[k])
217         i = i + 1
218
219
220 def convert_utf8(document):
221     document.encoding = "utf8"
222
223
224 def revert_utf8(document):
225     i = find_token(document.header, "\\inputencoding", 0)
226     if i == -1:
227         document.header.append("\\inputencoding auto")
228     elif get_value(document.header, "\\inputencoding", i) == "utf8":
229         document.header[i] = "\\inputencoding auto"
230     document.inputencoding = get_value(document.header, "\\inputencoding", 0)
231     document.encoding = get_encoding(document.language, document.inputencoding, 248)
232
233
234 def revert_cs_label(document):
235     " Remove status flag of charstyle label. "
236     i = 0
237     while 1:
238         i = find_token(document.body, "\\begin_inset CharStyle", i)
239         if i == -1:
240             return
241         # Seach for a line starting 'show_label'
242         # If it is not there, break with a warning message
243         i = i + 1
244         while 1:
245             if (document.body[i][:10] == "show_label"):
246                 del document.body[i]
247                 break
248             elif (document.body[i][:13] == "\\begin_layout"):
249                 document.warning("Malformed LyX document: Missing 'show_label'.")
250                 break
251             i = i + 1
252
253         i = i + 1
254
255
256 def convert_bibitem(document):
257     """ Convert
258 \bibitem [option]{argument}
259
260 to
261
262 \begin_inset LatexCommand bibitem
263 label "option"
264 key "argument"
265
266 \end_inset
267
268 This must be called after convert_commandparams.
269 """
270     regex = re.compile(r'\S+\s*(\[[^\[\{]*\])?(\{[^}]*\})')
271     i = 0
272     while 1:
273         i = find_token(document.body, "\\bibitem", i)
274         if i == -1:
275             break
276         match = re.match(regex, document.body[i])
277         option = match.group(1)
278         argument = match.group(2)
279         lines = ['\\begin_inset LatexCommand bibitem']
280         if option != None:
281             lines.append('label "%s"' % option[1:-1].replace('"', '\\"'))
282         lines.append('key "%s"' % argument[1:-1].replace('"', '\\"'))
283         lines.append('')
284         lines.append('\\end_inset')
285         document.body[i:i+1] = lines
286         i = i + 1
287
288
289 commandparams_info = {
290     # command : [option1, option2, argument]
291     "bibitem" : ["label", "", "key"],
292     "bibtex" : ["options", "btprint", "bibfiles"],
293     "cite"        : ["after", "before", "key"],
294     "citet"       : ["after", "before", "key"],
295     "citep"       : ["after", "before", "key"],
296     "citealt"     : ["after", "before", "key"],
297     "citealp"     : ["after", "before", "key"],
298     "citeauthor"  : ["after", "before", "key"],
299     "citeyear"    : ["after", "before", "key"],
300     "citeyearpar" : ["after", "before", "key"],
301     "citet*"      : ["after", "before", "key"],
302     "citep*"      : ["after", "before", "key"],
303     "citealt*"    : ["after", "before", "key"],
304     "citealp*"    : ["after", "before", "key"],
305     "citeauthor*" : ["after", "before", "key"],
306     "Citet"       : ["after", "before", "key"],
307     "Citep"       : ["after", "before", "key"],
308     "Citealt"     : ["after", "before", "key"],
309     "Citealp"     : ["after", "before", "key"],
310     "Citeauthor"  : ["after", "before", "key"],
311     "Citet*"      : ["after", "before", "key"],
312     "Citep*"      : ["after", "before", "key"],
313     "Citealt*"    : ["after", "before", "key"],
314     "Citealp*"    : ["after", "before", "key"],
315     "Citeauthor*" : ["after", "before", "key"],
316     "citefield"   : ["after", "before", "key"],
317     "citetitle"   : ["after", "before", "key"],
318     "cite*"       : ["after", "before", "key"],
319     "hfill" : ["", "", ""],
320     "index"      : ["", "", "name"],
321     "printindex" : ["", "", "name"],
322     "label" : ["", "", "name"],
323     "eqref"     : ["name", "", "reference"],
324     "pageref"   : ["name", "", "reference"],
325     "prettyref" : ["name", "", "reference"],
326     "ref"       : ["name", "", "reference"],
327     "vpageref"  : ["name", "", "reference"],
328     "vref"      : ["name", "", "reference"],
329     "tableofcontents" : ["", "", "type"],
330     "htmlurl" : ["name", "", "target"],
331     "url"     : ["name", "", "target"]}
332
333
334 def convert_commandparams(document):
335     """ Convert
336
337  \begin_inset LatexCommand \cmdname[opt1][opt2]{arg}
338  \end_inset
339
340  to
341
342  \begin_inset LatexCommand cmdname
343  name1 "opt1"
344  name2 "opt2"
345  name3 "arg"
346  \end_inset
347
348  name1, name2 and name3 can be different for each command.
349 """
350     # \begin_inset LatexCommand bibitem was not the official version (see
351     # convert_bibitem()), but could be read in, so we convert it here, too.
352
353     # FIXME: Handle things like \command[foo[bar]]{foo{bar}}
354     # we need a real parser here.
355     regex = re.compile(r'\\([^\[\{]+)(\[[^\[\{]*\])?(\[[^\[\{]*\])?(\{[^}]*\})?')
356     i = 0
357     while 1:
358         i = find_token(document.body, "\\begin_inset LatexCommand", i)
359         if i == -1:
360             break
361         command = document.body[i][26:].strip()
362         if command == "":
363             document.warning("Malformed LyX document: Missing LatexCommand name.")
364             i = i + 1
365             continue
366
367         # The following parser is taken from the original InsetCommandParams::scanCommand
368         name = ""
369         option1 = ""
370         option2 = ""
371         argument = ""
372         state = "WS"
373         # Used to handle things like \command[foo[bar]]{foo{bar}}
374         nestdepth = 0
375         b = 0
376         for c in command:
377             if ((state == "CMDNAME" and c == ' ') or
378                 (state == "CMDNAME" and c == '[') or
379                 (state == "CMDNAME" and c == '{')):
380                 state = "WS"
381             if ((state == "OPTION" and c == ']') or
382                 (state == "SECOPTION" and c == ']') or
383                 (state == "CONTENT" and c == '}')):
384                 if nestdepth == 0:
385                     state = "WS"
386                 else:
387                     --nestdepth
388             if ((state == "OPTION" and c == '[') or
389                 (state == "SECOPTION" and c == '[') or
390                 (state == "CONTENT" and c == '{')):
391                 ++nestdepth
392             if state == "CMDNAME":
393                     name += c
394             elif state == "OPTION":
395                     option1 += c
396             elif state == "SECOPTION":
397                     option2 += c
398             elif state == "CONTENT":
399                     argument += c
400             elif state == "WS":
401                 if c == '\\':
402                     state = "CMDNAME"
403                 elif c == '[' and b != ']':
404                     state = "OPTION"
405                     nestdepth = 0 # Just to be sure
406                 elif c == '[' and b == ']':
407                     state = "SECOPTION"
408                     nestdepth = 0 # Just to be sure
409                 elif c == '{':
410                     state = "CONTENT"
411                     nestdepth = 0 # Just to be sure
412             b = c
413
414         # Now we have parsed the command, output the parameters
415         lines = ["\\begin_inset LatexCommand %s" % name]
416         if option1 != "":
417             if commandparams_info[name][0] == "":
418                 document.warning("Ignoring invalid option `%s' of command `%s'." % (option1, name))
419             else:
420                 lines.append('%s "%s"' % (commandparams_info[name][0], option1.replace('"', '\\"')))
421         if option2 != "":
422             if commandparams_info[name][1] == "":
423                 document.warning("Ignoring invalid second option `%s' of command `%s'." % (option2, name))
424             else:
425                 lines.append('%s "%s"' % (commandparams_info[name][1], option2.replace('"', '\\"')))
426         if argument != "":
427             if commandparams_info[name][2] == "":
428                 document.warning("Ignoring invalid argument `%s' of command `%s'." % (argument, name))
429             else:
430                 lines.append('%s "%s"' % (commandparams_info[name][2], argument.replace('"', '\\"')))
431         document.body[i:i+1] = lines
432         i = i + 1
433
434
435 def revert_commandparams(document):
436     regex = re.compile(r'(\S+)\s+(.+)')
437     i = 0
438     while 1:
439         i = find_token(document.body, "\\begin_inset LatexCommand", i)
440         if i == -1:
441             break
442         name = document.body[i].split()[2]
443         j = find_end_of_inset(document.body, i + 1)
444         preview_line = ""
445         option1 = ""
446         option2 = ""
447         argument = ""
448         for k in range(i + 1, j):
449             match = re.match(regex, document.body[k])
450             if match:
451                 pname = match.group(1)
452                 pvalue = match.group(2)
453                 if pname == "preview":
454                     preview_line = document.body[k]
455                 elif (commandparams_info[name][0] != "" and
456                       pname == commandparams_info[name][0]):
457                     option1 = pvalue.strip('"').replace('\\"', '"')
458                 elif (commandparams_info[name][1] != "" and
459                       pname == commandparams_info[name][1]):
460                     option2 = pvalue.strip('"').replace('\\"', '"')
461                 elif (commandparams_info[name][2] != "" and
462                       pname == commandparams_info[name][2]):
463                     argument = pvalue.strip('"').replace('\\"', '"')
464             elif document.body[k].strip() != "":
465                 document.warning("Ignoring unknown contents `%s' in command inset %s." % (document.body[k], name))
466         if name == "bibitem":
467             if option1 == "":
468                 lines = ["\\bibitem {%s}" % argument]
469             else:
470                 lines = ["\\bibitem [%s]{%s}" % (option1, argument)]
471         else:
472             if option1 == "":
473                 if option2 == "":
474                     lines = ["\\begin_inset LatexCommand \\%s{%s}" % (name, argument)]
475                 else:
476                     lines = ["\\begin_inset LatexCommand \\%s[][%s]{%s}" % (name, option2, argument)]
477             else:
478                 if option2 == "":
479                     lines = ["\\begin_inset LatexCommand \\%s[%s]{%s}" % (name, option1, argument)]
480                 else:
481                     lines = ["\\begin_inset LatexCommand \\%s[%s][%s]{%s}" % (name, option1, option2, argument)]
482         if name != "bibitem":
483             if preview_line != "":
484                 lines.append(preview_line)
485             lines.append('')
486             lines.append('\\end_inset')
487         document.body[i:j+1] = lines
488         i = j + 1
489
490
491 def revert_nomenclature(document):
492     " Convert nomenclature entry to ERT. "
493     regex = re.compile(r'(\S+)\s+(.+)')
494     i = 0
495     use_nomencl = 0
496     while 1:
497         i = find_token(document.body, "\\begin_inset LatexCommand nomenclature", i)
498         if i == -1:
499             break
500         use_nomencl = 1
501         j = find_end_of_inset(document.body, i + 1)
502         preview_line = ""
503         symbol = ""
504         description = ""
505         prefix = ""
506         for k in range(i + 1, j):
507             match = re.match(regex, document.body[k])
508             if match:
509                 name = match.group(1)
510                 value = match.group(2)
511                 if name == "preview":
512                     preview_line = document.body[k]
513                 elif name == "symbol":
514                     symbol = value.strip('"').replace('\\"', '"')
515                 elif name == "description":
516                     description = value.strip('"').replace('\\"', '"')
517                 elif name == "prefix":
518                     prefix = value.strip('"').replace('\\"', '"')
519             elif document.body[k].strip() != "":
520                 document.warning("Ignoring unknown contents `%s' in nomenclature inset." % document.body[k])
521         if prefix == "":
522             command = 'nomenclature{%s}{%s}' % (symbol, description)
523         else:
524             command = 'nomenclature[%s]{%s}{%s}' % (prefix, symbol, description)
525         document.body[i:j+1] = ['\\begin_inset ERT',
526                                 'status collapsed',
527                                 '',
528                                 '\\begin_layout %s' % document.default_layout,
529                                 '',
530                                 '',
531                                 '\\backslash',
532                                 command,
533                                 '\\end_layout',
534                                 '',
535                                 '\\end_inset']
536         i = i + 11
537     if use_nomencl and find_token(document.preamble, '\\usepackage{nomencl}[2005/09/22]', 0) == -1:
538         document.preamble.append('\\usepackage{nomencl}[2005/09/22]')
539         document.preamble.append('\\makenomenclature')
540
541
542 def revert_printnomenclature(document):
543     " Convert printnomenclature to ERT. "
544     regex = re.compile(r'(\S+)\s+(.+)')
545     i = 0
546     use_nomencl = 0
547     while 1:
548         i = find_token(document.body, "\\begin_inset LatexCommand printnomenclature", i)
549         if i == -1:
550             break
551         use_nomencl = 1
552         j = find_end_of_inset(document.body, i + 1)
553         preview_line = ""
554         labelwidth = ""
555         for k in range(i + 1, j):
556             match = re.match(regex, document.body[k])
557             if match:
558                 name = match.group(1)
559                 value = match.group(2)
560                 if name == "preview":
561                     preview_line = document.body[k]
562                 elif name == "labelwidth":
563                     labelwidth = value.strip('"').replace('\\"', '"')
564             elif document.body[k].strip() != "":
565                 document.warning("Ignoring unknown contents `%s' in printnomenclature inset." % document.body[k])
566         if labelwidth == "":
567             command = 'nomenclature{}'
568         else:
569             command = 'nomenclature[%s]' % labelwidth
570         document.body[i:j+1] = ['\\begin_inset ERT',
571                                 'status collapsed',
572                                 '',
573                                 '\\begin_layout %s' % document.default_layout,
574                                 '',
575                                 '',
576                                 '\\backslash',
577                                 command,
578                                 '\\end_layout',
579                                 '',
580                                 '\\end_inset']
581         i = i + 11
582     if use_nomencl and find_token(document.preamble, '\\usepackage{nomencl}[2005/09/22]', 0) == -1:
583         document.preamble.append('\\usepackage{nomencl}[2005/09/22]')
584         document.preamble.append('\\makenomenclature')
585
586
587 def convert_esint(document):
588     " Add \\use_esint setting to header. "
589     i = find_token(document.header, "\\cite_engine", 0)
590     if i == -1:
591         document.warning("Malformed LyX document: Missing `\\cite_engine'.")
592         return
593     # 0 is off, 1 is auto, 2 is on.
594     document.header.insert(i, '\\use_esint 0')
595
596
597 def revert_esint(document):
598     " Remove \\use_esint setting from header. "
599     i = find_token(document.header, "\\use_esint", 0)
600     if i == -1:
601         document.warning("Malformed LyX document: Missing `\\use_esint'.")
602         return
603     use_esint = document.header[i].split()[1]
604     del document.header[i]
605     # 0 is off, 1 is auto, 2 is on.
606     if (use_esint == 2):
607         document.preamble.append('\\usepackage{esint}')
608
609
610 ##
611 # Conversion hub
612 #
613
614 supported_versions = ["1.5.0","1.5"]
615 convert = [[246, []],
616            [247, [convert_font_settings]],
617            [248, []],
618            [249, [convert_utf8]],
619            [250, []],
620            [251, []],
621            [252, [convert_commandparams, convert_bibitem]],
622            [253, []],
623            [254, [convert_esint]]]
624
625 revert =  [[253, [revert_esint]],
626            [252, [revert_nomenclature, revert_printnomenclature]],
627            [251, [revert_commandparams]],
628            [250, [revert_cs_label]],
629            [249, []],
630            [248, [revert_utf8]],
631            [247, [revert_booktabs]],
632            [246, [revert_font_settings]],
633            [245, [revert_framed]]]
634
635
636 if __name__ == "__main__":
637     pass
638