/***             analog 4.14             http://www.analog.cx/             ***/
/*** This program is copyright (c) Stephen R. E. Turner 1995 - 2001 except as
 *** stated otherwise. Distribution, usage and modification of this program is
 *** subject to the conditions of the Licence which you should have received
 *** with it. This program comes with no warranty, expressed or implied.   ***/

/*** The contents of this file is copyright (c) Jason Linhart 1998. ***/

/*** macinput.c; input functions for Mac */

#define REAL_STDIO	/* Define these to suppress defines in anlghea3.h */

#include "anlghea3.h"

#ifdef MAC
#ifdef USE_ZLIB
#include <unix.h>
#include <fcntl.h>
#include "my_zlib.h"
#endif

#ifdef LINE_PARSER
/*
	Input file parsing
*/

#define LOC_BUFF_SIZE		(16*1024)

#ifndef USE_ZLIB
typdef FILE *gzFile;
#endif

static gzFile in_fp = nil;
static long line_num;
static int buff_cnt, buff_offset;
static char *buff = nil;

static void
FillBuff(int drop_cnt)
{
	buff_offset+=drop_cnt;
	buff_cnt-=drop_cnt;
	if (buff_cnt<LOC_BUFF_SIZE/2) {
		if (buff_cnt>0) memmove(buff,buff+buff_offset,buff_cnt);
		buff_offset=0;
#ifdef USE_ZLIB
		buff_cnt+=gzread(in_fp,(voidp)(buff+buff_cnt),LOC_BUFF_SIZE-buff_cnt);
#else
		buff_cnt+=fread(buff+buff_cnt,1,LOC_BUFF_SIZE-buff_cnt,in_fp);
#endif
		}
	}

/*
	Get file from HighLevel Apple Event
*/

static Boolean haveFSS = false;
static FSSpec myFSS;

static OSErr
GotRequiredParams(AppleEvent *theAppleEvent)
{
	DescType typeCode;
	Size actualSize;
	OSErr retErr, err;

	err=AEGetAttributePtr(theAppleEvent,keyMissedKeywordAttr,typeWildCard,&typeCode,
		NULL,0,&actualSize);
	
	if (err==errAEDescNotFound)	retErr = noErr;		// we got all the required params: all is ok
	else if (err==noErr) retErr = errAEEventNotHandled;
	else retErr = err;
	return retErr;
	}

static pascal OSErr					/* Used for Print and Close events */
DoAENoop(AppleEvent *theAppleEvent,AppleEvent *reply,long handlerRefcon)
{
#pragma unused ( handlerRefcon )
	OSErr err;
	
	err=GotRequiredParams(theAppleEvent);
	if (!err && reply->dataHandle)				/*	a reply is sought */
		err=AEPutParamPtr(reply,'errs','TEXT',"Ignoring",8);	
	return(err);
	}

static pascal OSErr
DoAEOpenDoc(AppleEvent *theAppleEvent,AppleEvent *reply,long handlerRefcon)
{
#pragma unused ( reply )
#pragma unused ( handlerRefcon )
	OSErr err;
	AEDescList docList;
	Size actualSize;
	AEKeyword keywd;
	DescType typeCode;
	long itemsInList;
	
	err=AEGetParamDesc(theAppleEvent,keyDirectObject,typeAEList,&docList);
	if (!err) {
		err=GotRequiredParams(theAppleEvent);
		if (!err) {
			err=AECountItems(&docList,&itemsInList);
			if (!err && itemsInList>0) {
				err=AEGetNthPtr(&docList,1,typeFSS,&keywd,&typeCode,(Ptr)&myFSS,
					 sizeof(myFSS),&actualSize);
				if (!err) haveFSS=true;
				}
			}
		AEDisposeDesc(&docList);
		}
	return(err);
	}

char mac_do_script[256] = "";

