'From Squeak3.1alpha of 4 February 2001 [latest update: #3570] on 12 February 2001 at 2:59:05 pm'! "Change Set: FileFlushFix Date: 12 February 2001 Author: Andreas Raab Fixes a typo in the file prims file."! !InterpreterSupportCode class methodsFor: 'source files' stamp: 'ar 2/12/2001 14:57'! squeakFilePrimsFile ^ '#include "sq.h" #ifndef NO_STD_FILE_SUPPORT #include "FilePlugin.h" /*** The state of a file is kept in the following structure, which is stored directly in a Squeak bytes object. NOTE: The Squeak side is responsible for creating an object with enough room to store sizeof(SQFile) bytes. The session ID is used to detect stale file objects-- files that were still open when an image was written. The file pointer of such files is meaningless. Files are always opened in binary mode; Smalltalk code does (or someday will do) line-end conversion if needed. Writeable files are opened read/write. The stdio spec requires that a positioning operation be done when switching between reading and writing of a read/write filestream. The lastOp field records whether the last operation was a read or write operation, allowing this positioning operation to be done automatically if needed. typedef struct { File *file; int sessionID; int writable; int fileSize; int lastOp; // 0 = uncommitted, 1 = read, 2 = write // } SQFile; ***/ /*** Constants ***/ #define UNCOMMITTED 0 #define READ_OP 1 #define WRITE_OP 2 #ifndef SEEK_SET #define SEEK_SET 0 #define SEEK_CUR 1 #define SEEK_END 2 #endif /*** Variables ***/ int thisSession = 0; extern struct VirtualMachine * interpreterProxy; int sqFileAtEnd(SQFile *f) { /* Return true if the file''s read/write head is at the end of the file. */ if (!!sqFileValid(f)) return interpreterProxy->success(false); return ftell(f->file) == f->fileSize; } int sqFileClose(SQFile *f) { /* Close the given file. */ if (!!sqFileValid(f)) return interpreterProxy->success(false); fclose(f->file); f->file = NULL; f->sessionID = 0; f->writable = false; f->fileSize = 0; f->lastOp = UNCOMMITTED; } int sqFileDeleteNameSize(int sqFileNameIndex, int sqFileNameSize) { char cFileName[1000]; int i, err; if (sqFileNameSize >= 1000) { return interpreterProxy->success(false); } /* copy the file name into a null-terminated C string */ sqFilenameFromString(cFileName, sqFileNameIndex, sqFileNameSize); if (!!plugInAllowAccessToFilePath(cFileName, sqFileNameSize)) { return interpreterProxy->success(false); } err = remove(cFileName); if (err) { return interpreterProxy->success(false); } } int sqFileGetPosition(SQFile *f) { /* Return the current position of the file''s read/write head. */ int position; if (!!sqFileValid(f)) return interpreterProxy->success(false); position = ftell(f->file); if (position < 0) return interpreterProxy->success(false); return position; } int sqFileInit(void) { /* Create a session ID that is unlikely to be repeated. Zero is never used for a valid session number. Should be called once at startup time. */ thisSession = clock() + time(NULL); if (thisSession == 0) thisSession = 1; /* don''t use 0 */ return 1; } int sqFileShutdown(void) { return 1; } int sqFileOpen(SQFile *f, int sqFileNameIndex, int sqFileNameSize, int writeFlag) { /* Opens the given file using the supplied sqFile structure to record its state. Fails with no side effects if f is already open. Files are always opened in binary mode; Squeak must take care of any line-end character mapping. */ char cFileName[1001]; int i; /* don''t open an already open file */ if (sqFileValid(f)) return interpreterProxy->success(false); /* copy the file name into a null-terminated C string */ if (sqFileNameSize > 1000) { return interpreterProxy->success(false); } sqFilenameFromString(cFileName, sqFileNameIndex, sqFileNameSize); if (!!plugInAllowAccessToFilePath(cFileName, sqFileNameSize)) { return interpreterProxy->success(false); } if (writeFlag) { /* First try to open an existing file read/write: */ f->file = fopen(cFileName, "r+b"); if (f->file == NULL) { /* Previous call fails if file does not exist. In that case, try opening it in write mode to create a new, empty file. */ f->file = fopen(cFileName, "w+b"); if (f->file !!= NULL) { /* set the type and creator of newly created Mac files */ dir_SetMacFileTypeAndCreator((char *)sqFileNameIndex, sqFileNameSize, "TEXT", "R*ch"); } } f->writable = true; } else { f->file = fopen(cFileName, "rb"); f->writable = false; } if (f->file == NULL) { f->sessionID = 0; f->fileSize = 0; return interpreterProxy->success(false); } else { f->sessionID = thisSession; /* compute and cache file size */ fseek(f->file, 0, SEEK_END); f->fileSize = ftell(f->file); fseek(f->file, 0, SEEK_SET); } f->lastOp = UNCOMMITTED; } int sqFileReadIntoAt(SQFile *f, int count, int byteArrayIndex, int startIndex) { /* Read count bytes from the given file into byteArray starting at startIndex. byteArray is the address of the first byte of a Squeak bytes object (e.g. String or ByteArray). startIndex is a zero-based index; that is a startIndex of 0 starts writing at the first byte of byteArray. */ char *dst; int bytesRead; if (!!sqFileValid(f)) return interpreterProxy->success(false); if (f->writable && (f->lastOp == WRITE_OP)) fseek(f->file, 0, SEEK_CUR); /* seek between writing and reading */ dst = (char *) (byteArrayIndex + startIndex); bytesRead = fread(dst, 1, count, f->file); f->lastOp = READ_OP; return bytesRead; } int sqFileRenameOldSizeNewSize(int oldNameIndex, int oldNameSize, int newNameIndex, int newNameSize) { char cOldName[1000], cNewName[1000]; int i, err; if ((oldNameSize >= 1000) || (newNameSize >= 1000)) { return interpreterProxy->success(false); } /* copy the file names into null-terminated C strings */ sqFilenameFromString(cOldName, oldNameIndex, oldNameSize); sqFilenameFromString(cNewName, newNameIndex, newNameSize); if (!!plugInAllowAccessToFilePath(cOldName, oldNameSize) || !!plugInAllowAccessToFilePath(cNewName, newNameSize)) { return interpreterProxy->success(false); } err = rename(cOldName, cNewName); if (err) { return interpreterProxy->success(false); } } int sqFileSetPosition(SQFile *f, int position) { /* Set the file''s read/write head to the given position. */ if (!!sqFileValid(f)) return interpreterProxy->success(false); fseek(f->file, position, SEEK_SET); f->lastOp = UNCOMMITTED; } int sqFileSize(SQFile *f) { /* Return the length of the given file. */ if (!!sqFileValid(f)) return interpreterProxy->success(false); return f->fileSize; } int sqFileFlush(SQFile *f) { /* Return the length of the given file. */ if (!!sqFileValid(f)) return interpreterProxy->success(false); fflush(f->file); return 1; } int sqFileValid(SQFile *f) { return ( (f !!= NULL) && (f->file !!= NULL) && (f->sessionID == thisSession)); } int sqFileWriteFromAt(SQFile *f, int count, int byteArrayIndex, int startIndex) { /* Write count bytes to the given writable file starting at startIndex in the given byteArray. (See comment in sqFileReadIntoAt for interpretation of byteArray and startIndex). */ char *src; int bytesWritten, position; if (!!(sqFileValid(f) && f->writable)) return interpreterProxy->success(false); if (f->lastOp == READ_OP) fseek(f->file, 0, SEEK_CUR); /* seek between reading and writing */ src = (char *) (byteArrayIndex + startIndex); bytesWritten = fwrite(src, 1, count, f->file); position = ftell(f->file); if (position > f->fileSize) { f->fileSize = position; /* update file size */ } if (bytesWritten !!= count) { interpreterProxy->success(false); } f->lastOp = WRITE_OP; return bytesWritten; } #endif /* NO_STD_FILE_SUPPORT */ ' ! !