| 
									
										
										
										
											1996-03-18 13:38:52 +00:00
										 |  |  | <HTML><HEAD><TITLE>Creating a C extension module on the Macintosh</TITLE></HEAD> | 
					
						
							|  |  |  | <BODY> | 
					
						
							|  |  |  | <H1>Creating a C extension module on the Macintosh</H1> | 
					
						
							|  |  |  | <HR> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This document gives a step-by-step example of how to create a new C | 
					
						
							|  |  |  | extension module on the mac. For this example, we will create a module | 
					
						
							|  |  |  | to interface to the programmers' API of InterSLIP, a package that | 
					
						
							|  |  |  | allows you to use MacTCP (and, hence, all internet services) over a | 
					
						
							|  |  |  | modem connection. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <H2>Prerequisites</H2> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | There are a few things you need to pull this off. First and foremost, | 
					
						
							|  |  |  | you need a C development environment. Actually, you need a specific | 
					
						
							|  |  |  | development environment, CodeWarrior by <A | 
					
						
							|  |  |  | HREF="http://www.metrowerks.com/">MetroWerks</A>.  You will probably | 
					
						
							|  |  |  | need the latest version. You may be able to get by with an older | 
					
						
							|  |  |  | version of CodeWarrior or with another development environment (Up to | 
					
						
							|  |  |  | about 1994 python was developed with THINK C, and in the dim past it | 
					
						
							|  |  |  | was compiled with MPW C) assuming you have managed to get Python to | 
					
						
							|  |  |  | compile under your development environment, but the step-by-step | 
					
						
							|  |  |  | character of this document will be lost. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-08-27 14:08:22 +00:00
										 |  |  | Next, you need a <A | 
					
						
							|  |  |  | HREF="http://www.python.org/python/Sources.html">python source | 
					
						
							|  |  |  | distribution</A>.  For PowerPC and cfm68k development you can actually | 
					
						
							|  |  |  | get by without a full source distribution, using the Development | 
					
						
							| 
									
										
										
										
											1998-02-25 15:40:35 +00:00
										 |  |  | distribution. You'll also need a functional python interpreter, and | 
					
						
							| 
									
										
										
										
											1997-08-27 14:08:22 +00:00
										 |  |  | the Modulator program (which lives in <CODE>Tools:Modulator</CODE> in | 
					
						
							|  |  |  | the standard source distribution). You may also find that Guido's <A | 
					
						
							| 
									
										
										
										
											1996-03-18 13:38:52 +00:00
										 |  |  | HREF="http://www.python.org/doc/ext/ext.html">Extending and embedding | 
					
						
							|  |  |  | the Python interpreter</A> is a very handy piece of documentation. I | 
					
						
							|  |  |  | will skip lots of details that are handled there, like complete | 
					
						
							| 
									
										
										
										
											1997-08-27 14:08:22 +00:00
										 |  |  | descriptions of <CODE>Py_ParseTuple</CODE> and such utility routines, or | 
					
						
							|  |  |  | the general structure of extension modules. <p> | 
					
						
							| 
									
										
										
										
											1996-03-18 13:38:52 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | <H2>InterSLIP and the C API to it</H2> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | InterSLIP, the utility to which we are going to create a python | 
					
						
							|  |  |  | interface, is a system extension that does all the work of connecting | 
					
						
							|  |  |  | to the internet over a modem connection. InterSLIP is provided | 
					
						
							|  |  |  | free-of-charge by <A | 
					
						
							|  |  |  | HREF="http://www.intercon.com/">InterCon</A>. First it connects to | 
					
						
							|  |  |  | your modem, then it goes through the whole process of dialling, | 
					
						
							|  |  |  | logging in and possibly starting the SLIP software on the remote | 
					
						
							|  |  |  | computer and finally it starts with the real work: packing up IP | 
					
						
							|  |  |  | packets handed to it by MacTCP and sending them to the remote side | 
					
						
							|  |  |  | (and, of course, the reverse action of receiving incoming packets, | 
					
						
							|  |  |  | unpacking them and handing them to MacTCP). InterSLIP is a device | 
					
						
							|  |  |  | driver, and you control it using a application supplied with it, | 
					
						
							|  |  |  | InterSLIP Setup. The API that InterSLIP Setup uses to talk to the | 
					
						
							|  |  |  | device driver is published in the documentation and, hence, also | 
					
						
							|  |  |  | useable by other applications. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | I happened to have a C interface to the API, which is all ugly | 
					
						
							|  |  |  | low-level device-driver calls by itself. The C interface is in <A | 
					
						
							|  |  |  | HREF="interslip/InterslipLib.c">InterslipLib.c</A> and <A | 
					
						
							|  |  |  | HREF="interslip/InterslipLib.h">InterslipLib.h</A>, we'll | 
					
						
							|  |  |  | concentrate here on how to build the Python wrapper module around | 
					
						
							|  |  |  | it. Note that this is the "normal" situation when you are writing a | 
					
						
							|  |  |  | Python extension module: you have some sort of functionality available | 
					
						
							|  |  |  | to C programmers and want to make a Python interface to it. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <H2>Using Modulator</H2> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The method we describe in this document, using Modulator, is the best | 
					
						
							|  |  |  | method for small interfaces. For large interfaces there is another | 
					
						
							|  |  |  | tool, Bgen, which actually generates the complete module without you | 
					
						
							|  |  |  | lifting a single finger. Bgen, however, has the disadvantage of having | 
					
						
							|  |  |  | a very steep learning curve, so an example using it will have to wait | 
					
						
							|  |  |  | until another document, when I have more time. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | First, let us look at the <A | 
					
						
							|  |  |  | HREF="interslip/InterslipLib.h">InterslipLib.h</A> header file, | 
					
						
							|  |  |  | and see that the whole interface consists of six routines: | 
					
						
							|  |  |  | <CODE>is_open</CODE>, <CODE>is_connect</CODE>, | 
					
						
							|  |  |  | <CODE>is_disconnect</CODE>, <CODE>is_status</CODE>, | 
					
						
							|  |  |  | <CODE>is_getconfig</CODE> and <CODE>is_setconfig</CODE>.  Our first | 
					
						
							|  |  |  | step will be to create a skeleton file <A | 
					
						
							|  |  |  | HREF="interslip/@interslipmodule.c">@interslipmodule.c</A>, a | 
					
						
							|  |  |  | dummy module that will contain all the glue code that python expects | 
					
						
							|  |  |  | of an extension module. Creating this glue code is a breeze with | 
					
						
							|  |  |  | modulator, a tool that we only have to tell that we want to create a | 
					
						
							|  |  |  | module with methods of the six names above and that will create the | 
					
						
							|  |  |  | complete skeleton C code for us. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Why call this dummy module <CODE>@interslipmodule.c</CODE> and not | 
					
						
							|  |  |  | <CODE>interslipmodule.c</CODE>? Self-preservation: if ever you happen | 
					
						
							|  |  |  | to repeat the whole process after you have actually turned the | 
					
						
							|  |  |  | skeleton module into a real module you would overwrite your | 
					
						
							|  |  |  | hand-written code. By calling the dummy module a different name you | 
					
						
							|  |  |  | have to make <EM>two</EM> mistakes in a row before you do this. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-08-27 14:08:22 +00:00
										 |  |  | If you installed Tk support when you installed Python this is extremely | 
					
						
							|  |  |  | simple. You start modulator and are provided with a form in which you | 
					
						
							| 
									
										
										
										
											1996-03-18 13:38:52 +00:00
										 |  |  | fill out the details of the module you are creating. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <IMG SRC="html.icons/modulator.gif" ALIGN=CENTER><p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | You'll need to supply a module name (<CODE>interslip</CODE>, in our | 
					
						
							|  |  |  | case), a module abbreviation (<CODE>pyis</CODE>, which is used as a | 
					
						
							|  |  |  | prefix to all the routines and data structures modulator will create | 
					
						
							|  |  |  | for you) and you enter the names of all the methods your module will | 
					
						
							|  |  |  | export (the list above, with <CODE>is_</CODE> stripped off). Note that | 
					
						
							|  |  |  | we use <CODE>pyis</CODE> as the prefix instead of the more logical | 
					
						
							|  |  |  | <CODE>is</CODE>, since the latter would cause our routine names to | 
					
						
							|  |  |  | collide with those in the API we are interfacing to! The method names | 
					
						
							|  |  |  | are the names as seen by the python program, and the C routine names | 
					
						
							|  |  |  | will have the prefix and an underscore prepended. Modulator can do | 
					
						
							|  |  |  | much more, like generating code for objects and such, but that is a | 
					
						
							|  |  |  | topic for a later example. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Once you have told modulator all about the module you want to create | 
					
						
							|  |  |  | you press "check", which checks that you haven't omitted any | 
					
						
							|  |  |  | information and "Generate code". This will prompt you for a C output | 
					
						
							|  |  |  | file and generate your module for you. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <H2>Using Modulator without Tk</H2> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Modulator actually uses a two-stage process to create your code: first | 
					
						
							|  |  |  | the information you provided is turned into a number of python | 
					
						
							|  |  |  | statements and then these statements are executed to generate your | 
					
						
							|  |  |  | code. This is done so that you can even use modulator if you don't | 
					
						
							|  |  |  | have Tk support in Python: you'll just have to write the modulator | 
					
						
							|  |  |  | python statements by hand (about 10 lines, in our example) and | 
					
						
							|  |  |  | modulator will generate the C code (about 150 lines, in our | 
					
						
							|  |  |  | example). Here is the Python code you'll want to execute to generate | 
					
						
							|  |  |  | our skeleton module: <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <CODE><PRE> | 
					
						
							|  |  |  | 	import addpack | 
					
						
							|  |  |  | 	addpack.addpack('Tools') | 
					
						
							|  |  |  | 	addpack.addpack('modulator') | 
					
						
							|  |  |  | 	import genmodule | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m = genmodule.module() | 
					
						
							|  |  |  | 	m.name = 'interslip' | 
					
						
							|  |  |  | 	m.abbrev = 'pyis' | 
					
						
							|  |  |  | 	m.methodlist = ['open', 'connect', 'disconnect', 'status', \ | 
					
						
							|  |  |  | 		'getconfig', 'setconfig'] | 
					
						
							|  |  |  | 	m.objects = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	fp = open('@interslipmodule.c', 'w') | 
					
						
							|  |  |  | 	genmodule.write(fp, m) | 
					
						
							|  |  |  | </PRE></CODE> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Drop this program on the python interpreter and out will come your | 
					
						
							|  |  |  | skeleton module. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Now, rename the file to interslipmodule.c and you're all set to start | 
					
						
							|  |  |  | developing. The module is complete in the sense that it should | 
					
						
							|  |  |  | compile, and that if you import it in a python program you will see | 
					
						
							|  |  |  | all the methods.  It is, of course, not yet complete in a functional | 
					
						
							|  |  |  | way... <p> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-08-27 14:08:22 +00:00
										 |  |  | <H2>Adding a module to Classic 68K Python</H2> | 
					
						
							| 
									
										
										
										
											1996-03-18 13:38:52 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | What you do now depends on whether you're developing for PowerPC (or | 
					
						
							|  |  |  | for CFM68K) or for "traditional" mac. For a traditional 68K Python, | 
					
						
							|  |  |  | you will have to add your new module to the project file of the Python | 
					
						
							|  |  |  | interpreter, and you have to edit "config.c" to add the module to the | 
					
						
							|  |  |  | set of builtin modules. In config.c you will add the module at two | 
					
						
							|  |  |  | places: near the start of the file there is a list of external | 
					
						
							|  |  |  | declarations for all init() routines. Add a line of the form | 
					
						
							|  |  |  | <CODE><PRE> | 
					
						
							|  |  |  | 		extern void initinterslip(); | 
					
						
							|  |  |  | </PRE></CODE> | 
					
						
							|  |  |  | here. Further down the file there is an array that is initialized with | 
					
						
							|  |  |  | modulename/initfunction pairs. Add a line of the form | 
					
						
							|  |  |  | <CODE><PRE> | 
					
						
							|  |  |  | 		{"interslip",	initinterslip}, | 
					
						
							|  |  |  | </PRE></CODE> | 
					
						
							|  |  |  | here. You may want to bracket these two lines with | 
					
						
							|  |  |  | <CODE><PRE> | 
					
						
							|  |  |  | 	#ifdef USE_INTERSLIP | 
					
						
							|  |  |  | 	#endif | 
					
						
							|  |  |  | </PRE></CODE> | 
					
						
							|  |  |  | lines, that way you can easily control whether the module is | 
					
						
							|  |  |  | incorporated into python at compile time. If you decide to do the | 
					
						
							|  |  |  | latter edit your config file (you can find the name in the "C/C++ | 
					
						
							|  |  |  | language" section of the MW preferences dialog, it will probably be | 
					
						
							|  |  |  | "mwerks_nonshared_config.h") and add a | 
					
						
							|  |  |  | <CODE><PRE> | 
					
						
							|  |  |  | 	#define USE_INTERSLIP | 
					
						
							|  |  |  | </PRE></CODE> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Make the new interpreter and check that you can import the module, see | 
					
						
							|  |  |  | the methods (with "dir(interslip)") and call them. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-02-25 15:40:35 +00:00
										 |  |  | <H2>Creating a plugin module</H2> | 
					
						
							| 
									
										
										
										
											1996-03-18 13:38:52 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-02-25 15:40:35 +00:00
										 |  |  | For PowerPC or cfm68k development you could follow the same path, but it is | 
					
						
							| 
									
										
										
										
											1996-03-18 13:38:52 +00:00
										 |  |  | actually a better idea to use a dynamically loadable module. The | 
					
						
							|  |  |  | advantage of dynamically loadable modules is that they are not loaded | 
					
						
							|  |  |  | until a python program actually uses them (resulting in less memory | 
					
						
							|  |  |  | usage by the interpreter) and that development is a lot simpler (since | 
					
						
							|  |  |  | your projects will all be smaller). Moreover, you can distribute a | 
					
						
							|  |  |  | plugin module by itself without haveing to distribute a complete | 
					
						
							|  |  |  | python interpreter. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-08-27 14:08:22 +00:00
										 |  |  | Go to the "PlugIns" folder and copy the files xx.prj, | 
					
						
							|  |  |  | and xx.prj.exp to interslipmodule.prj and | 
					
						
							|  |  |  | interslipmodule.prj.exp, respectively. Edit | 
					
						
							|  |  |  | interslipmodule.prj.exp and change the name of the exported routine | 
					
						
							|  |  |  | "initxx" to "initinterslip".  Open interslipmodule.prj with CodeWarrior, | 
					
						
							| 
									
										
										
										
											1996-03-18 13:38:52 +00:00
										 |  |  | remove the file xxmodule.c and add interslipmodule.c and make a number | 
					
						
							|  |  |  | of adjustments to the preferences: | 
					
						
							|  |  |  | <UL> | 
					
						
							| 
									
										
										
										
											1997-08-27 14:08:22 +00:00
										 |  |  | <LI> in PPC target, set the output file name to "interslipmodule.pcc.slb", | 
					
						
							|  |  |  | <LI> in cfm68k target set the output file name to "interslipmodule.cfm68k.slb". | 
					
						
							| 
									
										
										
										
											1998-02-25 15:40:35 +00:00
										 |  |  | <LI> if you are working without a source distribution (i.e. with a normal | 
					
						
							|  |  |  | binary distribution plus a development distribution) you will not have | 
					
						
							|  |  |  | a file <code>PythonCore</code>. The installation process has deposited this | 
					
						
							|  |  |  | file in the System <code>Extensions</code> folder under the name | 
					
						
							|  |  |  | <code>PythonCore <i>version</i></code>. Add that file to the project, replacing | 
					
						
							|  |  |  | <code>PythonCore</code>. | 
					
						
							| 
									
										
										
										
											1996-03-18 13:38:52 +00:00
										 |  |  | </UL> | 
					
						
							|  |  |  | Next, compile and link your module, fire up python and do the same | 
					
						
							|  |  |  | tests as for 68K python. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <H2>Getting the module to do real work</H2> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | So far, so good. In half an hour or so we have created a complete new | 
					
						
							|  |  |  | extension module for Python. The downside, however, is that the module | 
					
						
							|  |  |  | does not do anything useful. So, in the next half hour we will turn | 
					
						
							|  |  |  | our beautiful skeleton module into something that is at least as | 
					
						
							|  |  |  | beautiful but also gets some serious work done.  For this once, | 
					
						
							|  |  |  | <EM>I</EM> have spent that half hour for you, and you can see the | 
					
						
							|  |  |  | results in <A | 
					
						
							|  |  |  | HREF="interslip/interslipmodule.c">interslipmodule.c</A>. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | We add | 
					
						
							|  |  |  | <CODE><PRE> | 
					
						
							|  |  |  | 	#include "InterslipLib.h" | 
					
						
							|  |  |  | 	#include "macglue.h" | 
					
						
							|  |  |  | </PRE></CODE> | 
					
						
							|  |  |  | to the top of the file, and work our way through each of the methods | 
					
						
							|  |  |  | to add the functionality needed. Starting with open, we fill in the | 
					
						
							|  |  |  | template docstring, the value accessible from Python by looking at | 
					
						
							|  |  |  | <CODE>interslip.open.__doc__</CODE>.  There are not many tools using | 
					
						
							|  |  |  | this information at the moment, but as soon as class browsers for | 
					
						
							|  |  |  | python become available having this minimal documentation available is | 
					
						
							|  |  |  | a good idea. We put "Load the interslip driver" as the comment | 
					
						
							|  |  |  | here. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Next, we tackle the body of <CODE>pyis_open()</CODE>.  Since it has no | 
					
						
							|  |  |  | arguments and no return value we don't need to mess with that, we just | 
					
						
							|  |  |  | have to add a call to <CODE>is_open()</CODE> and check the return for | 
					
						
							|  |  |  | an error code, in which case we raise an error: | 
					
						
							|  |  |  | <CODE><PRE> | 
					
						
							|  |  |  | 	err = is_open(); | 
					
						
							|  |  |  | 	if ( err ) { | 
					
						
							|  |  |  | 		PyErr_Mac(ErrorObject, err); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | </PRE></CODE> | 
					
						
							|  |  |  | The routine <CODE><A NAME="PyErr_Mac">PyErr_Mac()</A></CODE> is a | 
					
						
							|  |  |  | useful routine that raises the exception passed as its first | 
					
						
							|  |  |  | argument. The data passed with the exception is based on the standard | 
					
						
							|  |  |  | MacOS error code given, and PyErr_Mac() attempts to locate a textual | 
					
						
							|  |  |  | description of the error code (which sure beats the "error -14021" | 
					
						
							|  |  |  | messages that so many macintosh applications tell their poor | 
					
						
							|  |  |  | users). <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | We will skip pyis_connect and pyis_disconnect here, which are pretty | 
					
						
							|  |  |  | much identical to pyis_open: no arguments, no return value, just a | 
					
						
							|  |  |  | call and an error check. With pyis_status() things get interesting | 
					
						
							|  |  |  | again: this call still takes 3 arguments, and all happen to be values | 
					
						
							|  |  |  | returned (a numeric connection status indicator, a message sequence | 
					
						
							|  |  |  | number and a pointer to the message itself, in MacOS pascal-style | 
					
						
							|  |  |  | string form). We declare variables to receive the returned values, do | 
					
						
							|  |  |  | the call, check the error and format the return value. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Building the return value is done using <CODE><A | 
					
						
							|  |  |  | NAME="Py_BuildValue">Py_BuildValue</A></CODE>: | 
					
						
							|  |  |  | <CODE><PRE> | 
					
						
							|  |  |  | 	return Py_BuildValue("iiO&", (int)status, (int)seqnum, PyMac_BuildStr255, message); | 
					
						
							|  |  |  | </PRE></CODE> | 
					
						
							|  |  |  | Py_BuildValue() is a very handy routine that builds tuples according | 
					
						
							|  |  |  | to a format string, somewhat similar to the way <CODE>printf()</CODE> | 
					
						
							|  |  |  | works.  The format string specifies the arguments expected after the | 
					
						
							|  |  |  | string, and turns them from C objects into python objects. The | 
					
						
							|  |  |  | resulting objects are put in a python tuple object and returned. The | 
					
						
							|  |  |  | "i" format specifier signifies an "int" (hence the cast: status and | 
					
						
							|  |  |  | seqnum are declared as "long", which is what the is_status() routine | 
					
						
							|  |  |  | wants, and even though we use a 4-byte project there is really no | 
					
						
							|  |  |  | reason not to put the cast here). Py_BuildValue and its counterpart | 
					
						
							|  |  |  | Py_ParseTuple have format codes for all the common C types like ints, | 
					
						
							|  |  |  | shorts, C-strings, floats, etc. Also, there is a nifty escape | 
					
						
							|  |  |  | mechanism to format values about which is does not know. This is | 
					
						
							|  |  |  | invoked by the "O&" format: it expects two arguments, a routine | 
					
						
							|  |  |  | pointer and an int-sized data object. The routine is called with the | 
					
						
							|  |  |  | object as a parameter and it should return a python objects | 
					
						
							|  |  |  | representing the data. <CODE>Macglue.h</CODE> declares a number of | 
					
						
							|  |  |  | such formatting routines for common MacOS objects like Str255, FSSpec, | 
					
						
							|  |  |  | OSType, Rect, etc. See the comments in the include file for | 
					
						
							|  |  |  | details. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <CODE>Pyis_getconfig()</CODE> is again similar to pyis_getstatus, only | 
					
						
							|  |  |  | two minor points are worth noting here.  First, the C API return the | 
					
						
							|  |  |  | input and output baudrate squashed together into a single 4-byte | 
					
						
							|  |  |  | long. We separate them out before returning the result to | 
					
						
							|  |  |  | python. Second, whereas the status call returned us a pointer to a | 
					
						
							|  |  |  | <CODE>Str255</CODE> it kept we are responsible for allocating the | 
					
						
							|  |  |  | <CODE>Str255</CODE> for getconfig. This is something that would have | 
					
						
							|  |  |  | been easy to get wrong had we not used prototypes everywhere. Morale: | 
					
						
							|  |  |  | always try to include the header files for interfaces to libraries and | 
					
						
							|  |  |  | other stuff, so that the compiler can catch any mistakes you make. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <CODE>Pyis_setconfig()</CODE> finally shows off | 
					
						
							|  |  |  | <CODE>Py_ParseTuple</CODE>, the companion function to | 
					
						
							|  |  |  | <CODE>Py_BuildValue</CODE>.  You pass it the argument tuple "args" | 
					
						
							|  |  |  | that your method gets as its second argument, a format string and | 
					
						
							|  |  |  | pointers to where you want the arguments stored. Again, standard C | 
					
						
							|  |  |  | types such as strings and integers Py_ParseTuple knows all about and | 
					
						
							|  |  |  | through the "O&" format you can extend the functionality. For each | 
					
						
							|  |  |  | "O&" you pass a function pointer and a pointer to a data area. The | 
					
						
							|  |  |  | function will be called with a PyObject pointer and your data pointer | 
					
						
							|  |  |  | and it should convert the python object to the correct C type. It | 
					
						
							|  |  |  | should return 1 on success and 0 on failure. Again, a number of | 
					
						
							|  |  |  | converters for standard MacOS types are provided, and declared in | 
					
						
							|  |  |  | <CODE>macglue.h</CODE>. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Next in our source file comes the method table for our module, which | 
					
						
							|  |  |  | has been generated by modulator (and it did a good job too!), but | 
					
						
							|  |  |  | which is worth looking at for a moment.  Entries are of the form | 
					
						
							|  |  |  | <CODE><PRE> | 
					
						
							|  |  |  | 	{"open",	pyis_open,	1,	pyis_open__doc__}, | 
					
						
							|  |  |  | </PRE></CODE> | 
					
						
							|  |  |  | where the entries are python method name, C routine pointer, flags and | 
					
						
							|  |  |  | docstring pointer.  The value to note is the 1 for the flags: this | 
					
						
							|  |  |  | signifies that you want to use "new-style" Py_ParseTuple behaviour. If | 
					
						
							|  |  |  | you are writing a new module always use this, but if you are modifying | 
					
						
							|  |  |  | old code which calls something like <CODE>getargs(args, "(ii)", | 
					
						
							|  |  |  | ...)</CODE> you will have to put zero here. See "extending and | 
					
						
							|  |  |  | embedding" or possibly the getargs.c source file for details if you | 
					
						
							|  |  |  | need them. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Finally, we add some code to the init module, to put some symbolic | 
					
						
							|  |  |  | constants (codes that can by returned by the status method) in the | 
					
						
							|  |  |  | module dictionary, so the python program can use "interslip.RUN" | 
					
						
							|  |  |  | instead of the cryptic "4" when it wants to check that the interslip | 
					
						
							|  |  |  | driver is in RUN state. Modulator has already generated code to get at | 
					
						
							|  |  |  | the module dictionary using PyModule_GetDict() to store the exception | 
					
						
							|  |  |  | object, so we simply call | 
					
						
							|  |  |  | <CODE><PRE> | 
					
						
							|  |  |  | 	PyDict_SetItemString(d, "IDLE", PyInt_FromLong(IS_IDLE)); | 
					
						
							|  |  |  | </PRE></CODE> | 
					
						
							|  |  |  | for each of our items. Since the last bit of code in our init routine | 
					
						
							|  |  |  | checks for previous errors with <CODE>PyErr_Occurred()</CODE> and | 
					
						
							|  |  |  | since <CODE>PyDict_SetItemString()</CODE> gracefully handles the case | 
					
						
							|  |  |  | of <CODE>NULL</CODE> parameters (if <CODE>PyInt_FromLong()</CODE> | 
					
						
							|  |  |  | failed, for instance) we don't have to do error checking here. In some | 
					
						
							|  |  |  | other cases you may have to do error checking yourself. <p> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This concludes our crash-course on writing Python extensions in C on | 
					
						
							|  |  |  | the Macintosh.  If you are not done reading yet I suggest you look | 
					
						
							|  |  |  | back at the <A HREF="index.html">MacPython Crashcourse index</A> to | 
					
						
							|  |  |  | find another topic to study. <p> |