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