400 lines
6.2 KiB
C
400 lines
6.2 KiB
C
|
|
/*
|
|
* 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;
|
|
}
|
|
}
|