| #!/usr/bin/env python |
| # ************************************************************* |
| # |
| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| # |
| # ************************************************************* |
| |
| |
| import getopt |
| import os |
| import re |
| import sys |
| # |
| from srclexer import SrcLexer |
| from srcparser import SrcParser |
| from boxer import Boxer |
| # FIXME |
| from globals import * |
| |
| def option_parser (): |
| import optparse |
| p = optparse.OptionParser () |
| |
| p.usage = '''src2xml.py [OPTION]... SRC-FILE...''' |
| |
| examples = ''' |
| Examples: |
| src2xml.py --output-dir=. --post-process --ignore-includes zoom.src |
| src2xml.py --dry-run -I svx/inc -I svx/source/dialog zoom.src |
| ''' |
| |
| def format_examples (self): |
| return examples |
| |
| if 'epilog' in p.__dict__: |
| p.formatter.format_epilog = format_examples |
| p.epilog = examples |
| else: |
| p.formatter.format_description = format_examples |
| p.description = examples |
| |
| p.description = '''OOo SRC To Layout XML Converter. |
| |
| Convert OO.o's existing dialog resource files into XML layout files. |
| ''' |
| |
| p.add_option ('-l', '--debug-lexer', action='store_true', |
| dest='debug_lexer', default=False, |
| help='debug lexer') |
| |
| p.add_option ('-p', '--debug-parser', action='store_true', |
| dest='debug_parser', default=False, |
| help='debug parser') |
| |
| p.add_option ('-m', '--debug-macro', action='store_true', |
| dest='debug_macro', default=False, |
| help='debug macro') |
| |
| p.add_option ('-n', '--dry-run', action='store_true', |
| dest='dry_run', default=False, |
| help='dry run') |
| |
| p.add_option ('-k', '--keep-going', action='store_true', |
| dest='keep_going', default=False, |
| help='continue after error') |
| |
| p.add_option ('-i', '--ignore-includes', action='store_true', |
| dest='ignore_includes', default=False, |
| help='ignore #include directives') |
| |
| p.add_option ('-I', '--include-dir', action='append', |
| dest='include_path', |
| default=[], |
| metavar='DIR', |
| help='append DIR to include path') |
| |
| def from_file (option, opt_str, value, parser): |
| lst = getattr (parser.values, option.dest) |
| lst += file (value).read ().split ('\n') |
| setattr (parser.values, option.dest, lst) |
| |
| def from_path (option, opt_str, value, parser): |
| lst = getattr (parser.values, option.dest) |
| lst += value.split (':') |
| setattr (parser.values, option.dest, lst) |
| |
| # Junk me? |
| p.add_option ('--includes-from-file', action='callback', callback=from_file, |
| dest='include_path', |
| default=[], |
| type='string', |
| metavar='FILE', |
| help='append directory list from FILE to include path') |
| |
| p.add_option ('--include-path', action='callback', callback=from_path, |
| dest='include_path', |
| type='string', |
| default=[], |
| metavar='PATH', |
| help='append PATH to include path') |
| |
| p.add_option ('--only-expand-macros', action='store_true', |
| dest='only_expand_macros', default=False, |
| help='FIXME: better to say what NOT to expand?') |
| |
| p.add_option ('-o', '--output-dir', action='store', |
| dest='output_dir', default=None, |
| metavar='DIR', |
| help='Output to DIR') |
| |
| p.add_option ('-s', '--post-process', action='store_true', |
| dest='post_process', default=False, |
| help='post process output for use in Layout') |
| |
| p.add_option ('--stop-on-header', action='store_true', |
| dest='stopOnHeader', default=False, |
| help='FIXME: remove this?') |
| |
| return p |
| |
| |
| def convert (file_name, options): |
| progress ("parsing %(file_name)s ..." % locals ()) |
| fullpath = os.path.abspath(file_name) |
| if not os.path.isfile(fullpath): |
| error("no such file", exit=True) |
| |
| ##options.include_path.append (os.path.dirname (fullpath)) |
| |
| input = file (fullpath, 'r').read() |
| lexer = SrcLexer(input, fullpath) |
| lexer.expandHeaders = not options.ignore_includes |
| lexer.includeDirs = options.include_path |
| lexer.stopOnHeader = options.stopOnHeader |
| lexer.debugMacro = options.debug_macro |
| if options.debug_lexer: |
| lexer.debug = True |
| lexer.tokenize() |
| progress ("-"*68 + "\n") |
| progress ("** token dump\n") |
| lexer.dumpTokens() |
| progress ("** end of token dump\n") |
| return |
| |
| # Tokenize it using lexer |
| lexer.tokenize() |
| |
| parser = SrcParser(lexer.getTokens(), lexer.getDefines()) |
| parser.only_expand_macros = options.only_expand_macros |
| if options.debug_parser: |
| parser.debug = True |
| root = parser.parse() |
| s = root.dump() |
| return s |
| |
| # Parse the tokens. |
| root = parser.parse() |
| |
| # Box it, and return the XML tree. |
| root = Boxer(root).layout() |
| output = root.dump() |
| if not options.dry_run: |
| progress ("\n") |
| return output |
| |
| def dry_one_file (file_name, options): |
| try: |
| str = convert(file_name, options) |
| progress (" SUCCESS\n") |
| except Exception as e: |
| if options.keep_going: |
| progress (" FAILED\n") |
| else: |
| import traceback |
| print(traceback.format_exc (None)) |
| raise e |
| |
| def post_process (s): |
| """Make output directly usable by layout module.""" |
| s = re.sub ('(</?)([a-z]+)-([a-z]+)-([a-z]+)', r'\1\2\3\4', s) |
| s = re.sub ('(</?)([a-z]+)-([a-z]+)', r'\1\2\3', s) |
| s = re.sub ('(<(checkbox|(cancel|help|ignore|ok|push|more|no|radio|reset|retry|yes)button|(fixed(info|text)))[^>]*) text=', r'\1 label=', s) |
| s = re.sub (' (height|width|x|y)="[0-9]*"', '', s) |
| s = re.sub (' (label|text|title)="', r' _\1="', s) |
| s = re.sub ('&([^m][^p]*[^;]*)', r'&\1', s) |
| s = re.sub (' hide="(TRUE|true|1)"', ' show="false"', s) |
| |
| s = s.replace ('<modaldialog', '<modaldialog sizeable="true"') |
| s = s.replace (' rid=', ' id=') |
| s = s.replace (' border="true"', ' has_border="true"') |
| s = s.replace (' def-button="true"', ' defbutton="true"') |
| s = s.replace (' drop-down="', ' dropdown="') |
| s = s.replace (' tab-stop="', ' tabstop="') |
| return s |
| |
| XML_HEADER = '''<?xml version="1.0" encoding="UTF-8"?> |
| <!-- This is a template. i18n translation is not performed in-place; |
| i18n translated XML files are generated from this template by |
| transex3/layout/tralay. !--> |
| ''' |
| |
| def do_one_file (file_name, options): |
| str = XML_HEADER |
| str += convert(file_name, options) |
| str += '\n' |
| |
| if options.post_process: |
| str = post_process (str) |
| h = sys.stdout |
| if options.output_dir: |
| base = os.path.basename (file_name) |
| root, ext = os.path.splitext (base) |
| out_name = options.output_dir + '/' + root + '.xml' |
| progress ("writing %(out_name)s ..." % locals ()) |
| h = file (out_name, 'w') |
| h.write (str) |
| h.flush () |
| progress ("\n") |
| |
| def main (): |
| p = option_parser () |
| (options, files) = option_parser ().parse_args () |
| if not files: |
| p.error ("no input files") |
| |
| for f in files: |
| if options.dry_run: |
| dry_one_file (f, options) |
| else: |
| do_one_file (f, options) |
| |
| if __name__ == '__main__': |
| main () |