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