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 /* 434 * isvirtualized? - Return whether the loader runs under a 435 * hypervisor. 436 * 437 * isvirtualized? ( -- addr len flag | flag ) 438 */ 439 static void 440 ficlIsvirtualizedQ(ficlVm *pVM) 441 { 442 const char *hv; 443 444 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 3); 445 446 #ifdef _STANDALONE 447 hv = (archsw.arch_hypervisor != NULL) 448 ? (*archsw.arch_hypervisor)() 449 : NULL; 450 #else 451 hv = NULL; 452 #endif 453 if (hv != NULL) { 454 ficlStackPushPointer(ficlVmGetDataStack(pVM), (void *)hv); 455 ficlStackPushInteger(ficlVmGetDataStack(pVM), strlen(hv)); 456 ficlStackPushInteger(ficlVmGetDataStack(pVM), FICL_TRUE); 457 } else { 458 ficlStackPushInteger(ficlVmGetDataStack(pVM), FICL_FALSE); 459 } 460 } 461 462 void 463 ficlCcall(ficlVm *pVM) 464 { 465 int (*func)(int, ...); 466 int result, p[10]; 467 int nparam, i; 468 469 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 0); 470 471 func = (int (*)(int, ...))ficlStackPopPointer(ficlVmGetDataStack(pVM)); 472 nparam = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 473 474 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), nparam, 1); 475 476 for (i = 0; i < nparam; i++) 477 p[i] = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 478 479 result = func(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], 480 p[9]); 481 482 ficlStackPushInteger(ficlVmGetDataStack(pVM), result); 483 } 484 485 void 486 ficlUuidFromString(ficlVm *pVM) 487 { 488 char *uuid; 489 char *uuid_ptr; 490 int uuid_size; 491 uuid_t *u; 492 #ifdef _STANDALONE 493 uint32_t status; 494 #else 495 int status; 496 #endif 497 498 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 0); 499 500 uuid_size = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 501 uuid_ptr = ficlStackPopPointer(ficlVmGetDataStack(pVM)); 502 503 uuid = ficlMalloc(uuid_size + 1); 504 if (!uuid) 505 ficlVmThrowError(pVM, "Error: out of memory"); 506 (void) memcpy(uuid, uuid_ptr, uuid_size); 507 uuid[uuid_size] = '\0'; 508 509 u = ficlMalloc(sizeof (*u)); 510 #ifdef _STANDALONE 511 uuid_from_string(uuid, u, &status); 512 ficlFree(uuid); 513 if (status != uuid_s_ok) { 514 ficlFree(u); 515 u = NULL; 516 } 517 #else 518 status = uuid_parse(uuid, *u); 519 ficlFree(uuid); 520 if (status != 0) { 521 ficlFree(u); 522 u = NULL; 523 } 524 #endif 525 ficlStackPushPointer(ficlVmGetDataStack(pVM), u); 526 } 527 528 void 529 ficlUuidToString(ficlVm *pVM) 530 { 531 char *uuid; 532 uuid_t *u; 533 #ifdef _STANDALONE 534 uint32_t status; 535 #endif 536 537 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0); 538 539 u = ficlStackPopPointer(ficlVmGetDataStack(pVM)); 540 #ifdef _STANDALONE 541 uuid_to_string(u, &uuid, &status); 542 if (status == uuid_s_ok) { 543 ficlStackPushPointer(ficlVmGetDataStack(pVM), uuid); 544 ficlStackPushInteger(ficlVmGetDataStack(pVM), strlen(uuid)); 545 } else 546 #else 547 uuid = ficlMalloc(UUID_PRINTABLE_STRING_LENGTH); 548 if (uuid != NULL) { 549 uuid_unparse(*u, uuid); 550 ficlStackPushPointer(ficlVmGetDataStack(pVM), uuid); 551 ficlStackPushInteger(ficlVmGetDataStack(pVM), strlen(uuid)); 552 } else 553 #endif 554 ficlStackPushInteger(ficlVmGetDataStack(pVM), -1); 555 } 556 557 /* 558 * f i c l E x e c F D 559 * reads in text from file fd and passes it to ficlExec() 560 * returns FICL_VM_STATUS_OUT_OF_TEXT on success or the ficlExec() error 561 * code on failure. 562 */ 563 #define nLINEBUF 256 564 int 565 ficlExecFD(ficlVm *pVM, int fd) 566 { 567 char cp[nLINEBUF]; 568 int nLine = 0, rval = FICL_VM_STATUS_OUT_OF_TEXT; 569 char ch; 570 ficlCell id; 571 ficlString s; 572 573 id = pVM->sourceId; 574 pVM->sourceId.i = fd+1; /* in loader we can get 0, there is no stdin */ 575 576 /* feed each line to ficlExec */ 577 while (1) { 578 int status, i; 579 580 i = 0; 581 while ((status = read(fd, &ch, 1)) > 0 && ch != '\n') 582 cp[i++] = ch; 583 nLine++; 584 if (!i) { 585 if (status < 1) 586 break; 587 continue; 588 } 589 if (cp[i] == '\n') 590 cp[i] = '\0'; 591 592 FICL_STRING_SET_POINTER(s, cp); 593 FICL_STRING_SET_LENGTH(s, i); 594 595 rval = ficlVmExecuteString(pVM, s); 596 if (rval != FICL_VM_STATUS_QUIT && 597 rval != FICL_VM_STATUS_USER_EXIT && 598 rval != FICL_VM_STATUS_OUT_OF_TEXT) { 599 pVM->sourceId = id; 600 (void) ficlVmEvaluate(pVM, ""); 601 return (rval); 602 } 603 } 604 pVM->sourceId = id; 605 606 /* 607 * Pass an empty line with SOURCE-ID == -1 to flush 608 * any pending REFILLs (as required by FILE wordset) 609 */ 610 (void) ficlVmEvaluate(pVM, ""); 611 612 if (rval == FICL_VM_STATUS_USER_EXIT) 613 ficlVmThrow(pVM, FICL_VM_STATUS_USER_EXIT); 614 615 return (rval); 616 } 617 618 static void displayCellNoPad(ficlVm *pVM) 619 { 620 ficlCell c; 621 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0); 622 623 c = ficlStackPop(ficlVmGetDataStack(pVM)); 624 (void) ficlLtoa((c).i, pVM->pad, pVM->base); 625 ficlVmTextOut(pVM, pVM->pad); 626 } 627 628 /* 629 * isdir? - Return whether an fd corresponds to a directory. 630 * 631 * isdir? ( fd -- bool ) 632 */ 633 static void 634 isdirQuestion(ficlVm *pVM) 635 { 636 struct stat sb; 637 ficlInteger flag; 638 int fd; 639 640 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 1); 641 642 fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 643 flag = FICL_FALSE; 644 do { 645 if (fd < 0) 646 break; 647 if (fstat(fd, &sb) < 0) 648 break; 649 if (!S_ISDIR(sb.st_mode)) 650 break; 651 flag = FICL_TRUE; 652 } while (0); 653 ficlStackPushInteger(ficlVmGetDataStack(pVM), flag); 654 } 655 656 /* 657 * fopen - open a file and return new fd on stack. 658 * 659 * fopen ( ptr count mode -- fd ) 660 */ 661 extern char *get_dev(const char *); 662 663 static void 664 pfopen(ficlVm *pVM) 665 { 666 int mode, fd, count; 667 char *ptr, *name; 668 #ifndef _STANDALONE 669 char *tmp; 670 #endif 671 672 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1); 673 674 mode = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get mode */ 675 count = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get count */ 676 ptr = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get ptr */ 677 678 if ((count < 0) || (ptr == NULL)) { 679 ficlStackPushInteger(ficlVmGetDataStack(pVM), -1); 680 return; 681 } 682 683 /* ensure that the string is null terminated */ 684 name = (char *)malloc(count+1); 685 bcopy(ptr, name, count); 686 name[count] = 0; 687 #ifndef _STANDALONE 688 tmp = get_dev(name); 689 free(name); 690 name = tmp; 691 #endif 692 693 /* open the file */ 694 fd = open(name, mode); 695 free(name); 696 ficlStackPushInteger(ficlVmGetDataStack(pVM), fd); 697 } 698 699 /* 700 * fclose - close a file who's fd is on stack. 701 * fclose ( fd -- ) 702 */ 703 static void 704 pfclose(ficlVm *pVM) 705 { 706 int fd; 707 708 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0); 709 710 fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */ 711 if (fd != -1) 712 (void) close(fd); 713 } 714 715 /* 716 * fread - read file contents 717 * fread ( fd buf nbytes -- nread ) 718 */ 719 static void 720 pfread(ficlVm *pVM) 721 { 722 int fd, len; 723 char *buf; 724 725 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1); 726 727 len = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 728 buf = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get buffer */ 729 fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */ 730 if (len > 0 && buf && fd != -1) 731 ficlStackPushInteger(ficlVmGetDataStack(pVM), 732 read(fd, buf, len)); 733 else 734 ficlStackPushInteger(ficlVmGetDataStack(pVM), -1); 735 } 736 737 /* 738 * fopendir - open directory 739 * 740 * fopendir ( addr len -- ptr TRUE | FALSE ) 741 */ 742 static void pfopendir(ficlVm *pVM) 743 { 744 #ifndef _STANDALONE 745 DIR *dir; 746 char *tmp; 747 #else 748 struct stat sb; 749 int fd; 750 #endif 751 ficlInteger count; 752 char *ptr, *name; 753 ficlInteger flag = FICL_FALSE; 754 755 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 1); 756 757 count = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 758 ptr = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get ptr */ 759 760 if ((count < 0) || (ptr == NULL)) { 761 ficlStackPushInteger(ficlVmGetDataStack(pVM), flag); 762 return; 763 } 764 /* ensure that the string is null terminated */ 765 if ((name = malloc(count + 1)) == NULL) { 766 ficlStackPushInteger(ficlVmGetDataStack(pVM), flag); 767 return; 768 } 769 770 bcopy(ptr, name, count); 771 name[count] = 0; 772 #ifndef _STANDALONE 773 tmp = get_dev(name); 774 free(name); 775 name = tmp; 776 777 dir = opendir(name); 778 if (dir == NULL) { 779 ficlStackPushInteger(ficlVmGetDataStack(pVM), flag); 780 return; 781 } else 782 flag = FICL_TRUE; 783 784 ficlStackPushPointer(ficlVmGetDataStack(pVM), dir); 785 ficlStackPushInteger(ficlVmGetDataStack(pVM), flag); 786 #else 787 fd = open(name, O_RDONLY); 788 free(name); 789 do { 790 if (fd < 0) 791 break; 792 if (fstat(fd, &sb) < 0) 793 break; 794 if (!S_ISDIR(sb.st_mode)) 795 break; 796 flag = FICL_TRUE; 797 ficlStackPushInteger(ficlVmGetDataStack(pVM), fd); 798 ficlStackPushInteger(ficlVmGetDataStack(pVM), flag); 799 return; 800 } while (0); 801 802 if (fd >= 0) 803 close(fd); 804 805 ficlStackPushInteger(ficlVmGetDataStack(pVM), flag); 806 #endif 807 } 808 809 /* 810 * freaddir - read directory contents 811 * freaddir ( fd -- ptr len TRUE | FALSE ) 812 */ 813 static void 814 pfreaddir(ficlVm *pVM) 815 { 816 #ifndef _STANDALONE 817 static DIR *dir = NULL; 818 #else 819 int fd; 820 #endif 821 struct dirent *d = NULL; 822 823 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 3); 824 /* 825 * libstand readdir does not always return . nor .. so filter 826 * them out to have consistent behaviour. 827 */ 828 #ifndef _STANDALONE 829 dir = ficlStackPopPointer(ficlVmGetDataStack(pVM)); 830 if (dir != NULL) 831 do { 832 d = readdir(dir); 833 if (d != NULL && strcmp(d->d_name, ".") == 0) 834 continue; 835 if (d != NULL && strcmp(d->d_name, "..") == 0) 836 continue; 837 break; 838 } while (d != NULL); 839 #else 840 fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 841 if (fd != -1) 842 do { 843 d = readdirfd(fd); 844 if (d != NULL && strcmp(d->d_name, ".") == 0) 845 continue; 846 if (d != NULL && strcmp(d->d_name, "..") == 0) 847 continue; 848 break; 849 } while (d != NULL); 850 #endif 851 if (d != NULL) { 852 ficlStackPushPointer(ficlVmGetDataStack(pVM), d->d_name); 853 ficlStackPushInteger(ficlVmGetDataStack(pVM), 854 strlen(d->d_name)); 855 ficlStackPushInteger(ficlVmGetDataStack(pVM), FICL_TRUE); 856 } else { 857 ficlStackPushInteger(ficlVmGetDataStack(pVM), FICL_FALSE); 858 } 859 } 860 861 /* 862 * fclosedir - close a dir on stack. 863 * 864 * fclosedir ( fd -- ) 865 */ 866 static void 867 pfclosedir(ficlVm *pVM) 868 { 869 #ifndef _STANDALONE 870 DIR *dir; 871 #else 872 int fd; 873 #endif 874 875 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0); 876 877 #ifndef _STANDALONE 878 dir = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get dir */ 879 if (dir != NULL) 880 (void) closedir(dir); 881 #else 882 fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */ 883 if (fd != -1) 884 (void) close(fd); 885 #endif 886 } 887 888 /* 889 * fload - interpret file contents 890 * 891 * fload ( fd -- ) 892 */ 893 static void pfload(ficlVm *pVM) 894 { 895 int fd; 896 897 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0); 898 899 fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */ 900 if (fd != -1) 901 (void) ficlExecFD(pVM, fd); 902 } 903 904 /* 905 * fwrite - write file contents 906 * 907 * fwrite ( fd buf nbytes -- nwritten ) 908 */ 909 static void 910 pfwrite(ficlVm *pVM) 911 { 912 int fd, len; 913 char *buf; 914 915 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1); 916 917 len = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* bytes to read */ 918 buf = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get buffer */ 919 fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */ 920 if (len > 0 && buf && fd != -1) 921 ficlStackPushInteger(ficlVmGetDataStack(pVM), 922 write(fd, buf, len)); 923 else 924 ficlStackPushInteger(ficlVmGetDataStack(pVM), -1); 925 } 926 927 /* 928 * fseek - seek to a new position in a file 929 * 930 * fseek ( fd ofs whence -- pos ) 931 */ 932 static void 933 pfseek(ficlVm *pVM) 934 { 935 int fd, pos, whence; 936 937 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1); 938 939 whence = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 940 pos = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 941 fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 942 ficlStackPushInteger(ficlVmGetDataStack(pVM), lseek(fd, pos, whence)); 943 } 944 945 /* 946 * key - get a character from stdin 947 * 948 * key ( -- char ) 949 */ 950 static void 951 key(ficlVm *pVM) 952 { 953 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1); 954 955 ficlStackPushInteger(ficlVmGetDataStack(pVM), getchar()); 956 } 957 958 /* 959 * key? - check for a character from stdin (FACILITY) 960 * key? ( -- flag ) 961 */ 962 static void 963 keyQuestion(ficlVm *pVM) 964 { 965 #ifndef _STANDALONE 966 char ch = -1; 967 struct termios oldt; 968 struct termios newt; 969 #endif 970 971 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1); 972 973 #ifndef _STANDALONE 974 (void) tcgetattr(STDIN_FILENO, &oldt); 975 newt = oldt; 976 newt.c_lflag &= ~(ICANON | ECHO); 977 newt.c_cc[VMIN] = 0; 978 newt.c_cc[VTIME] = 0; 979 (void) tcsetattr(STDIN_FILENO, TCSANOW, &newt); 980 ch = getchar(); 981 (void) tcsetattr(STDIN_FILENO, TCSANOW, &oldt); 982 983 if (ch != -1) 984 (void) ungetc(ch, stdin); 985 986 ficlStackPushInteger(ficlVmGetDataStack(pVM), 987 ch != -1? FICL_TRUE : FICL_FALSE); 988 #else 989 ficlStackPushInteger(ficlVmGetDataStack(pVM), 990 ischar()? FICL_TRUE : FICL_FALSE); 991 #endif 992 } 993 994 /* 995 * seconds - gives number of seconds since beginning of time 996 * 997 * beginning of time is defined as: 998 * 999 * BTX - number of seconds since midnight 1000 * FreeBSD - number of seconds since Jan 1 1970 1001 * 1002 * seconds ( -- u ) 1003 */ 1004 static void 1005 pseconds(ficlVm *pVM) 1006 { 1007 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1); 1008 1009 ficlStackPushUnsigned(ficlVmGetDataStack(pVM), 1010 (ficlUnsigned) time(NULL)); 1011 } 1012 1013 /* 1014 * ms - wait at least that many milliseconds (FACILITY) 1015 * ms ( u -- ) 1016 */ 1017 static void 1018 ms(ficlVm *pVM) 1019 { 1020 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0); 1021 1022 #ifndef _STANDALONE 1023 (void) usleep(ficlStackPopUnsigned(ficlVmGetDataStack(pVM)) * 1000); 1024 #else 1025 delay(ficlStackPopUnsigned(ficlVmGetDataStack(pVM)) * 1000); 1026 #endif 1027 } 1028 1029 /* 1030 * fkey - get a character from a file 1031 * fkey ( file -- char ) 1032 */ 1033 static void 1034 fkey(ficlVm *pVM) 1035 { 1036 int i, fd; 1037 char ch; 1038 1039 FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 1); 1040 1041 fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); 1042 i = read(fd, &ch, 1); 1043 ficlStackPushInteger(ficlVmGetDataStack(pVM), i > 0 ? ch : -1); 1044 } 1045 1046 /* 1047 * Retrieves free space remaining on the dictionary 1048 */ 1049 static void 1050 freeHeap(ficlVm *pVM) 1051 { 1052 ficlStackPushInteger(ficlVmGetDataStack(pVM), 1053 ficlDictionaryCellsAvailable(ficlVmGetDictionary(pVM))); 1054 } 1055 1056 /* 1057 * f i c l C o m p i l e P l a t f o r m 1058 * Build FreeBSD platform extensions into the system dictionary 1059 */ 1060 void 1061 ficlSystemCompilePlatform(ficlSystem *pSys) 1062 { 1063 ficlDictionary *dp = ficlSystemGetDictionary(pSys); 1064 ficlDictionary *env = ficlSystemGetEnvironment(pSys); 1065 #ifdef _STANDALONE 1066 ficlCompileFcn **fnpp; 1067 #endif 1068 1069 FICL_SYSTEM_ASSERT(pSys, dp); 1070 FICL_SYSTEM_ASSERT(pSys, env); 1071 1072 (void) ficlDictionarySetPrimitive(dp, ".#", displayCellNoPad, 1073 FICL_WORD_DEFAULT); 1074 (void) ficlDictionarySetPrimitive(dp, "isdir?", isdirQuestion, 1075 FICL_WORD_DEFAULT); 1076 (void) ficlDictionarySetPrimitive(dp, "fopen", pfopen, 1077 FICL_WORD_DEFAULT); 1078 (void) ficlDictionarySetPrimitive(dp, "fclose", pfclose, 1079 FICL_WORD_DEFAULT); 1080 (void) ficlDictionarySetPrimitive(dp, "fread", pfread, 1081 FICL_WORD_DEFAULT); 1082 (void) ficlDictionarySetPrimitive(dp, "fopendir", pfopendir, 1083 FICL_WORD_DEFAULT); 1084 (void) ficlDictionarySetPrimitive(dp, "freaddir", pfreaddir, 1085 FICL_WORD_DEFAULT); 1086 (void) ficlDictionarySetPrimitive(dp, "fclosedir", pfclosedir, 1087 FICL_WORD_DEFAULT); 1088 (void) ficlDictionarySetPrimitive(dp, "fload", pfload, 1089 FICL_WORD_DEFAULT); 1090 (void) ficlDictionarySetPrimitive(dp, "fkey", fkey, 1091 FICL_WORD_DEFAULT); 1092 (void) ficlDictionarySetPrimitive(dp, "fseek", pfseek, 1093 FICL_WORD_DEFAULT); 1094 (void) ficlDictionarySetPrimitive(dp, "fwrite", pfwrite, 1095 FICL_WORD_DEFAULT); 1096 (void) ficlDictionarySetPrimitive(dp, "key", key, FICL_WORD_DEFAULT); 1097 (void) ficlDictionarySetPrimitive(dp, "key?", keyQuestion, 1098 FICL_WORD_DEFAULT); 1099 (void) ficlDictionarySetPrimitive(dp, "ms", ms, FICL_WORD_DEFAULT); 1100 (void) ficlDictionarySetPrimitive(dp, "seconds", pseconds, 1101 FICL_WORD_DEFAULT); 1102 (void) ficlDictionarySetPrimitive(dp, "heap?", freeHeap, 1103 FICL_WORD_DEFAULT); 1104 1105 (void) ficlDictionarySetPrimitive(dp, "setenv", ficlSetenv, 1106 FICL_WORD_DEFAULT); 1107 (void) ficlDictionarySetPrimitive(dp, "setenv?", ficlSetenvq, 1108 FICL_WORD_DEFAULT); 1109 (void) ficlDictionarySetPrimitive(dp, "getenv", ficlGetenv, 1110 FICL_WORD_DEFAULT); 1111 (void) ficlDictionarySetPrimitive(dp, "unsetenv", ficlUnsetenv, 1112 FICL_WORD_DEFAULT); 1113 (void) ficlDictionarySetPrimitive(dp, "copyin", ficlCopyin, 1114 FICL_WORD_DEFAULT); 1115 (void) ficlDictionarySetPrimitive(dp, "copyout", ficlCopyout, 1116 FICL_WORD_DEFAULT); 1117 (void) ficlDictionarySetPrimitive(dp, "findfile", ficlFindfile, 1118 FICL_WORD_DEFAULT); 1119 (void) ficlDictionarySetPrimitive(dp, "isvirtualized?", 1120 ficlIsvirtualizedQ, FICL_WORD_DEFAULT); 1121 (void) ficlDictionarySetPrimitive(dp, "ccall", ficlCcall, 1122 FICL_WORD_DEFAULT); 1123 (void) ficlDictionarySetPrimitive(dp, "uuid-from-string", 1124 ficlUuidFromString, FICL_WORD_DEFAULT); 1125 (void) ficlDictionarySetPrimitive(dp, "uuid-to-string", 1126 ficlUuidToString, FICL_WORD_DEFAULT); 1127 (void) ficlDictionarySetPrimitive(dp, "fb-setpixel", ficl_fb_setpixel, 1128 FICL_WORD_DEFAULT); 1129 (void) ficlDictionarySetPrimitive(dp, "fb-line", ficl_fb_line, 1130 FICL_WORD_DEFAULT); 1131 (void) ficlDictionarySetPrimitive(dp, "fb-bezier", ficl_fb_bezier, 1132 FICL_WORD_DEFAULT); 1133 (void) ficlDictionarySetPrimitive(dp, "fb-drawrect", ficl_fb_drawrect, 1134 FICL_WORD_DEFAULT); 1135 (void) ficlDictionarySetPrimitive(dp, "fb-putimage", ficl_fb_putimage, 1136 FICL_WORD_DEFAULT); 1137 (void) ficlDictionarySetPrimitive(dp, "term-drawrect", 1138 ficl_term_drawrect, FICL_WORD_DEFAULT); 1139 #ifdef _STANDALONE 1140 (void) ficlDictionarySetPrimitive(dp, "term-putimage", 1141 ficl_term_putimage, FICL_WORD_DEFAULT); 1142 /* Register words from linker set. */ 1143 SET_FOREACH(fnpp, Xficl_compile_set) 1144 (*fnpp)(pSys); 1145 #endif 1146 } 1147