|  | 
 | /* | 
 |  *  fopenRF.c -- Clone of fopen.c to open Mac resource forks. | 
 |  * | 
 |  *  Copyright (c) 1989 Symantec Corporation.  All rights reserved. | 
 |  * | 
 |  */ | 
 |  | 
 | #include "stdio.h" | 
 | #include "errno.h" | 
 | #include "string.h" | 
 | #include "ansi_private.h" | 
 |  | 
 | FILE *fopenRF(char *, char *); | 
 | FILE *freopenRF(char *, char *, FILE *); | 
 | FILE *__openRF(char *, int, int, FILE *); | 
 |  | 
 | #include <Files.h> | 
 |  | 
 | #define fcbVPtr(fcb)		(* (VCB **) (fcb + 20)) | 
 | #define fcbDirID(fcb)		(* (long *) (fcb + 58)) | 
 | #define fcbCName(fcb)		(fcb + 62) | 
 |  | 
 | static void setfiletype(StringPtr, int); | 
 | static void stdio_exit(void); | 
 | static int fileio(FILE *, int); | 
 | static int close(FILE *); | 
 | static void replace(unsigned char *, size_t, int, int); | 
 |  | 
 |  | 
 | FILE * | 
 | fopenRF(filename, mode) | 
 | char *filename, *mode; | 
 | { | 
 | 	return(freopenRF(filename, mode, __getfile())); | 
 | } | 
 |  | 
 |  | 
 | FILE * | 
 | freopenRF(filename, mode, fp) | 
 | char *filename; | 
 | register char *mode; | 
 | register FILE *fp; | 
 | { | 
 | 	int omode, oflag; | 
 | 	 | 
 | 		/*  interpret "rwa"  */ | 
 | 	 | 
 | 	if (mode[0] == 'r') { | 
 | 		omode = fsRdPerm; | 
 | 		oflag = 0; | 
 | 	} | 
 | 	else if (mode[0] == 'w') { | 
 | 		omode = fsWrPerm; | 
 | 		oflag = F_CREAT+F_TRUNC; | 
 | 	} | 
 | 	else if (mode[0] == 'a') { | 
 | 		omode = fsWrPerm; | 
 | 		oflag = F_CREAT+F_APPEND; | 
 | 	} | 
 | 	else { | 
 | 		errno = EINVAL; | 
 | 		return(NULL); | 
 | 	} | 
 | 		 | 
 | 		/*  interpret "b+"  */ | 
 | 		 | 
 | 	if (mode[1] == 'b') { | 
 | 		oflag |= F_BINARY; | 
 | 		if (mode[2] == '+') | 
 | 			omode = fsRdWrPerm; | 
 | 	} | 
 | 	else if (mode[1] == '+') { | 
 | 		omode = fsRdWrPerm; | 
 | 		if (mode[2] == 'b') | 
 | 			oflag |= F_BINARY; | 
 | 	} | 
 | 	 | 
 | 		/*  open the file  */ | 
 | 		 | 
 | 	return(__openRF(filename, omode, oflag, fp)); | 
 | } | 
 |  | 
 |  | 
 | FILE * | 
 | __openRF(filename, omode, oflag, fp) | 
 | char *filename; | 
 | int omode, oflag; | 
 | register FILE *fp; | 
 | { | 
 | 	ioParam pb; | 
 | 	char pname[FILENAME_MAX]; | 
 |  | 
 | 	if (fp == NULL) | 
 | 		return(NULL); | 
 | 	fclose(fp); | 
 | 	 | 
 | 		/*  set up pb  */ | 
 | 	 | 
 | 	pb.ioNamePtr = __c2p(filename, pname); | 
 | 	pb.ioVRefNum = 0; | 
 | 	pb.ioVersNum = 0; | 
 | 	pb.ioPermssn = omode; | 
 | 	pb.ioMisc = 0; | 
 |  | 
 | 		/*  create file  */ | 
 |  | 
 | 	if (oflag & F_CREAT) { | 
 | 		asm { | 
 | 			lea		pb,a0 | 
 | 			_PBCreate | 
 | 		} | 
 | 		if (pb.ioResult == noErr) | 
 | 			oflag &= ~F_TRUNC; | 
 | 		else if (pb.ioResult == dupFNErr && !(oflag & F_EXCL)) | 
 | 			oflag &= ~F_CREAT; | 
 | 		else { | 
 | 			errno = pb.ioResult; | 
 | 			return(NULL); | 
 | 		} | 
 | 	} | 
 | 	 | 
 | 		/*  open resource file  */ | 
 | 		 | 
 | 	asm { | 
 | 		lea		pb,a0 | 
 | 		_PBOpenRF | 
 | 	} | 
 | 	if (pb.ioResult) { | 
 | 		errno = pb.ioResult; | 
 | 		if (oflag & F_CREAT) asm { | 
 | 			lea		pb,a0 | 
 | 			_PBDelete | 
 | 		} | 
 | 		return(NULL); | 
 | 	} | 
 | 	fp->refnum = pb.ioRefNum; | 
 | 	 | 
 | 		/*  get/set file length  */ | 
 | 		 | 
 | 	if (oflag & F_TRUNC) asm { | 
 | 		lea		pb,a0 | 
 | 		_PBSetEOF | 
 | 	} | 
 | 	else if (!(oflag & F_CREAT)) asm { | 
 | 		lea		pb,a0 | 
 | 		_PBGetEOF | 
 | 	} | 
 | 	fp->len = (fpos_t) pb.ioMisc; | 
 | 		 | 
 | 		/*  initialize rest of FILE structure  */ | 
 | 		 | 
 | 	if (oflag & F_APPEND) { | 
 | 		fp->append = 1; | 
 | 		fp->pos = fp->len; | 
 | 	} | 
 | 	if (oflag & F_BINARY) | 
 | 		fp->binary = 1; | 
 | 	setvbuf(fp, NULL, _IOFBF, BUFSIZ); | 
 | 	fp->proc = fileio; | 
 |  | 
 | 		/*  set file type  */ | 
 |  | 
 | 	if (oflag & (F_CREAT|F_TRUNC)) | 
 | 		setfiletype(pb.ioNamePtr, oflag); | 
 | 		 | 
 | 		/*  done  */ | 
 | 		 | 
 | 	__atexit_stdio(stdio_exit); | 
 | 	return(fp); | 
 | } | 
 |  | 
 |  | 
 | /* | 
 |  *  setfiletype - set type/creator of new file | 
 |  * | 
 |  */ | 
 |  | 
 | static void | 
 | setfiletype(name, oflag) | 
 | StringPtr name; | 
 | int oflag; | 
 | { | 
 | 	fileParam pb; | 
 | 	 | 
 | 	pb.ioNamePtr = name; | 
 | 	pb.ioVRefNum = 0; | 
 | 	pb.ioFVersNum = 0; | 
 | 	pb.ioFDirIndex = 0; | 
 | 	asm { | 
 | 		lea		pb,a0 | 
 | 		_PBGetFInfo | 
 | 		bmi.s	@1 | 
 | 	} | 
 | 	pb.ioFlFndrInfo.fdType = pb.ioFlFndrInfo.fdCreator = '????'; | 
 | 	if (!(oflag & F_BINARY)) | 
 | 		pb.ioFlFndrInfo.fdType = 'TEXT'; | 
 | 	asm { | 
 | 		lea		pb,a0 | 
 | 		_PBSetFInfo | 
 | @1	} | 
 | } | 
 |  | 
 |  | 
 | /* | 
 |  *  stdio_exit - stdio shutdown routine | 
 |  * | 
 |  */ | 
 |  | 
 | static void | 
 | stdio_exit() | 
 | { | 
 | 	register FILE *fp; | 
 | 	int n; | 
 | 	 | 
 | 	for (fp = &__file[0], n = FOPEN_MAX; n--; fp++) | 
 | 		fclose(fp); | 
 | } | 
 |  | 
 |  | 
 | /* | 
 |  *  fileio - I/O handler proc for files and devices | 
 |  * | 
 |  */ | 
 |  | 
 | static int | 
 | fileio(fp, i) | 
 | register FILE *fp; | 
 | int i; | 
 | { | 
 | 	ioParam pb; | 
 | 	 | 
 | 	pb.ioRefNum = fp->refnum; | 
 | 	switch (i) { | 
 | 	 | 
 | 				/*  read  */ | 
 | 			 | 
 | 		case 0: | 
 | 			pb.ioBuffer = (Ptr) fp->ptr; | 
 | 			pb.ioReqCount = fp->cnt; | 
 | 			pb.ioPosMode = fp->refnum > 0 ? fsFromStart : fsAtMark; | 
 | 			pb.ioPosOffset = fp->pos - fp->cnt; | 
 | 			asm { | 
 | 				lea		pb,a0 | 
 | 				_PBRead | 
 | 			} | 
 | 			if (pb.ioResult == eofErr) { | 
 | 				fp->pos = pb.ioPosOffset; | 
 | 				if (fp->cnt = pb.ioActCount) | 
 | 					pb.ioResult = 0; | 
 | 				else { | 
 | 					fp->eof = 1; | 
 | 					return(EOF); | 
 | 				} | 
 | 			} | 
 | 			if (pb.ioResult) { | 
 | 				fp->pos -= fp->cnt; | 
 | 				fp->cnt = 0; | 
 | 			} | 
 | 			else if (!fp->binary) | 
 | 				replace(fp->ptr, fp->cnt, '\r', '\n'); | 
 | 			break; | 
 | 			 | 
 | 				/*  write  */ | 
 |  | 
 | 		case 1: | 
 | 			pb.ioBuffer = (Ptr) fp->ptr; | 
 | 			pb.ioReqCount = fp->cnt; | 
 | 			pb.ioPosMode = fp->refnum > 0 ? fsFromStart : fsAtMark; | 
 | 			if ((pb.ioPosOffset = fp->pos - fp->cnt) > fp->len) { | 
 | 				pb.ioMisc = (Ptr) pb.ioPosOffset; | 
 | 				asm { | 
 | 					lea		pb,a0 | 
 | 					_PBSetEOF | 
 | 					bmi.s	@1 | 
 | 				} | 
 | 			} | 
 | 			if (!fp->binary) | 
 | 				replace(fp->ptr, fp->cnt, '\n', '\r'); | 
 | 			asm { | 
 | 				lea		pb,a0 | 
 | 				_PBWrite | 
 | @1			} | 
 | 			if (pb.ioResult) { | 
 | 				fp->pos -= fp->cnt; | 
 | 				fp->cnt = 0; | 
 | 			} | 
 | 			else if (pb.ioPosOffset > fp->len) | 
 | 				fp->len = pb.ioPosOffset; | 
 | 			break; | 
 | 			 | 
 | 				/*  close  */ | 
 |  | 
 | 		case 2: | 
 | 			pb.ioResult = close(fp); | 
 | 			break; | 
 | 	} | 
 | 	 | 
 | 		/*  done  */ | 
 | 		 | 
 | 	if (pb.ioResult) { | 
 | 		fp->err = 1; | 
 | 		errno = pb.ioResult; | 
 | 		return(EOF); | 
 | 	} | 
 | 	return(0); | 
 | } | 
 |  | 
 |  | 
 | static int | 
 | close(fp) | 
 | register FILE *fp; | 
 | { | 
 | 	HFileParam pb; | 
 | 	Str255 buf; | 
 | 	register char *fcb = FCBSPtr + fp->refnum; | 
 | 	VCB *vcb = fcbVPtr(fcb); | 
 | 	register char *s; | 
 | 	 | 
 | 	pb.ioNamePtr = buf; | 
 | 	pb.ioFRefNum = fp->refnum; | 
 | 	pb.ioVRefNum = vcb->vcbVRefNum; | 
 | 	pb.ioFVersNum = 0; | 
 | 	 | 
 | 		/*  close temporary file - HFS  */ | 
 | 		 | 
 | 	if (fp->delete && vcb->vcbSigWord == 0x4244) { | 
 | 		pb.ioDirID = fcbDirID(fcb); | 
 | 		s = fcbCName(fcb); | 
 | 		asm { | 
 | 			lea		buf,a0 | 
 | 			moveq	#0,d0 | 
 | 			move.b	(s),d0 | 
 | @1			move.b	(s)+,(a0)+ | 
 | 			dbra	d0,@1 | 
 | 			lea		pb,a0 | 
 | 			_PBClose | 
 | 			bmi.s	@9 | 
 | 			_PBHDelete | 
 | 		} | 
 | 	} | 
 | 	 | 
 | 		/*  close temporary file - MFS  */ | 
 | 		 | 
 | 	else if (fp->delete && vcb->vcbSigWord == 0xD2D7) { | 
 | 		pb.ioFDirIndex = 1; | 
 | 		do asm { | 
 | 			lea		pb,a0 | 
 | 			_PBGetFInfo | 
 | 			bmi.s	@2 | 
 | 			addq.w	#1,pb.ioFDirIndex | 
 | 		} while (pb.ioFRefNum != fp->refnum); | 
 | 		asm { | 
 | 			lea		pb,a0 | 
 | 			_PBClose | 
 | 			bmi.s	@9 | 
 | 			_PBDelete | 
 | 		} | 
 | 	} | 
 | 	 | 
 | 		/*  normal case - just close file  */ | 
 | 		 | 
 | 	else { | 
 | 		asm { | 
 | @2			lea		pb,a0 | 
 | 			_PBClose | 
 | 			bmi.s	@9 | 
 | 		} | 
 | 	} | 
 | 	 | 
 | 		/*  flush volume buffer  */ | 
 | 		 | 
 | 	pb.ioNamePtr = 0; | 
 | 	asm { | 
 | 		lea		pb,a0 | 
 | 		_PBFlshVol | 
 | @9	} | 
 | 	return(pb.ioResult); | 
 | } | 
 |  | 
 |  | 
 | /* | 
 |  *  replace - routine for doing CR/LF conversion | 
 |  * | 
 |  */ | 
 |  | 
 | static void | 
 | replace(s, n, c1, c2) | 
 | register unsigned char *s; | 
 | register size_t n; | 
 | register int c1, c2; | 
 | { | 
 | 	register unsigned char *t; | 
 | 	 | 
 | 	for (; n && (t = memchr(s, c1, n)); s = t) { | 
 | 		*t++ = c2; | 
 | 		n -= t - s; | 
 | 	} | 
 | } |