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