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