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