/*** analog 4.13 http://www.analog.cx/ ***/ /*** This program is copyright (c) Stephen R. E. Turner 1995 - 2000 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. ***/ /*** macstuff.c; stuff only required for the Mac port ***/ /*** The contents of this file is copyright various authors as follows. ***/ /* The functions in this file inside #ifdef MAC_EVENTS are due to, and copyright, Jason Linhart (jason@summary.net), 1996. */ /* The functions in this file inside #ifdef MACDIRENT are due to Jason Linhart, January 1997. */ /* The functions in this file inside #ifdef MAC are due to Jason Linhart, March 1998. */ /* The functions in this file inside #ifndef NODNS are due to, and copyright, Jason Linhart and Stephan Somogyi, 1996, 1997. Version history: 950531 SCS First release 960716 JTL Switched to async OT calls and improved failure cases to not recheck 960927 JTL Added MacTCP support and combined check and open into OpenNetwork */ #define REAL_ALLOC #include "anlghea3.h" #ifdef MAC_EVENTS static char *cmd_vect[64] = { "analog", "-G", "+g%%%", 0 }; extern char mac_do_script[256]; extern char TryAEOpen(void); static int CmdParse(char **vect,char *cmd_line,int limit) { int count; for (count=0; count0 is open, 0 is closed, -1 is at end */ static CInfoPBRec finfo; static unsigned char fname[257]; static void CToPCpy(unsigned char *pstr, const char *cstr) { /* Convert a C string to a Pascal string */ register char *dptr, len; len=0; dptr=(char *)pstr+1; while (len<255 && (*dptr++ = *cstr++)!=0) ++len; *pstr=len; } DIR * opendir (const char *name) /* Open a directory stream on NAME. */ /* Return a DIR stream on the directory, or NULL if it could not be opened. */ { WDPBRec pb; VolumeParam vpb; HVolumeParam hvpb; int error; if (indx) { closedir((DIR *)1); return((DIR *)0); } while (name[0]=='.') ++name; finfo.hFileInfo.ioCompletion=(IOCompletionUPP)NULL; finfo.hFileInfo.ioNamePtr=fname; finfo.hFileInfo.ioFVersNum=0; finfo.hFileInfo.ioVRefNum=0; CToPCpy(fname,name); if (fname[fname[0]]!=':') { fname[fname[0]+1]=':'; ++fname[0]; } if (*name) { if (*strchr(name,':')) { if (name[0]!=':') { hvpb.ioCompletion=(IOCompletionUPP)NULL; hvpb.ioNamePtr=fname; hvpb.ioVRefNum = -1; hvpb.ioVolIndex = -1; if (!PBHGetVInfo((HParmBlkPtr)&hvpb,FALSE)) pb.ioVRefNum=hvpb.ioVRefNum; else return((DIR *)0); CToPCpy(fname,name); if (fname[fname[0]]!=':') { fname[fname[0]+1]=':'; ++fname[0]; } } else pb.ioVRefNum=0; pb.ioCompletion=(IOCompletionUPP)NULL; pb.ioNamePtr=NULL/*fname*/; pb.ioWDProcID='MAG^'; finfo.hFileInfo.ioFDirIndex=0; finfo.hFileInfo.ioDirID=0; if (!PBGetCatInfo(&finfo,FALSE)) { pb.ioWDDirID=finfo.hFileInfo.ioDirID; if (!PBOpenWD(&pb,FALSE)) finfo.hFileInfo.ioVRefNum=pb.ioVRefNum; } else return((DIR *)0); } else { vpb.ioNamePtr=hvpb.ioNamePtr=fname; vpb.ioVRefNum=hvpb.ioVRefNum=-1; hvpb.ioVolIndex=vpb.ioVolIndex=-1; if ((!(error=PBHGetVInfo((HParmBlkPtr)&hvpb,FALSE))) && hvpb.ioVDrvInfo){ vpb.ioVRefNum=hvpb.ioVRefNum; vpb.ioNamePtr=NULL; if (!PBGetVInfo((ParmBlkPtr)&vpb,FALSE)) finfo.hFileInfo.ioVRefNum=vpb.ioVRefNum; else return((DIR *)0); } else return((DIR *)0); finfo.hFileInfo.ioNamePtr=fname; } } indx=1; return((DIR *)1); } int closedir (DIR * dirp) /* Close the directory stream DIRP. Return 0 if successful, -1 if not. */ { if (indx) { PBCloseWD((WDPBPtr)&finfo,FALSE); indx=0; return(0); } return(-1); } struct dirent * readdir (DIR * dirp) /* Read a directory entry from DIRP. */ /* Return a pointer to a `struct dirent' describing the entry, or NULL for EOF or error. The storage returned may be overwritten by a later readdir call on the same DIR stream. */ { finfo.hFileInfo.ioFDirIndex=indx; finfo.hFileInfo.ioDirID=0; if (indx>0 && !PBGetCatInfo(&finfo,FALSE)) { fname[fname[0]+1]=0; ++indx; return((struct dirent *)(fname+1)); } if (indx) indx = -1; return((struct dirent *)0); } void rewinddir (DIR * dirp) /* Rewind DIRP to the beginning of the directory. */ { if (indx) indx=1; } void seekdir (DIR * dirp, off_t pos) /* Seek to position POS on DIRP. */ { if (indx && pos>0) indx=pos; } off_t telldir (DIR * dirp) /* Return the current position of DIRP. */ { return((indx>0)?indx:-1); } int dirstat(const char *file_name, struct stat *buf) /* Special version of stat that only works for most recent dir entry */ { if (indx) { if (finfo.hFileInfo.ioFlAttrib&0x10) buf->st_mode=S_IFDIR; else buf->st_mode=S_IFREG; return(0); } return(-1); } #endif #ifdef MAC #ifndef NODNS static long OpenNetwork(void); /* Takes a string of an IP address in *hostname, resolves it to a domain name, and returns the name in *hostname. Returns nil if unresolvable (or something else went wrong), otherwise returns 1. */ /* URL processing and host lookup */ static long slNetChecked = 0, slNetPresent = 0, slNetSvcOpen = 0; static ResultUPP gMacTCPDNRResultProcUPP = nil; typedef struct { /* Open Transport Internet services provider info */ InetSvcRef ref; /* provider reference */ Boolean done; /* true when asynch operation has completed */ OTResult result; /* result code */ void *cookie; /* cookie */ } SvcInfo; static SvcInfo sSvcRef; int IpAddr2Name(char *hostname) { struct hostInfo hInfoMacTCP; OSStatus lStatus; OSErr err; InetHost lHostAddr; int cnt, tmp; char *cptr; Boolean done; if (!slNetChecked) { slNetPresent = OpenNetwork(); slNetChecked = 1; } if (slNetPresent == 1) { /* turn ascii with periods into a long */ lStatus = OTInetStringToHost(hostname, &lHostAddr); if (lStatus != noErr) return 0; /* turn the long into a reverse-resolved name */ sSvcRef.done=false; lStatus=OTInetAddressToName(sSvcRef.ref,lHostAddr,hostname); if (!lStatus) { do { MacIdle(); } while (!sSvcRef.done); lStatus=sSvcRef.result; } if (!lStatus) { if (hostname[strlen(hostname)-1]=='.') hostname[strlen(hostname)-1]=0; return(1); } } else if (slNetPresent==2) { lHostAddr=0; cptr=hostname; for (cnt=0; cnt<4; ++cnt) { if (!ISDIGIT(*cptr)) return(0); tmp=atoi(cptr); if (tmp<0 || tmp>255) return(0); lHostAddr=(lHostAddr<<8)|tmp; while (ISDIGIT(*cptr)) ++cptr; if (cnt!=3 && *cptr!='.') return(0); ++cptr; } memset(&hInfoMacTCP, 0, sizeof(hInfoMacTCP)); done=false; err = AddrToName(lHostAddr, &hInfoMacTCP, gMacTCPDNRResultProcUPP, (char*)&done); if (err == cacheFault) { while (!done) MacIdle(); err = hInfoMacTCP.rtnCode; } if (err == noErr) { hInfoMacTCP.cname[254] = 0; (void)strcpy(hostname, hInfoMacTCP.cname); if (hostname[strlen(hostname)-1]=='.') hostname[strlen(hostname)-1]=0; return(1); } } return 0; } /* end IpAddr2Name() */ /* Must call this before quitting app */ void ResolverCleanup(void) { if (slNetChecked && slNetSvcOpen) { if (slNetPresent==1) OTCloseProvider(sSvcRef.ref); else if (slNetPresent==2) CloseResolver(); } } /* end ResolverCleanup() */ /* #pragma mark - */ /* Check for availbility of OT/TCP 1.1 or later, or MacTCP and open the service. Return nil if it isn't. */ static pascal void SvcNotifyProc(void *dataPtr,OTEventCode code,OTResult result,void *cookie) { register SvcInfo *svcInfo; svcInfo=(SvcInfo *)dataPtr; svcInfo->done=true; svcInfo->result=result; svcInfo->cookie=cookie; } static Boolean OpenInetServices(SvcInfo *svcInfo) { OSStatus result; svcInfo->done=false; result=OTAsyncOpenInternetServices(kDefaultInternetServicesPath, 0, SvcNotifyProc, svcInfo); if (!result) { do { MacIdle(); } while (!svcInfo->done); result=svcInfo->result; } if (result) return(false); svcInfo->ref=(InetSvcRef)svcInfo->cookie; return(true); } static pascal void MacTCPDNRResultProc (struct hostInfo *hInfoPtr, char *userDataPtr) { *(Boolean*)userDataPtr = true; } static long OpenNetwork(void) { OSStatus lStatus; OSErr err; long lResponse, lCriteria; err = Gestalt(gestaltOpenTpt, &lResponse); if (err == noErr) { /* Older OpenTransport Headers require that thenext line read: lCriteria = gestaltOpenTptPresent + gestaltOpenTptTCPPresent; */ lCriteria = gestaltOpenTptPresentMask + gestaltOpenTptTCPPresentMask; lResponse = lCriteria & lResponse; if (lResponse == lCriteria) { lStatus = InitOpenTransport(); if (lStatus == noErr) { if (OpenInetServices(&sSvcRef)) { slNetSvcOpen=1; return(1); } } return(0); /* OT present, but won't open */ } } else { gMacTCPDNRResultProcUPP = NewResultProc(MacTCPDNRResultProc); err = OpenResolver(nil); if (err == noErr) { slNetSvcOpen=1; return(2); } } return(0); } /* end OpenNetwork() */ #endif #endif #ifdef MAC #define MY_MAGIC_ONE 0x3748596A #define MY_MAGIC_TWO 0xA7958473 #define MY_BIG_SIZE (32*1024) #define MY_BLOCK_SIZE (4*(MY_BIG_SIZE+3*sizeof(long))) #if MY_BIG_SIZE!=BLOCKSIZE Look into this! They should be the same, but changes would require other adjustments. #endif static long my_cur_avail = 0; static char *my_cur_block; static struct my_block { struct my_block **next; char storage[MY_BLOCK_SIZE]; } **temp_mem_blocks = nil; static struct my_free { struct my_free *next; char storage[MY_BIG_SIZE-sizeof(struct my_free *)]; } *my_free_list = nil; void mac_temp_free(void); void mac_temp_free(void) { OSErr result; struct my_block **block, **next; block=temp_mem_blocks; while (block) { next=(*block)->next; TempDisposeHandle((Handle)block,&result); if (result) break; block=next; } } static void * my_temp_malloc(size_t size) { OSErr result; struct my_block **block; long version; char *ret_ptr; size=(size+3)&~3; if (Gestalt(gestaltSystemVersion,&version) || version<0x700) return(nil); if (size>MY_BLOCK_SIZE) { if (TempFreeMem()<1024*1024+size) return(nil); block=(struct my_block **)TempNewHandle(size+sizeof(struct my_block **),&result); if (!block || !*block || result) return(nil); TempHLock((Handle)block,&result); (*block)->next=temp_mem_blocks; temp_mem_blocks=block; return((void *)&(*block)->storage); } if (size>my_cur_avail) { if (TempFreeMem()<1024*1024+MY_BLOCK_SIZE) return(nil); block=(struct my_block **)TempNewHandle(sizeof(struct my_block),&result); if (!block || !*block || result) return(nil); TempHLock((Handle)block,&result); (*block)->next=temp_mem_blocks; temp_mem_blocks=block; my_cur_block=(*block)->storage; my_cur_avail=MY_BLOCK_SIZE; } ret_ptr=my_cur_block; my_cur_block+=size; my_cur_avail-=size; return((void *)ret_ptr); } #define MAC_LEAVE_FREE (64*1024) static void * sub_mac_malloc(size_t size) { char *ret_ptr; size=(size+3)&~3; if (size>=MY_BIG_SIZE) { if (MaxBlock()<=MAC_LEAVE_FREE+size) return(my_temp_malloc(size)); return(malloc(size)); } if (size>my_cur_avail) { if (MaxBlock()=MY_BIG_SIZE) { if (size==MY_BIG_SIZE && my_free_list) { ptr=(long *)my_free_list; my_free_list=my_free_list->next; } else { size+=(size/MY_BIG_SIZE)*3*sizeof(long); ptr=(long *)sub_mac_malloc(size); if (ptr) { *ptr++ = size; *ptr++ = MY_MAGIC_ONE; *ptr++ = MY_MAGIC_TWO; } } } else ptr=(long *)sub_mac_malloc(size); return((void *)ptr); } void * mac_calloc(size_t num,size_t size) { return(mac_malloc(num*size)); } void * mac_realloc(void *ptr,size_t size) { void *new_blk; if (!size || !(new_blk=mac_malloc(size))) return(nil); memcpy(new_blk,ptr,size); mac_free(ptr); return(new_blk); } void mac_free(void *ptr) { struct my_free *blk; long *lptr, size; lptr=(long *)ptr; if (lptr) { lptr-=3; if (lptr[1]==MY_MAGIC_ONE && lptr[2]==MY_MAGIC_TWO) { size = *lptr + 3*sizeof(long); while (size>=MY_BIG_SIZE+3*sizeof(long)) { blk=(struct my_free *)(lptr+3); blk->next=my_free_list; my_free_list=blk; *lptr=MY_BIG_SIZE+3*sizeof(long); lptr[1]=MY_MAGIC_ONE; lptr[2]=MY_MAGIC_TWO; lptr+=(MY_BIG_SIZE/sizeof(long))+3; size-=MY_BIG_SIZE+3*sizeof(long); } } } } #endif