PrintingSegment is an MPW tool to aid the building of printer drivers and extensions for QuickDraw GX. One of the fiddly parts with putting together a GX driver or extension is writing assembly-language headers for each of your 'pdvr' or 'pext' code segments, containing jumps to your actual message override routine entry points, and making sure the offsets to these jumps match up with the offsets listed in your 'over' resources. PrintingSegment helps to automate this whole process: it generates the header object files directly, without you having to write any assembler, and it also generates the 'over' resources, to save you worrying about those. As a bonus, it can also convert between C and Pascal calling conventions.
What you have to do is create an entry-point definition file. This is a text file with one line for each of your message override routines, that looks like this:
You can have any number of blanks or tabs before or after each item. Anything after a “#” character on a line is ignored, so you can put in comments. Blank lines are also ignored. “MessageID” is the integer code (or symbolic name) for the QuickDraw GX printing message that this routine is overriding; “ResID” is the integer ID (or symbolic name) for the 'over' resource which will contain the routine offset; “SegNr” is the non-negative ID of the 'pdvr' or 'pext' resource which will contain the routine code; “EntryPointName” is the symbolic name of the routine as known to the Linker (case-sensitive), and “CallConvention” is the calling convention that the routine obeys (one of the strings “C” or “Pascal”, or blank for the default, as specified on the command line). For example, the following line
defines an override for the gxFilterPanelEvent message. The override definition should go in the 'over' resource with ID gxExtensionUniversalOverrideID. The routine itself will be going in code segment ID 0, and its name is “PanelFilterMessageProc”.
Calling PrintingSegment
You invoke PrintingSegment from MPW as follows:
PrintingSegment EntryPointFile [Qualifiers...]
where “EntryPointFile” is the name of the entry-point definition file, as described above. “Qualifiers” are any of the following valid qualifiers; these can occur anywhere on the command line, in any order, and they are all optional:
-oo ObjOutput
a list of names to give the .o segment header files for the code segments. “ObjOutput” takes the form
n=FileName[,n=FileName...]
where n is the non-negative segment resource ID, and FileName is the name to give the header file for that segment. Note that spaces around the commas or equals signs are not allowed.
-op ObjPrefix
a common prefix to prepend to all the segment header file names. If you want to specify a common directory for all your object files, you can put it here, and pass just the plain file names to the -oo qualifier. This can help keep the ObjOutput string from exceeding the 255-character limit.
-far
generates calls and jumps that use 32-bit offsets instead of 16-bit offsets.
-call Convention
whether to default to C or Pascal calling conventions for your override routines. “Convention” can be “C” or “Pascal”. If omitted, the default is “Pascal”.
-globals
whether to automatically call NewMessageGlobals just before dispatching to your override for the gxInitialize message, and call DisposeMessageGlobals after dispatching to your override for the gxShutdown message. Requires that you define overrides for both these messages.
-ro ResOutput
the name of the file to which to write the 'over' resources. The resources are automatically assigned the “sysHeap” and “purgeable” attributes, as required by QuickDraw GX.
-t ResFileType
the type to give to the file containing the 'over' resources (default is 'rsrc')
-c ResFileCreator
the creator code to give to the file containing the 'over' resources (default is 'RSED')
-a
specifies that the 'over' resources should be appended to an existing resource file. If omitted, the entire resource fork is deleted before writing the 'over' resources.
-base BaseName
specifies a symbol (case-sensitive) to define at the start of each segment header. You can refer to this symbol in your code, for example to calculate offsets to things.
reads entry-point definitions from the file “Test.ep”, and generates two object files. The header for segment 0 goes into the file “:Objs:Test0.ep.o”, while the one for segment 2 goes into “:Objs:Test2.ep.o”. If “Test.ep” contains definitions for any segments other than 0 or 2, their segment headers are not generated on this call.
PrintingSegment Test.ep -ro MyExtension -t pext -a
This reads entry-point definitions from the same file as before, and generates the 'over' resources into the file “MyExtension”. The existing resource fork is not deleted before writing the resources, but the filetype is set to 'pext' and the creator to 'RSED'.
Note that you can generate the .o files and 'over' resources in one command, or split them into multiple commands. This gives you maximum flexibility in structuring your Makefiles. However, you must remember to specify (or default) the same settings for the -far, -call and -globals qualifiers on every invocation, otherwise the offsets in the 'over' resources will not match those in the code.
When you link your code segments, include the appropriate segment header (as generated by PrintingSegment), at the start of each one. Continuing the previous examples, we could have
Link -o MyExtension ∂
-rt pext=0 -ra =sysheap,purgeable -sg Seg0 ∂
:Objs:Test0.ep.o # must be first! ∂
... other object files for segment 0 ...
Link -o MyExtension ∂
-rt pext=1 -ra =sysheap,purgeable -sg Seg1 ∂
:Objs:Test1.ep.o # must be first! ∂
... other object files for segment 1 ...
and so on.
That’s pretty much all there is to it. If you hit any problems, or you have any suggestions for improvement, feel free to contact me.
Development History
Z-1.0d4 of 1994 July 26 — first public release.
Z-1.1d1 of 1996 November 15 — added new message names for GX 1.1, and support for -globals option.