xref: /illumos-gate/usr/src/common/ficl/loader.c (revision ce8560eeb961d528e27685fcdd2ffb03e9478dbf)
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 void
434 ficlCcall(ficlVm *pVM)
435 {
436 	int (*func)(int, ...);
437 	int result, p[10];
438 	int nparam, i;
439 
440 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 0);
441 
442 	func = (int (*)(int, ...))ficlStackPopPointer(ficlVmGetDataStack(pVM));
443 	nparam = ficlStackPopInteger(ficlVmGetDataStack(pVM));
444 
445 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), nparam, 1);
446 
447 	for (i = 0; i < nparam; i++)
448 		p[i] = ficlStackPopInteger(ficlVmGetDataStack(pVM));
449 
450 	result = func(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8],
451 	    p[9]);
452 
453 	ficlStackPushInteger(ficlVmGetDataStack(pVM), result);
454 }
455 
456 void
457 ficlUuidFromString(ficlVm *pVM)
458 {
459 	char	*uuid;
460 	char	*uuid_ptr;
461 	int	uuid_size;
462 	uuid_t	*u;
463 #ifdef _STANDALONE
464 	uint32_t status;
465 #else
466 	int status;
467 #endif
468 
469 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 0);
470 
471 	uuid_size = ficlStackPopInteger(ficlVmGetDataStack(pVM));
472 	uuid_ptr = ficlStackPopPointer(ficlVmGetDataStack(pVM));
473 
474 	uuid = ficlMalloc(uuid_size + 1);
475 	if (!uuid)
476 		ficlVmThrowError(pVM, "Error: out of memory");
477 	(void) memcpy(uuid, uuid_ptr, uuid_size);
478 	uuid[uuid_size] = '\0';
479 
480 	u = ficlMalloc(sizeof (*u));
481 #ifdef _STANDALONE
482 	uuid_from_string(uuid, u, &status);
483 	ficlFree(uuid);
484 	if (status != uuid_s_ok) {
485 		ficlFree(u);
486 		u = NULL;
487 	}
488 #else
489 	status = uuid_parse(uuid, *u);
490 	ficlFree(uuid);
491 	if (status != 0) {
492 		ficlFree(u);
493 		u = NULL;
494 	}
495 #endif
496 	ficlStackPushPointer(ficlVmGetDataStack(pVM), u);
497 }
498 
499 void
500 ficlUuidToString(ficlVm *pVM)
501 {
502 	char	*uuid;
503 	uuid_t	*u;
504 #ifdef _STANDALONE
505 	uint32_t status;
506 #endif
507 
508 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
509 
510 	u = ficlStackPopPointer(ficlVmGetDataStack(pVM));
511 #ifdef _STANDALONE
512 	uuid_to_string(u, &uuid, &status);
513 	if (status == uuid_s_ok) {
514 		ficlStackPushPointer(ficlVmGetDataStack(pVM), uuid);
515 		ficlStackPushInteger(ficlVmGetDataStack(pVM), strlen(uuid));
516 	} else
517 #else
518 	uuid = ficlMalloc(UUID_PRINTABLE_STRING_LENGTH);
519 	if (uuid != NULL) {
520 		uuid_unparse(*u, uuid);
521 		ficlStackPushPointer(ficlVmGetDataStack(pVM), uuid);
522 		ficlStackPushInteger(ficlVmGetDataStack(pVM), strlen(uuid));
523 	} else
524 #endif
525 		ficlStackPushInteger(ficlVmGetDataStack(pVM), -1);
526 }
527 
528 /*
529  * f i c l E x e c F D
530  * reads in text from file fd and passes it to ficlExec()
531  * returns FICL_VM_STATUS_OUT_OF_TEXT on success or the ficlExec() error
532  * code on failure.
533  */
534 #define	nLINEBUF	256
535 int
536 ficlExecFD(ficlVm *pVM, int fd)
537 {
538 	char cp[nLINEBUF];
539 	int nLine = 0, rval = FICL_VM_STATUS_OUT_OF_TEXT;
540 	char ch;
541 	ficlCell id;
542 	ficlString s;
543 
544 	id = pVM->sourceId;
545 	pVM->sourceId.i = fd+1; /* in loader we can get 0, there is no stdin */
546 
547 	/* feed each line to ficlExec */
548 	while (1) {
549 		int status, i;
550 
551 		i = 0;
552 		while ((status = read(fd, &ch, 1)) > 0 && ch != '\n')
553 			cp[i++] = ch;
554 		nLine++;
555 		if (!i) {
556 			if (status < 1)
557 				break;
558 			continue;
559 		}
560 		if (cp[i] == '\n')
561 			cp[i] = '\0';
562 
563 		FICL_STRING_SET_POINTER(s, cp);
564 		FICL_STRING_SET_LENGTH(s, i);
565 
566 		rval = ficlVmExecuteString(pVM, s);
567 		if (rval != FICL_VM_STATUS_QUIT &&
568 		    rval != FICL_VM_STATUS_USER_EXIT &&
569 		    rval != FICL_VM_STATUS_OUT_OF_TEXT) {
570 			pVM->sourceId = id;
571 			(void) ficlVmEvaluate(pVM, "");
572 			return (rval);
573 		}
574 	}
575 	pVM->sourceId = id;
576 
577 	/*
578 	 * Pass an empty line with SOURCE-ID == -1 to flush
579 	 * any pending REFILLs (as required by FILE wordset)
580 	 */
581 	(void) ficlVmEvaluate(pVM, "");
582 
583 	if (rval == FICL_VM_STATUS_USER_EXIT)
584 		ficlVmThrow(pVM, FICL_VM_STATUS_USER_EXIT);
585 
586 	return (rval);
587 }
588 
589 static void displayCellNoPad(ficlVm *pVM)
590 {
591 	ficlCell c;
592 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
593 
594 	c = ficlStackPop(ficlVmGetDataStack(pVM));
595 	(void) ficlLtoa((c).i, pVM->pad, pVM->base);
596 	ficlVmTextOut(pVM, pVM->pad);
597 }
598 
599 /*
600  * isdir? - Return whether an fd corresponds to a directory.
601  *
602  * isdir? ( fd -- bool )
603  */
604 static void
605 isdirQuestion(ficlVm *pVM)
606 {
607 	struct stat sb;
608 	ficlInteger flag;
609 	int fd;
610 
611 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 1);
612 
613 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM));
614 	flag = FICL_FALSE;
615 	do {
616 		if (fd < 0)
617 			break;
618 		if (fstat(fd, &sb) < 0)
619 			break;
620 		if (!S_ISDIR(sb.st_mode))
621 			break;
622 		flag = FICL_TRUE;
623 	} while (0);
624 	ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
625 }
626 
627 /*
628  * fopen - open a file and return new fd on stack.
629  *
630  * fopen ( ptr count mode -- fd )
631  */
632 extern char *get_dev(const char *);
633 
634 static void
635 pfopen(ficlVm *pVM)
636 {
637 	int mode, fd, count;
638 	char *ptr, *name;
639 #ifndef _STANDALONE
640 	char *tmp;
641 #endif
642 
643 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1);
644 
645 	mode = ficlStackPopInteger(ficlVmGetDataStack(pVM));	/* get mode */
646 	count = ficlStackPopInteger(ficlVmGetDataStack(pVM));	/* get count */
647 	ptr = ficlStackPopPointer(ficlVmGetDataStack(pVM));	/* get ptr */
648 
649 	if ((count < 0) || (ptr == NULL)) {
650 		ficlStackPushInteger(ficlVmGetDataStack(pVM), -1);
651 		return;
652 	}
653 
654 	/* ensure that the string is null terminated */
655 	name = (char *)malloc(count+1);
656 	bcopy(ptr, name, count);
657 	name[count] = 0;
658 #ifndef _STANDALONE
659 	tmp = get_dev(name);
660 	free(name);
661 	name = tmp;
662 #endif
663 
664 	/* open the file */
665 	fd = open(name, mode);
666 	free(name);
667 	ficlStackPushInteger(ficlVmGetDataStack(pVM), fd);
668 }
669 
670 /*
671  * fclose - close a file who's fd is on stack.
672  * fclose ( fd -- )
673  */
674 static void
675 pfclose(ficlVm *pVM)
676 {
677 	int fd;
678 
679 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
680 
681 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */
682 	if (fd != -1)
683 		(void) close(fd);
684 }
685 
686 /*
687  * fread - read file contents
688  * fread  ( fd buf nbytes  -- nread )
689  */
690 static void
691 pfread(ficlVm *pVM)
692 {
693 	int fd, len;
694 	char *buf;
695 
696 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1);
697 
698 	len = ficlStackPopInteger(ficlVmGetDataStack(pVM));
699 	buf = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get buffer */
700 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */
701 	if (len > 0 && buf && fd != -1)
702 		ficlStackPushInteger(ficlVmGetDataStack(pVM),
703 		    read(fd, buf, len));
704 	else
705 		ficlStackPushInteger(ficlVmGetDataStack(pVM), -1);
706 }
707 
708 /*
709  * fopendir - open directory
710  *
711  * fopendir ( addr len -- ptr TRUE | FALSE )
712  */
713 static void pfopendir(ficlVm *pVM)
714 {
715 #ifndef _STANDALONE
716 	DIR *dir;
717 	char *tmp;
718 #else
719 	struct stat sb;
720 	int fd;
721 #endif
722 	ficlInteger count;
723 	char *ptr, *name;
724 	ficlInteger flag = FICL_FALSE;
725 
726 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 1);
727 
728 	count = ficlStackPopInteger(ficlVmGetDataStack(pVM));
729 	ptr = ficlStackPopPointer(ficlVmGetDataStack(pVM));	/* get ptr */
730 
731 	if ((count < 0) || (ptr == NULL)) {
732 		ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
733 		return;
734 	}
735 	/* ensure that the string is null terminated */
736 	if ((name = malloc(count + 1)) == NULL) {
737 		ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
738 		return;
739 	}
740 
741 	bcopy(ptr, name, count);
742 	name[count] = 0;
743 #ifndef _STANDALONE
744 	tmp = get_dev(name);
745 	free(name);
746 	name = tmp;
747 
748 	dir = opendir(name);
749 	if (dir == NULL) {
750 		ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
751 		return;
752 	} else
753 		flag = FICL_TRUE;
754 
755 	ficlStackPushPointer(ficlVmGetDataStack(pVM), dir);
756 	ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
757 #else
758 	fd = open(name, O_RDONLY);
759 	free(name);
760 	do {
761 		if (fd < 0)
762 			break;
763 		if (fstat(fd, &sb) < 0)
764 			break;
765 		if (!S_ISDIR(sb.st_mode))
766 			break;
767 		flag = FICL_TRUE;
768 		ficlStackPushInteger(ficlVmGetDataStack(pVM), fd);
769 		ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
770 		return;
771 	} while (0);
772 
773 	if (fd >= 0)
774 		close(fd);
775 
776 	ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
777 #endif
778 }
779 
780 /*
781  * freaddir - read directory contents
782  * freaddir ( fd -- ptr len TRUE | FALSE )
783  */
784 static void
785 pfreaddir(ficlVm *pVM)
786 {
787 #ifndef _STANDALONE
788 	static DIR *dir = NULL;
789 #else
790 	int fd;
791 #endif
792 	struct dirent *d = NULL;
793 
794 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 3);
795 	/*
796 	 * libstand readdir does not always return . nor .. so filter
797 	 * them out to have consistent behaviour.
798 	 */
799 #ifndef _STANDALONE
800 	dir = ficlStackPopPointer(ficlVmGetDataStack(pVM));
801 	if (dir != NULL)
802 		do {
803 			d = readdir(dir);
804 			if (d != NULL && strcmp(d->d_name, ".") == 0)
805 				continue;
806 			if (d != NULL && strcmp(d->d_name, "..") == 0)
807 				continue;
808 			break;
809 		} while (d != NULL);
810 #else
811 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM));
812 	if (fd != -1)
813 		do {
814 			d = readdirfd(fd);
815 			if (d != NULL && strcmp(d->d_name, ".") == 0)
816 				continue;
817 			if (d != NULL && strcmp(d->d_name, "..") == 0)
818 				continue;
819 			break;
820 		} while (d != NULL);
821 #endif
822 	if (d != NULL) {
823 		ficlStackPushPointer(ficlVmGetDataStack(pVM), d->d_name);
824 		ficlStackPushInteger(ficlVmGetDataStack(pVM),
825 		    strlen(d->d_name));
826 		ficlStackPushInteger(ficlVmGetDataStack(pVM), FICL_TRUE);
827 	} else {
828 		ficlStackPushInteger(ficlVmGetDataStack(pVM), FICL_FALSE);
829 	}
830 }
831 
832 /*
833  * fclosedir - close a dir on stack.
834  *
835  * fclosedir ( fd -- )
836  */
837 static void
838 pfclosedir(ficlVm *pVM)
839 {
840 #ifndef _STANDALONE
841 	DIR *dir;
842 #else
843 	int fd;
844 #endif
845 
846 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
847 
848 #ifndef _STANDALONE
849 	dir = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get dir */
850 	if (dir != NULL)
851 		(void) closedir(dir);
852 #else
853 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */
854 	if (fd != -1)
855 		(void) close(fd);
856 #endif
857 }
858 
859 /*
860  * fload - interpret file contents
861  *
862  * fload  ( fd -- )
863  */
864 static void pfload(ficlVm *pVM)
865 {
866 	int fd;
867 
868 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
869 
870 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */
871 	if (fd != -1)
872 		(void) ficlExecFD(pVM, fd);
873 }
874 
875 /*
876  * fwrite - write file contents
877  *
878  * fwrite  ( fd buf nbytes  -- nwritten )
879  */
880 static void
881 pfwrite(ficlVm *pVM)
882 {
883 	int fd, len;
884 	char *buf;
885 
886 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1);
887 
888 	len = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* bytes to read */
889 	buf = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get buffer */
890 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */
891 	if (len > 0 && buf && fd != -1)
892 		ficlStackPushInteger(ficlVmGetDataStack(pVM),
893 		    write(fd, buf, len));
894 	else
895 		ficlStackPushInteger(ficlVmGetDataStack(pVM), -1);
896 }
897 
898 /*
899  * fseek - seek to a new position in a file
900  *
901  * fseek  ( fd ofs whence  -- pos )
902  */
903 static void
904 pfseek(ficlVm *pVM)
905 {
906 	int fd, pos, whence;
907 
908 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1);
909 
910 	whence = ficlStackPopInteger(ficlVmGetDataStack(pVM));
911 	pos = ficlStackPopInteger(ficlVmGetDataStack(pVM));
912 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM));
913 	ficlStackPushInteger(ficlVmGetDataStack(pVM), lseek(fd, pos, whence));
914 }
915 
916 /*
917  * key - get a character from stdin
918  *
919  * key ( -- char )
920  */
921 static void
922 key(ficlVm *pVM)
923 {
924 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1);
925 
926 	ficlStackPushInteger(ficlVmGetDataStack(pVM), getchar());
927 }
928 
929 /*
930  * key? - check for a character from stdin (FACILITY)
931  * key? ( -- flag )
932  */
933 static void
934 keyQuestion(ficlVm *pVM)
935 {
936 #ifndef _STANDALONE
937 	char ch = -1;
938 	struct termios oldt;
939 	struct termios newt;
940 #endif
941 
942 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1);
943 
944 #ifndef _STANDALONE
945 	(void) tcgetattr(STDIN_FILENO, &oldt);
946 	newt = oldt;
947 	newt.c_lflag &= ~(ICANON | ECHO);
948 	newt.c_cc[VMIN] = 0;
949 	newt.c_cc[VTIME] = 0;
950 	(void) tcsetattr(STDIN_FILENO, TCSANOW, &newt);
951 	ch = getchar();
952 	(void) tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
953 
954 	if (ch != -1)
955 		(void) ungetc(ch, stdin);
956 
957 	ficlStackPushInteger(ficlVmGetDataStack(pVM),
958 	    ch != -1? FICL_TRUE : FICL_FALSE);
959 #else
960 	ficlStackPushInteger(ficlVmGetDataStack(pVM),
961 	    ischar()? FICL_TRUE : FICL_FALSE);
962 #endif
963 }
964 
965 /*
966  * seconds - gives number of seconds since beginning of time
967  *
968  * beginning of time is defined as:
969  *
970  *	BTX	- number of seconds since midnight
971  *	FreeBSD	- number of seconds since Jan 1 1970
972  *
973  * seconds ( -- u )
974  */
975 static void
976 pseconds(ficlVm *pVM)
977 {
978 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1);
979 
980 	ficlStackPushUnsigned(ficlVmGetDataStack(pVM),
981 	    (ficlUnsigned) time(NULL));
982 }
983 
984 /*
985  * ms - wait at least that many milliseconds (FACILITY)
986  * ms ( u -- )
987  */
988 static void
989 ms(ficlVm *pVM)
990 {
991 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
992 
993 #ifndef _STANDALONE
994 	(void) usleep(ficlStackPopUnsigned(ficlVmGetDataStack(pVM)) * 1000);
995 #else
996 	delay(ficlStackPopUnsigned(ficlVmGetDataStack(pVM)) * 1000);
997 #endif
998 }
999 
1000 /*
1001  * fkey - get a character from a file
1002  * fkey ( file -- char )
1003  */
1004 static void
1005 fkey(ficlVm *pVM)
1006 {
1007 	int i, fd;
1008 	char ch;
1009 
1010 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 1);
1011 
1012 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM));
1013 	i = read(fd, &ch, 1);
1014 	ficlStackPushInteger(ficlVmGetDataStack(pVM), i > 0 ? ch : -1);
1015 }
1016 
1017 /*
1018  * Retrieves free space remaining on the dictionary
1019  */
1020 static void
1021 freeHeap(ficlVm *pVM)
1022 {
1023 	ficlStackPushInteger(ficlVmGetDataStack(pVM),
1024 	    ficlDictionaryCellsAvailable(ficlVmGetDictionary(pVM)));
1025 }
1026 
1027 /*
1028  * f i c l C o m p i l e P l a t f o r m
1029  * Build FreeBSD platform extensions into the system dictionary
1030  */
1031 void
1032 ficlSystemCompilePlatform(ficlSystem *pSys)
1033 {
1034 	ficlDictionary *dp = ficlSystemGetDictionary(pSys);
1035 	ficlDictionary *env = ficlSystemGetEnvironment(pSys);
1036 #ifdef _STANDALONE
1037 	ficlCompileFcn **fnpp;
1038 #endif
1039 
1040 	FICL_SYSTEM_ASSERT(pSys, dp);
1041 	FICL_SYSTEM_ASSERT(pSys, env);
1042 
1043 	(void) ficlDictionarySetPrimitive(dp, ".#", displayCellNoPad,
1044 	    FICL_WORD_DEFAULT);
1045 	(void) ficlDictionarySetPrimitive(dp, "isdir?", isdirQuestion,
1046 	    FICL_WORD_DEFAULT);
1047 	(void) ficlDictionarySetPrimitive(dp, "fopen", pfopen,
1048 	    FICL_WORD_DEFAULT);
1049 	(void) ficlDictionarySetPrimitive(dp, "fclose", pfclose,
1050 	    FICL_WORD_DEFAULT);
1051 	(void) ficlDictionarySetPrimitive(dp, "fread", pfread,
1052 	    FICL_WORD_DEFAULT);
1053 	(void) ficlDictionarySetPrimitive(dp, "fopendir", pfopendir,
1054 	    FICL_WORD_DEFAULT);
1055 	(void) ficlDictionarySetPrimitive(dp, "freaddir", pfreaddir,
1056 	    FICL_WORD_DEFAULT);
1057 	(void) ficlDictionarySetPrimitive(dp, "fclosedir", pfclosedir,
1058 	    FICL_WORD_DEFAULT);
1059 	(void) ficlDictionarySetPrimitive(dp, "fload", pfload,
1060 	    FICL_WORD_DEFAULT);
1061 	(void) ficlDictionarySetPrimitive(dp, "fkey", fkey,
1062 	    FICL_WORD_DEFAULT);
1063 	(void) ficlDictionarySetPrimitive(dp, "fseek", pfseek,
1064 	    FICL_WORD_DEFAULT);
1065 	(void) ficlDictionarySetPrimitive(dp, "fwrite", pfwrite,
1066 	    FICL_WORD_DEFAULT);
1067 	(void) ficlDictionarySetPrimitive(dp, "key", key, FICL_WORD_DEFAULT);
1068 	(void) ficlDictionarySetPrimitive(dp, "key?", keyQuestion,
1069 	    FICL_WORD_DEFAULT);
1070 	(void) ficlDictionarySetPrimitive(dp, "ms", ms, FICL_WORD_DEFAULT);
1071 	(void) ficlDictionarySetPrimitive(dp, "seconds", pseconds,
1072 	    FICL_WORD_DEFAULT);
1073 	(void) ficlDictionarySetPrimitive(dp, "heap?", freeHeap,
1074 	    FICL_WORD_DEFAULT);
1075 
1076 	(void) ficlDictionarySetPrimitive(dp, "setenv", ficlSetenv,
1077 	    FICL_WORD_DEFAULT);
1078 	(void) ficlDictionarySetPrimitive(dp, "setenv?", ficlSetenvq,
1079 	    FICL_WORD_DEFAULT);
1080 	(void) ficlDictionarySetPrimitive(dp, "getenv", ficlGetenv,
1081 	    FICL_WORD_DEFAULT);
1082 	(void) ficlDictionarySetPrimitive(dp, "unsetenv", ficlUnsetenv,
1083 	    FICL_WORD_DEFAULT);
1084 	(void) ficlDictionarySetPrimitive(dp, "copyin", ficlCopyin,
1085 	    FICL_WORD_DEFAULT);
1086 	(void) ficlDictionarySetPrimitive(dp, "copyout", ficlCopyout,
1087 	    FICL_WORD_DEFAULT);
1088 	(void) ficlDictionarySetPrimitive(dp, "findfile", ficlFindfile,
1089 	    FICL_WORD_DEFAULT);
1090 	(void) ficlDictionarySetPrimitive(dp, "ccall", ficlCcall,
1091 	    FICL_WORD_DEFAULT);
1092 	(void) ficlDictionarySetPrimitive(dp, "uuid-from-string",
1093 	    ficlUuidFromString, FICL_WORD_DEFAULT);
1094 	(void) ficlDictionarySetPrimitive(dp, "uuid-to-string",
1095 	    ficlUuidToString, FICL_WORD_DEFAULT);
1096 	(void) ficlDictionarySetPrimitive(dp, "fb-setpixel", ficl_fb_setpixel,
1097 	    FICL_WORD_DEFAULT);
1098 	(void) ficlDictionarySetPrimitive(dp, "fb-line", ficl_fb_line,
1099 	    FICL_WORD_DEFAULT);
1100 	(void) ficlDictionarySetPrimitive(dp, "fb-bezier", ficl_fb_bezier,
1101 	    FICL_WORD_DEFAULT);
1102 	(void) ficlDictionarySetPrimitive(dp, "fb-drawrect", ficl_fb_drawrect,
1103 	    FICL_WORD_DEFAULT);
1104 	(void) ficlDictionarySetPrimitive(dp, "fb-putimage", ficl_fb_putimage,
1105 	    FICL_WORD_DEFAULT);
1106 	(void) ficlDictionarySetPrimitive(dp, "term-drawrect",
1107 	    ficl_term_drawrect, FICL_WORD_DEFAULT);
1108 #ifdef _STANDALONE
1109 	(void) ficlDictionarySetPrimitive(dp, "term-putimage",
1110 	    ficl_term_putimage, FICL_WORD_DEFAULT);
1111 	/* Register words from linker set. */
1112 	SET_FOREACH(fnpp, Xficl_compile_set)
1113 		(*fnpp)(pSys);
1114 #endif
1115 
1116 #if defined(__i386__) || defined(__amd64__)
1117 	(void) ficlDictionarySetConstant(env, "arch-i386", FICL_TRUE);
1118 	(void) ficlDictionarySetConstant(env, "arch-sparc", FICL_FALSE);
1119 #endif
1120 #ifdef __sparc
1121 	(void) ficlDictionarySetConstant(env, "arch-i386", FICL_FALSE);
1122 	(void) ficlDictionarySetConstant(env, "arch-sparc", FICL_TRUE);
1123 #endif
1124 }
1125