source: SHX/trunk/src/SeismicHandler/core/shlib.py @ 153

Revision 153, 14.8 KB checked in by marcus, 14 years ago (diff)
  • final renaming Events to Messages
  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Rev Id Date
Line 
1# -*- coding: utf-8 -*-
2#
3# Copyright (C) 2008-2010 Marcus Walther (walther@szgrf.bgr.de)
4#
5# This file is part of Seismic Handler eXtended (SHX)
6# Full details can be found at project website http://www.seismic-handler.org/
7#
8# SHX is free software; you can redistribute it and/or modify
9# it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE as published by
10# the Free Software Foundation; either version 3 of the License, or
11# (at your option) any later version.
12#
13# SHX is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16# GNU Lesser General Public License for more details.
17#
18# You should have received a copy of the GNU Lesser General Public License
19# along with SHX (see license.txt); if not, write to the Free Software
20# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
21
22"""wrapper for seismic handler c library
23
24   - implemented as multiton (which does not work at the moment, because c
25     library is accessed as shared library, which can only loaded once into
26     one process
27   - maybe this will be changed later using parallel processing methods"""
28
29import ctypes as C
30import sys
31import os
32from copy import copy
33from StringIO import StringIO
34
35from SeismicHandler.core.log import logging
36from SeismicHandler.core.error import MultipleLibError, CommandStreamError, GotoTargetNotFoundError, CommandNotSuccessfulError
37from SeismicHandler.config.options import environment
38from SeismicHandler.core.shheaders import LINELENGTH, NOERROR, PARAM, CAPCNV, EMPTYVALUES
39from SeismicHandler.core.modules.Messages import MessageService, Message
40
41logger = logging.getLogger("core.shlib")
42
43class shlib(object):
44    _instances = {}
45    _active = ""
46
47    def __new__(cls, id="_standard", *args, **kwargs):
48        """ensure single instance with identifier "xyz"
49
50           - requested instance will be set as active"""
51
52        # issue regarding static vars not solved, so raise exception
53        if id != "_standard":
54            raise MultipleLibError
55
56        if not id in cls._instances:
57            cls._instances[id] = object.__new__(cls)
58
59        cls._active = id
60
61        return cls._instances[id]
62
63    def __init__(self, *args, **kwargs):
64        if not "sh" in self.__dict__:
65            # load shared lib (once per identifier)
66
67            try:
68                self.sh = C.CDLL(os.path.join(environment["root"], "libshc.so"))
69                logger.debug(self.sh)
70
71            except Exception, e:
72                logger.critical(("error loading shared lib", e))
73                sys.exit(1)
74
75            self._init()
76
77    def _init(self):
78        """start up setup of shlib"""
79
80        slib = self.sh
81
82        # somewhat needless, since c lib doesn't deal which command line parameters
83        status= C.c_int()
84        CSTR_ARRAY = C.c_char_p * 1
85        argv = CSTR_ARRAY("")
86
87        slib.GpReadParfile()
88        slib.se_initialize(len(argv), argv, C.byref(status))
89
90        if status.value == NOERROR:
91            logger.debug("init of shared lib id %s succeeded" % self._active)
92        else:
93            logger.critical("init of shared lib id %s failed" % self._active)
94            sys.exit(2)
95
96        self._startup()
97
98        idxu = Message(MessageService.INFOIDXUPDATE)
99        MessageService.subscribe(idxu, self._readIdxStructure)
100        MessageService.trigger(idxu)
101
102    def _readIdxStructure(self, *args, **kwargs):
103        idxlist = {
104                   "long": C.c_long,
105                   "int": C.c_int,
106                   "byte": C.c_byte,
107                   "real": C.c_float,
108                   "string": C.c_char_p,
109                   "char": C.c_char,
110                   "time": lambda x: x,
111                   "pointer": C.pointer,
112                   "flag": lambda x: x,
113                   "xtra": lambda x: x
114                   }
115
116        slib = self._instances[self._active].sh
117
118        idxstructure = {}
119
120        for idx in idxlist:
121            idx_1 = idx[0]
122
123            i = C.c_int.in_dll(slib, "icnt_%c_dbv" % idx_1)
124
125            nam = ((C.c_char*11)*i.value).in_dll(slib, "inam_%c_dbv" % idx_1)
126            ent = (C.c_uint*i.value).in_dll(slib, "ient_%c_dbv" % idx_1)
127
128            for e in range(i.value):
129                # structure maps name to type, ientry value, index and function
130                idxstructure[nam[e].value.replace("-", "_")] = (idx, ent[e], ent[e] & 0x03ff, idxlist[idx])
131
132        self.idx = idxstructure
133
134    def setInfoEntry(self, trc, name, value):
135        """transfer info entry "name" to shlib instance for trace at address trc
136
137        """
138
139        map = {
140               "long": "db_setl",
141               "int": "db_seti",
142               "byte": "db_setb",
143               "string": "db_sets",
144               "char": "db_setc",
145               "real": "db_setr",
146               "flag": "db_setf", # XXX
147               "pointer": "db_setp", # XXX not needed (still unchangeable)
148               "time": "db_sett",
149               }
150
151        dattype, ientry, _, vmap = self.idx[name.upper()]
152
153        fct = getattr(self.sh, map[dattype])
154
155        status = C.c_int()
156
157        if value == None:
158            value = EMPTYVALUES[dattype]
159        else:
160            value = vmap(value)
161
162        if dattype == "time":
163            fct(trc, ientry, C.byref(value), C.byref(status))
164        else:
165            fct(trc, ientry, value, C.byref(status))
166
167        MessageService.trigger(Message(MessageService.TRACEUPDATE))
168        if status.value:
169            logger.error("could not set info entry '%s'" % name)
170        else:
171            logger.debug("set info entry '%s' to '%s' for trace %u" % (name, str(value), trc))
172
173    def _startup(self):
174        """set some start up parameters"""
175
176#        self.call(StringIO("SHSTRTUP"))
177#        return
178   
179        self.call(StringIO("wdw/dc=s/ic=s/main"))
180        self.call(StringIO("wdw/ic=s"))
181
182        # new info entries
183        self.call(StringIO("entry define sign      i  6 11"))
184        self.call(StringIO("entry define eventno   i  7 12"))
185        self.call(StringIO("entry define mark      i  8 14"))
186        self.call(StringIO("entry define calib     r  1 26"))
187        self.call(StringIO("entry define distance  r  2 11"))
188        self.call(StringIO("entry define azimuth   r  4 12"))
189        self.call(StringIO("entry define slowness  r  3 18"))
190        self.call(StringIO("entry define inci      r 12 13"))
191        self.call(StringIO("entry define depth     r 13 14"))
192        self.call(StringIO("entry define magnitude r 14 15"))
193        self.call(StringIO("entry define lat       r 15 16"))
194        self.call(StringIO("entry define lon       r 16 17"))
195        self.call(StringIO("entry define signoise  r 17 22"))
196        self.call(StringIO("entry define pwdw      r 18 23"))
197        self.call(StringIO("entry define dcvreg    r 19 24"))
198        self.call(StringIO("entry define dcvinci   r 20 25"))
199        self.call(StringIO("entry define filter    s 10 11"))
200        self.call(StringIO("entry define quality   s 11 12"))
201        self.call(StringIO("entry define p-onset   t  1 22"))
202        self.call(StringIO("entry define s-onset   t  2 23"))
203        self.call(StringIO("entry define origin    t  3 24"))
204
205    def call(self, stream):
206        """call original c lib function to execute SH command in cmd
207
208           GOTO command is replaced by own implementation
209
210           @param stream: stream containing SH command(s) (one per line)
211        """
212
213        if not hasattr(stream, "readline"):
214            raise CommandStreamError
215
216        slib = self._instances[self._active].sh
217        cmd = PARAM()
218        status = C.c_int()
219
220        # analyse stream
221        script = Scripting(stream)
222
223        # now run
224        while True:
225            # read next command
226            try:
227                cmdstr = script.next()
228            except StopIteration:
229                break
230           
231            # make changeable string (strings in python may no be altered!)
232            cmdstr = C.create_string_buffer(cmdstr)
233
234            # upper case convert?
235            shflags = C.c_int.in_dll(slib, "shflags_shv")
236            if shflags.value & CAPCNV:
237                logger.debug("changing case of command")
238                slib.ut_cap(cmdstr)
239
240            # parse command
241            slib.cp_parse(cmdstr, C.byref(cmd), C.byref(status))
242
243            # substitute variables
244            if status.value == NOERROR:
245                slib.tr_partrans(C.byref(cmd), C.byref(status))
246            else:
247                raise CommandNotSuccessfulError(cmdstr.value, status.value)
248
249            logger.debug("command elements: %s", [y.value for y in cmd.p[:cmd.pno+1]])
250            logger.debug("qualifier elements: %s", [y.value for y in cmd.q[:cmd.qno+1]])
251
252            # GOTO
253            if cmd.p[0].value.upper() == "GOTO":
254                script.Goto(cmd.p[1].value)
255                continue
256
257            # IF -> GOTO
258            if cmd.p[0].value.upper() == "IF" and cmd.p[4].value.upper() == "GOTO":
259                script.IfGoto(cmd)
260                continue
261
262            # all other commands are passed to slib
263            slib.err_clearcontext()
264
265            execstr = C.create_string_buffer(LINELENGTH)
266            quit = C.c_int()
267            redraw = C.c_int()
268            iscmdproc = C.c_int()
269            rdlevel = C.c_int()
270
271            # check for prompt (not set if running non-interactively
272            try:
273                ptstr = sys.ps1
274            except AttributeError:
275                ptstr = ""
276
277            prompt = C.create_string_buffer(ptstr, LINELENGTH)
278
279            # save tc, cc channel
280            tc = C.c_int.in_dll(slib, "tc")
281            cc = C.c_int.in_dll(slib, "cc")
282            gc = C.c_int.in_dll(slib, "gc")
283
284            slib.ui_level.restype = C.c_int
285            slib.ui_levelname.restype = C.c_char_p
286
287            if status.value == NOERROR:
288                logger.debug("before: tc=%u, cc=%u, gc=%s, ui=%u" % (tc.value, cc.value, gc.value, slib.ui_level()))
289                slib.ui_setconsole(cc)
290
291                slib.se_execute_command(
292                    C.byref(cmd), cmdstr, execstr, C.byref(quit), C.byref(redraw),
293                    C.byref(iscmdproc), C.byref(rdlevel), prompt, C.byref(status))
294
295                if redraw.value:
296                    MessageService.trigger(Message(MessageService.REDRAW))
297
298#                print quit.value, redraw.value, iscmdproc.value, rdlevel.value, status.value
299
300                logger.debug("after: tc=%u, cc=%u, gc=%s, ui=%u" % (tc.value, cc.value, gc.value, slib.ui_level()))
301
302                if status.value == NOERROR and iscmdproc.value:
303                    cmdproc = slib.ui_levelname(slib.ui_level())
304                    logger.info("command procedure found: %s" % cmdproc)
305                    self.call(open(cmdproc))
306
307            if status.value != NOERROR:
308                logger.info("execution not successful, error code %u" % status.value)
309                slib.se_dsplymsg(cc, status)
310                raise CommandNotSuccessfulError(cmdstr.value, status.value)
311            else:
312                pass
313
314        return
315
316    def switch(self, id):
317        """switch between parallel instances of shlib
318
319           @param id: switch to shlib instance by identifier
320           If requested instance is not found, it will be created on the fly!"""
321
322        self._oldactive = self._active
323
324        if id in self._instances:
325            logger.debug("shlib instance switched to %s" % id)
326            self._active = id
327        else:
328            # start new instance
329            logger.info("id %s not found, start new one!" % id)
330            shlib(id)
331
332    def switchBack(self):
333        """switch back to former instance
334
335           If attribute doesn't exist just log message, no Exception raised.
336
337           Note: If former instance was quit before, a new one with same name
338           will be created on the fly!"""
339
340        try:
341            self.switch(self._oldactive)
342        except AttributeError:
343            logger.warning("Could not switch back to former instance")
344
345    def quit(self):
346        """shut down active shlib instance"""
347
348        logger.debug("shut down id %s" % self._active)
349
350        # last session terminates everything
351        # static variables are shared, so not double freeing occurs
352        if len(self._instances) == 1:
353            self._instances[self._active].sh.se_terminate()
354            self._instances[self._active].sh.SqlDeleteScratchFile()
355
356        del self._instances[self._active]
357
358        try:
359            self._active = self._instances.keys()[-1]
360        except IndexError:
361            self._active = ""
362
363    def quitAll(self):
364        """quit all shlib instances"""
365
366        for id in copy(self._instances):
367            self.switch(id)
368            self.quit()
369
370class Scripting(object):
371    def __init__(self, stream):
372        content = []
373        targets = {}
374        skipped = 0
375
376        for line, cmdstr in enumerate(stream):
377            cmdstr = cmdstr.strip()
378
379            # skip empty lines or comments
380            if len(cmdstr) and cmdstr[0] != "!":
381                # remember goto target line?
382                if cmdstr.split()[0][-1] == ":":
383                    targets[cmdstr.upper()] = line - skipped
384
385                content.append(cmdstr)
386            else:
387                skipped += 1
388
389        self.content = content
390        self.targets = targets
391        self.pointer = 0
392
393    def next(self):
394        try:
395            # skip goto targets
396            while self.pointer in self.targets.values():
397                self.pointer += 1
398
399            pnt = self.pointer
400            self.pointer += 1
401
402            return self.content[pnt]
403        except IndexError:
404            raise StopIteration
405
406    def Goto(self, target):
407        try:
408            self.pointer = self.targets[target.upper()]
409        except KeyError:
410            raise GotoTargetNotFoundError(target.upper())
411
412    def IfGoto(self, cmd):
413        # cast format
414        cast = {
415                "S": str,
416                "I": int,
417                "R": float
418                }
419
420        cmp, check = cmd.p[2].value, cmd.p[2].value[:2]
421
422        var1 = cast[cmp[-1]](cmd.p[1].value)
423        var2 = cast[cmp[-1]](cmd.p[3].value)
424
425        # comparison
426        try:
427            comp = {
428                    "EQ": var1.__eq__,
429                    "NE": var1.__ne__,
430                    "GT": var1.__gt__,
431                    "GE": var1.__ge__,
432                    "LT": var1.__lt__,
433                    "LE": var1.__le__,
434                    }
435        except AttributeError:
436            # in python 2.5 integers have no __eq__, __gt__, ... methods :(
437            comp = {
438                    "EQ": lambda x: var1 == x,
439                    "NE": lambda x: var1 != x,
440                    "GT": lambda x: var1 > x,
441                    "GE": lambda x: var1 >= x,
442                    "LT": lambda x: var1 < x,
443                    "LE": lambda x: var1 <= x,
444                    }
445
446        # check condition
447        if comp[check](var2):
448            self.Goto(cmd.p[5].value)
449
450if __name__ == "__main__":
451    s = shlib()
Note: See TracBrowser for help on using the repository browser.