static pascal OSErr
DoAEDo(AppleEvent *theAppleEvent,AppleEvent *reply,long handlerRefcon)
{
#pragma unused ( reply )
#pragma unused ( handlerRefcon )
  OSErr err;
  AEDesc desc;
  Size actualSize;
  DescType typeCode;
        
  err=AEGetParamDesc(theAppleEvent,keyDirectObject,typeChar,&desc);
  if (!err) {
    err=GotRequiredParams(theAppleEvent);
    if (!err) {
      err=AEGetParamPtr(theAppleEvent,keyDirectObject,typeChar,
			&typeCode,(Ptr)mac_do_script,256,&actualSize);
      if (err) mac_do_script[0]=0;
      else {
	mac_do_script[255]=0;
	if (actualSize>=0 && actualSize<256) mac_do_script[actualSize]=0;
      }
    }
    AEDisposeDesc(&desc);
  }
  return(err);
}

int mac_quit_now = 0;

static pascal OSErr                                     /* Used for Quit event 
*/
DoAEQuit(AppleEvent *theAppleEvent,AppleEvent *reply,long handlerRefcon)
{
#pragma unused ( handlerRefcon )
        OSErr err;
        
        err=GotRequiredParams(theAppleEvent);
        if (!err && reply->dataHandle)                          /*      a reply 
is sought */
                err=AEPutParamPtr(reply,'errs','TEXT',"Ignoring",8);
        mac_quit_now=1;
        return(err);
}

char TryAEOpen(void);

char
TryAEOpen(void)
{
	AEEventHandlerUPP HandlerUPP;
	EventRecord myEvent;
	OSErr result;
	long lvalue;
	int cnt;
	short refNum;
	char c;

	if (Gestalt(gestaltAppleEventsAttr,&lvalue)!=noErr) return(false);
	result=noErr;
	HandlerUPP=NewAEEventHandlerProc(DoAEOpenDoc);
	result=AEInstallEventHandler(kCoreEventClass,kAEOpenDocuments,HandlerUPP,0,false);
	if (result==noErr)	{
		HandlerUPP=NewAEEventHandlerProc(DoAENoop);
		result=AEInstallEventHandler(kCoreEventClass,kAEOpenApplication,HandlerUPP,0,false);
		}
	if (result==noErr)	{
		HandlerUPP=NewAEEventHandlerProc(DoAENoop);
		result=AEInstallEventHandler(kCoreEventClass,kAEPrintDocuments,HandlerUPP,0,false);
		}
	if (result==noErr)	{
		HandlerUPP=NewAEEventHandlerProc(DoAEQuit);
		result=AEInstallEventHandler(kCoreEventClass,kAEQuitApplication,HandlerUPP,0,false);
		}
        if (result==noErr)      {
                HandlerUPP=NewAEEventHandlerProc(DoAEDo);
                result=AEInstallEventHandler(kAEMiscStandards,kAEDoScript,HandlerUPP,0,false);
                }
	if (result==noErr) {
		for (cnt=0; cnt<40; ++cnt) {
			if (GetNextEvent(everyEvent,&myEvent)) {
				if (myEvent.what==kHighLevelEvent) AEProcessAppleEvent(&myEvent);
				else SIOUXHandleOneEvent(&myEvent);
				}
			}
		}
	if (haveFSS && !HOpenDF(myFSS.vRefNum,myFSS.parID,myFSS.name,fsRdPerm,&refNum)) {
		lvalue=1;
		FSRead(refNum,&lvalue,&c);
		FSClose(refNum);
		return(c);
		}
        return(0);
        }

#ifdef USE_ZLIB
static void *z_blocks[6] = { nil, nil, nil, nil, nil, nil };
static int z_bflags[6] = { 2, 2, 2, 2, 2, 2 };

static voidpf
my_gz_alloc_func(voidpf opaque,uInt items,uInt size)
{
	int indx;

	size*=items;
	if (size==28) indx=0;
	else if (size==76) indx=1;
	else if (size==1152) indx=2;
	else if (size>=512 && size<=2048) indx=3;
	else if (size==11520) indx=4;
	else if (size==16*1024) indx=5;
	else return(malloc(size));

    if (!z_bflags[indx]) {
    	z_bflags[indx]=1;
    	return(z_blocks[indx]);
    	}
    else if (z_bflags[indx]==2) {
    	switch (indx) {

		case 0:		z_blocks[0]=malloc(28);			break;
		case 1:		z_blocks[1]=malloc(76);			break;
		case 2:		z_blocks[2]=malloc(1152);		break;
		case 3:		z_blocks[3]=malloc(2048);		break;
		case 4:		z_blocks[4]=malloc(11520);		break;
		case 5:		z_blocks[5]=malloc(16*1024);	break;
			}
		z_bflags[indx]=1;
		return(z_blocks[indx]);
		}
	return(malloc(size));
	}

