Home | History | Annotate | Download | only in tools
      1 # Copyright (C) 2009 The Android Open Source Project
      2 #
      3 # Licensed under the Apache License, Version 2.0 (the "License");
      4 # you may not use this file except in compliance with the License.
      5 # You may obtain a copy of the License at
      6 #
      7 #      http://www.apache.org/licenses/LICENSE-2.0
      8 #
      9 # Unless required by applicable law or agreed to in writing, software
     10 # distributed under the License is distributed on an "AS IS" BASIS,
     11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 # See the License for the specific language governing permissions and
     13 # limitations under the License.
     14 
     15 """A module for reading and parsing event-log-tags files."""
     16 
     17 import re
     18 import sys
     19 
     20 class Tag(object):
     21   __slots__ = ["tagnum", "tagname", "description", "filename", "linenum"]
     22 
     23   def __init__(self, tagnum, tagname, description, filename, linenum):
     24     self.tagnum = tagnum
     25     self.tagname = tagname
     26     self.description = description
     27     self.filename = filename
     28     self.linenum = linenum
     29 
     30 
     31 class TagFile(object):
     32   """Read an input event-log-tags file."""
     33   def AddError(self, msg, linenum=None):
     34     if linenum is None:
     35       linenum = self.linenum
     36     self.errors.append((self.filename, linenum, msg))
     37 
     38   def AddWarning(self, msg, linenum=None):
     39     if linenum is None:
     40       linenum = self.linenum
     41     self.warnings.append((self.filename, linenum, msg))
     42 
     43   def __init__(self, filename, file_object=None):
     44     """'filename' is the name of the file (included in any error
     45     messages).  If 'file_object' is None, 'filename' will be opened
     46     for reading."""
     47     self.errors = []
     48     self.warnings = []
     49     self.tags = []
     50     self.options = {}
     51 
     52     self.filename = filename
     53     self.linenum = 0
     54 
     55     if file_object is None:
     56       try:
     57         file_object = open(filename, "rb")
     58       except (IOError, OSError), e:
     59         self.AddError(str(e))
     60         return
     61 
     62     try:
     63       for self.linenum, line in enumerate(file_object):
     64         self.linenum += 1
     65 
     66         line = line.strip()
     67         if not line or line[0] == '#': continue
     68         parts = re.split(r"\s+", line, 2)
     69 
     70         if len(parts) < 2:
     71           self.AddError("failed to parse \"%s\"" % (line,))
     72           continue
     73 
     74         if parts[0] == "option":
     75           self.options[parts[1]] = parts[2:]
     76           continue
     77 
     78         if parts[0] == "?":
     79           tag = None
     80         else:
     81           try:
     82             tag = int(parts[0])
     83           except ValueError:
     84             self.AddError("\"%s\" isn't an integer tag or '?'" % (parts[0],))
     85             continue
     86 
     87         tagname = parts[1]
     88         if len(parts) == 3:
     89           description = parts[2]
     90         else:
     91           description = None
     92 
     93         if description:
     94           # EventLog.java checks that the description field is
     95           # surrounded by parens, so we should too (to avoid a runtime
     96           # crash from badly-formatted descriptions).
     97           if not re.match(r"\(.*\)\s*$", description):
     98             self.AddError("tag \"%s\" has unparseable description" % (tagname,))
     99             continue
    100 
    101         self.tags.append(Tag(tag, tagname, description,
    102                              self.filename, self.linenum))
    103     except (IOError, OSError), e:
    104       self.AddError(str(e))
    105 
    106 
    107 def BooleanFromString(s):
    108   """Interpret 's' as a boolean and return its value.  Raise
    109   ValueError if it's not something we can interpret as true or
    110   false."""
    111   s = s.lower()
    112   if s in ("true", "t", "1", "on", "yes", "y"):
    113     return True
    114   if s in ("false", "f", "0", "off", "no", "n"):
    115     return False
    116   raise ValueError("'%s' not a valid boolean" % (s,))
    117 
    118 
    119 def WriteOutput(output_file, data):
    120   """Write 'data' to the given output filename (which may be None to
    121   indicate stdout).  Emit an error message and die on any failure.
    122   'data' may be a string or a StringIO object."""
    123   if not isinstance(data, str):
    124     data = data.getvalue()
    125   try:
    126     if output_file is None:
    127       out = sys.stdout
    128       output_file = "<stdout>"
    129     else:
    130       out = open(output_file, "wb")
    131     out.write(data)
    132     out.close()
    133   except (IOError, OSError), e:
    134     print >> sys.stderr, "failed to write %s: %s" % (output_file, e)
    135     sys.exit(1)
    136