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