Subversion Repositories freemyipod

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
396 farthen 1
#!/usr/bin/env python
2
#
3
#
4
#    Copyright 2010 TheSeven, benedikt93, Farthen
5
#
6
#
427 farthen 7
#    This file is part of emCORE.
396 farthen 8
#
427 farthen 9
#    emCORE is free software: you can redistribute it and/or
396 farthen 10
#    modify it under the terms of the GNU General Public License as
11
#    published by the Free Software Foundation, either version 2 of the
12
#    License, or (at your option) any later version.
13
#
427 farthen 14
#    emCORE is distributed in the hope that it will be useful,
396 farthen 15
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
16
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
#    See the GNU General Public License for more details.
18
#
19
#    You should have received a copy of the GNU General Public License
427 farthen 20
#    along with emCORE.  If not, see <http://www.gnu.org/licenses/>.
396 farthen 21
#
22
#
23
 
24
"""
25
    This file includes some reusable functions and classes that might be useful
26
    to all python scripts
27
"""
28
 
29
import sys
505 farthen 30
from ctypes import *
31
from _ctypes import _SimpleCData
427 farthen 32
import libemcoredata
396 farthen 33
 
34
class Logger(object):
35
    """
501 farthen 36
        Simple stdout/stderr/file logger.
401 farthen 37
        Loglevel 3 is most verbose, Loglevel 0: Only log something if there is an error.
38
        Loglevel -1 means that nothing is logged.
501 farthen 39
        The write function doesn't care about the loglevel and always logs everything.
396 farthen 40
    """
501 farthen 41
    def __init__(self, loglevel = 2, target = "stderr", logfile = "tools.log"):
400 farthen 42
        """
43
            loglevel: Possible values: 0 (only errors), 1 (warnings), 2 (info,
44
                      recommended for production use), 3 and more (debug)
45
            logfile: File to log to if using the target = "file"
46
            target: Default logging target. Can be "stdout", "file" or "string"
47
        """
48
        self.loglevel = loglevel
49
        self.logfile = logfile
50
        self.target = target
396 farthen 51
 
501 farthen 52
    def write(self, text, indent = 0, target = None):
401 farthen 53
        if self.loglevel >= 0:
54
            if target is None: target = self.target
55
            text = (indent * " ") + text
56
            text = text.replace("\n", "\n" + (indent * " "), text.count("\n") - 1)
57
            if target == "stdout":
501 farthen 58
                sys.stderr.write(text)
59
            if target == "stderr":
60
                sys.stderr.write(text)
401 farthen 61
            elif target == "file":
62
                with open(self.logfile, 'a') as f:
63
                    f.write(text)
64
                    f.close()
65
            elif target == "string":
66
                return text
396 farthen 67
 
400 farthen 68
    def debug(self, text, indent = 0, target = None):
396 farthen 69
        if self.loglevel >= 3:
501 farthen 70
            self.write("DEBUG: " + text, indent, target)
396 farthen 71
 
400 farthen 72
    def info(self, text, indent = 0, target = None):
396 farthen 73
        if self.loglevel >= 2:
501 farthen 74
            self.write(text, indent, target)
396 farthen 75
 
400 farthen 76
    def warn(self, text, indent = 0, target = None):
396 farthen 77
        if self.loglevel >= 1:
501 farthen 78
            self.write("WARNING: " + text, indent, target)
396 farthen 79
 
400 farthen 80
    def error(self, text, indent = 0, target = None):
401 farthen 81
        if self.loglevel >= 0:
501 farthen 82
            self.write("ERROR: " + text, indent, target)
396 farthen 83
 
84
 
85
class Bunch(dict):
86
    """
87
        This is a dict whose items can also be accessed with
88
        bunchinstance.something.
89
    """
90
    def __init__(self, **kw):
91
        dict.__init__(self, kw)
92
        self.__dict__ = self
93
 
94
    def __getstate__(self):
95
        return self
96
 
97
    def __setstate__(self, state):
98
        self.update(state)
99
        self.__dict__ = self
100
 
101
 
505 farthen 102
class c_enum(_SimpleCData):
103
    """
104
        Resembles the enum datatype from C with an 8 bit size.
105
        Returns the associated string of a value with c_enum[i]
106
        Returns the current value of the associated value as c_enum.__repr__()
107
        Comparison operators work with strings and values at the same time.
108
 
109
        ATTENTION: You can not really see if this is initialized or not.
110
        If it is uninitialized it will return the first entry of the enum.
111
        While this may be circumvented by changing the default value to
112
        something else this will not work if the enum is placed inside a
113
        ctypes structure as the __init__() method will not be called then.
114
    """    
115
    _type_ = c_uint8._type_
116
 
117
    def __init__(self, value = 0):
118
        if type(value) == str:
119
            value = getattr(self, value)
120
        _SimpleCData.__init__(self, value)
121
        self[value]
122
 
123
    def __getattr__(self, name):
124
        if name == "value":
125
            return self.value
126
        for key, value in enumerate(self._fields_):
127
            if value == name:
128
                return key
129
 
130
    def __getitem__(self, lookupkey):
131
        for key, value in enumerate(self._fields_):
132
            if key == lookupkey:
133
                return value
134
        raise IndexError("Value %d not in range of possible enum values for %s!" % (lookupkey, self.__class__.__name__))
135
 
136
    def __str__(self):
137
        return self[self.value]
138
 
139
    def __repr__(self):
140
        return self.__str__()
141
 
142
    def __eq__(self, other):
143
        if type(other) == str:
144
            try: return getattr(self, other) == self.value
145
            except AttributeError: return False
146
        else:
147
            return self.value == other
148
 
149
    def __lt__(self, other):
150
        if type(other) == str:
151
            try: return self.value < getattr(self, other)
