--- /dev/null
+#!/usr/bin/env python
+## $Id: abstfilter.py,v 1.1.1.1 2003/07/01 23:28:27 euske Exp $
+##
+## abstfilter.py - A framework for cascade filters.
+##
+
+
+## AbstractFeeder
+##
+class AbstractFeeder(object):
+
+ def __init__(self, next_filter):
+ self.next_filter = next_filter
+ return
+
+ def feed_next(self, s):
+ self.next_filter.feed(s)
+ return
+
+ def close(self):
+ self.next_filter.close()
+ return
+
+
+## AbstractFilter
+##
+class AbstractFilter(object):
+
+ def __init__(self, next_filter):
+ self.next_filter = next_filter
+ return
+
+ def process(self, s):
+ raise NotImplementedError
+
+ def feed(self, s):
+ self.feed_next(self.process(s))
+ return
+
+ def feed_next(self, s):
+ self.next_filter.feed(s)
+ return
+
+ def close(self):
+ self.next_filter.close()
+ return
+
+
+## AbstractConsumer
+##
+class AbstractConsumer(object):
+
+ def __init__(self):
+ return
+
+ def feed(self, s):
+ raise NotImplementedError
+
+ def close(self):
+ return
+
+
+## FileGenerator
+##
+class FileGenerator(AbstractFeeder):
+ def __init__(self, next_type):
+ next_filter = next_type(self)
+ AbstractFeeder.__init__(self, next_filter)
+ self.results = []
+ return
+
+ def feed(self, s):
+ self.results.append(s)
+ return
+
+ def close(self):
+ return
+
+ def pullopen(self, f):
+ while 1:
+ s = f.readline()
+ if not s: break
+ self.feed_next(s)
+ if self.results:
+ for s in self.results:
+ yield s
+ self.results = []
+ for s in self.results:
+ yield s
+ self.results = []
+ return
+
--- /dev/null
+#!/usr/bin/env python
+
+import sexpr
+import os
+import fcntl
+import select
+import sys
+from abstfilter import AbstractConsumer
+
+class Growler(AbstractConsumer):
+ def __init__(self):
+ return
+ def feed(self, s):
+ if s is None or type(s) is type(''): return
+ print repr(s)
+ d = dict([(ss[0], len(ss) > 2 and ss[2] or None) for ss in s])
+ if d['tzcspew'] == 'message':
+ zclass = d['class'].lower()
+ zinstance = d['instance'].lower()
+ zop = d['opcode'].lower()
+ zsender = d['sender'].lower()
+ zauth = d['auth'].lower() == 'yes'
+ ztime = ':'.join(d['time'].split(' ')[3].split(':')[0:2])
+ zmessage = d['message']
+ id = '%s/\n%s/\n%s\n %s' % (zclass, zinstance, zsender, ztime)
+ if zop == 'ping':
+ header = '%s (%s)' % (id, zsender)
+ message = '...'
+ elif zop == 'nil':
+ header = '%s (%s)' % (id, zmessage[0])
+ message = '%s' % zmessage[1]
+ else:
+ return
+ g = os.popen("growlnotify -a MacZephyr -n zephyr -d '%s' -t '%s'" % (id, header), 'w')
+ g.write(message)
+ g.close()
+ def close(self):
+ return
+
+def main(argv):
+ if len(argv) < 2:
+ print """barn-growl v.0.0.1
+
+Usage:
+barn-growl USERNAME"""
+ return 0
+
+ username = argv[1]
+ principal = username
+ if principal.find("@") == -1:
+ principal += '@ATHENA.MIT.EDU'
+ bash = "/bin/bash -lc \"kdo %s ssh %s@linerva.mit.edu 'tzc -si'\" 2>/dev/null </dev/null" % (principal, username)
+ p = os.popen(bash)
+ r = sexpr.SExprReader(Growler())
+
+ flags = fcntl.fcntl(p, fcntl.F_GETFL)
+ fcntl.fcntl(p, fcntl.F_SETFL, flags | os.O_NONBLOCK)
+
+ while 1:
+ [i,o,e] = select.select([p], [], [], 5)
+ if i: s = p.read(1024)
+ else: s = ''
+
+ if s != '':
+ r.feed(s)
+ return 0
+
+if __name__ == "__main__":
+ sys.exit(main(sys.argv))
--- /dev/null
+#!/usr/bin/env python
+##
+## sexpr.py - by Yusuke Shinyama
+##
+## * public domain *
+##
+
+from abstfilter import AbstractFeeder, AbstractFilter, AbstractConsumer
+
+
+## SExprReader
+##
+class SExprReader(AbstractFilter):
+ """Usage:
+
+ reader = SExprReader(consumer)
+ reader.feed("(this is (sexpr))")
+ reader.close()
+ """
+
+ COMMENT_BEGIN = ";"
+ COMMENT_END = "\n"
+ SEPARATOR = " \t\n"
+ PAREN_BEGIN = "("
+ PAREN_END = ")"
+ QUOTE = '"'
+ ESCAPE = "\\"
+
+ def __init__(self, next_filter,
+ comment_begin=COMMENT_BEGIN,
+ comment_end=COMMENT_END,
+ separator=SEPARATOR,
+ paren_begin=PAREN_BEGIN,
+ paren_end=PAREN_END,
+ quote=QUOTE,
+ escape=ESCAPE):
+ AbstractFilter.__init__(self, next_filter)
+ self.comment_begin = comment_begin
+ self.comment_end = comment_end
+ self.separator = separator
+ self.paren_begin = paren_begin
+ self.paren_end = paren_end
+ self.quote = quote
+ self.escape = escape
+ self.special = comment_begin + separator + paren_begin + paren_end + quote + escape
+ self.reset()
+ return
+
+ # SExprReader ignores any error and
+ # try to continue as long as possible.
+ # if you want to throw exception however,
+ # please modify these methods.
+
+ # called if redundant parantheses are found.
+ def illegal_close_paren(self, i):
+ print "Ignore a close parenthesis: %d" % i
+ return
+ # called if it reaches the end-of-file while the stack is not empty.
+ def premature_eof(self, i, x):
+ print "Premature end of file: %d parens left, partial=%s" % (i, x)
+ return
+
+ # reset the internal states.
+ def reset(self):
+ self.incomment = False # if within a comment.
+ self.inquote = False # if within a quote.
+ self.inescape = False # if within a escape.
+ self.sym = '' # partially constructed symbol.
+ # NOTICE: None != nil (an empty list)
+ self.build = None # partially constructed list.
+ self.build_stack = [] # to store a chain of partial lists.
+ return self
+
+ # analyze strings
+ def feed(self, tokens):
+ for (i,c) in enumerate(tokens):
+ if self.incomment:
+ # within a comment - skip
+ self.incomment = (c not in self.comment_end)
+ elif self.inescape or (c not in self.special):
+ # add to the current working symbol
+ self.sym += c
+ self.inescape = False
+ elif c in self.escape:
+ # escape
+ self.inescape = True
+ elif self.inquote and (c not in self.quote):
+ self.sym += c
+ else:
+ # special character (blanks, parentheses, or comment)
+ if self.sym:
+ # close the current symbol
+ if self.build == None:
+ self.feed_next(self.sym)
+ else:
+ self.build.append(self.sym)
+ self.sym = ''
+ if c in self.comment_begin:
+ # comment
+ self.incomment = True
+ elif c in self.quote:
+ # quote
+ self.inquote = not self.inquote
+ elif c in self.paren_begin:
+ # beginning a new list.
+ self.build_stack.append(self.build)
+ empty = []
+ if self.build == None:
+ # begin from a scratch.
+ self.build = empty
+ else:
+ # begin from the end of the current list.
+ self.build.append(empty)
+ self.build = empty
+ elif c in self.paren_end:
+ # terminating the current list
+ if self.build == None:
+ # there must be a working list.
+ self.illegal_close_paren(i)
+ else:
+ if len(self.build_stack) == 1:
+ # current working list is the last one in the stack.
+ self.feed_next(self.build)
+ self.build = self.build_stack.pop()
+ return self
+
+ # terminate
+ def terminate(self):
+ # a working list should not exist.
+ if self.build != None:
+ # error - still try to construct a partial structure.
+ if self.sym:
+ self.build.append(self.sym)
+ self.sym = ''
+ if len(self.build_stack) == 1:
+ x = self.build
+ else:
+ x = self.build_stack[1]
+ self.build = None
+ self.build_stack = []
+ self.premature_eof(len(self.build_stack), x)
+ elif self.sym:
+ # flush the current working symbol.
+ self.feed_next(self.sym)
+ self.sym = ''
+ return self
+
+ # closing.
+ def close(self):
+ AbstractFilter.close(self)
+ self.terminate()
+ return
+
+
+## StrictSExprReader
+##
+class SExprIllegalClosingParenError(ValueError):
+ """It throws an exception with an ill-structured input."""
+ pass
+class SExprPrematureEOFError(ValueError):
+ pass
+class StrictSExprReader(SExprReader):
+ def illegal_close_paren(self, i):
+ raise SExprIllegalClosingParenError(i)
+ def premature_eof(self, i, x):
+ raise SExprPrematureEOFError(i, x)
+
+
+## str2sexpr
+##
+class _SExprStrConverter(AbstractConsumer):
+ results = []
+ def feed(self, s):
+ _SExprStrConverter.results.append(s)
+ return
+_str_converter = SExprReader(_SExprStrConverter())
+_str_converter_strict = StrictSExprReader(_SExprStrConverter())
+
+def str2sexpr(s):
+ """parse a string as a sexpr."""
+ _SExprStrConverter.results = []
+ _str_converter.reset().feed(s).terminate()
+ return _SExprStrConverter.results
+def str2sexpr_strict(s):
+ """parse a string as a sexpr."""
+ _SExprStrConverter.results = []
+ _str_converter_strict.reset().feed(s).terminate()
+ return _SExprStrConverter.results
+
+
+## sexpr2str
+##
+def sexpr2str(e):
+ """convert a sexpr into Lisp-like representation."""
+ if not isinstance(e, list):
+ return e
+ return "("+" ".join(map(sexpr2str, e))+")"
+
+
+# test stuff
+def test():
+ assert str2sexpr("(this ;comment\n is (a test (sentences) (des()) (yo)))") == \
+ [["this", "is", ["a", "test", ["sentences"], ["des", []], ["yo"]]]]
+ assert str2sexpr('''(paren\\(\\)theses_in\\#symbol "space in \nsymbol"
+ this\\ way\\ also. "escape is \\"better than\\" quote")''') == \
+ [['paren()theses_in#symbol', 'space in \nsymbol', 'this way also.', 'escape is "better than" quote']]
+ str2sexpr("(this (is (a (parial (sentence")
+ return
+
+
+# main
+if __name__ == "__main__":
+ test()