BaseTools Script: Add the script to generate Structure PCD setting
authorLiming Gao <liming.gao@intel.com>
Tue, 17 Jul 2018 03:42:21 +0000 (11:42 +0800)
committerLiming Gao <liming.gao@intel.com>
Wed, 25 Jul 2018 03:12:18 +0000 (11:12 +0800)
Here is this script usage.
1. Build one platform.
2. Use FCE tool to read HII config from the generated FD image.
FCE read -i Platform.fd > Config.txt
3. Call the script to generate StructurePcd setting.
ConvertFceToStructurePcd.py -p Build\PlatformPkg\DEBUG_VS2015x86 \
-c Config.txt -o OutputDir
OutputDir directory has StructurePcd.dec, StructurePcd.dsc, StructurePcd.inf.
4. Refer to wiki https://github.com/lgao4/edk2/wiki/StructurePcd-Enable-Steps
to enable structure pcd in this platform.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Liming Gao <liming.gao@intel.com>
Reviewed-by: Yonghong Zhu <yonghong.zhu@intel.com>
BaseTools/Scripts/ConvertFceToStructurePcd.py [new file with mode: 0644]

diff --git a/BaseTools/Scripts/ConvertFceToStructurePcd.py b/BaseTools/Scripts/ConvertFceToStructurePcd.py
new file mode 100644 (file)
index 0000000..6ca51c4
--- /dev/null
@@ -0,0 +1,675 @@
+#!/usr/bin/python\r
+## @file\r
+# Firmware Configuration Editor (FCE) from https://firmware.intel.com/develop\r
+# can parse BIOS image and generate Firmware Configuration file.\r
+# This script bases on Firmware Configuration file, and generate the structure\r
+# PCD setting in DEC/DSC/INF files.\r
+#\r
+# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution.  The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+\r
+'''\r
+ConvertFceToStructurePcd\r
+'''\r
+\r
+import re\r
+import os\r
+import datetime\r
+import argparse\r
+\r
+#\r
+# Globals for help information\r
+#\r
+__prog__        = 'ConvertFceToStructurePcd'\r
+__version__     = '%s Version %s' % (__prog__, '0.1 ')\r
+__copyright__   = 'Copyright (c) 2018, Intel Corporation. All rights reserved.'\r
+__description__ = 'Generate Structure PCD in DEC/DSC/INF based on Firmware Configuration.\n'\r
+\r
+\r
+dscstatement='''[Defines]\r
+  VPD_TOOL_GUID                  = 8C3D856A-9BE6-468E-850A-24F7A8D38E08\r
+\r
+[SkuIds]\r
+  0|DEFAULT              # The entry: 0|DEFAULT is reserved and always required.\r
+\r
+[DefaultStores]\r
+  0|STANDARD             # UEFI Standard default  0|STANDARD is reserved.\r
+  1|MANUFACTURING        # UEFI Manufacturing default 1|MANUFACTURING is reserved.\r
+\r
+[PcdsDynamicExVpd.common.DEFAULT]\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdNvStoreDefaultValueBuffer|*\r
+'''\r
+\r
+decstatement = '''[Guids]\r
+  gStructPcdTokenSpaceGuid = {0x3f1406f4, 0x2b, 0x487a, {0x8b, 0x69, 0x74, 0x29, 0x1b, 0x36, 0x16, 0xf4}}\r
+\r
+[PcdsFixedAtBuild,PcdsPatchableInModule,PcdsDynamic,PcdsDynamicEx]\r
+'''\r
+\r
+infstatement = '''[Pcd]\r
+'''\r
+\r
+SECTION='PcdsDynamicHii'\r
+PCD_NAME='gStructPcdTokenSpaceGuid.Pcd'\r
+\r
+WARNING=[]\r
+ERRORMSG=[]\r
+\r
+class parser_lst(object):\r
+\r
+  def __init__(self,filelist):\r
+    self._ignore=['BOOLEAN', 'UINT8', 'UINT16', 'UINT32', 'UINT64']\r
+    self.file=filelist\r
+    self.text=self.megre_lst()[0]\r
+    self.content=self.megre_lst()[1]\r
+\r
+  def megre_lst(self):\r
+    alltext=''\r
+    content={}\r
+    for file in self.file:\r
+      with open(file,'r') as f:\r
+        read =f.read()\r
+      alltext += read\r
+      content[file]=read\r
+    return alltext,content\r
+\r
+  def struct_lst(self):#{struct:lst file}\r
+    structs_file={}\r
+    name_format = re.compile(r'(?<!typedef)\s+struct (\w+) {.*?;', re.S)\r
+    for i in list(self.content.keys()):\r
+      structs= name_format.findall(self.content[i])\r
+      if structs:\r
+        for j in structs:\r
+          if j not in self._ignore:\r
+            structs_file[j]=i\r
+      else:\r
+        print("%s"%structs)\r
+    return structs_file\r
+\r
+  def struct(self):#struct:{offset:name}\r
+    unit_num = re.compile('(\d+)')\r
+    offset1_re = re.compile('(\d+)\[')\r
+    pcdname_num_re = re.compile('\w+\[(\S+)\]')\r
+    pcdname_re = re.compile('\](.*)\<')\r
+    pcdname2_re = re.compile('(\w+)\[')\r
+    uint_re = re.compile('\<(\S+)\>')\r
+    name_format = re.compile(r'(?<!typedef)\s+struct (\w+) {.*?;', re.S)\r
+    name=name_format.findall(self.text)\r
+    info={}\r
+    unparse=[]\r
+    if name:\r
+      tmp_n = [n for n in name if n not in self._ignore]\r
+      name = list(set(tmp_n))\r
+      name.sort(key = tmp_n.index)\r
+      name.reverse()\r
+      #name=list(set(name).difference(set(self._ignore)))\r
+      for struct in name:\r
+        s_re = re.compile(r'struct %s :(.*?)};'% struct, re.S)\r
+        content = s_re.search(self.text)\r
+        if content:\r
+          tmp_dict = {}\r
+          text = content.group().split('+')\r
+          for line in text[1:]:\r
+            offset = offset1_re.findall(line)\r
+            t_name = pcdname_re.findall(line)\r
+            uint = uint_re.findall(line)\r
+            if offset and uint:\r
+              offset = offset[0]\r
+              uint = uint[0]\r
+              if t_name:\r
+                t_name = t_name[0].strip()\r
+                if (' ' in t_name) or ("=" in t_name) or (";" in t_name) or("\\" in name) or (t_name ==''):\r
+                  WARNING.append("Warning:Invalid Pcd name '%s' for Offset %s in struct %s" % (t_name,offset, struct))\r
+                else:\r
+                  if '[' in t_name:\r
+                    if uint in ['UINT8', 'UINT16', 'UINT32', 'UINT64']:\r
+                      offset = int(offset, 10)\r
+                      tmp_name = pcdname2_re.findall(t_name)[0] + '[0]'\r
+                      tmp_dict[offset] = tmp_name\r
+                      pcdname_num = int(pcdname_num_re.findall(t_name)[0],10)\r
+                      uint = int(unit_num.findall(uint)[0],10)\r
+                      bit = uint / 8\r
+                      for i in range(1, pcdname_num):\r
+                        offset += bit\r
+                        tmp_name = pcdname2_re.findall(t_name)[0] + '[%s]' % i\r
+                        tmp_dict[offset] = tmp_name\r
+                    else:\r
+                      tmp_name = pcdname2_re.findall(t_name)[0]\r
+                      pcdname_num = pcdname_num_re.findall(t_name)[0]\r
+                      line = [offset,tmp_name,pcdname_num,uint]\r
+                      line.append(struct)\r
+                      unparse.append(line)\r
+                  else:\r
+                    if uint not in ['UINT8', 'UINT16', 'UINT32', 'UINT64']:\r
+                      line = [offset, t_name, 0, uint]\r
+                      line.append(struct)\r
+                      unparse.append(line)\r
+                    else:\r
+                      offset = int(offset,10)\r
+                      tmp_dict[offset] = t_name\r
+        info[struct] = tmp_dict\r
+      if len(unparse) != 0:\r
+        for u in unparse:\r
+          if u[3] in list(info.keys()):\r
+            unpar = self.nameISstruct(u,info[u[3]])\r
+            info[u[4]]= dict(list(info[u[4]].items())+list(unpar[u[4]].items()))\r
+    else:\r
+      print("ERROR: No struct name found in %s" % self.file)\r
+      ERRORMSG.append("ERROR: No struct name found in %s" % self.file)\r
+    return info\r
+\r
+\r
+  def nameISstruct(self,line,key_dict):\r
+    dict={}\r
+    dict2={}\r
+    s_re = re.compile(r'struct %s :(.*?)};' % line[3], re.S)\r
+    size_re = re.compile(r'mTotalSize \[(\S+)\]')\r
+    content = s_re.search(self.text)\r
+    if content:\r
+      s_size = size_re.findall(content.group())[0]\r
+    else:\r
+      s_size = '0'\r
+      print("ERROR: Struct %s not define mTotalSize in lst file" %line[3])\r
+      ERRORMSG.append("ERROR: Struct %s not define mTotalSize in lst file" %line[3])\r
+    size = int(line[0], 10)\r
+    if line[2] != 0:\r
+      for j in range(0, int(line[2], 10)):\r
+        for k in list(key_dict.keys()):\r
+          offset = size  + k\r
+          name ='%s.%s' %((line[1]+'[%s]'%j),key_dict[k])\r
+          dict[offset] = name\r
+        size = int(s_size,16)+size\r
+    elif line[2] == 0:\r
+      for k in list(key_dict.keys()):\r
+        offset = size + k\r
+        name = '%s.%s' % (line[1], key_dict[k])\r
+        dict[offset] = name\r
+    dict2[line[4]] = dict\r
+    return dict2\r
+\r
+  def efivarstore_parser(self):\r
+    efivarstore_format = re.compile(r'efivarstore.*?;', re.S)\r
+    struct_re = re.compile(r'efivarstore(.*?),',re.S)\r
+    name_re = re.compile(r'name=(\w+)')\r
+    efivarstore_dict={}\r
+    efitxt = efivarstore_format.findall(self.text)\r
+    for i in efitxt:\r
+      struct = struct_re.findall(i.replace(' ',''))\r
+      name = name_re.findall(i.replace(' ',''))\r
+      if struct and name:\r
+        efivarstore_dict[name[0]]=struct[0]\r
+      else:\r
+        print("ERROR: Can't find Struct or name in lst file, please check have this format:efivarstore XXXX, name=xxxx")\r
+        ERRORMSG.append("ERROR: Can't find Struct or name in lst file, please check have this format:efivarstore XXXX, name=xxxx")\r
+    return efivarstore_dict\r
+\r
+class Config(object):\r
+\r
+  def __init__(self,Config):\r
+    self.config=Config\r
+\r
+  #Parser .config file,return list[offset,name,guid,value,help]\r
+  def config_parser(self):\r
+    ids_re =re.compile('_ID:(\d+)',re.S)\r
+    id_re= re.compile('\s+')\r
+    info = []\r
+    info_dict={}\r
+    with open(self.config, 'r') as text:\r
+      read = text.read()\r
+    if 'DEFAULT_ID:' in read:\r
+      all_txt = read.split('FCEKEY DEFAULT')\r
+      for i in all_txt[1:]:\r
+        part = [] #save all infomation for DEFAULT_ID\r
+        str_id=''\r
+        ids = ids_re.findall(i.replace(' ',''))\r
+        for m in ids:\r
+          str_id +=m+'_'\r
+        str_id=str_id[:-1]\r
+        part.append(ids)\r
+        section = i.split('\nQ') #split with '\nQ ' to get every block\r
+        part +=self.section_parser(section)\r
+        info_dict[str_id] = self.section_parser(section)\r
+        info.append(part)\r
+    else:\r
+      part = []\r
+      id=('0','0')\r
+      str_id='0_0'\r
+      part.append(id)\r
+      section = read.split('\nQ')\r
+      part +=self.section_parser(section)\r
+      info_dict[str_id] = self.section_parser(section)\r
+      info.append(part)\r
+    return info_dict\r
+\r
+  def eval_id(self,id):\r
+    id = id.split("_")\r
+    default_id=id[0:len(id)//2]\r
+    platform_id=id[len(id)//2:]\r
+    text=''\r
+    for i in range(len(default_id)):\r
+      text +="%s.common.%s.%s,"%(SECTION,self.id_name(platform_id[i],'PLATFORM'),self.id_name(default_id[i],'DEFAULT'))\r
+    return '\n[%s]\n'%text[:-1]\r
+\r
+  def id_name(self,ID, flag):\r
+    platform_dict = {'0': 'DEFAULT'}\r
+    default_dict = {'0': 'STANDARD', '1': 'MANUFACTURING'}\r
+    if flag == "PLATFORM":\r
+      try:\r
+        value = platform_dict[ID]\r
+      except KeyError:\r
+        value = 'SKUID%s' % ID\r
+    elif flag == 'DEFAULT':\r
+      try:\r
+        value = default_dict[ID]\r
+      except KeyError:\r
+        value = 'DEFAULTID%s' % ID\r
+    else:\r
+      value = None\r
+    return value\r
+\r
+  def section_parser(self,section):\r
+    offset_re = re.compile(r'offset=(\w+)')\r
+    name_re = re.compile(r'name=(\S+)')\r
+    guid_re = re.compile(r'guid=(\S+)')\r
+  #  help_re = re.compile(r'help = (.*)')\r
+    attribute_re=re.compile(r'attribute=(\w+)')\r
+    value_re = re.compile(r'(//.*)')\r
+    part = []\r
+    for x in section[1:]:\r
+        line=x.split('\n')[0]\r
+        line=value_re.sub('',line) #delete \\... in "Q...." line\r
+        list1=line.split(' ')\r
+        value=self.value_parser(list1)\r
+        offset = offset_re.findall(x.replace(' ',''))\r
+        name = name_re.findall(x.replace(' ',''))\r
+        guid = guid_re.findall(x.replace(' ',''))\r
+        attribute =attribute_re.findall(x.replace(' ',''))\r
+        if offset and name and guid and value and attribute:\r
+          if attribute[0] in ['0x3','0x7']:\r
+            offset = int(offset[0], 16)\r
+            #help = help_re.findall(x)\r
+            text = offset, name[0], guid[0], value, attribute[0]\r
+            part.append(text)\r
+    return(part)\r
+\r
+  def value_parser(self, list1):\r
+    list1 = [t for t in list1 if t != '']  # remove '' form list\r
+    first_num = int(list1[0], 16)\r
+    if list1[first_num + 1] == 'STRING':  # parser STRING\r
+      value = 'L%s' % list1[-1]\r
+    elif list1[first_num + 1] == 'ORDERED_LIST':  # parser ORDERED_LIST\r
+      value_total = int(list1[first_num + 2])\r
+      list2 = list1[-value_total:]\r
+      tmp = []\r
+      line = ''\r
+      for i in list2:\r
+        if len(i) % 2 == 0 and len(i) != 2:\r
+          for m in range(0, len(i) // 2):\r
+            tmp.append('0x%02x' % (int('0x%s' % i, 16) >> m * 8 & 0xff))\r
+        else:\r
+          tmp.append('0x%s' % i)\r
+      for i in tmp:\r
+        line += '%s,' % i\r
+      value = '{%s}' % line[:-1]\r
+    else:\r
+      value = "0x%01x" % int(list1[-1], 16)\r
+    return value\r
+\r
+\r
+#parser Guid file, get guid name form guid value\r
+class GUID(object):\r
+\r
+  def __init__(self,path):\r
+    self.path = path\r
+    self.guidfile = self.gfile()\r
+    self.guiddict = self.guid_dict()\r
+\r
+  def gfile(self):\r
+    for root, dir, file in os.walk(self.path, topdown=True, followlinks=False):\r
+      if 'FV' in dir:\r
+        gfile = os.path.join(root,'Fv','Guid.xref')\r
+        if os.path.isfile(gfile):\r
+          return gfile\r
+        else:\r
+          print("ERROR: Guid.xref file not found")\r
+          ERRORMSG.append("ERROR: Guid.xref file not found")\r
+          exit()\r
+\r
+  def guid_dict(self):\r
+    guiddict={}\r
+    with open(self.guidfile,'r') as file:\r
+      lines = file.readlines()\r
+    guidinfo=lines\r
+    for line in guidinfo:\r
+      list=line.strip().split(' ')\r
+      if list:\r
+        if len(list)>1:\r
+          guiddict[list[0].upper()]=list[1]\r
+        elif list[0] != ''and len(list)==1:\r
+          print("Error: line %s can't be parser in %s"%(line.strip(),self.guidfile))\r
+          ERRORMSG.append("Error: line %s can't be parser in %s"%(line.strip(),self.guidfile))\r
+      else:\r
+        print("ERROR: No data in %s" %self.guidfile)\r
+        ERRORMSG.append("ERROR: No data in %s" %self.guidfile)\r
+    return guiddict\r
+\r
+  def guid_parser(self,guid):\r
+    if guid.upper() in self.guiddict:\r
+      return self.guiddict[guid.upper()]\r
+    else:\r
+      print("ERROR: GUID %s not found in file %s"%(guid, self.guidfile))\r
+      ERRORMSG.append("ERROR: GUID %s not found in file %s"%(guid, self.guidfile))\r
+      return guid\r
+\r
+class PATH(object):\r
+\r
+  def __init__(self,path):\r
+    self.path=path\r
+    self.rootdir=self.get_root_dir()\r
+    self.usefuldir=[]\r
+    self.lstinf = {}\r
+    for path in self.rootdir:\r
+      for o_root, o_dir, o_file in os.walk(os.path.join(path, "OUTPUT"), topdown=True, followlinks=False):\r
+        for INF in o_file:\r
+          if os.path.splitext(INF)[1] == '.inf':\r
+            for l_root, l_dir, l_file in os.walk(os.path.join(path, "DEBUG"), topdown=True,\r
+                               followlinks=False):\r
+              for LST in l_file:\r
+                if os.path.splitext(LST)[1] == '.lst':\r
+                  self.lstinf[os.path.join(l_root, LST)] = os.path.join(o_root, INF)\r
+                  self.usefuldir.append(path)\r
+\r
+  def get_root_dir(self):\r
+    rootdir=[]\r
+    for root,dir,file in os.walk(self.path,topdown=True,followlinks=False):\r
+      if "OUTPUT" in root:\r
+        updir=root.split("OUTPUT",1)[0]\r
+        rootdir.append(updir)\r
+    rootdir=list(set(rootdir))\r
+    return rootdir\r
+\r
+  def lst_inf(self):\r
+    return self.lstinf\r
+\r
+  def package(self):\r
+    package={}\r
+    package_re=re.compile(r'Packages\.\w+]\n(.*)',re.S)\r
+    for i in list(self.lstinf.values()):\r
+      with open(i,'r') as inf:\r
+        read=inf.read()\r
+      section=read.split('[')\r
+      for j in section:\r
+        p=package_re.findall(j)\r
+        if p:\r
+          package[i]=p[0].rstrip()\r
+    return package\r
+\r
+  def header(self,struct):\r
+    header={}\r
+    head_re = re.compile(r'} %s;[\s\S\n]+h{1}"'%struct,re.M|re.S)\r
+    head_re2 = re.compile(r'#line[\s\d]+"(\S+h)"')\r
+    for i in list(self.lstinf.keys()):\r
+      with open(i,'r') as lst:\r
+        read = lst.read()\r
+      h = head_re.findall(read)\r
+      if h:\r
+        head=head_re2.findall(h[0])\r
+        if head:\r
+          format = head[0].replace('\\\\','/').replace('\\','/')\r
+          name =format.split('/')[-1]\r
+          head = self.makefile(name).replace('\\','/')\r
+          header[struct] = head\r
+    return header\r
+\r
+  def makefile(self,filename):\r
+    re_format = re.compile(r'DEBUG_DIR.*(?:\S+Pkg)\\(.*\\%s)'%filename)\r
+    for i in self.usefuldir:\r
+      with open(os.path.join(i,'Makefile'),'r') as make:\r
+        read = make.read()\r
+      dir = re_format.findall(read)\r
+      if dir:\r
+        return dir[0]\r
+\r
+class mainprocess(object):\r
+\r
+  def __init__(self,InputPath,Config,OutputPath):\r
+    self.init = 0xFCD00000\r
+    self.inputpath = os.path.abspath(InputPath)\r
+    self.outputpath = os.path.abspath(OutputPath)\r
+    self.LST = PATH(self.inputpath)\r
+    self.lst_dict = self.LST.lst_inf()\r
+    self.Config = Config\r
+    self.attribute_dict = {'0x3': 'NV, BS', '0x7': 'NV, BS, RT'}\r
+    self.guid = GUID(self.inputpath)\r
+    self.header={}\r
+\r
+  def main(self):\r
+    conf=Config(self.Config)\r
+    config_dict=conf.config_parser() #get {'0_0':[offset,name,guid,value,attribute]...,'1_0':....}\r
+    lst=parser_lst(list(self.lst_dict.keys()))\r
+    efi_dict=lst.efivarstore_parser() #get {name:struct} form lst file\r
+    keys=sorted(config_dict.keys())\r
+    all_struct=lst.struct()\r
+    stru_lst=lst.struct_lst()\r
+    title_list=[]\r
+    info_list=[]\r
+    header_list=[]\r
+    inf_list =[]\r
+    for i in stru_lst:\r
+      tmp = self.LST.header(i)\r
+      self.header.update(tmp)\r
+    for id_key in keys:\r
+      tmp_id=[id_key] #['0_0',[(struct,[name...]),(struct,[name...])]]\r
+      tmp_info={} #{name:struct}\r
+      for section in config_dict[id_key]:\r
+        c_offset,c_name,c_guid,c_value,c_attribute = section\r
+        if c_name in efi_dict:\r
+          struct = efi_dict[c_name]\r
+          title='%s%s|L"%s"|%s|0x00||%s\n'%(PCD_NAME,c_name,c_name,self.guid.guid_parser(c_guid),self.attribute_dict[c_attribute])\r
+          if struct in all_struct:\r
+            lstfile = stru_lst[struct]\r
+            struct_dict=all_struct[struct]\r
+            try:\r
+              title2 = '%s%s|{0}|%s|0xFCD00000{\n <HeaderFiles>\n  %s\n <Packages>\n%s\n}\n' % (PCD_NAME, c_name, struct, self.header[struct], self.LST.package()[self.lst_dict[lstfile]])\r
+            except KeyError:\r
+              WARNING.append("Warning: No <HeaderFiles> for struct %s"%struct)\r
+              title2 = '%s%s|{0}|%s|0xFCD00000{\n <HeaderFiles>\n  %s\n <Packages>\n%s\n}\n' % (PCD_NAME, c_name, struct, '', self.LST.package()[self.lst_dict[lstfile]])\r
+            header_list.append(title2)\r
+          else:\r
+            struct_dict ={}\r
+            print("ERROR: Struct %s can't found in lst file" %struct)\r
+            ERRORMSG.append("ERROR: Struct %s can't found in lst file" %struct)\r
+          if c_offset in struct_dict:\r
+            offset_name=struct_dict[c_offset]\r
+            info = "%s%s.%s|%s\n"%(PCD_NAME,c_name,offset_name,c_value)\r
+            inf = "%s%s\n"%(PCD_NAME,c_name)\r
+            inf_list.append(inf)\r
+            tmp_info[info]=title\r
+          else:\r
+            print("ERROR: Can't find offset %s with struct name %s"%(c_offset,struct))\r
+            ERRORMSG.append("ERROR: Can't find offset %s with name %s"%(c_offset,struct))\r
+        else:\r
+          print("ERROR: Can't find name %s in lst file"%(c_name))\r
+          ERRORMSG.append("ERROR: Can't find name %s in lst file"%(c_name))\r
+      tmp_id.append(list(self.reverse_dict(tmp_info).items()))\r
+      id,tmp_title_list,tmp_info_list = self.read_list(tmp_id)\r
+      title_list +=tmp_title_list\r
+      info_list.append(tmp_info_list)\r
+    inf_list = self.del_repeat(inf_list)\r
+    header_list = self.plus(self.del_repeat(header_list))\r
+    title_all=list(set(title_list))\r
+    info_list = self.del_repeat(info_list)\r
+    for i in range(len(info_list)-1,-1,-1):\r
+      if len(info_list[i]) == 0:\r
+        info_list.remove(info_list[i])\r
+    return keys,title_all,info_list,header_list,inf_list\r
+\r
+\r
+  def write_all(self):\r
+    title_flag=1\r
+    info_flag=1\r
+    if not os.path.isdir(self.outputpath):\r
+      os.makedirs(self.outputpath)\r
+    decwrite = write2file(os.path.join(self.outputpath,'StructurePcd.dec'))\r
+    dscwrite = write2file(os.path.join(self.outputpath,'StructurePcd.dsc'))\r
+    infwrite = write2file(os.path.join(self.outputpath, 'StructurePcd.inf'))\r
+    conf = Config(self.Config)\r
+    ids,title,info,header,inf=self.main()\r
+    decwrite.add2file(decstatement)\r
+    decwrite.add2file(header)\r
+    infwrite.add2file(infstatement)\r
+    infwrite.add2file(inf)\r
+    dscwrite.add2file(dscstatement)\r
+    for id in ids:\r
+      dscwrite.add2file(conf.eval_id(id))\r
+      if title_flag:\r
+        dscwrite.add2file(title)\r
+        title_flag=0\r
+      if len(info) == 1:\r
+        dscwrite.add2file(info)\r
+      elif len(info) == 2:\r
+        if info_flag:\r
+          dscwrite.add2file(info[0])\r
+          info_flag =0\r
+        else:\r
+          dscwrite.add2file(info[1])\r
+\r
+  def del_repeat(self,List):\r
+    if len(List) == 1 or len(List) == 0:\r
+      return List\r
+    else:\r
+      if type(List[0]) != type('xxx'):\r
+        alist=[]\r
+        for i in range(len(List)):\r
+          if i == 0:\r
+            alist.append(List[0])\r
+          else:\r
+            plist = []\r
+            for j in range(i):\r
+              plist += List[j]\r
+            alist.append(self.__del(list(set(plist)), List[i]))\r
+        return alist\r
+      else:\r
+        return list(set(List))\r
+\r
+\r
+  def __del(self,list1,list2):\r
+    return list(set(list2).difference(set(list1)))\r
+\r
+  def reverse_dict(self,dict):\r
+    data={}\r
+    for i in list(dict.items()):\r
+      if i[1] not in list(data.keys()):\r
+        data[i[1]]=[i[0]]\r
+      else:\r
+        data[i[1]].append(i[0])\r
+    return data\r
+\r
+  def read_list(self,list):\r
+    title_list=[]\r
+    info_list=[]\r
+    for i in list[1]:\r
+      title_list.append(i[0])\r
+      for j in i[1]:\r
+        info_list.append(j)\r
+    return list[0],title_list,info_list\r
+\r
+  def plus(self,list):\r
+    nums=[]\r
+    for i in list:\r
+      if type(i) != type([0]):\r
+        self.init += 1\r
+        num = "0x%01x" % self.init\r
+        j=i.replace('0xFCD00000',num.upper())\r
+        nums.append(j)\r
+    return nums\r
+\r
+class write2file(object):\r
+\r
+  def __init__(self,Output):\r
+    self.output=Output\r
+    self.text=''\r
+    if os.path.exists(self.output):\r
+      os.remove(self.output)\r
+\r
+  def add2file(self,content):\r
+    self.text = ''\r
+    with open(self.output,'a+') as file:\r
+      file.write(self.__gen(content))\r
+\r
+  def __gen(self,content):\r
+    if type(content) == type(''):\r
+      return content\r
+    elif type(content) == type([0,0])or type(content) == type((0,0)):\r
+      return self.__readlist(content)\r
+    elif type(content) == type({0:0}):\r
+      return self.__readdict(content)\r
+\r
+  def __readlist(self,list):\r
+    for i in list:\r
+      if type(i) == type([0,0])or type(i) == type((0,0)):\r
+        self.__readlist(i)\r
+      elif type(i) == type('') :\r
+        self.text +=i\r
+    return self.text\r
+\r
+  def __readdict(self,dict):\r
+    content=list(dict.items())\r
+    return self.__readlist(content)\r
+\r
+def stamp():\r
+  return datetime.datetime.now()\r
+\r
+def dtime(start,end,id=None):\r
+  if id:\r
+    pass\r
+    print("%s time:%s" % (id,str(end - start)))\r
+  else:\r
+    print("Total time:%s" %str(end-start)[:-7])\r
+\r
+\r
+def main():\r
+  start = stamp()\r
+  parser = argparse.ArgumentParser(prog = __prog__,\r
+                                   description = __description__ + __copyright__,\r
+                                   conflict_handler = 'resolve')\r
+  parser.add_argument('-v', '--version', action = 'version',version = __version__, help="show program's version number and exit")\r
+  parser.add_argument('-p', '--path', metavar='PATH', dest='path', help="platform build output directory")\r
+  parser.add_argument('-c', '--config',metavar='FILENAME', dest='config', help="firmware configuration file")\r
+  parser.add_argument('-o', '--outputdir', metavar='PATH', dest='output', help="output directoy")\r
+  options = parser.parse_args()\r
+  if options.config:\r
+    if options.path:\r
+      if options.output:\r
+        run = mainprocess(options.path, options.config, options.output)\r
+        print("Running...")\r
+        run.write_all()\r
+        if WARNING:\r
+          warning = list(set(WARNING))\r
+          for j in warning:\r
+            print(j)\r
+        if ERRORMSG:\r
+          ERROR = list(set(ERRORMSG))\r
+          with open("ERROR.log", 'w+') as error:\r
+            for i in ERROR:\r
+              error.write(i + '\n')\r
+          print("Some error find, error log in ERROR.log")\r
+        print('Finished, Output files in directory %s'%os.path.abspath(options.output))\r
+      else:\r
+        print('Error command, no output path, use -h for help')\r
+    else:\r
+      print('Error command, no build path input, use -h for help')\r
+  else:\r
+    print('Error command, no output file, use -h for help')\r
+  end = stamp()\r
+  dtime(start, end)\r
+\r
+if __name__ == '__main__':\r
+  main()\r