OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/python2.4 |
| 2 # Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. |
| 5 |
| 6 '''Item formatters for RC headers. |
| 7 ''' |
| 8 |
| 9 import re |
| 10 |
| 11 from grit.format import interface |
| 12 from grit import exception |
| 13 from grit import util |
| 14 |
| 15 from grit.extern import FP |
| 16 |
| 17 |
| 18 class TopLevel(interface.ItemFormatter): |
| 19 '''Writes the necessary preamble for a resource.h file.''' |
| 20 |
| 21 def Format(self, item, lang='', begin_item=True, output_dir='.'): |
| 22 if not begin_item: |
| 23 return '' |
| 24 else: |
| 25 header_string = '''// Copyright (c) Google Inc. %d |
| 26 // All rights reserved. |
| 27 // This file is automatically generated by GRIT. Do not edit. |
| 28 |
| 29 #pragma once |
| 30 ''' % (util.GetCurrentYear()) |
| 31 # Check for emit nodes under the rc_header. If any emit node |
| 32 # is present, we assume it means the GRD file wants to override |
| 33 # the default header, with no includes. |
| 34 for output_node in item.GetOutputFiles(): |
| 35 if output_node.GetType() == 'rc_header': |
| 36 for child in output_node.children: |
| 37 if child.name == 'emit': |
| 38 if child.attrs['emit_type'] == 'prepend': |
| 39 return header_string |
| 40 # else print out the default header with include |
| 41 return header_string + ''' |
| 42 #include <atlres.h> |
| 43 |
| 44 ''' |
| 45 |
| 46 |
| 47 class EmitAppender(interface.ItemFormatter): |
| 48 '''Adds the content of the <emit> nodes to the RC header file.''' |
| 49 |
| 50 def Format(self, item, lang='', begin_item=True, output_dir='.'): |
| 51 if not begin_item: |
| 52 return '' |
| 53 else: |
| 54 return '%s\n' % (item.GetCdata()) |
| 55 |
| 56 class Item(interface.ItemFormatter): |
| 57 '''Writes the #define line(s) for a single item in a resource.h file. If |
| 58 your node has multiple IDs that need to be defined (as is the case e.g. for |
| 59 dialog resources) it should define a function GetTextIds(self) that returns |
| 60 a list of textual IDs (strings). Otherwise the formatter will use the |
| 61 'name' attribute of the node.''' |
| 62 |
| 63 # All IDs allocated so far, mapped to the textual ID they represent. |
| 64 # Used to detect and resolve collisions. |
| 65 ids_ = {} |
| 66 |
| 67 # All textual IDs allocated so far, mapped to the numerical ID they |
| 68 # represent. Used when literal IDs are being defined in the 'identifiers' |
| 69 # section of the GRD file to define other message IDs. |
| 70 tids_ = {} |
| 71 |
| 72 def _VerifyId(self, id, tid, msg_if_error): |
| 73 if id in self.ids_ and self.ids_[id] != tid: |
| 74 raise exception.IdRangeOverlap(msg_if_error + |
| 75 '\nUse the first_id attribute on grouping nodes (<structures>,\n' |
| 76 '<includes>, <messages> and <ids>) to fix this problem.') |
| 77 if id < 101: |
| 78 print ('WARNING: Numeric resource IDs should be greater than 100 to avoid\
n' |
| 79 'conflicts with system-defined resource IDs.') |
| 80 |
| 81 def Format(self, item, lang='', begin_item=True, output_dir='.'): |
| 82 if not begin_item: |
| 83 return '' |
| 84 |
| 85 # Resources that use the RES protocol don't need |
| 86 # any numerical ids generated, so we skip them altogether. |
| 87 # This is accomplished by setting the flag 'generateid' to false |
| 88 # in the GRD file. |
| 89 if 'generateid' in item.attrs: |
| 90 if item.attrs['generateid'] == 'false': |
| 91 return '' |
| 92 |
| 93 text_ids = item.GetTextualIds() |
| 94 |
| 95 # We consider the "parent" of the item to be the GroupingNode containing |
| 96 # the item, as its immediate parent may be an <if> node. |
| 97 item_parent = item.parent |
| 98 import grit.node.empty |
| 99 while item_parent and not isinstance(item_parent, |
| 100 grit.node.empty.GroupingNode): |
| 101 item_parent = item_parent.parent |
| 102 |
| 103 lines = [] |
| 104 for tid in text_ids: |
| 105 if util.SYSTEM_IDENTIFIERS.match(tid): |
| 106 # Don't emit a new ID for predefined IDs |
| 107 continue |
| 108 |
| 109 # Some identifier nodes can provide their own id, |
| 110 # and we use that id in the generated header in that case. |
| 111 if hasattr(item, 'GetId') and item.GetId(): |
| 112 id = long(item.GetId()) |
| 113 |
| 114 elif ('offset' in item.attrs and item_parent and |
| 115 'first_id' in item_parent.attrs and item_parent.attrs['first_id'] !=
''): |
| 116 offset_text = item.attrs['offset'] |
| 117 parent_text = item_parent.attrs['first_id'] |
| 118 |
| 119 try: |
| 120 offset_id = long(offset_text) |
| 121 except ValueError: |
| 122 offset_id = self.tids_[offset_text] |
| 123 |
| 124 try: |
| 125 parent_id = long(parent_text) |
| 126 except ValueError: |
| 127 parent_id = self.tids_[parent_text] |
| 128 |
| 129 id = parent_id + offset_id |
| 130 |
| 131 # We try to allocate IDs sequentially for blocks of items that might |
| 132 # be related, for instance strings in a stringtable (as their IDs might be |
| 133 # used e.g. as IDs for some radio buttons, in which case the IDs must |
| 134 # be sequential). |
| 135 # |
| 136 # We do this by having the first item in a section store its computed ID |
| 137 # (computed from a fingerprint) in its parent object. Subsequent children |
| 138 # of the same parent will then try to get IDs that sequentially follow |
| 139 # the currently stored ID (on the parent) and increment it. |
| 140 elif not item_parent or not hasattr(item_parent, '_last_id_'): |
| 141 # First check if the starting ID is explicitly specified by the parent. |
| 142 if (item_parent and 'first_id' in item_parent.attrs and |
| 143 item_parent.attrs['first_id'] != ''): |
| 144 id = long(item_parent.attrs['first_id']) |
| 145 self._VerifyId(id, tid, |
| 146 'Explicitly specified numeric first_id %d conflicts with one of the\
n' |
| 147 'ID ranges already used.' % id) |
| 148 else: |
| 149 # Automatically generate the ID based on the first clique from the |
| 150 # first child of the first child node of our parent (i.e. when we |
| 151 # first get to this location in the code). |
| 152 |
| 153 # According to |
| 154 # http://msdn.microsoft.com/en-us/library/t2zechd4(VS.71).aspx |
| 155 # the safe usable range for resource IDs in Windows is from decimal |
| 156 # 101 to 0x7FFF. |
| 157 |
| 158 id = FP.UnsignedFingerPrint(tid) |
| 159 id = id % (0x7FFF - 101) |
| 160 id += 101 |
| 161 |
| 162 self._VerifyId(id, tid, |
| 163 'Automatic (fingerprint-based) numeric ID for %s (%d) overlapped\n' |
| 164 'with a previously allocated range.' % (tid, id)) |
| 165 |
| 166 if item_parent: |
| 167 item_parent._last_id_ = id |
| 168 else: |
| 169 assert hasattr(item_parent, '_last_id_') |
| 170 id = item_parent._last_id_ = item_parent._last_id_ + 1 |
| 171 self._VerifyId(id, tid, |
| 172 'Wanted to make numeric value for ID %s (%d) follow the numeric value
of\n' |
| 173 'the previous ID in the .grd file, but it was already used.' % (tid, i
d)) |
| 174 |
| 175 if tid not in self.ids_.values(): |
| 176 self.ids_[id] = tid |
| 177 self.tids_[tid] = id |
| 178 lines.append('#define %s %d\n' % (tid, id)) |
| 179 return ''.join(lines) |
| 180 |
OLD | NEW |