1 /* $FreeBSD$ */
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
20 static 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
32 static 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
83 static void ficlOpenFile(FICL_VM *pVM) /* ( c-addr u fam -- fileid ior ) */
84 {
85 ficlFopen(pVM, "a");
86 }
87
88
89 static void ficlCreateFile(FICL_VM *pVM) /* ( c-addr u fam -- fileid ior ) */
90 {
91 ficlFopen(pVM, "w");
92 }
93
94
95 static int closeFiclFILE(ficlFILE *ff) /* ( fileid -- ior ) */
96 {
97 FILE *f = ff->f;
98 free(ff);
99 return !fclose(f);
100 }
101
102 static void ficlCloseFile(FICL_VM *pVM) /* ( fileid -- ior ) */
103 {
104 ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
105 pushIor(pVM, closeFiclFILE(ff));
106 }
107
108 static 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
120 static 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
143 static 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
172 static 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
182 static 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
193 static 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
204 static 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
275 static 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
291 static 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
332 static 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
345 static 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
359 static 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
369 static 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
379 static 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
393 void 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 }
Cache object: e7594f216f26c4fd81a683bb4dda5c47
|