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 (void)pSys; 424 #endif /* FICL_WANT_FILE */ 425 } 426