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