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 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#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 90static void ficlOpenFile(FICL_VM *pVM) /* ( c-addr u fam -- fileid ior ) */ 91{ 92 ficlFopen(pVM, "a"); 93} 94 95 96static void ficlCreateFile(FICL_VM *pVM) /* ( c-addr u fam -- fileid ior ) */ 97{ 98 ficlFopen(pVM, "w"); 99} 100 101 102static int closeFiclFILE(ficlFILE *ff) /* ( fileid -- ior ) */ 103{ 104 FILE *f = ff->f; 105 free(ff); 106 return !fclose(f); 107} 108 109static void ficlCloseFile(FICL_VM *pVM) /* ( fileid -- ior ) */ 110{ 111 ficlFILE *ff = (ficlFILE *)stackPopPtr(pVM->pStack); 112 pushIor(pVM, closeFiclFILE(ff)); 113} 114 115static 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 127static 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 150static 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 179static 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 189static 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 200static 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 211static 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 282static 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 298static 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 339static 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 352static 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 366static 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 376static 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 386static 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 400void 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