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