ota: Merge 20240728 (bsd-feature) from ota 3319c34a8713
[freebsd/src.git] / stand / ficl / fileaccess.c
bloba66262fb2bf34eee30edbae1e70fdfde643b916a
2 #include <errno.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <ctype.h>
7 #include <sys/stat.h>
8 #include "ficl.h"
10 #if FICL_WANT_FILE
13 ** fileaccess.c
15 ** Implements all of the File Access word set that can be implemented in portable C.
19 static void pushIor(FICL_VM *pVM, int success)
21 int ior;
22 if (success)
23 ior = 0;
24 else
25 ior = errno;
26 stackPushINT(pVM->pStack, ior);
31 static void ficlFopen(FICL_VM *pVM, char *writeMode) /* ( c-addr u fam -- fileid ior ) */
33 int fam = stackPopINT(pVM->pStack);
34 int length = stackPopINT(pVM->pStack);
35 void *address = (void *)stackPopPtr(pVM->pStack);
36 char mode[4];
37 FILE *f;
39 char *filename = (char *)alloca(length + 1);
40 memcpy(filename, address, length);
41 filename[length] = 0;
43 *mode = 0;
45 switch (FICL_FAM_OPEN_MODE(fam))
47 case 0:
48 stackPushPtr(pVM->pStack, NULL);
49 stackPushINT(pVM->pStack, EINVAL);
50 return;
51 case FICL_FAM_READ:
52 strcat(mode, "r");
53 break;
54 case FICL_FAM_WRITE:
55 strcat(mode, writeMode);
56 break;
57 case FICL_FAM_READ | FICL_FAM_WRITE:
58 strcat(mode, writeMode);
59 strcat(mode, "+");
60 break;
63 strcat(mode, (fam & FICL_FAM_BINARY) ? "b" : "t");
65 f = fopen(filename, mode);
66 if (f == NULL)
67 stackPushPtr(pVM->pStack, NULL);
68 else
69 #ifdef LOADER_VERIEXEC
70 if (*mode == 'r' &&
71 verify_file(fileno(f), filename, 0, VE_GUESS, __func__) < 0) {
72 fclose(f);
73 stackPushPtr(pVM->pStack, NULL);
74 } else
75 #endif
77 ficlFILE *ff = (ficlFILE *)malloc(sizeof(ficlFILE));
78 strcpy(ff->filename, filename);
79 ff->f = f;
80 stackPushPtr(pVM->pStack, ff);
82 fseek(f, 0, SEEK_SET);
84 pushIor(pVM, f != NULL);
89 static void ficlOpenFile(FICL_VM *pVM) /* ( c-addr u fam -- fileid ior ) */
91 ficlFopen(pVM, "a");
95 static void ficlCreateFile(FICL_VM *pVM) /* ( c-addr u fam -- fileid ior ) */
97 ficlFopen(pVM, "w");
101 static int closeFiclFILE(ficlFILE *ff) /* ( fileid -- ior ) */
103 FILE *f = ff->f;
104 free(ff);
105 return !fclose(f);
108 static void ficlCloseFile(FICL_VM *pVM) /* ( fileid -- ior ) */
110 ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
111 pushIor(pVM, closeFiclFILE(ff));
114 static void ficlDeleteFile(FICL_VM *pVM) /* ( c-addr u -- ior ) */
116 int length = stackPopINT(pVM->pStack);
117 void *address = (void *)stackPopPtr(pVM->pStack);
119 char *filename = (char *)alloca(length + 1);
120 memcpy(filename, address, length);
121 filename[length] = 0;
123 pushIor(pVM, !unlink(filename));
126 static void ficlRenameFile(FICL_VM *pVM) /* ( c-addr1 u1 c-addr2 u2 -- ior ) */
128 int length;
129 void *address;
130 char *from;
131 char *to;
133 length = stackPopINT(pVM->pStack);
134 address = (void *)stackPopPtr(pVM->pStack);
135 to = (char *)alloca(length + 1);
136 memcpy(to, address, length);
137 to[length] = 0;
139 length = stackPopINT(pVM->pStack);
140 address = (void *)stackPopPtr(pVM->pStack);
142 from = (char *)alloca(length + 1);
143 memcpy(from, address, length);
144 from[length] = 0;
146 pushIor(pVM, !rename(from, to));
149 static void ficlFileStatus(FICL_VM *pVM) /* ( c-addr u -- x ior ) */
151 struct stat statbuf;
153 int length = stackPopINT(pVM->pStack);
154 void *address = (void *)stackPopPtr(pVM->pStack);
156 char *filename = (char *)alloca(length + 1);
157 memcpy(filename, address, length);
158 filename[length] = 0;
160 if (stat(filename, &statbuf) == 0)
163 ** the "x" left on the stack is implementation-defined.
164 ** I push the file's access mode (readable, writeable, is directory, etc)
165 ** as defined by ANSI C.
167 stackPushINT(pVM->pStack, statbuf.st_mode);
168 stackPushINT(pVM->pStack, 0);
170 else
172 stackPushINT(pVM->pStack, -1);
173 stackPushINT(pVM->pStack, ENOENT);
178 static void ficlFilePosition(FICL_VM *pVM) /* ( fileid -- ud ior ) */
180 ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
181 long ud = ftell(ff->f);
182 stackPushINT(pVM->pStack, ud);
183 pushIor(pVM, ud != -1);
188 static long fileSize(FILE *f)
190 struct stat statbuf;
191 statbuf.st_size = -1;
192 if (fstat(fileno(f), &statbuf) != 0)
193 return -1;
194 return statbuf.st_size;
199 static void ficlFileSize(FICL_VM *pVM) /* ( fileid -- ud ior ) */
201 ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
202 long ud = fileSize(ff->f);
203 stackPushINT(pVM->pStack, ud);
204 pushIor(pVM, ud != -1);
209 #define nLINEBUF 256
210 static void ficlIncludeFile(FICL_VM *pVM) /* ( i*x fileid -- j*x ) */
212 ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
213 CELL id = pVM->sourceID;
214 int result = VM_OUTOFTEXT;
215 long currentPosition, totalSize;
216 long size;
217 pVM->sourceID.p = (void *)ff;
219 currentPosition = ftell(ff->f);
220 totalSize = fileSize(ff->f);
221 size = totalSize - currentPosition;
223 if ((totalSize != -1) && (currentPosition != -1) && (size > 0))
225 char *buffer = (char *)malloc(size);
226 long got = fread(buffer, 1, size, ff->f);
227 if (got == size)
228 result = ficlExecC(pVM, buffer, size);
231 #if 0
232 ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
233 CELL id = pVM->sourceID;
234 char cp[nLINEBUF];
235 int nLine = 0;
236 int keepGoing;
237 int result;
238 pVM->sourceID.p = (void *)ff;
240 /* feed each line to ficlExec */
241 keepGoing = TRUE;
242 while (keepGoing && fgets(cp, nLINEBUF, ff->f))
244 int len = strlen(cp) - 1;
246 nLine++;
247 if (len <= 0)
248 continue;
250 if (cp[len] == '\n')
251 cp[len] = '\0';
253 result = ficlExec(pVM, cp);
255 switch (result)
257 case VM_OUTOFTEXT:
258 case VM_USEREXIT:
259 break;
261 default:
262 pVM->sourceID = id;
263 keepGoing = FALSE;
264 break;
267 #endif /* 0 */
269 ** Pass an empty line with SOURCE-ID == -1 to flush
270 ** any pending REFILLs (as required by FILE wordset)
272 pVM->sourceID.i = -1;
273 ficlExec(pVM, "");
275 pVM->sourceID = id;
276 closeFiclFILE(ff);
281 static void ficlReadFile(FICL_VM *pVM) /* ( c-addr u1 fileid -- u2 ior ) */
283 ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
284 int length = stackPopINT(pVM->pStack);
285 void *address = (void *)stackPopPtr(pVM->pStack);
286 int result;
288 clearerr(ff->f);
289 result = fread(address, 1, length, ff->f);
291 stackPushINT(pVM->pStack, result);
292 pushIor(pVM, ferror(ff->f) == 0);
297 static void ficlReadLine(FICL_VM *pVM) /* ( c-addr u1 fileid -- u2 flag ior ) */
299 ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
300 int length = stackPopINT(pVM->pStack);
301 char *address = (char *)stackPopPtr(pVM->pStack);
302 int error;
303 int flag;
305 if (feof(ff->f))
307 stackPushINT(pVM->pStack, -1);
308 stackPushINT(pVM->pStack, 0);
309 stackPushINT(pVM->pStack, 0);
310 return;
313 clearerr(ff->f);
314 *address = 0;
315 fgets(address, length, ff->f);
317 error = ferror(ff->f);
318 if (error != 0)
320 stackPushINT(pVM->pStack, -1);
321 stackPushINT(pVM->pStack, 0);
322 stackPushINT(pVM->pStack, error);
323 return;
326 length = strlen(address);
327 flag = (length > 0);
328 if (length && ((address[length - 1] == '\r') || (address[length - 1] == '\n')))
329 length--;
331 stackPushINT(pVM->pStack, length);
332 stackPushINT(pVM->pStack, flag);
333 stackPushINT(pVM->pStack, 0); /* ior */
338 static void ficlWriteFile(FICL_VM *pVM) /* ( c-addr u1 fileid -- ior ) */
340 ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
341 int length = stackPopINT(pVM->pStack);
342 void *address = (void *)stackPopPtr(pVM->pStack);
344 clearerr(ff->f);
345 fwrite(address, 1, length, ff->f);
346 pushIor(pVM, ferror(ff->f) == 0);
351 static void ficlWriteLine(FICL_VM *pVM) /* ( c-addr u1 fileid -- ior ) */
353 ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
354 size_t length = (size_t)stackPopINT(pVM->pStack);
355 void *address = (void *)stackPopPtr(pVM->pStack);
357 clearerr(ff->f);
358 if (fwrite(address, 1, length, ff->f) == length)
359 fwrite("\n", 1, 1, ff->f);
360 pushIor(pVM, ferror(ff->f) == 0);
365 static void ficlRepositionFile(FICL_VM *pVM) /* ( ud fileid -- ior ) */
367 ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
368 size_t ud = (size_t)stackPopINT(pVM->pStack);
370 pushIor(pVM, fseek(ff->f, ud, SEEK_SET) == 0);
375 static void ficlFlushFile(FICL_VM *pVM) /* ( fileid -- ior ) */
377 ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
378 pushIor(pVM, fflush(ff->f) == 0);
383 #if FICL_HAVE_FTRUNCATE
385 static void ficlResizeFile(FICL_VM *pVM) /* ( ud fileid -- ior ) */
387 ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack);
388 size_t ud = (size_t)stackPopINT(pVM->pStack);
390 pushIor(pVM, ftruncate(fileno(ff->f), ud) == 0);
393 #endif /* FICL_HAVE_FTRUNCATE */
395 #endif /* FICL_WANT_FILE */
399 void ficlCompileFile(FICL_SYSTEM *pSys)
401 #if FICL_WANT_FILE
402 FICL_DICT *dp = pSys->dp;
403 assert(dp);
405 dictAppendWord(dp, "create-file", ficlCreateFile, FW_DEFAULT);
406 dictAppendWord(dp, "open-file", ficlOpenFile, FW_DEFAULT);
407 dictAppendWord(dp, "close-file", ficlCloseFile, FW_DEFAULT);
408 dictAppendWord(dp, "include-file", ficlIncludeFile, FW_DEFAULT);
409 dictAppendWord(dp, "read-file", ficlReadFile, FW_DEFAULT);
410 dictAppendWord(dp, "read-line", ficlReadLine, FW_DEFAULT);
411 dictAppendWord(dp, "write-file", ficlWriteFile, FW_DEFAULT);
412 dictAppendWord(dp, "write-line", ficlWriteLine, FW_DEFAULT);
413 dictAppendWord(dp, "file-position", ficlFilePosition, FW_DEFAULT);
414 dictAppendWord(dp, "file-size", ficlFileSize, FW_DEFAULT);
415 dictAppendWord(dp, "reposition-file", ficlRepositionFile, FW_DEFAULT);
416 dictAppendWord(dp, "file-status", ficlFileStatus, FW_DEFAULT);
417 dictAppendWord(dp, "flush-file", ficlFlushFile, FW_DEFAULT);
419 dictAppendWord(dp, "delete-file", ficlDeleteFile, FW_DEFAULT);
420 dictAppendWord(dp, "rename-file", ficlRenameFile, FW_DEFAULT);
422 #ifdef FICL_HAVE_FTRUNCATE
423 dictAppendWord(dp, "resize-file", ficlResizeFile, FW_DEFAULT);
425 ficlSetEnv(pSys, "file", FICL_TRUE);
426 ficlSetEnv(pSys, "file-ext", FICL_TRUE);
427 #endif /* FICL_HAVE_FTRUNCATE */
428 #else
429 (void)pSys;
430 #endif /* FICL_WANT_FILE */