diff options
27 files changed, 1525 insertions, 0 deletions
diff --git a/Tools/modulator/EXAMPLE.py b/Tools/modulator/EXAMPLE.py new file mode 100644 index 0000000..4043699 --- /dev/null +++ b/Tools/modulator/EXAMPLE.py @@ -0,0 +1,46 @@ +# +# Example input file for modulator if you don't have tk. +# +# You may also have to strip some imports out of modulator to make +# it work. +# +# Generate code for a simple object with a method called sample + +o = genmodule.object() +o.name = 'simple object' +o.abbrev = 'simp' +o.methodlist = ['sample'] +o.funclist = ['new'] + +# +# Generate code for an object that looks numberish +# +o2 = genmodule.object() +o2.name = 'number-like object' +o2.abbrev = 'nl' +o2.typelist = ['tp_as_number'] +o2.funclist = ['new', 'tp_repr', 'tp_compare'] + +# +# Generate code for a method with a full complement of functions, +# some methods, accessible as sequence and allowing structmember.c type +# structure access as well. +# +o3 = genmodule.object() +o3.name = 'over-the-top object' +o3.abbrev = 'ot' +o3.methodlist = ['method1', 'method2'] +o3.funclist = ['new', 'tp_dealloc', 'tp_print', 'tp_getattr', 'tp_setattr', + 'tp_compare', 'tp_repr', 'tp_hash'] +o3.typelist = ['tp_as_sequence', 'structure'] + +# +# Now generate code for a module that incorporates these object types. +# Also add the boilerplates for functions to create instances of each +# type. +# +m = genmodule.module() +m.name = 'sample' +m.abbrev = 'sample' +m.methodlist = ['newsimple', 'newnumberish', 'newott'] +m.objects = [o, o2, o3] diff --git a/Tools/modulator/README b/Tools/modulator/README new file mode 100644 index 0000000..7ed09c8 --- /dev/null +++ b/Tools/modulator/README @@ -0,0 +1,17 @@ +This is release 1.0 of modulator, a generator of boilerplate code for +modules to be written in C. + +Usage when you have tk is *reall* simple: start modulator, fill out +the forms specifying all the objects and methods, tell modulator +whether objects should also be accessible as sequences, etc and press +'generate code'. It will write a complete skeleton module for you. + +Usage when you don't have tk is slightly more difficult. Look at +EXAMPLE.py for some details. + +Oh yeah: you'll probably want to change Templates/copyright, or all +your code ends up as being copyrighted to CWI:-) + +Let me know what you think, + Jack Jansen, jack@cwi.nl + diff --git a/Tools/modulator/ScrolledListbox.py b/Tools/modulator/ScrolledListbox.py new file mode 100644 index 0000000..89686ef --- /dev/null +++ b/Tools/modulator/ScrolledListbox.py @@ -0,0 +1,37 @@ +# A ScrolledList widget feels like a list widget but also has a +# vertical scroll bar on its right. (Later, options may be added to +# add a horizontal bar as well, to make the bars disappear +# automatically when not needed, to move them to the other side of the +# window, etc.) +# +# Configuration options are passed to the List widget. +# A Frame widget is inserted between the master and the list, to hold +# the Scrollbar widget. +# Most methods calls are inherited from the List widget; Pack methods +# are redirected to the Frame widget however. + +from Tkinter import * +from Tkinter import _cnfmerge + +class ScrolledListbox(Listbox): + def __init__(self, master=None, cnf={}): + cnf = _cnfmerge(cnf) + fcnf = {} + vcnf = {'name': 'vbar', + Pack: {'side': 'right', 'fill': 'y'},} + for k in cnf.keys(): + if type(k) == ClassType or k == 'name': + fcnf[k] = cnf[k] + del cnf[k] + self.frame = Frame(master, fcnf) + self.vbar = Scrollbar(self.frame, vcnf) + cnf[Pack] = {'side': 'left', 'fill': 'both', 'expand': 'yes'} + cnf['name'] = 'list' + Listbox.__init__(self, self.frame, cnf) + self['yscrollcommand'] = (self.vbar, 'set') + self.vbar['command'] = (self, 'yview') + + # Copy Pack methods of self.frame -- hack! + for m in Pack.__dict__.keys(): + if m[0] != '_' and m != 'config': + setattr(self, m, getattr(self.frame, m)) diff --git a/Tools/modulator/Templates/copyright b/Tools/modulator/Templates/copyright new file mode 100644 index 0000000..86206c3 --- /dev/null +++ b/Tools/modulator/Templates/copyright @@ -0,0 +1,23 @@ +/*********************************************************** +Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam, +The Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ diff --git a/Tools/modulator/Templates/module_head b/Tools/modulator/Templates/module_head new file mode 100644 index 0000000..d1fafdc --- /dev/null +++ b/Tools/modulator/Templates/module_head @@ -0,0 +1,7 @@ + +#include "allobjects.h" +#include "modsupport.h" /* For getargs() etc. */ + +static object *ErrorObject; + +/* ----------------------------------------------------- */ diff --git a/Tools/modulator/Templates/module_method b/Tools/modulator/Templates/module_method new file mode 100644 index 0000000..bf64e79 --- /dev/null +++ b/Tools/modulator/Templates/module_method @@ -0,0 +1,12 @@ + +static object * +$abbrev$_$method$(self, args) + object *self; /* Not used */ + object *args; +{ + + if (!newgetargs(args, "")) + return NULL; + INCREF(None); + return None; +} diff --git a/Tools/modulator/Templates/module_tail b/Tools/modulator/Templates/module_tail new file mode 100644 index 0000000..466c84a --- /dev/null +++ b/Tools/modulator/Templates/module_tail @@ -0,0 +1,30 @@ + +/* List of methods defined in the module */ + +static struct methodlist $abbrev$_methods[] = { + $methodlist$ + {NULL, NULL} /* sentinel */ +}; + + +/* Initialization function for the module (*must* be called init$name$) */ + +void +init$name$() +{ + object *m, *d; + + /* Create the module and add the functions */ + m = initmodule("$name$", $abbrev$_methods); + + /* Add some symbolic constants to the module */ + d = getmoduledict(m); + ErrorObject = newstringobject("$name$.error"); + dictinsert(d, "error", ErrorObject); + + /* XXXX Add constants here */ + + /* Check for errors */ + if (err_occurred()) + fatal("can't initialize module $name$"); +} diff --git a/Tools/modulator/Templates/object_head b/Tools/modulator/Templates/object_head new file mode 100644 index 0000000..bf69a51 --- /dev/null +++ b/Tools/modulator/Templates/object_head @@ -0,0 +1,12 @@ +/* Declarations for objects of type $name$ */ + +typedef struct { + OB_HEAD + /* XXXX Add your own stuff here */ +} $abbrev$object; + +staticforward typeobject $Abbrev$type; + +#define is_$abbrev$object(v) ((v)->ob_type == &$Abbrev$type) + +/* ---------------------------------------------------------------- */ diff --git a/Tools/modulator/Templates/object_method b/Tools/modulator/Templates/object_method new file mode 100644 index 0000000..20896de --- /dev/null +++ b/Tools/modulator/Templates/object_method @@ -0,0 +1,11 @@ + +static object * +$abbrev$_$method$(self, args) + $abbrev$object *self; + object *args; +{ + if (!newgetargs(args, "")) + return NULL; + INCREF(None); + return None; +} diff --git a/Tools/modulator/Templates/object_mlist b/Tools/modulator/Templates/object_mlist new file mode 100644 index 0000000..62d5894 --- /dev/null +++ b/Tools/modulator/Templates/object_mlist @@ -0,0 +1,7 @@ + +static struct methodlist $abbrev$_methods[] = { + $methodlist$ + {NULL, NULL} /* sentinel */ +}; + +/* ---------- */ diff --git a/Tools/modulator/Templates/object_new b/Tools/modulator/Templates/object_new new file mode 100644 index 0000000..1817a55 --- /dev/null +++ b/Tools/modulator/Templates/object_new @@ -0,0 +1,12 @@ + +static $abbrev$object * +new$abbrev$object() +{ + $abbrev$object *self; + + self = NEWOBJ($abbrev$object, &$Abbrev$type); + if (self == NULL) + return NULL; + /* XXXX Add your own initializers here */ + return self; +} diff --git a/Tools/modulator/Templates/object_structure b/Tools/modulator/Templates/object_structure new file mode 100644 index 0000000..6a54518 --- /dev/null +++ b/Tools/modulator/Templates/object_structure @@ -0,0 +1,41 @@ +/* Code to access structure members by accessing attributes */ + +#include "structmember.h" + +#define OFF(x) offsetof(XXXXobject, x) + +static struct memberlist $abbrev$_memberlist[] = { + /* XXXX Add lines like { "foo", T_INT, OFF(foo), RO } */ + {NULL} /* Sentinel */ +}; + +static object * +$abbrev$_getattr(self, name) + $abbrev$object *self; + char *name; +{ + object *rv; + + /* XXXX Add your own getattr code here */ + rv = getmember((char *)/*XXXX*/0, $abbrev$_memberlist, name); + if (rv) + return rv; + err_clear(); + return findmethod($abbrev$_methods, (object *)self, name); +} + + +static int +$abbrev$_setattr(self, name, v) + $abbrev$object *self; + char *name; + object *v; +{ + /* XXXX Add your own setattr code here */ + if ( v == NULL ) { + err_setstr(AttributeError, "Cannot delete attribute"); + return -1; + } + return setmember((char *)/*XXXX*/0, $abbrev$_memberlist, name, v); +} + diff --git a/Tools/modulator/Templates/object_tail b/Tools/modulator/Templates/object_tail new file mode 100644 index 0000000..9bc78ca --- /dev/null +++ b/Tools/modulator/Templates/object_tail @@ -0,0 +1,22 @@ + +static typeobject $Abbrev$type = { + OB_HEAD_INIT(&Typetype) + 0, /*ob_size*/ + "$name$", /*tp_name*/ + sizeof($abbrev$object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)$tp_dealloc$, /*tp_dealloc*/ + (printfunc)$tp_print$, /*tp_print*/ + (getattrfunc)$tp_getattr$, /*tp_getattr*/ + (setattrfunc)$tp_setattr$, /*tp_setattr*/ + (cmpfunc)$tp_compare$, /*tp_compare*/ + (reprfunc)$tp_repr$, /*tp_repr*/ + $tp_as_number$, /*tp_as_number*/ + $tp_as_sequence$, /*tp_as_sequence*/ + $tp_as_mapping$, /*tp_as_mapping*/ + (hashfunc)$tp_hash$, /*tp_hash*/ +}; + +/* End of code for $name$ objects */ +/* -------------------------------------------------------- */ diff --git a/Tools/modulator/Templates/object_tp_as_mapping b/Tools/modulator/Templates/object_tp_as_mapping new file mode 100644 index 0000000..c5edf3e --- /dev/null +++ b/Tools/modulator/Templates/object_tp_as_mapping @@ -0,0 +1,33 @@ +/* Code to access $name$ objects as mappings */ + +static int +$abbrev$_length(self) + $abbrev$object *self; +{ + /* XXXX Return the size of the mapping */ +} + +static object * +$abbrev$_subscript(self, key) + $abbrev$object *self; + object *key; +{ + /* XXXX Return the item of self indexed by key */ +} + +static int +$abbrev$_ass_sub(self, v, w) + $abbrev$object *self; + object *v, *w; +{ + /* XXXX Put w in self under key v */ + return 0; +} + +static mapping_methods $abbrev$_as_mapping = { + (inquiry)$abbrev$_length, /*mp_length*/ + (binaryfunc)$abbrev$_subscript, /*mp_subscript*/ + (objobjargproc)$abbrev$_ass_sub, /*mp_ass_subscript*/ +}; + +/* -------------------------------------------------------- */ diff --git a/Tools/modulator/Templates/object_tp_as_number b/Tools/modulator/Templates/object_tp_as_number new file mode 100644 index 0000000..b97d473 --- /dev/null +++ b/Tools/modulator/Templates/object_tp_as_number @@ -0,0 +1,249 @@ +/* Code to access $name$ objects as numbers */ + +static object * +$abbrev$_add(v, w) + $abbrev$object *v; + $abbrev$object *w; +{ + /* XXXX Add them */ + err_setstr(SystemError, "not implemented"); + return NULL; +} + +static object * +$abbrev$_sub(v, w) + $abbrev$object *v; + $abbrev$object *w; +{ + /* XXXX Subtract them */ + err_setstr(SystemError, "not implemented"); + return NULL; +} + +static object * +$abbrev$_mul(v, w) + $abbrev$object *v; + $abbrev$object *w; +{ + /* XXXX Multiply them */ + err_setstr(SystemError, "not implemented"); + return NULL; +} + +static object * +$abbrev$_div(x, y) + $abbrev$object *x; + $abbrev$object *y; +{ + /* XXXX Divide them */ + err_setstr(SystemError, "not implemented"); + return NULL; +} + +static object * +$abbrev$_mod(x, y) + $abbrev$object *x; + $abbrev$object *y; +{ + /* XXXX Modulo them */ + err_setstr(SystemError, "not implemented"); + return NULL; +} + +static object * +$abbrev$_divmod(x, y) + $abbrev$object *x; + $abbrev$object *y; +{ + /* XXXX Return 2-tuple with div and mod */ + err_setstr(SystemError, "not implemented"); + return NULL; +} + +static object * +$abbrev$_pow(v, w, z) + $abbrev$object *v; + $abbrev$object *w; + $abbrev$object *z; +{ + /* XXXX */ + err_setstr(SystemError, "not implemented"); + return NULL; +} + +static object * +$abbrev$_neg(v) + $abbrev$object *v; +{ + /* XXXX */ + err_setstr(SystemError, "not implemented"); + return NULL; +} + +static object * +$abbrev$_pos(v) + $abbrev$object *v; +{ + /* XXXX */ + err_setstr(SystemError, "not implemented"); + return NULL; +} + +static object * +$abbrev$_abs(v) + $abbrev$object *v; +{ + /* XXXX */ + err_setstr(SystemError, "not implemented"); + return NULL; +} + +static int +$abbrev$_nonzero(v) + $abbrev$object *v; +{ + /* XXXX Return 1 if non-zero */ + err_setstr(SystemError, "not implemented"); + return -1; +} + +static object * +$abbrev$_invert(v) + $abbrev$object *v; +{ + /* XXXX */ + err_setstr(SystemError, "not implemented"); + return NULL; +} + +static object * +$abbrev$_lshift(v, w) + $abbrev$object *v; + $abbrev$object *w; +{ + /* XXXX */ + err_setstr(SystemError, "not implemented"); + return NULL; +} + +static object * +$abbrev$_rshift(v, w) + $abbrev$object *v; + $abbrev$object *w; +{ + /* XXXX */ + err_setstr(SystemError, "not implemented"); + return NULL; +} + +static object * +$abbrev$_and(v, w) + $abbrev$object *v; + $abbrev$object *w; +{ + /* XXXX */ + err_setstr(SystemError, "not implemented"); + return NULL; +} + +static object * +$abbrev$_xor(v, w) + $abbrev$object *v; + $abbrev$object *w; +{ + /* XXXX */ + err_setstr(SystemError, "not implemented"); + return NULL; +} + +static object * +$abbrev$_or(v, w) + $abbrev$object *v; + $abbrev$object *w; +{ + /* XXXX */ + err_setstr(SystemError, "not implemented"); + return NULL; +} + +static int +$abbrev$_coerce(pv, pw) + object **pv; + object **pw; +{ + /* XXXX I haven't a clue... */ + return 1; +} + +static object * +$abbrev$_int(v) + $abbrev$object *v; +{ + /* XXXX */ + err_setstr(SystemError, "not implemented"); + return NULL; +} + +static object * +$abbrev$_long(v) + $abbrev$object *v; +{ + /* XXXX */ + err_setstr(SystemError, "not implemented"); + return NULL; +} + +static object * +$abbrev$_float(v) + $abbrev$object *v; +{ + /* XXXX */ + err_setstr(SystemError, "not implemented"); + return NULL; +} + +static object * +$abbrev$_oct(v) + $abbrev$object *v; +{ + /* XXXX Return object as octal stringobject */ + err_setstr(SystemError, "not implemented"); + return NULL; +} + +static object * +$abbrev$_hex(v) + $abbrev$object *v; +{ + /* XXXX Return object as hex stringobject */ + err_setstr(SystemError, "not implemented"); + return NULL; +} + +static number_methods $abbrev$_as_number = { + (binaryfunc)$abbrev$_add, /*nb_add*/ + (binaryfunc)$abbrev$_sub, /*nb_subtract*/ + (binaryfunc)$abbrev$_mul, /*nb_multiply*/ + (binaryfunc)$abbrev$_div, /*nb_divide*/ + (binaryfunc)$abbrev$_mod, /*nb_remainder*/ + (binaryfunc)$abbrev$_divmod, /*nb_divmod*/ + (ternaryfunc)$abbrev$_pow, /*nb_power*/ + (unaryfunc)$abbrev$_neg, /*nb_negative*/ + (unaryfunc)$abbrev$_pos, /*nb_positive*/ + (unaryfunc)$abbrev$_abs, /*nb_absolute*/ + (inquiry)$abbrev$_nonzero, /*nb_nonzero*/ + (unaryfunc)$abbrev$_invert, /*nb_invert*/ + (binaryfunc)$abbrev$_lshift, /*nb_lshift*/ + (binaryfunc)$abbrev$_rshift, /*nb_rshift*/ + (binaryfunc)$abbrev$_and, /*nb_and*/ + (binaryfunc)$abbrev$_xor, /*nb_xor*/ + (binaryfunc)$abbrev$_or, /*nb_or*/ + (coercion)$abbrev$_coerce, /*nb_coerce*/ + (unaryfunc)$abbrev$_int, /*nb_int*/ + (unaryfunc)$abbrev$_long, /*nb_long*/ + (unaryfunc)$abbrev$_float, /*nb_float*/ + (unaryfunc)$abbrev$_oct, /*nb_oct*/ + (unaryfunc)$abbrev$_hex, /*nb_hex*/ +}; + +/* ------------------------------------------------------- */ diff --git a/Tools/modulator/Templates/object_tp_as_sequence b/Tools/modulator/Templates/object_tp_as_sequence new file mode 100644 index 0000000..50f2f91 --- /dev/null +++ b/Tools/modulator/Templates/object_tp_as_sequence @@ -0,0 +1,73 @@ + +/* Code to handle accessing $name$ objects as sequence objects */ + +static int +$abbrev$_length(self) + $abbrev$object *self; +{ + /* XXXX Return the size of the object */ +} + +static object * +$abbrev$_concat(self, bb) + $abbrev$object *self; + object *bb; +{ + /* XXXX Return the concatenation of self and bb */ +} + +static object * +$abbrev$_repeat(self, n) + $abbrev$object *self; + int n; +{ + /* XXXX Return a new object that is n times self */ +} + +static object * +$abbrev$_item(self, i) + $abbrev$object *self; + int i; +{ + /* XXXX Return the i-th object of self */ +} + +static object * +$abbrev$_slice(self, ilow, ihigh) + $abbrev$object *self; + int ilow, ihigh; +{ + /* XXXX Return the ilow..ihigh slice of self in a new object */ +} + +static int +$abbrev$_ass_item(self, i, v) + $abbrev$object *self; + int i; + object *v; +{ + /* XXXX Assign to the i-th element of self */ + return 0; +} + +static int +$abbrev$_ass_slice(self, ilow, ihigh, v) + listobject *self; + int ilow, ihigh; + object *v; +{ + /* XXXX Replace ilow..ihigh slice of self with v */ + return 0; +} + +static sequence_methods $abbrev$_as_sequence = { + (inquiry)$abbrev$_length, /*sq_length*/ + (binaryfunc)$abbrev$_concat, /*sq_concat*/ + (intargfunc)$abbrev$_repeat, /*sq_repeat*/ + (intargfunc)$abbrev$_item, /*sq_item*/ + (intintargfunc)$abbrev$_slice, /*sq_slice*/ + (intobjargproc)$abbrev$_ass_item, /*sq_ass_item*/ + (intintobjargproc)$abbrev$_ass_slice, /*sq_ass_slice*/ +}; + +/* -------------------------------------------------------------- */ diff --git a/Tools/modulator/Templates/object_tp_compare b/Tools/modulator/Templates/object_tp_compare new file mode 100644 index 0000000..a2e2e9d --- /dev/null +++ b/Tools/modulator/Templates/object_tp_compare @@ -0,0 +1,7 @@ + +static int +$abbrev$_compare(v, w) + $abbrev$object *v, *w; +{ + /* XXXX Compare objects and return -1, 0 or 1 */ +} diff --git a/Tools/modulator/Templates/object_tp_dealloc b/Tools/modulator/Templates/object_tp_dealloc new file mode 100644 index 0000000..b4d573e --- /dev/null +++ b/Tools/modulator/Templates/object_tp_dealloc @@ -0,0 +1,8 @@ + +static void +$abbrev$_dealloc(self) + $abbrev$object *self; +{ + /* XXXX Add your own cleanup code here */ + DEL(self); +} diff --git a/Tools/modulator/Templates/object_tp_getattr b/Tools/modulator/Templates/object_tp_getattr new file mode 100644 index 0000000..3e5542f --- /dev/null +++ b/Tools/modulator/Templates/object_tp_getattr @@ -0,0 +1,9 @@ + +static object * +$abbrev$_getattr(self, name) + $abbrev$object *self; + char *name; +{ + /* XXXX Add your own getattr code here */ + return findmethod($abbrev$_methods, (object *)self, name); +} diff --git a/Tools/modulator/Templates/object_tp_hash b/Tools/modulator/Templates/object_tp_hash new file mode 100644 index 0000000..1681b4a --- /dev/null +++ b/Tools/modulator/Templates/object_tp_hash @@ -0,0 +1,7 @@ + +static long +$abbrev$_hash(self) + $abbrev$object *self; +{ + /* XXXX Return a hash of self (or -1) */ +} diff --git a/Tools/modulator/Templates/object_tp_print b/Tools/modulator/Templates/object_tp_print new file mode 100644 index 0000000..017712e --- /dev/null +++ b/Tools/modulator/Templates/object_tp_print @@ -0,0 +1,10 @@ + +static int +$abbrev$_print(self, fp, flags) + $abbrev$object *self; + FILE *fp; + int flags; +{ + /* XXXX Add code here to print self to fp */ + return 0; +} diff --git a/Tools/modulator/Templates/object_tp_repr b/Tools/modulator/Templates/object_tp_repr new file mode 100644 index 0000000..45c78df --- /dev/null +++ b/Tools/modulator/Templates/object_tp_repr @@ -0,0 +1,10 @@ + +static object * +$abbrev$_repr(self) + $abbrev$object *self; +{ + object *s; + + /* XXXX Add code here to put self into s */ + return s; +} diff --git a/Tools/modulator/Templates/object_tp_setattr b/Tools/modulator/Templates/object_tp_setattr new file mode 100644 index 0000000..d4da0ce --- /dev/null +++ b/Tools/modulator/Templates/object_tp_setattr @@ -0,0 +1,10 @@ + +static int +$abbrev$_setattr(self, name, v) + $abbrev$object *self; + char *name; + object *v; +{ + /* XXXX Add your own setattr code here */ + return -1; +} diff --git a/Tools/modulator/Tkextra.py b/Tools/modulator/Tkextra.py new file mode 100755 index 0000000..25681ae --- /dev/null +++ b/Tools/modulator/Tkextra.py @@ -0,0 +1,235 @@ +#! /usr/local/bin/python + +# A Python function that generates dialog boxes with a text message, +# optional bitmap, and any number of buttons. +# Cf. Ousterhout, Tcl and the Tk Toolkit, Figs. 27.2-3, pp. 269-270. + +from Tkinter import * + +mainWidget = None + +def dialog(master, title, text, bitmap, default, *args): + + # 1. Create the top-level window and divide it into top + # and bottom parts. + + w = Toplevel(master, {'class': 'Dialog'}) + w.title(title) + w.iconname('Dialog') + + top = Frame(w, {'relief': 'raised', 'bd': 1, + Pack: {'side': 'top', 'fill': 'both'}}) + bot = Frame(w, {'relief': 'raised', 'bd': 1, + Pack: {'side': 'bottom', 'fill': 'both'}}) + + # 2. Fill the top part with the bitmap and message. + + msg = Message(top, + {'width': '3i', + 'text': text, + 'font': '-Adobe-Times-Medium-R-Normal-*-180-*', + Pack: {'side': 'right', 'expand': 1, + 'fill': 'both', + 'padx': '3m', 'pady': '3m'}}) + if bitmap: + bm = Label(top, {'bitmap': bitmap, + Pack: {'side': 'left', + 'padx': '3m', 'pady': '3m'}}) + + # 3. Create a row of buttons at the bottom of the dialog. + + buttons = [] + i = 0 + for but in args: + b = Button(bot, {'text': but, + 'command': ('set', 'button', i)}) + buttons.append(b) + if i == default: + bd = Frame(bot, {'relief': 'sunken', 'bd': 1, + Pack: {'side': 'left', 'expand': 1, + 'padx': '3m', 'pady': '2m'}}) + b.lift() + b.pack ({'in': bd, 'side': 'left', + 'padx': '2m', 'pady': '2m', + 'ipadx': '2m', 'ipady': '1m'}) + else: + b.pack ({'side': 'left', 'expand': 1, + 'padx': '3m', 'pady': '3m', + 'ipady': '2m', 'ipady': '1m'}) + i = i+1 + + # 4. Set up a binding for <Return>, if there's a default, + # set a grab, and claim the focus too. + + if default >= 0: + w.bind('<Return>', + lambda e, b=buttons[default], i=default: + (b.flash(), + b.setvar('button', i))) + + oldFocus = w.tk.call('focus') # XXX + w.grab_set() + w.focus() + + # 5. Wait for the user to respond, then restore the focus + # and return the index of the selected button. + + w.waitvar('button') + w.destroy() + w.tk.call('focus', oldFocus) # XXX + return w.getint(w.getvar('button')) + +def strdialog(master, title, text, bitmap, default, *args): + + # 1. Create the top-level window and divide it into top + # and bottom parts. + + w = Toplevel(master, {'class': 'Dialog'}) + w.title(title) + w.iconname('Dialog') + + top = Frame(w, {'relief': 'raised', 'bd': 1, + Pack: {'side': 'top', 'fill': 'both'}}) + if args: + bot = Frame(w, {'relief': 'raised', 'bd': 1, + Pack: {'side': 'bottom', 'fill': 'both'}}) + + # 2. Fill the top part with the bitmap, message and input field. + + if bitmap: + bm = Label(top, {'bitmap': bitmap, + Pack: {'side': 'left', + 'padx': '3m', 'pady': '3m'}}) + + msg = Message(top, + {'width': '3i', + 'text': text, + 'font': '-Adobe-Times-Medium-R-Normal-*-180-*', + Pack: {'side': 'left', + 'fill': 'both', + 'padx': '3m', 'pady': '3m'}}) + + field = Entry(top, + {'relief':'sunken', + Pack:{'side':'left', + 'fill':'x', + 'expand':1, + 'padx':'3m', 'pady':'3m'}}) + # 3. Create a row of buttons at the bottom of the dialog. + + buttons = [] + i = 0 + for but in args: + b = Button(bot, {'text': but, + 'command': ('set', 'button', i)}) + buttons.append(b) + if i == default: + bd = Frame(bot, {'relief': 'sunken', 'bd': 1, + Pack: {'side': 'left', 'expand': 1, + 'padx': '3m', 'pady': '2m'}}) + b.lift() + b.pack ({'in': bd, 'side': 'left', + 'padx': '2m', 'pady': '2m', + 'ipadx': '2m', 'ipady': '1m'}) + else: + b.pack ({'side': 'left', 'expand': 1, + 'padx': '3m', 'pady': '3m', + 'ipady': '2m', 'ipady': '1m'}) + i = i+1 + + # 4. Set up a binding for <Return>, if there's a default, + # set a grab, and claim the focus too. + + if not args: + w.bind('<Return>', lambda arg, top=top: top.setvar('button', 0)) + field.bind('<Return>', lambda arg, top=top: top.setvar('button', 0)) + elif default >= 0: + w.bind('<Return>', + lambda e, b=buttons[default], i=default: + (b.flash(), + b.setvar('button', i))) + field.bind('<Return>', + lambda e, b=buttons[default], i=default: + (b.flash(), + b.setvar('button', i))) + + oldFocus = w.tk.call('focus') # XXX + w.grab_set() + field.focus() + + # 5. Wait for the user to respond, then restore the focus + # and return the index of the selected button. + + w.waitvar('button') + v = field.get() + w.destroy() + w.tk.call('focus', oldFocus) # XXX + if args: + return v, w.getint(w.getvar('button')) + else: + return v + +def message(str): + i = dialog(mainWidget, 'Message', str, '', 0, 'OK') + +def askyn(str): + i = dialog(mainWidget, 'Question', str, '', 0, 'No', 'Yes') + return i + +def askync(str): + i = dialog(mainWidget, 'Question', str, '', 0, 'Cancel', 'No', 'Yes') + return i-1 + +def askstr(str): + i = strdialog(mainWidget, 'Question', str, '', 0) + return i + +def askfile(str): # XXXX For now... + i = strdialog(mainWidget, 'Question', str, '', 0) + return i + +# The rest is the test program. + +def _go(): + i = dialog(mainWidget, + 'Not Responding', + "The file server isn't responding right now; " + "I'll keep trying.", + '', + -1, + 'OK') + print 'pressed button', i + i = dialog(mainWidget, + 'File Modified', + 'File "tcl.h" has been modified since ' + 'the last time it was saved. ' + 'Do you want to save it before exiting the application?', + 'warning', + 0, + 'Save File', + 'Discard Changes', + 'Return To Editor') + print 'pressed button', i + print message('Test of message') + print askyn('Test of yes/no') + print askync('Test of yes/no/cancel') + print askstr('Type a string:') + print strdialog(mainWidget, 'Question', 'Another string:', '', + 0, 'Save', 'Save as text') + +def _test(): + import sys + global mainWidget + mainWidget = Frame() + Pack.config(mainWidget) + start = Button(mainWidget, + {'text': 'Press Here To Start', 'command': _go}) + start.pack() + endit = Button(mainWidget, + {'text': 'Exit', + 'command': 'exit', + Pack: {'fill' : 'both'}}) + mainWidget.mainloop() + +if __name__ == '__main__': + _test() diff --git a/Tools/modulator/genmodule.py b/Tools/modulator/genmodule.py new file mode 100755 index 0000000..1c4cd1f --- /dev/null +++ b/Tools/modulator/genmodule.py @@ -0,0 +1,157 @@ +# +# Genmodule - A python program to help you build (template) modules. +# +# Usage: +# +# o = genmodule.object() +# o.name = 'dwarve object' +# o.abbrev = 'dw' +# o.funclist = ['new', 'dealloc', 'getattr', 'setattr'] +# o.methodlist = ['dig'] +# +# m = genmodule.module() +# m.name = 'beings' +# m.abbrev = 'be' +# m.methodlist = ['newdwarve'] +# m.objects = [o] +# +# genmodule.write(sys.stdout, m) +# +import sys +import os +import varsubst +import string + +error = 'genmodule.error' + +# +# Names of functions in the object-description struct. +# +FUNCLIST = ['new', 'tp_dealloc', 'tp_print', 'tp_getattr', 'tp_setattr', + 'tp_compare', 'tp_repr', 'tp_hash'] +TYPELIST = ['tp_as_number', 'tp_as_sequence', 'tp_as_mapping', 'structure'] + +# +# writer is a base class for the object and module classes +# it contains code common to both. +# +class writer: + def __init__(self): + self._subst = None + + def makesubst(self): + if not self._subst: + if not self.__dict__.has_key('abbrev'): + self.abbrev = self.name + self.Abbrev = string.upper(self.abbrev[0])+self.abbrev[1:] + subst = varsubst.Varsubst(self.__dict__) + subst.useindent(1) + self._subst = subst.subst + + def addcode(self, name, fp): + ifp = self.opentemplate(name) + self.makesubst() + d = ifp.read() + d = self._subst(d) + fp.write(d) + + def opentemplate(self, name): + for p in sys.path: + fn = os.path.join(p, name) + if os.path.exists(fn): + return open(fn, 'r') + fn = os.path.join(p, 'Templates') + fn = os.path.join(fn, name) + if os.path.exists(fn): + return open(fn, 'r') + raise error, 'Template '+name+' not found for '+self._type+' '+ \ + self.name + +class module(writer): + _type = 'module' + + def writecode(self, fp): + self.addcode('copyright', fp) + self.addcode('module_head', fp) + for o in self.objects: + o.writehead(fp) + for o in self.objects: + o.writebody(fp) + new_ml = '' + for fn in self.methodlist: + self.method = fn + self.addcode('module_method', fp) + new_ml = new_ml + ('{"%s",\t%s_%s,\t1},\n'%(fn, self.abbrev, fn)) + self.methodlist = new_ml + self.addcode('module_tail', fp) + +class object(writer): + _type = 'object' + def __init__(self): + self.typelist = [] + self.methodlist = [] + self.funclist = ['new'] + writer.__init__(self) + + def writecode(self, fp): + self.addcode('copyright', fp) + self.writehead(fp) + self.writebody(fp) + + def writehead(self, fp): + self.addcode('object_head', fp) + + def writebody(self, fp): + new_ml = '' + for fn in self.methodlist: + self.method = fn + self.addcode('object_method', fp) + new_ml = new_ml + ('{"%s",\t%s_%s,\t1},\n'%(fn, self.abbrev, fn)) + self.methodlist = new_ml + self.addcode('object_mlist', fp) + + # Add getattr if we have methods + if self.methodlist and not 'tp_getattr' in self.funclist: + self.funclist.insert(0, 'tp_getattr') + + for fn in FUNCLIST: + setattr(self, fn, '0') + + # + # Special case for structure-access objects: put getattr in the + # list of functions but don't generate code for it directly, + # the code is obtained from the object_structure template. + # The same goes for setattr. + # + if 'structure' in self.typelist: + if 'tp_getattr' in self.funclist: + self.funclist.remove('tp_getattr') + if 'tp_setattr' in self.funclist: + self.funclist.remove('tp_setattr') + self.tp_getattr = self.abbrev + '_getattr' + self.tp_setattr = self.abbrev + '_setattr' + for fn in self.funclist: + self.addcode('object_'+fn, fp) + setattr(self, fn, '%s_%s'%(self.abbrev, fn[3:])) + for tn in TYPELIST: + setattr(self, tn, '0') + for tn in self.typelist: + self.addcode('object_'+tn, fp) + setattr(self, tn, '&%s_%s'%(self.abbrev, tn[3:])) + self.addcode('object_tail', fp) + +def write(fp, obj): + obj.writecode(fp) + +if __name__ == '__main__': + o = object() + o.name = 'dwarve object' + o.abbrev = 'dw' + o.funclist = ['new', 'tp_dealloc'] + o.methodlist = ['dig'] + m = module() + m.name = 'beings' + m.abbrev = 'be' + m.methodlist = ['newdwarve'] + m.objects = [o] + write(sys.stdout, m) diff --git a/Tools/modulator/modulator.py b/Tools/modulator/modulator.py new file mode 100755 index 0000000..b569ac6 --- /dev/null +++ b/Tools/modulator/modulator.py @@ -0,0 +1,379 @@ +#! /usr/local/bin/python +# +# Modulator - Generate skeleton modules. +# +# The user fills out some forms with information about what the module +# should support (methods, objects), names of these things, prefixes to +# use for C code, whether the objects should also support access as numbers, +# etc etc etc. +# When the user presses 'Generate code' we generate a complete skeleton +# module in C. +# +# Alternatively, the selections made can be save to a python sourcefile and +# this sourcefile can be passed on the command line (resulting in the same +# skeleton C code). +# +# Jack Jansen, CWI, October 1994. +# + +import sys, os +sys.path.append(os.path.join(os.environ['HOME'], 'src/python/Demo/modulator')) + +from Tkinter import * +from Tkextra import * +import tkinter +from ScrolledListbox import ScrolledListbox +import sys +import genmodule +import string + +oops = 'oops' + +# Check that string is a legal C identifier +def checkid(str): + if not str: return 0 + if not str[0] in string.letters+'_': + return 0 + for c in str[1:]: + if not c in string.letters+string.digits+'_': + return 0 + return 1 + +def getlistlist(list): + rv = [] + n = list.size() + for i in range(n): + rv.append(list.get(i)) + return rv + +class UI: + def __init__(self): + self.main = Frame() + self.main.pack() + self.main.master.title('Modulator: Module view') + self.cmdframe = Frame(self.main, {'relief':'raised', 'bd':'0.5m', + Pack:{'side':'top', + 'fill':'x'}}) + self.objframe = Frame(self.main, {Pack:{'side':'top', 'fill':'x', + 'expand':1}}) + + + self.check_button = Button(self.cmdframe, + {'text':'Check', 'command':self.cb_check, + Pack:{'side':'left', 'padx':'0.5m'}}) + self.save_button = Button(self.cmdframe, + {'text':'Save...', 'command':self.cb_save, + Pack:{'side':'left', 'padx':'0.5m'}}) + self.code_button = Button(self.cmdframe, + {'text':'Generate code...', + 'command':self.cb_gencode, + Pack:{'side':'left', 'padx':'0.5m'}}) + self.quit_button = Button(self.cmdframe, + {'text':'Quit', + 'command':self.cb_quit, + Pack:{'side':'right', 'padx':'0.5m'}}) + + self.module = UI_module(self) + self.objects = [] + self.modified = 0 + + def run(self): + self.main.mainloop() + + def cb_quit(self, *args): + if self.modified: + if not askyn('You have not saved\nAre you sure you want to quit?'): + return + sys.exit(0) + + def cb_check(self, *args): + try: + self.module.synchronize() + for o in self.objects: + o.synchronize() + except oops: + pass + + def cb_save(self, *args): + try: + pycode = self.module.gencode('m', self.objects) + except oops: + return + + fn = askfile('Python file name: ') + if not fn: + return + + fp = open(fn, 'w') + + fp.write(pycode) + fp.close() + + def cb_gencode(self, *args): + try: + pycode = self.module.gencode('m', self.objects) + except oops: + pass + + fn = askfile('C file name: ') + if not fn: + return + + fp = open(fn, 'w') + + try: + exec pycode + except: + message('An error occurred:-)') + return + genmodule.write(fp, m) + fp.close() + +class UI_module: + def __init__(self, parent): + self.parent = parent + self.frame = Frame(parent.objframe, {'relief':'raised', 'bd':'0.2m', + Pack:{'side':'top', + 'fill':'x'}}) + self.f1 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', + 'fill':'x'}}) + self.f2 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', + 'fill':'x'}}) + self.f3 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', + 'fill':'x'}}) + self.f4 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', + 'fill':'x'}}) + + self.l1 = Label(self.f1, {'text':'Module:', Pack:{'side':'left', + 'padx':'0.5m'}}) + self.name_entry = Entry(self.f1, {'relief':'sunken', + Pack:{'side':'left', 'padx':'0.5m', 'expand':1}}) + self.l2 = Label(self.f1, {'text':'Abbrev:', Pack:{'side':'left', + 'padx':'0.5m'}}) + self.abbrev_entry = Entry(self.f1, {'relief':'sunken', 'width':5, + Pack:{'side':'left', 'padx':'0.5m'}}) + + self.l3 = Label(self.f2, {'text':'Methods:', Pack:{'side':'left', + 'padx':'0.5m'}}) + self.method_list = ScrolledListbox(self.f2, {'relief':'sunken','bd':2, + Pack:{'side':'left', 'expand':1, + 'padx':'0.5m', 'fill':'both'}}) + + self.l4 = Label(self.f3, {'text':'Add method:', Pack:{'side':'left', + 'padx':'0.5m'}}) + self.method_entry = Entry(self.f3, {'relief':'sunken', + Pack:{'side':'left', 'padx':'0.5m', 'expand':1}}) + self.method_entry.bind('<Return>', self.cb_method) + self.delete_button = Button(self.f3, {'text':'Delete method', + 'command':self.cb_delmethod, + Pack:{'side':'left', + 'padx':'0.5m'}}) + + self.newobj_button = Button(self.f4, {'text':'new object', + 'command':self.cb_newobj, + Pack:{'side':'left', + 'padx':'0.5m'}}) + + def cb_delmethod(self, *args): + list = self.method_list.curselection() + for i in list: + self.method_list.delete(i) + + def cb_newobj(self, *arg): + self.parent.objects.append(UI_object(self.parent)) + + def cb_method(self, *arg): + name = self.method_entry.get() + if not name: + return + self.method_entry.delete('0', 'end') + self.method_list.insert('end', name) + + def synchronize(self): + n = self.name_entry.get() + if not n: + message('Module name not set') + raise oops + if not checkid(n): + message('Module name not an identifier:\n'+n) + raise oops + if not self.abbrev_entry.get(): + self.abbrev_entry.insert('end', n) + m = getlistlist(self.method_list) + for n in m: + if not checkid(n): + message('Method name not an identifier:\n'+n) + raise oops + + def gencode(self, name, objects): + rv = '' + self.synchronize() + for o in objects: + o.synchronize() + onames = [] + for i in range(len(objects)): + oname = 'o'+`i+1` + rv = rv + objects[i].gencode(oname) + onames.append(oname) + rv = rv + (name+' = genmodule.module()\n') + rv = rv + (name+'.name = '+`self.name_entry.get()`+'\n') + rv = rv + (name+'.abbrev = '+`self.abbrev_entry.get()`+'\n') + rv = rv + (name+'.methodlist = '+`getlistlist(self.method_list)`+'\n') + rv = rv + (name+'.objects = ['+string.joinfields(onames, ',')+']\n') + rv = rv + ('\n') + return rv + +object_number = 0 + +class UI_object: + def __init__(self, parent): + global object_number + + object_number = object_number + 1 + self.num = object_number + self.vpref = 'o'+`self.num`+'_' + self.frame = Toplevel(parent.objframe) +# self.frame.pack() + self.frame.title('Modulator: object view') +# self.frame = Frame(parent.objframe, {'relief':'raised', 'bd':'0.2m', +# Pack:{'side':'top', +# 'fill':'x'}}) + self.f1 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', + 'fill':'x'}}) + self.f2 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', + 'fill':'x'}}) + self.f3 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', + 'fill':'x'}}) + self.f4 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', + 'fill':'x'}}) + + + self.l1 = Label(self.f1, {'text':'Object:', Pack:{'side':'left', + 'padx':'0.5m'}}) + self.name_entry = Entry(self.f1, {'relief':'sunken', + Pack:{'side':'left', 'padx':'0.5m', 'expand':1}}) + self.l2 = Label(self.f1, {'text':'Abbrev:', Pack:{'side':'left', + 'padx':'0.5m'}}) + self.abbrev_entry = Entry(self.f1, {'relief':'sunken', 'width':5, + Pack:{'side':'left', 'padx':'0.5m'}}) + + self.l3 = Label(self.f2, {'text':'Methods:', Pack:{'side':'left', + 'padx':'0.5m'}}) + self.method_list = ScrolledListbox(self.f2, {'relief':'sunken','bd':2, + Pack:{'side':'left', 'expand':1, + 'padx':'0.5m', 'fill':'both'}}) + + self.l4 = Label(self.f3, {'text':'Add method:', Pack:{'side':'left', + 'padx':'0.5m'}}) + self.method_entry = Entry(self.f3, {'relief':'sunken', + Pack:{'side':'left', 'padx':'0.5m', 'expand':1}}) + self.method_entry.bind('<Return>', self.cb_method) + self.delete_button = Button(self.f3, {'text':'Delete method', + 'command':self.cb_delmethod, + Pack:{'side':'left', + 'padx':'0.5m'}}) + + + self.l5 = Label(self.f4, {'text':'functions:', + Pack:{'side':'left', + 'padx':'0.5m'}}) + self.f5 = Frame(self.f4, {Pack:{'side':'left', 'pady':'0.5m', + 'fill':'both'}}) + self.l6 = Label(self.f4, {'text':'Types:', + Pack:{'side':'left', 'padx':'0.5m'}}) + self.f6 = Frame(self.f4, {Pack:{'side':'left', 'pady':'0.5m', + 'fill':'x'}}) + self.funcs = {} + for i in genmodule.FUNCLIST: + vname = self.vpref+i + self.f5.setvar(vname, 0) + b = Checkbutton(self.f5, {'variable':vname, 'text':i, + Pack:{'side':'top', 'pady':'0.5m', + 'anchor':'w','expand':1}}) + self.funcs[i] = b + self.f5.setvar(self.vpref+'new', 1) + + self.types = {} + for i in genmodule.TYPELIST: + vname = self.vpref + i + self.f6.setvar(vname, 0) + b = Checkbutton(self.f6, {'variable':vname, 'text':i, + Pack:{'side':'top', 'pady':'0.5m', + 'anchor':'w'}}) + self.types[i] = b + + def cb_method(self, *arg): + name = self.method_entry.get() + if not name: + return + self.method_entry.delete('0', 'end') + self.method_list.insert('end', name) + + def cb_delmethod(self, *args): + list = self.method_list.curselection() + for i in list: + self.method_list.delete(i) + + def synchronize(self): + n = self.name_entry.get() + if not n: + message('Object name not set') + raise oops + if not self.abbrev_entry.get(): + self.abbrev_entry.insert('end', n) + n = self.abbrev_entry.get() + if not checkid(n): + message('Abbreviation not an identifier:\n'+n) + raise oops + m = getlistlist(self.method_list) + for n in m: + if not checkid(n): + message('Method name not an identifier:\n'+n) + raise oops + if m: + self.f5.setvar(self.vpref+'tp_getattr', 1) + pass + + def gencode(self, name): + rv = '' + rv = rv + (name+' = genmodule.object()\n') + rv = rv + (name+'.name = '+`self.name_entry.get()`+'\n') + rv = rv + (name+'.abbrev = '+`self.abbrev_entry.get()`+'\n') + rv = rv + (name+'.methodlist = '+`getlistlist(self.method_list)`+'\n') + fl = [] + for fn in genmodule.FUNCLIST: + vname = self.vpref + fn + if self.f5.getvar(vname) == '1': + fl.append(fn) + rv = rv + (name+'.funclist = '+`fl`+'\n') + + fl = [] + for fn in genmodule.TYPELIST: + vname = self.vpref + fn + if self.f5.getvar(vname) == '1': + fl.append(fn) + + rv = rv + (name+'.typelist = '+`fl`+'\n') + + rv = rv + ('\n') + return rv + + +def main(): + if len(sys.argv) < 2: + ui = UI() + ui.run() + elif len(sys.argv) == 2: + fp = open(sys.argv[1]) + pycode = fp.read() + try: + exec pycode + except: + sys.stderr.write('An error occurred:-)\n') + sys.exit(1) + genmodule.write(sys.stdout, m) + else: + sys.stderr.write('Usage: modulator [file]\n') + sys.exit(1) + +main() diff --git a/Tools/modulator/varsubst.py b/Tools/modulator/varsubst.py new file mode 100644 index 0000000..ec89fe3 --- /dev/null +++ b/Tools/modulator/varsubst.py @@ -0,0 +1,61 @@ +# +# Variable substitution. Variables are $delimited$ +# +import string +import regex +import regsub + +error = 'varsubst.error' + +class Varsubst: + def __init__(self, dict): + self.dict = dict + self.prog = regex.compile('\$[a-zA-Z0-9_]*\$') + self.do_useindent = 0 + + def useindent(self, onoff): + self.do_useindent = onoff + + def subst(self, str): + rv = '' + while 1: + pos = self.prog.search(str) + if pos < 0: + return rv + str + if pos: + rv = rv + str[:pos] + str = str[pos:] + len = self.prog.match(str) + if len == 2: + # Escaped dollar + rv = rv + '$' + str = str[2:] + continue + name = str[1:len-1] + str = str[len:] + if not self.dict.has_key(name): + raise error, 'No such variable: '+name + value = self.dict[name] + if self.do_useindent and '\n' in value: + value = self._modindent(value, rv) + rv = rv + value + + def _modindent(self, value, old): + lastnl = string.rfind(old, '\n', 0) + 1 + lastnl = len(old) - lastnl + sub = '\n' + (' '*lastnl) + return regsub.gsub('\n', sub, value) + +def _test(): + import sys + import os + + sys.stderr.write('-- Copying stdin to stdout with environment map --\n') + c = Varsubst(os.environ) + c.useindent(1) + d = sys.stdin.read() + sys.stdout.write(c.subst(d)) + sys.exit(1) + +if __name__ == '__main__': + _test() |