1 | # @file ConvertMasmToNasm.py
|
---|
2 | # This script assists with conversion of MASM assembly syntax to NASM
|
---|
3 | #
|
---|
4 | # Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
|
---|
5 | #
|
---|
6 | # This program and the accompanying materials
|
---|
7 | # are licensed and made available under the terms and conditions of the BSD License
|
---|
8 | # which accompanies this distribution. The full text of the license may be found at
|
---|
9 | # http://opensource.org/licenses/bsd-license.php
|
---|
10 | #
|
---|
11 | # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
---|
12 | # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
---|
13 | #
|
---|
14 |
|
---|
15 | from __future__ import print_function
|
---|
16 |
|
---|
17 | #
|
---|
18 | # Import Modules
|
---|
19 | #
|
---|
20 | import argparse
|
---|
21 | import io
|
---|
22 | import os.path
|
---|
23 | import re
|
---|
24 | import subprocess
|
---|
25 | import sys
|
---|
26 |
|
---|
27 |
|
---|
28 | class UnsupportedConversion(Exception):
|
---|
29 | pass
|
---|
30 |
|
---|
31 |
|
---|
32 | class NoSourceFile(Exception):
|
---|
33 | pass
|
---|
34 |
|
---|
35 |
|
---|
36 | class UnsupportedArch(Exception):
|
---|
37 | unsupported = ('aarch64', 'arm', 'ebc', 'ipf')
|
---|
38 |
|
---|
39 |
|
---|
40 | class CommonUtils:
|
---|
41 |
|
---|
42 | # Version and Copyright
|
---|
43 | VersionNumber = "0.01"
|
---|
44 | __version__ = "%prog Version " + VersionNumber
|
---|
45 | __copyright__ = "Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved."
|
---|
46 | __usage__ = "%prog [options] source.asm [destination.nasm]"
|
---|
47 |
|
---|
48 | def __init__(self, clone=None):
|
---|
49 | if clone is None:
|
---|
50 | self.args = self.ProcessCommandLine()
|
---|
51 | else:
|
---|
52 | self.args = clone.args
|
---|
53 |
|
---|
54 | self.unsupportedSyntaxSeen = False
|
---|
55 | self.src = self.args.source
|
---|
56 | self.keep = self.args.keep
|
---|
57 | assert(os.path.exists(self.src))
|
---|
58 | self.dirmode = os.path.isdir(self.src)
|
---|
59 | srcExt = os.path.splitext(self.src)[1]
|
---|
60 | assert (self.dirmode or srcExt != '.nasm')
|
---|
61 | self.infmode = not self.dirmode and srcExt == '.inf'
|
---|
62 | self.diff = self.args.diff
|
---|
63 | self.git = self.args.git
|
---|
64 | self.force = self.args.force
|
---|
65 |
|
---|
66 | if clone is None:
|
---|
67 | self.rootdir = os.getcwd()
|
---|
68 | self.DetectGit()
|
---|
69 | else:
|
---|
70 | self.rootdir = clone.rootdir
|
---|
71 | self.gitdir = clone.gitdir
|
---|
72 | self.gitemail = clone.gitemail
|
---|
73 |
|
---|
74 | def ProcessCommandLine(self):
|
---|
75 | parser = argparse.ArgumentParser(description=self.__copyright__)
|
---|
76 | parser.add_argument('--version', action='version',
|
---|
77 | version='%(prog)s ' + self.VersionNumber)
|
---|
78 | parser.add_argument("-q", "--quiet", action="store_true",
|
---|
79 | help="Disable all messages except FATAL ERRORS.")
|
---|
80 | parser.add_argument("--git", action="store_true",
|
---|
81 | help="Use git to create commits for each file converted")
|
---|
82 | parser.add_argument("--keep", action="append", choices=('asm', 's'),
|
---|
83 | default=[],
|
---|
84 | help="Don't remove files with this extension")
|
---|
85 | parser.add_argument("--diff", action="store_true",
|
---|
86 | help="Show diff of conversion")
|
---|
87 | parser.add_argument("-f", "--force", action="store_true",
|
---|
88 | help="Force conversion even if unsupported")
|
---|
89 | parser.add_argument('source', help='MASM input file')
|
---|
90 | parser.add_argument('dest', nargs='?',
|
---|
91 | help='NASM output file (default=input.nasm; - for stdout)')
|
---|
92 |
|
---|
93 | return parser.parse_args()
|
---|
94 |
|
---|
95 | def RootRelative(self, path):
|
---|
96 | result = path
|
---|
97 | if result.startswith(self.rootdir):
|
---|
98 | result = result[len(self.rootdir):]
|
---|
99 | while len(result) > 0 and result[0] in '/\\':
|
---|
100 | result = result[1:]
|
---|
101 | return result
|
---|
102 |
|
---|
103 | def MatchAndSetMo(self, regexp, string):
|
---|
104 | self.mo = regexp.match(string)
|
---|
105 | return self.mo is not None
|
---|
106 |
|
---|
107 | def SearchAndSetMo(self, regexp, string):
|
---|
108 | self.mo = regexp.search(string)
|
---|
109 | return self.mo is not None
|
---|
110 |
|
---|
111 | def ReplacePreserveSpacing(self, string, find, replace):
|
---|
112 | if len(find) >= len(replace):
|
---|
113 | padded = replace + (' ' * (len(find) - len(replace)))
|
---|
114 | return string.replace(find, padded)
|
---|
115 | elif find.find(replace) >= 0:
|
---|
116 | return string.replace(find, replace)
|
---|
117 | else:
|
---|
118 | lenDiff = len(replace) - len(find)
|
---|
119 | result = string
|
---|
120 | for i in range(lenDiff, -1, -1):
|
---|
121 | padded = find + (' ' * i)
|
---|
122 | result = result.replace(padded, replace)
|
---|
123 | return result
|
---|
124 |
|
---|
125 | def DetectGit(self):
|
---|
126 | lastpath = os.path.realpath(self.src)
|
---|
127 | self.gitdir = None
|
---|
128 | while True:
|
---|
129 | path = os.path.split(lastpath)[0]
|
---|
130 | if path == lastpath:
|
---|
131 | self.gitemail = None
|
---|
132 | return
|
---|
133 | candidate = os.path.join(path, '.git')
|
---|
134 | if os.path.isdir(candidate):
|
---|
135 | self.gitdir = candidate
|
---|
136 | self.gitemail = self.FormatGitEmailAddress()
|
---|
137 | return
|
---|
138 | lastpath = path
|
---|
139 |
|
---|
140 | def FormatGitEmailAddress(self):
|
---|
141 | if not self.git or not self.gitdir:
|
---|
142 | return ''
|
---|
143 |
|
---|
144 | cmd = ('git', 'config', 'user.name')
|
---|
145 | name = self.RunAndCaptureOutput(cmd).strip()
|
---|
146 | cmd = ('git', 'config', 'user.email')
|
---|
147 | email = self.RunAndCaptureOutput(cmd).strip()
|
---|
148 | if name.find(',') >= 0:
|
---|
149 | name = '"' + name + '"'
|
---|
150 | return name + ' <' + email + '>'
|
---|
151 |
|
---|
152 | def RunAndCaptureOutput(self, cmd, checkExitCode=True, pipeIn=None):
|
---|
153 | if pipeIn:
|
---|
154 | subpStdin = subprocess.PIPE
|
---|
155 | else:
|
---|
156 | subpStdin = None
|
---|
157 | p = subprocess.Popen(args=cmd, stdout=subprocess.PIPE, stdin=subpStdin)
|
---|
158 | (stdout, stderr) = p.communicate(pipeIn)
|
---|
159 | if checkExitCode:
|
---|
160 | if p.returncode != 0:
|
---|
161 | print('command:', ' '.join(cmd))
|
---|
162 | print('stdout:', stdout)
|
---|
163 | print('stderr:', stderr)
|
---|
164 | print('return:', p.returncode)
|
---|
165 | assert p.returncode == 0
|
---|
166 | return stdout.decode('utf-8', 'ignore')
|
---|
167 |
|
---|
168 | def FileUpdated(self, path):
|
---|
169 | if not self.git or not self.gitdir:
|
---|
170 | return
|
---|
171 |
|
---|
172 | cmd = ('git', 'add', path)
|
---|
173 | self.RunAndCaptureOutput(cmd)
|
---|
174 |
|
---|
175 | def FileAdded(self, path):
|
---|
176 | self.FileUpdated(path)
|
---|
177 |
|
---|
178 | def RemoveFile(self, path):
|
---|
179 | if not self.git or not self.gitdir:
|
---|
180 | return
|
---|
181 |
|
---|
182 | if self.ShouldKeepFile(path):
|
---|
183 | return
|
---|
184 |
|
---|
185 | cmd = ('git', 'rm', path)
|
---|
186 | self.RunAndCaptureOutput(cmd)
|
---|
187 |
|
---|
188 | def ShouldKeepFile(self, path):
|
---|
189 | ext = os.path.splitext(path)[1].lower()
|
---|
190 | if ext.startswith('.'):
|
---|
191 | ext = ext[1:]
|
---|
192 | return ext in self.keep
|
---|
193 |
|
---|
194 | def FileConversionFinished(self, pkg, module, src, dst):
|
---|
195 | if not self.git or not self.gitdir:
|
---|
196 | return
|
---|
197 |
|
---|
198 | if not self.args.quiet:
|
---|
199 | print('Committing: Conversion of', dst)
|
---|
200 |
|
---|
201 | prefix = ' '.join(filter(lambda a: a, [pkg, module]))
|
---|
202 | message = ''
|
---|
203 | if self.unsupportedSyntaxSeen:
|
---|
204 | message += 'ERROR! '
|
---|
205 | message += '%s: Convert %s to NASM\n' % (prefix, src)
|
---|
206 | message += '\n'
|
---|
207 | message += 'The %s script was used to convert\n' % sys.argv[0]
|
---|
208 | message += '%s to %s\n' % (src, dst)
|
---|
209 | message += '\n'
|
---|
210 | message += 'Contributed-under: TianoCore Contribution Agreement 1.0\n'
|
---|
211 | assert(self.gitemail is not None)
|
---|
212 | message += 'Signed-off-by: %s\n' % self.gitemail
|
---|
213 | message = message.encode('utf-8', 'ignore')
|
---|
214 |
|
---|
215 | cmd = ('git', 'commit', '-F', '-')
|
---|
216 | self.RunAndCaptureOutput(cmd, pipeIn=message)
|
---|
217 |
|
---|
218 |
|
---|
219 | class ConvertAsmFile(CommonUtils):
|
---|
220 |
|
---|
221 | def __init__(self, src, dst, clone):
|
---|
222 | CommonUtils.__init__(self, clone)
|
---|
223 | self.ConvertAsmFile(src, dst)
|
---|
224 | self.FileAdded(dst)
|
---|
225 | self.RemoveFile(src)
|
---|
226 |
|
---|
227 | def ConvertAsmFile(self, inputFile, outputFile=None):
|
---|
228 | self.globals = set()
|
---|
229 | self.unsupportedSyntaxSeen = False
|
---|
230 | self.inputFilename = inputFile
|
---|
231 | if not outputFile:
|
---|
232 | outputFile = os.path.splitext(inputFile)[0] + '.nasm'
|
---|
233 | self.outputFilename = outputFile
|
---|
234 |
|
---|
235 | fullSrc = os.path.realpath(inputFile)
|
---|
236 | srcParentDir = os.path.basename(os.path.split(fullSrc)[0])
|
---|
237 | maybeArch = srcParentDir.lower()
|
---|
238 | if maybeArch in UnsupportedArch.unsupported:
|
---|
239 | raise UnsupportedArch
|
---|
240 | self.ia32 = maybeArch == 'ia32'
|
---|
241 | self.x64 = maybeArch == 'x64'
|
---|
242 |
|
---|
243 | self.inputFileBase = os.path.basename(self.inputFilename)
|
---|
244 | self.outputFileBase = os.path.basename(self.outputFilename)
|
---|
245 | self.output = io.BytesIO()
|
---|
246 | if not self.args.quiet:
|
---|
247 | dirpath, src = os.path.split(self.inputFilename)
|
---|
248 | dirpath = self.RootRelative(dirpath)
|
---|
249 | dst = os.path.basename(self.outputFilename)
|
---|
250 | print('Converting:', dirpath, src, '->', dst)
|
---|
251 | lines = io.open(self.inputFilename).readlines()
|
---|
252 | self.Convert(lines)
|
---|
253 | if self.outputFilename == '-' and not self.diff:
|
---|
254 | output_data = self.output.getvalue()
|
---|
255 | if sys.version_info >= (3, 0):
|
---|
256 | output_data = output_data.decode('utf-8', 'ignore')
|
---|
257 | sys.stdout.write(output_data)
|
---|
258 | self.output.close()
|
---|
259 | else:
|
---|
260 | f = io.open(self.outputFilename, 'wb')
|
---|
261 | f.write(self.output.getvalue())
|
---|
262 | f.close()
|
---|
263 | self.output.close()
|
---|
264 |
|
---|
265 | endOfLineRe = re.compile(r'''
|
---|
266 | \s* ( ; .* )? \n $
|
---|
267 | ''',
|
---|
268 | re.VERBOSE | re.MULTILINE
|
---|
269 | )
|
---|
270 | begOfLineRe = re.compile(r'''
|
---|
271 | \s*
|
---|
272 | ''',
|
---|
273 | re.VERBOSE
|
---|
274 | )
|
---|
275 |
|
---|
276 | def Convert(self, lines):
|
---|
277 | self.proc = None
|
---|
278 | self.anonLabelCount = -1
|
---|
279 | output = self.output
|
---|
280 | self.oldAsmEmptyLineCount = 0
|
---|
281 | self.newAsmEmptyLineCount = 0
|
---|
282 | for line in lines:
|
---|
283 | mo = self.begOfLineRe.search(line)
|
---|
284 | assert mo is not None
|
---|
285 | self.indent = mo.group()
|
---|
286 | lineWithoutBeginning = line[len(self.indent):]
|
---|
287 | mo = self.endOfLineRe.search(lineWithoutBeginning)
|
---|
288 | if mo is None:
|
---|
289 | endOfLine = ''
|
---|
290 | else:
|
---|
291 | endOfLine = mo.group()
|
---|
292 | oldAsm = line[len(self.indent):len(line) - len(endOfLine)]
|
---|
293 | self.originalLine = line.rstrip()
|
---|
294 | if line.strip() == '':
|
---|
295 | self.oldAsmEmptyLineCount += 1
|
---|
296 | self.TranslateAsm(oldAsm, endOfLine)
|
---|
297 | if line.strip() != '':
|
---|
298 | self.oldAsmEmptyLineCount = 0
|
---|
299 |
|
---|
300 | procDeclRe = re.compile(r'''
|
---|
301 | (?: ASM_PFX \s* [(] \s* )?
|
---|
302 | ([\w@][\w@0-9]*) \s*
|
---|
303 | [)]? \s+
|
---|
304 | PROC
|
---|
305 | (?: \s+ NEAR | FAR )?
|
---|
306 | (?: \s+ C )?
|
---|
307 | (?: \s+ (PUBLIC | PRIVATE) )?
|
---|
308 | (?: \s+ USES ( (?: \s+ \w[\w0-9]* )+ ) )?
|
---|
309 | \s* $
|
---|
310 | ''',
|
---|
311 | re.VERBOSE | re.IGNORECASE
|
---|
312 | )
|
---|
313 |
|
---|
314 | procEndRe = re.compile(r'''
|
---|
315 | ([\w@][\w@0-9]*) \s+
|
---|
316 | ENDP
|
---|
317 | \s* $
|
---|
318 | ''',
|
---|
319 | re.VERBOSE | re.IGNORECASE
|
---|
320 | )
|
---|
321 |
|
---|
322 | varAndTypeSubRe = r' (?: [\w@][\w@0-9]* ) (?: \s* : \s* \w+ )? '
|
---|
323 | publicRe = re.compile(r'''
|
---|
324 | PUBLIC \s+
|
---|
325 | ( %s (?: \s* , \s* %s )* )
|
---|
326 | \s* $
|
---|
327 | ''' % (varAndTypeSubRe, varAndTypeSubRe),
|
---|
328 | re.VERBOSE | re.IGNORECASE
|
---|
329 | )
|
---|
330 |
|
---|
331 | varAndTypeSubRe = re.compile(varAndTypeSubRe, re.VERBOSE | re.IGNORECASE)
|
---|
332 |
|
---|
333 | macroDeclRe = re.compile(r'''
|
---|
334 | ([\w@][\w@0-9]*) \s+
|
---|
335 | MACRO
|
---|
336 | \s* $
|
---|
337 | ''',
|
---|
338 | re.VERBOSE | re.IGNORECASE
|
---|
339 | )
|
---|
340 |
|
---|
341 | sectionDeclRe = re.compile(r'''
|
---|
342 | ([\w@][\w@0-9]*) \s+
|
---|
343 | ( SECTION | ENDS )
|
---|
344 | \s* $
|
---|
345 | ''',
|
---|
346 | re.VERBOSE | re.IGNORECASE
|
---|
347 | )
|
---|
348 |
|
---|
349 | externRe = re.compile(r'''
|
---|
350 | EXTE?RN \s+ (?: C \s+ )?
|
---|
351 | ([\w@][\w@0-9]*) \s* : \s* (\w+)
|
---|
352 | \s* $
|
---|
353 | ''',
|
---|
354 | re.VERBOSE | re.IGNORECASE
|
---|
355 | )
|
---|
356 |
|
---|
357 | externdefRe = re.compile(r'''
|
---|
358 | EXTERNDEF \s+ (?: C \s+ )?
|
---|
359 | ([\w@][\w@0-9]*) \s* : \s* (\w+)
|
---|
360 | \s* $
|
---|
361 | ''',
|
---|
362 | re.VERBOSE | re.IGNORECASE
|
---|
363 | )
|
---|
364 |
|
---|
365 | protoRe = re.compile(r'''
|
---|
366 | ([\w@][\w@0-9]*) \s+
|
---|
367 | PROTO
|
---|
368 | (?: \s+ .* )?
|
---|
369 | \s* $
|
---|
370 | ''',
|
---|
371 | re.VERBOSE | re.IGNORECASE
|
---|
372 | )
|
---|
373 |
|
---|
374 | defineDataRe = re.compile(r'''
|
---|
375 | ([\w@][\w@0-9]*) \s+
|
---|
376 | ( db | dw | dd | dq ) \s+
|
---|
377 | ( .*? )
|
---|
378 | \s* $
|
---|
379 | ''',
|
---|
380 | re.VERBOSE | re.IGNORECASE
|
---|
381 | )
|
---|
382 |
|
---|
383 | equRe = re.compile(r'''
|
---|
384 | ([\w@][\w@0-9]*) \s+ EQU \s+ (\S.*?)
|
---|
385 | \s* $
|
---|
386 | ''',
|
---|
387 | re.VERBOSE | re.IGNORECASE
|
---|
388 | )
|
---|
389 |
|
---|
390 | ignoreRe = re.compile(r'''
|
---|
391 | \. (?: const |
|
---|
392 | mmx |
|
---|
393 | model |
|
---|
394 | xmm |
|
---|
395 | x?list |
|
---|
396 | [3-6]86p?
|
---|
397 | ) |
|
---|
398 | page
|
---|
399 | (?: \s+ .* )?
|
---|
400 | \s* $
|
---|
401 | ''',
|
---|
402 | re.VERBOSE | re.IGNORECASE
|
---|
403 | )
|
---|
404 |
|
---|
405 | whitespaceRe = re.compile(r'\s+', re.MULTILINE)
|
---|
406 |
|
---|
407 | def TranslateAsm(self, oldAsm, endOfLine):
|
---|
408 | assert(oldAsm.strip() == oldAsm)
|
---|
409 |
|
---|
410 | endOfLine = endOfLine.replace(self.inputFileBase, self.outputFileBase)
|
---|
411 |
|
---|
412 | oldOp = oldAsm.split()
|
---|
413 | if len(oldOp) >= 1:
|
---|
414 | oldOp = oldOp[0]
|
---|
415 | else:
|
---|
416 | oldOp = ''
|
---|
417 |
|
---|
418 | if oldAsm == '':
|
---|
419 | newAsm = oldAsm
|
---|
420 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
421 | elif oldOp in ('#include', ):
|
---|
422 | newAsm = oldAsm
|
---|
423 | self.EmitLine(oldAsm + endOfLine)
|
---|
424 | elif oldOp.lower() in ('end', 'title', 'text'):
|
---|
425 | newAsm = ''
|
---|
426 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
427 | elif oldAsm.lower() == '@@:':
|
---|
428 | self.anonLabelCount += 1
|
---|
429 | self.EmitLine(self.anonLabel(self.anonLabelCount) + ':')
|
---|
430 | elif self.MatchAndSetMo(self.ignoreRe, oldAsm):
|
---|
431 | newAsm = ''
|
---|
432 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
433 | elif oldAsm.lower() == 'ret':
|
---|
434 | for i in range(len(self.uses) - 1, -1, -1):
|
---|
435 | register = self.uses[i]
|
---|
436 | self.EmitNewContent('pop ' + register)
|
---|
437 | newAsm = 'ret'
|
---|
438 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
439 | self.uses = tuple()
|
---|
440 | elif oldOp.lower() == 'lea':
|
---|
441 | newAsm = self.ConvertLea(oldAsm)
|
---|
442 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
443 | elif oldAsm.lower() == 'end':
|
---|
444 | newAsm = ''
|
---|
445 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
446 | self.uses = tuple()
|
---|
447 | elif self.MatchAndSetMo(self.equRe, oldAsm):
|
---|
448 | equ = self.mo.group(1)
|
---|
449 | newAsm = '%%define %s %s' % (equ, self.mo.group(2))
|
---|
450 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
451 | elif self.MatchAndSetMo(self.externRe, oldAsm) or \
|
---|
452 | self.MatchAndSetMo(self.protoRe, oldAsm):
|
---|
453 | extern = self.mo.group(1)
|
---|
454 | self.NewGlobal(extern)
|
---|
455 | newAsm = 'extern ' + extern
|
---|
456 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
457 | elif self.MatchAndSetMo(self.externdefRe, oldAsm):
|
---|
458 | newAsm = ''
|
---|
459 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
460 | elif self.MatchAndSetMo(self.macroDeclRe, oldAsm):
|
---|
461 | newAsm = '%%macro %s 0' % self.mo.group(1)
|
---|
462 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
463 | elif oldOp.lower() == 'endm':
|
---|
464 | newAsm = r'%endmacro'
|
---|
465 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
466 | elif self.MatchAndSetMo(self.sectionDeclRe, oldAsm):
|
---|
467 | name = self.mo.group(1)
|
---|
468 | ty = self.mo.group(2)
|
---|
469 | if ty.lower() == 'section':
|
---|
470 | newAsm = '.' + name
|
---|
471 | else:
|
---|
472 | newAsm = ''
|
---|
473 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
474 | elif self.MatchAndSetMo(self.procDeclRe, oldAsm):
|
---|
475 | proc = self.proc = self.mo.group(1)
|
---|
476 | visibility = self.mo.group(2)
|
---|
477 | if visibility is None:
|
---|
478 | visibility = ''
|
---|
479 | else:
|
---|
480 | visibility = visibility.lower()
|
---|
481 | if visibility != 'private':
|
---|
482 | self.NewGlobal(self.proc)
|
---|
483 | proc = 'ASM_PFX(' + proc + ')'
|
---|
484 | self.EmitNewContent('global ' + proc)
|
---|
485 | newAsm = proc + ':'
|
---|
486 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
487 | uses = self.mo.group(3)
|
---|
488 | if uses is not None:
|
---|
489 | uses = tuple(filter(None, uses.split()))
|
---|
490 | else:
|
---|
491 | uses = tuple()
|
---|
492 | self.uses = uses
|
---|
493 | for register in self.uses:
|
---|
494 | self.EmitNewContent(' push ' + register)
|
---|
495 | elif self.MatchAndSetMo(self.procEndRe, oldAsm):
|
---|
496 | newAsm = ''
|
---|
497 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
498 | elif self.MatchAndSetMo(self.publicRe, oldAsm):
|
---|
499 | publics = re.findall(self.varAndTypeSubRe, self.mo.group(1))
|
---|
500 | publics = tuple(map(lambda p: p.split(':')[0].strip(), publics))
|
---|
501 | for i in range(len(publics) - 1):
|
---|
502 | name = publics[i]
|
---|
503 | self.EmitNewContent('global ASM_PFX(%s)' % publics[i])
|
---|
504 | self.NewGlobal(name)
|
---|
505 | name = publics[-1]
|
---|
506 | self.NewGlobal(name)
|
---|
507 | newAsm = 'global ASM_PFX(%s)' % name
|
---|
508 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
509 | elif self.MatchAndSetMo(self.defineDataRe, oldAsm):
|
---|
510 | name = self.mo.group(1)
|
---|
511 | ty = self.mo.group(2)
|
---|
512 | value = self.mo.group(3)
|
---|
513 | if value == '?':
|
---|
514 | value = 0
|
---|
515 | newAsm = '%s: %s %s' % (name, ty, value)
|
---|
516 | newAsm = self.CommonConversions(newAsm)
|
---|
517 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
518 | else:
|
---|
519 | newAsm = self.CommonConversions(oldAsm)
|
---|
520 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
521 |
|
---|
522 | def NewGlobal(self, name):
|
---|
523 | regex = re.compile(r'(?<![_\w\d])(?<!ASM_PFX\()(' + re.escape(name) +
|
---|
524 | r')(?![_\w\d])')
|
---|
525 | self.globals.add(regex)
|
---|
526 |
|
---|
527 | def ConvertAnonymousLabels(self, oldAsm):
|
---|
528 | newAsm = oldAsm
|
---|
529 | anonLabel = self.anonLabel(self.anonLabelCount)
|
---|
530 | newAsm = newAsm.replace('@b', anonLabel)
|
---|
531 | newAsm = newAsm.replace('@B', anonLabel)
|
---|
532 | anonLabel = self.anonLabel(self.anonLabelCount + 1)
|
---|
533 | newAsm = newAsm.replace('@f', anonLabel)
|
---|
534 | newAsm = newAsm.replace('@F', anonLabel)
|
---|
535 | return newAsm
|
---|
536 |
|
---|
537 | def anonLabel(self, count):
|
---|
538 | return '.%d' % count
|
---|
539 |
|
---|
540 | def EmitString(self, string):
|
---|
541 | self.output.write(string.encode('utf-8', 'ignore'))
|
---|
542 |
|
---|
543 | def EmitLineWithDiff(self, old, new):
|
---|
544 | newLine = (self.indent + new).rstrip()
|
---|
545 | if self.diff:
|
---|
546 | if old is None:
|
---|
547 | print('+%s' % newLine)
|
---|
548 | elif newLine != old:
|
---|
549 | print('-%s' % old)
|
---|
550 | print('+%s' % newLine)
|
---|
551 | else:
|
---|
552 | print('', newLine)
|
---|
553 | if newLine != '':
|
---|
554 | self.newAsmEmptyLineCount = 0
|
---|
555 | self.EmitString(newLine + '\r\n')
|
---|
556 |
|
---|
557 | def EmitLine(self, string):
|
---|
558 | self.EmitLineWithDiff(self.originalLine, string)
|
---|
559 |
|
---|
560 | def EmitNewContent(self, string):
|
---|
561 | self.EmitLineWithDiff(None, string)
|
---|
562 |
|
---|
563 | def EmitAsmReplaceOp(self, oldAsm, oldOp, newOp, endOfLine):
|
---|
564 | newAsm = oldAsm.replace(oldOp, newOp, 1)
|
---|
565 | self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)
|
---|
566 |
|
---|
567 | hexNumRe = re.compile(r'0*((?=[\da-f])\d*(?<=\d)[\da-f]*)h', re.IGNORECASE)
|
---|
568 |
|
---|
569 | def EmitAsmWithComment(self, oldAsm, newAsm, endOfLine):
|
---|
570 | for glblRe in self.globals:
|
---|
571 | newAsm = glblRe.sub(r'ASM_PFX(\1)', newAsm)
|
---|
572 |
|
---|
573 | newAsm = self.hexNumRe.sub(r'0x\1', newAsm)
|
---|
574 |
|
---|
575 | newLine = newAsm + endOfLine
|
---|
576 | emitNewLine = ((newLine.strip() != '') or
|
---|
577 | ((oldAsm + endOfLine).strip() == ''))
|
---|
578 | if emitNewLine and newLine.strip() == '':
|
---|
579 | self.newAsmEmptyLineCount += 1
|
---|
580 | if self.newAsmEmptyLineCount > 1:
|
---|
581 | emitNewLine = False
|
---|
582 | if emitNewLine:
|
---|
583 | self.EmitLine(newLine.rstrip())
|
---|
584 | elif self.diff:
|
---|
585 | print('-%s' % self.originalLine)
|
---|
586 |
|
---|
587 | leaRe = re.compile(r'''
|
---|
588 | (lea \s+) ([\w@][\w@0-9]*) \s* , \s* (\S (?:.*\S)?)
|
---|
589 | \s* $
|
---|
590 | ''',
|
---|
591 | re.VERBOSE | re.IGNORECASE
|
---|
592 | )
|
---|
593 |
|
---|
594 | def ConvertLea(self, oldAsm):
|
---|
595 | newAsm = oldAsm
|
---|
596 | if self.MatchAndSetMo(self.leaRe, oldAsm):
|
---|
597 | lea = self.mo.group(1)
|
---|
598 | dst = self.mo.group(2)
|
---|
599 | src = self.mo.group(3)
|
---|
600 | if src.find('[') < 0:
|
---|
601 | src = '[' + src + ']'
|
---|
602 | newAsm = lea + dst + ', ' + src
|
---|
603 | newAsm = self.CommonConversions(newAsm)
|
---|
604 | return newAsm
|
---|
605 |
|
---|
606 | ptrRe = re.compile(r'''
|
---|
607 | (?<! \S )
|
---|
608 | ([dfq]?word|byte) \s+ (?: ptr ) (\s*)
|
---|
609 | (?= [[\s] )
|
---|
610 | ''',
|
---|
611 | re.VERBOSE | re.IGNORECASE
|
---|
612 | )
|
---|
613 |
|
---|
614 | def ConvertPtr(self, oldAsm):
|
---|
615 | newAsm = oldAsm
|
---|
616 | while self.SearchAndSetMo(self.ptrRe, newAsm):
|
---|
617 | ty = self.mo.group(1)
|
---|
618 | if ty.lower() == 'fword':
|
---|
619 | ty = ''
|
---|
620 | else:
|
---|
621 | ty += self.mo.group(2)
|
---|
622 | newAsm = newAsm[:self.mo.start(0)] + ty + newAsm[self.mo.end(0):]
|
---|
623 | return newAsm
|
---|
624 |
|
---|
625 | labelByteRe = re.compile(r'''
|
---|
626 | (?: \s+ label \s+ (?: [dfq]?word | byte ) )
|
---|
627 | (?! \S )
|
---|
628 | ''',
|
---|
629 | re.VERBOSE | re.IGNORECASE
|
---|
630 | )
|
---|
631 |
|
---|
632 | def ConvertLabelByte(self, oldAsm):
|
---|
633 | newAsm = oldAsm
|
---|
634 | if self.SearchAndSetMo(self.labelByteRe, newAsm):
|
---|
635 | newAsm = newAsm[:self.mo.start(0)] + ':' + newAsm[self.mo.end(0):]
|
---|
636 | return newAsm
|
---|
637 |
|
---|
638 | unaryBitwiseOpRe = re.compile(r'''
|
---|
639 | ( NOT )
|
---|
640 | (?= \s+ \S )
|
---|
641 | ''',
|
---|
642 | re.VERBOSE | re.IGNORECASE
|
---|
643 | )
|
---|
644 | binaryBitwiseOpRe = re.compile(r'''
|
---|
645 | ( \S \s+ )
|
---|
646 | ( AND | OR | SHL | SHR )
|
---|
647 | (?= \s+ \S )
|
---|
648 | ''',
|
---|
649 | re.VERBOSE | re.IGNORECASE
|
---|
650 | )
|
---|
651 | bitwiseOpReplacements = {
|
---|
652 | 'not': '~',
|
---|
653 | 'and': '&',
|
---|
654 | 'shl': '<<',
|
---|
655 | 'shr': '>>',
|
---|
656 | 'or': '|',
|
---|
657 | }
|
---|
658 |
|
---|
659 | def ConvertBitwiseOp(self, oldAsm):
|
---|
660 | newAsm = oldAsm
|
---|
661 | while self.SearchAndSetMo(self.binaryBitwiseOpRe, newAsm):
|
---|
662 | prefix = self.mo.group(1)
|
---|
663 | op = self.bitwiseOpReplacements[self.mo.group(2).lower()]
|
---|
664 | newAsm = newAsm[:self.mo.start(0)] + prefix + op + \
|
---|
665 | newAsm[self.mo.end(0):]
|
---|
666 | while self.SearchAndSetMo(self.unaryBitwiseOpRe, newAsm):
|
---|
667 | op = self.bitwiseOpReplacements[self.mo.group(1).lower()]
|
---|
668 | newAsm = newAsm[:self.mo.start(0)] + op + newAsm[self.mo.end(0):]
|
---|
669 | return newAsm
|
---|
670 |
|
---|
671 | sectionRe = re.compile(r'''
|
---|
672 | \. ( code |
|
---|
673 | data
|
---|
674 | )
|
---|
675 | (?: \s+ .* )?
|
---|
676 | \s* $
|
---|
677 | ''',
|
---|
678 | re.VERBOSE | re.IGNORECASE
|
---|
679 | )
|
---|
680 |
|
---|
681 | segmentRe = re.compile(r'''
|
---|
682 | ( code |
|
---|
683 | data )
|
---|
684 | (?: \s+ SEGMENT )
|
---|
685 | (?: \s+ .* )?
|
---|
686 | \s* $
|
---|
687 | ''',
|
---|
688 | re.VERBOSE | re.IGNORECASE
|
---|
689 | )
|
---|
690 |
|
---|
691 | def ConvertSection(self, oldAsm):
|
---|
692 | newAsm = oldAsm
|
---|
693 | if self.MatchAndSetMo(self.sectionRe, newAsm) or \
|
---|
694 | self.MatchAndSetMo(self.segmentRe, newAsm):
|
---|
695 | name = self.mo.group(1).lower()
|
---|
696 | if name == 'code':
|
---|
697 | if self.x64:
|
---|
698 | self.EmitLine('DEFAULT REL')
|
---|
699 | name = 'text'
|
---|
700 | newAsm = 'SECTION .' + name
|
---|
701 | return newAsm
|
---|
702 |
|
---|
703 | fwordRe = re.compile(r'''
|
---|
704 | (?<! \S )
|
---|
705 | fword
|
---|
706 | (?! \S )
|
---|
707 | ''',
|
---|
708 | re.VERBOSE | re.IGNORECASE
|
---|
709 | )
|
---|
710 |
|
---|
711 | def FwordUnsupportedCheck(self, oldAsm):
|
---|
712 | newAsm = oldAsm
|
---|
713 | if self.SearchAndSetMo(self.fwordRe, newAsm):
|
---|
714 | newAsm = self.Unsupported(newAsm, 'fword used')
|
---|
715 | return newAsm
|
---|
716 |
|
---|
717 | __common_conversion_routines__ = (
|
---|
718 | ConvertAnonymousLabels,
|
---|
719 | ConvertPtr,
|
---|
720 | FwordUnsupportedCheck,
|
---|
721 | ConvertBitwiseOp,
|
---|
722 | ConvertLabelByte,
|
---|
723 | ConvertSection,
|
---|
724 | )
|
---|
725 |
|
---|
726 | def CommonConversions(self, oldAsm):
|
---|
727 | newAsm = oldAsm
|
---|
728 | for conv in self.__common_conversion_routines__:
|
---|
729 | newAsm = conv(self, newAsm)
|
---|
730 | return newAsm
|
---|
731 |
|
---|
732 | def Unsupported(self, asm, message=None):
|
---|
733 | if not self.force:
|
---|
734 | raise UnsupportedConversion
|
---|
735 |
|
---|
736 | self.unsupportedSyntaxSeen = True
|
---|
737 | newAsm = '%error conversion unsupported'
|
---|
738 | if message:
|
---|
739 | newAsm += '; ' + message
|
---|
740 | newAsm += ': ' + asm
|
---|
741 | return newAsm
|
---|
742 |
|
---|
743 |
|
---|
744 | class ConvertInfFile(CommonUtils):
|
---|
745 |
|
---|
746 | def __init__(self, inf, clone):
|
---|
747 | CommonUtils.__init__(self, clone)
|
---|
748 | self.inf = inf
|
---|
749 | self.ScanInfAsmFiles()
|
---|
750 | if self.infmode:
|
---|
751 | self.ConvertInfAsmFiles()
|
---|
752 |
|
---|
753 | infSrcRe = re.compile(r'''
|
---|
754 | \s*
|
---|
755 | ( [\w@][\w@0-9/]* \.(asm|s) )
|
---|
756 | \s* (?: \| [^#]* )?
|
---|
757 | \s* (?: \# .* )?
|
---|
758 | $
|
---|
759 | ''',
|
---|
760 | re.VERBOSE | re.IGNORECASE
|
---|
761 | )
|
---|
762 |
|
---|
763 | def GetInfAsmFileMapping(self):
|
---|
764 | srcToDst = {'order': []}
|
---|
765 | for line in self.lines:
|
---|
766 | line = line.rstrip()
|
---|
767 | if self.MatchAndSetMo(self.infSrcRe, line):
|
---|
768 | src = self.mo.group(1)
|
---|
769 | srcExt = self.mo.group(2)
|
---|
770 | dst = os.path.splitext(src)[0] + '.nasm'
|
---|
771 | fullDst = os.path.join(self.dir, dst)
|
---|
772 | if src not in srcToDst and not os.path.exists(fullDst):
|
---|
773 | srcToDst[src] = dst
|
---|
774 | srcToDst['order'].append(src)
|
---|
775 | return srcToDst
|
---|
776 |
|
---|
777 | def ScanInfAsmFiles(self):
|
---|
778 | src = self.inf
|
---|
779 | assert os.path.isfile(src)
|
---|
780 | f = io.open(src, 'rt')
|
---|
781 | self.lines = f.readlines()
|
---|
782 | f.close()
|
---|
783 |
|
---|
784 | path = os.path.realpath(self.inf)
|
---|
785 | (self.dir, inf) = os.path.split(path)
|
---|
786 | parent = os.path.normpath(self.dir)
|
---|
787 | (lastpath, self.moduleName) = os.path.split(parent)
|
---|
788 | self.packageName = None
|
---|
789 | while True:
|
---|
790 | lastpath = os.path.normpath(lastpath)
|
---|
791 | (parent, basename) = os.path.split(lastpath)
|
---|
792 | if parent == lastpath:
|
---|
793 | break
|
---|
794 | if basename.endswith('Pkg'):
|
---|
795 | self.packageName = basename
|
---|
796 | break
|
---|
797 | lastpath = parent
|
---|
798 |
|
---|
799 | self.srcToDst = self.GetInfAsmFileMapping()
|
---|
800 |
|
---|
801 | self.dstToSrc = {'order': []}
|
---|
802 | for src in self.srcToDst['order']:
|
---|
803 | srcExt = os.path.splitext(src)[1]
|
---|
804 | dst = self.srcToDst[src]
|
---|
805 | if dst not in self.dstToSrc:
|
---|
806 | self.dstToSrc[dst] = [src]
|
---|
807 | self.dstToSrc['order'].append(dst)
|
---|
808 | else:
|
---|
809 | self.dstToSrc[dst].append(src)
|
---|
810 |
|
---|
811 | def __len__(self):
|
---|
812 | return len(self.dstToSrc['order'])
|
---|
813 |
|
---|
814 | def __iter__(self):
|
---|
815 | return iter(self.dstToSrc['order'])
|
---|
816 |
|
---|
817 | def ConvertInfAsmFiles(self):
|
---|
818 | notConverted = []
|
---|
819 | unsupportedArchCount = 0
|
---|
820 | for dst in self:
|
---|
821 | didSomething = False
|
---|
822 | try:
|
---|
823 | self.UpdateInfAsmFile(dst)
|
---|
824 | didSomething = True
|
---|
825 | except UnsupportedConversion:
|
---|
826 | if not self.args.quiet:
|
---|
827 | print('MASM=>NASM conversion unsupported for', dst)
|
---|
828 | notConverted.append(dst)
|
---|
829 | except NoSourceFile:
|
---|
830 | if not self.args.quiet:
|
---|
831 | print('Source file missing for', reldst)
|
---|
832 | notConverted.append(dst)
|
---|
833 | except UnsupportedArch:
|
---|
834 | unsupportedArchCount += 1
|
---|
835 | else:
|
---|
836 | if didSomething:
|
---|
837 | self.ConversionFinished(dst)
|
---|
838 | if len(notConverted) > 0 and not self.args.quiet:
|
---|
839 | for dst in notConverted:
|
---|
840 | reldst = self.RootRelative(dst)
|
---|
841 | print('Unabled to convert', reldst)
|
---|
842 | if unsupportedArchCount > 0 and not self.args.quiet:
|
---|
843 | print('Skipped', unsupportedArchCount, 'files based on architecture')
|
---|
844 |
|
---|
845 | def UpdateInfAsmFile(self, dst, IgnoreMissingAsm=False):
|
---|
846 | infPath = os.path.split(os.path.realpath(self.inf))[0]
|
---|
847 | asmSrc = os.path.splitext(dst)[0] + '.asm'
|
---|
848 | fullSrc = os.path.join(infPath, asmSrc)
|
---|
849 | fullDst = os.path.join(infPath, dst)
|
---|
850 | srcParentDir = os.path.basename(os.path.split(fullSrc)[0])
|
---|
851 | if srcParentDir.lower() in UnsupportedArch.unsupported:
|
---|
852 | raise UnsupportedArch
|
---|
853 | elif not os.path.exists(fullSrc):
|
---|
854 | if not IgnoreMissingAsm:
|
---|
855 | raise NoSourceFile
|
---|
856 | else: # not os.path.exists(fullDst):
|
---|
857 | conv = ConvertAsmFile(fullSrc, fullDst, self)
|
---|
858 | self.unsupportedSyntaxSeen = conv.unsupportedSyntaxSeen
|
---|
859 |
|
---|
860 | fileChanged = False
|
---|
861 | recentSources = list()
|
---|
862 | i = 0
|
---|
863 | while i < len(self.lines):
|
---|
864 | line = self.lines[i].rstrip()
|
---|
865 | updatedLine = line
|
---|
866 | lineChanged = False
|
---|
867 | preserveOldSource = False
|
---|
868 | for src in self.dstToSrc[dst]:
|
---|
869 | assert self.srcToDst[src] == dst
|
---|
870 | updatedLine = self.ReplacePreserveSpacing(
|
---|
871 | updatedLine, src, dst)
|
---|
872 | lineChanged = updatedLine != line
|
---|
873 | if lineChanged:
|
---|
874 | preserveOldSource = self.ShouldKeepFile(src)
|
---|
875 | break
|
---|
876 |
|
---|
877 | if lineChanged:
|
---|
878 | if preserveOldSource:
|
---|
879 | if updatedLine.strip() not in recentSources:
|
---|
880 | self.lines.insert(i, updatedLine + '\n')
|
---|
881 | recentSources.append(updatedLine.strip())
|
---|
882 | i += 1
|
---|
883 | if self.diff:
|
---|
884 | print('+%s' % updatedLine)
|
---|
885 | if self.diff:
|
---|
886 | print('', line)
|
---|
887 | else:
|
---|
888 | if self.diff:
|
---|
889 | print('-%s' % line)
|
---|
890 | if updatedLine.strip() in recentSources:
|
---|
891 | self.lines[i] = None
|
---|
892 | else:
|
---|
893 | self.lines[i] = updatedLine + '\n'
|
---|
894 | recentSources.append(updatedLine.strip())
|
---|
895 | if self.diff:
|
---|
896 | print('+%s' % updatedLine)
|
---|
897 | else:
|
---|
898 | if len(recentSources) > 0:
|
---|
899 | recentSources = list()
|
---|
900 | if self.diff:
|
---|
901 | print('', line)
|
---|
902 |
|
---|
903 | fileChanged |= lineChanged
|
---|
904 | i += 1
|
---|
905 |
|
---|
906 | if fileChanged:
|
---|
907 | self.lines = list(filter(lambda l: l is not None, self.lines))
|
---|
908 |
|
---|
909 | for src in self.dstToSrc[dst]:
|
---|
910 | if not src.endswith('.asm'):
|
---|
911 | fullSrc = os.path.join(infPath, src)
|
---|
912 | if os.path.exists(fullSrc):
|
---|
913 | self.RemoveFile(fullSrc)
|
---|
914 |
|
---|
915 | if fileChanged:
|
---|
916 | f = io.open(self.inf, 'w', newline='\r\n')
|
---|
917 | f.writelines(self.lines)
|
---|
918 | f.close()
|
---|
919 | self.FileUpdated(self.inf)
|
---|
920 |
|
---|
921 | def ConversionFinished(self, dst):
|
---|
922 | asmSrc = os.path.splitext(dst)[0] + '.asm'
|
---|
923 | self.FileConversionFinished(
|
---|
924 | self.packageName, self.moduleName, asmSrc, dst)
|
---|
925 |
|
---|
926 |
|
---|
927 | class ConvertInfFiles(CommonUtils):
|
---|
928 |
|
---|
929 | def __init__(self, infs, clone):
|
---|
930 | CommonUtils.__init__(self, clone)
|
---|
931 | infs = map(lambda i: ConvertInfFile(i, self), infs)
|
---|
932 | infs = filter(lambda i: len(i) > 0, infs)
|
---|
933 | dstToInfs = {'order': []}
|
---|
934 | for inf in infs:
|
---|
935 | for dst in inf:
|
---|
936 | fulldst = os.path.realpath(os.path.join(inf.dir, dst))
|
---|
937 | pair = (inf, dst)
|
---|
938 | if fulldst in dstToInfs:
|
---|
939 | dstToInfs[fulldst].append(pair)
|
---|
940 | else:
|
---|
941 | dstToInfs['order'].append(fulldst)
|
---|
942 | dstToInfs[fulldst] = [pair]
|
---|
943 |
|
---|
944 | notConverted = []
|
---|
945 | unsupportedArchCount = 0
|
---|
946 | for dst in dstToInfs['order']:
|
---|
947 | didSomething = False
|
---|
948 | try:
|
---|
949 | for inf, reldst in dstToInfs[dst]:
|
---|
950 | inf.UpdateInfAsmFile(reldst, IgnoreMissingAsm=didSomething)
|
---|
951 | didSomething = True
|
---|
952 | except UnsupportedConversion:
|
---|
953 | if not self.args.quiet:
|
---|
954 | print('MASM=>NASM conversion unsupported for', reldst)
|
---|
955 | notConverted.append(dst)
|
---|
956 | except NoSourceFile:
|
---|
957 | if not self.args.quiet:
|
---|
958 | print('Source file missing for', reldst)
|
---|
959 | notConverted.append(dst)
|
---|
960 | except UnsupportedArch:
|
---|
961 | unsupportedArchCount += 1
|
---|
962 | else:
|
---|
963 | if didSomething:
|
---|
964 | inf.ConversionFinished(reldst)
|
---|
965 | if len(notConverted) > 0 and not self.args.quiet:
|
---|
966 | for dst in notConverted:
|
---|
967 | reldst = self.RootRelative(dst)
|
---|
968 | print('Unabled to convert', reldst)
|
---|
969 | if unsupportedArchCount > 0 and not self.args.quiet:
|
---|
970 | print('Skipped', unsupportedArchCount, 'files based on architecture')
|
---|
971 |
|
---|
972 |
|
---|
973 | class ConvertDirectories(CommonUtils):
|
---|
974 |
|
---|
975 | def __init__(self, paths, clone):
|
---|
976 | CommonUtils.__init__(self, clone)
|
---|
977 | self.paths = paths
|
---|
978 | self.ConvertInfAndAsmFiles()
|
---|
979 |
|
---|
980 | def ConvertInfAndAsmFiles(self):
|
---|
981 | infs = list()
|
---|
982 | for path in self.paths:
|
---|
983 | assert(os.path.exists(path))
|
---|
984 | for path in self.paths:
|
---|
985 | for root, dirs, files in os.walk(path):
|
---|
986 | for d in ('.svn', '.git'):
|
---|
987 | if d in dirs:
|
---|
988 | dirs.remove(d)
|
---|
989 | for f in files:
|
---|
990 | if f.lower().endswith('.inf'):
|
---|
991 | inf = os.path.realpath(os.path.join(root, f))
|
---|
992 | infs.append(inf)
|
---|
993 |
|
---|
994 | ConvertInfFiles(infs, self)
|
---|
995 |
|
---|
996 |
|
---|
997 | class ConvertAsmApp(CommonUtils):
|
---|
998 |
|
---|
999 | def __init__(self):
|
---|
1000 | CommonUtils.__init__(self)
|
---|
1001 |
|
---|
1002 | src = self.args.source
|
---|
1003 | dst = self.args.dest
|
---|
1004 | if self.infmode:
|
---|
1005 | ConvertInfFiles((src,), self)
|
---|
1006 | elif self.dirmode:
|
---|
1007 | ConvertDirectories((src,), self)
|
---|
1008 | elif not self.dirmode:
|
---|
1009 | ConvertAsmFile(src, dst, self)
|
---|
1010 |
|
---|
1011 | ConvertAsmApp()
|
---|