static void
my_gz_free_func(voidpf opaque,voidpf address)
{
	if (address==z_blocks[0]) z_bflags[0]=0;
	else if (address==z_blocks[1]) z_bflags[1]=0;
	else if (address==z_blocks[2]) z_bflags[2]=0;
	else if (address==z_blocks[3]) z_bflags[3]=0;
	else if (address==z_blocks[4]) z_bflags[4]=0;
	else if (address==z_blocks[5]) z_bflags[5]=0;
	else free(address);
    }
#endif

FILE *
mac_fopen(const char *name,const char *mode)
{
        short refNum;

#ifdef USE_ZLIB
        gzsetalloc(my_gz_alloc_func,my_gz_free_func,nil);
#endif
        if (!strcmp(name,"%%%") && !strcmp(mode,"r") && haveFSS) {
		if (!HOpenDF(myFSS.vRefNum,myFSS.parID,myFSS.name,fsRdPerm,&refNum)) {
			if (in_fp) return(fdopen(refNum,"r"));
#ifdef USE_ZLIB
			in_fp=gzdopen(refNum,"rb");
#else
			in_fp=fdopen(refNum,"rb");
#endif
			}
		else return(nil);
		}
        else {
                if (strcmp(mode,"r") || in_fp) {
						FILE *fp;
						int omode, fd;

						if (mode[0]=='r') omode=O_RDONLY|O_BINARY;
						else if (mode[0]=='w') omode=O_WRONLY|O_CREAT|O_TRUNC;
						else omode=O_WRONLY|O_CREAT|O_APPEND;
						_fcreator='R*ch';
						_ftype='TEXT';
						fd=open(name,omode);
						_fcreator=_ftype=0;
						if (fd<0) return(nil);
						fp=fdopen(fd,(char *)mode);
						return(fp);
                        }
#ifdef USE_ZLIB
		{
			int fd;

			fd=open(name,O_RDONLY|O_BINARY);
			if (fd<0) return(nil);
			in_fp=gzdopen(fd,"rb");
			}
#else
		in_fp=fopen(name,"rb");
#endif
		}
	if (in_fp) {
		line_num=buff_cnt=buff_offset=0;
		if (!buff) buff=(char *)malloc(LOC_BUFF_SIZE);
		FillBuff(0);
		return((FILE *)in_fp);
		}
	return(nil);
	}

int
mac_fclose(FILE *file)
{
	int result;

	if ((gzFile)file==in_fp) {
#ifdef USE_ZLIB
		result=gzclose(in_fp);
#else
		result=fclose(in_fp);
#endif
		in_fp=nil;
		}
	else result=fclose(file);
	return(result);
	}

size_t
mac_fread(void *ptr,size_t size,size_t num,FILE *file)
{
	size_t total;
	long len;

	if (in_fp!=(gzFile)file) return(fread(ptr,size,num,file));
	num*=size;
	total=0;
	while (num>0) {
		if (buff_cnt<=0) return(total);
		len=buff_cnt;
		if (len>num) len=num;
		memcpy(ptr,buff+buff_offset,len);
		((char *)ptr)+=len;
		FillBuff(len);
		num-=len;
		total+=len;
		}
	return(total/size);
	}

int
mac_getc(FILE *file)
{
	int result;

	if (in_fp!=(gzFile)file) return(getc(file));
	if (buff_cnt<=0) return(EOF);
	result = *((unsigned char *)buff+buff_offset);
	FillBuff(1);
	return(result);
	}

int
mac_feof(FILE *file)
{
	if (in_fp!=(gzFile)file) return(feof(file));
	return(buff_cnt<=0);
	}

#endif
#endif

/* END OF macinput.c - read input files */
