]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Scripts/ConvertMasmToNasm.py
BaseTools: Use absolute import in Scripts
[mirror_edk2.git] / BaseTools / Scripts / ConvertMasmToNasm.py
index 2f0dd4f9a65c765591359024c16326514e6991c3..5b83724b3124f84eb6566efaa9da46c90d1538eb 100755 (executable)
 #  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
 #\r
 \r
+from __future__ import print_function\r
+\r
 #\r
 # Import Modules\r
 #\r
+import argparse\r
+import io\r
 import os.path\r
 import re\r
-import StringIO\r
 import subprocess\r
 import sys\r
-from optparse import OptionParser\r
 \r
 \r
 class UnsupportedConversion(Exception):\r
@@ -45,20 +47,21 @@ class CommonUtils:
 \r
     def __init__(self, clone=None):\r
         if clone is None:\r
-            (self.Opt, self.Args) = self.ProcessCommandLine()\r
+            self.args = self.ProcessCommandLine()\r
         else:\r
-            (self.Opt, self.Args) = (clone.Opt, clone.Args)\r
+            self.args = clone.args\r
 \r
         self.unsupportedSyntaxSeen = False\r
-        self.src = self.Args[0]\r
+        self.src = self.args.source\r
+        self.keep = self.args.keep\r
         assert(os.path.exists(self.src))\r
         self.dirmode = os.path.isdir(self.src)\r
         srcExt = os.path.splitext(self.src)[1]\r
         assert (self.dirmode or srcExt != '.nasm')\r
         self.infmode = not self.dirmode and srcExt == '.inf'\r
-        self.diff = self.Opt.diff\r
-        self.git = self.Opt.git\r
-        self.force = self.Opt.force\r
+        self.diff = self.args.diff\r
+        self.git = self.args.git\r
+        self.force = self.args.force\r
 \r
         if clone is None:\r
             self.rootdir = os.getcwd()\r
@@ -69,27 +72,25 @@ class CommonUtils:
             self.gitemail = clone.gitemail\r
 \r
     def ProcessCommandLine(self):\r
-        Parser = OptionParser(description=self.__copyright__,\r
-                              version=self.__version__,\r
-                              prog=sys.argv[0],\r
-                              usage=self.__usage__\r
-                              )\r
-        Parser.add_option("-q", "--quiet", action="store_true", type=None,\r
-                          help="Disable all messages except FATAL ERRORS.")\r
-        Parser.add_option("--git", action="store_true", type=None,\r
-                          help="Use git to create commits for each file converted")\r
-        Parser.add_option("--diff", action="store_true", type=None,\r
-                          help="Show diff of conversion")\r
-        Parser.add_option("-f", "--force", action="store_true", type=None,\r
-                          help="Force conversion even if unsupported")\r
-\r
-        (Opt, Args) = Parser.parse_args()\r
-\r
-        if not Opt.quiet:\r
-            print self.__copyright__\r
-            Parser.print_version()\r
-\r
-        return (Opt, Args)\r
+        parser = argparse.ArgumentParser(description=self.__copyright__)\r
+        parser.add_argument('--version', action='version',\r
+                            version='%(prog)s ' + self.VersionNumber)\r
+        parser.add_argument("-q", "--quiet", action="store_true",\r
+                            help="Disable all messages except FATAL ERRORS.")\r
+        parser.add_argument("--git", action="store_true",\r
+                            help="Use git to create commits for each file converted")\r
+        parser.add_argument("--keep", action="append", choices=('asm', 's'),\r
+                            default=[],\r
+                            help="Don't remove files with this extension")\r
+        parser.add_argument("--diff", action="store_true",\r
+                            help="Show diff of conversion")\r
+        parser.add_argument("-f", "--force", action="store_true",\r
+                            help="Force conversion even if unsupported")\r
+        parser.add_argument('source', help='MASM input file')\r
+        parser.add_argument('dest', nargs='?',\r
+                            help='NASM output file (default=input.nasm; - for stdout)')\r
+\r
+        return parser.parse_args()\r
 \r
     def RootRelative(self, path):\r
         result = path\r
@@ -157,12 +158,12 @@ class CommonUtils:
         (stdout, stderr) = p.communicate(pipeIn)\r
         if checkExitCode:\r
             if p.returncode != 0:\r
-                print 'command:', ' '.join(cmd)\r
-                print 'stdout:', stdout\r
-                print 'stderr:', stderr\r
-                print 'return:', p.returncode\r
+                print('command:', ' '.join(cmd))\r
+                print('stdout:', stdout)\r
+                print('stderr:', stderr)\r
+                print('return:', p.returncode)\r
             assert p.returncode == 0\r
-        return stdout\r
+        return stdout.decode('utf-8', 'ignore')\r
 \r
     def FileUpdated(self, path):\r
         if not self.git or not self.gitdir:\r
