sw@kernel.co.uk (Sak Wathanasin) (01/29/89)
[ThinkC Source for PAP i/f routines] I've just received my Jan 89 copy of MacTutor, and I noticed the request for PAP i/f routines. I attach below two files: pap.c and pap.h that are meant to be built into a project, and called from your host application. Because I do not build them into a DRVR (although you can), they are much simpler. Morever, they are self-contained and can be built using the ThinkC compiler alone (I've used both ThinkC 2.x and 3.0). The pap.c file includes a set of test routines (conditonally compiled using the variable TEST). When enabled, they simulate the action of the LW, but write the PS to a file. This allows you to test the sequence of PAP calls without having an LW present. To use the test routines, just call the PAP routines as usual, and periodically call the routine TestDelay (your main event loop is a good place). To use them, a) call the routine PAPLoad once to load the PAP routines from the LW driver b) call PAPOpen to open a connection to the LW c) call PAPRead/PAPWrite as required to talk to the printer d) call PAPClose to close the connection to the printer e) repeat (b) to (d) as required; see MacTutor article on details of how to send EOF to the printer f) the PAPStatus call can be used to return info about the printer at any time f) call PAPUnload once before your application exits (you must do this because the PAP mgr has VBL tasks running and these must be removed) I hope that you will find these routines useful. I have used them with all vintages of LW drivers from 2.0 to 5.2, and all Systems from 2.1 to 6.0.2 (note that if you use a machine with the 64K roms, you may have to install the AppleTalk drivers in your system file). I would be glad to hear of any bug reports. If anyone can add any details of the PAP mgr to that contained in Bob Denny's excellent MacTutor article, please post to the net. In particular, I'd like to know if there is any way of aborting a PS job once it has started. Sak Wathanasin uucp: ...!ukc!kernel!sw JANET: sw@uk.co.kernel BITNET: sw%kernel.co.uk%ukc.ac.uk@ukacrl.bitnet other: sw@kernel.co.uk phone: (+44) 532 444566 snail: Kernel Technology Ltd, 46 The Calls, Leeds LS2 7EY --- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # # pap.h # pap.c # # This archive created: Sun Jan 29 07:09:59 1989 # By: Roger L. Long (bytebug@dhw68k.cts.com) export PATH; PATH=/bin:$PATH echo shar: extracting "'pap.h'" '(971 characters)' if test -f 'pap.h' then echo shar: will not over-write existing file "'pap.h'" else sed 's/^X//' << \SHAR_EOF > 'pap.h' X#include "ResourceMgr.h" X#include "hfs.h" X#include "OSUtil.h" X/* X#define TEST X*/ Xtypedef struct X { long systemStuff; X Str255 statusStr; X } papStatusRec, *papStatusPtr; X X Xextern pascal short PAPOpen(); Xextern pascal short PAPRead(); Xextern pascal short PAPWrite(); Xextern pascal short PAPClose(); Xextern pascal short PAPStatus(); Xextern short PAPLoad(); Xextern short PAPUnload(); Xextern Handle pap; /* these static vars don't have to be locked */ Xextern Ptr papPtr; /* points to locked PAP mgr */ Xextern StringPtr lwNameP, /* handle to locked entity name */ X lwTypeP, X lwZoneP; X Xextern Fatal(); /* takes two parameters: Str255, short */ Xextern PrintErr(); X#define HFS FSFCBLen X#ifdef TEST X#include <AppleTalk.h> X Xextern void TestDelay(); Xextern WindowPtr dbgWind; X#define DELAY_FACTOR 300 X#endif TEST SHAR_EOF fi # end of overwriting check echo shar: extracting "'pap.c'" '(9960 characters)' if test -f 'pap.c' then echo shar: will not over-write existing file "'pap.c'" else sed 's/^X//' << \SHAR_EOF > 'pap.c' X/* Routines to interface to PAP driver. See MacTutor, Sep '86; also Jan '88. X This routines are meant to replace the assembly language "glue" X given in the Sep '86 article. Refer to the article for info on how to X use these routines. X X Sak Wathanasin (sw%kernel.co.uk or ....!mcvax!ukc!kernel!sw) X X This file (or a project built from it) can be included in any project X that wants to talk to the PAP routines, but you must provide two external X routines, PrintErr and Fatal (they take a Str255 and a short err number). X XSynopsis: X X typedef struct X { long systemStuff; X char statusStr[256]; X } papStatusRec, *papStatusPtr; X X pascal short PAPOpen (refNum, printerName, flowQuantum, statusBuf, compState) X short *refNum; X char *printerName; X short flowQuantum; X papStatusPtr statusBuf; X X pascal short PAPRead (refNum, buffer, length, eof, compState); X short refNum; X char *buffer; X short *length; X short *eol; X short *compState; X X pascal short PAPWrite (refNum, buffer, length, eof, compState) X short refNum; X char *buffer; X short length; X short eol; X short *compState; X X pascal short PAPClose (refNum); X short refNum; X X typedef struct AddrBlock { X short aNet; X Byte aNode; X Byte aSocket; X } AddrBlock; X X pascal short PAPStatus (printerName, statusBuff, netAddr) X char *printerName; X papStatusPtr statusBuff; X AddrBlock *netAddr; X X short PAPLoad (); X short PAPUnload(); X*/ X X#include "pap.h" X#define NIL 0L X XHandle pap=NIL; /* these static vars don't have to be locked */ XPtr papPtr; /* points to locked PAP mgr */ XHandle lwNameH; /* handle to locked entity name */ XStringPtr X lwNameP, /* ptr to same */ X lwTypeP, X lwZoneP; X X#ifdef TEST X/* test routines divert output to a file, so I can test X without an LW present */ X Xshort psRef=-1; Xstruct { X short *comp, X len, X eof; X Boolean inUse; X long delay; X} wInfo= {NIL, 0, 0, FALSE, 0L}; X Xstruct { X short *comp, X *len, X *eof; X char *buff; X Boolean inUse; X long delay; X} rInfo= {NIL, NIL, NIL, NIL, FALSE, 0L}; X Xpascal short PAPOpen (refNum, printerName, flowQuantum, statusBuf, compState) Xshort *refNum; Xchar *printerName; Xshort flowQuantum; XpapStatusPtr statusBuf; Xshort *compState; X{ X# define zeroLoc 10 X static Str255 fName="\pPS Dump 00"; X X (void)Create(fName, 0, 'PEDT', 'TEXT'); X (void)FSOpen(fName, 0, &psRef); X if (++fName[zeroLoc] > '9') { X fName[zeroLoc] = '0'; X fName[zeroLoc-1]++; X } X X *refNum = 0; X wInfo.comp = compState; X *compState = 1; X wInfo.delay = TickCount() + ( Random() % DELAY_FACTOR); X wInfo.inUse = TRUE; X return ((short)noErr); X} X X Xpascal short PAPRead (refNum, buffer, length, eof, compState) X short refNum; X char *buffer; X short *length; X short *eof; X short *compState; X{ X long tdelay; X rInfo.comp = compState; X *compState = 1; X rInfo.eof = eof; X rInfo.len = length; X rInfo.buff = buffer; X tdelay = ( Random() % DELAY_FACTOR); X rInfo.delay = TickCount() + tdelay; X rInfo.inUse = TRUE; X return((short)noErr); X} X Xpascal short PAPWrite (refNum, buffer, length, eof, compState) X short refNum; X char *buffer; X short length; X short eof; X short *compState; X{ X long psCnt; X OSErr err=noErr; X long tdelay; X X wInfo.comp = compState; X *compState = 1; X wInfo.eof = eof; X wInfo.len = length; X tdelay = ( Random() % DELAY_FACTOR); X wInfo.delay = TickCount() + tdelay; X if (wInfo.inUse) return (-4101); X else { X wInfo.inUse = TRUE; X psCnt = (long)length; X err = FSWrite (psRef, &psCnt, buffer); X return((short)err); X } X} X Xpascal short PAPClose (refNum) X short refNum; X X{ X long psTotal; X X wInfo.comp = NIL; X wInfo.eof = 0; X wInfo.len = 0; X wInfo.inUse = FALSE; X wInfo.delay = 0L; X rInfo.comp = NIL; X rInfo.eof = NIL; X rInfo.len = NIL; X rInfo.buff = NIL; X rInfo.inUse = FALSE; X rInfo.delay = 0L; X if (psRef >= 0) { X (void) GetFPos (psRef, &psTotal); X (void) SetEOF (psRef, psTotal); X (void)FSClose(psRef); X (void)FlushVol(nil, 0); X } X psRef = -1; X return(0); X} X Xpascal short PAPStatus (printerName, statusBuff, netAddr) X char *printerName; X papStatusPtr statusBuff; X AddrBlock *netAddr; X{ X static Str255 writing="\p status: writing", X idle="\p status: idle", X talking="\p status: talking"; X X if (wInfo.inUse) X BlockMove(writing, statusBuff->statusStr, (Size)sizeof(writing)); X else if (rInfo.inUse) X BlockMove(talking, statusBuff->statusStr, (Size)sizeof(talking)); X else X BlockMove(idle, statusBuff->statusStr, (Size)sizeof(idle)); X return(0); X} X Xextern long randSeed; Xshort PAPLoad () X{ X static Str255 lw="\pFake LaserWriter", X lwt="\pLaserWriter", X lwz="*"; X lwNameP = lw; X lwTypeP = lwt; X lwZoneP = lwz; X GetDateTime(&randSeed); X return(0); X} X Xshort PAPUnload() X{ X return(0); X} X XFakeRead() X{ X static char rubbish[]="Just some rubbish\n"; X X if (wInfo.eof) { X *(rInfo.eof) = 1; X *(rInfo.len) = 0; X wInfo.eof = 0; X } X else { X *(rInfo.eof) = 0; X *(rInfo.len) = sizeof(rubbish)-1; X BlockMove(rubbish, rInfo.buff, (Size)sizeof(rubbish)-1); X } X *(rInfo.comp) = 0; X rInfo.comp = NIL; X rInfo.eof = NIL; X rInfo.len = NIL; X rInfo.buff = NIL; X rInfo.inUse = FALSE; X rInfo.delay = 0L; X} X XFakeWrite() X{ X *(wInfo.comp) = 0; X wInfo.comp = NIL; X wInfo.len = 0; X wInfo.inUse = FALSE; X wInfo.delay = 0L; X} X Xvoid TestDelay() X{ X long myTick; X X myTick = TickCount(); X if (rInfo.inUse && myTick > rInfo.delay) FakeRead(); X if (wInfo.inUse && myTick > wInfo.delay) FakeWrite(); X} X X#else TEST Xshort PAPLoad () X{ short res; X OSErr err; X char NullString='\0'; X Str255 DVolname; X short DVolRefnum; X SysEnvRec X theWorld; X X /* we need to find the LaserWriter file on the boot volume X or 'blessed' folder without making a permanent change X in the current default volume; under HFS the "poor man's X search path" is used by default */ X X (void) SysEnvirons(1, &theWorld); X (void) GetVol (&DVolname, &DVolRefnum); X (void) SetVol( &NullString, theWorld.sysVRefNum); X X res = OpenResFile ("\pLaserWriter"); /* we should get this name from X the Chooser (in STR -8192) */ X if ( res < 0 ) { X /* couldn't find the file */ X Fatal("\pCan't find LaserWriter file", res); X return (res); X } X X /* Read the PAP code into memory & lock it down */ X if ((pap = GetResource('PDEF', 10)) == NIL || (err = ResError()) ) { X /* oops! something wrong */ X Fatal("\pCouldn't load PAP resources:", err); X if (res != -1) /* the file was opened earlier */ X CloseResFile (res); X return (err); X }; X X MoveHHi(pap); /* relocate to top of application heap */ X HLock(pap); /* lock it */ X DetachResource(pap); /* and detach from the file's resource map */ X papPtr = *pap; X /* save the addr in a global; it's OK to do X this as we've locked it */ X X /* Now get the printer entity name from the LaserWriter file */ X X if ((lwNameH = GetResource('PAPA', -8192)) == NIL || (err = ResError()) ) { X Fatal("Couldn't get LaserWriter name: ", err); X return(err); X } X X /* Move to top of heap & lock the name */ X MoveHHi(lwNameH); X HLock(lwNameH); X DetachResource(lwNameH); X lwNameP = (StringPtr)(*lwNameH); X lwTypeP = lwNameP + (short)lwNameP[0] + 1; X lwZoneP = lwTypeP + (short)lwTypeP[0] + 1; X X /* We're done with the LaserWriter file */ X CloseResFile(res); X (void) SetVol (&NullString, DVolRefnum); X return(0); X} X Xpascal short PAPOpen () X/* no params to stop LSC generating a stack frame */ X{ X asm{ X move.l papPtr, A0 X jmp 0(A0) X } X} X Xpascal short PAPRead () X/* no params to stop LSC generating a stack frame */ X{ X asm{ X move.l papPtr, A0 X jmp 4(A0) X } X} X Xpascal short PAPWrite () X/* no params to stop LSC generating a stack frame */ X{ X asm{ X move.l papPtr, A0 X jmp 8(A0) X } X} X Xpascal short PAPStatus () X/* no params to stop LSC generating a stack frame */ X{ X asm{ X move.l papPtr, A0 X jmp 12(A0) X } X} X Xpascal short PAPClose () X/* no params to stop LSC generating a stack frame */ X{ X asm{ X move.l papPtr, A0 X jmp 16(A0) X } X} X X/* The PAP driver installs several VBL tasks that must be removed X using the PAP unload call before disposing of the PAP code X*/ Xshort PAPUnload() X{ short res; X asm{ X subq.l #2, sp X move.l papPtr, A0 X jsr 20(A0) X move.w (sp)+, res /* save the result from the PAP call */ X } X /* can PAPUnload ever return an error? We assume not... */ X X HUnlock(lwNameH); X DisposHandle(lwNameH); /* junk the LW name */ X HUnlock(pap); X DisposHandle(pap); X return(res); X} X#endif TEST SHAR_EOF fi # end of overwriting check # End of shell archive exit 0 ---