summaryrefslogtreecommitdiffstats
path: root/stand/ficl/fileaccess.c
diff options
context:
space:
mode:
Diffstat (limited to 'stand/ficl/fileaccess.c')
-rw-r--r--stand/ficl/fileaccess.c425
1 files changed, 425 insertions, 0 deletions
diff --git a/stand/ficl/fileaccess.c b/stand/ficl/fileaccess.c
new file mode 100644
index 0000000..2b981c8
--- /dev/null
+++ b/stand/ficl/fileaccess.c
@@ -0,0 +1,425 @@
+/* $FreeBSD$ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include "ficl.h"
+
+#if FICL_WANT_FILE
+/*
+**
+** fileaccess.c
+**
+** Implements all of the File Access word set that can be implemented in portable C.
+**
+*/
+
+static void pushIor(FICL_VM *pVM, int success)
+{
+ int ior;
+ if (success)
+ ior = 0;
+ else
+ ior = errno;
+ stackPushINT(pVM->pStack, ior);
+}
+
+
+
+static void ficlFopen(FICL_VM *pVM, char *writeMode) /* ( c-addr u fam -- fileid ior ) */
+{
+ int fam = stackPopINT(pVM->pStack);
+ int length = stackPopINT(pVM->pStack);
+ void *address = (void *)stackPopPtr(pVM->pStack);
+ char mode[4];
+ FILE *f;
+
+ char *filename = (char *)alloca(length + 1);
+ memcpy(filename, address, length);
+ filename[length] = 0;
+
+ *mode = 0;
+
+ switch (FICL_FAM_OPEN_MODE(fam))
+ {
+ case 0:
+ stackPushPtr(pVM->pStack, NULL);
+ stackPushINT(pVM->pStack, EINVAL);
+ return;
+ case FICL_FAM_READ:
+ strcat(mode, "r");
+ break;
+ case FICL_FAM_WRITE:
+ strcat(mode, writeMode);
+ break;
+ case FICL_FAM_READ | FICL_FAM_WRITE:
+ strcat(mode, writeMode);
+ strcat(mode, "+");
+ break;
+ }
+
+ strcat(mode, (fam & FICL_FAM_BINARY) ? "b" : "t");
+
+ f = fopen(filename, mode);
+ if (f == NULL)
+ stackPushPtr(pVM->pStack, NULL);
+ else
+ {
+ ficlFILE *ff = (ficlFILE *)malloc(sizeof(ficlFILE));
+ strcpy(ff->filename, filename);
+ ff->f = f;
+ stackPushPtr(pVM->pStack, ff);
+
+ fseek(f, 0, SEEK_SET);
+ }
+ pushIor(pVM, f != NULL);
+}
+
+
+
+static void ficlOpenFile(FICL_VM *pVM) /* ( c-addr u fam -- fileid ior ) */
+{
+ ficlFopen(pVM, "a");
+}
+
+
+static void ficlCreateFile(FICL_VM *pVM) /* ( c-addr u fam -- fileid ior ) */
+{
+ ficlFopen(pVM, "w");
+}
+
+
+static int closeFiclFILE(ficlFILE *ff) /* ( fileid -- ior ) */
+{
+ FILE *f = ff->f;
+ free(ff);
+ return !fclose(f);
+}
+
+static void ficlCloseFile(FICL_VM *pVM) /* ( fileid -- ior ) */
+{
+ ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
+ pushIor(pVM, closeFiclFILE(ff));
+}
+
+static void ficlDeleteFile(FICL_VM *pVM) /* ( c-addr u -- ior ) */
+{
+ int length = stackPopINT(pVM->pStack);
+ void *address = (void *)stackPopPtr(pVM->pStack);
+
+ char *filename = (char *)alloca(length + 1);
+ memcpy(filename, address, length);
+ filename[length] = 0;
+
+ pushIor(pVM, !unlink(filename));
+}
+
+static void ficlRenameFile(FICL_VM *pVM) /* ( c-addr1 u1 c-addr2 u2 -- ior ) */
+{
+ int length;
+ void *address;
+ char *from;
+ char *to;
+
+ length = stackPopINT(pVM->pStack);
+ address = (void *)stackPopPtr(pVM->pStack);
+ to = (char *)alloca(length + 1);
+ memcpy(to, address, length);
+ to[length] = 0;
+
+ length = stackPopINT(pVM->pStack);
+ address = (void *)stackPopPtr(pVM->pStack);
+
+ from = (char *)alloca(length + 1);
+ memcpy(from, address, length);
+ from[length] = 0;
+
+ pushIor(pVM, !rename(from, to));
+}
+
+static void ficlFileStatus(FICL_VM *pVM) /* ( c-addr u -- x ior ) */
+{
+ struct stat statbuf;
+
+ int length = stackPopINT(pVM->pStack);
+ void *address = (void *)stackPopPtr(pVM->pStack);
+
+ char *filename = (char *)alloca(length + 1);
+ memcpy(filename, address, length);
+ filename[length] = 0;
+
+ if (stat(filename, &statbuf) == 0)
+ {
+ /*
+ ** the "x" left on the stack is implementation-defined.
+ ** I push the file's access mode (readable, writeable, is directory, etc)
+ ** as defined by ANSI C.
+ */
+ stackPushINT(pVM->pStack, statbuf.st_mode);
+ stackPushINT(pVM->pStack, 0);
+ }
+ else
+ {
+ stackPushINT(pVM->pStack, -1);
+ stackPushINT(pVM->pStack, ENOENT);
+ }
+}
+
+
+static void ficlFilePosition(FICL_VM *pVM) /* ( fileid -- ud ior ) */
+{
+ ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
+ long ud = ftell(ff->f);
+ stackPushINT(pVM->pStack, ud);
+ pushIor(pVM, ud != -1);
+}
+
+
+
+static long fileSize(FILE *f)
+{
+ struct stat statbuf;
+ statbuf.st_size = -1;
+ if (fstat(fileno(f), &statbuf) != 0)
+ return -1;
+ return statbuf.st_size;
+}
+
+
+
+static void ficlFileSize(FICL_VM *pVM) /* ( fileid -- ud ior ) */
+{
+ ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
+ long ud = fileSize(ff->f);
+ stackPushINT(pVM->pStack, ud);
+ pushIor(pVM, ud != -1);
+}
+
+
+
+#define nLINEBUF 256
+static void ficlIncludeFile(FICL_VM *pVM) /* ( i*x fileid -- j*x ) */
+{
+ ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
+ CELL id = pVM->sourceID;
+ int result = VM_OUTOFTEXT;
+ long currentPosition, totalSize;
+ long size;
+ pVM->sourceID.p = (void *)ff;
+
+ currentPosition = ftell(ff->f);
+ totalSize = fileSize(ff->f);
+ size = totalSize - currentPosition;
+
+ if ((totalSize != -1) && (currentPosition != -1) && (size > 0))
+ {
+ char *buffer = (char *)malloc(size);
+ long got = fread(buffer, 1, size, ff->f);
+ if (got == size)
+ result = ficlExecC(pVM, buffer, size);
+ }
+
+#if 0
+ ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
+ CELL id = pVM->sourceID;
+ char cp[nLINEBUF];
+ int nLine = 0;
+ int keepGoing;
+ int result;
+ pVM->sourceID.p = (void *)ff;
+
+ /* feed each line to ficlExec */
+ keepGoing = TRUE;
+ while (keepGoing && fgets(cp, nLINEBUF, ff->f))
+ {
+ int len = strlen(cp) - 1;
+
+ nLine++;
+ if (len <= 0)
+ continue;
+
+ if (cp[len] == '\n')
+ cp[len] = '\0';
+
+ result = ficlExec(pVM, cp);
+
+ switch (result)
+ {
+ case VM_OUTOFTEXT:
+ case VM_USEREXIT:
+ break;
+
+ default:
+ pVM->sourceID = id;
+ keepGoing = FALSE;
+ break;
+ }
+ }
+#endif /* 0 */
+ /*
+ ** Pass an empty line with SOURCE-ID == -1 to flush
+ ** any pending REFILLs (as required by FILE wordset)
+ */
+ pVM->sourceID.i = -1;
+ ficlExec(pVM, "");
+
+ pVM->sourceID = id;
+ closeFiclFILE(ff);
+}
+
+
+
+static void ficlReadFile(FICL_VM *pVM) /* ( c-addr u1 fileid -- u2 ior ) */
+{
+ ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
+ int length = stackPopINT(pVM->pStack);
+ void *address = (void *)stackPopPtr(pVM->pStack);
+ int result;
+
+ clearerr(ff->f);
+ result = fread(address, 1, length, ff->f);
+
+ stackPushINT(pVM->pStack, result);
+ pushIor(pVM, ferror(ff->f) == 0);
+}
+
+
+
+static void ficlReadLine(FICL_VM *pVM) /* ( c-addr u1 fileid -- u2 flag ior ) */
+{
+ ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
+ int length = stackPopINT(pVM->pStack);
+ char *address = (char *)stackPopPtr(pVM->pStack);
+ int error;
+ int flag;
+
+ if (feof(ff->f))
+ {
+ stackPushINT(pVM->pStack, -1);
+ stackPushINT(pVM->pStack, 0);
+ stackPushINT(pVM->pStack, 0);
+ return;
+ }
+
+ clearerr(ff->f);
+ *address = 0;
+ fgets(address, length, ff->f);
+
+ error = ferror(ff->f);
+ if (error != 0)
+ {
+ stackPushINT(pVM->pStack, -1);
+ stackPushINT(pVM->pStack, 0);
+ stackPushINT(pVM->pStack, error);
+ return;
+ }
+
+ length = strlen(address);
+ flag = (length > 0);
+ if (length && ((address[length - 1] == '\r') || (address[length - 1] == '\n')))
+ length--;
+
+ stackPushINT(pVM->pStack, length);
+ stackPushINT(pVM->pStack, flag);
+ stackPushINT(pVM->pStack, 0); /* ior */
+}
+
+
+
+static void ficlWriteFile(FICL_VM *pVM) /* ( c-addr u1 fileid -- ior ) */
+{
+ ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
+ int length = stackPopINT(pVM->pStack);
+ void *address = (void *)stackPopPtr(pVM->pStack);
+
+ clearerr(ff->f);
+ fwrite(address, 1, length, ff->f);
+ pushIor(pVM, ferror(ff->f) == 0);
+}
+
+
+
+static void ficlWriteLine(FICL_VM *pVM) /* ( c-addr u1 fileid -- ior ) */
+{
+ ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
+ size_t length = (size_t)stackPopINT(pVM->pStack);
+ void *address = (void *)stackPopPtr(pVM->pStack);
+
+ clearerr(ff->f);
+ if (fwrite(address, 1, length, ff->f) == length)
+ fwrite("\n", 1, 1, ff->f);
+ pushIor(pVM, ferror(ff->f) == 0);
+}
+
+
+
+static void ficlRepositionFile(FICL_VM *pVM) /* ( ud fileid -- ior ) */
+{
+ ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
+ size_t ud = (size_t)stackPopINT(pVM->pStack);
+
+ pushIor(pVM, fseek(ff->f, ud, SEEK_SET) == 0);
+}
+
+
+
+static void ficlFlushFile(FICL_VM *pVM) /* ( fileid -- ior ) */
+{
+ ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
+ pushIor(pVM, fflush(ff->f) == 0);
+}
+
+
+
+#if FICL_HAVE_FTRUNCATE
+
+static void ficlResizeFile(FICL_VM *pVM) /* ( ud fileid -- ior ) */
+{
+ ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
+ size_t ud = (size_t)stackPopINT(pVM->pStack);
+
+ pushIor(pVM, ftruncate(fileno(ff->f), ud) == 0);
+}
+
+#endif /* FICL_HAVE_FTRUNCATE */
+
+#endif /* FICL_WANT_FILE */
+
+
+
+void ficlCompileFile(FICL_SYSTEM *pSys)
+{
+#if FICL_WANT_FILE
+ FICL_DICT *dp = pSys->dp;
+ assert(dp);
+
+ dictAppendWord(dp, "create-file", ficlCreateFile, FW_DEFAULT);
+ dictAppendWord(dp, "open-file", ficlOpenFile, FW_DEFAULT);
+ dictAppendWord(dp, "close-file", ficlCloseFile, FW_DEFAULT);
+ dictAppendWord(dp, "include-file", ficlIncludeFile, FW_DEFAULT);
+ dictAppendWord(dp, "read-file", ficlReadFile, FW_DEFAULT);
+ dictAppendWord(dp, "read-line", ficlReadLine, FW_DEFAULT);
+ dictAppendWord(dp, "write-file", ficlWriteFile, FW_DEFAULT);
+ dictAppendWord(dp, "write-line", ficlWriteLine, FW_DEFAULT);
+ dictAppendWord(dp, "file-position", ficlFilePosition, FW_DEFAULT);
+ dictAppendWord(dp, "file-size", ficlFileSize, FW_DEFAULT);
+ dictAppendWord(dp, "reposition-file", ficlRepositionFile, FW_DEFAULT);
+ dictAppendWord(dp, "file-status", ficlFileStatus, FW_DEFAULT);
+ dictAppendWord(dp, "flush-file", ficlFlushFile, FW_DEFAULT);
+
+ dictAppendWord(dp, "delete-file", ficlDeleteFile, FW_DEFAULT);
+ dictAppendWord(dp, "rename-file", ficlRenameFile, FW_DEFAULT);
+
+#ifdef FICL_HAVE_FTRUNCATE
+ dictAppendWord(dp, "resize-file", ficlResizeFile, FW_DEFAULT);
+
+ ficlSetEnv(pSys, "file", FICL_TRUE);
+ ficlSetEnv(pSys, "file-ext", FICL_TRUE);
+#endif /* FICL_HAVE_FTRUNCATE */
+#else
+ (void)pSys;
+#endif /* FICL_WANT_FILE */
+}
OpenPOWER on IntegriCloud