@@ -178,15 +179,24 @@ class CommonUtils:
         if not self.git or not self.gitdir:\r
             return\r
 \r
+        if self.ShouldKeepFile(path):\r
+            return\r
+\r
         cmd = ('git', 'rm', path)\r
         self.RunAndCaptureOutput(cmd)\r
 \r
+    def ShouldKeepFile(self, path):\r
+        ext = os.path.splitext(path)[1].lower()\r
+        if ext.startswith('.'):\r
+            ext = ext[1:]\r
+        return ext in self.keep\r
+\r
     def FileConversionFinished(self, pkg, module, src, dst):\r
         if not self.git or not self.gitdir:\r
             return\r
 \r
-        if not self.Opt.quiet:\r
-            print 'Committing: Conversion of', dst\r
+        if not self.args.quiet:\r
+            print('Committing: Conversion of', dst)\r
 \r
         prefix = ' '.join(filter(lambda a: a, [pkg, module]))\r
         message = ''\r
@@ -200,6 +210,7 @@ class CommonUtils:
         message += 'Contributed-under: TianoCore Contribution Agreement 1.0\n'\r
         assert(self.gitemail is not None)\r
         message += 'Signed-off-by: %s\n' % self.gitemail\r
+        message = message.encode('utf-8', 'ignore')\r
 \r
         cmd = ('git', 'commit', '-F', '-')\r
         self.RunAndCaptureOutput(cmd, pipeIn=message)\r
@@ -231,23 +242,22 @@ class ConvertAsmFile(CommonUtils):
 \r
         self.inputFileBase = os.path.basename(self.inputFilename)\r
         self.outputFileBase = os.path.basename(self.outputFilename)\r
-        if self.outputFilename == '-' and not self.diff:\r
-            self.output = sys.stdout\r
-        else:\r
-            self.output = StringIO.StringIO()\r
-        if not self.Opt.quiet:\r
+        self.output = io.BytesIO()\r
+        if not self.args.quiet:\r
             dirpath, src = os.path.split(self.inputFilename)\r
             dirpath = self.RootRelative(dirpath)\r
             dst = os.path.basename(self.outputFilename)\r
-            print 'Converting:', dirpath, src, '->', dst\r
-        lines = open(self.inputFilename).readlines()\r
+            print('Converting:', dirpath, src, '->', dst)\r
+        lines = io.open(self.inputFilename).readlines()\r
         self.Convert(lines)\r
-        if self.outputFilename == '-':\r
-            if self.diff:\r
-                sys.stdout.write(self.output.getvalue())\r
-                self.output.close()\r
+        if self.outputFilename == '-' and not self.diff:\r
+            output_data = self.output.getvalue()\r
+            if sys.version_info >= (3, 0):\r
+                output_data = output_data.decode('utf-8', 'ignore')\r
+            sys.stdout.write(output_data)\r
+            self.output.close()\r
         else:\r
-            f = open(self.outputFilename, 'wb')\r
+            f = io.open(self.outputFilename, 'wb')\r
             f.write(self.output.getvalue())\r
             f.close()\r
             self.output.close()\r
