event_log_tags.py revision 9bd4962af87257c6a97e9026af7e4764394412c2
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
17import re
18import sys
19
20class 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
31class 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        try:
79          tag = int(parts[0])
80        except ValueError:
81          self.AddError("\"%s\" isn't an integer tag" % (parts[0],))
82          continue
83
84        tagname = parts[1]
85        if len(parts) == 3:
86          description = parts[2]
87        else:
88          description = None
89
90        self.tags.append(Tag(tag, tagname, description,
91                             self.filename, self.linenum))
92    except (IOError, OSError), e:
93      self.AddError(str(e))
94
95
96def WriteOutput(output_file, data):
97  """Write 'data' to the given output filename (which may be None to
98  indicate stdout).  Emit an error message and die on any failure.
99  'data' may be a string or a StringIO object."""
100  if not isinstance(data, str):
101    data = data.getvalue()
102  try:
103    if output_file is None:
104      out = sys.stdout
105      output_file = "<stdout>"
106    else:
107      out = open(output_file, "wb")
108    out.write(data)
109    out.close()
110  except (IOError, OSError), e:
111    print >> sys.stderr, "failed to write %s: %s" % (output_file, e)
112    sys.exit(1)
113