1 # @file ConvertMasmToNasm.py
2 # This script assists with conversion of MASM assembly syntax to NASM
4 # Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
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
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.
23 from optparse
import OptionParser
26 class UnsupportedConversion(Exception):
30 class NoSourceFile(Exception):
34 class UnsupportedArch(Exception):
35 unsupported
= ('aarch64', 'arm', 'ebc', 'ipf')
40 # Version and Copyright
41 VersionNumber
= "0.01"
42 __version__
= "%prog Version " + VersionNumber
43 __copyright__
= "Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved."
44 __usage__
= "%prog [options] source.asm [destination.nasm]"
46 def __init__(self
, clone
=None):
48 (self
.Opt
, self
.Args
) = self
.ProcessCommandLine()
50 (self
.Opt
, self
.Args
) = (clone
.Opt
, clone
.Args
)
52 self
.unsupportedSyntaxSeen
= False
53 self
.src
= self
.Args
[0]
54 assert(os
.path
.exists(self
.src
))
55 self
.dirmode
= os
.path
.isdir(self
.src
)
56 srcExt
= os
.path
.splitext(self
.src
)[1]
57 assert (self
.dirmode
or srcExt
!= '.nasm')
58 self
.infmode
= not self
.dirmode
and srcExt
== '.inf'
59 self
.diff
= self
.Opt
.diff
60 self
.git
= self
.Opt
.git
61 self
.force
= self
.Opt
.force
64 self
.rootdir
= os
.getcwd()
67 self
.rootdir
= clone
.rootdir
68 self
.gitdir
= clone
.gitdir
69 self
.gitemail
= clone
.gitemail
71 def ProcessCommandLine(self
):
72 Parser
= OptionParser(description
=self
.__copyright
__,
73 version
=self
.__version
__,
77 Parser
.add_option("-q", "--quiet", action
="store_true", type=None,
78 help="Disable all messages except FATAL ERRORS.")
79 Parser
.add_option("--git", action
="store_true", type=None,
80 help="Use git to create commits for each file converted")
81 Parser
.add_option("--diff", action
="store_true", type=None,
82 help="Show diff of conversion")
83 Parser
.add_option("-f", "--force", action
="store_true", type=None,
84 help="Force conversion even if unsupported")
86 (Opt
, Args
) = Parser
.parse_args()
89 print self
.__copyright
__
90 Parser
.print_version()
94 def RootRelative(self
, path
):
96 if result
.startswith(self
.rootdir
):
97 result
= result
[len(self
.rootdir
):]
98 while len(result
) > 0 and result
[0] in '/\\':
102 def MatchAndSetMo(self
, regexp
, string
):
103 self
.mo
= regexp
.match(string
)
104 return self
.mo
is not None
106 def SearchAndSetMo(self
, regexp
, string
):
107 self
.mo
= regexp
.search(string
)
108 return self
.mo
is not None
110 def ReplacePreserveSpacing(self
, string
, find
, replace
):
111 if len(find
) >= len(replace
):
112 padded
= replace
+ (' ' * (len(find
) - len(replace
)))
113 return string
.replace(find
, padded
)
114 elif find
.find(replace
) >= 0:
115 return string
.replace(find
, replace
)
117 lenDiff
= len(replace
) - len(find
)
119 for i
in range(lenDiff
, -1, -1):
120 padded
= find
+ (' ' * i
)
121 result
= result
.replace(padded
, replace
)
125 lastpath
= os
.path
.realpath(self
.src
)
128 path
= os
.path
.split(lastpath
)[0]
131 candidate
= os
.path
.join(path
, '.git')
132 if os
.path
.isdir(candidate
):
133 self
.gitdir
= candidate
134 self
.gitemail
= self
.FormatGitEmailAddress()
138 def FormatGitEmailAddress(self
):
139 if not self
.git
or not self
.gitdir
:
142 cmd
= ('git', 'config', 'user.name')
143 name
= self
.RunAndCaptureOutput(cmd
).strip()
144 cmd
= ('git', 'config', 'user.email')
145 email
= self
.RunAndCaptureOutput(cmd
).strip()
146 if name
.find(',') >= 0:
147 name
= '"' + name
+ '"'
148 return name
+ ' <' + email
+ '>'
150 def RunAndCaptureOutput(self
, cmd
, checkExitCode
=True, pipeIn
=None):
152 subpStdin
= subprocess
.PIPE
155 p
= subprocess
.Popen(args
=cmd
, stdout
=subprocess
.PIPE
, stdin
=subpStdin
)
156 (stdout
, stderr
) = p
.communicate(pipeIn
)
158 if p
.returncode
!= 0:
159 print 'command:', ' '.join(cmd
)
160 print 'stdout:', stdout
161 print 'stderr:', stderr
162 print 'return:', p
.returncode
163 assert p
.returncode
== 0
166 def FileUpdated(self
, path
):
167 if not self
.git
or not self
.gitdir
:
170 cmd
= ('git', 'add', path
)
171 self
.RunAndCaptureOutput(cmd
)
173 def FileAdded(self
, path
):
174 self
.FileUpdated(path
)
176 def RemoveFile(self
, path
):
177 if not self
.git
or not self
.gitdir
:
180 cmd
= ('git', 'rm', path
)
181 self
.RunAndCaptureOutput(cmd
)
183 def FileConversionFinished(self
, pkg
, module
, src
, dst
):
184 if not self
.git
or not self
.gitdir
:
187 if not self
.Opt
.quiet
:
188 print 'Committing: Conversion of', dst
190 prefix
= ' '.join(filter(lambda a
: a
, [pkg
, module
]))
192 if self
.unsupportedSyntaxSeen
:
194 message
+= '%s: Convert %s to NASM\n' % (prefix
, src
)
196 message
+= 'The %s script was used to convert\n' % sys
.argv
[0]
197 message
+= '%s to %s\n' % (src
, dst
)
199 message
+= 'Contributed-under: TianoCore Contribution Agreement 1.0\n'
200 message
+= 'Signed-off-by: %s\n' % self
.gitemail
202 cmd
= ('git', 'commit', '-F', '-')
203 self
.RunAndCaptureOutput(cmd
, pipeIn
=message
)
206 class ConvertAsmFile(CommonUtils
):
208 def __init__(self
, src
, dst
, clone
):
209 CommonUtils
.__init
__(self
, clone
)
210 self
.ConvertAsmFile(src
, dst
)
214 def ConvertAsmFile(self
, inputFile
, outputFile
=None):
216 self
.unsupportedSyntaxSeen
= False
217 self
.inputFilename
= inputFile
219 outputFile
= os
.path
.splitext(inputFile
)[0] + '.nasm'
220 self
.outputFilename
= outputFile
222 fullSrc
= os
.path
.realpath(inputFile
)
223 srcParentDir
= os
.path
.basename(os
.path
.split(fullSrc
)[0])
224 maybeArch
= srcParentDir
.lower()
225 if maybeArch
in UnsupportedArch
.unsupported
:
226 raise UnsupportedArch
227 self
.ia32
= maybeArch
== 'ia32'
228 self
.x64
= maybeArch
== 'x64'
230 self
.inputFileBase
= os
.path
.basename(self
.inputFilename
)
231 self
.outputFileBase
= os
.path
.basename(self
.outputFilename
)
232 if self
.outputFilename
== '-' and not self
.diff
:
233 self
.output
= sys
.stdout
235 self
.output
= StringIO
.StringIO()
236 if not self
.Opt
.quiet
:
237 dirpath
, src
= os
.path
.split(self
.inputFilename
)
238 dirpath
= self
.RootRelative(dirpath
)
239 dst
= os
.path
.basename(self
.outputFilename
)
240 print 'Converting:', dirpath
, src
, '->', dst
241 lines
= open(self
.inputFilename
).readlines()
243 if self
.outputFilename
== '-':
245 sys
.stdout
.write(self
.output
.getvalue())
248 f
= open(self
.outputFilename
, 'wb')
249 f
.write(self
.output
.getvalue())
253 endOfLineRe
= re
.compile(r
'''
256 re
.VERBOSE | re
.MULTILINE
258 begOfLineRe
= re
.compile(r
'''
264 def Convert(self
, lines
):
266 self
.anonLabelCount
= -1
268 self
.oldAsmEmptyLineCount
= 0
269 self
.newAsmEmptyLineCount
= 0
271 mo
= self
.begOfLineRe
.search(line
)
272 assert mo
is not None
273 self
.indent
= mo
.group()
274 lineWithoutBeginning
= line
[len(self
.indent
):]
275 mo
= self
.endOfLineRe
.search(lineWithoutBeginning
)
279 endOfLine
= mo
.group()
280 oldAsm
= line
[len(self
.indent
):len(line
) - len(endOfLine
)]
281 self
.originalLine
= line
.rstrip()
282 if line
.strip() == '':
283 self
.oldAsmEmptyLineCount
+= 1
284 self
.TranslateAsm(oldAsm
, endOfLine
)
285 if line
.strip() != '':
286 self
.oldAsmEmptyLineCount
= 0
288 procDeclRe
= re
.compile(r
'''
291 (?: \s+ NEAR | FAR )?
293 (?: \s+ (PUBLIC | PRIVATE) )?
294 (?: \s+ USES ( (?: \s+ \w[\w0-9]* )+ ) )?
297 re
.VERBOSE | re
.IGNORECASE
300 procEndRe
= re
.compile(r
'''
305 re
.VERBOSE | re
.IGNORECASE
308 varAndTypeSubRe
= r
' (?: [\w@][\w@0-9]* ) (?: \s* : \s* \w+ )? '
309 publicRe
= re
.compile(r
'''
311 ( %s (?: \s* , \s* %s )* )
313 ''' % (varAndTypeSubRe
, varAndTypeSubRe
),
314 re
.VERBOSE | re
.IGNORECASE
317 varAndTypeSubRe
= re
.compile(varAndTypeSubRe
, re
.VERBOSE | re
.IGNORECASE
)
319 macroDeclRe
= re
.compile(r
'''
324 re
.VERBOSE | re
.IGNORECASE
327 sectionDeclRe
= re
.compile(r
'''
332 re
.VERBOSE | re
.IGNORECASE
335 externRe
= re
.compile(r
'''
336 EXTE?RN \s+ (?: C \s+ )?
337 ([\w@][\w@0-9]*) \s* : \s* (\w+)
340 re
.VERBOSE | re
.IGNORECASE
343 externdefRe
= re
.compile(r
'''
344 EXTERNDEF \s+ (?: C \s+ )?
345 ([\w@][\w@0-9]*) \s* : \s* (\w+)
348 re
.VERBOSE | re
.IGNORECASE
351 protoRe
= re
.compile(r
'''
357 re
.VERBOSE | re
.IGNORECASE
360 defineDataRe
= re
.compile(r
'''
362 ( db | dw | dd | dq ) \s+
366 re
.VERBOSE | re
.IGNORECASE
369 equRe
= re
.compile(r
'''
370 ([\w@][\w@0-9]*) \s+ EQU \s+ (\S.*?)
373 re
.VERBOSE | re
.IGNORECASE
376 ignoreRe
= re
.compile(r
'''
388 re
.VERBOSE | re
.IGNORECASE
391 whitespaceRe
= re
.compile(r
'\s+', re
.MULTILINE
)
393 def TranslateAsm(self
, oldAsm
, endOfLine
):
394 assert(oldAsm
.strip() == oldAsm
)
396 endOfLine
= endOfLine
.replace(self
.inputFileBase
, self
.outputFileBase
)
398 oldOp
= oldAsm
.split()
406 self
.EmitAsmWithComment(oldAsm
, newAsm
, endOfLine
)
407 elif oldOp
in ('#include', ):
409 self
.EmitLine(oldAsm
+ endOfLine
)
410 elif oldOp
.lower() in ('end', 'title', 'text'):
412 self
.EmitAsmWithComment(oldAsm
, newAsm
, endOfLine
)
413 elif oldAsm
.lower() == '@@:':
414 self
.anonLabelCount
+= 1
415 self
.EmitLine(self
.anonLabel(self
.anonLabelCount
) + ':')
416 elif self
.MatchAndSetMo(self
.ignoreRe
, oldAsm
):
418 self
.EmitAsmWithComment(oldAsm
, newAsm
, endOfLine
)
419 elif oldAsm
.lower() == 'ret':
420 for i
in range(len(self
.uses
) - 1, -1, -1):
421 register
= self
.uses
[i
]
422 self
.EmitNewContent('pop ' + register
)
424 self
.EmitAsmWithComment(oldAsm
, newAsm
, endOfLine
)
426 elif oldOp
.lower() == 'lea':
427 newAsm
= self
.ConvertLea(oldAsm
)
428 self
.EmitAsmWithComment(oldAsm
, newAsm
, endOfLine
)
429 elif oldAsm
.lower() == 'end':
431 self
.EmitAsmWithComment(oldAsm
, newAsm
, endOfLine
)
433 elif self
.MatchAndSetMo(self
.equRe
, oldAsm
):
434 equ
= self
.mo
.group(1)
435 newAsm
= '%%define %s %s' % (equ
, self
.mo
.group(2))
436 self
.EmitAsmWithComment(oldAsm
, newAsm
, endOfLine
)
437 elif self
.MatchAndSetMo(self
.externRe
, oldAsm
) or \
438 self
.MatchAndSetMo(self
.protoRe
, oldAsm
):
439 extern
= self
.mo
.group(1)
440 self
.NewGlobal(extern
)
441 newAsm
= 'extern ' + extern
442 self
.EmitAsmWithComment(oldAsm
, newAsm
, endOfLine
)
443 elif self
.MatchAndSetMo(self
.externdefRe
, oldAsm
):
445 self
.EmitAsmWithComment(oldAsm
, newAsm
, endOfLine
)
446 elif self
.MatchAndSetMo(self
.macroDeclRe
, oldAsm
):
447 newAsm
= '%%macro %s 0' % self
.mo
.group(1)
448 self
.EmitAsmWithComment(oldAsm
, newAsm
, endOfLine
)
449 elif oldOp
.lower() == 'endm':
450 newAsm
= r
'%endmacro'
451 self
.EmitAsmWithComment(oldAsm
, newAsm
, endOfLine
)
452 elif self
.MatchAndSetMo(self
.sectionDeclRe
, oldAsm
):
453 name
= self
.mo
.group(1)
454 ty
= self
.mo
.group(2)
455 if ty
.lower() == 'section':
459 self
.EmitAsmWithComment(oldAsm
, newAsm
, endOfLine
)
460 elif self
.MatchAndSetMo(self
.procDeclRe
, oldAsm
):
461 proc
= self
.proc
= self
.mo
.group(1)
462 visibility
= self
.mo
.group(2)
463 if visibility
is None:
466 visibility
= visibility
.lower()
467 if visibility
!= 'private':
468 self
.NewGlobal(self
.proc
)
469 proc
= 'ASM_PFX(' + proc
+ ')'
470 self
.EmitNewContent('global ' + proc
)
472 self
.EmitAsmWithComment(oldAsm
, newAsm
, endOfLine
)
473 uses
= self
.mo
.group(3)
475 uses
= filter(None, uses
.split())
479 for register
in self
.uses
:
480 self
.EmitNewContent(' push ' + register
)
481 elif self
.MatchAndSetMo(self
.procEndRe
, oldAsm
):
483 self
.EmitAsmWithComment(oldAsm
, newAsm
, endOfLine
)
484 elif self
.MatchAndSetMo(self
.publicRe
, oldAsm
):
485 publics
= re
.findall(self
.varAndTypeSubRe
, self
.mo
.group(1))
486 publics
= map(lambda p
: p
.split(':')[0].strip(), publics
)
487 for i
in range(len(publics
) - 1):
489 self
.EmitNewContent('global ASM_PFX(%s)' % publics
[i
])
493 newAsm
= 'global ASM_PFX(%s)' % name
494 self
.EmitAsmWithComment(oldAsm
, newAsm
, endOfLine
)
495 elif self
.MatchAndSetMo(self
.defineDataRe
, oldAsm
):
496 name
= self
.mo
.group(1)
497 ty
= self
.mo
.group(2)
498 value
= self
.mo
.group(3)
501 newAsm
= '%s: %s %s' % (name
, ty
, value
)
502 newAsm
= self
.CommonConversions(newAsm
)
503 self
.EmitAsmWithComment(oldAsm
, newAsm
, endOfLine
)
505 newAsm
= self
.CommonConversions(oldAsm
)
506 self
.EmitAsmWithComment(oldAsm
, newAsm
, endOfLine
)
508 def NewGlobal(self
, name
):
509 regex
= re
.compile(r
'(?<![_\w\d])(?<!ASM_PFX\()(' + re
.escape(name
) +
511 self
.globals.add(regex
)
513 def ConvertAnonymousLabels(self
, oldAsm
):
515 anonLabel
= self
.anonLabel(self
.anonLabelCount
)
516 newAsm
= newAsm
.replace('@b', anonLabel
)
517 newAsm
= newAsm
.replace('@B', anonLabel
)
518 anonLabel
= self
.anonLabel(self
.anonLabelCount
+ 1)
519 newAsm
= newAsm
.replace('@f', anonLabel
)
520 newAsm
= newAsm
.replace('@F', anonLabel
)
523 def anonLabel(self
, count
):
526 def EmitString(self
, string
):
527 self
.output
.write(string
)
529 def EmitLineWithDiff(self
, old
, new
):
530 newLine
= (self
.indent
+ new
).rstrip()
533 print '+%s' % newLine
536 print '+%s' % newLine
540 self
.newAsmEmptyLineCount
= 0
541 self
.EmitString(newLine
+ '\r\n')
543 def EmitLine(self
, string
):
544 self
.EmitLineWithDiff(self
.originalLine
, string
)
546 def EmitNewContent(self
, string
):
547 self
.EmitLineWithDiff(None, string
)
549 def EmitAsmReplaceOp(self
, oldAsm
, oldOp
, newOp
, endOfLine
):
550 newAsm
= oldAsm
.replace(oldOp
, newOp
, 1)
551 self
.EmitAsmWithComment(oldAsm
, newAsm
, endOfLine
)
553 hexNumRe
= re
.compile(r
'0*((?=[\da-f])\d*(?<=\d)[\da-f]*)h', re
.IGNORECASE
)
555 def EmitAsmWithComment(self
, oldAsm
, newAsm
, endOfLine
):
556 for glblRe
in self
.globals:
557 newAsm
= glblRe
.sub(r
'ASM_PFX(\1)', newAsm
)
559 newAsm
= self
.hexNumRe
.sub(r
'0x\1', newAsm
)
561 newLine
= newAsm
+ endOfLine
562 emitNewLine
= ((newLine
.strip() != '') or
563 ((oldAsm
+ endOfLine
).strip() == ''))
564 if emitNewLine
and newLine
.strip() == '':
565 self
.newAsmEmptyLineCount
+= 1
566 if self
.newAsmEmptyLineCount
> 1:
569 self
.EmitLine(newLine
.rstrip())
571 print '-%s' % self
.originalLine
573 leaRe
= re
.compile(r
'''
574 (lea \s+) ([\w@][\w@0-9]*) \s* , \s* (\S (?:.*\S)?)
577 re
.VERBOSE | re
.IGNORECASE
580 def ConvertLea(self
, oldAsm
):
582 if self
.MatchAndSetMo(self
.leaRe
, oldAsm
):
583 lea
= self
.mo
.group(1)
584 dst
= self
.mo
.group(2)
585 src
= self
.mo
.group(3)
586 if src
.find('[') < 0:
587 src
= '[' + src
+ ']'
588 newAsm
= lea
+ dst
+ ', ' + src
589 newAsm
= self
.CommonConversions(newAsm
)
592 ptrRe
= re
.compile(r
'''
594 ([dfq]?word|byte) \s+ (?: ptr ) (\s*)
597 re
.VERBOSE | re
.IGNORECASE
600 def ConvertPtr(self
, oldAsm
):
602 while self
.SearchAndSetMo(self
.ptrRe
, newAsm
):
603 ty
= self
.mo
.group(1)
604 if ty
.lower() == 'fword':
607 ty
+= self
.mo
.group(2)
608 newAsm
= newAsm
[:self
.mo
.start(0)] + ty
+ newAsm
[self
.mo
.end(0):]
611 labelByteRe
= re
.compile(r
'''
612 (?: \s+ label \s+ (?: [dfq]?word | byte ) )
615 re
.VERBOSE | re
.IGNORECASE
618 def ConvertLabelByte(self
, oldAsm
):
620 if self
.SearchAndSetMo(self
.labelByteRe
, newAsm
):
621 newAsm
= newAsm
[:self
.mo
.start(0)] + ':' + newAsm
[self
.mo
.end(0):]
624 unaryBitwiseOpRe
= re
.compile(r
'''
628 re
.VERBOSE | re
.IGNORECASE
630 binaryBitwiseOpRe
= re
.compile(r
'''
632 ( AND | OR | SHL | SHR )
635 re
.VERBOSE | re
.IGNORECASE
637 bitwiseOpReplacements
= {
645 def ConvertBitwiseOp(self
, oldAsm
):
647 while self
.SearchAndSetMo(self
.binaryBitwiseOpRe
, newAsm
):
648 prefix
= self
.mo
.group(1)
649 op
= self
.bitwiseOpReplacements
[self
.mo
.group(2).lower()]
650 newAsm
= newAsm
[:self
.mo
.start(0)] + prefix
+ op
+ \
651 newAsm
[self
.mo
.end(0):]
652 while self
.SearchAndSetMo(self
.unaryBitwiseOpRe
, newAsm
):
653 op
= self
.bitwiseOpReplacements
[self
.mo
.group(1).lower()]
654 newAsm
= newAsm
[:self
.mo
.start(0)] + op
+ newAsm
[self
.mo
.end(0):]
657 sectionRe
= re
.compile(r
'''
664 re
.VERBOSE | re
.IGNORECASE
667 segmentRe
= re
.compile(r
'''
674 re
.VERBOSE | re
.IGNORECASE
677 def ConvertSection(self
, oldAsm
):
679 if self
.MatchAndSetMo(self
.sectionRe
, newAsm
) or \
680 self
.MatchAndSetMo(self
.segmentRe
, newAsm
):
681 name
= self
.mo
.group(1).lower()
684 self
.EmitLine('DEFAULT REL')
686 newAsm
= 'SECTION .' + name
689 fwordRe
= re
.compile(r
'''
694 re
.VERBOSE | re
.IGNORECASE
697 def FwordUnsupportedCheck(self
, oldAsm
):
699 if self
.SearchAndSetMo(self
.fwordRe
, newAsm
):
700 newAsm
= self
.Unsupported(newAsm
, 'fword used')
703 __common_conversion_routines__
= (
704 ConvertAnonymousLabels
,
706 FwordUnsupportedCheck
,
712 def CommonConversions(self
, oldAsm
):
714 for conv
in self
.__common
_conversion
_routines
__:
715 newAsm
= conv(self
, newAsm
)
718 def Unsupported(self
, asm
, message
=None):
720 raise UnsupportedConversion
722 self
.unsupportedSyntaxSeen
= True
723 newAsm
= '%error conversion unsupported'
725 newAsm
+= '; ' + message
730 class ConvertInfFile(CommonUtils
):
732 def __init__(self
, inf
, clone
):
733 CommonUtils
.__init
__(self
, clone
)
735 self
.ScanInfAsmFiles()
737 self
.ConvertInfAsmFiles()
739 infSrcRe
= re
.compile(r
'''
741 ( [\w@][\w@0-9/]* \.(asm|s) )
746 re
.VERBOSE | re
.IGNORECASE
749 def GetInfAsmFileMapping(self
):
750 srcToDst
= {'order': []}
751 for line
in self
.lines
:
753 if self
.MatchAndSetMo(self
.infSrcRe
, line
):
754 src
= self
.mo
.group(1)
755 srcExt
= self
.mo
.group(2)
756 dst
= os
.path
.splitext(src
)[0] + '.nasm'
757 if src
not in srcToDst
:
759 srcToDst
['order'].append(src
)
762 def ScanInfAsmFiles(self
):
764 assert os
.path
.isfile(src
)
766 self
.lines
= f
.readlines()
769 path
= os
.path
.realpath(self
.inf
)
770 (self
.dir, inf
) = os
.path
.split(path
)
771 parent
= os
.path
.normpath(self
.dir)
772 (lastpath
, self
.moduleName
) = os
.path
.split(parent
)
773 self
.packageName
= None
775 lastpath
= os
.path
.normpath(lastpath
)
776 (parent
, basename
) = os
.path
.split(lastpath
)
777 if parent
== lastpath
:
779 if basename
.endswith('Pkg'):
780 self
.packageName
= basename
784 self
.srcToDst
= self
.GetInfAsmFileMapping()
786 self
.dstToSrc
= {'order': []}
787 for src
in self
.srcToDst
['order']:
788 srcExt
= os
.path
.splitext(src
)[1]
789 dst
= self
.srcToDst
[src
]
790 if dst
not in self
.dstToSrc
:
791 self
.dstToSrc
[dst
] = [src
]
792 self
.dstToSrc
['order'].append(dst
)
794 self
.dstToSrc
[dst
].append(src
)
797 return len(self
.dstToSrc
['order'])
800 return iter(self
.dstToSrc
['order'])
802 def ConvertInfAsmFiles(self
):
804 unsupportedArchCount
= 0
807 fileChanged
= self
.UpdateInfAsmFile(dst
)
809 self
.UpdateInfAsmFile(dst
)
811 except UnsupportedConversion
:
812 if not self
.Opt
.quiet
:
813 print 'MASM=>NASM conversion unsupported for', dst
814 notConverted
.append(dst
)
816 if not self
.Opt
.quiet
:
817 print 'Source file missing for', reldst
818 notConverted
.append(dst
)
819 except UnsupportedArch
:
820 unsupportedArchCount
+= 1
823 self
.ConversionFinished(dst
)
824 if len(notConverted
) > 0 and not self
.Opt
.quiet
:
825 for dst
in notConverted
:
826 reldst
= self
.RootRelative(dst
)
827 print 'Unabled to convert', reldst
828 if unsupportedArchCount
> 0 and not self
.Opt
.quiet
:
829 print 'Skipped', unsupportedArchCount
, 'files based on architecture'
831 def UpdateInfAsmFile(self
, dst
, IgnoreMissingAsm
=False):
832 infPath
= os
.path
.split(os
.path
.realpath(self
.inf
))[0]
833 asmSrc
= os
.path
.splitext(dst
)[0] + '.asm'
834 fullSrc
= os
.path
.join(infPath
, asmSrc
)
835 fullDst
= os
.path
.join(infPath
, dst
)
836 srcParentDir
= os
.path
.basename(os
.path
.split(fullSrc
)[0])
837 if srcParentDir
.lower() in UnsupportedArch
.unsupported
:
838 raise UnsupportedArch
839 elif not os
.path
.exists(fullSrc
):
840 if not IgnoreMissingAsm
:
842 else: # not os.path.exists(fullDst):
843 conv
= ConvertAsmFile(fullSrc
, fullDst
, self
)
844 self
.unsupportedSyntaxSeen
= conv
.unsupportedSyntaxSeen
848 for i
in range(len(self
.lines
)):
849 line
= self
.lines
[i
].rstrip()
851 for src
in self
.dstToSrc
[dst
]:
852 assert self
.srcToDst
[src
] == dst
853 updatedLine
= self
.ReplacePreserveSpacing(
854 updatedLine
, src
, dst
)
856 lineChanged
= updatedLine
!= line
858 if lastLine
.strip() == updatedLine
.strip():
861 self
.lines
[i
] = updatedLine
+ '\r\n'
866 if self
.lines
[i
] is not None:
867 print '+%s' % updatedLine
871 fileChanged |
= lineChanged
872 if self
.lines
[i
] is not None:
873 lastLine
= self
.lines
[i
]
876 self
.lines
= filter(lambda l
: l
is not None, self
.lines
)
878 for src
in self
.dstToSrc
[dst
]:
879 if not src
.endswith('.asm'):
880 fullSrc
= os
.path
.join(infPath
, src
)
881 if os
.path
.exists(fullSrc
):
882 self
.RemoveFile(fullSrc
)
885 f
= open(self
.inf
, 'wb')
886 f
.writelines(self
.lines
)
888 self
.FileUpdated(self
.inf
)
890 def ConversionFinished(self
, dst
):
891 asmSrc
= os
.path
.splitext(dst
)[0] + '.asm'
892 self
.FileConversionFinished(
893 self
.packageName
, self
.moduleName
, asmSrc
, dst
)
896 class ConvertInfFiles(CommonUtils
):
898 def __init__(self
, infs
, clone
):
899 CommonUtils
.__init
__(self
, clone
)
900 infs
= map(lambda i
: ConvertInfFile(i
, self
), infs
)
901 infs
= filter(lambda i
: len(i
) > 0, infs
)
902 dstToInfs
= {'order': []}
905 fulldst
= os
.path
.realpath(os
.path
.join(inf
.dir, dst
))
907 if fulldst
in dstToInfs
:
908 dstToInfs
[fulldst
].append(pair
)
910 dstToInfs
['order'].append(fulldst
)
911 dstToInfs
[fulldst
] = [pair
]
914 unsupportedArchCount
= 0
915 for dst
in dstToInfs
['order']:
918 for inf
, reldst
in dstToInfs
[dst
]:
919 inf
.UpdateInfAsmFile(reldst
, IgnoreMissingAsm
=didSomething
)
921 except UnsupportedConversion
:
922 if not self
.Opt
.quiet
:
923 print 'MASM=>NASM conversion unsupported for', reldst
924 notConverted
.append(dst
)
926 if not self
.Opt
.quiet
:
927 print 'Source file missing for', reldst
928 notConverted
.append(dst
)
929 except UnsupportedArch
:
930 unsupportedArchCount
+= 1
933 inf
.ConversionFinished(reldst
)
934 if len(notConverted
) > 0 and not self
.Opt
.quiet
:
935 for dst
in notConverted
:
936 reldst
= self
.RootRelative(dst
)
937 print 'Unabled to convert', reldst
938 if unsupportedArchCount
> 0 and not self
.Opt
.quiet
:
939 print 'Skipped', unsupportedArchCount
, 'files based on architecture'
942 class ConvertDirectories(CommonUtils
):
944 def __init__(self
, paths
, clone
):
945 CommonUtils
.__init
__(self
, clone
)
947 self
.ConvertInfAndAsmFiles()
949 def ConvertInfAndAsmFiles(self
):
951 for path
in self
.paths
:
952 assert(os
.path
.exists(path
))
953 for path
in self
.paths
:
954 for root
, dirs
, files
in os
.walk(path
):
955 for d
in ('.svn', '.git'):
959 if f
.lower().endswith('.inf'):
960 inf
= os
.path
.realpath(os
.path
.join(root
, f
))
963 ConvertInfFiles(infs
, self
)
966 class ConvertAsmApp(CommonUtils
):
969 CommonUtils
.__init
__(self
)
971 numArgs
= len(self
.Args
)
974 ConvertInfFiles(self
.Args
, self
)
976 ConvertDirectories(self
.Args
, self
)
977 elif not self
.dirmode
:
984 ConvertAsmFile(src
, dst
, self
)