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