diff options
author | Guido van Rossum <guido@python.org> | 1990-10-14 12:07:46 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 1990-10-14 12:07:46 (GMT) |
commit | 85a5fbbdfea617f6cc8fae82c9e8c2b5c424436d (patch) | |
tree | a1bf57db1c75e2a7029c8f2fad5f8dba4b9ba25c /Modules | |
parent | c636014c430620325f8d213e9ba10d925991b8d7 (diff) | |
download | cpython-85a5fbbdfea617f6cc8fae82c9e8c2b5c424436d.zip cpython-85a5fbbdfea617f6cc8fae82c9e8c2b5c424436d.tar.gz cpython-85a5fbbdfea617f6cc8fae82c9e8c2b5c424436d.tar.bz2 |
Initial revision
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/cgen.py | 458 | ||||
-rw-r--r-- | Modules/cgensupport.c | 369 | ||||
-rw-r--r-- | Modules/cgensupport.h | 15 | ||||
-rw-r--r-- | Modules/cstubs | 1010 | ||||
-rw-r--r-- | Modules/mathmodule.c | 167 | ||||
-rw-r--r-- | Modules/posixmodule.c | 444 | ||||
-rw-r--r-- | Modules/stdwinmodule.c | 1520 | ||||
-rw-r--r-- | Modules/timemodule.c | 178 |
8 files changed, 4161 insertions, 0 deletions
diff --git a/Modules/cgen.py b/Modules/cgen.py new file mode 100644 index 0000000..0cdeaa6 --- /dev/null +++ b/Modules/cgen.py @@ -0,0 +1,458 @@ +# Python script to parse cstubs file for gl and generate C stubs. +# usage: python cgen <cstubs >glmodule.c +# +# XXX BUG return arrays generate wrong code +# XXX need to change error returns into gotos to free mallocked arrays + + +import string +import sys + + +# Function to print to stderr +# +def err(args): + savestdout = sys.stdout + try: + sys.stdout = sys.stderr + for i in args: + print i, + print + finally: + sys.stdout = savestdout + + +# The set of digits that form a number +# +digits = '0123456789' + + +# Function to extract a string of digits from the front of the string. +# Returns the leading string of digits and the remaining string. +# If no number is found, returns '' and the original string. +# +def getnum(s): + n = '' + while s[:1] in digits: + n = n + s[:1] + s = s[1:] + return n, s + + +# Function to check if a string is a number +# +def isnum(s): + if not s: return 0 + for c in s: + if not c in digits: return 0 + return 1 + + +# Allowed function return types +# +return_types = ['void', 'short', 'long'] + + +# Allowed function argument types +# +arg_types = ['char', 'string', 'short', 'float', 'long', 'double'] + + +# Need to classify arguments as follows +# simple input variable +# simple output variable +# input array +# output array +# input giving size of some array +# +# Array dimensions can be specified as follows +# constant +# argN +# constant * argN +# retval +# constant * retval +# +# The dimensions given as constants * something are really +# arrays of points where points are 2- 3- or 4-tuples +# +# We have to consider three lists: +# python input arguments +# C stub arguments (in & out) +# python output arguments (really return values) +# +# There is a mapping from python input arguments to the input arguments +# of the C stub, and a further mapping from C stub arguments to the +# python return values + + +# Exception raised by checkarg() and generate() +# +arg_error = 'bad arg' + + +# Function to check one argument. +# Arguments: the type and the arg "name" (really mode plus subscript). +# Raises arg_error if something's wrong. +# Return type, mode, factor, rest of subscript; factor and rest may be empty. +# +def checkarg(type, arg): + # + # Turn "char *x" into "string x". + # + if type = 'char' and arg[0] = '*': + type = 'string' + arg = arg[1:] + # + # Check that the type is supported. + # + if type not in arg_types: + raise arg_error, ('bad type', type) + # + # Split it in the mode (first character) and the rest. + # + mode, rest = arg[:1], arg[1:] + # + # The mode must be 's' for send (= input) or 'r' for return argument. + # + if mode not in ('r', 's'): + raise arg_error, ('bad arg mode', mode) + # + # Is it a simple argument: if so, we are done. + # + if not rest: + return type, mode, '', '' + # + # Not a simple argument; must be an array. + # The 'rest' must be a subscript enclosed in [ and ]. + # The subscript must be one of the following forms, + # otherwise we don't handle it (where N is a number): + # N + # argN + # retval + # N*argN + # N*retval + # + if rest[:1] <> '[' or rest[-1:] <> ']': + raise arg_error, ('subscript expected', rest) + sub = rest[1:-1] + # + # Is there a leading number? + # + num, sub = getnum(sub) + if num: + # There is a leading number + if not sub: + # The subscript is just a number + return type, mode, num, '' + if sub[:1] = '*': + # There is a factor prefix + sub = sub[1:] + else: + raise arg_error, ('\'*\' expected', sub) + if sub = 'retval': + # size is retval -- must be a reply argument + if mode <> 'r': + raise arg_error, ('non-r mode with [retval]', mode) + elif sub[:3] <> 'arg' or not isnum(sub[3:]): + raise arg_error, ('bad subscript', sub) + # + return type, mode, num, sub + + +# List of functions for which we have generated stubs +# +functions = [] + + +# Generate the stub for the given function, using the database of argument +# information build by successive calls to checkarg() +# +def generate(type, func, database): + # + # Check that we can handle this case: + # no variable size reply arrays yet + # + n_in_args = 0 + n_out_args = 0 + # + for a_type, a_mode, a_factor, a_sub in database: + if a_mode = 's': + n_in_args = n_in_args + 1 + elif a_mode = 'r': + n_out_args = n_out_args + 1 + else: + # Can't happen + raise arg_error, ('bad a_mode', a_mode) + if (a_mode = 'r' and a_sub) or a_sub = 'retval': + e = 'Function', func, 'too complicated:' + err(e + (a_type, a_mode, a_factor, a_sub)) + print '/* XXX Too complicated to generate code for */' + return + # + functions.append(func) + # + # Stub header + # + print + print 'static object *' + print 'gl_' + func + '(self, args)' + print '\tobject *self;' + print '\tobject *args;' + print '{' + # + # Declare return value if any + # + if type <> 'void': + print '\t' + type, 'retval;' + # + # Declare arguments + # + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + print '\t' + a_type, + if a_sub: + print '*', + print 'arg' + `i+1`, + if a_factor and not a_sub: + print '[', a_factor, ']', + print ';' + # + # Find input arguments derived from array sizes + # + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode = 's' and a_sub[:3] = 'arg' and isnum(a_sub[3:]): + # Sending a variable-length array + n = eval(a_sub[3:]) + if 1 <= n <= len(database): + b_type, b_mode, b_factor, b_sub = database[n-1] + if b_mode = 's': + database[n-1] = b_type, 'i', a_factor, `i` + n_in_args = n_in_args - 1 + # + # Assign argument positions in the Python argument list + # + in_pos = [] + i_in = 0 + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode = 's': + in_pos.append(i_in) + i_in = i_in + 1 + else: + in_pos.append(-1) + # + # Get input arguments + # + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode = 'i': + # + # Implicit argument; + # a_factor is divisor if present, + # a_sub indicates which arg (`database index`) + # + j = eval(a_sub) + print '\tif', + print '(!geti' + a_type + 'arraysize(args,', + print `n_in_args` + ',', + print `in_pos[j]` + ',', + print '&arg' + `i+1` + '))' + print '\t\treturn NULL;' + if a_factor: + print '\targ' + `i+1`, + print '= arg' + `i+1`, + print '/', a_factor + ';' + elif a_mode = 's': + if a_sub: # Allocate memory for varsize array + print '\tif ((arg' + `i+1`, '=', + print 'NEW(' + a_type + ',', + if a_factor: print a_factor, '*', + print a_sub, ')) == NULL)' + print '\t\treturn err_nomem();' + print '\tif', + if a_factor or a_sub: # Get a fixed-size array array + print '(!geti' + a_type + 'array(args,', + print `n_in_args` + ',', + print `in_pos[i]` + ',', + if a_factor: print a_factor, + if a_factor and a_sub: print '*', + if a_sub: print a_sub, + print ', arg' + `i+1` + '))' + else: # Get a simple variable + print '(!geti' + a_type + 'arg(args,', + print `n_in_args` + ',', + print `in_pos[i]` + ',', + print '&arg' + `i+1` + '))' + print '\t\treturn NULL;' + # + # Begin of function call + # + if type <> 'void': + print '\tretval =', func + '(', + else: + print '\t' + func + '(', + # + # Argument list + # + for i in range(len(database)): + if i > 0: print ',', + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode = 'r' and not a_factor: + print '&', + print 'arg' + `i+1`, + # + # End of function call + # + print ');' + # + # Free varsize arrays + # + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode = 's' and a_sub: + print '\tDEL(arg' + `i+1` + ');' + # + # Return + # + if n_out_args: + # + # Multiple return values -- construct a tuple + # + if type <> 'void': + n_out_args = n_out_args + 1 + if n_out_args = 1: + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode = 'r': + break + else: + raise arg_error, 'expected r arg not found' + print '\treturn', + print mkobject(a_type, 'arg' + `i+1`) + ';' + else: + print '\t{ object *v = newtupleobject(', + print n_out_args, ');' + print '\t if (v == NULL) return NULL;' + i_out = 0 + if type <> 'void': + print '\t settupleitem(v,', + print `i_out` + ',', + print mkobject(type, 'retval') + ');' + i_out = i_out + 1 + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode = 'r': + print '\t settupleitem(v,', + print `i_out` + ',', + s = mkobject(a_type, 'arg' + `i+1`) + print s + ');' + i_out = i_out + 1 + print '\t return v;' + print '\t}' + else: + # + # Simple function return + # Return None or return value + # + if type = 'void': + print '\tINCREF(None);' + print '\treturn None;' + else: + print '\treturn', mkobject(type, 'retval') + ';' + # + # Stub body closing brace + # + print '}' + + +# Subroutine to return a function call to mknew<type>object(<arg>) +# +def mkobject(type, arg): + return 'mknew' + type + 'object(' + arg + ')' + + +# Input line number +lno = 0 + + +# Input is divided in two parts, separated by a line containing '%%'. +# <part1> -- literally copied to stdout +# <part2> -- stub definitions + +# Variable indicating the current input part. +# +part = 1 + +# Main loop over the input +# +while 1: + try: + line = raw_input() + except EOFError: + break + # + lno = lno+1 + words = string.split(line) + # + if part = 1: + # + # In part 1, copy everything literally + # except look for a line of just '%%' + # + if words = ['%%']: + part = part + 1 + else: + # + # Look for names of manually written + # stubs: a single percent followed by the name + # of the function in Python. + # The stub name is derived by prefixing 'gl_'. + # + if words and words[0][0] = '%': + func = words[0][1:] + if (not func) and words[1:]: + func = words[1] + if func: + functions.append(func) + else: + print line + elif not words: + pass # skip empty line + elif words[0] = '#include': + print line + elif words[0][:1] = '#': + pass # ignore comment + elif words[0] not in return_types: + err('Line', lno, ': bad return type :', words[0]) + elif len(words) < 2: + err('Line', lno, ': no funcname :', line) + else: + if len(words) % 2 <> 0: + err('Line', lno, ': odd argument list :', words[2:]) + else: + database = [] + try: + for i in range(2, len(words), 2): + x = checkarg(words[i], words[i+1]) + database.append(x) + print + print '/*', + for w in words: print w, + print '*/' + generate(words[0], words[1], database) + except arg_error, msg: + err('Line', lno, ':', msg) + + +print +print 'static struct methodlist gl_methods[] = {' +for func in functions: + print '\t{"' + func + '", gl_' + func + '},' +print '\t{NULL, NULL} /* Sentinel */' +print '};' +print +print 'initgl()' +print '{' +print '\tinitmodule("gl", gl_methods);' +print '}' diff --git a/Modules/cgensupport.c b/Modules/cgensupport.c new file mode 100644 index 0000000..a81c90b --- /dev/null +++ b/Modules/cgensupport.c @@ -0,0 +1,369 @@ +/* Functions used by cgen output */ + +#include <stdio.h> + +#include "PROTO.h" +#include "object.h" +#include "intobject.h" +#include "floatobject.h" +#include "stringobject.h" +#include "tupleobject.h" +#include "listobject.h" +#include "methodobject.h" +#include "moduleobject.h" +#include "modsupport.h" +#include "import.h" +#include "cgensupport.h" +#include "errors.h" + + +/* Functions to construct return values */ + +object * +mknewcharobject(c) + int c; +{ + char ch[1]; + ch[0] = c; + return newsizedstringobject(ch, 1); +} + +/* Functions to extract arguments. + These needs to know the total number of arguments supplied, + since the argument list is a tuple only of there is more than + one argument. */ + +int +getiobjectarg(args, nargs, i, p_arg) + register object *args; + int nargs, i; + object **p_arg; +{ + if (nargs != 1) { + if (args == NULL || !is_tupleobject(args) || + nargs != gettuplesize(args) || + i < 0 || i >= nargs) { + return err_badarg(); + } + else { + args = gettupleitem(args, i); + } + } + if (args == NULL) { + return err_badarg(); + } + *p_arg = args; + return 1; +} + +int +getilongarg(args, nargs, i, p_arg) + register object *args; + int nargs, i; + long *p_arg; +{ + if (nargs != 1) { + if (args == NULL || !is_tupleobject(args) || + nargs != gettuplesize(args) || + i < 0 || i >= nargs) { + return err_badarg(); + } + args = gettupleitem(args, i); + } + if (args == NULL || !is_intobject(args)) { + return err_badarg(); + } + *p_arg = getintvalue(args); + return 1; +} + +int +getishortarg(args, nargs, i, p_arg) + register object *args; + int nargs, i; + short *p_arg; +{ + long x; + if (!getilongarg(args, nargs, i, &x)) + return 0; + *p_arg = x; + return 1; +} + +static int +extractdouble(v, p_arg) + register object *v; + double *p_arg; +{ + if (v == NULL) { + /* Fall through to error return at end of function */ + } + else if (is_floatobject(v)) { + *p_arg = GETFLOATVALUE((floatobject *)v); + return 1; + } + else if (is_intobject(v)) { + *p_arg = GETINTVALUE((intobject *)v); + return 1; + } + return err_badarg(); +} + +static int +extractfloat(v, p_arg) + register object *v; + float *p_arg; +{ + if (v == NULL) { + /* Fall through to error return at end of function */ + } + else if (is_floatobject(v)) { + *p_arg = GETFLOATVALUE((floatobject *)v); + return 1; + } + else if (is_intobject(v)) { + *p_arg = GETINTVALUE((intobject *)v); + return 1; + } + return err_badarg(); +} + +int +getifloatarg(args, nargs, i, p_arg) + register object *args; + int nargs, i; + float *p_arg; +{ + object *v; + float x; + if (!getiobjectarg(args, nargs, i, &v)) + return 0; + if (!extractfloat(v, &x)) + return 0; + *p_arg = x; + return 1; +} + +int +getistringarg(args, nargs, i, p_arg) + object *args; + int nargs, i; + string *p_arg; +{ + object *v; + if (!getiobjectarg(args, nargs, i, &v)) + return NULL; + if (!is_stringobject(v)) { + return err_badarg(); + } + *p_arg = getstringvalue(v); + return 1; +} + +int +getichararg(args, nargs, i, p_arg) + object *args; + int nargs, i; + char *p_arg; +{ + string x; + if (!getistringarg(args, nargs, i, &x)) + return 0; + if (x[0] == '\0' || x[1] != '\0') { + /* Not exactly one char */ + return err_badarg(); + } + *p_arg = x[0]; + return 1; +} + +int +getilongarraysize(args, nargs, i, p_arg) + object *args; + int nargs, i; + long *p_arg; +{ + object *v; + if (!getiobjectarg(args, nargs, i, &v)) + return 0; + if (is_tupleobject(v)) { + *p_arg = gettuplesize(v); + return 1; + } + if (is_listobject(v)) { + *p_arg = getlistsize(v); + return 1; + } + return err_badarg(); +} + +int +getishortarraysize(args, nargs, i, p_arg) + object *args; + int nargs, i; + short *p_arg; +{ + long x; + if (!getilongarraysize(args, nargs, i, &x)) + return 0; + *p_arg = x; + return 1; +} + +/* XXX The following four are too similar. Should share more code. */ + +int +getilongarray(args, nargs, i, n, p_arg) + object *args; + int nargs, i; + int n; + long *p_arg; /* [n] */ +{ + object *v, *w; + if (!getiobjectarg(args, nargs, i, &v)) + return 0; + if (is_tupleobject(v)) { + if (gettuplesize(v) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + w = gettupleitem(v, i); + if (!is_intobject(w)) { + return err_badarg(); + } + p_arg[i] = getintvalue(w); + } + return 1; + } + else if (is_listobject(v)) { + if (getlistsize(v) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + w = getlistitem(v, i); + if (!is_intobject(w)) { + return err_badarg(); + } + p_arg[i] = getintvalue(w); + } + return 1; + } + else { + return err_badarg(); + } +} + +int +getishortarray(args, nargs, i, n, p_arg) + object *args; + int nargs, i; + int n; + short *p_arg; /* [n] */ +{ + object *v, *w; + if (!getiobjectarg(args, nargs, i, &v)) + return 0; + if (is_tupleobject(v)) { + if (gettuplesize(v) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + w = gettupleitem(v, i); + if (!is_intobject(w)) { + return err_badarg(); + } + p_arg[i] = getintvalue(w); + } + return 1; + } + else if (is_listobject(v)) { + if (getlistsize(v) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + w = getlistitem(v, i); + if (!is_intobject(w)) { + return err_badarg(); + } + p_arg[i] = getintvalue(w); + } + return 1; + } + else { + return err_badarg(); + } +} + +int +getidoublearray(args, nargs, i, n, p_arg) + object *args; + int nargs, i; + int n; + double *p_arg; /* [n] */ +{ + object *v, *w; + if (!getiobjectarg(args, nargs, i, &v)) + return 0; + if (is_tupleobject(v)) { + if (gettuplesize(v) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + w = gettupleitem(v, i); + if (!extractdouble(w, &p_arg[i])) + return 0; + } + return 1; + } + else if (is_listobject(v)) { + if (getlistsize(v) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + w = getlistitem(v, i); + if (!extractdouble(w, &p_arg[i])) + return 0; + } + return 1; + } + else { + return err_badarg(); + } +} + +int +getifloatarray(args, nargs, i, n, p_arg) + object *args; + int nargs, i; + int n; + float *p_arg; /* [n] */ +{ + object *v, *w; + if (!getiobjectarg(args, nargs, i, &v)) + return 0; + if (is_tupleobject(v)) { + if (gettuplesize(v) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + w = gettupleitem(v, i); + if (!extractfloat(w, &p_arg[i])) + return 0; + } + return 1; + } + else if (is_listobject(v)) { + if (getlistsize(v) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + w = getlistitem(v, i); + if (!extractfloat(w, &p_arg[i])) + return 0; + } + return 1; + } + else { + return err_badarg(); + } +} diff --git a/Modules/cgensupport.h b/Modules/cgensupport.h new file mode 100644 index 0000000..8b3af07 --- /dev/null +++ b/Modules/cgensupport.h @@ -0,0 +1,15 @@ +/* Definitions used by cgen output */ + +typedef char *string; + +#define mknewlongobject(x) newintobject(x) +#define mknewshortobject(x) newintobject((long)x) +#define mknewfloatobject(x) newfloatobject(x) + +extern object *mknewcharobject PROTO((int c)); + +extern int getiobjectarg PROTO((object *args, int nargs, int i, object **p_a)); +extern int getilongarg PROTO((object *args, int nargs, int i, long *p_a)); +extern int getishortarg PROTO((object *args, int nargs, int i, short *p_a)); +extern int getifloatarg PROTO((object *args, int nargs, int i, float *p_a)); +extern int getistringarg PROTO((object *args, int nargs, int i, string *p_a)); diff --git a/Modules/cstubs b/Modules/cstubs new file mode 100644 index 0000000..f0f5ade --- /dev/null +++ b/Modules/cstubs @@ -0,0 +1,1010 @@ +/* +Input used to generate the Python module "glmodule.c". +The stub generator is a Python script called "cgen". + +Each definition must be contained on one line: + +<returntype> <name> <type> <arg> <type> <arg> + +<returntype> can be: void, short, long (XXX maybe others?) + +<type> can be: char, string, short, float, long, or double + string indicates a null terminated string; + if <type> is char and <arg> begins with a *, the * is stripped + and <type> is changed into string + +<arg> has the form <mode> or <mode>[<subscript>] + where <mode> can be + s: arg is sent + r: arg is received (arg is a pointer) + and <subscript> can be (N and I are numbers): + N + argI + retval + N*argI + N*retval +*/ + +#include <stdio.h> +#include <gl.h> +#include <device.h> +#include "PROTO.h" +#include "object.h" +#include "intobject.h" +#include "floatobject.h" +#include "listobject.h" +#include "tupleobject.h" +#include "dictobject.h" +#include "methodobject.h" +#include "moduleobject.h" +#include "objimpl.h" +#include "import.h" +#include "sigtype.h" +#include "modsupport.h" +#include "cgensupport.h" +#include "errors.h" + +/* +Some stubs are too complicated for the stub generator. +We can include manually written versions of them here. +A line starting with '%' gives the name of the function so the stub +generator can include it in the table of functions. +*/ + +/* +varray -- an array of v.. calls. +The argument is an array (maybe list or tuple) of points. +Each point must be a tuple or list of coordinates (x, y, z). +The points may be 2- or 3-dimensional but must all have the +same dimension. Float and int values may be mixed however. +The points are always converted to 3D double precision points +by assuming z=0.0 if necessary (as indicated in the man page), +and for each point v3d() is called. +*/ + +% varray + +static object * +gl_varray(self, args) + object *self; + object *args; +{ + object *v, *w; + int i, n, width; + double vec[3]; + object * (*getitem) FPROTO((object *, int)); + + if (!getiobjectarg(args, 1, 0, &v)) + return NULL; + + if (is_listobject(v)) { + n = getlistsize(v); + getitem = getlistitem; + } + else if (is_tupleobject(v)) { + n = gettuplesize(v); + getitem = gettupleitem; + } + else { + err_badarg(); + return NULL; + } + + if (n == 0) { + INCREF(None); + return None; + } + if (n > 0) + w = (*getitem)(v, 0); + + width = 0; + if (w == NULL) { + } + else if (is_listobject(w)) { + width = getlistsize(w); + } + else if (is_tupleobject(w)) { + width = gettuplesize(w); + } + + switch (width) { + case 2: + vec[2] = 0.0; + /* Fall through */ + case 3: + break; + default: + err_badarg(); + return NULL; + } + + for (i = 0; i < n; i++) { + w = (*getitem)(v, i); + if (!getidoublearray(w, 1, 0, width, vec)) + return NULL; + v3d(vec); + } + + INCREF(None); + return None; +} + +/* +vnarray, nvarray -- an array of n3f and v3f calls. +The argument is an array (list or tuple) of pairs of points and normals. +Each pair is a tuple (NOT a list) of a point and a normal for that point. +Each point or normal must be a tuple (NOT a list) of coordinates (x, y, z). +Three coordinates must be given. Float and int values may be mixed. +For each pair, n3f() is called for the normal, and then v3f() is called +for the vector. + +vnarray and nvarray differ only in the order of the vector and normal in +the pair: vnarray expects (v, n) while nvarray expects (n, v). +*/ + +static object *gen_nvarray(); /* Forward */ + +% nvarray + +static object * +gl_nvarray(self, args) + object *self; + object *args; +{ + return gen_nvarray(args, 0); +} + +% vnarray + +static object * +gl_vnarray(self, args) + object *self; + object *args; +{ + return gen_nvarray(args, 1); +} + +/* Generic, internal version of {nv,nv}array: inorm indicates the + argument order, 0: normal first, 1: vector first. */ + +static object * +gen_nvarray(args, inorm) + object *args; + int inorm; +{ + object *v, *w, *wnorm, *wvec; + int i, n; + float norm[3], vec[3]; + object * (*getitem) FPROTO((object *, int)); + + if (!getiobjectarg(args, 1, 0, &v)) + return NULL; + + if (is_listobject(v)) { + n = getlistsize(v); + getitem = getlistitem; + } + else if (is_tupleobject(v)) { + n = gettuplesize(v); + getitem = gettupleitem; + } + else { + err_badarg(); + return NULL; + } + + for (i = 0; i < n; i++) { + w = (*getitem)(v, i); + if (!is_tupleobject(w) || gettuplesize(w) != 2) { + err_badarg(); + return NULL; + } + wnorm = gettupleitem(w, inorm); + wvec = gettupleitem(w, 1 - inorm); + if (!getifloatarray(wnorm, 1, 0, 3, norm) || + !getifloatarray(wvec, 1, 0, 3, vec)) + return NULL; + n3f(norm); + v3f(vec); + } + + INCREF(None); + return None; +} + +/* nurbssurface(s_knots[], t_knots[], ctl[][], s_order, t_order, type). + The dimensions of ctl[] are computed as follows: + [len(s_knots) - s_order], [len(t_knots) - t_order] +*/ + +% nurbssurface + +static object * +gl_nurbssurface(self, args) + object *self; + object *args; +{ + long arg1 ; + double * arg2 ; + long arg3 ; + double * arg4 ; + double *arg5 ; + long arg6 ; + long arg7 ; + long arg8 ; + long ncoords; + long s_byte_stride, t_byte_stride; + long s_nctl, t_nctl; + long s, t; + object *v, *w, *pt; + double *pnext; + if (!getilongarraysize(args, 6, 0, &arg1)) + return NULL; + if ((arg2 = NEW(double, arg1 )) == NULL) { + return err_nomem(); + } + if (!getidoublearray(args, 6, 0, arg1 , arg2)) + return NULL; + if (!getilongarraysize(args, 6, 1, &arg3)) + return NULL; + if ((arg4 = NEW(double, arg3 )) == NULL) { + return err_nomem(); + } + if (!getidoublearray(args, 6, 1, arg3 , arg4)) + return NULL; + if (!getilongarg(args, 6, 3, &arg6)) + return NULL; + if (!getilongarg(args, 6, 4, &arg7)) + return NULL; + if (!getilongarg(args, 6, 5, &arg8)) + return NULL; + if (arg8 == N_XYZ) + ncoords = 3; + else if (arg8 == N_XYZW) + ncoords = 4; + else { + err_badarg(); + return NULL; + } + s_nctl = arg1 - arg6; + t_nctl = arg3 - arg7; + if (!getiobjectarg(args, 6, 2, &v)) + return NULL; + if (!is_listobject(v) || getlistsize(v) != s_nctl) { + err_badarg(); + return NULL; + } + if ((arg5 = NEW(double, s_nctl*t_nctl*ncoords )) == NULL) { + return err_nomem(); + } + pnext = arg5; + for (s = 0; s < s_nctl; s++) { + w = getlistitem(v, s); + if (w == NULL || !is_listobject(w) || + getlistsize(w) != t_nctl) { + err_badarg(); + return NULL; + } + for (t = 0; t < t_nctl; t++) { + pt = getlistitem(w, t); + if (!getidoublearray(pt, 1, 0, ncoords, pnext)) + return NULL; + pnext += ncoords; + } + } + s_byte_stride = sizeof(double) * ncoords; + t_byte_stride = s_byte_stride * s_nctl; + nurbssurface( arg1 , arg2 , arg3 , arg4 , + s_byte_stride , t_byte_stride , arg5 , arg6 , arg7 , arg8 ); + DEL(arg2); + DEL(arg4); + DEL(arg5); + INCREF(None); + return None; +} + +/* nurbscurve(knots, ctlpoints, order, type). + The length of ctlpoints is len(knots)-order. */ + +%nurbscurve + +static object * +gl_nurbscurve(self, args) + object *self; + object *args; +{ + long arg1 ; + double * arg2 ; + long arg3 ; + double * arg4 ; + long arg5 ; + long arg6 ; + int ncoords, npoints; + int i; + object *v; + double *pnext; + if (!getilongarraysize(args, 4, 0, &arg1)) + return NULL; + if ((arg2 = NEW(double, arg1 )) == NULL) { + return err_nomem(); + } + if (!getidoublearray(args, 4, 0, arg1 , arg2)) + return NULL; + if (!getilongarg(args, 4, 2, &arg5)) + return NULL; + if (!getilongarg(args, 4, 3, &arg6)) + return NULL; + if (arg6 == N_ST) + ncoords = 2; + else if (arg6 == N_STW) + ncoords = 3; + else { + err_badarg(); + return NULL; + } + npoints = arg1 - arg5; + if (!getiobjectarg(args, 4, 1, &v)) + return NULL; + if (!is_listobject(v) || getlistsize(v) != npoints) { + err_badarg(); + return NULL; + } + if ((arg4 = NEW(double, npoints*ncoords )) == NULL) { + return err_nomem(); + } + pnext = arg4; + for (i = 0; i < npoints; i++) { + if (!getidoublearray(getlistitem(v, i), 1, 0, ncoords, pnext)) + return NULL; + pnext += ncoords; + } + arg3 = (sizeof(double)) * ncoords; + nurbscurve( arg1 , arg2 , arg3 , arg4 , arg5 , arg6 ); + DEL(arg2); + DEL(arg4); + INCREF(None); + return None; +} + +/* pwlcurve(points, type). + Points is a list of points. Type must be N_ST. */ + +%pwlcurve + +static object * +gl_pwlcurve(self, args) + object *self; + object *args; +{ + object *v; + long type; + double *data, *pnext; + long npoints, ncoords; + int i; + if (!getiobjectarg(args, 2, 0, &v)) + return NULL; + if (!getilongarg(args, 2, 1, &type)) + return NULL; + if (!is_listobject(v)) { + err_badarg(); + return NULL; + } + npoints = getlistsize(v); + if (type == N_ST) + ncoords = 2; + else { + err_badarg(); + return NULL; + } + if ((data = NEW(double, npoints*ncoords)) == NULL) { + return err_nomem(); + } + pnext = data; + for (i = 0; i < npoints; i++) { + if (!getidoublearray(getlistitem(v, i), 1, 0, ncoords, pnext)) + return NULL; + pnext += ncoords; + } + pwlcurve(npoints, data, sizeof(double)*ncoords, type); + DEL(data); + INCREF(None); + return None; +} + + +/* Picking and Selecting */ + +static short *pickbuffer = NULL; +static long pickbuffersize; + +static object * +pick_select(args, func) + object *args; + void (*func)(); +{ + if (!getilongarg(args, 1, 0, &pickbuffersize)) + return NULL; + if (pickbuffer != NULL) { + err_setstr(RuntimeError, + "pick/gselect: already picking/selecting"); + return NULL; + } + if ((pickbuffer = NEW(short, pickbuffersize)) == NULL) { + return err_nomem(); + } + (*func)(pickbuffer, pickbuffersize); + INCREF(None); + return None; +} + +static object * +endpick_select(args, func) + object *args; + long (*func)(); +{ + object *v, *w; + int i, nhits, n; + if (!getnoarg(args)) + return NULL; + if (pickbuffer == NULL) { + err_setstr(RuntimeError, + "endpick/endselect: not in pick/select mode"); + return NULL; + } + nhits = (*func)(pickbuffer); + if (nhits < 0) { + nhits = -nhits; /* How to report buffer overflow otherwise? */ + } + /* Scan the buffer to see how many integers */ + n = 0; + for (; nhits > 0; nhits--) { + n += 1 + pickbuffer[n]; + } + v = newlistobject(n); + if (v == NULL) + return NULL; + /* XXX Could do it nicer and interpret the data structure here, + returning a list of lists. But this can be done in Python... */ + for (i = 0; i < n; i++) { + w = newintobject((long)pickbuffer[i]); + if (w == NULL) { + DECREF(v); + return NULL; + } + setlistitem(v, i, w); + } + DEL(pickbuffer); + pickbuffer = NULL; + return v; +} + +extern void pick(), gselect(); +extern long endpick(), endselect(); + +%pick +static object *gl_pick(self, args) object *self, *args; { + return pick_select(args, pick); +} + +%endpick +static object *gl_endpick(self, args) object *self, *args; { + return endpick_select(args, endpick); +} + +%gselect +static object *gl_gselect(self, args) object *self, *args; { + return pick_select(args, gselect); +} + +%endselect +static object *gl_endselect(self, args) object *self, *args; { + return endpick_select(args, endselect); +} + + +/* XXX The generator botches this one. Here's a quick hack to fix it. */ + +% getmatrix float r[16] + +static object * +gl_getmatrix(self, args) + object *self; + object *args; +{ + float arg1 [ 16 ] ; + object *v, *w; + int i; + getmatrix( arg1 ); + v = newlistobject(16); + if (v == NULL) { + return err_nomem(); + } + for (i = 0; i < 16; i++) { + w = mknewfloatobject(arg1[i]); + if (w == NULL) { + DECREF(v); + return NULL; + } + setlistitem(v, i, w); + } + return v; +} + +/* End of manually written stubs */ + +%% + +long getshade +void devport short s long s +void rdr2i long s long s +void rectfs short s short s short s short s +void rects short s short s short s short s +void rmv2i long s long s +void noport +void popviewport +void clear +void clearhitcode +void closeobj +void cursoff +void curson +void doublebuffer +void finish +void gconfig +void ginit +void greset +void multimap +void onemap +void popattributes +void popmatrix +void pushattributes +void pushmatrix +void pushviewport +void qreset +void RGBmode +void singlebuffer +void swapbuffers +void gsync +void tpon +void tpoff +void clkon +void clkoff +void ringbell +#void callfunc +void gbegin +void textinit +void initnames +void pclos +void popname +void spclos +void zclear +void screenspace +void reshapeviewport +void winpush +void winpop +void foreground +void endfullscrn +void endpupmode +void fullscrn +void pupmode +void winconstraints +void pagecolor short s +void textcolor short s +void color short s +void curveit short s +void font short s +void linewidth short s +void setlinestyle short s +void setmap short s +void swapinterval short s +void writemask short s +void textwritemask short s +void qdevice short s +void unqdevice short s +void curvebasis short s +void curveprecision short s +void loadname short s +void passthrough short s +void pushname short s +void setmonitor short s +void setshade short s +void setpattern short s +void pagewritemask short s +# +void callobj long s +void delobj long s +void editobj long s +void makeobj long s +void maketag long s +void chunksize long s +void compactify long s +void deltag long s +void lsrepeat long s +void objinsert long s +void objreplace long s +void winclose long s +void blanktime long s +void freepup long s +# This is not in the library!? +###void pupcolor long s +# +void backbuffer long s +void frontbuffer long s +void lsbackup long s +void resetls long s +void lampon long s +void lampoff long s +void setbell long s +void blankscreen long s +void depthcue long s +void zbuffer long s +void backface long s +# +void cmov2i long s long s +void draw2i long s long s +void move2i long s long s +void pnt2i long s long s +void patchbasis long s long s +void patchprecision long s long s +void pdr2i long s long s +void pmv2i long s long s +void rpdr2i long s long s +void rpmv2i long s long s +void xfpt2i long s long s +void objdelete long s long s +void patchcurves long s long s +void minsize long s long s +void maxsize long s long s +void keepaspect long s long s +void prefsize long s long s +void stepunit long s long s +void fudge long s long s +void winmove long s long s +# +void attachcursor short s short s +void deflinestyle short s short s +void noise short s short s +void picksize short s short s +void qenter short s short s +void setdepth short s short s +void cmov2s short s short s +void draw2s short s short s +void move2s short s short s +void pdr2s short s short s +void pmv2s short s short s +void pnt2s short s short s +void rdr2s short s short s +void rmv2s short s short s +void rpdr2s short s short s +void rpmv2s short s short s +void xfpt2s short s short s +# +void cmov2 float s float s +void draw2 float s float s +void move2 float s float s +void pnt2 float s float s +void pdr2 float s float s +void pmv2 float s float s +void rdr2 float s float s +void rmv2 float s float s +void rpdr2 float s float s +void rpmv2 float s float s +void xfpt2 float s float s +# +void loadmatrix float s[16] +void multmatrix float s[16] +void crv float s[16] +void rcrv float s[16] +# +# Methods that have strings. +# +void addtopup long s char *s long s +void charstr char *s +void getport char *s +long strwidth char *s +long winopen char *s +void wintitle char *s +# +# Methods that have 1 long (# of elements) and an array +# +void polf long s float s[3*arg1] +void polf2 long s float s[2*arg1] +void poly long s float s[3*arg1] +void poly2 long s float s[2*arg1] +void crvn long s float s[3*arg1] +void rcrvn long s float s[4*arg1] +# +void polf2i long s long s[2*arg1] +void polfi long s long s[3*arg1] +void poly2i long s long s[2*arg1] +void polyi long s long s[3*arg1] +# +void polf2s long s short s[2*arg1] +void polfs long s short s[3*arg1] +void polys long s short s[3*arg1] +void poly2s long s short s[2*arg1] +# +void defcursor short s short s[16] +void writepixels short s short s[arg1] +void defbasis long s float s[16] +void gewrite short s short s[arg1] +# +void rotate short s char s +# This is not in the library!? +###void setbutton short s char s +void rot float s char s +# +void circfi long s long s long s +void circi long s long s long s +void cmovi long s long s long s +void drawi long s long s long s +void movei long s long s long s +void pnti long s long s long s +void newtag long s long s long s +void pdri long s long s long s +void pmvi long s long s long s +void rdri long s long s long s +void rmvi long s long s long s +void rpdri long s long s long s +void rpmvi long s long s long s +void xfpti long s long s long s +# +void circ float s float s float s +void circf float s float s float s +void cmov float s float s float s +void draw float s float s float s +void move float s float s float s +void pnt float s float s float s +void scale float s float s float s +void translate float s float s float s +void pdr float s float s float s +void pmv float s float s float s +void rdr float s float s float s +void rmv float s float s float s +void rpdr float s float s float s +void rpmv float s float s float s +void xfpt float s float s float s +# +void RGBcolor short s short s short s +void RGBwritemask short s short s short s +void setcursor short s short s short s +void tie short s short s short s +void circfs short s short s short s +void circs short s short s short s +void cmovs short s short s short s +void draws short s short s short s +void moves short s short s short s +void pdrs short s short s short s +void pmvs short s short s short s +void pnts short s short s short s +void rdrs short s short s short s +void rmvs short s short s short s +void rpdrs short s short s short s +void rpmvs short s short s short s +void xfpts short s short s short s +void curorigin short s short s short s +void cyclemap short s short s short s +# +void patch float s[16] float s[16] float s[16] +void splf long s float s[3*arg1] short s[arg1] +void splf2 long s float s[2*arg1] short s[arg1] +void splfi long s long s[3*arg1] short s[arg1] +void splf2i long s long s[2*arg1] short s[arg1] +void splfs long s short s[3*arg1] short s[arg1] +void splf2s long s short s[2*arg1] short s[arg1] +void defpattern short s short s short s[arg2*arg2/16] +# +void rpatch float s[16] float s[16] float s[16] float s[16] +# +# routines that send 4 floats +# +void ortho2 float s float s float s float s +void rect float s float s float s float s +void rectf float s float s float s float s +void xfpt4 float s float s float s float s +# +void textport short s short s short s short s +void mapcolor short s short s short s short s +void scrmask short s short s short s short s +void setvaluator short s short s short s short s +void viewport short s short s short s short s +void shaderange short s short s short s short s +void xfpt4s short s short s short s short s +void rectfi long s long s long s long s +void recti long s long s long s long s +void xfpt4i long s long s long s long s +void prefposition long s long s long s long s +# +void arc float s float s float s short s short s +void arcf float s float s float s short s short s +void arcfi long s long s long s short s short s +void arci long s long s long s short s short s +# +void bbox2 short s short s float s float s float s float s +void bbox2i short s short s long s long s long s long s +void bbox2s short s short s short s short s short s short s +void blink short s short s short s short s short s +void ortho float s float s float s float s float s float s +void window float s float s float s float s float s float s +void lookat float s float s float s float s float s float s short s +# +void perspective short s float s float s float s +void polarview float s short s short s short s +# XXX getichararray not supported +#void writeRGB short s char s[arg1] char s[arg1] char s[arg1] +# +void arcfs short s short s short s short s short s +void arcs short s short s short s short s short s +void rectcopy short s short s short s short s short s short s +void RGBcursor short s short s short s short s short s short s short s +# +long getbutton short s +long getcmmode +long getlsbackup +long getresetls +long getdcm +long getzbuffer +long ismex +long isobj long s +long isqueued short s +long istag long s +# +long genobj +long gentag +long getbuffer +long getcolor +long getdisplaymode +long getfont +long getheight +long gethitcode +long getlstyle +long getlwidth +long getmap +long getplanes +long getwritemask +long qtest +long getlsrepeat +long getmonitor +long getopenobj +long getpattern +long winget +long winattach +long getothermonitor +long newpup +# +long getvaluator short s +void winset long s +long dopup long s +void getdepth short r short r +void getcpos short r short r +void getsize long r long r +void getorigin long r long r +void getviewport short r short r short r short r +void gettp short r short r short r short r +void getgpos float r float r float r float r +void winposition long s long s long s long s +void gRGBcolor short r short r short r +void gRGBmask short r short r short r +void getscrmask short r short r short r short r +void gRGBcursor short r short r short r short r short r short r short r short r long * +void getmcolor short s short r short r short r +void mapw long s short s short s float r float r float r float r float r float r +void mapw2 long s short s short s float r float r +void defrasterfont short s short s short s Fontchar s[arg3] short s short s[4*arg5] +long qread short r +void getcursor short r short r short r long r +# +# For these we receive arrays of stuff +# +void getdev long s short s[arg1] short r[arg1] +#XXX not generated correctly yet +#void getmatrix float r[16] +long readpixels short s short r[retval] +long readRGB short s char r[retval] char r[retval] char r[retval] +long blkqread short s short r[arg1] +# +# New 4D routines +# +void cmode +void concave long s +void curstype long s +void drawmode long s +void gammaramp short s[256] short s[256] short s[256] +long getbackface +long getdescender +long getdrawmode +long getmmode +long getsm +long getvideo long s +void imakebackground +void lmbind short s short s +void lmdef long s long s long s float s[arg3] +void mmode long s +void normal float s[3] +void overlay long s +void RGBrange short s short s short s short s short s short s short s short s +void setvideo long s long s +void shademodel long s +void underlay long s +# +# New Personal Iris/GT Routines +# +void bgnclosedline +void bgnline +void bgnpoint +void bgnpolygon +void bgnsurface +void bgntmesh +void bgntrim +void endclosedline +void endline +void endpoint +void endpolygon +void endsurface +void endtmesh +void endtrim +void blendfunction long s long s +void c3f float s[3] +void c3i long s[3] +void c3s short s[3] +void c4f float s[4] +void c4i long s[4] +void c4s short s[4] +void colorf float s +void cpack long s +void czclear long s long s +void dglclose long s +long dglopen char *s long s +long getgdesc long s +void getnurbsproperty long s float r +void glcompat long s long s +void iconsize long s long s +void icontitle char *s +void lRGBrange short s short s short s short s short s short s long s long s +void linesmooth long s +void lmcolor long s +void logicop long s +long lrectread short s short s short s short s long r[retval] +void lrectwrite short s short s short s short s long s[(arg2-arg1+1)*(arg4-arg3+1)] +long rectread short s short s short s short s short r[retval] +void rectwrite short s short s short s short s short s[(arg2-arg1+1)*(arg4-arg3+1)] +void lsetdepth long s long s +void lshaderange short s short s long s long s +void n3f float s[3] +void noborder +void pntsmooth long s +void readsource long s +void rectzoom float s float s +void sbox float s float s float s float s +void sboxi long s long s long s long s +void sboxs short s short s short s short s +void sboxf float s float s float s float s +void sboxfi long s long s long s long s +void sboxfs short s short s short s short s +void setnurbsproperty long s float s +void setpup long s long s long s +void smoothline long s +void subpixel long s +void swaptmesh +long swinopen long s +void v2f float s[2] +void v2i long s[2] +void v2s short s[2] +void v3f float s[3] +void v3i long s[3] +void v3s short s[3] +void v4f float s[4] +void v4i long s[4] +void v4s short s[4] +void videocmd long s +long windepth long s +void wmpack long s +void zdraw long s +void zfunction long s +void zsource long s +void zwritemask long s +# +# uses doubles +# +void v2d double s[2] +void v3d double s[3] +void v4d double s[4] diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c new file mode 100644 index 0000000..400790f --- /dev/null +++ b/Modules/mathmodule.c @@ -0,0 +1,167 @@ +/* Math module -- standard C math library functions, pi and e */ + +#include <stdio.h> +#include <math.h> + +#include "PROTO.h" +#include "object.h" +#include "intobject.h" +#include "tupleobject.h" +#include "floatobject.h" +#include "dictobject.h" +#include "methodobject.h" +#include "moduleobject.h" +#include "objimpl.h" +#include "import.h" +#include "modsupport.h" + +static int +getdoublearg(args, px) + register object *args; + double *px; +{ + if (args == NULL) + return err_badarg(); + if (is_floatobject(args)) { + *px = getfloatvalue(args); + return 1; + } + if (is_intobject(args)) { + *px = getintvalue(args); + return 1; + } + return err_badarg(); +} + +static int +get2doublearg(args, px, py) + register object *args; + double *px, *py; +{ + if (args == NULL || !is_tupleobject(args) || gettuplesize(args) != 2) + return err_badarg(); + return getdoublearg(gettupleitem(args, 0), px) && + getdoublearg(gettupleitem(args, 1), py); +} + +static object * +math_1(args, func) + object *args; + double (*func) FPROTO((double)); +{ + double x; + if (!getdoublearg(args, &x)) + return NULL; + errno = 0; + x = (*func)(x); + if (errno != 0) + return NULL; + else + return newfloatobject(x); +} + +static object * +math_2(args, func) + object *args; + double (*func) FPROTO((double, double)); +{ + double x, y; + if (!get2doublearg(args, &x, &y)) + return NULL; + errno = 0; + x = (*func)(x, y); + if (errno != 0) + return NULL; + else + return newfloatobject(x); +} + +#define FUNC1(stubname, func) \ + static object * stubname(self, args) object *self, *args; { \ + return math_1(args, func); \ + } + +#define FUNC2(stubname, func) \ + static object * stubname(self, args) object *self, *args; { \ + return math_2(args, func); \ + } + +FUNC1(math_acos, acos) +FUNC1(math_asin, asin) +FUNC1(math_atan, atan) +FUNC2(math_atan2, atan2) +FUNC1(math_ceil, ceil) +FUNC1(math_cos, cos) +FUNC1(math_cosh, cosh) +FUNC1(math_exp, exp) +FUNC1(math_fabs, fabs) +FUNC1(math_floor, floor) +#if 0 +/* XXX This one is not in the Amoeba library yet, so what the heck... */ +FUNC2(math_fmod, fmod) +#endif +FUNC1(math_log, log) +FUNC1(math_log10, log10) +FUNC2(math_pow, pow) +FUNC1(math_sin, sin) +FUNC1(math_sinh, sinh) +FUNC1(math_sqrt, sqrt) +FUNC1(math_tan, tan) +FUNC1(math_tanh, tanh) + +#if 0 +/* What about these? */ +double frexp(double x, int *i); +double ldexp(double x, int n); +double modf(double x, double *i); +#endif + +static struct methodlist math_methods[] = { + {"acos", math_acos}, + {"asin", math_asin}, + {"atan", math_atan}, + {"atan2", math_atan2}, + {"ceil", math_ceil}, + {"cos", math_cos}, + {"cosh", math_cosh}, + {"exp", math_exp}, + {"fabs", math_fabs}, + {"floor", math_floor}, +#if 0 + {"fmod", math_fmod}, + {"frexp", math_freqp}, + {"ldexp", math_ldexp}, +#endif + {"log", math_log}, + {"log10", math_log10}, +#if 0 + {"modf", math_modf}, +#endif + {"pow", math_pow}, + {"sin", math_sin}, + {"sinh", math_sinh}, + {"sqrt", math_sqrt}, + {"tan", math_tan}, + {"tanh", math_tanh}, + {NULL, NULL} /* sentinel */ +}; + +void +initmath() +{ + object *m, *d, *v; + struct methodlist *ml; + if ((m = new_module("math")) == NULL) + fatal("can't create math module"); + d = getmoduledict(m); + for (ml = math_methods; ml->ml_name != NULL; ml++) { + v = newmethodobject(ml->ml_name, ml->ml_meth, (object *)NULL); + if (v == NULL || dictinsert(d, ml->ml_name, v) != 0) { + fatal("can't initialize math module"); + } + DECREF(v); + } + dictinsert(d, "pi", newfloatobject(atan(1.0) * 4.0)); + dictinsert(d, "e", newfloatobject(exp(1.0))); + DECREF(m); +} diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c new file mode 100644 index 0000000..0c1a487 --- /dev/null +++ b/Modules/posixmodule.c @@ -0,0 +1,444 @@ +/* POSIX module implementation */ + +#include <stdio.h> +#include <signal.h> +#include <string.h> +#include <setjmp.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#ifdef SYSV +#include <dirent.h> +#define direct dirent +#else +#include <sys/dir.h> +#endif + +#include "PROTO.h" +#include "object.h" +#include "intobject.h" +#include "stringobject.h" +#include "tupleobject.h" +#include "listobject.h" +#include "dictobject.h" +#include "methodobject.h" +#include "moduleobject.h" +#include "objimpl.h" +#include "import.h" +#include "sigtype.h" +#include "modsupport.h" +#include "errors.h" + +extern char *strerror(); + +#ifdef AMOEBA +#define NO_LSTAT +#endif + + +/* Return a dictionary corresponding to the POSIX environment table */ + +extern char **environ; + +static object * +convertenviron() +{ + object *d; + char **e; + d = newdictobject(); + if (d == NULL) + return NULL; + if (environ == NULL) + return d; + /* XXX This part ignores errors */ + for (e = environ; *e != NULL; e++) { + object *v; + char *p = strchr(*e, '='); + if (p == NULL) + continue; + v = newstringobject(p+1); + if (v == NULL) + continue; + *p = '\0'; + (void) dictinsert(d, *e, v); + *p = '='; + DECREF(v); + } + return d; +} + + +static object *PosixError; /* Exception posix.error */ + +/* Set a POSIX-specific error from errno, and return NULL */ + +static object * +posix_error() +{ + object *v = newtupleobject(2); + if (v != NULL) { + settupleitem(v, 0, newintobject((long)errno)); + settupleitem(v, 1, newstringobject(strerror(errno))); + } + err_setval(PosixError, v); + if (v != NULL) + DECREF(v); + return NULL; +} + + +/* POSIX generic methods */ + +static object * +posix_1str(args, func) + object *args; + int (*func) FPROTO((const char *)); +{ + object *path1; + if (!getstrarg(args, &path1)) + return NULL; + if ((*func)(getstringvalue(path1)) < 0) + return posix_error(); + INCREF(None); + return None; +} + +static object * +posix_2str(args, func) + object *args; + int (*func) FPROTO((const char *, const char *)); +{ + object *path1, *path2; + if (!getstrstrarg(args, &path1, &path2)) + return NULL; + if ((*func)(getstringvalue(path1), getstringvalue(path2)) < 0) + return posix_error(); + INCREF(None); + return None; +} + +static object * +posix_strint(args, func) + object *args; + int (*func) FPROTO((const char *, int)); +{ + object *path1; + int i; + if (!getstrintarg(args, &path1, &i)) + return NULL; + if ((*func)(getstringvalue(path1), i) < 0) + return posix_error(); + INCREF(None); + return None; +} + +static object * +posix_do_stat(self, args, statfunc) + object *self; + object *args; + int (*statfunc) FPROTO((const char *, struct stat *)); +{ + struct stat st; + object *path; + object *v; + if (!getstrarg(args, &path)) + return NULL; + if ((*statfunc)(getstringvalue(path), &st) != 0) + return posix_error(); + v = newtupleobject(10); + if (v == NULL) + return NULL; + errno = 0; +#define SET(i, st_member) settupleitem(v, i, newintobject((long)st.st_member)) + SET(0, st_mode); + SET(1, st_ino); + SET(2, st_dev); + SET(3, st_nlink); + SET(4, st_uid); + SET(5, st_gid); + SET(6, st_size); + SET(7, st_atime); + SET(8, st_mtime); + SET(9, st_ctime); +#undef SET + if (errno != 0) { + DECREF(v); + return err_nomem(); + } + return v; +} + + +/* POSIX methods */ + +static object * +posix_chdir(self, args) + object *self; + object *args; +{ + extern int chdir PROTO((const char *)); + return posix_1str(args, chdir); +} + +static object * +posix_chmod(self, args) + object *self; + object *args; +{ + extern int chmod PROTO((const char *, mode_t)); + return posix_strint(args, chmod); +} + +static object * +posix_getcwd(self, args) + object *self; + object *args; +{ + char buf[1026]; + extern char *getcwd PROTO((char *, int)); + if (!getnoarg(args)) + return NULL; + if (getcwd(buf, sizeof buf) == NULL) + return posix_error(); + return newstringobject(buf); +} + +static object * +posix_link(self, args) + object *self; + object *args; +{ + extern int link PROTO((const char *, const char *)); + return posix_2str(args, link); +} + +static object * +posix_listdir(self, args) + object *self; + object *args; +{ + object *name, *d, *v; + DIR *dirp; + struct direct *ep; + if (!getstrarg(args, &name)) + return NULL; + if ((dirp = opendir(getstringvalue(name))) == NULL) + return posix_error(); + if ((d = newlistobject(0)) == NULL) { + closedir(dirp); + return NULL; + } + while ((ep = readdir(dirp)) != NULL) { + v = newstringobject(ep->d_name); + if (v == NULL) { + DECREF(d); + d = NULL; + break; + } + if (addlistitem(d, v) != 0) { + DECREF(v); + DECREF(d); + d = NULL; + break; + } + DECREF(v); + } + closedir(dirp); + return d; +} + +static object * +posix_mkdir(self, args) + object *self; + object *args; +{ + extern int mkdir PROTO((const char *, mode_t)); + return posix_strint(args, mkdir); +} + +static object * +posix_rename(self, args) + object *self; + object *args; +{ + extern int rename PROTO((const char *, const char *)); + return posix_2str(args, rename); +} + +static object * +posix_rmdir(self, args) + object *self; + object *args; +{ + extern int rmdir PROTO((const char *)); + return posix_1str(args, rmdir); +} + +static object * +posix_stat(self, args) + object *self; + object *args; +{ + extern int stat PROTO((const char *, struct stat *)); + return posix_do_stat(self, args, stat); +} + +static object * +posix_system(self, args) + object *self; + object *args; +{ + object *command; + int sts; + if (!getstrarg(args, &command)) + return NULL; + sts = system(getstringvalue(command)); + return newintobject((long)sts); +} + +static object * +posix_umask(self, args) + object *self; + object *args; +{ + int i; + if (!getintarg(args, &i)) + return NULL; + i = umask(i); + if (i < 0) + return posix_error(); + return newintobject((long)i); +} + +static object * +posix_unlink(self, args) + object *self; + object *args; +{ + extern int unlink PROTO((const char *)); + return posix_1str(args, unlink); +} + +static object * +posix_utimes(self, args) + object *self; + object *args; +{ + object *path; + struct timeval tv[2]; + if (args == NULL || !is_tupleobject(args) || gettuplesize(args) != 2) { + err_badarg(); + return NULL; + } + if (!getstrarg(gettupleitem(args, 0), &path) || + !getlonglongargs(gettupleitem(args, 1), + &tv[0].tv_sec, &tv[1].tv_sec)) + return NULL; + tv[0].tv_usec = tv[1].tv_usec = 0; + if (utimes(getstringvalue(path), tv) < 0) + return posix_error(); + INCREF(None); + return None; +} + +#ifdef NO_GETCWD + +/* Quick hack to get posix.getcwd() working for pure BSD 4.3 */ +/* XXX This assumes MAXPATHLEN = 1024 !!! */ + +static char * +getcwd(buf, size) + char *buf; + int size; +{ + extern char *getwd PROTO((char *)); + register char *ret = getwd(buf); + if (ret == NULL) + errno = EACCES; /* Most likely error */ + return ret; +} + +#endif /* NO_GETCWD */ + + +#ifndef NO_LSTAT + +static object * +posix_lstat(self, args) + object *self; + object *args; +{ + extern int lstat PROTO((const char *, struct stat *)); + return posix_do_stat(self, args, lstat); +} + +static object * +posix_readlink(self, args) + object *self; + object *args; +{ + char buf[1024]; /* XXX Should use MAXPATHLEN */ + object *path; + int n; + if (!getstrarg(args, &path)) + return NULL; + n = readlink(getstringvalue(path), buf, sizeof buf); + if (n < 0) + return posix_error(); + return newsizedstringobject(buf, n); +} + +static object * +posix_symlink(self, args) + object *self; + object *args; +{ + extern int symlink PROTO((const char *, const char *)); + return posix_2str(args, symlink); +} + +#endif /* NO_LSTAT */ + + +static struct methodlist posix_methods[] = { + {"chdir", posix_chdir}, + {"chmod", posix_chmod}, + {"getcwd", posix_getcwd}, + {"link", posix_link}, + {"listdir", posix_listdir}, + {"mkdir", posix_mkdir}, + {"rename", posix_rename}, + {"rmdir", posix_rmdir}, + {"stat", posix_stat}, + {"system", posix_system}, + {"umask", posix_umask}, + {"unlink", posix_unlink}, + {"utimes", posix_utimes}, +#ifndef NO_LSTAT + {"lstat", posix_lstat}, + {"readlink", posix_readlink}, + {"symlink", posix_symlink}, +#endif + {NULL, NULL} /* Sentinel */ +}; + + +void +initposix() +{ + object *m, *d, *v; + + m = initmodule("posix", posix_methods); + d = getmoduledict(m); + + /* Initialize posix.environ dictionary */ + v = convertenviron(); + if (v == NULL || dictinsert(d, "environ", v) != 0) + fatal("can't define posix.environ"); + DECREF(v); + + /* Initialize posix.error exception */ + PosixError = newstringobject("posix.error"); + if (PosixError == NULL || dictinsert(d, "error", PosixError) != 0) + fatal("can't define posix.error"); +} diff --git a/Modules/stdwinmodule.c b/Modules/stdwinmodule.c new file mode 100644 index 0000000..3f472bb --- /dev/null +++ b/Modules/stdwinmodule.c @@ -0,0 +1,1520 @@ +/* Stdwin module */ + +/* Stdwin itself is a module, not a separate object type. + Object types defined here: + wp: a window + dp: a drawing structure (only one can exist at a time) + mp: a menu + tp: a textedit block +*/ + +/* Rules for translating C stdwin function calls into Python stwin: + - All names drop their initial letter 'w' + - Functions with a window as first parameter are methods of window objects + - There is no equivalent for wclose(); just delete the window object + (all references to it!) (XXX maybe this is a bad idea) + - w.begindrawing() returns a drawing object + - There is no equivalent for wenddrawing(win); just delete the drawing + object (all references to it!) (XXX maybe this is a bad idea) + - Functions that may only be used inside wbegindrawing / wendddrawing + are methods of the drawing object; this includes the text measurement + functions (which however have doubles as module functions). + - Methods of the drawing object drop an initial 'draw' from their name + if they have it, e.g., wdrawline() --> d.line() + - The obvious type conversions: int --> intobject; string --> stringobject + - A text parameter followed by a length parameter is only a text (string) + parameter in Python + - A point or other pair of horizontal and vertical coordinates is always + a pair of integers in Python + - Two points forming a rectangle or endpoints of a line segment are a + pair of points in Python + - The arguments to d.elarc() are three points. + - The functions wgetclip() and wsetclip() are translated into + stdwin.getcutbuffer() and stdwin.setcutbuffer(); 'clip' is really + a bad word for what these functions do (clipping has a different + meaning in the drawing world), while cutbuffer is standard X jargon. + - For textedit, similar rules hold, but they are less strict. + XXX more? +*/ + +#include <stdio.h> +#include "stdwin.h" + +#include "PROTO.h" +#include "object.h" +#include "intobject.h" +#include "stringobject.h" +#include "tupleobject.h" +#include "dictobject.h" +#include "methodobject.h" +#include "moduleobject.h" +#include "objimpl.h" +#include "import.h" +#include "modsupport.h" +#include "errors.h" + + +/* Window and menu object types declared here because of forward references */ + +typedef struct { + OB_HEAD + object *w_title; + WINDOW *w_win; + object *w_attr; /* Attributes dictionary */ +} windowobject; + +extern typeobject Windowtype; /* Really static, forward */ + +#define is_windowobject(wp) ((wp)->ob_type == &Windowtype) + +typedef struct { + OB_HEAD + MENU *m_menu; + int m_id; + object *m_attr; /* Attributes dictionary */ +} menuobject; + +extern typeobject Menutype; /* Really static, forward */ + +#define is_menuobject(mp) ((mp)->ob_type == &Menutype) + + +/* Strongly stdwin-specific argument handlers */ + +static int +getmousedetail(v, ep) + object *v; + EVENT *ep; +{ + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 4) + return err_badarg(); + return getintintarg(gettupleitem(v, 0), + &ep->u.where.h, &ep->u.where.v) && + getintarg(gettupleitem(v, 1), &ep->u.where.clicks) && + getintarg(gettupleitem(v, 2), &ep->u.where.button) && + getintarg(gettupleitem(v, 3), &ep->u.where.mask); +} + +static int +getmenudetail(v, ep) + object *v; + EVENT *ep; +{ + object *mp; + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) + return err_badarg(); + mp = gettupleitem(v, 0); + if (mp == NULL || !is_menuobject(mp)) + return err_badarg(); + ep->u.m.id = ((menuobject *)mp) -> m_id; + return getintarg(gettupleitem(v, 1), &ep->u.m.item); +} + +static int +geteventarg(v, ep) + object *v; + EVENT *ep; +{ + object *wp, *detail; + int a[4]; + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 3) + return err_badarg(); + if (!getintarg(gettupleitem(v, 0), &ep->type)) + return 0; + wp = gettupleitem(v, 1); + if (wp == None) + ep->window = NULL; + else if (wp == NULL || !is_windowobject(wp)) + return err_badarg(); + else + ep->window = ((windowobject *)wp) -> w_win; + detail = gettupleitem(v, 2); + switch (ep->type) { + case WE_CHAR: + if (!is_stringobject(detail) || getstringsize(detail) != 1) + return err_badarg(); + ep->u.character = getstringvalue(detail)[0]; + return 1; + case WE_COMMAND: + return getintarg(detail, &ep->u.command); + case WE_DRAW: + if (!getrectarg(detail, a)) + return 0; + ep->u.area.left = a[0]; + ep->u.area.top = a[1]; + ep->u.area.right = a[2]; + ep->u.area.bottom = a[3]; + return 1; + case WE_MOUSE_DOWN: + case WE_MOUSE_UP: + case WE_MOUSE_MOVE: + return getmousedetail(detail, ep); + case WE_MENU: + return getmenudetail(detail, ep); + default: + return 1; + } +} + + +/* Return construction tools */ + +static object * +makepoint(a, b) + int a, b; +{ + object *v; + object *w; + if ((v = newtupleobject(2)) == NULL) + return NULL; + if ((w = newintobject((long)a)) == NULL || + settupleitem(v, 0, w) != 0 || + (w = newintobject((long)b)) == NULL || + settupleitem(v, 1, w) != 0) { + DECREF(v); + return NULL; + } + return v; +} + +static object * +makerect(a, b, c, d) + int a, b, c, d; +{ + object *v; + object *w; + if ((v = newtupleobject(2)) == NULL) + return NULL; + if ((w = makepoint(a, b)) == NULL || + settupleitem(v, 0, w) != 0 || + (w = makepoint(c, d)) == NULL || + settupleitem(v, 1, w) != 0) { + DECREF(v); + return NULL; + } + return v; +} + +static object * +makemouse(hor, ver, clicks, button, mask) + int hor, ver, clicks, button, mask; +{ + object *v; + object *w; + if ((v = newtupleobject(4)) == NULL) + return NULL; + if ((w = makepoint(hor, ver)) == NULL || + settupleitem(v, 0, w) != 0 || + (w = newintobject((long)clicks)) == NULL || + settupleitem(v, 1, w) != 0 || + (w = newintobject((long)button)) == NULL || + settupleitem(v, 2, w) != 0 || + (w = newintobject((long)mask)) == NULL || + settupleitem(v, 3, w) != 0) { + DECREF(v); + return NULL; + } + return v; +} + +static object * +makemenu(mp, item) + object *mp; + int item; +{ + object *v; + object *w; + if ((v = newtupleobject(2)) == NULL) + return NULL; + INCREF(mp); + if (settupleitem(v, 0, mp) != 0 || + (w = newintobject((long)item)) == NULL || + settupleitem(v, 1, w) != 0) { + DECREF(v); + return NULL; + } + return v; +} + + +/* Drawing objects */ + +typedef struct { + OB_HEAD + windowobject *d_ref; +} drawingobject; + +static drawingobject *Drawing; /* Set to current drawing object, or NULL */ + +/* Drawing methods */ + +static void +drawing_dealloc(dp) + drawingobject *dp; +{ + wenddrawing(dp->d_ref->w_win); + Drawing = NULL; + DECREF(dp->d_ref); + free((char *)dp); +} + +static object * +drawing_generic(dp, args, func) + drawingobject *dp; + object *args; + void (*func) FPROTO((int, int, int, int)); +{ + int a[4]; + if (!getrectarg(args, a)) + return NULL; + (*func)(a[0], a[1], a[2], a[3]); + INCREF(None); + return None; +} + +static object * +drawing_line(dp, args) + drawingobject *dp; + object *args; +{ + drawing_generic(dp, args, wdrawline); +} + +static object * +drawing_xorline(dp, args) + drawingobject *dp; + object *args; +{ + drawing_generic(dp, args, wxorline); +} + +static object * +drawing_circle(dp, args) + drawingobject *dp; + object *args; +{ + int a[3]; + if (!getpointintarg(args, a)) + return NULL; + wdrawcircle(a[0], a[1], a[2]); + INCREF(None); + return None; +} + +static object * +drawing_elarc(dp, args) + drawingobject *dp; + object *args; +{ + int a[6]; + if (!get3pointarg(args, a)) + return NULL; + wdrawelarc(a[0], a[1], a[2], a[3], a[4], a[5]); + INCREF(None); + return None; +} + +static object * +drawing_box(dp, args) + drawingobject *dp; + object *args; +{ + drawing_generic(dp, args, wdrawbox); +} + +static object * +drawing_erase(dp, args) + drawingobject *dp; + object *args; +{ + drawing_generic(dp, args, werase); +} + +static object * +drawing_paint(dp, args) + drawingobject *dp; + object *args; +{ + drawing_generic(dp, args, wpaint); +} + +static object * +drawing_invert(dp, args) + drawingobject *dp; + object *args; +{ + drawing_generic(dp, args, winvert); +} + +static object * +drawing_cliprect(dp, args) + drawingobject *dp; + object *args; +{ + drawing_generic(dp, args, wcliprect); +} + +static object * +drawing_noclip(dp, args) + drawingobject *dp; + object *args; +{ + if (!getnoarg(args)) + return NULL; + wnoclip(); + INCREF(None); + return None; +} + +static object * +drawing_shade(dp, args) + drawingobject *dp; + object *args; +{ + int a[5]; + if (!getrectintarg(args, a)) + return NULL; + wshade(a[0], a[1], a[2], a[3], a[4]); + INCREF(None); + return None; +} + +static object * +drawing_text(dp, args) + drawingobject *dp; + object *args; +{ + int a[2]; + object *s; + if (!getpointstrarg(args, a, &s)) + return NULL; + wdrawtext(a[0], a[1], getstringvalue(s), (int)getstringsize(s)); + INCREF(None); + return None; +} + +/* The following four are also used as stdwin functions */ + +static object * +drawing_lineheight(dp, args) + drawingobject *dp; + object *args; +{ + if (!getnoarg(args)) + return NULL; + return newintobject((long)wlineheight()); +} + +static object * +drawing_baseline(dp, args) + drawingobject *dp; + object *args; +{ + if (!getnoarg(args)) + return NULL; + return newintobject((long)wbaseline()); +} + +static object * +drawing_textwidth(dp, args) + drawingobject *dp; + object *args; +{ + object *s; + if (!getstrarg(args, &s)) + return NULL; + return newintobject( + (long)wtextwidth(getstringvalue(s), (int)getstringsize(s))); +} + +static object * +drawing_textbreak(dp, args) + drawingobject *dp; + object *args; +{ + object *s; + int a; + if (!getstrintarg(args, &s, &a)) + return NULL; + return newintobject( + (long)wtextbreak(getstringvalue(s), (int)getstringsize(s), a)); +} + +static struct methodlist drawing_methods[] = { + {"box", drawing_box}, + {"circle", drawing_circle}, + {"cliprect", drawing_cliprect}, + {"elarc", drawing_elarc}, + {"erase", drawing_erase}, + {"invert", drawing_invert}, + {"line", drawing_line}, + {"noclip", drawing_noclip}, + {"paint", drawing_paint}, + {"shade", drawing_shade}, + {"text", drawing_text}, + {"xorline", drawing_xorline}, + + /* Text measuring methods: */ + {"baseline", drawing_baseline}, + {"lineheight", drawing_lineheight}, + {"textbreak", drawing_textbreak}, + {"textwidth", drawing_textwidth}, + {NULL, NULL} /* sentinel */ +}; + +static object * +drawing_getattr(wp, name) + drawingobject *wp; + char *name; +{ + return findmethod(drawing_methods, (object *)wp, name); +} + +static typeobject Drawingtype = { + OB_HEAD_INIT(&Typetype) + 0, /*ob_size*/ + "drawing", /*tp_name*/ + sizeof(drawingobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + drawing_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + drawing_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ +}; + + +/* Text(edit) objects */ + +typedef struct { + OB_HEAD + TEXTEDIT *t_text; + windowobject *t_ref; + object *t_attr; /* Attributes dictionary */ +} textobject; + +extern typeobject Texttype; /* Really static, forward */ + +static textobject * +newtextobject(wp, left, top, right, bottom) + windowobject *wp; + int left, top, right, bottom; +{ + textobject *tp; + tp = NEWOBJ(textobject, &Texttype); + if (tp == NULL) + return NULL; + tp->t_attr = NULL; + INCREF(wp); + tp->t_ref = wp; + tp->t_text = tecreate(wp->w_win, left, top, right, bottom); + if (tp->t_text == NULL) { + DECREF(tp); + return (textobject *) err_nomem(); + } + return tp; +} + +/* Text(edit) methods */ + +static void +text_dealloc(tp) + textobject *tp; +{ + if (tp->t_text != NULL) + tefree(tp->t_text); + if (tp->t_attr != NULL) + DECREF(tp->t_attr); + DECREF(tp->t_ref); + DEL(tp); +} + +static object * +text_arrow(self, args) + textobject *self; + object *args; +{ + int code; + if (!getintarg(args, &code)) + return NULL; + tearrow(self->t_text, code); + INCREF(None); + return None; +} + +static object * +text_draw(self, args) + textobject *self; + object *args; +{ + register TEXTEDIT *tp = self->t_text; + int a[4]; + int left, top, right, bottom; + if (!getrectarg(args, a)) + return NULL; + if (Drawing != NULL) { + err_setstr(RuntimeError, "not drawing"); + return NULL; + } + /* Clip to text area and ignore if area is empty */ + left = tegetleft(tp); + top = tegettop(tp); + right = tegetright(tp); + bottom = tegetbottom(tp); + if (a[0] < left) a[0] = left; + if (a[1] < top) a[1] = top; + if (a[2] > right) a[2] = right; + if (a[3] > bottom) a[3] = bottom; + if (a[0] < a[2] && a[1] < a[3]) { + /* Hide/show focus around draw call; these are undocumented, + but required here to get the highlighting correct. + The call to werase is also required for this reason. + Finally, this forces us to require (above) that we are NOT + already drawing. */ + tehidefocus(tp); + wbegindrawing(self->t_ref->w_win); + werase(a[0], a[1], a[2], a[3]); + tedrawnew(tp, a[0], a[1], a[2], a[3]); + wenddrawing(self->t_ref->w_win); + teshowfocus(tp); + } + INCREF(None); + return None; +} + +static object * +text_event(self, args) + textobject *self; + object *args; +{ + register TEXTEDIT *tp = self->t_text; + EVENT e; + if (!geteventarg(args, &e)) + return NULL; + if (e.type == WE_MOUSE_DOWN) { + /* Cheat at the left margin */ + if (e.u.where.h < 0 && tegetleft(tp) == 0) + e.u.where.h = 0; + /* XXX should also check right margin and bottom, + but we have no wgetdocsize() yet */ + } + return newintobject((long) teevent(tp, &e)); +} + +static object * +text_getfocus(self, args) + textobject *self; + object *args; +{ + if (!getnoarg(args)) + return NULL; + return makepoint(tegetfoc1(self->t_text), tegetfoc2(self->t_text)); +} + +static object * +text_getfocustext(self, args) + textobject *self; + object *args; +{ + int f1, f2; + char *text; + if (!getnoarg(args)) + return NULL; + f1 = tegetfoc1(self->t_text); + f2 = tegetfoc2(self->t_text); + text = tegettext(self->t_text); + return newsizedstringobject(text + f1, f2-f1); +} + +static object * +text_getrect(self, args) + textobject *self; + object *args; +{ + if (!getnoarg(args)) + return NULL; + return makerect(tegetleft(self->t_text), + tegettop(self->t_text), + tegetright(self->t_text), + tegetbottom(self->t_text)); +} + +static object * +text_gettext(self, args) + textobject *self; + object *args; +{ + if (!getnoarg(args)) + return NULL; + return newsizedstringobject(tegettext(self->t_text), + tegetlen(self->t_text)); +} + +static object * +text_move(self, args) + textobject *self; + object *args; +{ + int a[4]; + if (!getrectarg(args, a)) + return NULL; + temovenew(self->t_text, a[0], a[1], a[2], a[3]); + INCREF(None); + return None; +} + +static object * +text_setfocus(self, args) + textobject *self; + object *args; +{ + int a[2]; + if (!getpointarg(args, a)) + return NULL; + tesetfocus(self->t_text, a[0], a[1]); + INCREF(None); + return None; +} + +static object * +text_replace(self, args) + textobject *self; + object *args; +{ + object *text; + if (!getstrarg(args, &text)) + return NULL; + tereplace(self->t_text, getstringvalue(text)); + INCREF(None); + return None; +} + +static struct methodlist text_methods[] = { + "arrow", text_arrow, + "draw", text_draw, + "event", text_event, + "getfocus", text_getfocus, + "getfocustext", text_getfocustext, + "getrect", text_getrect, + "gettext", text_gettext, + "move", text_move, + "replace", text_replace, + "setfocus", text_setfocus, + {NULL, NULL} /* sentinel */ +}; + +static object * +text_getattr(tp, name) + textobject *tp; + char *name; +{ + if (tp->t_attr != NULL) { + object *v = dictlookup(tp->t_attr, name); + if (v != NULL) { + INCREF(v); + return v; + } + } + return findmethod(text_methods, (object *)tp, name); +} + +static int +text_setattr(tp, name, v) + textobject *tp; + char *name; + object *v; +{ + if (tp->t_attr == NULL) { + tp->t_attr = newdictobject(); + if (tp->t_attr == NULL) + return -1; + } + if (v == NULL) + return dictremove(tp->t_attr, name); + else + return dictinsert(tp->t_attr, name, v); +} + +static typeobject Texttype = { + OB_HEAD_INIT(&Typetype) + 0, /*ob_size*/ + "textedit", /*tp_name*/ + sizeof(textobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + text_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + text_getattr, /*tp_getattr*/ + text_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ +}; + + +/* Menu objects */ + +#define MAXNMENU 50 +static menuobject *menulist[MAXNMENU]; /* Slot 0 unused */ + +static menuobject * +newmenuobject(title) + object *title; +{ + int id; + MENU *menu; + menuobject *mp; + for (id = 1; id < MAXNMENU; id++) { + if (menulist[id] == NULL) + break; + } + if (id >= MAXNMENU) + return (menuobject *) err_nomem(); + menu = wmenucreate(id, getstringvalue(title)); + if (menu == NULL) + return (menuobject *) err_nomem(); + mp = NEWOBJ(menuobject, &Menutype); + if (mp != NULL) { + mp->m_menu = menu; + mp->m_id = id; + mp->m_attr = NULL; + menulist[id] = mp; + } + else + wmenudelete(menu); + return mp; +} + +/* Menu methods */ + +static void +menu_dealloc(mp) + menuobject *mp; +{ + + int id = mp->m_id; + if (id >= 0 && id < MAXNMENU) { + menulist[id] = NULL; + } + wmenudelete(mp->m_menu); + if (mp->m_attr != NULL) + DECREF(mp->m_attr); + DEL(mp); +} + +static object * +menu_additem(self, args) + menuobject *self; + object *args; +{ + object *text; + int shortcut; + if (is_tupleobject(args)) { + object *v; + if (!getstrstrarg(args, &text, &v)) + return NULL; + if (getstringsize(v) != 1) { + err_badarg(); + return NULL; + } + shortcut = *getstringvalue(v) & 0xff; + } + else { + if (!getstrarg(args, &text)) + return NULL; + shortcut = -1; + } + wmenuadditem(self->m_menu, getstringvalue(text), shortcut); + INCREF(None); + return None; +} + +static object * +menu_setitem(self, args) + menuobject *self; + object *args; +{ + int index; + object *text; + if (!getintstrarg(args, &index, &text)) + return NULL; + wmenusetitem(self->m_menu, index, getstringvalue(text)); + INCREF(None); + return None; +} + +static object * +menu_enable(self, args) + menuobject *self; + object *args; +{ + int index; + int flag; + if (!getintintarg(args, &index, &flag)) + return NULL; + wmenuenable(self->m_menu, index, flag); + INCREF(None); + return None; +} + +static object * +menu_check(self, args) + menuobject *self; + object *args; +{ + int index; + int flag; + if (!getintintarg(args, &index, &flag)) + return NULL; + wmenucheck(self->m_menu, index, flag); + INCREF(None); + return None; +} + +static struct methodlist menu_methods[] = { + "additem", menu_additem, + "setitem", menu_setitem, + "enable", menu_enable, + "check", menu_check, + {NULL, NULL} /* sentinel */ +}; + +static object * +menu_getattr(mp, name) + menuobject *mp; + char *name; +{ + if (mp->m_attr != NULL) { + object *v = dictlookup(mp->m_attr, name); + if (v != NULL) { + INCREF(v); + return v; + } + } + return findmethod(menu_methods, (object *)mp, name); +} + +static int +menu_setattr(mp, name, v) + menuobject *mp; + char *name; + object *v; +{ + if (mp->m_attr == NULL) { + mp->m_attr = newdictobject(); + if (mp->m_attr == NULL) + return -1; + } + if (v == NULL) + return dictremove(mp->m_attr, name); + else + return dictinsert(mp->m_attr, name, v); +} + +static typeobject Menutype = { + OB_HEAD_INIT(&Typetype) + 0, /*ob_size*/ + "menu", /*tp_name*/ + sizeof(menuobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + menu_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + menu_getattr, /*tp_getattr*/ + menu_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ +}; + + +/* Windows */ + +#define MAXNWIN 50 +static windowobject *windowlist[MAXNWIN]; + +/* Window methods */ + +static void +window_dealloc(wp) + windowobject *wp; +{ + if (wp->w_win != NULL) { + int tag = wgettag(wp->w_win); + if (tag >= 0 && tag < MAXNWIN) + windowlist[tag] = NULL; + else + fprintf(stderr, "XXX help! tag %d in window_dealloc\n", + tag); + wclose(wp->w_win); + } + DECREF(wp->w_title); + if (wp->w_attr != NULL) + DECREF(wp->w_attr); + free((char *)wp); +} + +static void +window_print(wp, fp, flags) + windowobject *wp; + FILE *fp; + int flags; +{ + fprintf(fp, "<window titled '%s'>", getstringvalue(wp->w_title)); +} + +static object * +window_begindrawing(wp, args) + windowobject *wp; + object *args; +{ + drawingobject *dp; + if (!getnoarg(args)) + return NULL; + if (Drawing != NULL) { + err_setstr(RuntimeError, "already drawing"); + return NULL; + } + dp = NEWOBJ(drawingobject, &Drawingtype); + if (dp == NULL) + return NULL; + Drawing = dp; + INCREF(wp); + dp->d_ref = wp; + wbegindrawing(wp->w_win); + return (object *)dp; +} + +static object * +window_change(wp, args) + windowobject *wp; + object *args; +{ + int a[4]; + if (!getrectarg(args, a)) + return NULL; + wchange(wp->w_win, a[0], a[1], a[2], a[3]); + INCREF(None); + return None; +} + +static object * +window_gettitle(wp, args) + windowobject *wp; + object *args; +{ + if (!getnoarg(args)) + return NULL; + INCREF(wp->w_title); + return wp->w_title; +} + +static object * +window_getwinsize(wp, args) + windowobject *wp; + object *args; +{ + int width, height; + if (!getnoarg(args)) + return NULL; + wgetwinsize(wp->w_win, &width, &height); + return makepoint(width, height); +} + +static object * +window_getdocsize(wp, args) + windowobject *wp; + object *args; +{ + int width, height; + if (!getnoarg(args)) + return NULL; + wgetdocsize(wp->w_win, &width, &height); + return makepoint(width, height); +} + +static object * +window_getorigin(wp, args) + windowobject *wp; + object *args; +{ + int width, height; + if (!getnoarg(args)) + return NULL; + wgetorigin(wp->w_win, &width, &height); + return makepoint(width, height); +} + +static object * +window_scroll(wp, args) + windowobject *wp; + object *args; +{ + int a[6]; + if (!getrectpointarg(args, a)) + return NULL; + wscroll(wp->w_win, a[0], a[1], a[2], a[3], a[4], a[5]); + INCREF(None); + return None; +} + +static object * +window_setdocsize(wp, args) + windowobject *wp; + object *args; +{ + int a[2]; + if (!getpointarg(args, a)) + return NULL; + wsetdocsize(wp->w_win, a[0], a[1]); + INCREF(None); + return None; +} + +static object * +window_setorigin(wp, args) + windowobject *wp; + object *args; +{ + int a[2]; + if (!getpointarg(args, a)) + return NULL; + wsetorigin(wp->w_win, a[0], a[1]); + INCREF(None); + return None; +} + +static object * +window_settitle(wp, args) + windowobject *wp; + object *args; +{ + object *title; + if (!getstrarg(args, &title)) + return NULL; + DECREF(wp->w_title); + INCREF(title); + wp->w_title = title; + wsettitle(wp->w_win, getstringvalue(title)); + INCREF(None); + return None; +} + +static object * +window_show(wp, args) + windowobject *wp; + object *args; +{ + int a[4]; + if (!getrectarg(args, a)) + return NULL; + wshow(wp->w_win, a[0], a[1], a[2], a[3]); + INCREF(None); + return None; +} + +static object * +window_settimer(wp, args) + windowobject *wp; + object *args; +{ + int a; + if (!getintarg(args, &a)) + return NULL; + wsettimer(wp->w_win, a); + INCREF(None); + return None; +} + +static object * +window_menucreate(self, args) + windowobject *self; + object *args; +{ + menuobject *mp; + object *title; + if (!getstrarg(args, &title)) + return NULL; + wmenusetdeflocal(1); + mp = newmenuobject(title); + if (mp == NULL) + return NULL; + wmenuattach(self->w_win, mp->m_menu); + return (object *)mp; +} + +static object * +window_textcreate(self, args) + windowobject *self; + object *args; +{ + textobject *tp; + int a[4]; + if (!getrectarg(args, a)) + return NULL; + return (object *) + newtextobject(self, a[0], a[1], a[2], a[3]); +} + +static struct methodlist window_methods[] = { + {"begindrawing",window_begindrawing}, + {"change", window_change}, + {"getdocsize", window_getdocsize}, + {"getorigin", window_getorigin}, + {"gettitle", window_gettitle}, + {"getwinsize", window_getwinsize}, + {"menucreate", window_menucreate}, + {"scroll", window_scroll}, + {"setdocsize", window_setdocsize}, + {"setorigin", window_setorigin}, + {"settimer", window_settimer}, + {"settitle", window_settitle}, + {"show", window_show}, + {"textcreate", window_textcreate}, + {NULL, NULL} /* sentinel */ +}; + +static object * +window_getattr(wp, name) + windowobject *wp; + char *name; +{ + if (wp->w_attr != NULL) { + object *v = dictlookup(wp->w_attr, name); + if (v != NULL) { + INCREF(v); + return v; + } + } + return findmethod(window_methods, (object *)wp, name); +} + +static int +window_setattr(wp, name, v) + windowobject *wp; + char *name; + object *v; +{ + if (wp->w_attr == NULL) { + wp->w_attr = newdictobject(); + if (wp->w_attr == NULL) + return -1; + } + if (v == NULL) + return dictremove(wp->w_attr, name); + else + return dictinsert(wp->w_attr, name, v); +} + +static typeobject Windowtype = { + OB_HEAD_INIT(&Typetype) + 0, /*ob_size*/ + "window", /*tp_name*/ + sizeof(windowobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + window_dealloc, /*tp_dealloc*/ + window_print, /*tp_print*/ + window_getattr, /*tp_getattr*/ + window_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ +}; + +/* Stdwin methods */ + +static object * +stdwin_open(sw, args) + object *sw; + object *args; +{ + int tag; + object *title; + windowobject *wp; + if (!getstrarg(args, &title)) + return NULL; + for (tag = 0; tag < MAXNWIN; tag++) { + if (windowlist[tag] == NULL) + break; + } + if (tag >= MAXNWIN) + return err_nomem(); + wp = NEWOBJ(windowobject, &Windowtype); + if (wp == NULL) + return NULL; + INCREF(title); + wp->w_title = title; + wp->w_win = wopen(getstringvalue(title), (void (*)()) NULL); + wp->w_attr = NULL; + if (wp->w_win == NULL) { + DECREF(wp); + return NULL; + } + windowlist[tag] = wp; + wsettag(wp->w_win, tag); + return (object *)wp; +} + +static object * +stdwin_getevent(sw, args) + object *sw; + object *args; +{ + EVENT e; + object *v, *w; + if (!getnoarg(args)) + return NULL; + if (Drawing != NULL) { + err_setstr(RuntimeError, "cannot getevent() while drawing"); + return NULL; + } + again: + wgetevent(&e); + if (e.type == WE_COMMAND && e.u.command == WC_CANCEL) { + /* Turn keyboard interrupts into exceptions */ + err_set(KeyboardInterrupt); + return NULL; + } + if (e.window == NULL && (e.type == WE_COMMAND || e.type == WE_CHAR)) + goto again; + v = newtupleobject(3); + if (v == NULL) + return NULL; + if ((w = newintobject((long)e.type)) == NULL) { + DECREF(v); + return NULL; + } + settupleitem(v, 0, w); + if (e.window == NULL) + w = None; + else { + int tag = wgettag(e.window); + if (tag < 0 || tag >= MAXNWIN || windowlist[tag] == NULL) + w = None; + else + w = (object *)windowlist[tag]; + } +if ((long)w == (long)0x80000001) { +err_setstr(SystemError, "bad pointer in stdwin.getevent()"); +return NULL; +} + INCREF(w); + settupleitem(v, 1, w); + switch (e.type) { + case WE_CHAR: + { + char c[1]; + c[0] = e.u.character; + w = newsizedstringobject(c, 1); + } + break; + case WE_COMMAND: + w = newintobject((long)e.u.command); + break; + case WE_DRAW: + w = makerect(e.u.area.left, e.u.area.top, + e.u.area.right, e.u.area.bottom); + break; + case WE_MOUSE_DOWN: + case WE_MOUSE_MOVE: + case WE_MOUSE_UP: + w = makemouse(e.u.where.h, e.u.where.v, + e.u.where.clicks, + e.u.where.button, + e.u.where.mask); + break; + case WE_MENU: + if (e.u.m.id >= 0 && e.u.m.id < MAXNMENU && + menulist[e.u.m.id] != NULL) + w = (object *)menulist[e.u.m.id]; + else + w = None; + w = makemenu(w, e.u.m.item); + break; + default: + w = None; + INCREF(w); + break; + } + if (w == NULL) { + DECREF(v); + return NULL; + } + settupleitem(v, 2, w); + return v; +} + +static object * +stdwin_setdefwinpos(sw, args) + object *sw; + object *args; +{ + int a[2]; + if (!getpointarg(args, a)) + return NULL; + wsetdefwinpos(a[0], a[1]); + INCREF(None); + return None; +} + +static object * +stdwin_setdefwinsize(sw, args) + object *sw; + object *args; +{ + int a[2]; + if (!getpointarg(args, a)) + return NULL; + wsetdefwinsize(a[0], a[1]); + INCREF(None); + return None; +} + +static object * +stdwin_menucreate(self, args) + object *self; + object *args; +{ + object *title; + if (!getstrarg(args, &title)) + return NULL; + wmenusetdeflocal(0); + return (object *)newmenuobject(title); +} + +static object * +stdwin_askfile(self, args) + object *self; + object *args; +{ + object *prompt, *dflt; + int new, ret; + char buf[256]; + if (!getstrstrintarg(args, &prompt, &dflt, &new)) + return NULL; + strncpy(buf, getstringvalue(dflt), sizeof buf); + buf[sizeof buf - 1] = '\0'; + ret = waskfile(getstringvalue(prompt), buf, sizeof buf, new); + if (!ret) { + err_set(KeyboardInterrupt); + return NULL; + } + return newstringobject(buf); +} + +static object * +stdwin_askync(self, args) + object *self; + object *args; +{ + object *prompt; + int new, ret; + if (!getstrintarg(args, &prompt, &new)) + return NULL; + ret = waskync(getstringvalue(prompt), new); + if (ret < 0) { + err_set(KeyboardInterrupt); + return NULL; + } + return newintobject((long)ret); +} + +static object * +stdwin_askstr(self, args) + object *self; + object *args; +{ + object *prompt, *dflt; + int ret; + char buf[256]; + if (!getstrstrarg(args, &prompt, &dflt)) + return NULL; + strncpy(buf, getstringvalue(dflt), sizeof buf); + buf[sizeof buf - 1] = '\0'; + ret = waskstr(getstringvalue(prompt), buf, sizeof buf); + if (!ret) { + err_set(KeyboardInterrupt); + return NULL; + } + return newstringobject(buf); +} + +static object * +stdwin_message(self, args) + object *self; + object *args; +{ + object *msg; + if (!getstrarg(args, &msg)) + return NULL; + wmessage(getstringvalue(msg)); + INCREF(None); + return None; +} + +static object * +stdwin_fleep(self, args) + object *self; + object *args; +{ + if (!getnoarg(args)) + return NULL; + wfleep(); + INCREF(None); + return None; +} + +static object * +stdwin_setcutbuffer(self, args) + object *self; + object *args; +{ + object *str; + if (!getstrarg(args, &str)) + return NULL; + wsetclip(getstringvalue(str), getstringsize(str)); + INCREF(None); + return None; +} + +static object * +stdwin_getcutbuffer(self, args) + object *self; + object *args; +{ + char *str; + if (!getnoarg(args)) + return NULL; + str = wgetclip(); + if (str == NULL) + str = ""; + return newstringobject(str); +} + +static struct methodlist stdwin_methods[] = { + {"askfile", stdwin_askfile}, + {"askstr", stdwin_askstr}, + {"askync", stdwin_askync}, + {"fleep", stdwin_fleep}, + {"getcutbuffer", stdwin_getcutbuffer}, + {"getevent", stdwin_getevent}, + {"menucreate", stdwin_menucreate}, + {"message", stdwin_message}, + {"open", stdwin_open}, + {"setcutbuffer", stdwin_setcutbuffer}, + {"setdefwinpos", stdwin_setdefwinpos}, + {"setdefwinsize", stdwin_setdefwinsize}, + + /* Text measuring methods borrow code from drawing objects: */ + {"baseline", drawing_baseline}, + {"lineheight", drawing_lineheight}, + {"textbreak", drawing_textbreak}, + {"textwidth", drawing_textwidth}, + {NULL, NULL} /* sentinel */ +}; + +void +initstdwin() +{ + initmodule("stdwin", stdwin_methods); +} diff --git a/Modules/timemodule.c b/Modules/timemodule.c new file mode 100644 index 0000000..334b2d3 --- /dev/null +++ b/Modules/timemodule.c @@ -0,0 +1,178 @@ +/* Time module */ + +#include <stdio.h> +#include <signal.h> +#include <setjmp.h> + +#ifdef __STDC__ +#include <time.h> +#else /* !__STDC__ */ +typedef unsigned long time_t; +extern time_t time(); +#endif /* !__STDC__ */ + +#include "PROTO.h" +#include "object.h" +#include "intobject.h" +#include "dictobject.h" +#include "methodobject.h" +#include "moduleobject.h" +#include "objimpl.h" +#include "import.h" +#include "sigtype.h" +#include "modsupport.h" +#include "errors.h" + + +/* Time methods */ + +static object * +time_time(self, args) + object *self; + object *args; +{ + long secs; + if (!getnoarg(args)) + return NULL; + secs = time((time_t *)NULL); + return newintobject(secs); +} + +static jmp_buf sleep_intr; + +static void +sleep_catcher(sig) + int sig; +{ + longjmp(sleep_intr, 1); +} + +static object * +time_sleep(self, args) + object *self; + object *args; +{ + int secs; + SIGTYPE (*sigsave)(); + if (!getintarg(args, &secs)) + return NULL; + if (setjmp(sleep_intr)) { + signal(SIGINT, sigsave); + err_set(KeyboardInterrupt); + return NULL; + } + sigsave = signal(SIGINT, SIG_IGN); + if (sigsave != (SIGTYPE (*)()) SIG_IGN) + signal(SIGINT, sleep_catcher); + sleep(secs); + signal(SIGINT, sigsave); + INCREF(None); + return None; +} + +#ifdef THINK_C +#define DO_MILLI +#endif /* THINK_C */ + +#ifdef AMOEBA +#define DO_MILLI +extern long sys_milli(); +#define millitimer sys_milli +#endif /* AMOEBA */ + +#ifdef DO_MILLI + +static object * +time_millisleep(self, args) + object *self; + object *args; +{ + long msecs; + SIGTYPE (*sigsave)(); + if (!getlongarg(args, &msecs)) + return NULL; + if (setjmp(sleep_intr)) { + signal(SIGINT, sigsave); + err_set(KeyboardInterrupt); + return NULL; + } + sigsave = signal(SIGINT, SIG_IGN); + if (sigsave != (SIGTYPE (*)()) SIG_IGN) + signal(SIGINT, sleep_catcher); + millisleep(msecs); + signal(SIGINT, sigsave); + INCREF(None); + return None; +} + +static object * +time_millitimer(self, args) + object *self; + object *args; +{ + long msecs; + extern long millitimer(); + if (!getnoarg(args)) + return NULL; + msecs = millitimer(); + return newintobject(msecs); +} + +#endif /* DO_MILLI */ + + +static struct methodlist time_methods[] = { +#ifdef DO_MILLI + {"millisleep", time_millisleep}, + {"millitimer", time_millitimer}, +#endif /* DO_MILLI */ + {"sleep", time_sleep}, + {"time", time_time}, + {NULL, NULL} /* sentinel */ +}; + + +void +inittime() +{ + initmodule("time", time_methods); +} + + +#ifdef THINK_C + +#define MacTicks (* (long *)0x16A) + +static +sleep(msecs) + int msecs; +{ + register long deadline; + + deadline = MacTicks + msecs * 60; + while (MacTicks < deadline) { + if (intrcheck()) + sleep_catcher(SIGINT); + } +} + +static +millisleep(msecs) + long msecs; +{ + register long deadline; + + deadline = MacTicks + msecs * 3 / 50; /* msecs * 60 / 1000 */ + while (MacTicks < deadline) { + if (intrcheck()) + sleep_catcher(SIGINT); + } +} + +static long +millitimer() +{ + return MacTicks * 50 / 3; /* MacTicks * 1000 / 60 */ +} + +#endif /* THINK_C */ |