[comp.sources.mac] ThinkC Source for PAP i/f routines

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
---