Merge from vendor branch LIBSTDC++:
[dragonfly.git] / sys / boot / 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: src/sys/boot/ficl/loader.c,v 1.9 2003/06/08 03:11:16 nyan Exp $
27  * $DragonFly: src/sys/boot/ficl/loader.c,v 1.3 2003/11/10 06:08:33 dillon Exp $
28  */
29
30 /*******************************************************************
31 ** l o a d e r . c
32 ** Additional FICL words designed for FreeBSD's loader
33 ** 
34 *******************************************************************/
35
36 #ifdef TESTMAIN
37 #include <stdlib.h>
38 #else
39 #include <stand.h>
40 #endif
41 #include "bootstrap.h"
42 #include <string.h>
43 #include "ficl.h"
44
45 /*              FreeBSD's loader interaction words and extras
46  *
47  *              setenv      ( value n name n' -- )
48  *              setenv?     ( value n name n' flag -- )
49  *              getenv      ( addr n -- addr' n' | -1 )
50  *              unsetenv    ( addr n -- )
51  *              copyin      ( addr addr' len -- )
52  *              copyout     ( addr addr' len -- )
53  *              findfile    ( name len type len' -- addr )
54  *              pnpdevices  ( -- addr )
55  *              pnphandlers ( -- addr )
56  *              ccall       ( [[...[p10] p9] ... p1] n addr -- result )
57  *              .#          ( value -- )
58  */
59
60 #ifndef TESTMAIN
61 void
62 ficlSetenv(FICL_VM *pVM)
63 {
64         char    *namep, *valuep, *name, *value;
65         int     names, values;
66
67 #if FICL_ROBUST > 1
68         vmCheckStack(pVM, 4, 0);
69 #endif
70         names = stackPopINT(pVM->pStack);
71         namep = (char*) stackPopPtr(pVM->pStack);
72         values = stackPopINT(pVM->pStack);
73         valuep = (char*) stackPopPtr(pVM->pStack);
74
75         name = (char*) ficlMalloc(names+1);
76         if (!name)
77                 vmThrowErr(pVM, "Error: out of memory");
78         strncpy(name, namep, names);
79         name[names] = '\0';
80         value = (char*) ficlMalloc(values+1);
81         if (!value)
82                 vmThrowErr(pVM, "Error: out of memory");
83         strncpy(value, valuep, values);
84         value[values] = '\0';
85
86         setenv(name, value, 1);
87         ficlFree(name);
88         ficlFree(value);
89
90         return;
91 }
92
93 void
94 ficlSetenvq(FICL_VM *pVM)
95 {
96         char    *namep, *valuep, *name, *value;
97         int     names, values, overwrite;
98
99 #if FICL_ROBUST > 1
100         vmCheckStack(pVM, 5, 0);
101 #endif
102         overwrite = stackPopINT(pVM->pStack);
103         names = stackPopINT(pVM->pStack);
104         namep = (char*) stackPopPtr(pVM->pStack);
105         values = stackPopINT(pVM->pStack);
106         valuep = (char*) stackPopPtr(pVM->pStack);
107
108         name = (char*) ficlMalloc(names+1);
109         if (!name)
110                 vmThrowErr(pVM, "Error: out of memory");
111         strncpy(name, namep, names);
112         name[names] = '\0';
113         value = (char*) ficlMalloc(values+1);
114         if (!value)
115                 vmThrowErr(pVM, "Error: out of memory");
116         strncpy(value, valuep, values);
117         value[values] = '\0';
118
119         setenv(name, value, overwrite);
120         ficlFree(name);
121         ficlFree(value);
122
123         return;
124 }
125
126 void
127 ficlGetenv(FICL_VM *pVM)
128 {
129         char    *namep, *name, *value;
130         int     names;
131
132 #if FICL_ROBUST > 1
133         vmCheckStack(pVM, 2, 2);
134 #endif
135         names = stackPopINT(pVM->pStack);
136         namep = (char*) stackPopPtr(pVM->pStack);
137
138         name = (char*) ficlMalloc(names+1);
139         if (!name)
140                 vmThrowErr(pVM, "Error: out of memory");
141         strncpy(name, namep, names);
142         name[names] = '\0';
143
144         value = getenv(name);
145         ficlFree(name);
146
147         if(value != NULL) {
148                 stackPushPtr(pVM->pStack, value);
149                 stackPushINT(pVM->pStack, strlen(value));
150         } else
151                 stackPushINT(pVM->pStack, -1);
152
153         return;
154 }
155
156 void
157 ficlUnsetenv(FICL_VM *pVM)
158 {
159         char    *namep, *name;
160         int     names;
161
162 #if FICL_ROBUST > 1
163         vmCheckStack(pVM, 2, 0);
164 #endif
165         names = stackPopINT(pVM->pStack);
166         namep = (char*) stackPopPtr(pVM->pStack);
167
168         name = (char*) ficlMalloc(names+1);
169         if (!name)
170                 vmThrowErr(pVM, "Error: out of memory");
171         strncpy(name, namep, names);
172         name[names] = '\0';
173
174         unsetenv(name);
175         ficlFree(name);
176
177         return;
178 }
179
180 void
181 ficlCopyin(FICL_VM *pVM)
182 {
183         void*           src;
184         vm_offset_t     dest;
185         size_t          len;
186
187 #if FICL_ROBUST > 1
188         vmCheckStack(pVM, 3, 0);
189 #endif
190
191         len = stackPopINT(pVM->pStack);
192         dest = stackPopINT(pVM->pStack);
193         src = stackPopPtr(pVM->pStack);
194
195         archsw.arch_copyin(src, dest, len);
196
197         return;
198 }
199
200 void
201 ficlCopyout(FICL_VM *pVM)
202 {
203         void*           dest;
204         vm_offset_t     src;
205         size_t          len;
206
207 #if FICL_ROBUST > 1
208         vmCheckStack(pVM, 3, 0);
209 #endif
210
211         len = stackPopINT(pVM->pStack);
212         dest = stackPopPtr(pVM->pStack);
213         src = stackPopINT(pVM->pStack);
214
215         archsw.arch_copyout(src, dest, len);
216
217         return;
218 }
219
220 void
221 ficlFindfile(FICL_VM *pVM)
222 {
223         char    *name, *type, *namep, *typep;
224         struct  preloaded_file* fp;
225         int     names, types;
226
227 #if FICL_ROBUST > 1
228         vmCheckStack(pVM, 4, 1);
229 #endif
230
231         types = stackPopINT(pVM->pStack);
232         typep = (char*) stackPopPtr(pVM->pStack);
233         names = stackPopINT(pVM->pStack);
234         namep = (char*) stackPopPtr(pVM->pStack);
235         name = (char*) ficlMalloc(names+1);
236         if (!name)
237                 vmThrowErr(pVM, "Error: out of memory");
238         strncpy(name, namep, names);
239         name[names] = '\0';
240         type = (char*) ficlMalloc(types+1);
241         if (!type)
242                 vmThrowErr(pVM, "Error: out of memory");
243         strncpy(type, typep, types);
244         type[types] = '\0';
245
246         fp = file_findfile(name, type);
247         stackPushPtr(pVM->pStack, fp);
248
249         return;
250 }
251
252 #ifdef HAVE_PNP
253
254 void
255 ficlPnpdevices(FICL_VM *pVM)
256 {
257         static int pnp_devices_initted = 0;
258 #if FICL_ROBUST > 1
259         vmCheckStack(pVM, 0, 1);
260 #endif
261
262         if(!pnp_devices_initted) {
263                 STAILQ_INIT(&pnp_devices);
264                 pnp_devices_initted = 1;
265         }
266
267         stackPushPtr(pVM->pStack, &pnp_devices);
268
269         return;
270 }
271
272 void
273 ficlPnphandlers(FICL_VM *pVM)
274 {
275 #if FICL_ROBUST > 1
276         vmCheckStack(pVM, 0, 1);
277 #endif
278
279         stackPushPtr(pVM->pStack, pnphandlers);
280
281         return;
282 }
283
284 #endif
285
286 #endif /* ndef TESTMAIN */
287
288 void
289 ficlCcall(FICL_VM *pVM)
290 {
291         int (*func)(int, ...);
292         int result, p[10];
293         int nparam, i;
294
295 #if FICL_ROBUST > 1
296         vmCheckStack(pVM, 2, 0);
297 #endif
298
299         func = stackPopPtr(pVM->pStack);
300         nparam = stackPopINT(pVM->pStack);
301
302 #if FICL_ROBUST > 1
303         vmCheckStack(pVM, nparam, 1);
304 #endif
305
306         for (i = 0; i < nparam; i++)
307                 p[i] = stackPopINT(pVM->pStack);
308
309         result = func(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8],
310             p[9]);
311
312         stackPushINT(pVM->pStack, result);
313
314         return;
315 }
316
317 /**************************************************************************
318                         f i c l E x e c F D
319 ** reads in text from file fd and passes it to ficlExec()
320  * returns VM_OUTOFTEXT on success or the ficlExec() error code on
321  * failure.
322  */ 
323 #define nLINEBUF 256
324 int ficlExecFD(FICL_VM *pVM, int fd)
325 {
326     char    cp[nLINEBUF];
327     int     nLine = 0, rval = VM_OUTOFTEXT;
328     char    ch;
329     CELL    id;
330
331     id = pVM->sourceID;
332     pVM->sourceID.i = fd;
333
334     /* feed each line to ficlExec */
335     while (1) {
336         int status, i;
337
338         i = 0;
339         while ((status = read(fd, &ch, 1)) > 0 && ch != '\n')
340             cp[i++] = ch;
341         nLine++;
342         if (!i) {
343             if (status < 1)
344                 break;
345             continue;
346         }
347         rval = ficlExecC(pVM, cp, i);
348         if(rval != VM_QUIT && rval != VM_USEREXIT && rval != VM_OUTOFTEXT)
349         {
350             pVM->sourceID = id;
351             return rval; 
352         }
353     }
354     /*
355     ** Pass an empty line with SOURCE-ID == -1 to flush
356     ** any pending REFILLs (as required by FILE wordset)
357     */
358     pVM->sourceID.i = -1;
359     ficlExec(pVM, "");
360
361     pVM->sourceID = id;
362     return rval;
363 }
364
365 static void displayCellNoPad(FICL_VM *pVM)
366 {
367     CELL c;
368 #if FICL_ROBUST > 1
369     vmCheckStack(pVM, 1, 0);
370 #endif
371     c = stackPop(pVM->pStack);
372     ltoa((c).i, pVM->pad, pVM->base);
373     vmTextOut(pVM, pVM->pad, 0);
374     return;
375 }
376
377 /*          fopen - open a file and return new fd on stack.
378  *
379  * fopen ( ptr count mode -- fd )
380  */
381 static void pfopen(FICL_VM *pVM)
382 {
383     int     mode, fd, count;
384     char    *ptr, *name;
385
386 #if FICL_ROBUST > 1
387     vmCheckStack(pVM, 3, 1);
388 #endif
389
390     mode = stackPopINT(pVM->pStack);    /* get mode */
391     count = stackPopINT(pVM->pStack);   /* get count */
392     ptr = stackPopPtr(pVM->pStack);     /* get ptr */
393
394     if ((count < 0) || (ptr == NULL)) {
395         stackPushINT(pVM->pStack, -1);
396         return;
397     }
398
399     /* ensure that the string is null terminated */
400     name = (char *)malloc(count+1);
401     bcopy(ptr,name,count);
402     name[count] = 0;
403
404     /* open the file */
405     fd = open(name, mode);
406     free(name);
407     stackPushINT(pVM->pStack, fd);
408     return;
409 }
410  
411 /*          fclose - close a file who's fd is on stack.
412  *
413  * fclose ( fd -- )
414  */
415 static void pfclose(FICL_VM *pVM)
416 {
417     int fd;
418
419 #if FICL_ROBUST > 1
420     vmCheckStack(pVM, 1, 0);
421 #endif
422     fd = stackPopINT(pVM->pStack); /* get fd */
423     if (fd != -1)
424         close(fd);
425     return;
426 }
427
428 /*          fread - read file contents
429  *
430  * fread  ( fd buf nbytes  -- nread )
431  */
432 static void pfread(FICL_VM *pVM)
433 {
434     int     fd, len;
435     char *buf;
436
437 #if FICL_ROBUST > 1
438     vmCheckStack(pVM, 3, 1);
439 #endif
440     len = stackPopINT(pVM->pStack); /* get number of bytes to read */
441     buf = stackPopPtr(pVM->pStack); /* get buffer */
442     fd = stackPopINT(pVM->pStack); /* get fd */
443     if (len > 0 && buf && fd != -1)
444         stackPushINT(pVM->pStack, read(fd, buf, len));
445     else
446         stackPushINT(pVM->pStack, -1);
447     return;
448 }
449
450 /*          fload - interpret file contents
451  *
452  * fload  ( fd -- )
453  */
454 static void pfload(FICL_VM *pVM)
455 {
456     int     fd;
457
458 #if FICL_ROBUST > 1
459     vmCheckStack(pVM, 1, 0);
460 #endif
461     fd = stackPopINT(pVM->pStack); /* get fd */
462     if (fd != -1)
463         ficlExecFD(pVM, fd);
464     return;
465 }
466
467 /*          fwrite - write file contents
468  *
469  * fwrite  ( fd buf nbytes  -- nwritten )
470  */
471 static void pfwrite(FICL_VM *pVM)
472 {
473     int     fd, len;
474     char *buf;
475
476 #if FICL_ROBUST > 1
477     vmCheckStack(pVM, 3, 1);
478 #endif
479     len = stackPopINT(pVM->pStack); /* get number of bytes to read */
480     buf = stackPopPtr(pVM->pStack); /* get buffer */
481     fd = stackPopINT(pVM->pStack); /* get fd */
482     if (len > 0 && buf && fd != -1)
483         stackPushINT(pVM->pStack, write(fd, buf, len));
484     else
485         stackPushINT(pVM->pStack, -1);
486     return;
487 }
488
489 /*          fseek - seek to a new position in a file
490  *
491  * fseek  ( fd ofs whence  -- pos )
492  */
493 static void pfseek(FICL_VM *pVM)
494 {
495     int     fd, pos, whence;
496
497 #if FICL_ROBUST > 1
498     vmCheckStack(pVM, 3, 1);
499 #endif
500     whence = stackPopINT(pVM->pStack);
501     pos = stackPopINT(pVM->pStack);
502     fd = stackPopINT(pVM->pStack);
503     stackPushINT(pVM->pStack, lseek(fd, pos, whence));
504     return;
505 }
506
507 /*           key - get a character from stdin
508  *
509  * key ( -- char )
510  */
511 static void key(FICL_VM *pVM)
512 {
513 #if FICL_ROBUST > 1
514     vmCheckStack(pVM, 0, 1);
515 #endif
516     stackPushINT(pVM->pStack, getchar());
517     return;
518 }
519
520 /*           key? - check for a character from stdin (FACILITY)
521  *
522  * key? ( -- flag )
523  */
524 static void keyQuestion(FICL_VM *pVM)
525 {
526 #if FICL_ROBUST > 1
527     vmCheckStack(pVM, 0, 1);
528 #endif
529 #ifdef TESTMAIN
530     /* XXX Since we don't fiddle with termios, let it always succeed... */
531     stackPushINT(pVM->pStack, FICL_TRUE);
532 #else
533     /* But here do the right thing. */
534     stackPushINT(pVM->pStack, ischar()? FICL_TRUE : FICL_FALSE);
535 #endif
536     return;
537 }
538
539 /* seconds - gives number of seconds since beginning of time
540  *
541  * beginning of time is defined as:
542  *
543  *      BTX     - number of seconds since midnight
544  *      FreeBSD - number of seconds since Jan 1 1970
545  *
546  * seconds ( -- u )
547  */
548 static void pseconds(FICL_VM *pVM)
549 {
550 #if FICL_ROBUST > 1
551     vmCheckStack(pVM,0,1);
552 #endif
553     stackPushUNS(pVM->pStack, (FICL_UNS) time(NULL));
554     return;
555 }
556
557 /* ms - wait at least that many milliseconds (FACILITY)
558  *
559  * ms ( u -- )
560  *
561  */
562 static void ms(FICL_VM *pVM)
563 {
564 #if FICL_ROBUST > 1
565     vmCheckStack(pVM,1,0);
566 #endif
567 #ifdef TESTMAIN
568     usleep(stackPopUNS(pVM->pStack)*1000);
569 #else
570     delay(stackPopUNS(pVM->pStack)*1000);
571 #endif
572     return;
573 }
574
575 /*           fkey - get a character from a file
576  *
577  * fkey ( file -- char )
578  */
579 static void fkey(FICL_VM *pVM)
580 {
581     int i, fd;
582     char ch;
583
584 #if FICL_ROBUST > 1
585     vmCheckStack(pVM, 1, 1);
586 #endif
587     fd = stackPopINT(pVM->pStack);
588     i = read(fd, &ch, 1);
589     stackPushINT(pVM->pStack, i > 0 ? ch : -1);
590     return;
591 }
592
593 /*
594 ** Retrieves free space remaining on the dictionary
595 */
596
597 static void freeHeap(FICL_VM *pVM)
598 {
599     stackPushINT(pVM->pStack, dictCellsAvail(ficlGetDict(pVM->pSys)));
600 }
601
602
603 /******************* Increase dictionary size on-demand ******************/
604  
605 static void ficlDictThreshold(FICL_VM *pVM)
606 {
607     stackPushPtr(pVM->pStack, &dictThreshold);
608 }
609  
610 static void ficlDictIncrease(FICL_VM *pVM)
611 {
612     stackPushPtr(pVM->pStack, &dictIncrease);
613 }
614
615
616 /**************************************************************************
617                         f i c l C o m p i l e P l a t f o r m
618 ** Build FreeBSD platform extensions into the system dictionary
619 **************************************************************************/
620 void ficlCompilePlatform(FICL_SYSTEM *pSys)
621 {
622     FICL_DICT *dp = pSys->dp;
623     assert (dp);
624
625     dictAppendWord(dp, ".#",        displayCellNoPad,    FW_DEFAULT);
626     dictAppendWord(dp, "fopen",     pfopen,         FW_DEFAULT);
627     dictAppendWord(dp, "fclose",    pfclose,        FW_DEFAULT);
628     dictAppendWord(dp, "fread",     pfread,         FW_DEFAULT);
629     dictAppendWord(dp, "fload",     pfload,         FW_DEFAULT);
630     dictAppendWord(dp, "fkey",      fkey,           FW_DEFAULT);
631     dictAppendWord(dp, "fseek",     pfseek,         FW_DEFAULT);
632     dictAppendWord(dp, "fwrite",    pfwrite,        FW_DEFAULT);
633     dictAppendWord(dp, "key",       key,            FW_DEFAULT);
634     dictAppendWord(dp, "key?",      keyQuestion,    FW_DEFAULT);
635     dictAppendWord(dp, "ms",        ms,             FW_DEFAULT);
636     dictAppendWord(dp, "seconds",   pseconds,       FW_DEFAULT);
637     dictAppendWord(dp, "heap?",     freeHeap,       FW_DEFAULT);
638     dictAppendWord(dp, "dictthreshold", ficlDictThreshold, FW_DEFAULT);
639     dictAppendWord(dp, "dictincrease", ficlDictIncrease, FW_DEFAULT);
640
641 #ifndef TESTMAIN
642 #ifdef __i386__
643     dictAppendWord(dp, "outb",      ficlOutb,       FW_DEFAULT);
644     dictAppendWord(dp, "inb",       ficlInb,        FW_DEFAULT);
645 #endif
646     dictAppendWord(dp, "setenv",    ficlSetenv,     FW_DEFAULT);
647     dictAppendWord(dp, "setenv?",   ficlSetenvq,    FW_DEFAULT);
648     dictAppendWord(dp, "getenv",    ficlGetenv,     FW_DEFAULT);
649     dictAppendWord(dp, "unsetenv",  ficlUnsetenv,   FW_DEFAULT);
650     dictAppendWord(dp, "copyin",    ficlCopyin,     FW_DEFAULT);
651     dictAppendWord(dp, "copyout",   ficlCopyout,    FW_DEFAULT);
652     dictAppendWord(dp, "findfile",  ficlFindfile,   FW_DEFAULT);
653 #ifdef HAVE_PNP
654     dictAppendWord(dp, "pnpdevices",ficlPnpdevices, FW_DEFAULT);
655     dictAppendWord(dp, "pnphandlers",ficlPnphandlers, FW_DEFAULT);
656 #endif
657     dictAppendWord(dp, "ccall",     ficlCcall,      FW_DEFAULT);
658 #endif
659
660 #if defined(PC98)
661     ficlSetEnv(pSys, "arch-pc98",         FICL_TRUE);
662 #elif defined(__i386__)
663     ficlSetEnv(pSys, "arch-i386",         FICL_TRUE);
664     ficlSetEnv(pSys, "arch-alpha",        FICL_FALSE);
665     ficlSetEnv(pSys, "arch-ia64",         FICL_FALSE);
666 #elif defined(__alpha__)
667     ficlSetEnv(pSys, "arch-i386",         FICL_FALSE);
668     ficlSetEnv(pSys, "arch-alpha",        FICL_TRUE);
669     ficlSetEnv(pSys, "arch-ia64",         FICL_FALSE);
670 #elif defined(__ia64__)
671     ficlSetEnv(pSys, "arch-i386",         FICL_FALSE);
672     ficlSetEnv(pSys, "arch-alpha",        FICL_FALSE);
673     ficlSetEnv(pSys, "arch-ia64",         FICL_TRUE);
674 #endif
675
676     return;
677 }
678