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