1 /* 2 * Copyright (c) 2000 Daniel Capo Sobral 3 * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 /* 29 * l o a d e r . c 30 * Additional FICL words designed for FreeBSD's loader 31 */ 32 33 #ifndef _STANDALONE 34 #include <sys/types.h> 35 #include <sys/stat.h> 36 #include <dirent.h> 37 #include <fcntl.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <unistd.h> 41 #include <strings.h> 42 #include <termios.h> 43 #else 44 #include <stand.h> 45 #include <gfx_fb.h> 46 #include "bootstrap.h" 47 #endif 48 #ifdef _STANDALONE 49 #include <uuid.h> 50 #else 51 #include <uuid/uuid.h> 52 #endif 53 #include <string.h> 54 #include <gfx_fb.h> 55 #include "ficl.h" 56 57 /* 58 * FreeBSD's loader interaction words and extras 59 * 60 * setenv ( value n name n' -- ) 61 * setenv? ( value n name n' flag -- ) 62 * getenv ( addr n -- addr' n' | -1 ) 63 * unsetenv ( addr n -- ) 64 * copyin ( addr addr' len -- ) 65 * copyout ( addr addr' len -- ) 66 * findfile ( name len type len' -- addr ) 67 * ccall ( [[...[p10] p9] ... p1] n addr -- result ) 68 * uuid-from-string ( addr n -- addr' ) 69 * uuid-to-string ( addr' -- addr n | -1 ) 70 * .# ( value -- ) 71 */ 72 73 /* ( flags x1 y1 x2 y2 -- flag ) */ 74 void 75 ficl_fb_putimage(ficlVm *pVM) 76 { 77 char *namep, *name; 78 ficlUnsigned names; 79 ficlInteger ret = FICL_FALSE; 80 uint32_t x1, y1, x2, y2, f; 81 png_t png; 82 83 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 7, 1); 84 85 names = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 86 namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM)); 87 y2 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 88 x2 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 89 y1 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 90 x1 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 91 f = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 92 93 name = ficlMalloc(names + 1); 94 if (!name) 95 ficlVmThrowError(pVM, "Error: out of memory"); 96 (void) strncpy(name, namep, names); 97 name[names] = '\0'; 98 99 if (png_open(&png, name) == PNG_NO_ERROR) { 100 if (gfx_fb_putimage(&png, x1, y1, x2, y2, f) == 0) 101 ret = FICL_TRUE; /* success */ 102 png_close(&png); 103 } 104 ficlFree(name); 105 ficlStackPushInteger(ficlVmGetDataStack(pVM), ret); 106 } 107 108 void 109 ficl_fb_setpixel(ficlVm *pVM) 110 { 111 ficlUnsigned x, y; 112 113 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 0); 114 115 y = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 116 x = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 117 gfx_fb_setpixel(x, y); 118 } 119 120 void 121 ficl_fb_line(ficlVm *pVM) 122 { 123 ficlUnsigned x0, y0, x1, y1, wd; 124 125 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 5, 0); 126 127 wd = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 128 y1 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 129 x1 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 130 y0 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 131 x0 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 132 gfx_fb_line(x0, y0, x1, y1, wd); 133 } 134 135 void 136 ficl_fb_bezier(ficlVm *pVM) 137 { 138 ficlUnsigned x0, y0, x1, y1, x2, y2, width; 139 140 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 7, 0); 141 142 width = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 143 y2 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 144 x2 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 145 y1 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 146 x1 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 147 y0 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 148 x0 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 149 gfx_fb_bezier(x0, y0, x1, y1, x2, y2, width); 150 } 151 152 void 153 ficl_fb_drawrect(ficlVm *pVM) 154 { 155 ficlUnsigned x1, x2, y1, y2, fill; 156 157 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 5, 0); 158 159 fill = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 160 y2 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 161 x2 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 162 y1 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 163 x1 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 164 gfx_fb_drawrect(x1, y1, x2, y2, fill); 165 } 166 167 void 168 ficl_term_drawrect(ficlVm *pVM) 169 { 170 ficlUnsigned x1, x2, y1, y2; 171 172 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 4, 0); 173 174 y2 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 175 x2 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 176 y1 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 177 x1 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); 178 gfx_term_drawrect(x1, y1, x2, y2); 179 } 180 181 void 182 ficlSetenv(ficlVm *pVM) 183 { 184 char *name, *value; 185 char *namep, *valuep; 186 int names, values; 187 188 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 4, 0); 189 190 names = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 191 namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM)); 192 values = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 193 valuep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM)); 194 195 name = (char *)ficlMalloc(names+1); 196 if (!name) 197 ficlVmThrowError(pVM, "Error: out of memory"); 198 strncpy(name, namep, names); 199 name[names] = '\0'; 200 value = (char *)ficlMalloc(values+1); 201 if (!value) 202 ficlVmThrowError(pVM, "Error: out of memory"); 203 strncpy(value, valuep, values); 204 value[values] = '\0'; 205 206 setenv(name, value, 1); 207 ficlFree(name); 208 ficlFree(value); 209 } 210 211 void 212 ficlSetenvq(ficlVm *pVM) 213 { 214 char *name, *value; 215 char *namep, *valuep; 216 int names, values, overwrite; 217 218 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 5, 0); 219 220 overwrite = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 221 names = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 222 namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM)); 223 values = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 224 valuep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM)); 225 226 name = (char *)ficlMalloc(names+1); 227 if (!name) 228 ficlVmThrowError(pVM, "Error: out of memory"); 229 strncpy(name, namep, names); 230 name[names] = '\0'; 231 value = (char *)ficlMalloc(values+1); 232 if (!value) 233 ficlVmThrowError(pVM, "Error: out of memory"); 234 strncpy(value, valuep, values); 235 value[values] = '\0'; 236 237 setenv(name, value, overwrite); 238 ficlFree(name); 239 ficlFree(value); 240 } 241 242 void 243 ficlGetenv(ficlVm *pVM) 244 { 245 char *name, *value; 246 char *namep; 247 int names; 248 249 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 2); 250 251 names = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 252 namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM)); 253 254 name = (char *)ficlMalloc(names+1); 255 if (!name) 256 ficlVmThrowError(pVM, "Error: out of memory"); 257 strncpy(name, namep, names); 258 name[names] = '\0'; 259 260 value = getenv(name); 261 ficlFree(name); 262 263 if (value != NULL) { 264 ficlStackPushPointer(ficlVmGetDataStack(pVM), value); 265 ficlStackPushInteger(ficlVmGetDataStack(pVM), strlen(value)); 266 } else 267 ficlStackPushInteger(ficlVmGetDataStack(pVM), -1); 268 } 269 270 void 271 ficlUnsetenv(ficlVm *pVM) 272 { 273 char *name; 274 char *namep; 275 int names; 276 277 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 0); 278 279 names = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 280 namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM)); 281 282 name = (char *)ficlMalloc(names+1); 283 if (!name) 284 ficlVmThrowError(pVM, "Error: out of memory"); 285 strncpy(name, namep, names); 286 name[names] = '\0'; 287 288 unsetenv(name); 289 ficlFree(name); 290 } 291 292 void 293 ficlCopyin(ficlVm *pVM) 294 { 295 #ifdef _STANDALONE 296 void* src; 297 vm_offset_t dest; 298 size_t len; 299 #endif 300 301 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 0); 302 303 #ifdef _STANDALONE 304 len = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 305 dest = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 306 src = ficlStackPopPointer(ficlVmGetDataStack(pVM)); 307 archsw.arch_copyin(src, dest, len); 308 #else 309 (void) ficlStackPopInteger(ficlVmGetDataStack(pVM)); 310 (void) ficlStackPopInteger(ficlVmGetDataStack(pVM)); 311 (void) ficlStackPopPointer(ficlVmGetDataStack(pVM)); 312 #endif 313 } 314 315 void 316 ficlCopyout(ficlVm *pVM) 317 { 318 #ifdef _STANDALONE 319 void* dest; 320 vm_offset_t src; 321 size_t len; 322 #endif 323 324 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 0); 325 326 #ifdef _STANDALONE 327 len = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 328 dest = ficlStackPopPointer(ficlVmGetDataStack(pVM)); 329 src = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 330 archsw.arch_copyout(src, dest, len); 331 #else 332 (void) ficlStackPopInteger(ficlVmGetDataStack(pVM)); 333 (void) ficlStackPopPointer(ficlVmGetDataStack(pVM)); 334 (void) ficlStackPopInteger(ficlVmGetDataStack(pVM)); 335 #endif 336 } 337 338 void 339 ficlFindfile(ficlVm *pVM) 340 { 341 #ifdef _STANDALONE 342 char *name, *type; 343 char *namep, *typep; 344 int names, types; 345 #endif 346 struct preloaded_file *fp; 347 348 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 4, 1); 349 350 #ifdef _STANDALONE 351 types = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 352 typep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM)); 353 names = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 354 namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM)); 355 356 name = (char *)ficlMalloc(names+1); 357 if (!name) 358 ficlVmThrowError(pVM, "Error: out of memory"); 359 strncpy(name, namep, names); 360 name[names] = '\0'; 361 type = (char *)ficlMalloc(types+1); 362 if (!type) 363 ficlVmThrowError(pVM, "Error: out of memory"); 364 strncpy(type, typep, types); 365 type[types] = '\0'; 366 367 fp = file_findfile(name, type); 368 #else 369 (void) ficlStackPopInteger(ficlVmGetDataStack(pVM)); 370 (void) ficlStackPopPointer(ficlVmGetDataStack(pVM)); 371 (void) ficlStackPopInteger(ficlVmGetDataStack(pVM)); 372 (void) ficlStackPopPointer(ficlVmGetDataStack(pVM)); 373 374 fp = NULL; 375 #endif 376 ficlStackPushPointer(ficlVmGetDataStack(pVM), fp); 377 } 378 379 void 380 ficlCcall(ficlVm *pVM) 381 { 382 int (*func)(int, ...); 383 int result, p[10]; 384 int nparam, i; 385 386 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 0); 387 388 func = (int (*)(int, ...))ficlStackPopPointer(ficlVmGetDataStack(pVM)); 389 nparam = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 390 391 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), nparam, 1); 392 393 for (i = 0; i < nparam; i++) 394 p[i] = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 395 396 result = func(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], 397 p[9]); 398 399 ficlStackPushInteger(ficlVmGetDataStack(pVM), result); 400 } 401 402 void 403 ficlUuidFromString(ficlVm *pVM) 404 { 405 char *uuid; 406 char *uuid_ptr; 407 int uuid_size; 408 uuid_t *u; 409 #ifdef _STANDALONE 410 uint32_t status; 411 #else 412 int status; 413 #endif 414 415 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 0); 416 417 uuid_size = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 418 uuid_ptr = ficlStackPopPointer(ficlVmGetDataStack(pVM)); 419 420 uuid = ficlMalloc(uuid_size + 1); 421 if (!uuid) 422 ficlVmThrowError(pVM, "Error: out of memory"); 423 (void) memcpy(uuid, uuid_ptr, uuid_size); 424 uuid[uuid_size] = '\0'; 425 426 u = ficlMalloc(sizeof (*u)); 427 #ifdef _STANDALONE 428 uuid_from_string(uuid, u, &status); 429 ficlFree(uuid); 430 if (status != uuid_s_ok) { 431 ficlFree(u); 432 u = NULL; 433 } 434 #else 435 status = uuid_parse(uuid, *u); 436 ficlFree(uuid); 437 if (status != 0) { 438 ficlFree(u); 439 u = NULL; 440 } 441 #endif 442 ficlStackPushPointer(ficlVmGetDataStack(pVM), u); 443 } 444 445 void 446 ficlUuidToString(ficlVm *pVM) 447 { 448 char *uuid; 449 uuid_t *u; 450 #ifdef _STANDALONE 451 uint32_t status; 452 #endif 453 454 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0); 455 456 u = ficlStackPopPointer(ficlVmGetDataStack(pVM)); 457 #ifdef _STANDALONE 458 uuid_to_string(u, &uuid, &status); 459 if (status == uuid_s_ok) { 460 ficlStackPushPointer(ficlVmGetDataStack(pVM), uuid); 461 ficlStackPushInteger(ficlVmGetDataStack(pVM), strlen(uuid)); 462 } else 463 #else 464 uuid = ficlMalloc(UUID_PRINTABLE_STRING_LENGTH); 465 if (uuid != NULL) { 466 uuid_unparse(*u, uuid); 467 ficlStackPushPointer(ficlVmGetDataStack(pVM), uuid); 468 ficlStackPushInteger(ficlVmGetDataStack(pVM), strlen(uuid)); 469 } else 470 #endif 471 ficlStackPushInteger(ficlVmGetDataStack(pVM), -1); 472 } 473 474 /* 475 * f i c l E x e c F D 476 * reads in text from file fd and passes it to ficlExec() 477 * returns FICL_VM_STATUS_OUT_OF_TEXT on success or the ficlExec() error 478 * code on failure. 479 */ 480 #define nLINEBUF 256 481 int 482 ficlExecFD(ficlVm *pVM, int fd) 483 { 484 char cp[nLINEBUF]; 485 int nLine = 0, rval = FICL_VM_STATUS_OUT_OF_TEXT; 486 char ch; 487 ficlCell id; 488 ficlString s; 489 490 id = pVM->sourceId; 491 pVM->sourceId.i = fd+1; /* in loader we can get 0, there is no stdin */ 492 493 /* feed each line to ficlExec */ 494 while (1) { 495 int status, i; 496 497 i = 0; 498 while ((status = read(fd, &ch, 1)) > 0 && ch != '\n') 499 cp[i++] = ch; 500 nLine++; 501 if (!i) { 502 if (status < 1) 503 break; 504 continue; 505 } 506 if (cp[i] == '\n') 507 cp[i] = '\0'; 508 509 FICL_STRING_SET_POINTER(s, cp); 510 FICL_STRING_SET_LENGTH(s, i); 511 512 rval = ficlVmExecuteString(pVM, s); 513 if (rval != FICL_VM_STATUS_QUIT && 514 rval != FICL_VM_STATUS_USER_EXIT && 515 rval != FICL_VM_STATUS_OUT_OF_TEXT) { 516 pVM->sourceId = id; 517 (void) ficlVmEvaluate(pVM, ""); 518 return (rval); 519 } 520 } 521 pVM->sourceId = id; 522 523 /* 524 * Pass an empty line with SOURCE-ID == -1 to flush 525 * any pending REFILLs (as required by FILE wordset) 526 */ 527 (void) ficlVmEvaluate(pVM, ""); 528 529 if (rval == FICL_VM_STATUS_USER_EXIT) 530 ficlVmThrow(pVM, FICL_VM_STATUS_USER_EXIT); 531 532 return (rval); 533 } 534 535 static void displayCellNoPad(ficlVm *pVM) 536 { 537 ficlCell c; 538 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0); 539 540 c = ficlStackPop(ficlVmGetDataStack(pVM)); 541 ficlLtoa((c).i, pVM->pad, pVM->base); 542 ficlVmTextOut(pVM, pVM->pad); 543 } 544 545 /* 546 * isdir? - Return whether an fd corresponds to a directory. 547 * 548 * isdir? ( fd -- bool ) 549 */ 550 static void 551 isdirQuestion(ficlVm *pVM) 552 { 553 struct stat sb; 554 ficlInteger flag; 555 int fd; 556 557 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 1); 558 559 fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 560 flag = FICL_FALSE; 561 do { 562 if (fd < 0) 563 break; 564 if (fstat(fd, &sb) < 0) 565 break; 566 if (!S_ISDIR(sb.st_mode)) 567 break; 568 flag = FICL_TRUE; 569 } while (0); 570 ficlStackPushInteger(ficlVmGetDataStack(pVM), flag); 571 } 572 573 /* 574 * fopen - open a file and return new fd on stack. 575 * 576 * fopen ( ptr count mode -- fd ) 577 */ 578 extern char *get_dev(const char *); 579 580 static void 581 pfopen(ficlVm *pVM) 582 { 583 int mode, fd, count; 584 char *ptr, *name; 585 #ifndef _STANDALONE 586 char *tmp; 587 #endif 588 589 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1); 590 591 mode = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get mode */ 592 count = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get count */ 593 ptr = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get ptr */ 594 595 if ((count < 0) || (ptr == NULL)) { 596 ficlStackPushInteger(ficlVmGetDataStack(pVM), -1); 597 return; 598 } 599 600 /* ensure that the string is null terminated */ 601 name = (char *)malloc(count+1); 602 bcopy(ptr, name, count); 603 name[count] = 0; 604 #ifndef _STANDALONE 605 tmp = get_dev(name); 606 free(name); 607 name = tmp; 608 #endif 609 610 /* open the file */ 611 fd = open(name, mode); 612 free(name); 613 ficlStackPushInteger(ficlVmGetDataStack(pVM), fd); 614 } 615 616 /* 617 * fclose - close a file who's fd is on stack. 618 * fclose ( fd -- ) 619 */ 620 static void 621 pfclose(ficlVm *pVM) 622 { 623 int fd; 624 625 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0); 626 627 fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */ 628 if (fd != -1) 629 close(fd); 630 } 631 632 /* 633 * fread - read file contents 634 * fread ( fd buf nbytes -- nread ) 635 */ 636 static void 637 pfread(ficlVm *pVM) 638 { 639 int fd, len; 640 char *buf; 641 642 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1); 643 644 len = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 645 buf = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get buffer */ 646 fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */ 647 if (len > 0 && buf && fd != -1) 648 ficlStackPushInteger(ficlVmGetDataStack(pVM), 649 read(fd, buf, len)); 650 else 651 ficlStackPushInteger(ficlVmGetDataStack(pVM), -1); 652 } 653 654 /* 655 * fopendir - open directory 656 * 657 * fopendir ( addr len -- ptr TRUE | FALSE ) 658 */ 659 static void pfopendir(ficlVm *pVM) 660 { 661 #ifndef _STANDALONE 662 DIR *dir; 663 char *tmp; 664 #else 665 struct stat sb; 666 int fd; 667 #endif 668 int count; 669 char *ptr, *name; 670 ficlInteger flag = FICL_FALSE; 671 672 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 1); 673 674 count = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 675 ptr = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get ptr */ 676 677 if ((count < 0) || (ptr == NULL)) { 678 ficlStackPushInteger(ficlVmGetDataStack(pVM), -1); 679 return; 680 } 681 /* ensure that the string is null terminated */ 682 name = (char *)malloc(count+1); 683 bcopy(ptr, name, count); 684 name[count] = 0; 685 #ifndef _STANDALONE 686 tmp = get_dev(name); 687 free(name); 688 name = tmp; 689 #else 690 fd = open(name, O_RDONLY); 691 free(name); 692 do { 693 if (fd < 0) 694 break; 695 if (fstat(fd, &sb) < 0) 696 break; 697 if (!S_ISDIR(sb.st_mode)) 698 break; 699 flag = FICL_TRUE; 700 ficlStackPushInteger(ficlVmGetDataStack(pVM), fd); 701 ficlStackPushInteger(ficlVmGetDataStack(pVM), flag); 702 return; 703 } while (0); 704 705 if (fd >= 0) 706 close(fd); 707 708 ficlStackPushInteger(ficlVmGetDataStack(pVM), flag); 709 return; 710 #endif 711 #ifndef _STANDALONE 712 dir = opendir(name); 713 if (dir == NULL) { 714 ficlStackPushInteger(ficlVmGetDataStack(pVM), flag); 715 return; 716 } else 717 flag = FICL_TRUE; 718 719 ficlStackPushPointer(ficlVmGetDataStack(pVM), dir); 720 ficlStackPushInteger(ficlVmGetDataStack(pVM), flag); 721 #endif 722 } 723 724 /* 725 * freaddir - read directory contents 726 * freaddir ( fd -- ptr len TRUE | FALSE ) 727 */ 728 static void 729 pfreaddir(ficlVm *pVM) 730 { 731 #ifndef _STANDALONE 732 static DIR *dir = NULL; 733 #else 734 int fd; 735 #endif 736 struct dirent *d = NULL; 737 738 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 3); 739 /* 740 * libstand readdir does not always return . nor .. so filter 741 * them out to have consistent behaviour. 742 */ 743 #ifndef _STANDALONE 744 dir = ficlStackPopPointer(ficlVmGetDataStack(pVM)); 745 if (dir != NULL) 746 do { 747 d = readdir(dir); 748 if (d != NULL && strcmp(d->d_name, ".") == 0) 749 continue; 750 if (d != NULL && strcmp(d->d_name, "..") == 0) 751 continue; 752 break; 753 } while (d != NULL); 754 #else 755 fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 756 if (fd != -1) 757 do { 758 d = readdirfd(fd); 759 if (d != NULL && strcmp(d->d_name, ".") == 0) 760 continue; 761 if (d != NULL && strcmp(d->d_name, "..") == 0) 762 continue; 763 break; 764 } while (d != NULL); 765 #endif 766 if (d != NULL) { 767 ficlStackPushPointer(ficlVmGetDataStack(pVM), d->d_name); 768 ficlStackPushInteger(ficlVmGetDataStack(pVM), 769 strlen(d->d_name)); 770 ficlStackPushInteger(ficlVmGetDataStack(pVM), FICL_TRUE); 771 } else { 772 ficlStackPushInteger(ficlVmGetDataStack(pVM), FICL_FALSE); 773 } 774 } 775 776 /* 777 * fclosedir - close a dir on stack. 778 * 779 * fclosedir ( fd -- ) 780 */ 781 static void 782 pfclosedir(ficlVm *pVM) 783 { 784 #ifndef _STANDALONE 785 DIR *dir; 786 #else 787 int fd; 788 #endif 789 790 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0); 791 792 #ifndef _STANDALONE 793 dir = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get dir */ 794 if (dir != NULL) 795 closedir(dir); 796 #else 797 fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */ 798 if (fd != -1) 799 close(fd); 800 #endif 801 } 802 803 /* 804 * fload - interpret file contents 805 * 806 * fload ( fd -- ) 807 */ 808 static void pfload(ficlVm *pVM) 809 { 810 int fd; 811 812 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0); 813 814 fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */ 815 if (fd != -1) 816 ficlExecFD(pVM, fd); 817 } 818 819 /* 820 * fwrite - write file contents 821 * 822 * fwrite ( fd buf nbytes -- nwritten ) 823 */ 824 static void 825 pfwrite(ficlVm *pVM) 826 { 827 int fd, len; 828 char *buf; 829 830 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1); 831 832 len = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* bytes to read */ 833 buf = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get buffer */ 834 fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */ 835 if (len > 0 && buf && fd != -1) 836 ficlStackPushInteger(ficlVmGetDataStack(pVM), 837 write(fd, buf, len)); 838 else 839 ficlStackPushInteger(ficlVmGetDataStack(pVM), -1); 840 } 841 842 /* 843 * fseek - seek to a new position in a file 844 * 845 * fseek ( fd ofs whence -- pos ) 846 */ 847 static void 848 pfseek(ficlVm *pVM) 849 { 850 int fd, pos, whence; 851 852 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1); 853 854 whence = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 855 pos = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 856 fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 857 ficlStackPushInteger(ficlVmGetDataStack(pVM), lseek(fd, pos, whence)); 858 } 859 860 /* 861 * key - get a character from stdin 862 * 863 * key ( -- char ) 864 */ 865 static void 866 key(ficlVm *pVM) 867 { 868 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1); 869 870 ficlStackPushInteger(ficlVmGetDataStack(pVM), getchar()); 871 } 872 873 /* 874 * key? - check for a character from stdin (FACILITY) 875 * key? ( -- flag ) 876 */ 877 static void 878 keyQuestion(ficlVm *pVM) 879 { 880 #ifndef _STANDALONE 881 char ch = -1; 882 struct termios oldt; 883 struct termios newt; 884 #endif 885 886 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1); 887 888 #ifndef _STANDALONE 889 tcgetattr(STDIN_FILENO, &oldt); 890 newt = oldt; 891 newt.c_lflag &= ~(ICANON | ECHO); 892 newt.c_cc[VMIN] = 0; 893 newt.c_cc[VTIME] = 0; 894 tcsetattr(STDIN_FILENO, TCSANOW, &newt); 895 ch = getchar(); 896 tcsetattr(STDIN_FILENO, TCSANOW, &oldt); 897 898 if (ch != -1) 899 (void) ungetc(ch, stdin); 900 901 ficlStackPushInteger(ficlVmGetDataStack(pVM), 902 ch != -1? FICL_TRUE : FICL_FALSE); 903 #else 904 ficlStackPushInteger(ficlVmGetDataStack(pVM), 905 ischar()? FICL_TRUE : FICL_FALSE); 906 #endif 907 } 908 909 /* 910 * seconds - gives number of seconds since beginning of time 911 * 912 * beginning of time is defined as: 913 * 914 * BTX - number of seconds since midnight 915 * FreeBSD - number of seconds since Jan 1 1970 916 * 917 * seconds ( -- u ) 918 */ 919 static void 920 pseconds(ficlVm *pVM) 921 { 922 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1); 923 924 ficlStackPushUnsigned(ficlVmGetDataStack(pVM), 925 (ficlUnsigned) time(NULL)); 926 } 927 928 /* 929 * ms - wait at least that many milliseconds (FACILITY) 930 * ms ( u -- ) 931 */ 932 static void 933 ms(ficlVm *pVM) 934 { 935 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0); 936 937 #ifndef _STANDALONE 938 usleep(ficlStackPopUnsigned(ficlVmGetDataStack(pVM)) * 1000); 939 #else 940 delay(ficlStackPopUnsigned(ficlVmGetDataStack(pVM)) * 1000); 941 #endif 942 } 943 944 /* 945 * fkey - get a character from a file 946 * fkey ( file -- char ) 947 */ 948 static void 949 fkey(ficlVm *pVM) 950 { 951 int i, fd; 952 char ch; 953 954 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 1); 955 956 fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 957 i = read(fd, &ch, 1); 958 ficlStackPushInteger(ficlVmGetDataStack(pVM), i > 0 ? ch : -1); 959 } 960 961 /* 962 * Retrieves free space remaining on the dictionary 963 */ 964 static void 965 freeHeap(ficlVm *pVM) 966 { 967 ficlStackPushInteger(ficlVmGetDataStack(pVM), 968 ficlDictionaryCellsAvailable(ficlVmGetDictionary(pVM))); 969 } 970 971 /* 972 * f i c l C o m p i l e P l a t f o r m 973 * Build FreeBSD platform extensions into the system dictionary 974 */ 975 void 976 ficlSystemCompilePlatform(ficlSystem *pSys) 977 { 978 ficlDictionary *dp = ficlSystemGetDictionary(pSys); 979 ficlDictionary *env = ficlSystemGetEnvironment(pSys); 980 #ifdef _STANDALONE 981 ficlCompileFcn **fnpp; 982 #endif 983 984 FICL_SYSTEM_ASSERT(pSys, dp); 985 FICL_SYSTEM_ASSERT(pSys, env); 986 987 ficlDictionarySetPrimitive(dp, ".#", displayCellNoPad, 988 FICL_WORD_DEFAULT); 989 ficlDictionarySetPrimitive(dp, "isdir?", isdirQuestion, 990 FICL_WORD_DEFAULT); 991 ficlDictionarySetPrimitive(dp, "fopen", pfopen, FICL_WORD_DEFAULT); 992 ficlDictionarySetPrimitive(dp, "fclose", pfclose, FICL_WORD_DEFAULT); 993 ficlDictionarySetPrimitive(dp, "fread", pfread, FICL_WORD_DEFAULT); 994 ficlDictionarySetPrimitive(dp, "fopendir", pfopendir, 995 FICL_WORD_DEFAULT); 996 ficlDictionarySetPrimitive(dp, "freaddir", pfreaddir, 997 FICL_WORD_DEFAULT); 998 ficlDictionarySetPrimitive(dp, "fclosedir", pfclosedir, 999 FICL_WORD_DEFAULT); 1000 ficlDictionarySetPrimitive(dp, "fload", pfload, FICL_WORD_DEFAULT); 1001 ficlDictionarySetPrimitive(dp, "fkey", fkey, FICL_WORD_DEFAULT); 1002 ficlDictionarySetPrimitive(dp, "fseek", pfseek, FICL_WORD_DEFAULT); 1003 ficlDictionarySetPrimitive(dp, "fwrite", pfwrite, FICL_WORD_DEFAULT); 1004 ficlDictionarySetPrimitive(dp, "key", key, FICL_WORD_DEFAULT); 1005 ficlDictionarySetPrimitive(dp, "key?", keyQuestion, FICL_WORD_DEFAULT); 1006 ficlDictionarySetPrimitive(dp, "ms", ms, FICL_WORD_DEFAULT); 1007 ficlDictionarySetPrimitive(dp, "seconds", pseconds, FICL_WORD_DEFAULT); 1008 ficlDictionarySetPrimitive(dp, "heap?", freeHeap, FICL_WORD_DEFAULT); 1009 1010 ficlDictionarySetPrimitive(dp, "setenv", ficlSetenv, FICL_WORD_DEFAULT); 1011 ficlDictionarySetPrimitive(dp, "setenv?", ficlSetenvq, 1012 FICL_WORD_DEFAULT); 1013 ficlDictionarySetPrimitive(dp, "getenv", ficlGetenv, FICL_WORD_DEFAULT); 1014 ficlDictionarySetPrimitive(dp, "unsetenv", ficlUnsetenv, 1015 FICL_WORD_DEFAULT); 1016 ficlDictionarySetPrimitive(dp, "copyin", ficlCopyin, FICL_WORD_DEFAULT); 1017 ficlDictionarySetPrimitive(dp, "copyout", ficlCopyout, 1018 FICL_WORD_DEFAULT); 1019 ficlDictionarySetPrimitive(dp, "findfile", ficlFindfile, 1020 FICL_WORD_DEFAULT); 1021 ficlDictionarySetPrimitive(dp, "ccall", ficlCcall, FICL_WORD_DEFAULT); 1022 ficlDictionarySetPrimitive(dp, "uuid-from-string", ficlUuidFromString, 1023 FICL_WORD_DEFAULT); 1024 ficlDictionarySetPrimitive(dp, "uuid-to-string", ficlUuidToString, 1025 FICL_WORD_DEFAULT); 1026 ficlDictionarySetPrimitive(dp, "fb-setpixel", ficl_fb_setpixel, 1027 FICL_WORD_DEFAULT); 1028 ficlDictionarySetPrimitive(dp, "fb-line", ficl_fb_line, 1029 FICL_WORD_DEFAULT); 1030 ficlDictionarySetPrimitive(dp, "fb-bezier", ficl_fb_bezier, 1031 FICL_WORD_DEFAULT); 1032 ficlDictionarySetPrimitive(dp, "fb-drawrect", ficl_fb_drawrect, 1033 FICL_WORD_DEFAULT); 1034 ficlDictionarySetPrimitive(dp, "fb-putimage", ficl_fb_putimage, 1035 FICL_WORD_DEFAULT); 1036 ficlDictionarySetPrimitive(dp, "term-drawrect", ficl_term_drawrect, 1037 FICL_WORD_DEFAULT); 1038 #ifdef _STANDALONE 1039 /* Register words from linker set. */ 1040 SET_FOREACH(fnpp, Xficl_compile_set) 1041 (*fnpp)(pSys); 1042 #endif 1043 1044 #if defined(__i386__) || defined(__amd64__) 1045 ficlDictionarySetConstant(env, "arch-i386", FICL_TRUE); 1046 ficlDictionarySetConstant(env, "arch-sparc", FICL_FALSE); 1047 #endif 1048 #ifdef __sparc 1049 ficlDictionarySetConstant(env, "arch-i386", FICL_FALSE); 1050 ficlDictionarySetConstant(env, "arch-sparc", FICL_TRUE); 1051 #endif 1052 } 1053