152
            except AttributeError: return False
153
        else:
154
            return self.value < other
155
 
156
    def __gt__(self, other):
157
        if type(other) == str:
158
            try: return  self.value > getattr(self, other)
159
            except AttributeError: return False
160
        else:
161
            return self.value > other
162
 
163
    def __le__(self, other):
164
        if self.value == other or self.value < other:
165
            return True
166
        return False
167
 
168
    def __ge__(self, other):
169
        if self.value == other or self.value > other:
170
            return True
171
        return False
172
 
173
    def __ne__(self, other):
174
        if self.value == other:
175
            return False
176
        return True
177
 
178
 
179
class ExtendedCStruct(LittleEndianStructure):
180
    """
181
        This is a subclass of the LittleEndianStructure.
182
        It implements functions to easily convert
183
        structures to/from strings and Bunches.
184
    """
185
    def _from_bunch(self, bunch):
186
        for field, _ in self._fields_:
187
            if field in bunch:
188
                setattr(self, field, getattr(bunch, field))
189
 
190
    def _to_bunch(self):
191
        return Bunch(**{field: getattr(self, field) for field, _ in self._fields_})
192
 
193
    def _from_string(self, string):
194
        memmove(addressof(self), string, sizeof(self))
195
 
196
    def _to_string(self):
197
        return string_at(addressof(self), sizeof(self))
198
 
199
 
200
 
396 farthen 201
class Error(Exception):
202
    def __init__(self, value=None):
203
        self.value = value
204
    def __str__(self):
205
        if self.value != None:
206
            return repr(self.value)
207
 
208
 
398 farthen 209
def gethwname(id):
210
    try:
427 farthen 211
        hwtype = libemcoredata.hwtypes[id]
398 farthen 212
    except KeyError:
213
        hwtype = "UNKNOWN (ID = " + self._hex(id) + ")"
214
    return hwtype
215
 
216
 
396 farthen 217
def trimdoc(docstring):
218
    """
219
        Trims whitespace from docstrings
220
    """
221
    if not docstring:
222
        return ''
223
    # Convert tabs to spaces (following the normal Python rules)
224
    # and split into a list of lines:
225
    lines = docstring.expandtabs().splitlines()
226
    # Determine minimum indentation (first line doesn't count):
227
    indent = sys.maxint
228
    for line in lines[1:]:
229
        stripped = line.lstrip()
230
        if stripped:
231
            indent = min(indent, len(line) - len(stripped))
232
    # Remove indentation (first line is special):
233
    trimmed = [lines[0].strip()]
234
    if indent < sys.maxint:
235
        for line in lines[1:]:
236
            trimmed.append(line[indent:].rstrip())
237
    # Strip off trailing and leading blank lines:
238
    while trimmed and not trimmed[-1]:
239
        trimmed.pop()
240
    while trimmed and not trimmed[0]:
241
        trimmed.pop(0)
242
    # Return a single string:
243
    return '\n'.join(trimmed)
244
 
245
 
246
def getfuncdoc(funcdict):
247
    """
248
        Extracts important information from a dict of functions like the
249
        docstring and arguments and returns them in a human readable format
250
    """
251
    import inspect
252
    import re
253
    functions = Bunch()
254
    for function in funcdict:
255
        function = funcdict[function].func
256
        docinfo = Bunch()
257
        name = function.__name__
258
        args = inspect.getargspec(function)[0]
259
        docinfo['varargs'] = False
260
        if inspect.getargspec(function)[1]:
261
            docinfo['varargs'] = True
262
        kwargvalues = inspect.getargspec(function)[3]
263
        kwargs = Bunch()
264
        if args:
265
            if kwargvalues:
266
                argnum = len(args) - len(kwargvalues)
267
                kwargnum = len(kwargvalues)
268
                kwargs = dict(zip(args[argnum:], kwargvalues))
269
            else:
270
                argnum = len(args)
271
        else:
272
            argnum = 0
273
        docinfo['args'] = args[1:argnum]
274
        docinfo['kwargs'] = kwargs
275
        if function.__doc__:
276
            # strip unneccessary whitespace
277
            docinfo['documentation'] = trimdoc(function.__doc__)
278
        else:
279
            docinfo['documentation'] = None
280
        functions[name] = docinfo
281
    return functions
282
 
283
 
284
def gendoc(funcdict, indentwidth = 4, logtarget = "string"):
285
    logger = Logger()
286
    doc = getfuncdoc(funcdict)
287
    ret = ""
288
    for function in sorted(doc.items()):
289
        function = function[0]
290
        ret += logger.log("def " + function + "(", target = logtarget)
291
        counter = 0
292
        if doc[function]['args']:
293
            for arg in doc[function]['args']:
294
                if counter > 0:
295
                    sys.stdout.write(", ")
296
                counter += 1
297
                ret += logger.log(arg, target = logtarget)
298
        if doc[function]['kwargs']:
299
            for kwarg, kwargvalue in doc[function]['kwargs'].items():
300
                if counter > 0:
301
                    sys.stdout.write(", ")
302
                counter += 1
303
                ret += logger.log(kwarg + "=" + str(kwargvalue), target = logtarget)
304
        if doc[function]['varargs']:
305
            ret += logger.log("*argv", target = logtarget)
306
        ret += logger.log("):\n", target = logtarget)
307
        if doc[function]['documentation']:
308
            ret += logger.log("\"\"\"\n", indent = indentwidth, target = logtarget)
309
            ret += logger.log(trimdoc(doc[function]['documentation']) + "\n", indent = 2 * indentwidth, target = logtarget)
310
            ret += logger.log("\"\"\"\n", indent = indentwidth, target = logtarget)
311
        ret += logger.log("\n", target = logtarget)
312
    return ret