| |
| /* |
| * fopen.c |
| * |
| * Copyright (c) 1991 Symantec Corporation. All rights reserved. |
| * |
| */ |
| |
| #include <MacHeaders> |
| |
| #include "stdio.h" |
| #include "errno.h" |
| #include "string.h" |
| #include "ansi_private.h" |
| |
| extern long _ftype, _fcreator; |
| |
| #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 *freopenRF(); |
| FILE *__openRF(); |
| |
| FILE * |
| fopenRF(const char *filename, const char *mode) |
| { |
| return(freopenRF(filename, mode, __getfile())); |
| } |
| |
| |
| FILE * |
| freopenRF(const char *filename, const char *mode, 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(const char *filename, int omode, int oflag, 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) { |
| PBCreateSync((ParmBlkPtr)&pb); |
| 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 file */ |
| |
| PBOpenRFSync((ParmBlkPtr)&pb); |
| if (pb.ioResult) { |
| errno = pb.ioResult; |
| if (oflag & F_CREAT) |
| PBDeleteSync((ParmBlkPtr)&pb); |
| return(NULL); |
| } |
| fp->refnum = pb.ioRefNum; |
| |
| /* get/set file length */ |
| |
| if (oflag & F_TRUNC) |
| PBSetEOFSync((ParmBlkPtr)&pb); |
| else if (!(oflag & F_CREAT)) |
| PBGetEOFSync((ParmBlkPtr)&pb); |
| 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(StringPtr name, int oflag) |
| { |
| FileParam pb; |
| |
| pb.ioNamePtr = name; |
| pb.ioVRefNum = 0; |
| pb.ioFVersNum = 0; |
| pb.ioFDirIndex = 0; |
| if (PBGetFInfoSync((ParmBlkPtr)&pb) == noErr) { |
| if (oflag & F_BINARY) |
| pb.ioFlFndrInfo.fdType = _ftype; |
| else |
| pb.ioFlFndrInfo.fdType = 'TEXT'; |
| pb.ioFlFndrInfo.fdCreator = _fcreator; |
| PBSetFInfoSync((ParmBlkPtr)&pb); |
| } |
| } |
| |
| |
| /* |
| * stdio_exit - stdio shutdown routine |
| * |
| */ |
| |
| static void |
| stdio_exit(void) |
| { |
| 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(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; |
| PBReadSync((ParmBlkPtr)&pb); |
| 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->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; |
| if (PBSetEOFSync((ParmBlkPtr)&pb) != noErr) |
| break; |
| } |
| if (!fp->binary) |
| replace(fp->ptr, fp->cnt, '\n', '\r'); |
| PBWriteSync((ParmBlkPtr)&pb); |
| if (!pb.ioResult && pb.ioPosOffset > fp->len) |
| fp->len = pb.ioPosOffset; |
| break; |
| |
| /* close */ |
| |
| case 2: |
| pb.ioResult = close(fp); |
| break; |
| } |
| |
| /* done */ |
| |
| if (pb.ioResult) { |
| if (i < 2) { |
| fp->pos -= fp->cnt; |
| fp->cnt = 0; |
| } |
| fp->err = 1; |
| errno = pb.ioResult; |
| return(EOF); |
| } |
| return(0); |
| } |
| |
| |
| static int |
| close(FILE *fp) |
| { |
| HFileParam pb; |
| Str255 buf; |
| register char *fcb = FCBSPtr + fp->refnum; |
| VCB *vcb = fcbVPtr(fcb); |
| register char *s; |
| enum { none, MFS, HFS } del = none; |
| |
| pb.ioVRefNum = vcb->vcbVRefNum; |
| if (fp->remove) { |
| pb.ioNamePtr = buf; |
| pb.ioFVersNum = 0; |
| |
| /* close temporary file - HFS */ |
| |
| if (vcb->vcbSigWord == 0x4244) { |
| pb.ioDirID = fcbDirID(fcb); |
| s = fcbCName(fcb); |
| memcpy(buf, s, Length(s) + 1); |
| del = HFS; |
| } |
| |
| /* close temporary file - MFS */ |
| |
| else if (vcb->vcbSigWord == 0xD2D7) { |
| for (pb.ioFDirIndex = 1; PBGetFInfoSync((ParmBlkPtr)&pb) == noErr; pb.ioFDirIndex++) { |
| if (pb.ioFRefNum == fp->refnum) { |
| del = MFS; |
| break; |
| } |
| } |
| } |
| } |
| |
| /* close file and flush volume buffer */ |
| |
| pb.ioFRefNum = fp->refnum; |
| if (PBCloseSync((ParmBlkPtr)&pb) == noErr) { |
| if (del == MFS) |
| PBDeleteSync((ParmBlkPtr)&pb); |
| else if (del == HFS) |
| PBHDeleteSync((HParmBlkPtr)&pb); |
| pb.ioNamePtr = 0; |
| PBFlushVolSync((ParmBlkPtr)&pb); |
| } |
| return(pb.ioResult); |
| } |
| |
| |
| /* |
| * replace - routine for doing CR/LF conversion |
| * |
| */ |
| |
| static void |
| replace(register unsigned char *s, register size_t n, register int c1, register int c2) |
| { |
| #pragma options(honor_register) |
| register unsigned char *t; |
| |
| for (; n && (t = memchr(s, c1, n)); s = t) { |
| *t++ = c2; |
| n -= t - s; |
| } |
| } |