File indexing completed on 2024-05-05 17:01:41
0001 """Library code for language-independent D-Bus-related code generation. 0002 0003 The master copy of this library is in the telepathy-glib repository - 0004 please make any changes there. 0005 """ 0006 0007 # Copyright (C) 2006-2008 Collabora Limited 0008 # 0009 # This library is free software; you can redistribute it and/or 0010 # modify it under the terms of the GNU Lesser General Public 0011 # License as published by the Free Software Foundation; either 0012 # version 2.1 of the License, or (at your option) any later version. 0013 # 0014 # This library is distributed in the hope that it will be useful, 0015 # but WITHOUT ANY WARRANTY; without even the implied warranty of 0016 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0017 # Lesser General Public License for more details. 0018 # 0019 # You should have received a copy of the GNU Lesser General Public 0020 # License along with this library; if not, write to the Free Software 0021 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 0022 0023 0024 from string import ascii_letters, digits 0025 0026 0027 NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" 0028 0029 _ASCII_ALNUM = ascii_letters + digits 0030 0031 0032 def cmp_by_name(node1, node2): 0033 return cmp(node1.getAttributeNode("name").nodeValue, 0034 node2.getAttributeNode("name").nodeValue) 0035 0036 0037 def escape_as_identifier(identifier): 0038 """Escape the given string to be a valid D-Bus object path or service 0039 name component, using a reversible encoding to ensure uniqueness. 0040 0041 The reversible encoding is as follows: 0042 0043 * The empty string becomes '_' 0044 * Otherwise, each non-alphanumeric character is replaced by '_' plus 0045 two lower-case hex digits; the same replacement is carried out on 0046 the first character, if it's a digit 0047 """ 0048 # '' -> '_' 0049 if not identifier: 0050 return '_' 0051 0052 # A bit of a fast path for strings which are already OK. 0053 # We deliberately omit '_' because, for reversibility, that must also 0054 # be escaped. 0055 if (identifier.strip(_ASCII_ALNUM) == '' and 0056 identifier[0] in ascii_letters): 0057 return identifier 0058 0059 # The first character may not be a digit 0060 if identifier[0] not in ascii_letters: 0061 ret = ['_%02x' % ord(identifier[0])] 0062 else: 0063 ret = [identifier[0]] 0064 0065 # Subsequent characters may be digits or ASCII letters 0066 for c in identifier[1:]: 0067 if c in _ASCII_ALNUM: 0068 ret.append(c) 0069 else: 0070 ret.append('_%02x' % ord(c)) 0071 0072 return ''.join(ret) 0073 0074 0075 def get_by_path(element, path): 0076 branches = path.split('/') 0077 branch = branches[0] 0078 0079 # Is the current branch an attribute, if so, return the attribute value 0080 if branch[0] == '@': 0081 return element.getAttribute(branch[1:]) 0082 0083 # Find matching children for the branch 0084 children = [] 0085 if branch == '..': 0086 children.append(element.parentNode) 0087 else: 0088 for x in element.childNodes: 0089 if x.localName == branch: 0090 children.append(x) 0091 0092 ret = [] 0093 # If this is not the last path element, recursively gather results from 0094 # children 0095 if len(branches) > 1: 0096 for x in children: 0097 add = get_by_path(x, '/'.join(branches[1:])) 0098 if isinstance(add, list): 0099 ret += add 0100 else: 0101 return add 0102 else: 0103 ret = children 0104 0105 return ret 0106 0107 0108 def get_docstring(element): 0109 docstring = None 0110 for x in element.childNodes: 0111 if x.namespaceURI == NS_TP and x.localName == 'docstring': 0112 docstring = x 0113 if docstring is not None: 0114 docstring = docstring.toxml().replace('\n', ' ').strip() 0115 if docstring.startswith('<tp:docstring>'): 0116 docstring = docstring[14:].lstrip() 0117 if docstring.endswith('</tp:docstring>'): 0118 docstring = docstring[:-15].rstrip() 0119 if docstring in ('<tp:docstring/>', ''): 0120 docstring = '' 0121 return docstring 0122 0123 def get_deprecated(element): 0124 text = [] 0125 for x in element.childNodes: 0126 if hasattr(x, 'data'): 0127 text.append(x.data.replace('\n', ' ').strip()) 0128 else: 0129 # This caters for tp:dbus-ref elements, but little else. 0130 if x.childNodes and hasattr(x.childNodes[0], 'data'): 0131 text.append(x.childNodes[0].data.replace('\n', ' ').strip()) 0132 return ' '.join(text) 0133 0134 def get_descendant_text(element_or_elements): 0135 if not element_or_elements: 0136 return '' 0137 if isinstance(element_or_elements, list): 0138 return ''.join(map(get_descendant_text, element_or_elements)) 0139 parts = [] 0140 for x in element_or_elements.childNodes: 0141 if x.nodeType == x.TEXT_NODE: 0142 parts.append(x.nodeValue) 0143 elif x.nodeType == x.ELEMENT_NODE: 0144 parts.append(get_descendant_text(x)) 0145 else: 0146 pass 0147 return ''.join(parts) 0148 0149 0150 class _SignatureIter: 0151 """Iterator over a D-Bus signature. Copied from dbus-python 0.71 so we 0152 can run genginterface in a limited environment with only Python 0153 (like Scratchbox). 0154 """ 0155 def __init__(self, string): 0156 self.remaining = string 0157 0158 def next(self): 0159 if self.remaining == '': 0160 raise StopIteration 0161 0162 signature = self.remaining 0163 block_depth = 0 0164 block_type = None 0165 end = len(signature) 0166 0167 for marker in range(0, end): 0168 cur_sig = signature[marker] 0169 0170 if cur_sig == 'a': 0171 pass 0172 elif cur_sig == '{' or cur_sig == '(': 0173 if block_type == None: 0174 block_type = cur_sig 0175 0176 if block_type == cur_sig: 0177 block_depth = block_depth + 1 0178 0179 elif cur_sig == '}': 0180 if block_type == '{': 0181 block_depth = block_depth - 1 0182 0183 if block_depth == 0: 0184 end = marker 0185 break 0186 0187 elif cur_sig == ')': 0188 if block_type == '(': 0189 block_depth = block_depth - 1 0190 0191 if block_depth == 0: 0192 end = marker 0193 break 0194 0195 else: 0196 if block_depth == 0: 0197 end = marker 0198 break 0199 0200 end = end + 1 0201 self.remaining = signature[end:] 0202 return Signature(signature[0:end]) 0203 0204 0205 class Signature(str): 0206 """A string, iteration over which is by D-Bus single complete types 0207 rather than characters. 0208 """ 0209 def __iter__(self): 0210 return _SignatureIter(self) 0211 0212 0213 def xml_escape(s): 0214 s = s.replace('&', '&').replace("'", ''').replace('"', '"') 0215 return s.replace('<', '<').replace('>', '>')