lyx_mirror/lib/scripts/prefs2prefs.py

203 lines
5.8 KiB
Python
Raw Permalink Normal View History

# -*- coding: utf-8 -*-
# file prefs2prefs.py
# This file is part of LyX, the document processor.
# Licence details can be found in the file COPYING.
# author Richard Heck
# Full author contact details are available in file CREDITS
# This is the main file for the user preferences conversion system.
# There are two subsidiary files:
# prefs2prefs_lfuns.py
# prefs2prefs_prefs.py
# The former is used to convert bind and ui files; the latter, to convert
# the preferences file.
#
# I've organized it this way because, in many ways, converting bind and ui
# files lfuns) and converting the preferences file are the same task. It's
# very line-by-line, unlike lyx2lyx and layout2layout, where changes can be
# more "global". So we read the file, line by line, and give a bunch of
# converter functions a chance to see if they want to modify that line.
# The converter functions are all in the subsidiary files. They take a line
# as argument and return a list: (Bool, NewLine), where the Bool says if
# we've modified anything and the NewLine is the new line, if so, which will
# be used to replace the old line.
# The format of the existing files is format 0, as of 2.0.alpha6. We'll
# introduce new format numbers as we proceed, just as with layout2layout.
# These will be different for the bind and ui files and for the preferences
# file.
from __future__ import print_function
import os, re, string, sys
from getopt import getopt
import io
###########################################################
# Utility functions, borrowed from layout2layout.py
def trim_bom(line):
" Remove byte order mark."
if line[0:3] == u"\357\273\277":
return line[3:]
else:
return line
def read(source):
" Read input file and strip lineendings."
lines = source.read().splitlines() or ['']
lines[0] = trim_bom(lines[0])
return lines
def write(output, lines):
" Write output file with native lineendings."
output.write(os.linesep.join(lines) + os.linesep)
# for use by find_format_lines
re_comment = re.compile(r'^#')
re_empty = re.compile(r'^\s*$')
def find_format_line(lines):
'''
Returns (bool, int), where int is number of the line the `Format'
specification is on, or else the number of the first non-blank,
non-comment line. The bool tells whether we found a format line.
'''
for i in range(len(lines)):
l = lines[i]
if re_comment.search(l) or re_empty.search(l):
continue
m = re_format.search(l)
if m:
return (True, i)
# we're done when we have hit a non-comment, non-empty line
break
return (False, i)
# for use by get_format
re_format = re.compile(r'^Format\s+(\d+)\s*$')
def get_format(lines):
" Gets format of current file and replaces the format line with a new one "
(found, format_line) = find_format_line(lines)
if not found:
return 0
line = lines[format_line]
m = re_format.search(line)
if not m:
sys.stderr.write("Couldn't match format line!\n" + line + "\n")
sys.exit(1)
return int(m.group(1))
def update_format(lines):
" Writes new format line "
(found, format_line) = find_format_line(lines)
if not found:
lines[format_line:format_line] = ("Format 1", "")
return
line = lines[format_line]
m = re_format.search(line)
if not m:
sys.stderr.write("Couldn't match format line!\n" + line + "\n")
sys.exit(1)
format = int(m.group(1))
lines[format_line] = "Format " + str(format + 1)
def abort(msg):
sys.stderr.write("\n%s\n" % (msg))
sys.exit(10)
#
###########################################################
def usage():
print ("%s [-l] [-p] infile outfile" % sys.argv[0])
print ("or: %s [-l] [-p] <infile >outfile" % sys.argv[0])
print (" -l: convert LFUNs (bind and ui files)")
print (" -p: convert preferences")
print ("Note that exactly one of -l and -p is required.")
def main(argv):
try:
(options, args) = getopt(sys.argv[1:], "lp")
except:
usage()
abort("Unrecognized option")
opened_files = False
# Open files
if len(args) == 0:
source = sys.stdin
output = sys.stdout
elif len(args) == 2:
source = io.open(args[0], 'r', encoding='utf_8', errors='surrogateescape')
output = io.open(args[1], 'w', encoding='utf_8', newline='\n')
opened_files = True
else:
usage()
abort("Either zero or two arguments must be given.")
conversions = False
for (opt, param) in options:
if opt == "-l":
from prefs2prefs_lfuns import conversions
elif opt == "-p":
from prefs2prefs_prefs import conversions
if not conversions:
usage()
abort("Neither -l nor -p given.")
elif len(options) > 1:
usage()
abort("Only one of -l or -p should be given.")
current_format = len(conversions)
lines = read(source)
format = get_format(lines)
while format < current_format:
target_format, convert = conversions[format]
old_format = format
# make sure the conversion list is sequential
if int(old_format) + 1 != target_format:
abort("Something is wrong with the conversion chain.")
for c in convert:
for i in range(len(lines)):
(update, newline) = c(lines[i])
if update:
lines[i] = newline
update_format(lines)
format = get_format(lines)
# sanity check
if int(old_format) + 1 != int(format):
abort("Failed to convert to new format!")
write(output, lines)
# Close files
if opened_files:
source.close()
output.close()
return 0
if __name__ == "__main__":
main(sys.argv)