1#!/usr/bin/python
2## @file
3# Firmware Configuration Editor (FCE) from https://firmware.intel.com/develop
4# can parse BIOS image and generate Firmware Configuration file.
5# This script bases on Firmware Configuration file, and generate the structure
6# PCD setting in DEC/DSC/INF files.
7#
8# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
9# SPDX-License-Identifier: BSD-2-Clause-Patent
10#
11
12'''
13ConvertFceToStructurePcd
14'''
15
16import re
17import os
18import datetime
19import argparse
20
21#
22# Globals for help information
23#
24__prog__        = 'ConvertFceToStructurePcd'
25__version__     = '%s Version %s' % (__prog__, '0.1 ')
26__copyright__   = 'Copyright (c) 2018, Intel Corporation. All rights reserved.'
27__description__ = 'Generate Structure PCD in DEC/DSC/INF based on Firmware Configuration.\n'
28
29
30dscstatement='''[Defines]
31  VPD_TOOL_GUID                  = 8C3D856A-9BE6-468E-850A-24F7A8D38E08
32
33[SkuIds]
34  0|DEFAULT              # The entry: 0|DEFAULT is reserved and always required.
35
36[DefaultStores]
37  0|STANDARD             # UEFI Standard default  0|STANDARD is reserved.
38  1|MANUFACTURING        # UEFI Manufacturing default 1|MANUFACTURING is reserved.
39
40[PcdsDynamicExVpd.common.DEFAULT]
41  gEfiMdeModulePkgTokenSpaceGuid.PcdNvStoreDefaultValueBuffer|*
42'''
43
44decstatement = '''[Guids]
45  gStructPcdTokenSpaceGuid = {0x3f1406f4, 0x2b, 0x487a, {0x8b, 0x69, 0x74, 0x29, 0x1b, 0x36, 0x16, 0xf4}}
46
47[PcdsFixedAtBuild,PcdsPatchableInModule,PcdsDynamic,PcdsDynamicEx]
48'''
49
50infstatement = '''[Pcd]
51'''
52
53SECTION='PcdsDynamicHii'
54PCD_NAME='gStructPcdTokenSpaceGuid.Pcd'
55
56WARNING=[]
57ERRORMSG=[]
58
59class parser_lst(object):
60
61  def __init__(self,filelist):
62    self._ignore=['BOOLEAN', 'UINT8', 'UINT16', 'UINT32', 'UINT64']
63    self.file=filelist
64    self.text=self.megre_lst()[0]
65    self.content=self.megre_lst()[1]
66
67  def megre_lst(self):
68    alltext=''
69    content={}
70    for file in self.file:
71      with open(file,'r') as f:
72        read =f.read()
73      alltext += read
74      content[file]=read
75    return alltext,content
76
77  def struct_lst(self):#{struct:lst file}
78    structs_file={}
79    name_format = re.compile(r'(?<!typedef)\s+struct (\w+) {.*?;', re.S)
80    for i in list(self.content.keys()):
81      structs= name_format.findall(self.content[i])
82      if structs:
83        for j in structs:
84          if j not in self._ignore:
85            structs_file[j]=i
86      else:
87        print("%s"%structs)
88    return structs_file
89
90  def struct(self):#struct:{offset:name}
91    unit_num = re.compile('(\d+)')
92    offset1_re = re.compile('(\d+)\[')
93    pcdname_num_re = re.compile('\w+\[(\S+)\]')
94    pcdname_re = re.compile('\](.*)\<')
95    pcdname2_re = re.compile('(\w+)\[')
96    uint_re = re.compile('\<(\S+)\>')
97    name_format = re.compile(r'(?<!typedef)\s+struct (\w+) {.*?;', re.S)
98    name=name_format.findall(self.text)
99    info={}
100    unparse=[]
101    if name:
102      tmp_n = [n for n in name if n not in self._ignore]
103      name = list(set(tmp_n))
104      name.sort(key = tmp_n.index)
105      name.reverse()
106      #name=list(set(name).difference(set(self._ignore)))
107      for struct in name:
108        s_re = re.compile(r'struct %s :(.*?)};'% struct, re.S)
109        content = s_re.search(self.text)
110        if content:
111          tmp_dict = {}
112          text = content.group().split('+')
113          for line in text[1:]:
114            offset = offset1_re.findall(line)
115            t_name = pcdname_re.findall(line)
116            uint = uint_re.findall(line)
117            if offset and uint:
118              offset = offset[0]
119              uint = uint[0]
120              if t_name:
121                t_name = t_name[0].strip()
122                if (' ' in t_name) or ("=" in t_name) or (";" in t_name) or("\\" in name) or (t_name ==''):
123                  WARNING.append("Warning:Invalid Pcd name '%s' for Offset %s in struct %s" % (t_name,offset, struct))
124                else:
125                  if '[' in t_name:
126                    if uint in ['UINT8', 'UINT16', 'UINT32', 'UINT64']:
127                      offset = int(offset, 10)
128                      tmp_name = pcdname2_re.findall(t_name)[0] + '[0]'
129                      tmp_dict[offset] = tmp_name
130                      pcdname_num = int(pcdname_num_re.findall(t_name)[0],10)
131                      uint = int(unit_num.findall(uint)[0],10)
132                      bit = uint // 8
133                      for i in range(1, pcdname_num):
134                        offset += bit
135                        tmp_name = pcdname2_re.findall(t_name)[0] + '[%s]' % i
136                        tmp_dict[offset] = tmp_name
137                    else:
138                      tmp_name = pcdname2_re.findall(t_name)[0]
139                      pcdname_num = pcdname_num_re.findall(t_name)[0]
140                      line = [offset,tmp_name,pcdname_num,uint]
141                      line.append(struct)
142                      unparse.append(line)
143                  else:
144                    if uint not in ['UINT8', 'UINT16', 'UINT32', 'UINT64']:
145                      line = [offset, t_name, 0, uint]
146                      line.append(struct)
147                      unparse.append(line)
148                    else:
149                      offset = int(offset,10)
150                      tmp_dict[offset] = t_name
151        info[struct] = tmp_dict
152      if len(unparse) != 0:
153        for u in unparse:
154          if u[3] in list(info.keys()):
155            unpar = self.nameISstruct(u,info[u[3]])
156            info[u[4]]= dict(list(info[u[4]].items())+list(unpar[u[4]].items()))
157    else:
158      print("ERROR: No struct name found in %s" % self.file)
159      ERRORMSG.append("ERROR: No struct name found in %s" % self.file)
160    return info
161
162
163  def nameISstruct(self,line,key_dict):
164    dict={}
165    dict2={}
166    s_re = re.compile(r'struct %s :(.*?)};' % line[3], re.S)
167    size_re = re.compile(r'mTotalSize \[(\S+)\]')
168    content = s_re.search(self.text)
169    if content:
170      s_size = size_re.findall(content.group())[0]
171    else:
172      s_size = '0'
173      print("ERROR: Struct %s not define mTotalSize in lst file" %line[3])
174      ERRORMSG.append("ERROR: Struct %s not define mTotalSize in lst file" %line[3])
175    size = int(line[0], 10)
176    if line[2] != 0:
177      for j in range(0, int(line[2], 10)):
178        for k in list(key_dict.keys()):
179          offset = size  + k
180          name ='%s.%s' %((line[1]+'[%s]'%j),key_dict[k])
181          dict[offset] = name
182        size = int(s_size,16)+size
183    elif line[2] == 0:
184      for k in list(key_dict.keys()):
185        offset = size + k
186        name = '%s.%s' % (line[1], key_dict[k])
187        dict[offset] = name
188    dict2[line[4]] = dict
189    return dict2
190
191  def efivarstore_parser(self):
192    efivarstore_format = re.compile(r'efivarstore.*?;', re.S)
193    struct_re = re.compile(r'efivarstore(.*?),',re.S)
194    name_re = re.compile(r'name=(\w+)')
195    efivarstore_dict={}
196    efitxt = efivarstore_format.findall(self.text)
197    for i in efitxt:
198      struct = struct_re.findall(i.replace(' ',''))
199      name = name_re.findall(i.replace(' ',''))
200      if struct and name:
201        efivarstore_dict[name[0]]=struct[0]
202      else:
203        print("ERROR: Can't find Struct or name in lst file, please check have this format:efivarstore XXXX, name=xxxx")
204        ERRORMSG.append("ERROR: Can't find Struct or name in lst file, please check have this format:efivarstore XXXX, name=xxxx")
205    return efivarstore_dict
206
207class Config(object):
208
209  def __init__(self,Config):
210    self.config=Config
211
212  #Parser .config file,return list[offset,name,guid,value,help]
213  def config_parser(self):
214    ids_re =re.compile('_ID:(\d+)',re.S)
215    id_re= re.compile('\s+')
216    info = []
217    info_dict={}
218    with open(self.config, 'r') as text:
219      read = text.read()
220    if 'DEFAULT_ID:' in read:
221      all_txt = read.split('FCEKEY DEFAULT')
222      for i in all_txt[1:]:
223        part = [] #save all infomation for DEFAULT_ID
224        str_id=''
225        ids = ids_re.findall(i.replace(' ',''))
226        for m in ids:
227          str_id +=m+'_'
228        str_id=str_id[:-1]
229        part.append(ids)
230        section = i.split('\nQ') #split with '\nQ ' to get every block
231        part +=self.section_parser(section)
232        info_dict[str_id] = self.section_parser(section)
233        info.append(part)
234    else:
235      part = []
236      id=('0','0')
237      str_id='0_0'
238      part.append(id)
239      section = read.split('\nQ')
240      part +=self.section_parser(section)
241      info_dict[str_id] = self.section_parser(section)
242      info.append(part)
243    return info_dict
244
245  def eval_id(self,id):
246    id = id.split("_")
247    default_id=id[0:len(id)//2]
248    platform_id=id[len(id)//2:]
249    text=''
250    for i in range(len(default_id)):
251      text +="%s.common.%s.%s,"%(SECTION,self.id_name(platform_id[i],'PLATFORM'),self.id_name(default_id[i],'DEFAULT'))
252    return '\n[%s]\n'%text[:-1]
253
254  def id_name(self,ID, flag):
255    platform_dict = {'0': 'DEFAULT'}
256    default_dict = {'0': 'STANDARD', '1': 'MANUFACTURING'}
257    if flag == "PLATFORM":
258      try:
259        value = platform_dict[ID]
260      except KeyError:
261        value = 'SKUID%s' % ID
262    elif flag == 'DEFAULT':
263      try:
264        value = default_dict[ID]
265      except KeyError:
266        value = 'DEFAULTID%s' % ID
267    else:
268      value = None
269    return value
270
271  def section_parser(self,section):
272    offset_re = re.compile(r'offset=(\w+)')
273    name_re = re.compile(r'name=(\S+)')
274    guid_re = re.compile(r'guid=(\S+)')
275  #  help_re = re.compile(r'help = (.*)')
276    attribute_re=re.compile(r'attribute=(\w+)')
277    value_re = re.compile(r'(//.*)')
278    part = []
279    for x in section[1:]:
280        line=x.split('\n')[0]
281        line=value_re.sub('',line) #delete \\... in "Q...." line
282        list1=line.split(' ')
283        value=self.value_parser(list1)
284        offset = offset_re.findall(x.replace(' ',''))
285        name = name_re.findall(x.replace(' ',''))
286        guid = guid_re.findall(x.replace(' ',''))
287        attribute =attribute_re.findall(x.replace(' ',''))
288        if offset and name and guid and value and attribute:
289          if attribute[0] in ['0x3','0x7']:
290            offset = int(offset[0], 16)
291            #help = help_re.findall(x)
292            text = offset, name[0], guid[0], value, attribute[0]
293            part.append(text)
294    return(part)
295
296  def value_parser(self, list1):
297    list1 = [t for t in list1 if t != '']  # remove '' form list
298    first_num = int(list1[0], 16)
299    if list1[first_num + 1] == 'STRING':  # parser STRING
300      if list1[-1] == '""':
301        value = "{0x0, 0x0}"
302      else:
303        value = 'L%s' % list1[-1]
304    elif list1[first_num + 1] == 'ORDERED_LIST':  # parser ORDERED_LIST
305      value_total = int(list1[first_num + 2])
306      list2 = list1[-value_total:]
307      tmp = []
308      line = ''
309      for i in list2:
310        if len(i) % 2 == 0 and len(i) != 2:
311          for m in range(0, len(i) // 2):
312            tmp.append('0x%02x' % (int('0x%s' % i, 16) >> m * 8 & 0xff))
313        else:
314          tmp.append('0x%s' % i)
315      for i in tmp:
316        line += '%s,' % i
317      value = '{%s}' % line[:-1]
318    else:
319      value = "0x%01x" % int(list1[-1], 16)
320    return value
321
322
323#parser Guid file, get guid name form guid value
324class GUID(object):
325
326  def __init__(self,path):
327    self.path = path
328    self.guidfile = self.gfile()
329    self.guiddict = self.guid_dict()
330
331  def gfile(self):
332    for root, dir, file in os.walk(self.path, topdown=True, followlinks=False):
333      if 'FV' in dir:
334        gfile = os.path.join(root,'Fv','Guid.xref')
335        if os.path.isfile(gfile):
336          return gfile
337        else:
338          print("ERROR: Guid.xref file not found")
339          ERRORMSG.append("ERROR: Guid.xref file not found")
340          exit()
341
342  def guid_dict(self):
343    guiddict={}
344    with open(self.guidfile,'r') as file:
345      lines = file.readlines()
346    guidinfo=lines
347    for line in guidinfo:
348      list=line.strip().split(' ')
349      if list:
350        if len(list)>1:
351          guiddict[list[0].upper()]=list[1]
352        elif list[0] != ''and len(list)==1:
353          print("Error: line %s can't be parser in %s"%(line.strip(),self.guidfile))
354          ERRORMSG.append("Error: line %s can't be parser in %s"%(line.strip(),self.guidfile))
355      else:
356        print("ERROR: No data in %s" %self.guidfile)
357        ERRORMSG.append("ERROR: No data in %s" %self.guidfile)
358    return guiddict
359
360  def guid_parser(self,guid):
361    if guid.upper() in self.guiddict:
362      return self.guiddict[guid.upper()]
363    else:
364      print("ERROR: GUID %s not found in file %s"%(guid, self.guidfile))
365      ERRORMSG.append("ERROR: GUID %s not found in file %s"%(guid, self.guidfile))
366      return guid
367
368class PATH(object):
369
370  def __init__(self,path):
371    self.path=path
372    self.rootdir=self.get_root_dir()
373    self.usefuldir=[]
374    self.lstinf = {}
375    for path in self.rootdir:
376      for o_root, o_dir, o_file in os.walk(os.path.join(path, "OUTPUT"), topdown=True, followlinks=False):
377        for INF in o_file:
378          if os.path.splitext(INF)[1] == '.inf':
379            for l_root, l_dir, l_file in os.walk(os.path.join(path, "DEBUG"), topdown=True,
380                               followlinks=False):
381              for LST in l_file:
382                if os.path.splitext(LST)[1] == '.lst':
383                  self.lstinf[os.path.join(l_root, LST)] = os.path.join(o_root, INF)
384                  self.usefuldir.append(path)
385
386  def get_root_dir(self):
387    rootdir=[]
388    for root,dir,file in os.walk(self.path,topdown=True,followlinks=False):
389      if "OUTPUT" in root:
390        updir=root.split("OUTPUT",1)[0]
391        rootdir.append(updir)
392    rootdir=list(set(rootdir))
393    return rootdir
394
395  def lst_inf(self):
396    return self.lstinf
397
398  def package(self):
399    package={}
400    package_re=re.compile(r'Packages\.\w+]\n(.*)',re.S)
401    for i in list(self.lstinf.values()):
402      with open(i,'r') as inf:
403        read=inf.read()
404      section=read.split('[')
405      for j in section:
406        p=package_re.findall(j)
407        if p:
408          package[i]=p[0].rstrip()
409    return package
410
411  def header(self,struct):
412    header={}
413    head_re = re.compile('typedef.*} %s;[\n]+(.*?)(?:typedef|formset)'%struct,re.M|re.S)
414    head_re2 = re.compile(r'#line[\s\d]+"(\S+h)"')
415    for i in list(self.lstinf.keys()):
416      with open(i,'r') as lst:
417        read = lst.read()
418      h = head_re.findall(read)
419      if h:
420        head=head_re2.findall(h[0])
421        if head:
422          format = head[0].replace('\\\\','/').replace('\\','/')
423          name =format.split('/')[-1]
424          head = self.makefile(name).replace('\\','/')
425          header[struct] = head
426    return header
427
428  def makefile(self,filename):
429    re_format = re.compile(r'DEBUG_DIR.*(?:\S+Pkg)\\(.*\\%s)'%filename)
430    for i in self.usefuldir:
431      with open(os.path.join(i,'Makefile'),'r') as make:
432        read = make.read()
433      dir = re_format.findall(read)
434      if dir:
435        return dir[0]
436
437class mainprocess(object):
438
439  def __init__(self,InputPath,Config,OutputPath):
440    self.init = 0xFCD00000
441    self.inputpath = os.path.abspath(InputPath)
442    self.outputpath = os.path.abspath(OutputPath)
443    self.LST = PATH(self.inputpath)
444    self.lst_dict = self.LST.lst_inf()
445    self.Config = Config
446    self.attribute_dict = {'0x3': 'NV, BS', '0x7': 'NV, BS, RT'}
447    self.guid = GUID(self.inputpath)
448    self.header={}
449
450  def main(self):
451    conf=Config(self.Config)
452    config_dict=conf.config_parser() #get {'0_0':[offset,name,guid,value,attribute]...,'1_0':....}
453    lst=parser_lst(list(self.lst_dict.keys()))
454    efi_dict=lst.efivarstore_parser() #get {name:struct} form lst file
455    keys=sorted(config_dict.keys())
456    all_struct=lst.struct()
457    stru_lst=lst.struct_lst()
458    title_list=[]
459    info_list=[]
460    header_list=[]
461    inf_list =[]
462    for i in stru_lst:
463      tmp = self.LST.header(i)
464      self.header.update(tmp)
465    for id_key in keys:
466      tmp_id=[id_key] #['0_0',[(struct,[name...]),(struct,[name...])]]
467      tmp_info={} #{name:struct}
468      for section in config_dict[id_key]:
469        c_offset,c_name,c_guid,c_value,c_attribute = section
470        if c_name in efi_dict:
471          struct = efi_dict[c_name]
472          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])
473          if struct in all_struct:
474            lstfile = stru_lst[struct]
475            struct_dict=all_struct[struct]
476            try:
477              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]])
478            except KeyError:
479              WARNING.append("Warning: No <HeaderFiles> for struct %s"%struct)
480              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]])
481            header_list.append(title2)
482          else:
483            struct_dict ={}
484            print("ERROR: Struct %s can't found in lst file" %struct)
485            ERRORMSG.append("ERROR: Struct %s can't found in lst file" %struct)
486          if c_offset in struct_dict:
487            offset_name=struct_dict[c_offset]
488            info = "%s%s.%s|%s\n"%(PCD_NAME,c_name,offset_name,c_value)
489            inf = "%s%s\n"%(PCD_NAME,c_name)
490            inf_list.append(inf)
491            tmp_info[info]=title
492          else:
493            print("ERROR: Can't find offset %s with struct name %s"%(c_offset,struct))
494            ERRORMSG.append("ERROR: Can't find offset %s with name %s"%(c_offset,struct))
495        else:
496          print("ERROR: Can't find name %s in lst file"%(c_name))
497          ERRORMSG.append("ERROR: Can't find name %s in lst file"%(c_name))
498      tmp_id.append(list(self.reverse_dict(tmp_info).items()))
499      id,tmp_title_list,tmp_info_list = self.read_list(tmp_id)
500      title_list +=tmp_title_list
501      info_list.append(tmp_info_list)
502    inf_list = self.del_repeat(inf_list)
503    header_list = self.plus(self.del_repeat(header_list))
504    title_all=list(set(title_list))
505    info_list = self.remove_bracket(self.del_repeat(info_list))
506    for i in range(len(info_list)-1,-1,-1):
507      if len(info_list[i]) == 0:
508        info_list.remove(info_list[i])
509    for i in (inf_list, title_all, header_list):
510      i.sort()
511    return keys,title_all,info_list,header_list,inf_list
512
513  def remove_bracket(self,List):
514    for i in List:
515      for j in i:
516        tmp = j.split("|")
517        if (('L"' in j) and ("[" in j)) or (tmp[1].strip() == '{0x0, 0x0}'):
518          tmp[0] = tmp[0][:tmp[0].index('[')]
519          List[List.index(i)][i.index(j)] = "|".join(tmp)
520        else:
521          List[List.index(i)][i.index(j)] = j
522    for i in List:
523      if type(i) == type([0,0]):
524        i.sort()
525    return List
526
527  def write_all(self):
528    title_flag=1
529    info_flag=1
530    if not os.path.isdir(self.outputpath):
531      os.makedirs(self.outputpath)
532    decwrite = write2file(os.path.join(self.outputpath,'StructurePcd.dec'))
533    dscwrite = write2file(os.path.join(self.outputpath,'StructurePcd.dsc'))
534    infwrite = write2file(os.path.join(self.outputpath, 'StructurePcd.inf'))
535    conf = Config(self.Config)
536    ids,title,info,header,inf=self.main()
537    decwrite.add2file(decstatement)
538    decwrite.add2file(header)
539    infwrite.add2file(infstatement)
540    infwrite.add2file(inf)
541    dscwrite.add2file(dscstatement)
542    for id in ids:
543      dscwrite.add2file(conf.eval_id(id))
544      if title_flag:
545        dscwrite.add2file(title)
546        title_flag=0
547      if len(info) == 1:
548        dscwrite.add2file(info)
549      elif len(info) == 2:
550        if info_flag:
551          dscwrite.add2file(info[0])
552          info_flag =0
553        else:
554          dscwrite.add2file(info[1])
555
556  def del_repeat(self,List):
557    if len(List) == 1 or len(List) == 0:
558      return List
559    else:
560      if type(List[0]) != type('xxx'):
561        alist=[]
562        for i in range(len(List)):
563          if i == 0:
564            alist.append(List[0])
565          else:
566            plist = []
567            for j in range(i):
568              plist += List[j]
569            alist.append(self.__del(list(set(plist)), List[i]))
570        return alist
571      else:
572        return list(set(List))
573
574
575  def __del(self,list1,list2):
576    return list(set(list2).difference(set(list1)))
577
578  def reverse_dict(self,dict):
579    data={}
580    for i in list(dict.items()):
581      if i[1] not in list(data.keys()):
582        data[i[1]]=[i[0]]
583      else:
584        data[i[1]].append(i[0])
585    return data
586
587  def read_list(self,list):
588    title_list=[]
589    info_list=[]
590    for i in list[1]:
591      title_list.append(i[0])
592      for j in i[1]:
593        info_list.append(j)
594    return list[0],title_list,info_list
595
596  def plus(self,list):
597    nums=[]
598    for i in list:
599      if type(i) != type([0]):
600        self.init += 1
601        num = "0x%01x" % self.init
602        j=i.replace('0xFCD00000',num.upper())
603        nums.append(j)
604    return nums
605
606class write2file(object):
607
608  def __init__(self,Output):
609    self.output=Output
610    self.text=''
611    if os.path.exists(self.output):
612      os.remove(self.output)
613
614  def add2file(self,content):
615    self.text = ''
616    with open(self.output,'a+') as file:
617      file.write(self.__gen(content))
618
619  def __gen(self,content):
620    if type(content) == type(''):
621      return content
622    elif type(content) == type([0,0])or type(content) == type((0,0)):
623      return self.__readlist(content)
624    elif type(content) == type({0:0}):
625      return self.__readdict(content)
626
627  def __readlist(self,list):
628    for i in list:
629      if type(i) == type([0,0])or type(i) == type((0,0)):
630        self.__readlist(i)
631      elif type(i) == type('') :
632        self.text +=i
633    return self.text
634
635  def __readdict(self,dict):
636    content=list(dict.items())
637    return self.__readlist(content)
638
639def stamp():
640  return datetime.datetime.now()
641
642def dtime(start,end,id=None):
643  if id:
644    pass
645    print("%s time:%s" % (id,str(end - start)))
646  else:
647    print("Total time:%s" %str(end-start)[:-7])
648
649
650def main():
651  start = stamp()
652  parser = argparse.ArgumentParser(prog = __prog__,
653                                   description = __description__ + __copyright__,
654                                   conflict_handler = 'resolve')
655  parser.add_argument('-v', '--version', action = 'version',version = __version__, help="show program's version number and exit")
656  parser.add_argument('-p', '--path', metavar='PATH', dest='path', help="platform build output directory")
657  parser.add_argument('-c', '--config',metavar='FILENAME', dest='config', help="firmware configuration file")
658  parser.add_argument('-o', '--outputdir', metavar='PATH', dest='output', help="output directoy")
659  options = parser.parse_args()
660  if options.config:
661    if options.path:
662      if options.output:
663        run = mainprocess(options.path, options.config, options.output)
664        print("Running...")
665        run.write_all()
666        if WARNING:
667          warning = list(set(WARNING))
668          for j in warning:
669            print(j)
670        if ERRORMSG:
671          ERROR = list(set(ERRORMSG))
672          with open("ERROR.log", 'w+') as error:
673            for i in ERROR:
674              error.write(i + '\n')
675          print("Some error find, error log in ERROR.log")
676        print('Finished, Output files in directory %s'%os.path.abspath(options.output))
677      else:
678        print('Error command, no output path, use -h for help')
679    else:
680      print('Error command, no build path input, use -h for help')
681  else:
682    print('Error command, no output file, use -h for help')
683  end = stamp()
684  dtime(start, end)
685
686if __name__ == '__main__':
687  main()
688