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