GestaltTalk/GestaltTalkCommands.c

/*
    GestaltTalkCommands
    -------------------
 
    By Brigham Stevens
    Apple Computer DTS
*/
 
 
#include <GestaltTalk.h>
 
/*  initialize everything - call first */
static OSErr GestaltTalkInit(GestaltTalkPB *gpb);
 
/* returns the number of bytes in buffer */
static OSErr GestaltTalkStatus(GestaltTalkPB *gpb);
 
/* read some bytes from the buffer */
static OSErr GestaltTalkRead(GestaltTalkPB *gpb);
 
/* write some bytes to the buffer */
static OSErr GestaltTalkWrite(GestaltTalkPB *gpb);
 
/* If an application registers, then an init can wake it up at the 'right times' */
static OSErr GestaltTalkRegister(GestaltTalkPB *gpb);
 
/* call before your app quits so the init will not try to wake you */
static OSErr GestaltTalkUnregister(GestaltTalkPB *gpb);
 
/* Used to get the PSN of the registerd application (pointer to it in data) */
static OSErr GestaltTalkGetRegisteredApp(GestaltTalkPB *gpb);
 
/* This function gets the address of the gestalt talk buffer and stores 
    the returned pointer in gtData 
    Then future GestaltTalk calls will be faster becuase they will not
    use Gestalt to get the address of the buffer */
static OSErr GestaltTalkUserInit(GestaltTalkPB *gpb);
/*
    This function gets the address of the gestalt talk buffer
*/
static OSErr GetGestaltTalkBuffer(gtp *g);
 
#ifdef BUILD_INIT
    pascal OSErr GestaltTalkGestalt(long selector, long *response);
#endif
 
 
/*
    This is the main entry point to GestaltTalk
    All of the other routines should be access by filling
    out the gestaltTalk parameter block and calling this
*/
OSErr GestaltTalk(GestaltTalkPB *gpb)
{
    OSErr   err = 0;
    
    switch(gpb->command) {
#ifdef BUILD_INIT
        case ginit:         err = GestaltTalkInit(gpb);
                            break;
#endif
        case gstatus:       err = GestaltTalkStatus(gpb);
                            break;
        case gread:         err = GestaltTalkRead(gpb);
                            break;
        case gwrite:        err = GestaltTalkWrite(gpb);
                            break;
        case gregister:     err = GestaltTalkRegister(gpb);
                            break;
        case gunregister:   err = GestaltTalkUnregister(gpb);
                            break;
        case ggetapp:       err = GestaltTalkGetRegisteredApp(gpb);
                            break;
        case guserinit:     err = GestaltTalkUserInit(gpb);
                            break;
        default:            return paramErr;
    }
    
    return err;
}
 
 
 
#ifdef BUILD_INIT
 
static OSErr GestaltTalkInit(GestaltTalkPB *gpb)
{
    gtp     g;
    OSErr   err = 0;
    
 
    err = GetGestaltTalkBuffer(&g);
    if(err) {
        DebugStr("\p GestaltTalkInit - GetGestaltTalkBuffer failed.");
        goto bail;
    }
    g->dataBuffer = NewPtrSysClear(bufferSize);
 
    if(!g->dataBuffer) {
        err = MemError();
        DebugStr("\p GestaltTalkInit - NewPtrSysClear failed.");
        goto bail;
    }
    
    g->buffCount = 0;
 
bail:
    return err;
}
#endif
 
