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