fileaccess.c revision 94290
1/* $FreeBSD: head/sys/boot/ficl/fileaccess.c 94290 2002-04-09 17:45:28Z dcs $ */
2
3#include <errno.h>
4#include <stdlib.h>
5#include <stdio.h>
6#include <string.h>
7#include <ctype.h>
8#include <sys/stat.h>
9#include "ficl.h"
10
11#if FICL_WANT_FILE
12/*
13**
14** fileaccess.c
15**
16** Implements all of the File Access word set that can be implemented in portable C.
17**
18*/
19
20static void pushIor(FICL_VM *pVM, int success)
21{
22    int ior;
23    if (success)
24        ior = 0;
25    else
26        ior = errno;
27    stackPushINT(pVM->pStack, ior);
28}
29
30
31
32static void ficlFopen(FICL_VM *pVM, char *writeMode) /* ( c-addr u fam -- fileid ior ) */
33{
34    int fam = stackPopINT(pVM->pStack);
35    int length = stackPopINT(pVM->pStack);
36    void *address = (void *)stackPopPtr(pVM->pStack);
37    char mode[4];
38    FILE *f;
39
40    char *filename = (char *)alloca(length + 1);
41    memcpy(filename, address, length);
42    filename[length] = 0;
43
44    *mode = 0;
45
46    switch (FICL_FAM_OPEN_MODE(fam))
47        {
48        case 0:
49            stackPushPtr(pVM->pStack, NULL);
50            stackPushINT(pVM->pStack, EINVAL);
51            return;
52        case FICL_FAM_READ:
53            strcat(mode, "r");
54            break;
55        case FICL_FAM_WRITE:
56            strcat(mode, writeMode);
57            break;
58        case FICL_FAM_READ | FICL_FAM_WRITE:
59            strcat(mode, writeMode);
60            strcat(mode, "+");
61            break;
62        }
63
64    strcat(mode, (fam & FICL_FAM_BINARY) ? "b" : "t");
65
66    f = fopen(filename, mode);
67    if (f == NULL)
68        stackPushPtr(pVM->pStack, NULL);
69    else
70        {
71        ficlFILE *ff = (ficlFILE *)malloc(sizeof(ficlFILE));
72        strcpy(ff->filename, filename);
73        ff->f = f;
74        stackPushPtr(pVM->pStack, ff);
75
76        fseek(f, 0, SEEK_SET);
77        }
78    pushIor(pVM, f != NULL);
79}
80
81
82
83static void ficlOpenFile(FICL_VM *pVM) /* ( c-addr u fam -- fileid ior ) */
84{
85    ficlFopen(pVM, "a");
86}
87
88
89static void ficlCreateFile(FICL_VM *pVM) /* ( c-addr u fam -- fileid ior ) */
90{
91    ficlFopen(pVM, "w");
92}
93
94
95static int closeFiclFILE(ficlFILE *ff) /* ( fileid -- ior ) */
96{
97    FILE *f = ff->f;
98    free(ff);
99    return !fclose(f);
100}
101
102static void ficlCloseFile(FICL_VM *pVM) /* ( fileid -- ior ) */
103{
104    ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
105    pushIor(pVM, closeFiclFILE(ff));
106}
107
108static void ficlDeleteFile(FICL_VM *pVM) /* ( c-addr u -- ior ) */
109{
110    int length = stackPopINT(pVM->pStack);
111    void *address = (void *)stackPopPtr(pVM->pStack);
112
113    char *filename = (char *)alloca(length + 1);
114    memcpy(filename, address, length);
115    filename[length] = 0;
116
117    pushIor(pVM, !unlink(filename));
118}
119
120static void ficlRenameFile(FICL_VM *pVM) /* ( c-addr1 u1 c-addr2 u2 -- ior ) */
121{
122    int length;
123    void *address;
124    char *from;
125    char *to;
126
127    length = stackPopINT(pVM->pStack);
128    address = (void *)stackPopPtr(pVM->pStack);
129    to = (char *)alloca(length + 1);
130    memcpy(to, address, length);
131    to[length] = 0;
132
133    length = stackPopINT(pVM->pStack);
134    address = (void *)stackPopPtr(pVM->pStack);
135
136    from = (char *)alloca(length + 1);
137    memcpy(from, address, length);
138    from[length] = 0;
139
140    pushIor(pVM, !rename(from, to));
141}
142
143static void ficlFileStatus(FICL_VM *pVM) /* ( c-addr u -- x ior ) */
144{
145    struct stat statbuf;
146
147    int length = stackPopINT(pVM->pStack);
148    void *address = (void *)stackPopPtr(pVM->pStack);
149
150    char *filename = (char *)alloca(length + 1);
151    memcpy(filename, address, length);
152    filename[length] = 0;
153
154    if (stat(filename, &statbuf) == 0)
155    {
156        /*
157        ** the "x" left on the stack is implementation-defined.
158        ** I push the file's access mode (readable, writeable, is directory, etc)
159        ** as defined by ANSI C.
160        */
161        stackPushINT(pVM->pStack, statbuf.st_mode);
162        stackPushINT(pVM->pStack, 0);
163    }
164    else
165    {
166        stackPushINT(pVM->pStack, -1);
167        stackPushINT(pVM->pStack, ENOENT);
168    }
169}
170
171
172static void ficlFilePosition(FICL_VM *pVM) /* ( fileid -- ud ior ) */
173{
174    ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
175    long ud = ftell(ff->f);
176    stackPushINT(pVM->pStack, ud);
177    pushIor(pVM, ud != -1);
178}
179
180
181
182static long fileSize(FILE *f)
183{
184    struct stat statbuf;
185    statbuf.st_size = -1;
186    if (fstat(fileno(f), &statbuf) != 0)
187        return -1;
188    return statbuf.st_size;
189}
190
191
192
193static void ficlFileSize(FICL_VM *pVM) /* ( fileid -- ud ior ) */
194{
195    ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
196    long ud = fileSize(ff->f);
197    stackPushINT(pVM->pStack, ud);
198    pushIor(pVM, ud != -1);
199}
200
201
202
203#define nLINEBUF 256
204static void ficlIncludeFile(FICL_VM *pVM) /* ( i*x fileid -- j*x ) */
205{
206    ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
207    CELL id = pVM->sourceID;
208    int     result = VM_OUTOFTEXT;
209    long currentPosition, totalSize;
210    long size;
211    pVM->sourceID.p = (void *)ff;
212
213    currentPosition = ftell(ff->f);
214    totalSize = fileSize(ff->f);
215    size = totalSize - currentPosition;
216
217    if ((totalSize != -1) && (currentPosition != -1) && (size > 0))
218        {
219        char *buffer = (char *)malloc(size);
220        long got = fread(buffer, 1, size, ff->f);
221        if (got == size)
222            result = ficlExecC(pVM, buffer, size);
223        }
224
225#if 0
226    ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
227    CELL id = pVM->sourceID;
228    char    cp[nLINEBUF];
229    int     nLine = 0;
230    int     keepGoing;
231    int     result;
232    pVM->sourceID.p = (void *)ff;
233
234    /* feed each line to ficlExec */
235    keepGoing = TRUE;
236    while (keepGoing && fgets(cp, nLINEBUF, ff->f))
237    {
238        int len = strlen(cp) - 1;
239
240        nLine++;
241        if (len <= 0)
242            continue;
243
244        if (cp[len] == '\n')
245            cp[len] = '\0';
246
247        result = ficlExec(pVM, cp);
248
249        switch (result)
250        {
251            case VM_OUTOFTEXT:
252            case VM_USEREXIT:
253                break;
254
255            default:
256                pVM->sourceID = id;
257                keepGoing = FALSE;
258                break;
259        }
260    }
261#endif /* 0 */
262    /*
263    ** Pass an empty line with SOURCE-ID == -1 to flush
264    ** any pending REFILLs (as required by FILE wordset)
265    */
266    pVM->sourceID.i = -1;
267    ficlExec(pVM, "");
268
269    pVM->sourceID = id;
270    closeFiclFILE(ff);
271}
272
273
274
275static void ficlReadFile(FICL_VM *pVM) /* ( c-addr u1 fileid -- u2 ior ) */
276{
277    ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
278    int length = stackPopINT(pVM->pStack);
279    void *address = (void *)stackPopPtr(pVM->pStack);
280    int result;
281
282    clearerr(ff->f);
283    result = fread(address, 1, length, ff->f);
284
285    stackPushINT(pVM->pStack, result);
286    pushIor(pVM, ferror(ff->f) == 0);
287}
288
289
290
291static void ficlReadLine(FICL_VM *pVM) /* ( c-addr u1 fileid -- u2 flag ior ) */
292{
293    ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
294    int length = stackPopINT(pVM->pStack);
295    char *address = (char *)stackPopPtr(pVM->pStack);
296    int error;
297    int flag;
298
299    if (feof(ff->f))
300        {
301        stackPushINT(pVM->pStack, -1);
302        stackPushINT(pVM->pStack, 0);
303        stackPushINT(pVM->pStack, 0);
304        return;
305        }
306
307    clearerr(ff->f);
308    *address = 0;
309    fgets(address, length, ff->f);
310
311    error = ferror(ff->f);
312    if (error != 0)
313        {
314        stackPushINT(pVM->pStack, -1);
315        stackPushINT(pVM->pStack, 0);
316        stackPushINT(pVM->pStack, error);
317        return;
318        }
319
320    length = strlen(address);
321    flag = (length > 0);
322    if (length && ((address[length - 1] == '\r') || (address[length - 1] == '\n')))
323        length--;
324
325    stackPushINT(pVM->pStack, length);
326    stackPushINT(pVM->pStack, flag);
327    stackPushINT(pVM->pStack, 0); /* ior */
328}
329
330
331
332static void ficlWriteFile(FICL_VM *pVM) /* ( c-addr u1 fileid -- ior ) */
333{
334    ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
335    int length = stackPopINT(pVM->pStack);
336    void *address = (void *)stackPopPtr(pVM->pStack);
337
338    clearerr(ff->f);
339    fwrite(address, 1, length, ff->f);
340    pushIor(pVM, ferror(ff->f) == 0);
341}
342
343
344
345static void ficlWriteLine(FICL_VM *pVM) /* ( c-addr u1 fileid -- ior ) */
346{
347    ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
348    size_t length = (size_t)stackPopINT(pVM->pStack);
349    void *address = (void *)stackPopPtr(pVM->pStack);
350
351    clearerr(ff->f);
352    if (fwrite(address, 1, length, ff->f) == length)
353        fwrite("\n", 1, 1, ff->f);
354    pushIor(pVM, ferror(ff->f) == 0);
355}
356
357
358
359static void ficlRepositionFile(FICL_VM *pVM) /* ( ud fileid -- ior ) */
360{
361    ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
362    size_t ud = (size_t)stackPopINT(pVM->pStack);
363
364    pushIor(pVM, fseek(ff->f, ud, SEEK_SET) == 0);
365}
366
367
368
369static void ficlFlushFile(FICL_VM *pVM) /* ( fileid -- ior ) */
370{
371    ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
372    pushIor(pVM, fflush(ff->f) == 0);
373}
374
375
376
377#if FICL_HAVE_FTRUNCATE
378
379static void ficlResizeFile(FICL_VM *pVM) /* ( ud fileid -- ior ) */
380{
381    ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
382    size_t ud = (size_t)stackPopINT(pVM->pStack);
383
384    pushIor(pVM, ftruncate(fileno(ff->f), ud) == 0);
385}
386
387#endif /* FICL_HAVE_FTRUNCATE */
388
389#endif /* FICL_WANT_FILE */
390
391
392
393void ficlCompileFile(FICL_SYSTEM *pSys)
394{
395#if FICL_WANT_FILE
396    FICL_DICT *dp = pSys->dp;
397    assert(dp);
398
399    dictAppendWord(dp, "create-file", ficlCreateFile,  FW_DEFAULT);
400    dictAppendWord(dp, "open-file", ficlOpenFile,  FW_DEFAULT);
401    dictAppendWord(dp, "close-file", ficlCloseFile,  FW_DEFAULT);
402    dictAppendWord(dp, "include-file", ficlIncludeFile,  FW_DEFAULT);
403    dictAppendWord(dp, "read-file", ficlReadFile,  FW_DEFAULT);
404    dictAppendWord(dp, "read-line", ficlReadLine,  FW_DEFAULT);
405    dictAppendWord(dp, "write-file", ficlWriteFile,  FW_DEFAULT);
406    dictAppendWord(dp, "write-line", ficlWriteLine,  FW_DEFAULT);
407    dictAppendWord(dp, "file-position", ficlFilePosition,  FW_DEFAULT);
408    dictAppendWord(dp, "file-size", ficlFileSize,  FW_DEFAULT);
409    dictAppendWord(dp, "reposition-file", ficlRepositionFile,  FW_DEFAULT);
410    dictAppendWord(dp, "file-status", ficlFileStatus,  FW_DEFAULT);
411    dictAppendWord(dp, "flush-file", ficlFlushFile,  FW_DEFAULT);
412
413    dictAppendWord(dp, "delete-file", ficlDeleteFile,  FW_DEFAULT);
414    dictAppendWord(dp, "rename-file", ficlRenameFile,  FW_DEFAULT);
415
416#ifdef FICL_HAVE_FTRUNCATE
417    dictAppendWord(dp, "resize-file", ficlResizeFile,  FW_DEFAULT);
418
419    ficlSetEnv(pSys, "file", FICL_TRUE);
420    ficlSetEnv(pSys, "file-ext", FICL_TRUE);
421#endif /* FICL_HAVE_FTRUNCATE */
422#else
423    &pSys;
424#endif /* FICL_WANT_FILE */
425}
426