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
 
514 farthen 142
    def __int__(self):
143
        return self.value
144
 
505 farthen 145
    def __eq__(self, other):
146
        if type(other) == str:
147
            try: return getattr(self, other) == self.value
148
            except AttributeError: return False
149
        else:
150
            return self.value == other
151
 
152
    def __lt__(self, other):
153
        if type(other) == str:
154
            try: return self.value < getattr(self, other)
155
            except AttributeError: return False
156
        else:
157
            return self.value < other
158
 
159
    def __gt__(self, other):
160
        if type(other) == str:
161
            try: return  self.value > getattr(self, other)
162
            except AttributeError: return False
163
        else:
164
            return self.value > other
165
 
166
    def __le__(self, other):
167
        if self.value == other or self.value < other:
168
            return True
169
        return False
170
 
171
    def __ge__(self, other):
172
        if self.value == other or self.value > other:
173
            return True
174
        return False
175
 
176
    def __ne__(self, other):
177
        if self.value == other:
178
            return False
179
        return True
180
 
181
 
182
class ExtendedCStruct(LittleEndianStructure):
183
    """
184
        This is a subclass of the LittleEndianStructure.
185
        It implements functions to easily convert
186
        structures to/from strings and Bunches.
187
    """
188
    def _from_bunch(self, bunch):
189
        for field, _ in self._fields_:
190
            if field in bunch:
191
                setattr(self, field, getattr(bunch, field))
192
 
193
    def _to_bunch(self):
510 farthen 194
        bunch = Bunch()
195
        for field, _ in self._fields_:
196
            setattr(bunch, field, getattr(self, field))
197
        return bunch
505 farthen 198
 
199
    def _from_string(self, string):
200
        memmove(addressof(self), string, sizeof(self))
201
 
202
    def _to_string(self):
203
        return string_at(addressof(self), sizeof(self))
204
 
205
 
206
 
396 farthen 207
class Error(Exception):
208
    def __init__(self, value=None):
209
        self.value = value
210
    def __str__(self):
211
        if self.value != None:
212
            return repr(self.value)
213
 
214
 
398 farthen 215
def gethwname(id):
216
    try:
427 farthen 217
        hwtype = libemcoredata.hwtypes[id]
398 farthen 218
    except KeyError:
219
        hwtype = "UNKNOWN (ID = " + self._hex(id) + ")"
220
    return hwtype
221
 
222
 
396 farthen 223
def trimdoc(docstring):
224
    """
225
        Trims whitespace from docstrings
226
    """
227
    if not docstring:
228
        return ''
229
    # Convert tabs to spaces (following the normal Python rules)
230
    # and split into a list of lines:
231
    lines = docstring.expandtabs().splitlines()
232
    # Determine minimum indentation (first line doesn't count):
233
    indent = sys.maxint
234
    for line in lines[1:]:
235
        stripped = line.lstrip()
236
        if stripped:
237
            indent = min(indent, len(line) - len(stripped))
238
    # Remove indentation (first line is special):
239
    trimmed = [lines[0].strip()]
240
    if indent < sys.maxint:
241
        for line in lines[1:]:
242
            trimmed.append(line[indent:].rstrip())
243
    # Strip off trailing and leading blank lines:
244
    while trimmed and not trimmed[-1]:
245
        trimmed.pop()
246
    while trimmed and not trimmed[0]:
247
        trimmed.pop(0)
248
    # Return a single string:
249
    return '\n'.join(trimmed)
250
 
251
 
252
def getfuncdoc(funcdict):
253
    """
254
        Extracts important information from a dict of functions like the
255
        docstring and arguments and returns them in a human readable format
256
    """
257
    import inspect
258
    import re
259
    functions = Bunch()
260
    for function in funcdict:
261
        function = funcdict[function].func
262
        docinfo = Bunch()
263
        name = function.__name__
264
        args = inspect.getargspec(function)[0]
265
        docinfo['varargs'] = False
266
        if inspect.getargspec(function)[1]:
267
            docinfo['varargs'] = True
268
        kwargvalues = inspect.getargspec(function)[3]
269
        kwargs = Bunch()
270
        if args:
271
            if kwargvalues:
272
                argnum = len(args) - len(kwargvalues)
273
                kwargnum = len(kwargvalues)
274
                kwargs = dict(zip(args[argnum:], kwargvalues))
275
            else:
276
                argnum = len(args)
277
        else:
278
            argnum = 0
279
        docinfo['args'] = args[1:argnum]
280
        docinfo['kwargs'] = kwargs
281
        if function.__doc__:
282
            # strip unneccessary whitespace
283
            docinfo['documentation'] = trimdoc(function.__doc__)
284
        else:
285
            docinfo['documentation'] = None
286
        functions[name] = docinfo
287
    return functions
288
 
289
 
290
def gendoc(funcdict, indentwidth = 4, logtarget = "string"):
291
    logger = Logger()
292
    doc = getfuncdoc(funcdict)
293
    ret = ""
294
    for function in sorted(doc.items()):
295
        function = function[0]
296
        ret += logger.log("def " + function + "(", target = logtarget)
297
        counter = 0
298
        if doc[function]['args']:
299
            for arg in doc[function]['args']:
300
                if counter > 0:
301
                    sys.stdout.write(", ")
302
                counter += 1
303
                ret += logger.log(arg, target = logtarget)
304
        if doc[function]['kwargs']:
305
            for kwarg, kwargvalue in doc[function]['kwargs'].items():
306
                if counter > 0:
307
                    sys.stdout.write(", ")
308
                counter += 1
309
                ret += logger.log(kwarg + "=" + str(kwargvalue), target = logtarget)
310
        if doc[function]['varargs']:
311
            ret += logger.log("*argv", target = logtarget)
312
        ret += logger.log("):\n", target = logtarget)
313
        if doc[function]['documentation']:
314
            ret += logger.log("\"\"\"\n", indent = indentwidth, target = logtarget)
315
            ret += logger.log(trimdoc(doc[function]['documentation']) + "\n", indent = 2 * indentwidth, target = logtarget)
316
            ret += logger.log("\"\"\"\n", indent = indentwidth, target = logtarget)
317
        ret += logger.log("\n", target = logtarget)
318
    return ret