/*
    gets the number of bytes in the buffer in datalength
*/
OSErr GestaltTalkStatus(GestaltTalkPB *gpb)
{
    short   err = 0;    
    gtp     g;
    
    if(gpb->gtData)
        g = gpb->gtData;
    else {
        err = GetGestaltTalkBuffer(&g);
        if(err) goto bail;
    }
    
    gpb->datalength = g->buffCount;
 
bail:   
    return err;
}
 
 
OSErr GestaltTalkRead(GestaltTalkPB *gpb)
{
    short   err = 0;
    gtp     g;
    
    if(gpb->gtData)
        g = gpb->gtData;
    else {
        err = GetGestaltTalkBuffer(&g);
        if(err) goto bail;
    }
    
    if(!g->buffCount) {
        gpb->datalength = 0;
        goto bail;
    }
 
    if(gpb->datalength < g->buffCount) {
        err = readErr;
        BlockMove(g->dataBuffer, gpb->data, gpb->datalength);
    } else if (gpb->datalength > g->buffCount)
        err = eofErr;
 
    BlockMove(g->dataBuffer, gpb->data, g->buffCount);
    gpb->datalength = g->buffCount;
 
/*      right now this only supports one entry */
/*      next version supports multiple entries */
    g->buffCount = 0;
 
bail:   
    return err;
}
 
 
 
OSErr GestaltTalkWrite(GestaltTalkPB *gpb)
{
    short   err = 0;
    gtp     g;
    
    if(gpb->gtData)
        g = gpb->gtData;
    else {
        err = GetGestaltTalkBuffer(&g);
        if(err) goto bail;
    }
    
    if(!gpb->datalength) {
        err = paramErr;
        goto bail;
    }
    if(gpb->datalength > bufferSize) {
        err = writErr;
        BlockMove(gpb->data,g->dataBuffer,bufferSize);
        g->buffCount = bufferSize;
        gpb->datalength = bufferSize;
    } else {
        BlockMove(gpb->data,g->dataBuffer,gpb->datalength);
        g->buffCount = gpb->datalength;
    }
        
bail:
    return err;
}
 
 
 
/*
    If an appliation registers it's PSN with GestaltTalk
    then the PoliteNotification init will wake up the application
    so it can fetch the notification message from the buffers.
*/
/* can be called from an interrtupt */
OSErr GestaltTalkRegister(GestaltTalkPB *gpb)
{
    short   err = 0;
    gtp     g;
    
    if(gpb->gtData)
        g = gpb->gtData;
    else {
        err = GetGestaltTalkBuffer(&g);
        if(err) goto bail;
    }
    
    g->appPSN = *(ProcessSerialNumber*)gpb->data;
    g->appRegistered = 0x01;
    
bail:
    return err;
 
}
 
/*  can be called from an interrtupt  */
OSErr GestaltTalkUnregister(GestaltTalkPB *gpb)
{
    short               err = 0;
    gtp                 g;
    
    if(gpb->gtData)
        g = gpb->gtData;
    else {
        err = GetGestaltTalkBuffer(&g);
        if(err) goto bail;
    }
    
    g->appRegistered = false;   
 
bail:   
    return err;
 
}
 
OSErr GestaltTalkGetRegisteredApp(GestaltTalkPB *gpb)
{
    short   err = 0;
    gtp     g;
    
    if(gpb->gtData)
        g = gpb->gtData;
    else {
        err = GetGestaltTalkBuffer(&g);
        if(err) goto bail;
    }
    
    if(!g->appRegistered) {
        err = paramErr;
        goto bail;
    }
 
    gpb->data = &g->appPSN;
    gpb->datalength = sizeof(ProcessSerialNumber);
    
bail:   
    return err;
 
}
 
/*
    This procedure returns the address of the GTalk buffer
*/
static OSErr GestaltTalkUserInit(GestaltTalkPB *gpb)
{
    short   err = 0;
    gtp     g;
    
    err = GetGestaltTalkBuffer(&g);
    gpb->gtData = g;
        
bail:   
    return err;
}
 
OSErr GetGestaltTalkBuffer(gtp *g)
{
    OSErr   err = 0;
    
    #ifdef BUILD_INIT
        return GestaltTalkGestalt(gestaltTalkSelector, (long*)g);
    #endif
    
    #ifdef BUILD_USER
    asm {
            move.l  #gestaltTalkSelector,d0
            _Gestalt
            move.l  g,a1
            move.l  a0,(a1)
        }
    #endif
}