1*b1cdbd2cSJim Jagielski#!/usr/bin/env python 2*b1cdbd2cSJim Jagielski# ************************************************************* 3*b1cdbd2cSJim Jagielski# 4*b1cdbd2cSJim Jagielski# Licensed to the Apache Software Foundation (ASF) under one 5*b1cdbd2cSJim Jagielski# or more contributor license agreements. See the NOTICE file 6*b1cdbd2cSJim Jagielski# distributed with this work for additional information 7*b1cdbd2cSJim Jagielski# regarding copyright ownership. The ASF licenses this file 8*b1cdbd2cSJim Jagielski# to you under the Apache License, Version 2.0 (the 9*b1cdbd2cSJim Jagielski# "License"); you may not use this file except in compliance 10*b1cdbd2cSJim Jagielski# with the License. You may obtain a copy of the License at 11*b1cdbd2cSJim Jagielski# 12*b1cdbd2cSJim Jagielski# http://www.apache.org/licenses/LICENSE-2.0 13*b1cdbd2cSJim Jagielski# 14*b1cdbd2cSJim Jagielski# Unless required by applicable law or agreed to in writing, 15*b1cdbd2cSJim Jagielski# software distributed under the License is distributed on an 16*b1cdbd2cSJim Jagielski# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17*b1cdbd2cSJim Jagielski# KIND, either express or implied. See the License for the 18*b1cdbd2cSJim Jagielski# specific language governing permissions and limitations 19*b1cdbd2cSJim Jagielski# under the License. 20*b1cdbd2cSJim Jagielski# 21*b1cdbd2cSJim Jagielski# ************************************************************* 22*b1cdbd2cSJim Jagielski 23*b1cdbd2cSJim Jagielski 24*b1cdbd2cSJim Jagielskiimport getopt 25*b1cdbd2cSJim Jagielskiimport os 26*b1cdbd2cSJim Jagielskiimport re 27*b1cdbd2cSJim Jagielskiimport sys 28*b1cdbd2cSJim Jagielski# 29*b1cdbd2cSJim Jagielskifrom srclexer import SrcLexer 30*b1cdbd2cSJim Jagielskifrom srcparser import SrcParser 31*b1cdbd2cSJim Jagielskifrom boxer import Boxer 32*b1cdbd2cSJim Jagielski# FIXME 33*b1cdbd2cSJim Jagielskifrom globals import * 34*b1cdbd2cSJim Jagielski 35*b1cdbd2cSJim Jagielskidef option_parser (): 36*b1cdbd2cSJim Jagielski import optparse 37*b1cdbd2cSJim Jagielski p = optparse.OptionParser () 38*b1cdbd2cSJim Jagielski 39*b1cdbd2cSJim Jagielski p.usage = '''src2xml.py [OPTION]... SRC-FILE...''' 40*b1cdbd2cSJim Jagielski 41*b1cdbd2cSJim Jagielski examples = ''' 42*b1cdbd2cSJim JagielskiExamples: 43*b1cdbd2cSJim Jagielski src2xml.py --output-dir=. --post-process --ignore-includes zoom.src 44*b1cdbd2cSJim Jagielski src2xml.py --dry-run -I svx/inc -I svx/source/dialog zoom.src 45*b1cdbd2cSJim Jagielski''' 46*b1cdbd2cSJim Jagielski 47*b1cdbd2cSJim Jagielski def format_examples (self): 48*b1cdbd2cSJim Jagielski return examples 49*b1cdbd2cSJim Jagielski 50*b1cdbd2cSJim Jagielski if 'epilog' in p.__dict__: 51*b1cdbd2cSJim Jagielski p.formatter.format_epilog = format_examples 52*b1cdbd2cSJim Jagielski p.epilog = examples 53*b1cdbd2cSJim Jagielski else: 54*b1cdbd2cSJim Jagielski p.formatter.format_description = format_examples 55*b1cdbd2cSJim Jagielski p.description = examples 56*b1cdbd2cSJim Jagielski 57*b1cdbd2cSJim Jagielski p.description = '''OOo SRC To Layout XML Converter. 58*b1cdbd2cSJim Jagielski 59*b1cdbd2cSJim JagielskiConvert OO.o's existing dialog resource files into XML layout files. 60*b1cdbd2cSJim Jagielski''' 61*b1cdbd2cSJim Jagielski 62*b1cdbd2cSJim Jagielski p.add_option ('-l', '--debug-lexer', action='store_true', 63*b1cdbd2cSJim Jagielski dest='debug_lexer', default=False, 64*b1cdbd2cSJim Jagielski help='debug lexer') 65*b1cdbd2cSJim Jagielski 66*b1cdbd2cSJim Jagielski p.add_option ('-p', '--debug-parser', action='store_true', 67*b1cdbd2cSJim Jagielski dest='debug_parser', default=False, 68*b1cdbd2cSJim Jagielski help='debug parser') 69*b1cdbd2cSJim Jagielski 70*b1cdbd2cSJim Jagielski p.add_option ('-m', '--debug-macro', action='store_true', 71*b1cdbd2cSJim Jagielski dest='debug_macro', default=False, 72*b1cdbd2cSJim Jagielski help='debug macro') 73*b1cdbd2cSJim Jagielski 74*b1cdbd2cSJim Jagielski p.add_option ('-n', '--dry-run', action='store_true', 75*b1cdbd2cSJim Jagielski dest='dry_run', default=False, 76*b1cdbd2cSJim Jagielski help='dry run') 77*b1cdbd2cSJim Jagielski 78*b1cdbd2cSJim Jagielski p.add_option ('-k', '--keep-going', action='store_true', 79*b1cdbd2cSJim Jagielski dest='keep_going', default=False, 80*b1cdbd2cSJim Jagielski help='continue after error') 81*b1cdbd2cSJim Jagielski 82*b1cdbd2cSJim Jagielski p.add_option ('-i', '--ignore-includes', action='store_true', 83*b1cdbd2cSJim Jagielski dest='ignore_includes', default=False, 84*b1cdbd2cSJim Jagielski help='ignore #include directives') 85*b1cdbd2cSJim Jagielski 86*b1cdbd2cSJim Jagielski p.add_option ('-I', '--include-dir', action='append', 87*b1cdbd2cSJim Jagielski dest='include_path', 88*b1cdbd2cSJim Jagielski default=[], 89*b1cdbd2cSJim Jagielski metavar='DIR', 90*b1cdbd2cSJim Jagielski help='append DIR to include path') 91*b1cdbd2cSJim Jagielski 92*b1cdbd2cSJim Jagielski def from_file (option, opt_str, value, parser): 93*b1cdbd2cSJim Jagielski lst = getattr (parser.values, option.dest) 94*b1cdbd2cSJim Jagielski lst += file (value).read ().split ('\n') 95*b1cdbd2cSJim Jagielski setattr (parser.values, option.dest, lst) 96*b1cdbd2cSJim Jagielski 97*b1cdbd2cSJim Jagielski def from_path (option, opt_str, value, parser): 98*b1cdbd2cSJim Jagielski lst = getattr (parser.values, option.dest) 99*b1cdbd2cSJim Jagielski lst += value.split (':') 100*b1cdbd2cSJim Jagielski setattr (parser.values, option.dest, lst) 101*b1cdbd2cSJim Jagielski 102*b1cdbd2cSJim Jagielski # Junk me? 103*b1cdbd2cSJim Jagielski p.add_option ('--includes-from-file', action='callback', callback=from_file, 104*b1cdbd2cSJim Jagielski dest='include_path', 105*b1cdbd2cSJim Jagielski default=[], 106*b1cdbd2cSJim Jagielski type='string', 107*b1cdbd2cSJim Jagielski metavar='FILE', 108*b1cdbd2cSJim Jagielski help='append directory list from FILE to include path') 109*b1cdbd2cSJim Jagielski 110*b1cdbd2cSJim Jagielski p.add_option ('--include-path', action='callback', callback=from_path, 111*b1cdbd2cSJim Jagielski dest='include_path', 112*b1cdbd2cSJim Jagielski type='string', 113*b1cdbd2cSJim Jagielski default=[], 114*b1cdbd2cSJim Jagielski metavar='PATH', 115*b1cdbd2cSJim Jagielski help='append PATH to include path') 116*b1cdbd2cSJim Jagielski 117*b1cdbd2cSJim Jagielski p.add_option ('--only-expand-macros', action='store_true', 118*b1cdbd2cSJim Jagielski dest='only_expand_macros', default=False, 119*b1cdbd2cSJim Jagielski help='FIXME: better to say what NOT to expand?') 120*b1cdbd2cSJim Jagielski 121*b1cdbd2cSJim Jagielski p.add_option ('-o', '--output-dir', action='store', 122*b1cdbd2cSJim Jagielski dest='output_dir', default=None, 123*b1cdbd2cSJim Jagielski metavar='DIR', 124*b1cdbd2cSJim Jagielski help='Output to DIR') 125*b1cdbd2cSJim Jagielski 126*b1cdbd2cSJim Jagielski p.add_option ('-s', '--post-process', action='store_true', 127*b1cdbd2cSJim Jagielski dest='post_process', default=False, 128*b1cdbd2cSJim Jagielski help='post process output for use in Layout') 129*b1cdbd2cSJim Jagielski 130*b1cdbd2cSJim Jagielski p.add_option ('--stop-on-header', action='store_true', 131*b1cdbd2cSJim Jagielski dest='stopOnHeader', default=False, 132*b1cdbd2cSJim Jagielski help='FIXME: remove this?') 133*b1cdbd2cSJim Jagielski 134*b1cdbd2cSJim Jagielski return p 135*b1cdbd2cSJim Jagielski 136*b1cdbd2cSJim Jagielski 137*b1cdbd2cSJim Jagielskidef convert (file_name, options): 138*b1cdbd2cSJim Jagielski progress ("parsing %(file_name)s ..." % locals ()) 139*b1cdbd2cSJim Jagielski fullpath = os.path.abspath(file_name) 140*b1cdbd2cSJim Jagielski if not os.path.isfile(fullpath): 141*b1cdbd2cSJim Jagielski error("no such file", exit=True) 142*b1cdbd2cSJim Jagielski 143*b1cdbd2cSJim Jagielski ##options.include_path.append (os.path.dirname (fullpath)) 144*b1cdbd2cSJim Jagielski 145*b1cdbd2cSJim Jagielski input = file (fullpath, 'r').read() 146*b1cdbd2cSJim Jagielski lexer = SrcLexer(input, fullpath) 147*b1cdbd2cSJim Jagielski lexer.expandHeaders = not options.ignore_includes 148*b1cdbd2cSJim Jagielski lexer.includeDirs = options.include_path 149*b1cdbd2cSJim Jagielski lexer.stopOnHeader = options.stopOnHeader 150*b1cdbd2cSJim Jagielski lexer.debugMacro = options.debug_macro 151*b1cdbd2cSJim Jagielski if options.debug_lexer: 152*b1cdbd2cSJim Jagielski lexer.debug = True 153*b1cdbd2cSJim Jagielski lexer.tokenize() 154*b1cdbd2cSJim Jagielski progress ("-"*68 + "\n") 155*b1cdbd2cSJim Jagielski progress ("** token dump\n") 156*b1cdbd2cSJim Jagielski lexer.dumpTokens() 157*b1cdbd2cSJim Jagielski progress ("** end of token dump\n") 158*b1cdbd2cSJim Jagielski return 159*b1cdbd2cSJim Jagielski 160*b1cdbd2cSJim Jagielski # Tokenize it using lexer 161*b1cdbd2cSJim Jagielski lexer.tokenize() 162*b1cdbd2cSJim Jagielski 163*b1cdbd2cSJim Jagielski parser = SrcParser(lexer.getTokens(), lexer.getDefines()) 164*b1cdbd2cSJim Jagielski parser.only_expand_macros = options.only_expand_macros 165*b1cdbd2cSJim Jagielski if options.debug_parser: 166*b1cdbd2cSJim Jagielski parser.debug = True 167*b1cdbd2cSJim Jagielski root = parser.parse() 168*b1cdbd2cSJim Jagielski s = root.dump() 169*b1cdbd2cSJim Jagielski return s 170*b1cdbd2cSJim Jagielski 171*b1cdbd2cSJim Jagielski # Parse the tokens. 172*b1cdbd2cSJim Jagielski root = parser.parse() 173*b1cdbd2cSJim Jagielski 174*b1cdbd2cSJim Jagielski # Box it, and return the XML tree. 175*b1cdbd2cSJim Jagielski root = Boxer(root).layout() 176*b1cdbd2cSJim Jagielski output = root.dump() 177*b1cdbd2cSJim Jagielski if not options.dry_run: 178*b1cdbd2cSJim Jagielski progress ("\n") 179*b1cdbd2cSJim Jagielski return output 180*b1cdbd2cSJim Jagielski 181*b1cdbd2cSJim Jagielskidef dry_one_file (file_name, options): 182*b1cdbd2cSJim Jagielski try: 183*b1cdbd2cSJim Jagielski str = convert(file_name, options) 184*b1cdbd2cSJim Jagielski progress (" SUCCESS\n") 185*b1cdbd2cSJim Jagielski except Exception as e: 186*b1cdbd2cSJim Jagielski if options.keep_going: 187*b1cdbd2cSJim Jagielski progress (" FAILED\n") 188*b1cdbd2cSJim Jagielski else: 189*b1cdbd2cSJim Jagielski import traceback 190*b1cdbd2cSJim Jagielski print(traceback.format_exc (None)) 191*b1cdbd2cSJim Jagielski raise e 192*b1cdbd2cSJim Jagielski 193*b1cdbd2cSJim Jagielskidef post_process (s): 194*b1cdbd2cSJim Jagielski """Make output directly usable by layout module.""" 195*b1cdbd2cSJim Jagielski s = re.sub ('(</?)([a-z]+)-([a-z]+)-([a-z]+)', r'\1\2\3\4', s) 196*b1cdbd2cSJim Jagielski s = re.sub ('(</?)([a-z]+)-([a-z]+)', r'\1\2\3', s) 197*b1cdbd2cSJim Jagielski s = re.sub ('(<(checkbox|(cancel|help|ignore|ok|push|more|no|radio|reset|retry|yes)button|(fixed(info|text)))[^>]*) text=', r'\1 label=', s) 198*b1cdbd2cSJim Jagielski s = re.sub (' (height|width|x|y)="[0-9]*"', '', s) 199*b1cdbd2cSJim Jagielski s = re.sub (' (label|text|title)="', r' _\1="', s) 200*b1cdbd2cSJim Jagielski s = re.sub ('&([^m][^p]*[^;]*)', r'&\1', s) 201*b1cdbd2cSJim Jagielski s = re.sub (' hide="(TRUE|true|1)"', ' show="false"', s) 202*b1cdbd2cSJim Jagielski 203*b1cdbd2cSJim Jagielski s = s.replace ('<modaldialog', '<modaldialog sizeable="true"') 204*b1cdbd2cSJim Jagielski s = s.replace (' rid=', ' id=') 205*b1cdbd2cSJim Jagielski s = s.replace (' border="true"', ' has_border="true"') 206*b1cdbd2cSJim Jagielski s = s.replace (' def-button="true"', ' defbutton="true"') 207*b1cdbd2cSJim Jagielski s = s.replace (' drop-down="', ' dropdown="') 208*b1cdbd2cSJim Jagielski s = s.replace (' tab-stop="', ' tabstop="') 209*b1cdbd2cSJim Jagielski return s 210*b1cdbd2cSJim Jagielski 211*b1cdbd2cSJim JagielskiXML_HEADER = '''<?xml version="1.0" encoding="UTF-8"?> 212*b1cdbd2cSJim Jagielski<!-- This is a template. i18n translation is not performed in-place; 213*b1cdbd2cSJim Jagielski i18n translated XML files are generated from this template by 214*b1cdbd2cSJim Jagielski transex3/layout/tralay. !--> 215*b1cdbd2cSJim Jagielski''' 216*b1cdbd2cSJim Jagielski 217*b1cdbd2cSJim Jagielskidef do_one_file (file_name, options): 218*b1cdbd2cSJim Jagielski str = XML_HEADER 219*b1cdbd2cSJim Jagielski str += convert(file_name, options) 220*b1cdbd2cSJim Jagielski str += '\n' 221*b1cdbd2cSJim Jagielski 222*b1cdbd2cSJim Jagielski if options.post_process: 223*b1cdbd2cSJim Jagielski str = post_process (str) 224*b1cdbd2cSJim Jagielski h = sys.stdout 225*b1cdbd2cSJim Jagielski if options.output_dir: 226*b1cdbd2cSJim Jagielski base = os.path.basename (file_name) 227*b1cdbd2cSJim Jagielski root, ext = os.path.splitext (base) 228*b1cdbd2cSJim Jagielski out_name = options.output_dir + '/' + root + '.xml' 229*b1cdbd2cSJim Jagielski progress ("writing %(out_name)s ..." % locals ()) 230*b1cdbd2cSJim Jagielski h = file (out_name, 'w') 231*b1cdbd2cSJim Jagielski h.write (str) 232*b1cdbd2cSJim Jagielski h.flush () 233*b1cdbd2cSJim Jagielski progress ("\n") 234*b1cdbd2cSJim Jagielski 235*b1cdbd2cSJim Jagielskidef main (): 236*b1cdbd2cSJim Jagielski p = option_parser () 237*b1cdbd2cSJim Jagielski (options, files) = option_parser ().parse_args () 238*b1cdbd2cSJim Jagielski if not files: 239*b1cdbd2cSJim Jagielski p.error ("no input files") 240*b1cdbd2cSJim Jagielski 241*b1cdbd2cSJim Jagielski for f in files: 242*b1cdbd2cSJim Jagielski if options.dry_run: 243*b1cdbd2cSJim Jagielski dry_one_file (f, options) 244*b1cdbd2cSJim Jagielski else: 245*b1cdbd2cSJim Jagielski do_one_file (f, options) 246*b1cdbd2cSJim Jagielski 247*b1cdbd2cSJim Jagielskiif __name__ == '__main__': 248*b1cdbd2cSJim Jagielski main () 249