]> git.lyx.org Git - lyx.git/blob - lib/scripts/prefs2prefs.py
Pass parameters by reference (performance)
[lyx.git] / lib / scripts / prefs2prefs.py
1 # -*- coding: utf-8 -*-
2
3 # file prefs2prefs.py
4 # This file is part of LyX, the document processor.
5 # Licence details can be found in the file COPYING.
6
7 # author Richard Heck
8
9 # Full author contact details are available in file CREDITS
10
11 # This is the main file for the user preferences conversion system.
12 # There are two subsidiary files:
13 #       prefs2prefs_lfuns.py
14 #       prefs2prefs_prefs.py
15 # The former is used to convert bind and ui files; the latter, to convert
16 # the preferences file.
17 #
18 # I've organized it this way because, in many ways, converting bind and ui 
19 # files  lfuns) and converting the preferences file are the same task. It's 
20 # very line-by-line, unlike lyx2lyx and layout2layout, where changes can be 
21 # more "global". So we read the file, line by line, and give a bunch of 
22 # converter functions a chance to see if they want to modify that line.
23
24 # The converter functions are all in the subsidiary files. They take a line 
25 # as  argument and return a list: (Bool, NewLine), where the Bool says if 
26 # we've modified anything and the NewLine is the new line, if so, which will
27 # be used to replace the old line.
28
29 # The format of the existing files is format 0, as of 2.0.alpha6. We'll 
30 # introduce new format numbers as we proceed, just as with layout2layout.
31 # These will be different for the bind and ui files and for the preferences
32 # file. 
33
34 import os, re, string, sys
35 from getopt import getopt
36
37 ###########################################################
38 # Utility functions, borrowed from layout2layout.py
39
40 def trim_bom(line):
41         " Remove byte order mark."
42         if line[0:3] == "\357\273\277":
43                 return line[3:]
44         else:
45                 return  line
46
47
48 def read(source):
49         " Read input file and strip lineendings."
50         lines = source.read().splitlines() or ['']
51         lines[0] = trim_bom(lines[0])
52         return lines
53
54
55 def write(output, lines):
56         " Write output file with native lineendings."
57         output.write(os.linesep.join(lines) + os.linesep)
58
59
60 # for use by find_format_lines
61 re_comment = re.compile(r'^#')
62 re_empty   = re.compile(r'^\s*$')
63
64 def find_format_line(lines):
65         '''
66         Returns (bool, int), where int is number of the line the `Format' 
67         specification is on, or else the number of the first non-blank, 
68         non-comment line. The bool tells whether we found a format line.
69         '''
70         for i in range(len(lines)):
71                 l = lines[i]
72                 if re_comment.search(l) or re_empty.search(l):
73                         continue
74                 m = re_format.search(l)
75                 if m:
76                         return (True, i)
77                 # we're done when we have hit a non-comment, non-empty line
78                 break
79         return (False, i)
80
81
82 # for use by get_format
83 re_format  = re.compile(r'^Format\s+(\d+)\s*$')
84
85 def get_format(lines):
86         " Gets format of current file and replaces the format line with a new one "
87         (found, format_line) = find_format_line(lines)
88         if not found:
89                 return 0
90         line = lines[format_line]
91         m = re_format.search(line)
92         if not m:
93                 sys.stderr.write("Couldn't match format line!\n" + line + "\n")
94                 sys.exit(1)
95         return int(m.group(1))
96
97
98 def update_format(lines):
99         " Writes new format line "
100         (found, format_line) = find_format_line(lines)
101         if not found:
102                 lines[format_line:format_line] = ("Format 1", "")
103                 return
104
105         line = lines[format_line]
106         m = re_format.search(line)
107         if not m:
108                 sys.stderr.write("Couldn't match format line!\n" + line + "\n")
109                 sys.exit(1)
110         format = int(m.group(1))
111         lines[format_line] = "Format " + str(format + 1)
112
113
114 #
115 ###########################################################
116
117 def usage():
118         print "%s [-l] [-p] infile outfile" % sys.argv[0]
119         print "or: %s [-l] [-p] <infile >outfile" % sys.argv[0]
120         print "  -l: convert LFUNs (bind and ui files)"
121         print "  -p: convert preferences"
122         print "Note that exactly one of -l and -p is required."
123
124
125 def main(argv):
126         try:
127                 (options, args) = getopt(sys.argv[1:], "lp")
128         except:
129                 usage()
130                 print "\nUnrecognized option"
131                 sys.exit(1)
132
133         opened_files = False
134         # Open files
135         if len(args) == 0:
136                 source = sys.stdin
137                 output = sys.stdout
138         elif len(args) == 2:
139                 source = open(args[0], 'rb')
140                 output = open(args[1], 'wb')
141                 opened_files = True
142         else:
143                 usage()
144                 print "\nEither zero or two arguments must be given."
145                 sys.exit(1)
146
147         conversions = False
148
149         for (opt, param) in options:
150                 if opt == "-l":
151                         from prefs2prefs_lfuns import conversions
152                 elif opt == "-p":
153                         from prefs2prefs_prefs import conversions
154         
155         if not conversions:
156                 usage()
157                 print "\nNeither -l nor -p given."
158                 sys.exit(1)
159         elif len(options) > 1:
160                 usage()
161                 print "\nOnly one of -l or -p should be given."
162                 sys.exit(1)
163
164         current_format = len(conversions)
165         lines = read(source)
166         format = get_format(lines)
167
168         while format < current_format:
169                 target_format, convert = conversions[format]
170                 old_format = format
171
172                 # make sure the conversion list is sequential
173                 if int(old_format) + 1 != target_format:
174                         sys.stderr.write("Something is wrong with the conversion chain.\n")
175                         sys.exit(1)
176
177                 for c in convert:
178                         for i in range(len(lines)):
179                                 (update, newline) = c(lines[i])
180                                 if update:
181                                         lines[i] = newline
182
183                 update_format(lines)
184                 format = get_format(lines)
185
186                 # sanity check
187                 if int(old_format) + 1 != int(format):
188                         sys.stderr.write("Failed to convert to new format!\n")
189                         sys.exit(1)
190
191         write(output, lines)
192
193         # Close files
194         if opened_files:
195                 source.close()
196                 output.close()
197
198         return 0
199
200
201 if __name__ == "__main__":
202     main(sys.argv)