Bethon-0.5.4/ 0000755 0000000 0000000 00000000000 11257600067 011434 5 ustar user root Bethon-0.5.4/Bethon.html 0000644 0000000 0000144 00000001526 07310060206 013722 0 ustar user users
The name ``Bethon''
What's this about ``Bethon''?
Had to call it something. I have been using "bpy" and
variations on that theme, but I got sick of "PY" as an ending.
Then I thought "BePython", but it proved too much work to type.
"Bethon" is easier, and it doesn't falsely imply that Python
is contained herein (it isn't, this is just a bunch of modules.)
A Google search didn't turn up anything else at all in the
computer world with this name, just a lot of French names.
Bonjour, if you like it because it looks French, c'est OK.
It is "Be" as in Be, Inc. and "thon" as in Python, so pronounce
it accordingly.
For more about this distribution, read
the Readme.html file.
Donn Cave, note new email: donn@drizzle.com
Bethon-0.5.4/Bugs.html 0000644 0000000 0000144 00000006067 07412017236 013420 0 ustar user users
Bugs
System - issues like threads, storage etc.
Crash on quit
Problem is at least much diminished, if 1) I create windows
from only the main thread, and 2) don't exit before the non-main threads
have finished. This is probably a fact of life that is just much more
poignant in Python. It can be kind of difficult to achieve #2.
C storage vs. Python
What a mess. Most functions take their data pointer, do what they
need and let it go. Some, however, take the pointer and squirrel it away,
in which case it needs an incref to pin the Python version up.
This appears to be a case-by-case research project.
Other functions may later release the pointer, and we'd like to decref
at that point, but I can't bear to even think about that.
Maybe just RemoveChild() and the like, but basically anything that
overwrites or clears a pointer we made a reference for.
The "incref" option is duly noted for a few functions, probably not all
that need it. A similar option "dup" is for cases where it seemed
better for one reason or another to make a copy.
Reference counts for wrap instances
Need more research, but I have reason to suspect that there are
some extra references somewhere that keep the instance from ever
getting to refcount 0 once it has been bound - despite attempts
to unbind with bind(None). Pretty sure some of them are actually
references to member functions. I will fix this stuff if I figure
out how -- and the result may be inconvenient for you, if you have
been depending on this bug that allows your BWindow objects to
persist despite no apparent references!
Inheritance details
More virtual functions are now implemented in each derived class,
now automatic for "virtual" functions where before (in 0.3.0) it
had to be done by hand. There certainly may be more virtual functions
that need to be declared as such in source/*.dx.
Interpreter lock over-use
Think about eliminating the thread unlock/lock around some of the
function calls. Most of them are fast and therefore don't need to
release the interpreter lock. Don't have any idea how much advantage
this would be. Since I am not hurting for performance, the incentive
is not strong.
Python interface
Compiler
Function stanza order errors
Warn or something when missing return/status etc. in first fn of
multiple input overload, where return/status etc. was probably intended
to apply to all.
Parsing
More tolerant whitespace handling.
Unsupported types
Array of char*, many of these in omitted BFont functions. I think that
can be addressed with new type, in sgrules, in general zero terminated vs.
dimensioned. (Arrives in 0.3.0, but some of those BFont functions are
probably going to have to be done by hand, in the end.)
BList, pattern, various other compound types.
Horrible coding mess
Rewrite everything, maybe ditch m4.
Bethon-0.5.4/ChangeLog 0000644 0000000 0000144 00000012132 11257576650 013406 0 ustar user users Sep 26 Donn 0.5.4
(general) various changes for Haiku
Dec 7 François Revol 0.5.2
gen/module.m4
base class order fix for Python 2.3
May 22 Lars Hanson 0.5.2
source/BEntryList.dx, BMenuField.dx, BQuery.dx, BVolumeRoster.dx
new modules
source/BFont.dx, BFont.dx, BOutlineView.dx, BView.dx
bug fixes, enhancements, non-standard platform support
July 10 donn 0.5.2
sggen.py, sgparse.py, sgoutput.py
Static method support (BTranslationUtils::GetBitmap)
sggen.py
constructor return bug fix
December 15 donn 0.5.1
sggen.py
Increment reference count for None in hook function parameters.
November 28 donn 0.5.0
PyBase.h
Improve a couple of multi-statement macros.
PyBase.cpp
Lose base getattr function, store object type in baseItem.
module.m4, sggen.py
Extensive changes to use Python2.2 class/type features.
New m4 macros to cut down a little on `' quoting.
November 2 donn 0.4.2
PyBase.h, module.m4, sggen.py, sgvar.py
Extend meaning of "internal" to include ordinary Be API objects,
as opposed to Bethon subclasses, as long as they're allocated
in conjunction with the Python object. To reclaim memory.
July 24 donn 0.4.1
sggen.py, BNode.dx
Add support for module level functions.
December 23 donn 0.3.1
sggen.py
Generate doc strings for functions.
December 23 donn 0.3.1
module.m4, defs.m4, sggen.py
Special run-time binding for be_bold_font et al.
December 21 donn 0.3.1
sggen.py
Check for hook function execution prior to looper thread,
don't call into interpreter in this case.
December 21 donn 0.3.1
sgparse.py, *.dx
New "virtual" functions are methods that propagate from the
base class definition, so we're always calling the derived
virtual function. Remove extraneous definitions in derived
classes. Automatically specify C++ class in function call
to avoid calling wrapper hook methods.
December 20 donn 0.3.1
sgrules.py, module.m4, sggen.py
Handle a null pointer hook parameter as None, and pass 0 for
method parameter None (when that's declared as a possible input.)
June 19 donn 0.3.0
sgrules.py, sgvar.py, sggen.py, BRoster.dx,BApplication.dx
Support for array parameters, so far just argv string arrays.
Invoke setup_p2c for function returns, from hooks, to get the
new function that checks if Bxxx type before loading the Bxxx
module. (As it happens, in that case the check doesn't help!)
June 6 donn 0.3.0
BView.dx,BTextView.dx,BAppFileInfo.dx,BNodeInfo.dx
New structs - text_run_array, version_info
New functions and objects.
June 6 donn 0.3.0
sg*.py
General code reorganization, involving primarily the variable
analysis functions in sggen.py, moved to sgvar.py and substantially
rewritten.
May 31 donn 0.2.3
PyMisc.cpp
Clear Python error register after calling a parameter conversion
function, cures "unraised exception" whine.
April 27 donn 0.2.2
sgparse.py
Make "param" default from "input" in "hook" declarations.
March 6 donn 0.2.2
PyBase.cpp, module.m4
Replace old type stamp with special attribute, after losing
the slot for the stamp in Python 2.1.
February 23 donn 0.2.2
sgrules.py
Allow any numeric type in BRect, BPoint
Begin year 2001
November 15 donn 0.2.2
sggen.py, various .dx modules
"hook" function with more useful declaration options
October 29 donn 0.2.1
wrap up release
October 25 donn 0.2.1
BSlider.dx
add a couple of 5.0 methods to BSlider
October 21 donn 0.2.1
build procedures, app.cpp
support new plat-beos[45] directory structure in Python 2.0
September 10 donn 0.2.0
reorganize, add a few gimmicks.
August 10 donn 0.1.9
various .dx modules
Add a lot of derived virtual functions that are documented
to be different from the base implementation, e.g., Draw,
SetEnabled.
August 9 donn 0.1.9
sggen.py
Use PyTuple_SetItem directly instead of BuildValue("(OO)",...)
August 7 donn 0.1.9
sggen.py
Tweak "dup" parameter code to check for null input value.
August 3 donn 0.1.9
sgparse.py, module.m4, defs.m4
Complicate "preset" feature to accommodate be_app_messenger.
July 27 donn 0.1.9
sggen.py
Support "<"variable as dimension. (Cf. BBitmap Bits())
July 22 donn 0.1.9
sggen.py
Support null pointer returns, %0=None.
June 16 donn 0.1.8
BPropertyInfo.cpp
A little fixing up.
module.m4, defs.m4, sggen.py, PyBase.cpp
Pre-calculate offsets for base class casts.
May 30 donn 0.1.7
various .dx
Changed old "return blah=0"s to "return blah%0", for consistency.
Fixed a bug or two in passing.
sggen.py
Fixed bug in return string&size dimensioning.
May 5 donn 0.1.6
module.m4
Cast be_roster et al. to (void *) in cobj assignment, for gcc.
sggen.py
Change "dup" implementation to pass object instead of pointer,
i.e., BMessage& instead of BMessage*.
various .dx, sggen.py
Added const option for local variables.
various .dx
Added more include files for 5.0, e.g., StringItem includes View.h
Oct 21 donn 0.1.3
sggen.py
Fixed inappropriate free() of external C++ objects.
Sep 12 donn 0.1.2
sgrules.py
Fixed (hacked) char parameter handling (as opposed to normal char *).
Main affected module is BMenuItem, with its shortcuts &c.
Bethon-0.5.4/Dx.html 0000644 0000000 0000144 00000011037 07313600125 013057 0 ustar user users
How to write your own module
How to make a new module BSinkmodule.so
Each module starts with a .dx
file that has to be written by
hand.
First I read the .h into the editor, /boot/develop/headers/be/storage/Sink.h.
It's not enough like the .dx file to be exactly a starting point, but it's
at least a handy reference. I will also need the Be Book reference at hand.
The .dx file has a simple tab indented format.
The "include" stanza should be fairly obvious. The module's own include
may be the only one needed here, the compiler will let you know if not.
The "class" stanza is where everything happens. The class statement
itself might look like this: "class Sink handler". (Note, not BSink.)
"handler" is a keyword here, that classifies this object in general
terms. The alternatives are "looper" and "abstract", neither of them
all that common, and "ref" which is the default. BView subclasses are
all "handler", for example.
The statements under "class" are all one kind or another of function
definition, except "base", which declares the base class(es). Don't
spell out the whole inheritance tree - Window for example is a subclass
of Looper, and _not_ Handler. A base class supplies its functions
and virtual functions, so the new BSink module adds only its unique
new functions.
There may be a "constructor" statement, if there are any virtual functions.
Its "param" shows the parameters of the class constructor(s). I omit any
constructor where I can't handle the types. I haven't bothered with
BArchivable support, and I omit the usual constructor from BMessage.
Virtual functions listed in the "hooks" section of the BeBook page are
declared in "hook" statements. (Not all virtual functions, only the hooks.)
Non-hook functions are just functions, to be called from Python - and
if a function is used both ways, it should be declared both ways (see
MessageReceived.) In this case, use the optional "C++ name" parameter
to "function" to specify the base class, e.g. BHandler::MessageReceived,
to avoid infinite recursion.
Then there will be a bunch of "function"s, the class methods. Instead
of "param", these use "input", the arguments in the Python call. There
often will be some remapping, and the "param" following "input" shows
this - if there's no "param", then the same argument list is presumed
to pass right through to C++. For a "hook" function the relationship
is naturally inverted; the "input" still declares the Python function's
parameters, and but they're created from the C++ parameter values
(and "input" still is the default for "param".)
This part is very order dependent. Start with "input". If a "param"
is needed, it follows, plus any "return" and "status" statements. Then
if there are any overloads with different parameter lists, more "input"
lines may follow. They inherit the preceding "return" & "status" by
default, but of course not "param". "return" is optional, default is
no (None) return.
The parameter list is comma separated - not comma separated with optional
white space, just comma separated. Types are declared with familiar C
notation, and position index - e.g., char*@1=0 means first parameter is
a string, but optional with default value NULL. Parameter 0 is the
function return. Position indices like &status_t%3 mean that a variable
of type status_t is passed to the C++ function to receive a return value,
and of course it's allocated within the interface call because Python
doesn't pass variables by reference like that. Return values use the
% notation too. "status" is usually the status_t return of the C++
function, and when declared as such it will be checked to see if an
exception should be raised.
There are plenty of parameter lists that are too tricky for me yet.
To see a few of the more obscure notation tricks, see BFile.dx.
There could easily be a few new incidental structs or classes that
BSink will need. I've been handling these as tuples, rather than
making new Python types for everything. That's all in sgrules.py,
which just needs to be edited to add the new struct - ``follow the
example of other structs.'' If the thing has a constructor, assignment
operator, etc., make it a CTorTuple, not just TupleBase.
BSink will also probably introduce some int typedefs. Defined a load
of these, already, in sgrules.py - look for "long".
OK, that's more than anyone is going to read, anyway. Good luck, have
fun, write if you get it to work!
Donn, donn@drizzle.com
Bethon-0.5.4/Makefile 0000644 0000000 0000144 00000000535 10171665462 013272 0 ustar user users all: pythonversion
cd base; make
cd build; make
cd symbols; make
install: all
cd build; make install
cd symbols; make install
pythonversion:
python -c 'import sys; open("pythonversion", "w").write("PYTHONVERSION=%s.%s\n" % sys.version_info[:2])'
clean:
cd base; make clean
cd build; make clean
cd gen; make clean
cd symbols; make clean
Bethon-0.5.4/Readme.html 0000644 0000000 0000144 00000010650 07575023202 013706 0 ustar user users
Python classes for BeOS C++ API
Python classes for BeOS C++ API, version 0.5.0.
If you're a Python programmer and not a C++ programmer, and
only want to use the modules, the worst problem is just documentation,
or lack thereof. We have none, we rely entirely on the BeBook
documentation of the C++ API. And there are some transforms between
that and this Python API that should fairly obvious to someone who
understands both, but maybe not if you only know Python.
There is hope, though, since at least there are some example programs.
If anyone wants to contribute more example programs, incidentally,
that would be great. There is also usually included with this
distribution a real application, maybe not the slickest thing in
the world but I use it.
If you have used an older release, 0.4.2 or older, this one marks
a substantial change in that the Python 2.2 class/type integration
allows us to inherit directly from a Be API type, instead of using
a special bind() method to link the class instance up. The old way
still works, and the new actually has some drawbacks - it can be
harder to find the right base class for a MessageReceived or whatever.
All the examples have been converted to the new style.
Credits - I got some of the ideas in this system from a paper by
Jim Ahlstrom, though they've probably been perverted beyond
recognition and the resulting mess shouldn't reflect on him
at this point.
Step one: Python
Get Python. I think at some point this could be a binary distribution,
including Python, but at present you have to get Python separately.
As of Bethon-0.5.0, Python 2.2 is required. My Python 2.2 distribution
for BeOS includes binaries from version Bethon 0.5.0.
I assume installation makes and uses /boot/home/config/lib/python2.2 and
a subdirectory plat-beos5. I'm assuming BeOS 5.0. That's what I have.
If anyone needs to work with 4.5, I may be able to help - should be mostly
just some changes in the API. ``Improved'' distributions of 5.0 and
bootleg post-5.0 unreleased distributions seem to be a common source of
problems, and I can't help much with that.
I use a file in the top directory "pythonversion" with one
line PYTHONVERSION=2.2, and the makefiles can find that. You must
however keep build versions consistent, don't try to run old modules
with new interpeter or vice versa.
PPC and Intel are both supported, of course.
Step two: Build these modules.
Cd to base
, run make.
Cd to build
, run make. Then make install, to
put the modules in the lib directory where python will look.
Cd to symbols
, run make. Then make install, to
install the symbol modules for symbols like B_QUIT_REQUESTED.
Step three: Figure out what went wrong.
If it doesn't work, I would like to hear about. There will be some
errors in the compile, for sure - a few things I do the compiler doesn't
like, plenty of functions that can't be compiled because we don't have
type support for them yet.
The system.
Each module represents a BeOS API class. The source is a .dx file,
using my own ad hoc notation. This is compiled with a Python program,
"sg", to m4, a macro language that has been around for many years and
happens to be supported on BeOS. m4 converts that to a .cpp C++ file,
to be compiled and linked as a shared library.
There are 51 modules as I write this. Should be easy to write more -
should be easier than it is! See Dx.html for more on this. Send
along anything you can bear to see included here - we already have
a few contributed modules. It doesn't even have to work right.
Sometimes I can fix them. Sometimes there's a problem that I have
to change the template compiler to fix, but if you wait for me to
run into the problem on my own, it could be long wait! As I write
this I'm sitting on some other contributed modules that need more
thought than I have time for right now, that happens too.
The module for a derived class can fall back on its base classes -
for example, the many BView descendants rely on the BView module for
methods like Bounds(). They do this at run time. Virtual hook
functions are also inherited, but not at run time - they're just
pulled out of their respective .dx files at compile time.
Donn Cave, donn@drizzle.com
Bethon-0.5.4/Todo.html 0000644 0000000 0000144 00000006316 07574307125 013432 0 ustar user users
Stuff to do some day
Binary packages
Look at moving the base functions to the Python core, to eliminate a
bit of redundant code in every .so module. Would mean .so modules
would need to be built specially to run with a vanilla Python, so
it's worth doing only if it saves a lot of overhead.
Development environment
A WYSIWYG graphic element composer would be extravagantly cool.
An interactive Python window, debugger, stuff like that would
be cool. Icons for the little Python files, probably the same
old serpent but something else if possible.
Scripting
I don't really get BeOS scripting, but maybe it's just waiting
for someone to make some real use of it. The C++ API is unfortunately
one of the more difficult interfaces, but I hand-coded a BPropertyInfo
module and there are some example programs in test/script.
More goodies
More modules of course. There's a whole chunk of stuff I haven't
thought about for a long time having to do with archiving, and
including replicants etc.
Start over from scratch
What about SWIG? What about Boost (http://www.boost.org/)? C++
support has reportedly improved a lot in the former, and the latter
looks quite cool, but I have no real idea what's there. We really
have pretty modest needs here, thanks to the relatively conservative
way the Be API uses C++.
Points where (OpenBeOS?) could provide some support
The whole thing revolves around getting a correct interface.
Some aspects of that correctness are a much bigger issue for
Python than they are for conventional C++ applications, because
Python puts odd stresses on the system. Particularly, storage.
We will routinely free objects that any normal application would
never think to free, for example, because Python mechanically
frees anything with a 0 reference count. Another aspect of
the same problem is that it isn't the Python programmer's
responsibility to allocate storage to pass to some function,
it doesn't work that way. If a function needs to write to
memory allocated by the caller, that must be done in the
interface.
So we have to know what is correct. Ideally, it would be
really great to have information about the API that is both
comprehensive in the way we need, and also machine readable
so we can reliably generate the bulk of it with no human
analysis. Unambiguous, comprehensive machine readable information.
I don't see how a multiple interface system could work any
other way.
Storage/ownership issues. In/Out parameters (I suppose a lot of
that can be inferred from presence or absence of "const".) More
of a problem, I think, is something like the BMessage that is
consumed by BControl. I need to know about that, so a reference
can be kept, or maybe make a copy to give to the function.
Could we get underneath C++? I don't know if the C++ API is
really a lot of implementation or only a veneer. I have read
comments that made it sound like there's a usable environment
underneath it. It's important in this project to follow the
C++ API, so unless it's a really thin veneer, we're probably
better off on top of it.
Bethon-0.5.4/base/ 0000755 0000000 0000000 00000000000 11257602016 012342 5 ustar user root Bethon-0.5.4/base/BpyBase.cpp 0000644 0000000 0000144 00000003536 07272721610 014575 0 ustar user users // Copyright 1998-1999 by Donn Cave, Seattle, Washington, USA.
// All rights reserved. Permission to copy, modify and distribute this
// material is hereby granted, without fee, provided that the above
// copyright notice appear in all copies.
// Base class to subclass along with Be API class that defines virtual
// functions. Its purpose is to allow a Python class to implement these
// virtual functions.
//
#include "Python.h"
#include
#include
#include "BpyBase.h"
// Look for virtual functions that may have been defined in the
// Python class that this thing is attached to.
//
// I check the class first, on the assumption that such functions
// will be defined there as well. This avoids the wrapper lookup
// back into the C object when the attribute isn't in the wrapper.
// There must be a better way to get class than looking up "__class__".
//
int
BpyVBase::VFNInventory(PyInstanceObject *inst, PyObject **vfn,
struct vfnLookupTbl *tbl, int nlup)
{
instance = inst;
// Py_INCREF((PyObject *) inst);
PyObject *classe = (PyObject *) instance->in_class;
if (!classe)
return -1;
int i, count;
for (i = 0, count = 0; i < nlup; ++i) {
PyObject *fun = PyObject_GetAttrString(classe, tbl[i].name);
PyObject *meth;
if (fun) {
meth = PyObject_GetAttrString((PyObject *) instance, tbl[i].name);
if (!PyMethod_Check(meth)) {
PyErr_SetString(PyExc_TypeError, tbl[i].name);
return -1;
}
} else {
meth = 0;
PyErr_Clear();
}
vfn[tbl[i].index] = meth;
if (meth) {
// slprintf(" Python virtual function: %s\n", tbl[i].name);
// Py_INCREF(meth);
// Refs here can be circular and don't help.
// Pretty sure getattr() above already made one anyway,
// so the question really is whether a DECREF() would
// work here.
++count;
}
}
return count;
}
Bethon-0.5.4/base/BpyBase.h 0000644 0000000 0000144 00000005354 07540026352 014241 0 ustar user users #ifndef __BPYBASE_H_
#define __BPYBASE_H_
#include
#include "Python.h"
#define BPYSTAMP 0xc2d0d9c2
class BpyBase {
public:
uint32 pystamp;
PyObject *pyself;
BpyBase() { pystamp = BPYSTAMP; pyself = 0; }
~BpyBase() {
unbindSelf();
pystamp = 0;
}
bool frmpy() { return pystamp == BPYSTAMP; }
PyObject *self() { return pyself; }
void bindSelf(PyObject *self) {
pyself = self;
// Py_INCREF(pyself);
}
void unbindSelf() {
if (pyself) {
// Py_DECREF(pyself);
pyself = 0;
}
}
};
struct vfnLookupTbl {
int index;
char *name;
};
class BpyVBase: public BpyBase {
public:
PyInstanceObject *instance;
BpyVBase(): BpyBase() { instance = 0; }
~BpyVBase() { unbindInstance(); }
virtual int bindInstance(PyInstanceObject *) = 0;
void unbindInstance() {
// Think this is OK without thread lock.
if (instance) {
pystamp = 0;
Py_DECREF(instance);
instance = 0;
}
}
virtual PyObject *lookup(int) = 0;
int VFNInventory(PyInstanceObject *, PyObject **, struct vfnLookupTbl *, int);
};
class BpyLVBase: public BpyVBase {
PyThreadState *loopthread;
public:
PyObject *lastchancefun;
BpyLVBase(): BpyVBase() {
loopthread = 0;
lastchancefun = 0;
}
~BpyLVBase() {
getPyThread();
unbindInstance();
unbindSelf();
releasePyThread();
}
int getPyThread() {
if (loopthread)
PyEval_AcquireThread(loopthread);
return 1;
}
void initPyThread(PyThreadState *tstate) {
loopthread = tstate;
}
void releasePyThread() {
if (loopthread)
PyEval_ReleaseThread(loopthread);
}
void lastchance() {
if (lastchancefun) {
PyObject *t, *v, *tb;
PyErr_Fetch(&t, &v, &tb);
PyObject *args = 0;
if (t && v && tb)
args = PyTuple_New(3);
if (args) {
PyTuple_SetItem(args, 0, t);
PyTuple_SetItem(args, 1, v);
PyTuple_SetItem(args, 2, tb);
}
PyObject *res = PyEval_CallObject(lastchancefun, args);
if (args)
Py_DECREF(args);
if (res) {
Py_DECREF(res);
return;
}
}
PyErr_Print();
}
};
class BpyHVBase: public BpyVBase {
public:
BpyHVBase(): BpyVBase() {};
int getPyThread(BLooper *looper) {
if (looper) {
BpyLVBase *b = dynamic_cast(looper);
if (b)
return b->getPyThread();
else
return 0;
} else
return 0;
}
void releasePyThread(BLooper *looper) {
if (looper) {
BpyLVBase *b = dynamic_cast(looper);
if (b)
b->releasePyThread();
}
}
void lastchance(BLooper *looper) {
if (looper) {
BpyLVBase *b = dynamic_cast(looper);
if (b)
b->lastchance();
}
}
};
// All classes also implement this function, but separately since it refers
// different vfn tables.
// PyObject *lookup(int i) {
// if (instance && i < NVFN)
// return vfn[i];
// else
// return 0;
// }
#endif
Bethon-0.5.4/base/Makefile 0000644 0000000 0000144 00000000646 11240113527 014173 0 ustar user users PYTHONVERSION=2.2
-include ../pythonversion
OPT= -O
DEFS= -DHAVE_CONFIG_H
INCLDIR= /boot/common/include/python${PYTHONVERSION}
CFLAGS= $(OPT) -I. -I$(INCLDIR) $(DEFS)
all: PyBase.o PyMisc.o BpyBase.o
PyBase.o: PyBase.cpp PyBase.h BpyBase.h
$(CC) -c $(CFLAGS) PyBase.cpp
PyMisc.o: PyMisc.cpp PyMisc.h
$(CC) -c $(CFLAGS) PyMisc.cpp
BpyBase.o: BpyBase.cpp BpyBase.h
$(CC) -c $(CFLAGS) BpyBase.cpp
clean:
rm -f *.o
Bethon-0.5.4/base/PyBase.cpp 0000644 0000000 0000144 00000003605 07574304361 014435 0 ustar user users // Copyright 1998-1999 by Donn Cave, Seattle, Washington, USA.
// All rights reserved. Permission to copy, modify and distribute this
// material is hereby granted, without fee, provided that the above
// copyright notice appear in all copies.
// Support functions for cross-module inheritance of ordinary class
// methods and attributes.
//
#include
#include
#include "Python.h"
#include "PyBase.h"
void
Base_init(struct baseItem *base, const char *name, int offset, PyTypeObject *type)
{
int i;
if (type) {
// Find first empty slot.
//
for (i = 0; i < MAXBASETYPES && base[i].name[0]; ++i)
;
if (i < MAXBASETYPES) {
int len = strlen(name);
struct baseItem *ibase = &(base[i]);
if (len >= sizeof(ibase->name))
len = sizeof(ibase->name) - 1;
memcpy(ibase->name, name, len);
ibase->name[len] = 0;
ibase->offset = offset;
ibase->type = type;
} else
fprintf(stderr, "\"%s\": Base limit exceeded.\n", name);
} else {
for (i = 0; i < MAXBASETYPES && base[i].name[0]; ++i) {
if (strcmp(base[i].name, name) == 0) {
base[i].offset = offset;
return;
}
}
fprintf(stderr, "\"%s\": Base not found in 2nd pass!\n", name);
}
}
PyTypeObject *
Base_initFromName(struct baseItem *base, const char *name, int offset)
{
// Get module and load base support.
//
char simple[128], *mod;
struct BaseFunctions *basefun;
if (PyErr_Occurred()) {
// Sloppy bind attribute lookup, etc.
fprintf(stderr, "-- \"%s\" base init: cleaning up unraised errors.\n", name);
PyErr_Print();
PyErr_Clear();
}
basefun = (struct BaseFunctions *) PyCObject_Import((char *)name, "functions");
if (basefun) {
if (PyErr_Occurred())
fprintf(stderr, "Error in \"%s\" import\n", name);
Base_init(base, name, offset, basefun->type);
return basefun->type;
} else {
PyErr_Clear();
return 0;
}
}
Bethon-0.5.4/base/PyBase.h 0000644 0000000 0000144 00000004012 07571603351 014071 0 ustar user users #ifndef _PYBASE_H_
#define _PYBASE_H_
//
// Copyright 1998 by Donn Cave, Seattle, Washington, USA.
// All Rights Reserved. Permission to use, copy, modify and distribute
// is hereby granted, provided that above copyright appear in all copies.
//
#include
#include "Python.h"
struct BaseObject;
#define MAXBASETYPES 11
struct baseItem {
char name[32];
int offset;
PyTypeObject *type;
};
#include "BpyBase.h"
#define MOTHERBASE void
#define BEBOSTAMP "like me?"
#define BEVOIDINT 0xc2c5d6cf
#define BEVOIDEXT 0xc2c5d6ce
// Object header with a C linkage and pseudo-base class references.
// This has to be consistent in order to refer this object
// back to C-Python pseudo-base classes.
//
#define BaseObject_HEAD PyObject_HEAD \
MOTHERBASE *bevoid; \
uint32 bevoidness; \
struct baseItem *base;
struct BaseObject {
BaseObject_HEAD
};
#define INTERNAL_BEPTR(o) ((o)->bevoidness == BEVOIDINT)
#define EXTERNAL_BEPTR(o) ((o)->bevoidness == BEVOIDEXT)
#define SETEXT_BEPTR(o,c) ( (o)->bevoid = c, (o)->bevoidness = BEVOIDEXT )
#define SETINT_BEPTR(o,c) ( (o)->bevoid = c, (o)->bevoidness = BEVOIDINT )
#define BINDINT_BEPTR(o,c) (c)->bindSelf((PyObject *) o);
// Base for exported C function table; when looking up the base classes
// for a derived pseudo class, their simpleattr functions are found through
// this table exported as a CObject during module initialization.
//
struct BaseFunctions {
PyObject *(*FromIt)(const void *, int);
void *(*AsIt)(PyObject *);
PyTypeObject *type;
};
#define SysBaseObject_HEAD BaseObject_HEAD \
int sysref;
// Objects held by system; particularly, subject to deletion by system.
// See BpySRVBase
//
struct SysBaseObject {
SysBaseObject_HEAD
};
// Objects for system dispatching threads. See BpyLSRVBase.
//
struct LooperBaseObject {
SysBaseObject_HEAD
PyThreadState *tstate;
};
void Base_init(baseItem *, const char *, int, PyTypeObject *);
PyTypeObject *Base_initFromName(baseItem *, const char *, int);
#endif
Bethon-0.5.4/base/PyMisc.cpp 0000644 0000000 0000144 00000003510 07411552575 014453 0 ustar user users // Copyright 1999 by Donn Cave, Seattle, Washington, USA.
// All rights reserved. Permission to copy, modify and distribute this
// material is hereby granted, without fee, provided that the above
// copyright notice appear in all copies.
#include
#include "Python.h"
#include "PyMisc.h"
// Check actual against formal parameters.
int
ParseTuple(PyObject *argv, struct InputParam *par, int np)
{
int i;
int n = PyTuple_Size(argv);
for (i = 0; i < np && par[i].fun; ++i) {
struct InputParam *p = &par[i];
// Possible optimization - previous call already validated this
// same object, from reference in another parameter.
// It could be a good idea anyway. Caller would need to provide
// full overload table.
// Cheap trick alternative - caller initializes to 0,
// so non-0 values are successful conversions. The
// case of int 0 is obviously not accounted for, but
// that's possibly not as expensive as others.
// Call specified converter, put result in "res"
if (i < n) {
PyObject *arg = PyTuple_GetItem(argv, i);
if (arg == Py_None) {
if (p->res)
memcpy(p->var, p->res, p->size);
else
memset(p->var, 0, p->size);
} else {
if (p->fun(p, PyTuple_GetItem(argv, i)))
p->res = p->var;
else {
// Forget any error here, since
// this is not going to be raised.
// (If this is not as good of an
// idea as I think, then turn off
// the unraised exception complaint
// in Base_initFromName.)
PyErr_Clear();
return 0;
}
}
} else if (p->res)
// memcpy() will lose with entry_ref et al., thanks to destructors.
// Maybe solve with 3rd param to "fun", which can cast and assign -
// assignment operators presumably account for storage issues.
memcpy(p->var, p->res, p->size);
else
return 0;
}
return i >= n;
}
Bethon-0.5.4/base/PyMisc.h 0000644 0000000 0000144 00000000515 07411552562 014116 0 ustar user users #ifndef _PYMISC_H_
#define _PYMISC_H_
struct InputParam {
void *var; // Storage.
void *res; // Default if any.
const char *tname; // Name for error report.
int (*fun)(struct InputParam *, PyObject *); // P2C converter.
int size; // Size of storage.
};
int ParseTuple(PyObject *, struct InputParam *, int);
#endif
Bethon-0.5.4/build/ 0000755 0000000 0000000 00000000000 11257601350 012527 5 ustar user root Bethon-0.5.4/build/Makefile 0000644 0000000 0000144 00000000661 07156345043 014370 0 ustar user users # Default target makes another Makefile, with rules for each and every
# .dx file in src.
#
# The "bld" script is equivalent to "alias bld='make -f xmakefile'".
# It's a short route to the generated makefile when you need to build
# just one specific piece.
#
all: xmakefile
make -f xmakefile
install: xmakefile
make -f xmakefile install
FORCE:
xmakefile: FORCE
python mkmake
clean:
rm -f *.cpp *.o *.so *.m4 xmakefile
Bethon-0.5.4/build/bld 0000755 0000000 0000144 00000000044 07151014530 013377 0 ustar user users #!/bin/sh
exec make -f xmakefile $@
Bethon-0.5.4/build/head.mk 0000644 0000000 0000000 00000002120 11240113563 013750 0 ustar user root #
# General definitions.
#
# Python version: works with 1.5.2 and 2.0, default is 2.0.
# If you're using something other than the default, you can put a file
# in the top directory called "pythonversion", with contents
# PYTHONVERSION=2.2
# That will then override the default, via the include statement below.
# I use "-include" (instead of "include") so it's OK if the file isn't
# there.
#
PYTHONVERSION=2.2
-include ../pythonversion
GENDEPS = ../gen/sggen.py ../gen/sgrules.py ../gen/sgparse.py ../gen/sgvar.py ../gen/module.m4 ../gen/defs.m4
BASEOBJS = ../base/PyBase.o ../base/PyMisc.o ../base/BpyBase.o
BASEINCL = ../base/BpyBase.h ../base/PyBase.h
# -ltracker for FilePanel, -ldevice for SerialPort
LIBS = -L/system/lib -nodefaultlibs -lbe -ltracker -ldevice -ltranslation -lroot
OPT = -O
PYTHONCFLAGS = -DHAVE_CONFIG -I/boot/common/include/python$(PYTHONVERSION)
CFLAGS = $(OPT) -I../base $(PYTHONCFLAGS)
VPATH=../source
.SUFFIXES: .dx module.so
.dx.cpp:
PYTHONPATH=../gen python ../gen/sg $<
m4 -I../gen -Dtemplate=module.m4 xxdefs.m4 > $@
.cpp.o:
$(CC) -c $(CFLAGS) $< -o $@
Bethon-0.5.4/build/install 0000755 0000000 0000000 00000000763 11240113634 014124 0 ustar user root #!/bin/sh
PYTHONVERSION=2.2
if test -e ../pythonversion
then
. ../pythonversion
fi
pvrs=$PYTHONVERSION
case $pvrs in
1.*)
PYTHONLIB=/boot/common/lib/python${pvrs}/plat-beos
;;
*)
r=$(uname -r)
r=${r%%.*}
PYTHONLIB=/boot/common/lib/python${pvrs}/plat-haiku1
;;
esac
case $# in
0)
set *.so;;
*)
case $1 in
*.so) ;;
*) echo 'usage: install [BThingmodule.so ...]'; exit 1;;
esac
esac
if test -d $PYTHONLIB
then :
else
echo $PYTHONLIB: 'No such directory'; exit 1
fi
mv $* $PYTHONLIB
Bethon-0.5.4/build/mkmake 0000644 0000000 0000000 00000005312 11240113654 013715 0 ustar user root #!/boot/common/bin/python
#
# Build makefile for the present module collection.
# Includes platform specific (PPC vs Intel) link options, depending
# on posix.uname().
#
# Handles both .dx and .cpp module source files.
#
# This can be run frequently, as long as you don't need to modify it
# by hand afterwards (ideally, if you need to change something, you
# might start with head.mk.) Should happen if you just type "make"
# with the default Makefile. I find it painlessly quick even on my
# BeBox.
#
import posix
import string
import sys
class Platform:
def __init__(self):
#
# Which source directory to use? Current, or older?
#
sys, node, rel, ver, mach = posix.uname()
if sys == 'Haiku' or rel[:1] == '5':
self.srcdir = '../source'
else:
# Older versions, 4.5.2 and probably earlier.
self.srcdir = '../source4'
if sys == 'Haiku':
self.ldso = '-shared -o $@ $< $(BASEOBJS) $(LIBS)'
elif mach == 'BePC':
self.ldso = '-nostart -Wl -o $@ $< $(BASEOBJS) $(LIBS)'
else:
self.ldso = '-xms -nodup -export init$* $< $(BASEOBJS) -o $@ /boot/develop/lib/ppc/glue-noinit.a /boot/develop/lib/ppc/init_term_dyn.o $(LIBS)'
platform = Platform()
class CSource:
def __init__(self, file):
self.cfile = file
self.getmodulename(file)
def prdeps(self, fp):
nm = self.module
fp.write('%smodule.so: %s.o $(BASEOBJS)\n' % (nm, nm))
fp.write('%s.o: %s $(BASEINCL)\n' % (nm, self.cfile))
def getmodulename(self, filename):
filename = string.split(filename, '/')[-1]
base, suffix = string.split(filename, '.')
self.module = base
class DSource(CSource):
def __init__(self, file):
self.dfile = file
self.getmodulename(file)
self.cfile = self.module + '.cpp'
def prdeps(self, fp):
CSource.prdeps(self, fp)
fp.write('%s: %s $(GENDEPS)\n' % (self.cfile, self.dfile))
def mkhead(fp):
fp.write('# Generated by mkmake\n')
fp.write('\ninclude head.mk\n')
fp.write('\nVPATH=%s\n' % (platform.srcdir,))
fp.write('\n.omodule.so:\n')
fp.write('\t$(CC) %s\n\n' % (platform.ldso,))
def inventory():
sources = []
for file in posix.listdir(platform.srcdir):
file = '%s/%s' % (platform.srcdir, file)
if file[-4:] == '.cpp':
s = CSource(file)
elif file[-3:] == '.dx':
s = DSource(file)
else:
continue
sources.append(s)
return sources
def main():
# Get list of all source files.
sources = inventory()
makefile = open('xmakefile', 'w')
mkhead(makefile)
# Make default target, all modules.
makefile.write('all: ')
for source in sources:
makefile.write(' %smodule.so' % source.module)
makefile.write('\n\ninstall: all\n ./install\n\n')
# Make target for each module and dependencies.
for source in sources:
source.prdeps(makefile)
makefile.close()
main()
Bethon-0.5.4/gen/ 0000755 0000000 0000000 00000000000 11257602026 012202 5 ustar user root Bethon-0.5.4/gen/Makefile 0000644 0000000 0000144 00000000024 07150672163 014033 0 ustar user users clean:
rm -f *.pyc
Bethon-0.5.4/gen/defs.m4 0000644 0000000 0000144 00000005704 07571600575 013575 0 ustar user users dnl Copyright 1999 by Donn Cave, Seattle, Washington, USA.
dnl All rights reserved. Permission to copy, modify and distribute this
dnl material is hereby granted, without fee, provided that the above
dnl copyright notice appear in all copies.
define(`list',
`ifelse($1,, ,$1
` list(shift($*))')')
define(`percomlist',
`ifelse($1,, ,`translit($1,`.',`,')'
` percomlist(shift($*))')')
define(`includes',
`ifelse($1,, ,#include $1
`includes(shift($*))')')
define(`strings',
`ifelse($1,, ,"$1"`,'
` strings(shift($*))')')
dnl define(`bases',
dnl `ifelse($1,, ,"B$1"`,'
dnl ` bases(shift($*))')')
dnldefine(`bases',
dnl`ifelse($1,, ,{"B$1"`,' (long)((B$1 *) zob) - (long) zob}`,'
dnl` bases(shift($*))')')
define(`bases',
`ifelse($1,, ,t = Base_initFromName`('basemodules`,' "B$1"`,' (long) ((B$1 *) derived) - (long) derived`)';
`if (t && basi < MAXBASETYPES)
tsb[basi++] = (PyObject *) t;'
` bases(shift($*))')')
define(`debases',
`ifelse($1,, ,Base_initFromName`('basemodules`,' "B$1"`,' 0`)';
` debases(shift($*))')')
define(`symbols',
`ifelse($1,, ,set($1);
` symbols(shift($*))')')
define(`presets',
`ifelse($1,, ,preset($1, $2);
` presets(shift(shift($*)))')')
define(`dummypresets',
`ifelse($1,, ,preset($1, dummy_$2);
` dummypresets(shift(shift($*)))')')
define(`decldummypresets',
`ifelse($2,, ,static void *dummy_$2 = (void *) $1;
`decldummypresets(incr($1), shift(shift(shift($*))))')')
define(`testpresets',
`ifelse($3,, ,$1 $2 == dummy_`'$3
` testpresets(`||', $2, shift(shift(shift(shift($*)))))')')
define(`realpresets',
`ifelse($3,, ,$1 if ($2 == dummy_$3)
$2 = (void *) $4;
` realpresets(`else', $2, shift(shift(shift(shift($*)))))')')
define(`methods',
`ifelse($1,, ,{"$1"`, (PyCFunction) PyB'CLASS`'_$1`, 1, (char *) PyB'CLASS`'_$1`_doc},'
` methods(shift($*))')')
define(`exptbl',
`ifelse($1,, ,cfunctions.$1 = PyB`'CLASS`'_$1;
` exptbl(shift($*))')')
dnl define(`imports',
dnl `ifelse($1,, ,#include "$1.h"
dnl static struct $1`'Functions *$1`'CTbl = 0;
dnl `imports(shift($*))')')
define(`imports',
`ifelse($1,, ,static struct BaseFunctions *$1`'CTbl = 0;
`imports(shift($*))')')
dnl define(`imports',
dnl `ifelse($1,, ,`#'ifndef $1`'_CTBL_
dnl `#'define $1`'_CTBL_
dnl static struct BaseFunctions *$1`'CTbl = 0;
dnl `#'endif
dnl `imports(shift($*))')')
define(`append', `define(`$1', defn(`$1')`,$2')')
define(`vhincl',
`ifelse($1,, ,#include "$1.h"
`vhincl(shift($*))')')
define(`vdincl',
`ifelse($1,, ,#include "$1.def"
`vdincl(shift($*))')')
define(`venums', `ifelse($1,, ,`v'$1`,' `venums(shift($*))')')
define(`vfns',
`ifelse($1,, ,$1`'VFNs
` vfns(shift($*))')')
dnl define(`vfms',
dnl `ifelse($1,, ,$1`'VFMs
dnl ` vfms(shift($*))')')
define(`vfms',
`ifelse($1,, ,`{v'$1`, "'$1`"},'
` vfms(shift($*))')')
define(`BCLASS', `B'CLASS)
define(`PCLASS', `PyB'CLASS`Object')
define(`ECLASS', `PyB'CLASS`Error')
dnl define(`upper', `translit($1,`abcdefghijklmnopqrstuvxyz', `ABCDEFGHIJKLMNOPQRSTUVXYZ')')
define(`acount', `ifelse($1,,`0',`incr(acount(shift($*)))')')
Bethon-0.5.4/gen/module.m4 0000644 0000000 0000144 00000047553 10171665677 014155 0 ustar user users dnl Copyright 2002 by Donn Cave, Seattle, Washington, USA.
dnl All rights reserved. Permission to copy, modify and distribute this
dnl material is hereby granted, without fee, provided that the above
dnl copyright notice appear in all copies.
//
// C++ code automatically generated.
//
#include
#include
includes(BE_INCLUDES)
dnl Virtual functions need be_app, to quit if something goes wrong.
dnl
ifdef(`VFUNS',``#'include ')
`#'include
`#'include "PyBase.h"
`#'include "PyMisc.h"
imports(IMPORTS)
`#'include "BpyBase.h"
ifdef(`VFUNS',
`// Class has virtual methods - e.g., handler.
enum {
venums(VFUNS)
NVFN
};
//
')
define(`MODULENAME', `B'CLASS)
define(`APINAME', `B'CLASS)
define(`PREFIX', `PyB'CLASS)
define(`APITYPE', `PyB'CLASS`Type')
define(`APIOBJECT', `PyB'CLASS`Object')
define(`BEAPITYPE', `B'CLASS)
static PyObject *ECLASS;
dnl Inheritance scheme for C++ classes derived from Be API for Python:
dnl "var" just Be API class. (Obsolete?)
dnl "ref" add 4-byte tag to identify Python-internal objects, & ptr.
dnl "VFUNS" has virtual functions, from Python instance wrapper.
dnl "handler" not "looper", but has Looper() function.
dnl "looper" has its own Python thread.
dnl "BApplication" special looper.
dnl
dnl "var" vs. "ref" basically revolves around the FromIt function
dnl (e.g., PyBHandler_FromBHandler() - this function gets a pointer
dnl to a C object and wraps it up in a Python C object.) It might
dnl copy the C object, which would be the normal case ("var"), but
dnl many C objects wouldn't take well to that - a BLooper, for example,
dnl so we'll want a Python reference to that very C object. In this
dnl case, Python just needs to know that it should only delete the
dnl C object, when it created it. This distinction is recorded in
dnl the C object (because that's what FromIt gets), along with a pointer
dnl back to the Python C object. When the stamp is recognized, FromIt
dnl returns the same Python C object. For an example - the DispatchMessage
dnl virtual hook gets a BHandler, and needs to convert that to a PyBHandler
dnl for its Python function. Since the system accepts external objects,
dnl not created here, we may point to either our derived class, or the
dnl plain Be base class, and use a variety of hacks to distinguish.
dnl
dnl Support for virtual functions adds a table for callbacks into the
dnl Python class instance wrapper, and thread interfaces. The derived
dnl class for this instantiates each supported virtual function, and
dnl if it's not actually provided in the wrapper, calls the base class
dnl function and returns.
dnl
dnl These callbacks need to be integrated with Python threads. The
dnl model for that here is one thread per looper, and all callbacks
dnl use their looper's thread (objects that are not themselves loopers
dnl can call Looper() to get the thread looper.) This model leaves
dnl a few things out, e.g., BFilePanel/BRefFilter callbacks aren't
dnl looking like they're going to work out at this point. A few hook
dnl functions get BView etc. parameters that can be used to find the
dnl thread looper (see "looperhandler" in .dx files), but we need either
dnl this or Handler/Looper parentage; otherwise, can't find thread state,
dnl can't branch into Python.
dnl
dnl Meanwhile, the Python object also has base class issues, because
dnl a BListView for example needs to be accepted as a BView in Python
dnl function calls just as in C++. This happens in the AsIt function,
dnl which goes about it in whatever funky way - once it has determined
dnl that the object is of the BaseObject variety, via another one of
dnl these hacky stamps.
define(`SEMANTICS', ifelse(FROMSELF, `var', `var', `ref'))
ifdef(`VFUNS',
`ifelse(FROMSELF, `looper',
`define(`VECLASS', `BpyLVBase')
define(`looperspec')',
`define(`VECLASS', `BpyHVBase')
define(`looperspec', `$1')
ifelse(FROMSELF, `handler',, `define(`looperless')')'
)',
`define(`VECLASS', `BpyBase')'
)
ifelse(FROMSELF, `abstract',
`define(`BCLASS', B`'CLASS)',
`define(`BCLASS', Bpy`'CLASS)
class BCLASS: public BEAPITYPE, public VECLASS {
ifdef(`VFUNS', `PyObject *vfn[NVFN];')
public:
dnl Constructor(s):
percomlist(CTORDCL)
ifdef(`VFUNS', `
~`'BCLASS`'() {
ifdef(`looperless',`//') getPyThread(looperspec(`Looper()'));
unbindInstance();
unbindSelf();
ifdef(`looperless',`//') releasePyThread(looperspec(`Looper()'));
}
int bindInstance(PyInstanceObject *);
void bindType(PyObject *);
PyObject *lookup(int i) {
if (instance && i < NVFN)
return vfn[i];
else
return 0;
}
list(VFNDCL)
')
};')
ifdef(`VFUNS', `
static struct vfnLookupTbl stdvfn[NVFN] = {
vfms(VFUNS)
};
// Set up Python/C++ peer (shadow?)
int
BCLASS::bindInstance(PyInstanceObject *inst)
{
int count;
ifelse(FROMSELF, `looper', `struct vfnLookupTbl lcfun = { 0, "lastchance" };
count = VFNInventory(inst, &lastchancefun, &lcfun, 1);
if (count < 0)
return 0;', `count = 0;')
count += VFNInventory(inst, vfn, stdvfn, NVFN);
// if (count > 0)
Py_INCREF(inst);
return 1;
}
// Set up Python subclass of C++ type.
static PyObject *
searchself(PyObject *obj, char *name)
{
PyObject *fun = PyObject_GetAttrString(obj, name);
if (fun) {
if (!PyMethod_Check(fun))
fun = 0;
} else
PyErr_Clear();
return fun;
}
void
BCLASS::bindType(PyObject *inst)
{
ifelse(FROMSELF, `looper', `lastchancefun = searchself(inst, "lastchance");')
instance = (PyInstanceObject *) inst; // Bleah!
int i;
for (i = 0; i < NVFN; ++i)
vfn[stdvfn[i].index] = searchself(inst, stdvfn[i].name);
}
')
dnl Global variables that are unstable, in the sense that their values
dnl vary during program execution. In the case of be_bold_font et al.,
dnl they are null until the BApplication constructor, which normally
dnl would tend to occur after module imports. The C/Python object for
dnl be_bold_font always refers to the present C value, thanks to this
dnl function and the run-time redirection that invokes it.
ifelse(CLASS, `Font', `define(`UNSTABLE_PRESETS', `dummy')')
ifdef(`UNSTABLE_PRESETS', `decldummypresets(11, PRESET)
static void *
realfromdummy(void *was)
{
realpresets(`', was, PRESET)
if (!was)
PyErr_SetString(PyExc_ValueError, "APINAME global object referenced prior to Application constructor");
return was;
}
')
ifelse(FROMSELF, `looper',
`typedef LooperBaseObject PCLASS;',
`typedef BaseObject PCLASS;')
ifelse(FROMSELF, `looper',
`ifelse(CLASS, `Application',
`static void
PREFIX`'_dealloc(PCLASS *self)
{
}',
`static int
deleteThread(PyThreadState *tstate)
{
PyThreadState_Clear(tstate);
PyThreadState_Delete(tstate);
return 1;
}
static void
PREFIX`'_dealloc(PCLASS *self)
{
BCLASS *cobj;
if (INTERNAL_BEPTR(self))
cobj = (BCLASS *) self->bevoid;
else
cobj = 0;
if (cobj)
cobj->instance = 0;
if (cobj && cobj->pystamp == BPYSTAMP) {
cobj->pystamp = 0;
PyThreadState *tstate = self->tstate;
if (cobj && !self->sysref) {
if (cobj->Lock())
cobj->Quit(); // == delete cobj.
}
if (tstate) {
// End of the road for this thread.
// Would like to delete its state table.
// Cannot do this from same thread(?), but
// a pending call is OK.
PyThreadState *cur = PyThreadState_Get();
if (cur == tstate)
Py_AddPendingCall(
(int (*)(void *)) deleteThread,
(void *) tstate);
else
deleteThread(tstate);
}
}
self->bevoidness = 0;
self->ob_type->tp_free((PyObject *) self);
}')',
`ifelse(FROMSELF, `abstract',`',
`static void
PREFIX`'_dealloc(PCLASS *self)
{
if (INTERNAL_BEPTR(self)) {
ifelse(FROMSELF,`abstract',`BEAPITYPE *cobj = (BEAPITYPE *) self->bevoid;
delete cobj;',
`BCLASS *dobj = (BCLASS *) self->bevoid;
if (dobj->frmpy()) {
ifdef(`VFUNS', `dobj->instance = 0;')
delete dobj;
} else {
BEAPITYPE *cobj = (BEAPITYPE *) self->bevoid;
delete cobj;
}')
} ifelse(FROMSELF,`var', ` else ifdef(`UNSTABLE_PRESETS', `if (!(testpresets(`', self->bevoid, PRESET)))') {
BEAPITYPE *cobj = (BEAPITYPE *) self->bevoid;
delete cobj;
}')
self->bevoidness = 0;
self->ob_type->tp_free((PyObject *) self);
}')')
// cfunctions will be used to export the to/from functions, to other
// Bxxx.so modules.
static struct BaseFunctions cfunctions;
typedef struct StringDx {
char *ptr;
int len;
} pstring;
typedef void *None;
typedef float ifloat;
static PyObject *
StatusError(const char *name, status_t stnum)
{
static const char unknown[] = "(unknown)";
char *r = strerror(stnum);
if (!r)
r = (char *) unknown;
PyErr_SetObject(ECLASS, Py_BuildValue("ls", stnum, r));
return 0;
}
static BEAPITYPE *nativePtr(PCLASS *);
ifelse(FROMSELF, `looper',
`define(`mkDerivative', `
BCLASS *$2;
if (!INTERNAL_BEPTR($1)) {
PyErr_SetString(PyExc_SystemError, "Illegal operation on external object.");
return 0;
}
$2 = (BCLASS *) ($1)->bevoid;')')
dnl macro to generate this function, only because in a very few cases
dnl there is no need for it and a few bytes can be saved.
define(`isB', `static int
isBThing(PyObject *a)
{
dnl (is this ridiculous? just make it a normal attribute!)
PyTypeObject *tp = a->ob_type;
PyObject *stamped;
static PyObject *bebostamp = 0;
if (!bebostamp)
bebostamp = PyString_FromString(BEBOSTAMP);
stamped = PyObject_GetAttr(a, bebostamp);
if (stamped)
Py_DECREF(stamped);
return stamped && stamped == Py_None;
dnl PyObject *mro = tp->tp_mro;
dnl int i, n;
dnl for (i = -1;;) {
dnl ++i;
dnl if (i == 0) {
dnl if (mro && PyTuple_Check(mro))
dnl n = PyTuple_Size(mro);
dnl else
dnl return 0;
dnl }
dnl if (i < n)
dnl tp = (PyTypeObject *) PyTuple_GetItem(mro, i);
dnl else
dnl return 0;
dnl }
}')
dnl Bring in a bunch of generated sections:
include(CODEINCL)
include(FUNCINCL)
ifdef(`VFUNS',
`static PyObject *
PREFIX`'_bind(PCLASS *self, PyObject *arg)
{
BCLASS *cobj;
if (INTERNAL_BEPTR(self))
cobj = (BCLASS *) self->bevoid;
else
cobj = 0;
if (!arg) {
PyObject *inst;
if (cobj && cobj->frmpy())
inst = (PyObject *) cobj->instance;
else
inst = 0;
if (!inst)
inst = Py_None;
Py_INCREF(inst);
return inst;
}
if (!cobj || !cobj->frmpy()) {
PyErr_SetString(PyExc_ValueError,
"operation not supported on externally referenced object");
return 0;
}
if (arg == Py_None)
cobj->unbindInstance();
else {
if (!PyInstance_Check(arg)) {
PyErr_SetString(PyExc_TypeError,
"bind requires 1 instance argument");
return 0;
}
if (!cobj->bindInstance((PyInstanceObject *) arg))
return 0;
}
Py_INCREF(Py_None);
return Py_None;
}')
static struct PyMethodDef PREFIX`'_methods[] = {
methods(METHODS)
ifdef(`VFUNS', `{"bind", (PyCFunction) PREFIX`'_bind},')
{NULL, NULL} /* sentinel */
};
static PyObject *
PREFIX`'_GetAttr(PyObject *obj, PyObject *nob)
{
char *name = PyString_AsString(nob);
if (name) {
if (!strcmp(name, BEBOSTAMP)) {
Py_INCREF(Py_None);
return Py_None;
}
dnl Bunch of code for the rare case of a data attribute,
dnl like "what". Now that the object here may be a class
dnl instance that inherits the present type, it's possible
dnl to get here prior to any initialization - the class
dnl __init__() hasn't called BParent.__init__(). At this
dnl point, let's say no data attributes.
PCLASS *self = (PCLASS *) obj;
BEAPITYPE *cobj;
if (INTERNAL_BEPTR(self)) {
ifelse(FROMSELF,`abstract',`cobj = (BEAPITYPE *) self->bevoid;',
`BCLASS *dobj = (BCLASS *) self->bevoid;
if (dobj->frmpy())
cobj = (BEAPITYPE *) dobj;
else
cobj = (BEAPITYPE *) self->bevoid;
cobj = (BEAPITYPE *) dobj;')
} else if (EXTERNAL_BEPTR(self)) {
void *bevoid = self->bevoid;
ifdef(`UNSTABLE_PRESETS', `bevoid = realfromdummy(bevoid);')
cobj = (BEAPITYPE *) bevoid;
} else
cobj = 0;
dnl } else {
dnl PyErr_SetString(PyExc_SystemError, "Invalid object");
dnl return 0;
dnl }
// For internal use, to recognize Bethon modules.
PyObject *ret;
static char *attrs[] = {
strings(ATTRIBUTES)
0
};
if (cobj) {
include(ATTRINCL)
}
}
return PyObject_GenericGetAttr(obj, nob);
}
ifelse(FROMSELF, `abstract',,`static int PREFIX`'_init(PyObject *, PyObject *, PyObject *);')
ifelse(FROMSELF, `abstract',,`static PyObject *PREFIX`'_new(PyTypeObject *, PyObject *, PyObject *);')
static PyTypeObject APITYPE = {
PyObject_HEAD_INIT(&PyType_Type)
0, /*ob_size*/
"MODULENAME`.'APINAME", /*tp_name*/
sizeof(PCLASS), /*tp_size*/
0, /*tp_itemsize*/
/* methods */
ifelse(FROMSELF, `abstract', 0, `(destructor) PREFIX`'_dealloc'), /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
PREFIX`_GetAttr', /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
PREFIX`'_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
ifelse(FROMSELF, `abstract', `0', `PREFIX`'_init'), /* tp_init */
PyType_GenericAlloc, /* tp_alloc */
ifelse(FROMSELF, `abstract', `0', `PREFIX`'_new'), /* tp_new */
_PyObject_Del, /* tp_free */
};
static struct baseItem basemodules[MAXBASETYPES];
static BEAPITYPE *
nativePtr(PCLASS *self)
{
int i;
for (i = 0; i < MAXBASETYPES && self->base[i].name[0]; ++i) {
if (self->base[i].type == &APITYPE) {
void *bevoid = self->bevoid;
ifdef(`UNSTABLE_PRESETS',` bevoid = realfromdummy(bevoid);')
return (BEAPITYPE *) ((void *) (((long) bevoid) + self->base[i].offset));
}
}
fprintf(stderr, "BEAPITYPE not found.\n");
return 0;
}
// Recursively call PyType_Ready() - PyType_Ready() will gag
// if it hits a base that it hasn't initialized, so the hierarchy
// has to be initialized ahead of time from the bottom up.
static void readyBases(PyTypeObject *);
static void
readyBases(PyTypeObject *tp)
{
int n;
if (tp->tp_bases && PyTuple_Check(tp->tp_bases))
n = PyTuple_Size(tp->tp_bases);
else
n = 0;
int i;
for (i = 0; i < n; ++i)
readyBases((PyTypeObject *) PyTuple_GetItem(tp->tp_bases, i));
PyType_Ready(tp);
}
static void
initBases()
{
static int initstate = 0;
// First of our kind?
if (initstate)
return;
memset(basemodules, 0, sizeof(basemodules));
// Need a non-null pointer value here, but cannot be sure
// that the first caller will have access to a properly
// constructed BCLASS. Appears that any non-null value
// is as good as another, though. If this is not true
// after all, we will have to put back in some code that
// comes back and cleans this up the first time a real
// BCLASS is available.
BCLASS *derived = (BCLASS *) 0xdeadbeef;
Base_init(basemodules, "APINAME",
(long) ((BEAPITYPE *) derived) - (long) derived, &APITYPE);
PyObject *tsb[MAXBASETYPES + 2];
PyTypeObject *t;
int basi = 0;
bases(BASES)
tsb[basi++] = (PyObject *) &PyBaseObject_Type;
tsb[basi] = 0;
PyObject *baseq = PyTuple_New(basi);
for (basi = 0; tsb[basi]; ++basi)
PyTuple_SetItem(baseq, basi, tsb[basi]);
APITYPE.tp_bases = baseq;
readyBases(&APITYPE);
initstate = 1;
}
ifelse(FROMSELF,`abstract',,
`static PyObject *
PREFIX`'_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PCLASS *self;
self = (PCLASS *) (type->tp_alloc(type, 0));
if (self) {
self->bevoid = 0;
self->bevoidness = 0;
self->base = basemodules;
ifelse(FROMSELF, `looper', `self->sysref = 0;
self->tstate = PyThreadState_Get();')
}
return (PyObject *) self;
}
')
static BEAPITYPE *
PREFIX`_As'APINAME`'(PyObject *arg)
{
dnl if (arg->ob_type != &APITYPE)
dnl return 0;
dnl return (BEAPITYPE *) ((APIOBJECT *) arg)->cobj;
dnl The present object may be of Python type B`'CLASS, or of a
dnl derived class, and it suits our purposes to accept either.
dnl So if it appears that it is at least of the BeOS type generally,
dnl try to cast to B`'CLASS from the universal base. dynamic_cast
dnl is supposed to return 0 if that is not legit with this object,
dnl but I seem unable to get that to work by trying various things
dnl at random. So, I grub through the Python base list, which is
dnl not really the ideal notion of what we want.
dnl I mean, the question really is whether the object is acceptably
dnl derived per the Be API, not whether we happen to have a Python
dnl implementation of the type with the nominally required relationship.
dnl
dnl abstract classes used to return 0 here, not sure why!
APIOBJECT *ob = (APIOBJECT *) arg;
if (!PyType_IsSubtype(arg->ob_type, &APITYPE)) {
PyErr_SetString(PyExc_TypeError, arg->ob_type->tp_name);
return 0;
}
BEAPITYPE *cobj;
if (INTERNAL_BEPTR(ob)) {
ifelse(FROMSELF,`abstract',`cobj = (BEAPITYPE *) ob->bevoid;', `BCLASS *dobj = (BCLASS *) ob->bevoid;
if (dobj->frmpy())
cobj = (BEAPITYPE *) dobj;
else
cobj = (BEAPITYPE *) ob->bevoid;')
} else if (EXTERNAL_BEPTR(ob)) {
void *bevoid = ob->bevoid;
ifdef(`UNSTABLE_PRESETS', `bevoid = realfromdummy(bevoid);')
cobj = (BEAPITYPE *) bevoid;
} else {
PyErr_SetString(PyExc_SystemError, "Invalid object");
return 0;
}
return cobj;
}
dnl BStatable is an abstract class, for example.
dnl be_app_messenger is a "preset", already instantiated.
ifelse(FROMSELF,`abstract',
`static PyObject *
PREFIX`_From'APINAME`'(const BEAPITYPE *cobj, int internal)
{
// Bogus function purely for standard cfunctions table.
return 0;
}',FROMSELF,`var',
`static PyObject *
PREFIX`_From'APINAME`'(const BEAPITYPE *cobj, int internal)
{
if (!cobj) {
PyErr_SetString(PyExc_ValueError, "null pointer");
return 0;
}
PCLASS *self = (PCLASS *) PREFIX`'_new(&APITYPE, 0, 0);
if (self) {
BEAPITYPE *copy = new BEAPITYPE`'((*(BEAPITYPE`' *) cobj));
SETINT_BEPTR(self, copy);
initBases();
}
return (PyObject *) self;
}',
`static PyObject *
PREFIX`_From'APINAME`'(BEAPITYPE *cob, int internal)
{
if (!cob) {
PyErr_SetString(PyExc_ValueError, "null pointer");
return 0;
}
ifdef(`VFUNS',
`define(`basecast',`dynamic_cast<$1>($2)')',
`define(`basecast',`($1) $2')')
BpyBase *dobj;
dobj = basecast(`BpyBase *', `cob');
if (dobj && dobj->frmpy()) {
PyObject *self = dobj->self();
Py_INCREF(self);
return self;
} else {
PCLASS *self = (PCLASS *) PREFIX`'_new(&APITYPE, 0, 0);
if (self) {
if (internal)
SETINT_BEPTR(self, cob);
else
SETEXT_BEPTR(self, cob);
initBases();
}
return (PyObject *) self;
}
}')
static PyObject *module_dict;
include(GFUNCINCL)
static struct PyMethodDef MODULENAME`'_global_methods[] = {
include(GLMETHINCL)
{NULL, NULL} /* sentinel */
};
#define set(s) PyDict_SetItemString(module_dict, #s, PyInt_FromLong(s))
`#'define preset(s,v) std`'PCLASS = (PCLASS *) PREFIX`'_new(&APITYPE, 0, 0); \
SETEXT_BEPTR(std`'PCLASS, (void *) v); \
initBases(); \
PyDict_SetItemString(module_dict, `#'s, (PyObject *) std`'PCLASS);
extern "C" void
`init'MODULENAME`'()
{
ifdef(`PRESET',` PCLASS *std`'PCLASS;')
PyObject *mod = Py_InitModule("MODULENAME", MODULENAME`_global_methods');
module_dict = PyModule_GetDict(mod);
ECLASS = PyErr_NewException("MODULENAME.error", 0, 0);
PyDict_SetItemString(module_dict, "error", ECLASS);
// Force import to get base classes, really needed only if this is
// a base class.
initBases();
PyDict_SetItemString(module_dict, "APINAME", (PyObject *) &APITYPE);
ifdef(`PRESET', ` ifdef(`UNSTABLE_PRESETS', `dummypresets(PRESET)', `presets(PRESET)')')
ifdef(`SYMBOLS', ` symbols(SYMBOLS)')
cfunctions.AsIt = (void *(*)(PyObject *)) PREFIX`_As'APINAME;
cfunctions.FromIt = (PyObject *(*)(const void *, int)) PREFIX`_From'APINAME;
cfunctions.type = &APITYPE;
PyDict_SetItemString(module_dict, "functions", PyCObject_FromVoidPtr(&cfunctions, 0));
include(GLSMINCL)
}
Bethon-0.5.4/gen/sg 0000755 0000000 0000144 00000000714 11240114125 012720 0 ustar user users #!/boot/common/bin/python
#
# Copyright 1999 by Donn Cave, Seattle, Washington, USA.
# All rights reserved. Permission to copy, modify and distribute this
# material is hereby granted, without fee, provided that the above
# copyright notice appear in all copies.
from sgcf import cf
import sgrules
import sgparse
import sgoutput
import sggen
import sys
if __name__ == '__main__':
for arg in sys.argv[1:]:
cf.parse.parseFile(arg)
cf.parse.Generate()
Bethon-0.5.4/gen/sgcf.py 0000644 0000000 0000144 00000000507 07150775453 013703 0 ustar user users # Copyright 1999 by Donn Cave, Seattle, Washington, USA.
# All rights reserved. Permission to copy, modify and distribute this
# material is hereby granted, without fee, provided that the above
# copyright notice appear in all copies.
class Cf:
def __init__(self):
self.srcdir = '../source'
cf = Cf()
cf.files = Cf()
Bethon-0.5.4/gen/sggen.py 0000644 0000000 0000144 00000051025 07703447662 014067 0 ustar user users # Copyright 1999 by Donn Cave, Seattle, Washington, USA.
# All rights reserved. Permission to copy, modify and distribute this
# material is hereby granted, without fee, provided that the above
# copyright notice appear in all copies.
import re
import string
from sgcf import cf
from sgvar import ParamParser, ParamTable, Variable, UnsupportedError
class Issue:
def __init__(self, out):
self.out = out
def __call__(self, cfile):
if self.out:
cfile.iput(self.out);
# Function derived from a single "input" statement.
class Function:
fail = Issue('return 0;\n')
castself = Issue(None)
def __init__(self, name, cname, ds, vprfx, table):
self.ds = ds
self.name = name
self.cname = cname
self.parser = ParamParser()
self.clist = []
self.plist = []
self.rlist = []
self.slist = []
listdict = {'input': self.plist, 'param': self.clist,
'return': self.rlist, 'status': self.slist}
for ltype in ('input', 'param', 'return', 'status'):
vd = ds[ltype]
if not vd:
continue
xlist = listdict[ltype]
for i in range(len(vd)):
p = self.parser.parse(vd[i], table, vprfx)
xlist.append(p)
self.autoparam = ds['byhand'] is None
def pparams(self):
for p in self.plist:
p.setup_p2c()
return len(self.plist)
def cparams(self):
pass
def rparams(self):
pass
def looperspec(self):
# How to get at the looper for the right thread.
handler = self.ds['loophandler']
if not handler:
return 'Looper()'
else:
p = self.parser.parse(handler[0])
return '%s->Looper()' % p.var.name
def docargtbl(self, width):
crep = []
for i in range(width):
if i < len(self.plist):
p = self.plist[i]
if p.initval:
crep.append('%s=%s' % (p.var.rule.ptype, p.initval.value))
else:
crep.append(p.var.rule.ptype)
cret = []
for r in self.rlist:
cret.append(r.var.rule.ptype)
return crep, cret
def declargtbl(self, width):
cfile = cf.cfile
cfile.iput('{')
for i in range(width):
if i:
cfile.put(', ')
if i >= len(self.plist):
cfile.put('{0, 0, 0, 0, 0}');
else:
p = self.plist[i]
init = p.initptr()
vr = p.var.rwptr()
# cfile.put('{&%s, %s, %s_rep, %s_p2c, sizeof(%s)}' % (vr, init, p.var.rule, p.var.rule, vr))
cfile.put('{&%s, %s, 0, %s_p2c, sizeof(%s)}' % (vr, init, p.var.rule, vr))
cfile.put('}')
def parse(self, i):
cfile = cf.cfile
cfile.put('if (ParseTuple(args, inp[%d], %d)) {\n' % (i, len(self.plist)))
cfile.indent(1)
self.putfuncall()
cfile.indent(-1)
def scopefun(self):
return self.cname
def putfuncall(self):
cfile = cf.cfile
ccode = self.ds['code']
if ccode is None:
ccode = ()
# cfile.iput('// --- code slot 1 ---\n')
if ccode and ccode[1]:
for line in ccode[1]:
cfile.iput(string.join(line) + '\n')
for c in self.clist:
allocs = c.allocate(cfile)
for alloc in allocs:
cfile.iput('if (!%s)\n' % alloc)
cfile.indent(1)
cfile.iput('return PyErr_NoMemory();\n')
cfile.indent(-1)
# cfile.iput('// --- code slot 2 ---\n')
if ccode and ccode[2]:
for line in ccode[2]:
cfile.iput(string.join(line) + '\n')
if self.slist and self.slist[0].pos == 0:
fv = self.slist[0].var
elif self.rlist and self.rlist[0].pos == 0:
fv = self.rlist[0].var
else:
fv = None
cfile.iput('Py_BEGIN_ALLOW_THREADS\n')
if fv:
cfile.iput('%s = ' % fv.name)
else:
cfile.iput('')
cfile.put('%s(' % self.scopefun())
cl = []
for c in self.clist:
cl.append(c.passout())
cfile.put(string.join(cl, ', '))
cfile.put(');\n')
cfile.iput('Py_END_ALLOW_THREADS\n')
if self.slist:
cfile.iput('if (%s < B_OK)\n' % self.slist[0].var.name)
cfile.indent(1)
cfile.iput('return StatusError("%s", %s);\n' % (self.name, self.slist[0].var.name))
cfile.indent(-1)
for c in self.clist:
if c.refsemantics() == 'incref':
cfile.iput('Py_INCREF(PyTuple_GetItem(args, %d));\n' % (c.pos - 1))
pyolist = []
cprlist = []
# cfile.iput('// --- code slot 3 ---\n')
if ccode and ccode[3]:
for line in ccode[3]:
cfile.iput(string.join(line) + '\n')
for r in self.rlist:
n = 'P' + r.var.name
pyolist.append(n)
cprlist.append((r, n))
if self.rlist:
cfile.iput('PyObject *')
cfile.put(string.join(pyolist, ', *'))
cfile.put(';\n')
for r, n in cprlist:
p = Variable('PyObject*', n)
if r.initval:
cfile.iput('if (%s) {\n' % r.var)
cfile.indent(1)
r.c2p(p)
if r.initval:
cfile.indent(-1)
cfile.iput('} else {\n')
cfile.indent(1)
x = str(r.initval)
if x == 'None' or x == 'Py_None':
cfile.iput('Py_INCREF(Py_None);\n');
cfile.iput('%s = Py_None;\n' % (n,))
else:
cfile.iput('%s = %s;\n' % (n, x))
cfile.indent(-1)
cfile.iput('}\n')
cfile.iput('PyObject *retv;\n')
if len(self.rlist) == 0:
cfile.iput('Py_INCREF(Py_None);\n')
cfile.iput('retv = Py_None;\n')
elif len(self.rlist) == 1:
cfile.iput('retv = %s;\n' % pyolist[0])
else:
# cfile.iput('retv = Py_BuildValue("%s", ' % ('O' * len(self.rlist)))
# cfile.put(string.join(pyolist, ', '))
# cfile.put(');\n')
cfile.iput('retv = PyTuple_New(%d);\n' % len(pyolist));
i = 0
for pyo in pyolist:
cfile.iput('PyTuple_SetItem(retv, %d, %s);\n' % (i, pyo))
i = i + 1
for c in self.clist:
c.var.free(cfile)
# cfile.iput('// --- code slot 4 ---\n')
if ccode and ccode[4]:
for line in ccode[4]:
cfile.iput(string.join(line) + '\n')
cfile.iput('return retv;\n')
class MemberFunction(Function):
def scopefun(self):
return 'cobj->%s' % self.cname
class Constructor(MemberFunction):
fail = Issue('return -1;\n')
castself = Issue('PCLASS *self = (PCLASS *) selfob;\n')
def putfuncall(self):
ccode = self.ds['code']
if ccode is None:
ccode = ()
# "return" object is known in principle, and the m4 macros
# are more useful here than the description file return stmt.
#
# fv = self.rlist[0].cob.name
cfile = cf.cfile
cfile.iput("BCLASS *a0 = new BCLASS`'(")
cfile.put(string.join(map(lambda v: v.passout(), self.clist), ', '))
cfile.put(');\n')
if self.slist:
cfile.iput('if (%s != B_OK) {\n' % self.slist[0].var)
cfile.indent(1)
cfile.iput('StatusError("%s", %s);\n' % (self.name, self.slist[0].var))
self.fail(cfile)
cfile.indent(-1)
cfile.iput('}\n')
cfile.iput('if (!a0)\n')
cfile.indent(1)
self.fail(cfile)
cfile.indent(-1)
for c in self.clist:
if c.refsemantics() == 'incref':
cfile.iput('Py_INCREF(PyTuple_GetItem(args, %d));\n' % (c.pos - 1))
cfile.iput('initBases();\n')
# cfile.iput('// --- code slot 2 ---\n')
if ccode and ccode[2]:
for line in ccode[2]:
cfile.iput(string.join(line) + '\n')
# cfile.iput('// --- code slot 3 ---\n')
if ccode and ccode[3]:
for line in ccode[3]:
cfile.iput(string.join(line) + '\n')
cfile.iput('SETINT_BEPTR(self, a0);\n')
cfile.iput('BINDINT_BEPTR(self, a0);\n')
cfile.iput('ifdef(`VFUNS\', `a0->bindType(selfob);\')\n')
# cfile.iput('// --- code slot 4 ---\n')
if ccode and ccode[4]:
for line in ccode[4]:
cfile.iput(string.join(line) + '\n')
cfile.iput('return 0;\n')
class VFunction(MemberFunction):
def pparams(self):
pass
def rparams(self):
for p in self.rlist:
p.setup_p2c()
# The set of the function's overloads.
class FunctionSet:
def __init__(self, name, cname, ostack, fclass, cfname):
self.name = name
self.fclass = fclass
self.cfname = cfname
self.partbl = ParamTable()
self.fs = []
self.maxinpars = 0
# Invert overload stack to make a list of dicts of lists,
# from a dict of lists of lists.
il = ostack.items()
inv = []
for i in range(len(il[0][1])):
inv.append({})
for k, v in il:
inv[i][k] = v[i]
vprfx = 'A'
for o in inv:
#
# Here is the parameter analysis.
#
self.fs.append(fclass(self.name, cname, o, vprfx, self.partbl))
vprfx = chr(ord(vprfx) + 1)
for o in self.fs:
n = o.pparams()
if self.maxinpars < n:
self.maxinpars = n
for o in self.fs:
o.cparams()
for o in self.fs:
o.rparams()
def declvars(self):
for p in self.partbl.dump():
for d in p.declare():
cf.cfile.iput(d + ';\n')
def docargtbl(self):
frep = []
for f in self.fs:
crep, cret = f.docargtbl(self.maxinpars)
frep.append(string.join(crep, ','))
if cret:
if len(cret) > 1:
cret = '(%s)' % string.join(cret, ',')
else:
cret = cret[0]
name = '%s %s' % (cret, self.name)
else:
name = self.name
return 'static const char %s_doc[] = "%s(%s)";\n' % (self.cfname, name, string.join(frep, '|'))
def declargtbl(self):
cfile = cf.cfile
if self.maxinpars > 0:
# Lay out table of argument overloads.
# Specify variable address, result variable address,
# default value and converter function for each.
cfile.iput('struct InputParam inp[%d][%d] = {\n' % (len(self.fs), self.maxinpars))
cfile.indent(1)
lf = self.fs[-1]
for f in self.fs:
f.declargtbl(self.maxinpars)
if not f is lf:
cfile.put(',')
cfile.put('\n')
cfile.indent(-1)
cfile.iput('};\n')
def process(self):
cfile = cf.cfile
if self.maxinpars == 0:
cfile.iput('if (PyTuple_Size(args)) {\n')
cfile.indent(1)
cfile.iput('PyErr_SetString(PyExc_TypeError, %s_doc);\n' % self.cfname)
self.fclass.fail(cfile)
cfile.indent(-1)
cfile.iput('}\n');
self.fs[0].putfuncall()
elif not self.fs:
cfile.iput('/* XXX no function parameter list specified! */\n')
else:
for i in range(len(self.fs)):
if i == 0:
cfile.iput('')
else:
cfile.iput('} else ')
self.fs[i].parse(i)
cfile.iput('} else {\n')
cfile.indent(1)
cfile.iput('PyErr_SetString(PyExc_TypeError, %s_doc);\n' % self.cfname)
self.fclass.fail(cfile)
cfile.indent(-1)
cfile.iput('}\n');
class CC:
def __init__(self):
pass
def codegen(self, list):
for line in list:
line = string.join(line)
i = 0
while line[i:i+2] == '^I':
i = i + 2
line = '\t'*(i/2) + line[i:]
cf.files.xcode.put(line)
def inclgen(self, list):
st = 'define(`BE_INCLUDES\', `' + string.join(list, ', ') + '\')\n'
cf.files.xdefs.put(st)
cf.files.xincl.put(st)
def classgen(self, name):
self.name = 'B' + name
xdefs = cf.files.xdefs
xdefs.put('define(`CLASS\', `' + name + '\')\n')
xdefs.put('define(`UPPERCLASS\', `' + string.upper(name) + '\')\n')
xdefs.put('include(defs.m4)\n')
def classlistgen(self, fromself, bases, methods, attribs, ctors, vfuns, vfundecl, preset):
xdefs = cf.files.xdefs
methods = filter(lambda x, n=self.name: x != n, methods)
xdefs.put('define(`FROMSELF\', `' + fromself + '\')\n')
xdefs.put('define(`BASES\', `' + string.join(bases, ', ') + '\')\n')
xdefs.put('define(`METHODS\', `' + string.join(methods, ', ') + '\')\n')
xdefs.put('define(`ATTRIBUTES\', `' + string.join(attribs, ', ') + '\')\n')
xdefs.put('define(`CTORDCL\', `' + string.join(ctors, ', ') + '\')\n')
if vfuns:
xdefs.put('define(`VFUNS\', `' + string.join(vfuns, ', ') + '\')\n')
if vfundecl:
xdefs.put('define(`VFNDCL\', `' + string.join(vfundecl, ', ') + '\')\n')
if preset:
xdefs.put('define(`PRESET\', `' + string.join(preset, ', ') + '\')\n')
def finish(self):
xdefs = cf.files.xdefs
if not hasattr(self, 'name'):
self.name = 'Bconsts'
xdefs.put('include(defs.m4)\n')
xdefs.put('define(`FUNCINCL\', `xxfuns.m4\')\n')
xdefs.put('define(`GFUNCINCL\', `xxgfun.m4\')\n')
xdefs.put('define(`GLMETHINCL\', `xxglme.m4\')\n')
xdefs.put('define(`GLSMINCL\', `xxglsm.m4\')\n')
xdefs.put('define(`ATTRINCL\', `xxattr.m4\')\n')
xdefs.put('define(`CODEINCL\', `xxcode.m4\')\n')
xdefs.put('define(`IMPORTS\', `' + string.join(cf.cfile.bmports(), ', ') + '\')\n')
xdefs.put('divert(0)\n')
xdefs.put('include(template)\n')
def symgen(self, data):
cf.files.xdefs.iput('define(`SYMBOLS\', `' + string.join(data, ', ') + '\')\n')
def ctor(self, ostack):
elist = []
for pl in ostack['param']:
pes = ''
pbs = ''
for p in pl:
p = string.split(p, '@')
if pes:
pes = pes + ', '
pes = pes + p[0] + ' P' + p[1]
if pbs:
pbs = pbs + ', '
pbs = pbs + 'P' + p[1]
elist.append('BCLASS`\'(' + pes + '): B`\'CLASS`\'(' + pbs + ') {}')
return elist
# Module level function. (watch_node, stop_watch.)
def fungen(self, name, cname, ostack, sourcefile):
fclass = Function
xfuns = cf.files.xfuns
cf.cfile.setfile(xfuns)
cfname = 'PyB_' + str(name)
fset = FunctionSet(name, cname, ostack, fclass, cfname)
xfuns.put('// from %s\n' % sourcefile)
xfuns.put(fset.docargtbl())
xfuns.put('static PyObject *\n');
xfuns.put(cfname)
xfuns.put('(PyObject *module, PyObject *args)\n{\n')
xfuns.put('/* ' + repr(ostack) + ' */\n')
xfuns.indent(1)
fset.declvars()
fset.declargtbl()
fset.process()
xfuns.indent(-1)
xfuns.put('}\n\n')
xglme = cf.files.xglme
xglme.put('\t{"%s", %s, 1},\n' % (name, cfname))
def smgen(self, name, cname, ostack, sourcefile):
self.fungen(name, cname, ostack, sourcefile)
cfname = str(name)
xglsm = cf.files.xglsm
xglsm.indent(1)
xglsm.iput('PyObject *mf = PyDict_GetItemString(module_dict, "%s");\n' % cfname)
xglsm.iput('if (mf) {\n');
xglsm.indent(1)
xglsm.iput('PyObject *sm = PyStaticMethod_New(mf);\n');
xglsm.iput('if (sm)\n')
xglsm.indent(1)
xglsm.iput('PyDict_SetItemString(APITYPE.tp_dict, "%s", sm);\n' % cfname);
xglsm.indent(-2)
xglsm.iput('}\n')
def methgen(self, name, cname, ostack, sourcefile):
if name == self.name:
fclass = Constructor
xfuns = cf.files.xgfun
frtype = 'int'
argst = '(PyObject *selfob, PyObject *args, PyObject *kwds)'
co = None
fname = 'init'
else:
fclass = MemberFunction
xfuns = cf.files.xfuns
frtype = 'PyObject *'
argst = '(PCLASS *self, PyObject *args)'
co = 'B`\'CLASS *cobj = nativePtr(self); if (!cobj) return 0;\n'
fname = str(name)
cf.cfile.setfile(xfuns)
cfname = 'PyB`\'CLASS`\'_' + name
fset = FunctionSet(name, cname, ostack, fclass, cfname)
xfuns.put('// from %s\n' % sourcefile)
xfuns.put(fset.docargtbl())
xfuns.put('static %s\n' % frtype);
xfuns.put('PyB`\'CLASS`\'_' + fname)
xfuns.put('%s\n{\n' % argst)
xfuns.put('/* ' + repr(ostack) + ' */\n')
xfuns.indent(1)
fclass.castself(xfuns)
fset.declvars()
fset.declargtbl()
if co:
xfuns.iput(co)
# xfuns.iput('static const char me[] = "%s";\n' % name);
fset.process()
xfuns.indent(-1)
xfuns.put('}\n\n')
def hookdecl(self, name, ostack):
# If there is to be a return value for the C++ function,
# it must come from the Python function, so we would find
# it in the "return" key.
ret = ostack['return'][0]
if ret:
for retval in ret:
retval = string.split(retval, '%')
if len(retval) > 1 and retval[1][:1] == '0':
ret = retval[0]
break
else:
ret = 'void'
else:
ret = 'void'
p = ostack['param'][0]
if p is None:
p = ''
else:
p = string.join(map(lambda x, s='@': string.split(x,s)[0], p), ', ')
return 'virtual %s %s(`%s\');' % (ret, name, p)
def hookgen(self, name, may_call_base, ostack, sourcefile):
cf.cfile.setfile(cf.files.xfuns)
xfuns = cf.files.xfuns
o = {}
for k, v in ostack.items():
o[k] = v[0]
ccode = o['code']
if ccode is None:
ccode = ()
fun = VFunction(name, name, o, 'V', ParamTable())
fun.cparams()
fun.pparams()
fun.rparams()
# How to specify the Looper for this thread. This is
# by default the Handler's Looper() function ... and then
# a module-level m4 macro keeps this from being expressed
# in the case of the Looper class itself.
looper = fun.looperspec()
if fun.rlist:
ret = 'void'
for r in fun.rlist:
if hasattr(r, 'pos'):
if r.pos == 0:
ret = r.type
else:
print r, 'has no pos'
else:
ret = 'void'
arglist = []
for arg in fun.clist:
arglist.append('%s %s' % (arg.type, arg.var.name))
xfuns.put('// from %s\n' % sourcefile)
xfuns.put('%s\n' % ret)
xfuns.put('Bpy%s::%s(%s)\n{\n' % (self.name[1:], name, string.join(arglist, ', ')))
xfuns.put('/* ' + repr(ostack) + ' */\n')
xfuns.indent(1)
xfuns.iput('PyObject *argv;\n')
xfuns.iput('PyObject *res = 0;\n')
for r in fun.rlist:
if r.pos == 0:
fv = r.var
xfuns.iput('%s %s;\n' % (fv.type, fv.name))
break
else:
fv = None
arglist = []
for arg in fun.clist:
arglist.append(arg.var.name)
if may_call_base:
basecall = '%s::%s(%s);\n' % (self.name, name, string.join(arglist, ', '))
else:
basecall = '// No implementation for this function.\n'
if fun.rlist:
basecall = 'return ' + basecall
xfuns.iput('PyObject *fun;\n')
xfuns.iput('looperspec(BLooper *looper;)\n')
xfuns.iput('fun = lookup(v%s);\n' % name)
xfuns.iput('if (!fun)\n')
xfuns.indent(1)
xfuns.iput('goto nofun;\n')
xfuns.indent(-1)
xfuns.iput('looperspec(looper = %s;)\n' % looper);
xfuns.iput('if (looperspec(!looper || )looperspec(looper->)Thread() < B_NO_ERROR || !getPyThread(looperspec(looper)))\n')
xfuns.indent(1)
xfuns.iput('goto nofun;\n')
xfuns.indent(-1)
xfuns.iput('if (PyErr_Occurred()) {\n')
xfuns.indent(1)
xfuns.iput('releasePyThread(looperspec(%s));\n' % looper)
xfuns.iput('goto nofun;\n')
xfuns.indent(-1)
xfuns.iput('}\n')
xfuns.iput('goto goodfun;\n')
xfuns.iput('nofun:\n')
xfuns.indent(1)
xfuns.iput(basecall)
if not fun.rlist:
xfuns.iput('return;\n')
xfuns.indent(-1)
xfuns.iput('goodfun:\n')
pyolist = []
pprlist = []
if fun.autoparam:
for o in fun.plist:
n = 'P' + o.var.name
pyolist.append(n)
pprlist.append((o, n))
cf.cfile.setabort('goto abt;\n')
if len(fun.plist) > 0:
xfuns.iput('argv = PyTuple_New(%d);\n' % len(fun.plist))
xfuns.iput('if (!argv)\n')
xfuns.indent(1)
xfuns.iput('goto abt;\n')
xfuns.indent(-1)
else:
xfuns.iput('argv = 0;\n')
if fun.plist:
xfuns.iput('PyObject *')
xfuns.put(string.join(pyolist, ', *'))
xfuns.put(';\n')
i = 0
for o, n in pprlist:
p = Variable('PyObject*', n)
if o.var.ptrcount > 0:
xfuns.iput('if (!%s) {\n' % o.var.name)
xfuns.indent(1)
xfuns.iput('%s = Py_None;\n' % n)
xfuns.iput('Py_INCREF(Py_None);\n')
xfuns.indent(-1)
xfuns.iput('} else {\n')
xfuns.indent(1)
o.c2p(p)
if o.var.ptrcount > 0:
xfuns.indent(-1)
xfuns.iput('}\n')
xfuns.iput('PyTuple_SetItem(argv, %d, %s);\n' % (i, n))
i = i + 1
# if len(fun.clist) == 0:
# xfuns.iput('argv = 0;\n')
# else:
# xfuns.iput('argv = Py_BuildValue("(%s)", %s);\n' % (('O' * len(fun.clist)), string.join(pyolist, ', ')))
# xfuns.iput('// --- code slot 2 ---\n')
if ccode and ccode[2]:
for line in ccode[2]:
xfuns.iput(string.join(line) + '\n')
xfuns.iput('res = PyEval_CallObject(fun, argv);\n')
xfuns.put('abt:\n')
xfuns.iput('if (res) {\n')
xfuns.indent(1)
if len(fun.rlist) == 1:
pv = Variable('PyObject*', 'res')
r = fun.rlist[0]
r.var.p2c(pv)
elif len(fun.rlist) > 1:
for i in range(len(fun.rlist)):
pv = Variable('PyObject*', 'PyTuple_GetItem(res, %d)' % i)
r = fun.rlist[i]
r.var.p2c(pv)
xfuns.iput('Py_DECREF(res);\n')
xfuns.indent(-1)
xfuns.iput('} else {\n')
xfuns.indent(1)
# xfuns.iput('PyErr_Print();\n')
xfuns.iput('lastchance(looperspec(%s));\n' % looper)
xfuns.indent(-1)
xfuns.iput('}\n')
xfuns.iput('if (argv)\n')
xfuns.indent(1)
xfuns.iput('Py_DECREF(argv);\n')
xfuns.indent(-1)
cf.cfile.setabort()
xfuns.iput('releasePyThread(looperspec(%s));\n' % looper)
xfuns.iput('if (res)\n')
xfuns.indent(1)
if fv:
xfuns.iput('return %s;\n' % fv.name)
else:
xfuns.iput('return;\n')
xfuns.indent(-1)
xfuns.iput('else {\n')
xfuns.indent(1)
xfuns.iput('be_app->PostMessage(B_QUIT_REQUESTED);\n')
if name == 'QuitRequested':
xfuns.iput('return 1;\n')
elif fv:
# Arbitrary maybe, but not random anyway.
xfuns.iput('return 0;\n')
# xfuns.iput('looperspec(`%s->\')Quit();\n' % looper)
# xfuns.iput('be_app->Lock();\n');
# xfuns.iput('be_app->Quit();\n');
xfuns.indent(-1)
xfuns.iput('}\n')
xfuns.indent(-1)
xfuns.put('}\n\n')
def vfundecl(self, name, ostack):
ret = ostack['return'][0]
if ret:
ret = string.split(ret[0], '%')[0]
else:
ret = 'void'
p = ostack['param'][0]
if p is None:
p = ''
else:
p = string.join(map(lambda x, s='@': string.split(x,s)[0], p), ', ')
return 'virtual %s %s(`%s\');' % (ret, name, p)
def datagen(self, name, elements):
xattr = cf.files.xattr
cf.cfile.setfile(xattr)
xattr.indent(1)
xattr.iput('if (!strcmp(name, "%s")) {\n' % name)
xattr.indent(1)
xattr.iput('/* %s */\n' % string.join(elements[0]))
ret = elements[0]
xattr.iput('PyObject *ret;\n')
v = Variable(ret[1], 'cobj->' + name)
v.classify()
r = Variable('PyObject*', 'ret')
v.c2p(r)
xattr.iput('return ret;\n')
xattr.indent(-1)
xattr.iput('}\n')
xattr.indent(-1)
cf.gen = CC()
cf.gen.UnsupportedError = UnsupportedError
Bethon-0.5.4/gen/sgoutput.py 0000644 0000000 0000144 00000003453 07703446422 014651 0 ustar user users # Copyright 1999 by Donn Cave, Seattle, Washington, USA.
# All rights reserved. Permission to copy, modify and distribute this
# material is hereby granted, without fee, provided that the above
# copyright notice appear in all copies.
from sgcf import cf
class CodeFile:
def __init__(self, fp):
self.fp = fp
self.tab = 0
def iput(self, s):
self.put(' ' * self.tab)
self.put(s)
def indent(self, x):
self.tab = self.tab + x
if self.tab < 0:
self.tab = 0
def put(self, s):
self.fp.write(s)
class CFile:
def __init__(self):
self.file = None
self.incl = {}
self.bmpo = {}
self.setabort()
def append(self, st):
self.file.iput(st + '\n')
def code(self, st):
self.file.iput(st + '\n')
def abortif(self, t):
self.file.iput('if (%s)\n' % t)
self.file.indent(1)
self.file.iput(self.abortexpr)
self.file.indent(-1)
def indent(self, d):
self.file.indent(d)
def iput(self, s):
self.file.iput(s)
def put(self, s):
self.file.put(s)
def setfile(self, file):
r = self.file
self.file = file
return r
def include(self, st):
self.incl[st] = 1
def includes(self):
s = self.incl.keys()
s.sort()
return s
def bmport(self, st):
self.bmpo[st] = 1
def bmports(self):
s = self.bmpo.keys()
s.sort()
return s
def setabort(self, expr=None):
if expr:
self.abortexpr = expr
else:
self.abortexpr = 'return 0;\n'
cf.files.xfuns = CodeFile(open('xxfuns.m4', 'w'))
cf.files.xgfun = CodeFile(open('xxgfun.m4', 'w'))
cf.files.xdefs = CodeFile(open('xxdefs.m4', 'w'))
cf.files.xdefs.iput('divert(-1)\n')
cf.files.xattr = CodeFile(open('xxattr.m4', 'w'))
cf.files.xincl = CodeFile(open('xxincl.m4', 'w'))
cf.files.xcode = CodeFile(open('xxcode.m4', 'w'))
cf.files.xglme = CodeFile(open('xxglme.m4', 'w'))
cf.files.xglsm = CodeFile(open('xxglsm.m4', 'w'))
cf.cfile = CFile()
Bethon-0.5.4/gen/sgparse.py 0000644 0000000 0000144 00000027167 10171666104 014425 0 ustar user users # Copyright 1999 by Donn Cave, Seattle, Washington, USA.
# All rights reserved. Permission to copy, modify and distribute this
# material is hereby granted, without fee, provided that the above
# copyright notice appear in all copies.
# Generate C Python module code from class and rules descriptions.
# The result is used in conjunction with an m4 module template
# that lays out some standard module boilerplate.
# - write out module definitions like name, symbols, base
# classes, functions etc. ... XXdefs.m4
# - write out functions XXfunctions.m4
# - XXdefs.m4 includes module.m4
# - module.m4 includes XXfunctions.m4
import re
import string
import sys
from sgcf import cf
#
# Base class for parse node with non-leaf branches. Any relation to
# classic parse trees is accidental, here we have simply a topic like
# "function" that has subtopics like "param".
#
# "parse" method is invoked with split input line. Class must provide
# a function for interpreting this line, indexed by the first word in
# the line. E.g., to parse a nested input ' take this for example':
# in __init__, self.terms = {..., 'take':TakeOne, ...}
# If the object returned by parse has its own "parse" function, it jumps
# on top of the parse stack.
#
# Subtopics like "define", which accepts nested input but where that
# input is any old data, can provide a trivial definition of "parse",
# returning None, themselves rather than inherit from this class.
#
class ClassElement:
may_implement = 1
class Super:
def attach(self, ob):
self.elements.append(ob)
def close(self):
pass
def generate(self):
for el in self.elements:
if hasattr(el, 'generate'):
el.generate()
def parse(self, file, args):
term = self.terms[args[0]]
x = term(args[1:])
if hasattr(x, 'setfile'):
x.setfile(file)
self.attach(x)
# print 'parse?', repr(x),
if hasattr(x, 'parse'):
# print 'has parse'
return x
else:
# print 'has no parse'
return None
class LineData:
def __init__(self, args):
self.data = []
self.args = args
if args:
self.name = args[0]
def parse(self, file, args):
self.data.append(tuple(args))
return None
def __repr__(self):
return '<%s %s: %s>' % (self.__class__.__name__, repr(self.args), repr(self.data))
class WordData(LineData):
def parse(self, file, args):
self.data = self.data + args
return None
class Simple:
def __init__(self, name, args):
self.name = name
self.args = args
def __repr__(self):
return '<%s %s>' % (self.name, self.args)
class ArgGen:
def __init__(self, name):
self.name = name
def __call__(self, args):
return Simple(self.name, args)
def __repr__(self):
return '<%s: %s>' % (self.__class__.__name__, self.name)
class SetArgs:
def __init__(self, name):
self.args = None
self.name = name
def __call__(self, args):
self.args = tuple(args)
return None
def __repr__(self):
return '<%s: %s>' % (self.__class__.__name__, repr(self.args))
class CommArgGen(ArgGen):
def __call__(self, args):
if args:
# self.args = tuple(string.split(args[0], ','))
a = string.split(string.join(args), ',')
a.insert(0, self.name)
return tuple(a)
else:
# self.args = ()
return (self.name,)
# return Simple(self.name, self.args)
class BlockArgGen(ArgGen):
def __init__(self, args):
ArgGen.__init__(self, args)
def __call__(self, args):
return CodeLines([self.name] + args)
class CodeLines(LineData):
Range = 5
def __getitem__(self, i):
if i == 0:
return self.name
else:
raise IndexError, i
def __len__(self):
return len(self.data) + 1
def __getslice__(self, i, j):
print 'getslice', i, j
return self.data[i+1:j+1]
def __getattr__(self, a):
if a == 'index':
return string.atoi(self.args[1])
else:
raise AttributeError, a
# This could be general to derived classes, so class A's bases are
# implicitly acquired through class B's explicit relationship to C.
# But building any class would then require the whole suite of inherited
# class definitions. This way, that's only true among virtual-function
# classes.
#
def getBaseVirtuals(base, baselist, methods, vfuns, vfndecl):
baseparse = Parse()
try:
# Location of .dx files could be handled better.
baseparse.parseFile('%s/B%s.dx' % (cf.srcdir, base))
except IOError, ev:
print ev
print 'base virtuals for', base
for x in baseparse.nodelist:
if x.__class__ != Top:
continue
for y in x.elements:
if y.__class__ != Classe:
continue
for z in y.elements:
if z.__class__ is Hook:
z.may_call_base = 1
z.generate()
vfuns.append(z.name)
vfndecl.append(z.decl())
elif z.__class__ is Virtual:
# Pick up only new methods
for m in methods:
if m == z.name:
print >> sys.stderr, 'duplicate', z.name, 'in', base
# Probably OK to allow derived classes
# override, in which case uncomment break.
break
else:
z.may_implement = 1 # (pro forma)
z.generate()
methods.append(z.name)
# Make this pass last, so subclass methods prevail
# in Virtual clause above.
for z in y.elements:
if z.__class__ == Bases:
# Put immediate parents first, to please python 2.3
# else importing BButton fails because of different
# baseclass order than BControl...
for name in z.name:
baselist.append(name)
for name in z.name:
getBaseVirtuals(name, baselist, methods, vfuns, vfndecl)
class Classe(Super):
def __init__(self, args):
self.name = args[0]
if len(args) > 1:
self.fromself = args[1]
else:
self.fromself = 'var'
self.elements = []
self.terms = {'virtual':Virtual, 'hook':Hook, 'constructor':Constructor, 'attr':DataMember,
'function':MemberFunction, 'preset':Preset, 'base':Bases}
def close(self):
pass
def generate(self):
cf.gen.classgen(self.name)
bases = []
methods = []
attribs = []
ctors = []
preset = []
vfuns = []
vfndecl = []
for el in self.elements:
if not el.may_implement:
continue
try:
el.generate()
except cf.gen.UnsupportedError, val:
try:
nm = el.name
except AttributeError:
nm = repr(el)
print nm, 'failed, unsupported', val
el = None
if not el:
pass
elif el.__class__ is Constructor:
ctors = el.decl()
elif el.__class__ is Hook:
vfuns.append(el.name)
vfndecl.append(el.decl())
elif el.__class__ is MemberFunction or el.__class__ is Virtual:
methods.append(el.name)
elif el.__class__ is DataMember:
attribs.append(el.name)
elif el.__class__ is Preset:
preset.append(el.name)
elif el.__class__ is Bases:
bases = bases + el.name
baselist = bases[:]
for base in bases:
getBaseVirtuals(base, baselist, methods, vfuns, vfndecl)
bases = baselist
cf.gen.classlistgen(self.fromself, bases, methods, attribs, ctors, vfuns, vfndecl, preset)
def __repr__(self):
return '' % (self.name, repr(self.elements))
class Define(WordData):
def generate(self):
cf.gen.symgen(self.data)
class Include(WordData):
def generate(self):
cf.gen.inclgen(self.data)
class ModuleCode(LineData):
def generate(self):
cf.gen.codegen(self.data)
# Function default options semantics:
# on "input" statement recurrence, a new overload of the function appears.
#
class Function(Super):
overloadkey = 'input'
woverload = 'param'
stdterms = ('input', 'param', 'status', 'return', 'byhand')
def __init__(self, args):
self.name = args[0]
self.cname = self.name
self.options(args[1:])
self.terms = {}
self.ostack = {}
for i in self.stdterms:
self.terms[i] = CommArgGen(i)
self.ostack[i] = [None]
self.terms['code'] = BlockArgGen('code')
self.ostack['code'] = [None]
self.ofun = ()
self.over = 0
self.file = '?'
def options(self, opts):
if opts:
self.cname = opts[0]
def setfile(self, file):
self.file = file
def close(self):
pass
def overload(self):
for k in self.terms.keys():
self.ostack[k].append(())
self.over = self.over + 1
def resolve(self):
self.over = self.over + 1
self.ofun = ('hi',)
# Propagate specs forward as defaults.
# print 'resolve', self.name, self.ostack
for pl in self.ostack.values():
defp = pl[0]
for i in range(len(pl)):
if pl[i]:
defp = pl[i]
else:
pl[i] = defp
def attach(self, ob):
termname = ob[0]
a = self.ostack[termname]
if termname == self.overloadkey:
if not a[self.over] is None:
self.overload()
# "param" initially defaults to same as "input"
if self.woverload:
self.ostack[self.woverload][self.over] = ob[1:]
if type(ob) == type(()):
a[self.over] = ob[1:]
else:
x = a[self.over]
if not x:
x = [None]*ob.Range
x[ob.index] = ob.data
a[self.over] = x
def generate(self):
if not self.ofun:
self.resolve()
cf.gen.fungen(self.name, self.cname, self.ostack, self.file)
class StaticMethod(Function):
def generate(self):
if not self.ofun:
self.resolve()
cf.gen.smgen(self.name, self.cname, self.ostack, self.file)
class MemberFunction(Function, ClassElement):
def generate(self):
if not self.ofun:
self.resolve()
cf.gen.methgen(self.name, self.cname, self.ostack, self.file)
class Constructor(MemberFunction):
overloadkey = 'param'
woverload = None
def __init__(self, args):
MemberFunction.__init__(self, [None])
def decl(self):
if not self.ofun:
self.resolve()
return cf.gen.ctor(self.ostack)
def generate(self):
pass
class Hook(MemberFunction):
overloadkey = 'input'
woverload = 'param'
stdterms = ('input', 'param', 'status', 'return', 'byhand', 'loophandler')
may_call_base = 1
def options(self, opts):
for opt in opts:
if opt == 'none' or opt == 'None':
self.may_call_base = 0
def generate(self):
if not self.ofun:
self.resolve()
cf.gen.hookgen(self.name, self.may_call_base, self.ostack, self.file)
def decl(self):
if not self.ofun:
self.resolve()
return cf.gen.hookdecl(self.name, self.ostack)
class Virtual(MemberFunction):
def options(self, opts):
self.cname = None
for opt in opts:
if opt == 'none' or opt == 'None':
self.may_implement = None
else:
self.cname = opt
if self.cname is None:
self.cname = 'B`\'CLASS::' + self.name
class DataMember(Super, ClassElement):
def __init__(self, args):
self.name = args[0];
self.elements = []
self.terms = {'return':CommArgGen('return')}
def generate(self):
cf.gen.datagen(self.name, self.elements)
class Preset(ClassElement):
def __init__(self, args):
if len(args) > 1:
v = args[1]
else:
v = args[0]
self.name = '%s, %s' % (args[0], v)
def generate(self):
pass
class Bases(ClassElement):
def __init__(self, args):
self.name = args
def generate(self):
pass
class Top(Super):
def __init__(self, file, args):
self.terms = {'class':Classe, 'define':Define, 'include':Include, 'code':ModuleCode, 'function':Function, 'staticmethod':StaticMethod}
self.file = file
self.elements = []
def attach(self, ob):
self.elements.append(ob)
def __repr__(self):
return '<%s: %s>' % (self.__class__.__name__, repr(self.elements))
class Parse:
def __init__(self):
self.nodelist = []
def parseFile(self, file):
fp = open(file, 'r')
stack = [Top(file, [])]
level = 0
while 1:
x = fp.readline()
if not x:
break
for lev in range(len(x)):
if x[lev] != ' ':
break
a = string.split(x)
for i in range(len(a)):
if a[i][:1] == '#':
a = a[:i]
break
if not a:
continue
while lev < level:
del stack[level]
level = level - 1
e = stack[level].parse(file, a)
if not e is None:
stack.append(e)
level = level + 1
self.nodelist.append(stack[0])
def Generate(self):
for node in self.nodelist:
if hasattr(node, 'generate'):
node.generate()
else:
print node.__class__.__name__, 'no generate'
cf.gen.finish()
cf.parse = Parse()
Bethon-0.5.4/gen/sgrules.py 0000644 0000000 0000144 00000062266 07571602135 014450 0 ustar user users # Copyright 1999 by Donn Cave, Seattle, Washington, USA.
# All rights reserved. Permission to copy, modify and distribute this
# material is hereby granted, without fee, provided that the above
# copyright notice appear in all copies.
import string
import sys
from sgcf import cf
from sgvar import Variable
class RuleBase:
makepointer = 0
storage = None
def pretpgen(self):
pass
def __str__(self):
name = getattr(self, 'name', None)
if not name:
name = self.__class__.__name__
return name
# get from/to functions from exported CObject
#
class CTbl:
def __init__(self, name, rule):
self.name = name
self.rule = rule
def require(self, forwhat = None):
if hasattr(cf.gen, 'name') and cf.gen.name == self.name:
# This one is our own module.
return 'cfunctions.'
cf.cfile.bmport(self.name)
tbl = self.name + 'CTbl'
if forwhat:
cf.cfile.abortif('!%s && !isBThing(%s)' % (tbl, forwhat))
cf.cfile.iput('if (!%s)\n' % tbl)
cf.cfile.indent(1)
cf.cfile.iput('%s = (BaseFunctions *) PyCObject_Import("%s", "functions");\n' % (tbl, self.name))
cf.cfile.indent(-1)
cf.cfile.abortif('!' + tbl)
return tbl + '->'
class CImporter(RuleBase):
storage = Variable.CTBL
ctbl = None
pretpok = ['OK']
def pretpgen(self):
if self.pretpok:
cf.cfile.put('// Check for Bxx module, to save an import if parameter is a string or something\n')
del self.pretpok[0]
# Nice m4 macro, instead of writing the vile hacks here
cf.cfile.put('isB()\n')
def p2c(self, inm, onm):
if not self.ctbl:
self.ctbl = CTbl(self.ptype, self)
tbl = self.ctbl.require(inm.ptr())
if onm.ptrcount > 0:
cf.cfile.iput('%s = (%s) %sAsIt(%s);\n' % (onm.ptr(), onm.type, tbl, inm.ptr()))
cf.cfile.abortif('!%s' % onm.ptr())
# cf.cfile.iput('%s = (%s) %sAsIt(%s);\n' % (onm.ptr(), self.vtype, tbl, inm.ptr()))
else:
# AsBFont returns pointer, but .font is value.
cf.cfile.iput('%s = *((%s *) %sAsIt(%s));\n' % (onm.val(), onm.type, tbl, inm.ptr()))
def c2p(self, inm, onm, dim):
if not self.ctbl:
self.ctbl = CTbl(self.ptype, self)
tbl = self.ctbl.require()
internal = inm.storage == inm.HEAP
cf.cfile.iput('%s = %sFromIt(%s, %d);\n' % (onm.ptr(), tbl, inm.ptr(), internal))
cf.cfile.abortif('!%s' % onm.ptr())
class Int32Rules(RuleBase):
target = ('int32',
'long',
'alert_type',
'alignment',
'alpha_function',
'app_verb',
'bitmap_tiling',
'border_style',
'buffer_orientation',
'buffer_layout',
'button_spacing',
'button_width',
'cap_mode',
'color_space',
'color_which',
'color_control_layout',
'data_bits',
'data_rate',
'dev_t',
'drawing_mode',
'file_panel_button',
'file_panel_mode',
'font_direction',
'font_file_format',
'hash_mark_location',
'icon_size',
'join_mode',
'list_view_type',
'menu_bar_border',
'menu_layout',
'orientation',
'parity_mode',
'perform_code',
'sem_id',
'size_t',
'source_alpha',
'ssize_t',
'status_t',
'stop_bits',
'team_id',
'thread_id',
'thumb_style',
'time_t',
'type_code',
'version_kind',
'vertical_alignment',
'window_alignment',
'window_type',
'window_look',
'window_feel'
)
name = 'tplong'
vtype = 'long'
ptype = 'int'
bldval = 'l'
def pck(self, inm):
cf.cfile.iput('PyInt_Check(%s)' % inm.ptr())
def p2c(self, inm, onm):
cf.cfile.abortif('!PyInt_Check(%s)' % inm.ptr())
cf.cfile.iput('%s = PyInt_AsLong(%s);\n' % (onm.val(), inm.ptr()))
def c2p(self, inm, onm, dim):
cf.cfile.iput('%s = PyInt_FromLong(%s);\n' % (onm.ptr(), inm.val()))
cf.cfile.abortif('!%s' % onm.ptr())
class Int16Rules(Int32Rules):
target = ('short', 'int16')
name = 'tpshort'
vtype = 'int16' # Was "int"
ptype = 'int'
bldval = 'i'
class Int8Rules(Int32Rules):
target = ('int8', 'bool')
name = 'tpbyte'
vtype = 'int8'
ptype = 'int'
bldval = 'c'
class Int64Rules(Int32Rules):
target = ('int64', 'bigtime_t', 'off_t')
name = 'tplonglong'
vtype = 'int64'
ptype = 'long'
bldval = 'l'
bldcast = 'long'
def p2c(self, inm, onm):
# Hm, longs probably should be legit for all int types?
cf.cfile.iput('if (PyLong_Check(%s))' % inm.ptr())
cf.cfile.indent(1)
cf.cfile.iput('%s = PyLong_AsLongLong(%s);\n' % (onm.val(), inm.ptr()))
cf.cfile.indent(-1)
cf.cfile.iput('else if (PyInt_Check(%s))\n' % inm.ptr())
cf.cfile.indent(1)
cf.cfile.iput('%s = PyInt_AsLong(%s);\n' % (onm.val(), inm.ptr()))
cf.cfile.indent(-1)
cf.cfile.iput('else\n')
cf.cfile.indent(1)
cf.cfile.iput(cf.cfile.abortexpr + '\n')
cf.cfile.indent(-1)
def c2p(self, inm, onm, dim):
cf.cfile.iput('%s = PyLong_FromLongLong(%s);\n' % (onm.ptr(), inm.val()))
cf.cfile.abortif('!%s' % onm.ptr())
class UInt8Rules(Int8Rules):
target = ('uint8',)
name = 'tpuint8'
vtype = 'uint8'
ptype = 'int'
bldval = 'b'
class UInt16Rules(Int16Rules):
target = ('uint16',)
name = 'tpuint16'
vtype = 'uint16'
ptype = 'int'
bldval = 'h'
class UInt32Rules(Int32Rules):
target = ('uint32','uid_t','gid_t', 'mode_t')
name = 'tpulong'
vtype = 'unsigned long'
ptype = 'int'
bldval = 'l'
def p2c(self, inm, onm):
cf.cfile.iput('if (PyInt_Check(%s))\n' % inm.ptr())
cf.cfile.indent(1)
cf.cfile.iput('%s = PyInt_AsLong(%s);\n' % (onm.val(), inm.ptr()))
cf.cfile.indent(-1)
cf.cfile.iput('else if (PyLong_Check(%s))\n' % inm.ptr())
cf.cfile.indent(1)
cf.cfile.iput('%s = PyLong_AsLong(%s);\n' % (onm.val(), inm.ptr()))
cf.cfile.indent(-1)
cf.cfile.iput('else\n')
cf.cfile.indent(1)
cf.cfile.iput('return 0;\n')
cf.cfile.indent(-1)
def c2p(self, inm, onm, dim):
# PyLong because it's the only Unsigned conversion I know of.
cf.cfile.iput('%s = PyLong_FromUnsignedLong(%s);\n' % (onm.ptr(), inm.val()))
cf.cfile.abortif('!%s' % onm.ptr())
class DoubleRules(RuleBase):
target = ('double',)
name = 'tpfloat'
vtype = 'double'
ptype = 'float'
bldval = 'd'
def pck(self, inm):
cf.cfile.iput('PyFloat_Check(%s)' % inm.ptr())
def p2c(self, inm, onm):
cf.cfile.abortif('!PyFloat_Check(%s)' % inm.ptr())
cf.cfile.iput('%s = PyFloat_AsDouble(%s);\n' % (onm.val(), inm.ptr()))
def c2p(self, inm, onm, dim):
cf.cfile.iput('%s = PyFloat_FromDouble(%s);\n' % (onm.ptr(), inm.val()))
cf.cfile.abortif('!%s' % onm.ptr())
class FloatRules(DoubleRules):
target = ('float',)
name = 'tpfloat'
vtype = 'float'
ptype = 'float'
bldval = 'f'
bldcast = 'double'
def pck(self, inm):
cf.cfile.iput('PyFloat_Check(%s)' % inm.ptr())
def p2c(self, inm, onm):
cf.cfile.abortif('!PyFloat_Check(%s)' % inm.ptr())
cf.cfile.iput('%s = PyFloat_AsDouble(%s);\n' % (onm.val(), inm.ptr()))
def c2p(self, inm, onm, dim):
cf.cfile.iput('%s = PyFloat_FromDouble(%s);\n' % (onm.ptr(), inm.val()))
cf.cfile.abortif('!%s' % onm.ptr())
class IFloatRules(FloatRules):
target = ('ifloat',)
name = 'tpifloat'
ptype = 'ifloat'
def pck(self, inm):
cf.cfile.iput('PyNumber_Check(%s)' % inm.ptr())
def p2c(self, inm, onm):
cf.cfile.abortif('!PyNumber_Check(%s)' % inm.ptr())
cf.cfile.iput('%s = PyFloat_AsDouble(%s);\n' % (onm.val(), inm.ptr()))
class CharPtrRules(RuleBase):
target = ('char','void', 'font_family', 'font_style')
name = 'tpcharptr'
vtype = 'char*'
ptype = 'string'
bldval = 's'
def pck(self, inm):
cf.cfile.iput('PyString_Check(%s)' % inm.ptr())
def p2c(self, inm, onm):
cf.cfile.iput('%s = PyString_AsString(%s);\n' % (onm.ptr(), inm.ptr()))
cf.cfile.abortif('!%s' % onm.ptr())
cf.cfile.iput('// hack alert:\n')
cf.cfile.iput('if (p->size == 1) {\n')
cf.cfile.iput('\t*((char *) p->var) = *%s;\n' % onm.ptr())
cf.cfile.iput('\treturn 1;\n')
cf.cfile.iput('}\n')
def c2p(self, inm, onm, dim):
if dim:
cf.cfile.iput('%s = PyString_FromStringAndSize((char *) %s, %s);\n' % (onm.ptr(), inm.ptr(), dim))
else:
cf.cfile.iput('%s = PyString_FromString(%s);\n' % (onm.ptr(), inm.ptr()))
cf.cfile.abortif('!%s' % onm.ptr())
class NullRules(RuleBase):
target = ('None',)
name = 'tpnull'
vtype = 'None'
ptype = 'None'
structdef = 'typedef void *None;'
bldval = 's'
literal_representation = '0'
def pck(self, inm):
cf.cfile.iput('%s == Py_None' % inm.ptr())
def p2c(self, inm, onm):
cf.cfile.abortif('%s != Py_None' % inm.ptr())
cf.cfile.iput('%s = 0;\n' % onm.val())
def c2p(self, inm, onm, dim):
cf.cfile.iput('%s = Py_None;\n' % (onm.ptr(),))
class patternRules(CharPtrRules):
target = ('pattern',)
name = 'tppattern'
vtype = 'pattern'
ptype = 'string'
fixedlength = 8
def pck(self, inm):
cf.cfile.iput('PyString_Check(%s) && PyString_Size(%s) == %d' % (inm.ptr(), inm.ptr(), self.fixedlength))
def p2c(self, inm, onm):
cf.cfile.abortif('PyString_Size(%s) != %d' % (inm.ptr(), self.fixedlength))
cf.cfile.iput('memcpy(%s.data, PyString_AsString(%s), %d);\n' % (onm.val(), inm.ptr(), self.fixedlength))
def c2p(self, inm, onm, dim):
cf.cfile.iput('%s = PyString_FromStringAndSize((char *) %s.data, %s);\n' % (onm.ptr(), inm.val(), self.fixedlength))
cf.cfile.abortif('!%s' % onm.ptr())
class fixed8Rules(CharPtrRules):
target = ()
name = 'tpfixed8'
vtype = 'char*'
ptype = 'string'
fixedlength = 8
bldval = None
def pck(self, inm):
cf.cfile.iput('PyString_Check(%s) && PyString_Size(%s) == %d' % (inm.ptr(), inm.ptr(), self.fixedlength))
def p2c(self, inm, onm):
cf.cfile.abortif('PyString_Size(%s) != %d' % (inm.ptr(), self.fixedlength))
cf.cfile.iput('memcpy(%s, PyString_AsString(%s), %d);\n' % (onm.ptr(), inm.ptr(), self.fixedlength))
def c2p(self, inm, onm, dim):
cf.cfile.iput('%s = PyString_FromStringAndSize((char *) %s, %s);\n' % (onm.ptr(), inm.ptr(), self.fixedlength))
cf.cfile.abortif('!%s' % onm.ptr())
class char8Rules(CharPtrRules):
target = ()
name = 'tpchar8'
vtype = 'char*'
ptype = 'string'
fixedlength = 8
bldval = None
def p2c(self, inm, onm):
cf.cfile.iput('strncpy(%s, PyString_AsString(%s), %d);\n' % (onm.ptr(), inm.ptr(), self.fixedlength))
def c2p(self, inm, onm, dim):
cf.cfile.iput('{int clen = strlen(%s);\n' % inm.ptr())
cf.cfile.iput(' if (clen >= %s)\n' % self.fixedlength)
cf.cfile.iput(' clen = %s;\n' % (self.fixedlength - 1,))
cf.cfile.iput('%s = PyString_FromStringAndSize((char *) %s, clen);\n' % (onm.ptr(), inm.ptr()))
cf.cfile.iput('}\n')
cf.cfile.abortif('!%s' % onm.ptr())
class char64Rules(char8Rules):
name = 'tpchar64'
fixedlength = 64
class char256Rules(char8Rules):
name = 'tpchar256'
fixedlength = 256
class StringRules(RuleBase):
target = ('pstring',)
name = 'tpstring'
vtype = 'struct StringDx'
structdef = 'typedef struct StringDx {\n\tchar *ptr;\n\tint len;\n} pstring;'
ptype = 'string'
bldval = '#s'
def pck(self, inm):
cf.cfile.iput('PyString_Check(%s)' % inm.ptr())
def p2c(self, inm, onm):
cf.cfile.iput('%s.ptr = PyString_AsString(%s);\n' % (onm.val(), inm.ptr()))
cf.cfile.abortif('!%s' % onm.ptr())
cf.cfile.iput('%s.len = PyString_Size(%s);\n' % (onm.val(), inm.ptr()))
def c2p(self, inm, onm, dim):
cf.cfile.iput('%s to %s kind of a surprise.\n' % (inm.ptr(), onm.ptr()))
class SeqRules(RuleBase):
target = ()
storage = Variable.HEAP
def c2p(self, inm, onm, dim):
cf.cfile.iput('%s = Py%s_New(%s);\n' % (onm.ptr(), self.seqtype, dim.val()))
cf.cfile.abortif('!%s' % onm.ptr())
cf.cfile.iput('int i;\n')
cf.cfile.iput('for (i = 0; i < %s; ++i) {\n' % dim.val())
cf.cfile.indent(1)
ps = Variable('PyObject*', 'pelem')
cf.cfile.iput('PyObject *pelem;\n')
vs = Variable(self.vetype, 'celem')
vs.classify(self.elementrule)
# Why inm.val()?
cf.cfile.iput('%s celem = %s[i];\n' % (self.vetype, inm.val()))
vs.c2p(ps)
cf.cfile.iput('Py%s_SetItem(%s, i, %s);\n' % (self.seqtype, onm.ptr(), ps.ptr()))
cf.cfile.indent(-1)
cf.cfile.iput('}\n')
def p2c(self, inm, onm):
cf.cfile.iput('int i;\n')
cf.cfile.iput('int n = Py%s_Size(%s);\n' % (self.seqtype, inm.ptr()))
cf.cfile.iput('%s.ptr = (%s) malloc(%s);\n' % (onm.val(), self.vatype, self.allocsize('n')))
cf.cfile.abortif('!%s.ptr' % onm.val())
cf.cfile.iput('%s.len = n;\n' % onm.val())
cf.cfile.iput('for (i = 0; i < n; ++i) {\n')
cf.cfile.indent(1)
ps = Variable('PyObject*', 'pelem')
cf.cfile.iput('PyObject *pelem;\n')
vs = Variable(self.vetype, 'celem')
vs.classify(self.elementrule)
cf.cfile.iput('pelem = Py%s_GetItem(%s, i);\n' % (self.seqtype, inm.ptr()))
cf.cfile.iput('%s celem;\n' % self.vetype)
vs.p2c(ps)
# XX Too easy, won't be good for fancy structs.
cf.cfile.iput('%s.ptr[i] = celem;\n' % onm.val())
cf.cfile.indent(-1)
cf.cfile.iput('}\n')
self.lastelem(onm, 'i')
def lastelem(self, onm, e):
pass
class ArgvpRules(SeqRules):
target = ('argvp',)
seqtype = 'Sequence'
vtype = 'struct ArgvDx'
name = 'tpargv'
ptype = 'list'
vatype = 'char**'
vetype = 'char*'
elementrule = CharPtrRules()
def allocsize(self, count):
# return 'sizeof(%s) * %s + sizeof(struct ArgvDx)' % (self.vetype, count)
return 'sizeof(%s) * (%s + 1)' % (self.vetype, count)
def pretpgen(self):
cf.cfile.iput('typedef struct ArgvDx {\n\tint len;\n\tchar **ptr;\n} argvp;\n')
def csize(self, inm, onm):
cf.cfile.iput('for (%s = 0; %s[%s]; ++%s)\n' % (onm.val(), inm.ptr(), onm.val(), onm.val()))
cf.cfile.iput(' ;\n')
def lastelem(self, onm, e):
cf.cfile.iput('%s.ptr[%s] = 0;\n' % (onm.val(), e))
class ArgvcRules(SeqRules):
target = ('argvc',)
seqtype = 'Tuple'
vtype = 'char**'
ptype = 'tuple'
name = 'tpargvc'
vatype = 'char**'
vetype = 'char*'
elementrule = CharPtrRules()
def allocsize(self, count):
return 'blah'
class NVar:
def __init__(self, expr):
self.ptr_ = expr
self.val_ = expr
def ptr(self):
return self.ptr_
def val(self):
return self.val_
# Structs like stat, attr_info, etc. that don't warrant their own
# C implementation.
#
class TupleBase(RuleBase):
# Tuple base expects:
# target: (type as in module description file, ...)
# name: for p2c conversion function.
# vtype: for declarations
# ptype: for Python users
# members = ((struct member, rule instance), ...)
ptype = 'tuple'
makepointer = 1
bldval = None
def p2c(self, inm, onm):
cf.cfile.iput('if (PyTuple_Check(%s) && PyTuple_Size(%s) == %d) {\n' % (inm.ptr(), inm.ptr(), len(self.members)))
cf.cfile.indent(1)
i = 0
for m, r in self.members:
cf.cfile.iput('PyObject *p%s = PyTuple_GetItem(%s, %d);\n' % (m, inm.ptr(), i))
i = i + 1
pv = NVar('p' + m)
if onm.ptrcount:
mve = '%s->' % onm.ptr()
else:
mve = '%s.' % onm.val()
mv = Variable(r.vtype, '%s%s' % (mve, m))
r.p2c(pv, mv)
cf.cfile.indent(-1)
cf.cfile.iput('} else\n')
cf.cfile.indent(1)
cf.cfile.iput(cf.cfile.abortexpr + '\n')
cf.cfile.indent(-1)
def c2p(self, inm, onm, dim):
bldval = ''
mv = []
pmx = 1
for m, r in self.members:
if inm.ptrcount > 0:
inmprefix = '%s->' % inm.ptr()
else:
inmprefix = '%s.' % inm.val()
nm = '%s%s' % (inmprefix, m)
if r.bldval is None:
b = 'O'
cm = Variable(r.vtype, nm)
cm.classify(r)
pmn = 'PM%d' % pmx
cf.cfile.iput('PyObject *%s;\n' % pmn)
pm = Variable('PyObject*', pmn)
pmx = pmx + 1
cm.c2p(pm)
else:
b = r.bldval
bldval = bldval + b
#
# Casting: avoid passing int16 to a stdarg(...)
# function that expects int32 - or whatever.
# This is tricky, and naturally I will resort
# to hackery.
#
if b == 'O':
mv.append(pmn)
# Should this be DECREF'd, after bldvalue?
elif hasattr(r, 'bldcast'):
mv.append('(%s) %s%s' % (r.bldcast, inmprefix, m))
else:
mv.append('%s%s' % (inmprefix, m))
cf.cfile.iput('%s = Py_BuildValue("%s", %s);\n' % (onm.ptr(), bldval, string.join(mv, ', ')))
cf.cfile.abortif('!%s' % onm.ptr())
def classgen(self, fp):
# Generate class to name tuple items.
# Drop leading "struct", if any.
name = string.split(self.vtype)[-1]
fp.write('class %s(Structuple):\n' % name)
ml = []
tl = []
for m, t in self.members:
if hasattr(t, 'classgen'):
t = string.split(t.vtype)[-1]
else:
t = 'None'
tl.append(t)
ml.append('\'%s\'' % m)
fp.write('\t_members = (%s)\n' % string.join(ml, ', '))
fp.write('\tdef typegen(self):\n')
fp.write('\t\treturn (%s)\n' % string.join(tl, ', '))
fp.write('\n')
# Tuples representing serious classes whose constructors and destructors
# need to be involved in things.
#
class CTorTuple(TupleBase):
def p2c(self, inm, onm):
mvlist = []
for m, r in self.members:
cf.cfile.iput('%s %s;\n' % (r.vtype, m))
mvlist.append(m);
cf.cfile.abortif('!PyTuple_Check(%s) || !PyTuple_Size(%s) == %d' % (inm.ptr(), inm.ptr(), len(self.members)))
i = 0
for m, r in self.members:
cf.cfile.iput('PyObject *p%s = PyTuple_GetItem(%s, %d);\n' % (m, inm.ptr(), i))
i = i + 1
pv = NVar('p' + m)
mv = NVar(m)
r.p2c(pv, mv)
# XXX more fixes needed in generator to avoid extra copies.
# memcpy() hack turned out to be unhealthful, as auto vbls
# destructors released storage they didn't allocate --
# entry_ref.name for example.
cf.cfile.iput('%s psud(%s);\n' % (self.vtype, string.join(mvlist, ', ')))
cf.cfile.iput('%s = psud;\n' % onm.val());
# cf.cfile.indent(-1)
class noderefRules(TupleBase):
target = ('node_ref',)
name = 'tpnode_ref'
vtype = 'node_ref'
members = (('device', Int32Rules()), ('node', Int64Rules()))
class attrinfoRules(TupleBase):
target = ('struct attr_info',)
name = 'tpattr_info'
vtype = 'struct attr_info'
members = (('type', UInt32Rules()), ('size', Int64Rules()))
class BPointRules(TupleBase):
target = ('BPoint',)
name = 'tpBPoint'
vtype = 'BPoint'
members = (('x', IFloatRules()), ('y', IFloatRules()))
class entryrefRules(CTorTuple):
target = ('entry_ref',)
name = 'tpentry_ref'
vtype = 'entry_ref'
bldval = None
members = (('device', Int32Rules()), ('directory', Int64Rules()), ('name', CharPtrRules()))
class appinfoRules(CTorTuple):
target = ('app_info',)
name = 'tpapp_info'
vtype = 'app_info'
members = (('thread', Int32Rules()), ('team', Int32Rules()), ('port', Int32Rules()), ('flags', UInt32Rules()), ('ref', entryrefRules()), ('signature', CharPtrRules()))
class BRectRules(TupleBase):
target = ('BRect',)
name = 'tpBRect'
vtype = 'BRect'
f = IFloatRules()
members = (('left', f), ('top', f), ('right', f), ('bottom', f))
class statRules(TupleBase):
target = ('struct stat',)
name = 'tpstat'
vtype = 'struct stat'
l = Int32Rules()
L = Int64Rules()
# Add crtime to end of posix.stat order; omit blksize.
# crtime sounds interesting and likely to be recognized in this
# position; blksize may be useful, but not obvious where.
members = (('st_mode', l), ('st_ino', L), ('st_dev', l),
('st_nlink', l), ('st_uid', l), ('st_gid', l), ('st_size', L),
('st_atime', l), ('st_mtime', l), ('st_ctime', l),
('st_crtime', l))
class rgbcolorRules(TupleBase):
target = ('rgb_color',)
name = 'tprgb_color'
vtype = 'rgb_color'
u = UInt8Rules()
members = (('red', u), ('green', u), ('blue', u), ('alpha', u))
class scrollbarinfoRules(TupleBase):
target = ('scroll_bar_info',)
name = 'tpscroll_bar_info'
vtype = 'scroll_bar_info'
b = Int8Rules()
l = Int32Rules()
members = (('proportional', b), ('double_arrows', b), ('knob', l), ('min_knob_size', l))
class fontheightRules(TupleBase):
target = ('font_height',)
name = 'tpfont_height'
vtype = 'font_height'
f = FloatRules()
members = (('ascent', f), ('descent', f), ('leading', f))
class escapementdeltaRules(TupleBase):
target = ('escapement_delta',)
name = 'tpescapement_delta'
vtype = 'escapement_delta'
f = FloatRules()
members = (('nonspace', f), ('space', f))
class fontcacheinfoRules(TupleBase):
target = ('font_cache_info',)
name = 'tpfont_cache_info'
vtype = 'font_cache_info'
f = FloatRules()
i = Int32Rules()
members = (('sheared_font_penalty', i), ('rotated_font_penalty', i), ('oversize_threshold', f), ('oversize_penalty', i), ('cache_size', i), ('spacing_size_threshold', f))
class tunedfontinfoRules(TupleBase):
target = ('tuned_font_info',)
name = 'tptuned_font_info'
vtype = 'tuned_font_info'
f = FloatRules()
i = UInt32Rules()
members = (('size', f), ('shear', f), ('rotation', f), ('flags', i), ('face', i))
# class keyinfoRules(TupleBase):
# target = ('key_info',)
# name = 'tpkey_info'
# vtype = 'key_info'
# members = (('modifiers', UInt32Rules()), ('key_states', fixed16Rules()))
class screenidRules(TupleBase):
target = ('screen_id',)
name = 'tpscreen_id'
vtype = 'screen_id'
members = (('id', UInt32Rules()),)
class versioninfoRules(TupleBase):
target = ('version_info',)
name = 'tpversion_info'
vtype = 'version_info'
i = UInt32Rules()
members = (('major', i), ('middle', i), ('minor', i), ('variety', i), ('internal', i), ('short_info', char64Rules()), ('long_info', char256Rules()))
class textrunRules(TupleBase):
target = ('text_run',)
name = 'tptext_run'
vtype = 'text_run'
fr = CImporter()
fr.target = ('vBFont',)
fr.name = 'tpvBFont'
fr.vtype = 'BFont'
fr.ptype = 'BFont'
fr.bldval = None
members = (('offset', Int32Rules()), ('font', fr), ('color', rgbcolorRules()))
class textrunarrayRules(RuleBase):
target = ('text_run_array',)
name = 'tptext_run_array'
vtype = 'text_run_array*'
ptype = 'list'
storage = Variable.HEAP
def p2c(self, inm, onm):
cf.cfile.abortif('!PyList_Check(%s)' % inm.ptr())
cf.cfile.iput('else {\n')
cf.cfile.indent(1)
cf.cfile.iput('int n = PyList_Size(%s);\n' % inm.ptr())
# OK if n == 0, right?
cf.cfile.iput('%s = (text_run_array *) malloc(sizeof(text_run) * n + 4);\n' % (onm.ptr(),))
cf.cfile.abortif('!%s' % onm.ptr())
cf.cfile.iput('(%s)->count = n;\n' % onm.ptr())
cf.cfile.iput('int i;\n')
cf.cfile.iput('for (i = 0; i < n; ++i) {\n')
cf.cfile.indent(1)
saveabort = cf.cfile.abortexpr
cf.cfile.abortexpr = 'goto fail;\n'
cf.cfile.iput('PyObject *ptextrun = PyList_GetItem(%s, i);\n' % inm.ptr())
# pt = NVar('ptextrun')
pt = Variable('PyObject*', 'ptextrun')
cf.cfile.iput('text_run *textrun = &(%s)->runs[i];\n' % onm.ptr())
ct = Variable('text_run*', 'textrun')
ct.classify(textrunRules(), 1)
ct.p2c(pt)
cf.cfile.abortexpr = saveabort
cf.cfile.indent(-1)
cf.cfile.iput('}\n')
cf.cfile.indent(-1)
cf.cfile.iput('}\n')
cf.cfile.iput('goto nofail;\n')
cf.cfile.put('fail:\n')
cf.cfile.iput('free(%s);\n' % inm.ptr())
cf.cfile.iput(cf.cfile.abortexpr)
cf.cfile.put('nofail:\n')
def c2p(self, inm, onm, dim):
# "dim" is actually the size in bytes!
cf.cfile.iput('int i;\n')
cf.cfile.iput('%s = PyTuple_New(%s->count);\n' % (onm.ptr(), inm.ptr()))
cf.cfile.iput('for (i = 0; i < %s->count; ++i) {\n' % inm.ptr())
cf.cfile.indent(1)
cf.cfile.iput('text_run *textrun = &%s->runs[i];\n' % inm.ptr())
ct = Variable('text_run*', 'textrun')
ct.classify(textrunRules, 1)
cf.cfile.iput('PyObject *ptextrun;\n')
pt = Variable('PyObject*', 'ptextrun')
ct.c2p(pt)
cf.cfile.iput('PyTuple_SetItem(%s, i, %s);\n' % (onm.ptr(), pt.ptr()))
cf.cfile.indent(-1)
cf.cfile.iput('}\n')
cf.cfile.iput('free(%s);\n' % inm.ptr())
# To do:
#
# typedef struct color_map {
# int32 id;
# rgb_color color_list[256];
# uint8 inversion_map[256];
# uint8 index_map[32768];
# } color_map;
#
# (why?)
# struct key_info {
# uint32 modifiers;
# uint8 key_states[16];
# }
#
# struct menu_info {
# float font_size;
# font_family f_family;
# font_style f_style;
# rgb_color background_color;
# int32 separator;
# bool click_to_open;
# bool triggers_always_shown;
# };
class ListBase(RuleBase):
# List base expects:
# target: blist_team_id, for example.
# itemtype: team_id
vtype = 'BList'
def declare(self, inm):
# cf.cfile.iput('BList *%s = new BList();\n' % inm.name)
return ['BList *%s = new BList()' % inm.name]
def p2c(self, inm, onm):
cf.cfile.iput('yikes, don\'t know how to make C BList.\n')
def c2p(self, inm, onm, dim):
import sggen
bldval = ''
mv = []
pmx = 1
cf.cfile.iput('int count = %s->CountItems();\n' % inm.ptr())
cf.cfile.iput('%s = PyList_New(count);\n' % onm.ptr())
cf.cfile.abortif('!%s' % onm.ptr())
cf.cfile.iput('int i;\n')
cf.cfile.iput('for (i = 0; i < count; ++i) {\n')
cf.cfile.indent(1)
cm = Variable(self.itemtype, 'item')
cm.classify()
cf.cfile.iput('%s item;\n' % self.itemtype)
pm = Variable('PyObject *', 'pytem')
cf.cfile.iput('PyObject *pytem;\n')
cf.cfile.iput('item = (%s)%s->ItemAt(i);\n' % (self.itemtype, inm.ptr()))
cm.c2p(pm)
cf.cfile.iput('PyList_SetItem(%s, i, pytem);\n' % onm.ptr())
cf.cfile.indent(-1)
cf.cfile.iput('}\n')
class TeamIDListRules(ListBase):
target = ('blist_team_id',)
itemtype = 'team_id'
ptype = 'list'
name = 'tpteamidlist'
class BMessageListRules(ListBase):
target = ('blist_BMessage',)
itemtype = 'BMessage*'
ptype = 'list'
name = 'tpbmessagelist'
class RuleSet:
def __init__(self):
self.dict = {}
def add(self, rule, name):
self.dict[name] = rule
def query(self, name):
t = self.dict.get(name)
if t:
return t
if name[:1] == 'B':
c = CImporter()
c.target = name
c.name = 'tp' + name
c.vtype = name + '*'
c.ptype = name
self.dict[name] = c
return c
raise KeyError, name
def Ruleset():
cf.rules = RuleSet()
for ck, cv in globals().items():
if ck[-5:] == 'Rules':
ob = cv()
for t in cv.target:
cf.rules.add(ob, t)
if __name__ == '__main__':
fp = sys.stdout
fp.write('# automatically generated by sgrules.py\n\n')
fp.write('from structuple import Structuple\n\n')
for ck, cv in globals().items():
if ck[-5:] == 'Rules' and hasattr(cv, 'classgen'):
ob = cv()
ob.classgen(fp)
else:
Ruleset()
Bethon-0.5.4/gen/sgvar.py 0000644 0000000 0000144 00000032533 07571601277 014106 0 ustar user users # Copyright 2001 by Donn Cave, Seattle, Washington, USA.
# All rights reserved. Permission to copy, modify and distribute this
# material is hereby granted, without fee, provided that the above
# copyright notice appear in all copies.
#
# Analysis of variables, parameters, types.
from sgcf import cf
import re
class UnsupportedError(Exception):
pass
#
# C types used in the present module.
#
class Types:
cache = {}
def __init__(self, rule):
self.rule = rule
self.name = rule.name
Types.cache[self.name] = self
self.have_p2c = 0
self.have_c2p = 0
def setup_p2c(self, full):
#
# Generate a function to extract a variable of this type
# from its Python analogue.
#
if self.have_p2c:
return
if not full:
# For function returns, which don't need the
# InputParam stuff.
xf = cf.files.xfuns
oldfile = cf.cfile.setfile(xf)
self.rule.pretpgen()
cf.cfile.setfile(oldfile)
return
self.have_p2c = 1
xf = cf.files.xfuns
oldfile = cf.cfile.setfile(xf)
self.rule.pretpgen()
# xf.iput('static const char %s_rep[] = "%s";\n' % (self.name, self.rule.ptype))
xf.iput('static int\n')
xf.iput('%s_p2c(struct InputParam *p, PyObject *a)\n' % self.name)
xf.iput('{\n')
xf.indent(1)
xf.iput('%s spud;\n' % self.rule.vtype)
v = Variable(self.rule.vtype, 'spud')
p = Variable('PyObject*', 'a')
self.rule.p2c(p, v)
if self.rule.makepointer:
xf.iput('**((%s **) p->var) = spud;\n' % self.rule.vtype)
else:
xf.iput('*((%s *) p->var) = spud;\n' % self.rule.vtype)
xf.iput('return 1;\n')
xf.indent(-1)
xf.iput('}\n')
cf.cfile.setfile(oldfile)
#
# Static, module scoped variables used for default values.
#
class ModuleStatics:
def __init__(self):
self.col = {}
self.ind = 0
def mkvalue(self, type, val):
#
# Check for already existing variable with required
# type and value.
#
fval = '(%s) %s' % (type, val)
var = self.col.get(fval)
if not var:
xf = cf.files.xfuns
var = Variable(type, 'defVar%d' % self.ind)
self.col[fval] = var
self.ind = self.ind + 1
xf.put('\n')
decl = var.declare()
xf.iput('static %s = %s;\n\n' % (
decl[0], fval))
var.value = val
return var
class Expression:
AUTO = 'auto'
CTBL = 'ctbl'
HEAP = 'heap'
EXPR = 'expr'
class Literal(Expression):
def __init__(self, value):
self.value = value
self.storage = self.EXPR
def val(self):
return self.value
def __str__(self):
return self.value
def __repr__(self):
return '<%s %s>' % (self.__class__.__name__, repr(self.value))
class Variable(Expression):
def __init__(self, typedesc, name = None):
self.type = typedesc
if name:
self.name = name
self.ptrcount = 0
while typedesc[-1:] == '*':
self.ptrcount = self.ptrcount + 1
typedesc = typedesc[:-1]
s = typedesc.split(None, 1)
if s[0] == 'const':
self.const = 1
typedesc = s[1]
else:
self.const = 0
self.basetype = typedesc
self.storage = self.AUTO
self.auxptr = 0
self.dim = None
self.fromctbl = 0
def allocate(self, xf, dim):
if self.fromctbl:
self.storage = self.HEAP
xf.iput('%s = new %s();\n' % (self.name, self.basetype))
return [self.name]
elif dim:
self.storage = self.HEAP
xf. iput('%s = (%s) malloc(%s);\n' % (self.name, self.type, dim))
return [self.name]
else:
return []
def ampersand(self):
if not self.dim and not self.ptrcount and self.rule.storage == self.CTBL:
# A BEntry, for example, initialized by the
# C++ API function and to be returned as a
# Python object. So this is a case of heap
# storage where the Python API function is
# not to free the object but rather return it.
# .dx notation will be &BEntry%...
# BMessenger is conventionally passed by value,
# so it won't get here.
#
self.fromctbl = 1
self.type = self.type + '*'
self.ptrcount = self.ptrcount + 1
if self.rule.storage == self.HEAP:
# Caller must allocate this one dynamically, for
# whatever reason - probably because size is known
# at run time - and the .dx notation isn't the right
# place to decide that the variable should therefore
# be a pointer.
if not self.ptrcount:
self.type = self.type + '*'
self.ptrcount = self.ptrcount + 1
self.storage = self.HEAP
def c2p(self, p, dim = None):
self.typo.rule.c2p(self, p, dim)
def classify(self, rule = None, ptrcount = None):
#
# Locate the appropriate rules for this type.
# rule and ptrcount parameters are used with
# internally generated variables, where the
# rule is already known.
#
if rule:
self.rule = rule
else:
try:
self.rule = cf.rules.query(self.basetype)
except KeyError:
print repr(self), repr(self.basetype)
raise UnsupportedError(self.basetype)
self.typo = Types.cache.get(self.rule.name)
if not self.typo:
self.typo = Types(self.rule)
if self.rule.makepointer and ptrcount is None:
# May take value of (its_type *) 0, so for
# convenience, might as well create an auxiliary
# pointer variable for it.
self.auxptr = 1
# And if it was specified like "entry_ref*",
# reduce the pointer - this variable is to be
# declared "entry_ref", and that was just a
# notational convenience.
# The ptrcount parameter allows the caller
# to override this whole gimmick because
# some internal variables will in fact be
# pointers.
if self.ptrcount:
self.ptrcount = self.ptrcount - 1
self.type = self.basetype
def free(self, xf):
if self.fromctbl:
xf.iput('// from CTbl - do not free(%s);\n' % self.name);
# (xxx -- is second condition necessary?)
elif self.storage == self.HEAP and not hasattr(self.dim, 'value'):
xf.iput('free(%s);\n' % self.name)
def declare(self):
# Return a declaration for the variable - and also
# for its auxiliary if any. Hence a list, not a
# string.
#
# Most variables will already have a type classification
# (default variables won't), and one or two of the rules
# has its own declare function, like BList.
#
if hasattr(self, 'typo') and hasattr(self.typo.rule, 'declare'):
return self.typo.rule.declare(self)
if self.dim:
dim = self.dim
if self.storage == self.AUTO:
if hasattr(dim, 'pos'):
dim = dim.var
dim = '[%s]' % dim
else:
dim = self.dim
else:
dim = ''
me = '%s %s%s' % (self.type, self.name, dim)
if self.auxptr:
aux = '%s *%s = &%s' % (self.type, 'p' + self.name, self.name)
return [me, aux]
else:
return [me]
def p2c(self, p):
self.typo.rule.p2c(p, self)
def passout(self, typedesc, pref, ref, field):
#
# Return this variable as it would appear as a
# function argument, given the passing semantics
# supplied by the caller (presumably a Parameter.)
#
if ref == 'dup':
return '(%s ? new %s(*%s) : 0)' % (self.name,
self.basetype, self.name)
elif hasattr(self.typo.rule, 'literal_representation'):
return self.typo.rule.literal_representation
elif self.fromctbl:
return self.name
elif self.auxptr and not pref and typedesc[-1:] == '*':
# Would not hurt to have a pointer count in
# the parameter caller, where the logic would
# be "if param.ptrcount == self.ptrcount + 1"
return 'p' + self.name
else:
name = self.name
if field:
if self.ptrcount:
name = '%s->%s' % (name, field)
else:
name = '%s.%s' % (name, field)
return pref + name
def ptr(self):
if self.ptrcount or self.dim:
return self.name
else:
return '&' + self.name
def rwptr(self):
#
# Object for argument table, to be written by
# Python to C converter. Caller will supply
# ampersand. The auxiliary pointer allows an
# an object to get a null (pointer) value.
#
if self.auxptr:
return 'p' + self.name
else:
return self.name
def setup_p2c(self, full):
self.typo.setup_p2c(full)
def val(self):
if self.ptrcount:
return '*' + self.name
else:
return self.name
def __repr__(self):
name = getattr(self, 'name', None)
cl = self.__class__.__name__
r = '%s %s' % (self.type, name)
return '<%s %s>' % (cl, repr(r))
def __str__(self):
x = getattr(self, 'name')
if x is None:
x = '(no name yet)'
return x
#
# Parameters are references to a variable, in a function argument list
# but also returns, etc. Parameters have type and position, and some
# other attributes as required. A parameter will eventually be attached
# to a variable, and represents an application of that variable.
#
class Parameter:
def __init__(self, type, passpref, pos, field, init, dim, ref):
self.type = type
self.passpref = passpref
try:
self.pos = int(pos)
except ValueError:
raise UnsupportedError, '(parameter name %s)' % (pos,)
self.field = field
if init:
self.makeinitval(init)
else:
self.initval = None
self.dim = dim
self.refsem = ref
def allocate(self, xf):
if hasattr(self.dim, 'var'):
return self.var.allocate(xf, self.dim.var)
else:
return self.var.allocate(xf, self.dim)
def c2p(self, p):
#
# Convert variable to a Python object.
# Parameter dimension here would be the result length
# of a buffer string, for example, as returned by
# a C++ function like File::Read().
#
if hasattr(self.dim, 'var'):
dim = self.dim.var
else:
dim = self.dim
return self.var.c2p(p, dim)
def classify(self, var):
var.classify()
if self.passpref == '&':
var.ampersand()
return var
def makeinitval(self, val):
self.initval = Literal(val)
def initptr(self):
if self.initval:
return '&' + self.initval.name
else:
return '0'
def passout(self):
return self.var.passout(self.type, self.passpref, self.refsem, self.field)
def refsemantics(self):
return self.refsem
def setrefsemantics(self, name):
self.refsem = name
def setup_p2c(self):
self.var.setup_p2c(0)
def __repr__(self):
var = getattr(self, 'var', None)
vr = '(%s)' % repr(var)
return '<%s %s@%s %s>' % (self.__class__.__name__, self.type, self.pos, vr)
#
# Input is a special case of Parameter, an argument to the Python
# API function.
#
class Input(Parameter):
statics = ModuleStatics()
def makeinitval(self, val):
dtype = self.type
if self.passpref == '&':
dtype = dtype + '*'
self.initval = self.statics.mkvalue(dtype, val)
def setup_p2c(self):
self.var.setup_p2c(1)
#
# Parameters required for a Python API function and its one or more
# C++ API overload functions.
#
class ParamTable:
def __init__(self):
self.tbl = []
def dump(self):
pl = []
for pt in self.tbl:
for v in pt.values():
pl.append(v)
return pl
def index(self, type, pos):
try:
return self.tbl[pos][type]
except (IndexError, KeyError):
return None
def set(self, type, pos, val):
while pos >= len(self.tbl):
self.tbl.append({})
self.tbl[pos][type] = val
#
# Positional parameter parser for a single function overload.
#
class ParamParser:
psep = re.compile('[@%=]')
def __init__(self):
self.plist = []
def parse(self, desc, table = None, vprefix = None):
param, vp = self.parsedx(desc)
self.resolve(param, vp, table, vprefix)
return param
#
# Parse a .dx parameter specification.
# Result is two variables, a parameter and its variable.
#
def parsedx(self, desc):
s = self.psep.split(desc, 1)
if len(s) == 2:
if desc[len(s[0])] == '@':
paramclass = Input
else:
paramclass = Parameter
typedesc, pos = s
else:
raise ValueError, desc
if typedesc[:1] == '&':
passpref = '&'
typedesc = typedesc[1:]
elif typedesc[:1] == '*':
passpref = '*'
typedesc = typedesc[1:]
else:
passpref = ''
var = Variable(typedesc)
# BMessage*@4!dup
s = pos.split('!')
if len(s) > 1:
pos, s = s
ref = s
else:
ref = None
# int32@1=0
s = pos.split('=')
if len(s) > 1:
pos, init = s
else:
init = None
# string@1.ptr
s = pos.split('.')
if len(s) > 1:
pos, field = s
else:
field = None
# Dimensions.
pdim = None
s = pos.split('[')
if len(s) > 1:
pos, dp = s
sep = self.psep.search(dp)
if sep:
# char*%3[@2
#
pdim = self.parse('int' + dp)
else:
if dp[:1] == '<':
# void*%0[BitsLength() ...
#
pdim = Literal(dp[1:])
else:
# A static dimension for the variable.
var.dim = Literal(dp)
param = paramclass(typedesc, passpref, pos, field, init, pdim, ref)
return param, var
def resolve(self, param, vp, table, vprefix):
#
# Locate that variable.
#
pos = param.pos
while len(self.plist) <= pos:
self.plist.append(None)
if table:
# Parameter resolution by type and position.
# This allows a function to share variables
# across several overloaded parameter lists.
# Normal parameters are resolved this way.
#
var = table.index(param.type, pos)
if not var:
var = vp
param.classify(var)
var.name = '%c%d' % (vprefix, pos)
table.set(param.type, pos, var)
param.var = var
# Rescue unresolved parameter references (dimensions)
# (see below)
pv = self.plist[pos]
if pv and not hasattr(pv, 'var'):
pv.var = var
self.plist[pos] = param
else:
# Parameter resolution by position, specifically
# for parameter dimensions which are themselves
# parameters. Specific to the present function
# overload, typeless.
#
pv = self.plist[pos]
if pv:
if hasattr(pv, 'var'):
param.var = pv.var
else:
# Two dimensions derived from the same
# parameter? I guess it's possible!
# New one must die, first one wins.
#
param = pv
else:
self.plist[pos] = param
return param
Bethon-0.5.4/misc/ 0000755 0000000 0000000 00000000000 11257577700 012376 5 ustar user root Bethon-0.5.4/misc/Makefile 0000644 0000000 0000144 00000001146 11257577607 014235 0 ustar user users PYTHONVERSION=2.2
-include ../pythonversion
OPT=-O
INCLUDE=-I- -I/boot/common/include/python$(PYTHONVERSION)
DEFS=-DHAVE_CONFIG $(INCLUDE)
CFLAGS=$(OPT) $(DEFS)
LIBS=-L/boot/common/lib -lpython$(PYTHONVERSION) -ltextencoding -lnetwork -lbe -ltracker -lroot
# Like, you can leave this file here if you want.
BPYSRC = ../
APP = $(BPYSRC)/misc/app.cpp
hello_app: hello_app.o hello.pk
$(CC) -o $@ hello_app.o $(LIBS)
../test/load_attr hello_app < hello.pk
hello_app.o: $(APP)
$(CC) -c $(CFLAGS) $(APP) -o $@ -DAPPLICATION='"'$$PWD'/hello"' -DAPPLICATION_LOG='"/var/log/Hello"'
clean:
rm -f *.o *.pyc hello_app
Bethon-0.5.4/misc/app.cpp 0000644 0000000 0000144 00000005464 11032462540 014044 0 ustar user users // This simple program is compile-linked to the Python interpreter,
// so it can provide a "binary" image for the Python program it really
// runs, and all kinds of BeOS loading semantics can be attached here -
// mime types, icons, single-launch, bla bla. This example is the most
// minimal, crude but reasonably effective.
//
// It's also possible to implement BApplication in C++ here, then import
// the main Python module (now rewritten of course to omit its BApplication
// class wrapper) and call its exported methods. I don't see anything
// to be gained from this, but there's a lot I don't know. Anyway, to do
// it you need to add a tweak to BApplication.cpp, to set "be_app" from
// the FromBApplication() function.
#include
#include
#include
#include /* creat */
#ifndef PYTHON_INSTALL_PREFIX
#define PYTHON_INSTALL_PREFIX "/boot/home/config"
#endif
#include
static void
setup_log()
{
static const char logfile[] = APPLICATION_LOG;
int efd;
efd = creat(logfile, 0000);
if (efd >= 0) {
dup2(efd, 1);
dup2(efd, 2);
} else
perror(logfile);
}
static void
setup_interpreter(int argc, char **argv, char *appdir)
{
char path[256];
static const char prefix[] = PYTHON_INSTALL_PREFIX;
char python[12];
Py_SetProgramName(argv[0]);
Py_Initialize();
PySys_SetArgv(argc, argv);
sprintf(python, "python%d.%d", PY_MAJOR_VERSION, PY_MINOR_VERSION);
#if PY_MAJOR_VERSION == 1
sprintf(path, "%s:%s/lib/%s:%s/lib/%s/plat-beos:%s/lib/%s/lib-dynload",
#else
# ifdef __HAIKU__
sprintf(path, "%s:%s/lib/%s:%s/lib/%s/plat-haiku1:%s/lib/%s/lib-dynload",
# else
# ifndef B_BEOS_VERSION_5
# define B_BEOS_VERSION_5 0x0500
# endif
# ifndef B_BEOS_VERSION_6
# define B_BEOS_VERSION_6 0x0600
# endif
# if B_BEOS_VERSION >= B_BEOS_VERSION_4 && B_BEOS_VERSION < B_BEOS_VERSION_5
sprintf(path, "%s:%s/lib/%s:%s/lib/%s/plat-beos4:%s/lib/%s/lib-dynload",
# elif B_BEOS_VERSION >= B_BEOS_VERSION_5 && B_BEOS_VERSION < B_BEOS_VERSION_6
sprintf(path, "%s:%s/lib/%s:%s/lib/%s/plat-beos5:%s/lib/%s/lib-dynload",
# elif B_BEOS_VERSION >= B_BEOS_VERSION_6
sprintf(path, "%s:%s/lib/%s:%s/lib/%s/plat-beos6:%s/lib/%s/lib-dynload",
# endif
# endif
#endif
appdir,
prefix, python,
prefix, python,
prefix, python);
PySys_SetPath(path);
}
int
main(int argc, char **argv)
{
FILE *py;
char *nm;
static char progfile[] = APPLICATION;
static char defdir[] = ".";
char *progbase, *progdir;
py = fopen(progfile, "r");
if (!py) {
perror(progfile);
exit(1);
}
progbase = strrchr(progfile, '/');
if (progbase) {
*progbase++ = 0;
progdir = progfile;
} else {
progbase = progfile;
progdir = defdir;
}
setup_log();
setup_interpreter(argc, argv, progfile);
PyRun_AnyFile(py, progbase);
if (PyErr_Occurred()) {
PyErr_Print();
exit(1);
} else
exit(0);
}
Bethon-0.5.4/misc/app.html 0000644 0000000 0000144 00000002614 07156104550 014226 0 ustar user users
C++ wrapper
C++ wrapper for Python wrapper for C++ BeOS API
Here's a C++ Python main(). You can set application attributes as
per regular C++ application, like icon, single/multiple launch etc.
In this example, the Python program is "hello". That's set up in
Makefile, which defines C pre-processor symbols so you don't have
to edit the C++ program to make a different one for each program.
The Makefile also loads attributes from a file - a goofy icon and
some other ordinary stuff. The file is a Python ``pickle'' archive,
dumped from an executable file where I had defined these attributes
with FileTypes. (I omitted the BEOS:TYPE attribute from the attributes,
though, that's the linker's job.) There must be better ways to do it,
I'm just not very well informed on stuff like that.
The easy way to do almost the same thing without any C++ file is
a BEOS:PPATH attribute on the Python program itself, pointing
to the python binary. (That's what BAppFileInfo::SetAppHint() does.)
Then the program will be executed (interpreted) by python when
you select it from a Tracker window. But the file's icon doesn't
show up in the dock that way. I don't think it's necessarily a
good idea to do this routinely with every Python program -- in
many cases the 'edit this file' default will be more appropriate.
Bethon-0.5.4/misc/hello 0000755 0000000 0000144 00000002615 11257577631 013625 0 ustar user users #!/boot/common/bin/python
import sys
import BApplication
from BStringView import BStringView
from BWindow import BWindow
from InterfaceKit import B_FOLLOW_ALL,B_TITLED_WINDOW,B_WILL_DRAW,B_NOT_RESIZABLE,B_NOT_ZOOMABLE
from AppKit import B_QUIT_REQUESTED
class HelloView(BStringView):
def __init__(self, rect, name, text):
BStringView.__init__(self, rect, name, text, B_FOLLOW_ALL, B_WILL_DRAW)
# be_bold_font can't be imported at the top of the script,
# because at that point we don't have a BApplication.
# I believe that means if be_bold_font is going to be used,
# BFont can't be imported at the top. This is not so good.
from BFont import be_bold_font
self.SetFont(be_bold_font)
self.SetFontSize(24.0)
class HelloWindow(BWindow):
def __init__(self, frame):
BWindow.__init__(self, frame, 'Hello', B_TITLED_WINDOW, B_NOT_RESIZABLE|B_NOT_ZOOMABLE)
# set up a rectangle and instantiate a new view
self.view = HelloView(self.Bounds(), 'HelloView', 'Hello, world!')
self.AddChild(self.view)
def QuitRequested(self):
BApplication.be_app.PostMessage(B_QUIT_REQUESTED)
return 1
class HelloApplication(BApplication.BApplication):
def __init__(self):
BApplication.BApplication.__init__(self, "application/x-vnd.Be-HelloWorldSample")
def ReadyToRun(self):
window = HelloWindow((100.0, 80.0, 260.0, 120.0))
window.Show()
myApplication = HelloApplication()
myApplication.Run()
Bethon-0.5.4/misc/hello.pk 0000644 0000000 0000144 00000015661 07156102420 014217 0 ustar user users (lp0
(I1296649555
S'BEOS:PREF_APP'
p1
S'\000'
p2
tp3
a(I1296646990
S'BEOS:M:STD_ICON'
p4
S'\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\37799\377\377\377\377\377\377\377\37799\377\377\377\37799\377\377\377\377\377\377\377\37799\377\377\377\37799\377\377\377\377\377\377\377\377999\377\377\37799\377\377\377\377\377\377\377\377\37799\377\377\37799\377\377\377\377\377\377\377\377\37799\377\377\37799\377\377\377\377\377\377\377\377\377999\377\37799\377\377\377\377\377\377\377\377\377\37799\377\37799\377\377\377\377\377\377\377\377\377\377999999\377\377\377\377\377\377\377\3779999\320\32099\377\377\377\377\377\377\377\377999999999\377\377\377\377\377\37799\3209999999\377\377\377\377\377\377999\320\320\320\320999\377\377\377\377\377\377999\320\320\320\320999\377\377\377\377\377\377\3779\320\320\320\320999\377\377\377\377'
p5
tp6
a(I1296649555
S'BEOS:APP_SIG'
p7
S'application/x-vnd.Be-HelloWorldSample\000'
p8
tp9
a(I1095782470
S'BEOS:APP_FLAGS'
p10
S'\000\000\000\000'
p11
tp12
a(I1095782486
S'BEOS:APP_VERSION'
p13
S'\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000'
p14
tp15
a(I1229147982
S'BEOS:L:STD_ICON'
p16
S'\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\37799\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377999\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\3779999\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377999\377\377\377\377\377\377\377\377\3779999\377\377\377\377\377\377\377\377\377\377\377\377\377\377\3779999\377\377\377\377\377\377\377\377\3779999\377\377\377\377\377\377\377\377\377\377\377\377\377\377\37799999\377\377\377\377\377\377\377\3779999\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\3779999\377\377\377\377\377\377\377\3779999\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\37799999\377\377\377\377\377\377\3779999\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\37799999\377\377\377\377\377\377\3779999\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\37799999\377\377\377\377\377\3779999\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\37799999\377\377\377\377\377\3779999\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\3779999\377\377\377\377\377\3779999\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\37799999\377\377\377\377\3779999\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\3779999\377\377\377\377\3779999\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\37799999\377\377\377\3779999\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\3779999\377\377\377\3779999\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\37799999\377\37799999\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\3779999\377999999\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\37799999999999\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\37799999999999\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377999\320999999999\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\3209999\320\320\320\320\320\32099\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\3779\32099999999999999\377\377\377\377\377\377\377\377\377\377\377\377\377\377\37799\320\32099999999999999\377\377\377\377\377\377\377\377\377\377\377\377\377\3779999\320\320\320\320\320\320\320\320\32099999\377\377\377\377\377\377\377\377\377\377\377\377\377\3779999999\320\320\320\320\320\32099999\377\377\377\377\377\377\377\377\377\377\377\377\377\37799999999\320\320\320\320999999\377\377\377\377\377\377\377\377\377\377\377\377\377999\320\320999\320\320\320\3209999999\377\377\377\377\377\377\377\377\377\377\377\377\3779999\320\320\320\320\320\320\320\3209999999\377\377\377\377\377\377\377\377\377\377\377\377\377\37799999\320\320\320\32099999999\377\377\377\377\377\377\377\377\377\377\377\377\377\377\3779\320\320\320\320\320\320\320\3209999999\377\377\377\377\377\377\377'
p17
tp18
a. Bethon-0.5.4/misc/hello_app 0000755 0000000 0000000 00000017346 11257577700 014302 0 ustar user root ELF
4 D 4 ( P h p p p % . ,
+ " ! % - $ ( # * '
) &