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