@@ -288,7 +298,9 @@ class ConvertAsmFile(CommonUtils):
                 self.oldAsmEmptyLineCount = 0\r
 \r
     procDeclRe = re.compile(r'''\r
-                                ([\w@][\w@0-9]*) \s+\r
+                                (?: ASM_PFX \s* [(] \s* )?\r
+                                ([\w@][\w@0-9]*) \s*\r
+                                [)]? \s+\r
                                 PROC\r
                                 (?: \s+ NEAR | FAR )?\r
                                 (?: \s+ C )?\r
@@ -474,7 +486,7 @@ class ConvertAsmFile(CommonUtils):
             self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
             uses = self.mo.group(3)\r
             if uses is not None:\r
-                uses = filter(None, uses.split())\r
+                uses = tuple(filter(None, uses.split()))\r
             else:\r
                 uses = tuple()\r
             self.uses = uses\r
@@ -485,7 +497,7 @@ class ConvertAsmFile(CommonUtils):
             self.EmitAsmWithComment(oldAsm, newAsm, endOfLine)\r
         elif self.MatchAndSetMo(self.publicRe, oldAsm):\r
             publics = re.findall(self.varAndTypeSubRe, self.mo.group(1))\r
-            publics = map(lambda p: p.split(':')[0].strip(), publics)\r
+            publics = tuple(map(lambda p: p.split(':')[0].strip(), publics))\r
             for i in range(len(publics) - 1):\r
                 name = publics[i]\r
                 self.EmitNewContent('global ASM_PFX(%s)' % publics[i])\r
@@ -526,18 +538,18 @@ class ConvertAsmFile(CommonUtils):
         return '.%d' % count\r
 \r
     def EmitString(self, string):\r
-        self.output.write(string)\r
+        self.output.write(string.encode('utf-8', 'ignore'))\r
 \r
     def EmitLineWithDiff(self, old, new):\r
         newLine = (self.indent + new).rstrip()\r
         if self.diff:\r
             if old is None:\r
-                print '+%s' % newLine\r
+                print('+%s' % newLine)\r
             elif newLine != old:\r
-                print '-%s' % old\r
-                print '+%s' % newLine\r
+                print('-%s' % old)\r
+                print('+%s' % newLine)\r
             else:\r
-                print '', newLine\r
+                print('', newLine)\r
         if newLine != '':\r
             self.newAsmEmptyLineCount = 0\r
         self.EmitString(newLine + '\r\n')\r
@@ -570,7 +582,7 @@ class ConvertAsmFile(CommonUtils):
         if emitNewLine:\r
             self.EmitLine(newLine.rstrip())\r
         elif self.diff:\r
-            print '-%s' % self.originalLine\r
+            print('-%s' % self.originalLine)\r
 \r
     leaRe = re.compile(r'''\r
                            (lea \s+) ([\w@][\w@0-9]*) \s* , \s* (\S (?:.*\S)?)\r
@@ -756,7 +768,8 @@ class ConvertInfFile(CommonUtils):
                 src = self.mo.group(1)\r
                 srcExt = self.mo.group(2)\r
                 dst = os.path.splitext(src)[0] + '.nasm'\r
-                if src not in srcToDst:\r
+                fullDst = os.path.join(self.dir, dst)\r
+                if src not in srcToDst and not os.path.exists(fullDst):\r
                     srcToDst[src] = dst\r
                     srcToDst['order'].append(src)\r
         return srcToDst\r
@@ -764,7 +777,7 @@ class ConvertInfFile(CommonUtils):
     def ScanInfAsmFiles(self):\r
         src = self.inf\r
         assert os.path.isfile(src)\r
-        f = open(src)\r
+        f = io.open(src, 'rt')\r
         self.lines = f.readlines()\r
         f.close()\r
 \r
@@ -806,29 +819,28 @@ class ConvertInfFile(CommonUtils):
         unsupportedArchCount = 0\r
         for dst in self:\r
             didSomething = False\r
-            fileChanged = self.UpdateInfAsmFile(dst)\r
             try:\r
                 self.UpdateInfAsmFile(dst)\r
                 didSomething = True\r
             except UnsupportedConversion:\r
-                if not self.Opt.quiet:\r
-                    print 'MASM=>NASM conversion unsupported for', dst\r
+                if not self.args.quiet:\r
+                    print('MASM=>NASM conversion unsupported for', dst)\r
                 notConverted.append(dst)\r
             except NoSourceFile:\r
-                if not self.Opt.quiet:\r
-                    print 'Source file missing for', reldst\r
+                if not self.args.quiet:\r
+                    print('Source file missing for', reldst)\r
                 notConverted.append(dst)\r
             except UnsupportedArch:\r
                 unsupportedArchCount += 1\r
             else:\r
                 if didSomething:\r
                     self.ConversionFinished(dst)\r
-        if len(notConverted) > 0 and not self.Opt.quiet:\r
+        if len(notConverted) > 0 and not self.args.quiet:\r
             for dst in notConverted:\r
                 reldst = self.RootRelative(dst)\r
-                print 'Unabled to convert', reldst\r
-        if unsupportedArchCount > 0 and not self.Opt.quiet:\r
-            print 'Skipped', unsupportedArchCount, 'files based on architecture'\r
+                print('Unabled to convert', reldst)\r
+        if unsupportedArchCount > 0 and not self.args.quiet:\r
+            print('Skipped', unsupportedArchCount, 'files based on architecture')\r
 \r
     def UpdateInfAsmFile(self, dst, IgnoreMissingAsm=False):\r
         infPath = os.path.split(os.path.realpath(self.inf))[0]\r
@@ -845,37 +857,54 @@ class ConvertInfFile(CommonUtils):
             conv = ConvertAsmFile(fullSrc, fullDst, self)\r
             self.unsupportedSyntaxSeen = conv.unsupportedSyntaxSeen\r
 \r
-        lastLine = ''\r
         fileChanged = False\r
-        for i in range(len(self.lines)):\r
+        recentSources = list()\r
+        i = 0\r
+        while i < len(self.lines):\r
             line = self.lines[i].rstrip()\r
             updatedLine = line\r
+            lineChanged = False\r
+            preserveOldSource = False\r
             for src in self.dstToSrc[dst]:\r
                 assert self.srcToDst[src] == dst\r
                 updatedLine = self.ReplacePreserveSpacing(\r
                     updatedLine, src, dst)\r
+                lineChanged = updatedLine != line\r
+                if lineChanged:\r
+                    preserveOldSource = self.ShouldKeepFile(src)\r
+                    break\r
 \r
-            lineChanged = updatedLine != line\r
             if lineChanged:\r
-                if lastLine.strip() == updatedLine.strip():\r
-                    self.lines[i] = None\r
+                if preserveOldSource:\r
+                    if updatedLine.strip() not in recentSources:\r
+                        self.lines.insert(i, updatedLine + '\n')\r
+                        recentSources.append(updatedLine.strip())\r
+                        i += 1\r
+                        if self.diff:\r
+                            print('+%s' % updatedLine)\r
+                    if self.diff:\r
+                        print('', line)\r
                 else:\r
-                    self.lines[i] = updatedLine + '\r\n'\r
-\r
-            if self.diff:\r
-                if lineChanged:\r
-                    print '-%s' % line\r
-                    if self.lines[i] is not None:\r
-                        print '+%s' % updatedLine\r
-                else:\r
-                    print '', line\r
+                    if self.diff:\r
+                        print('-%s' % line)\r
+                    if updatedLine.strip() in recentSources:\r
+                        self.lines[i] = None\r
+                    else:\r
+                        self.lines[i] = updatedLine + '\n'\r
+                        recentSources.append(updatedLine.strip())\r
+                        if self.diff:\r
+                            print('+%s' % updatedLine)\r
+            else:\r
+                if len(recentSources) > 0:\r
+                    recentSources = list()\r
+                if self.diff:\r
+                    print('', line)\r
 \r
             fileChanged |= lineChanged\r
-            if self.lines[i] is not None:\r
-                lastLine = self.lines[i]\r
+            i += 1\r
 \r
         if fileChanged:\r
-            self.lines = filter(lambda l: l is not None, self.lines)\r
+            self.lines = list(filter(lambda l: l is not None, self.lines))\r
 \r
         for src in self.dstToSrc[dst]:\r
             if not src.endswith('.asm'):\r
@@ -884,7 +913,7 @@ class ConvertInfFile(CommonUtils):
                     self.RemoveFile(fullSrc)\r
 \r
         if fileChanged:\r
-            f = open(self.inf, 'wb')\r
+            f = io.open(self.inf, 'w', newline='\r\n')\r
             f.writelines(self.lines)\r
             f.close()\r
             self.FileUpdated(self.inf)\r
@@ -921,24 +950,24 @@ class ConvertInfFiles(CommonUtils):
                     inf.UpdateInfAsmFile(reldst, IgnoreMissingAsm=didSomething)\r
                     didSomething = True\r
             except UnsupportedConversion:\r
-                if not self.Opt.quiet:\r
-                    print 'MASM=>NASM conversion unsupported for', reldst\r
+                if not self.args.quiet:\r
+                    print('MASM=>NASM conversion unsupported for', reldst)\r
                 notConverted.append(dst)\r
             except NoSourceFile:\r
-                if not self.Opt.quiet:\r
-                    print 'Source file missing for', reldst\r
+                if not self.args.quiet:\r
+                    print('Source file missing for', reldst)\r
                 notConverted.append(dst)\r
             except UnsupportedArch:\r
                 unsupportedArchCount += 1\r
             else:\r
                 if didSomething:\r
                     inf.ConversionFinished(reldst)\r
-        if len(notConverted) > 0 and not self.Opt.quiet:\r
+        if len(notConverted) > 0 and not self.args.quiet:\r
             for dst in notConverted:\r
                 reldst = self.RootRelative(dst)\r
-                print 'Unabled to convert', reldst\r
-        if unsupportedArchCount > 0 and not self.Opt.quiet:\r
-            print 'Skipped', unsupportedArchCount, 'files based on architecture'\r
+                print('Unabled to convert', reldst)\r
+        if unsupportedArchCount > 0 and not self.args.quiet:\r
+            print('Skipped', unsupportedArchCount, 'files based on architecture')\r
 \r
 \r
 class ConvertDirectories(CommonUtils):\r
@@ -970,19 +999,13 @@ class ConvertAsmApp(CommonUtils):
     def __init__(self):\r
         CommonUtils.__init__(self)\r
 \r
-        numArgs = len(self.Args)\r
-        assert(numArgs >= 1)\r
+        src = self.args.source\r
+        dst = self.args.dest\r
         if self.infmode:\r
-            ConvertInfFiles(self.Args, self)\r
+            ConvertInfFiles((src,), self)\r
         elif self.dirmode:\r
-            ConvertDirectories(self.Args, self)\r
+            ConvertDirectories((src,), self)\r
         elif not self.dirmode:\r
-            assert(numArgs <= 2)\r
-            src = self.Args[0]\r
-            if numArgs > 1:\r
-                dst = self.Args[1]\r
-            else:\r
-                dst = None\r
             ConvertAsmFile(src, dst, self)\r
 \r
 ConvertAsmApp()\r