xref: /illumos-gate/usr/src/common/ficl/loader.c (revision 8a2b682e57a046b828f37bcde1776f131ef4629f)
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 <gfx_fb.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 /* ( 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 		(void) 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 
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 	(void) 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 	(void) strncpy(value, valuep, values);
204 	value[values] = '\0';
205 
206 	(void) 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 		(void) ficlVmThrowError(pVM, "Error: out of memory");
229 	(void) 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 	(void) strncpy(value, valuep, values);
235 	value[values] = '\0';
236 
237 	(void) 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 	(void) 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 	(void) strncpy(name, namep, names);
286 	name[names] = '\0';
287 
288 	(void) 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 	(void) 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 		(void) 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 	ficlInteger 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), flag);
679 		return;
680 	}
681 	/* ensure that the string is null terminated */
682 	if ((name = malloc(count + 1)) == NULL) {
683 		ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
684 		return;
685 	}
686 
687 	bcopy(ptr, name, count);
688 	name[count] = 0;
689 #ifndef _STANDALONE
690 	tmp = get_dev(name);
691 	free(name);
692 	name = tmp;
693 
694 	dir = opendir(name);
695 	if (dir == NULL) {
696 		ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
697 		return;
698 	} else
699 		flag = FICL_TRUE;
700 
701 	ficlStackPushPointer(ficlVmGetDataStack(pVM), dir);
702 	ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
703 #else
704 	fd = open(name, O_RDONLY);
705 	free(name);
706 	do {
707 		if (fd < 0)
708 			break;
709 		if (fstat(fd, &sb) < 0)
710 			break;
711 		if (!S_ISDIR(sb.st_mode))
712 			break;
713 		flag = FICL_TRUE;
714 		ficlStackPushInteger(ficlVmGetDataStack(pVM), fd);
715 		ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
716 		return;
717 	} while (0);
718 
719 	if (fd >= 0)
720 		close(fd);
721 
722 	ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
723 #endif
724 }
725 
726 /*
727  * freaddir - read directory contents
728  * freaddir ( fd -- ptr len TRUE | FALSE )
729  */
730 static void
731 pfreaddir(ficlVm *pVM)
732 {
733 #ifndef _STANDALONE
734 	static DIR *dir = NULL;
735 #else
736 	int fd;
737 #endif
738 	struct dirent *d = NULL;
739 
740 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 3);
741 	/*
742 	 * libstand readdir does not always return . nor .. so filter
743 	 * them out to have consistent behaviour.
744 	 */
745 #ifndef _STANDALONE
746 	dir = ficlStackPopPointer(ficlVmGetDataStack(pVM));
747 	if (dir != NULL)
748 		do {
749 			d = readdir(dir);
750 			if (d != NULL && strcmp(d->d_name, ".") == 0)
751 				continue;
752 			if (d != NULL && strcmp(d->d_name, "..") == 0)
753 				continue;
754 			break;
755 		} while (d != NULL);
756 #else
757 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM));
758 	if (fd != -1)
759 		do {
760 			d = readdirfd(fd);
761 			if (d != NULL && strcmp(d->d_name, ".") == 0)
762 				continue;
763 			if (d != NULL && strcmp(d->d_name, "..") == 0)
764 				continue;
765 			break;
766 		} while (d != NULL);
767 #endif
768 	if (d != NULL) {
769 		ficlStackPushPointer(ficlVmGetDataStack(pVM), d->d_name);
770 		ficlStackPushInteger(ficlVmGetDataStack(pVM),
771 		    strlen(d->d_name));
772 		ficlStackPushInteger(ficlVmGetDataStack(pVM), FICL_TRUE);
773 	} else {
774 		ficlStackPushInteger(ficlVmGetDataStack(pVM), FICL_FALSE);
775 	}
776 }
777 
778 /*
779  * fclosedir - close a dir on stack.
780  *
781  * fclosedir ( fd -- )
782  */
783 static void
784 pfclosedir(ficlVm *pVM)
785 {
786 #ifndef _STANDALONE
787 	DIR *dir;
788 #else
789 	int fd;
790 #endif
791 
792 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
793 
794 #ifndef _STANDALONE
795 	dir = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get dir */
796 	if (dir != NULL)
797 		(void) closedir(dir);
798 #else
799 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */
800 	if (fd != -1)
801 		(void) close(fd);
802 #endif
803 }
804 
805 /*
806  * fload - interpret file contents
807  *
808  * fload  ( fd -- )
809  */
810 static void pfload(ficlVm *pVM)
811 {
812 	int fd;
813 
814 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
815 
816 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */
817 	if (fd != -1)
818 		(void) ficlExecFD(pVM, fd);
819 }
820 
821 /*
822  * fwrite - write file contents
823  *
824  * fwrite  ( fd buf nbytes  -- nwritten )
825  */
826 static void
827 pfwrite(ficlVm *pVM)
828 {
829 	int fd, len;
830 	char *buf;
831 
832 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1);
833 
834 	len = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* bytes to read */
835 	buf = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get buffer */
836 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */
837 	if (len > 0 && buf && fd != -1)
838 		ficlStackPushInteger(ficlVmGetDataStack(pVM),
839 		    write(fd, buf, len));
840 	else
841 		ficlStackPushInteger(ficlVmGetDataStack(pVM), -1);
842 }
843 
844 /*
845  * fseek - seek to a new position in a file
846  *
847  * fseek  ( fd ofs whence  -- pos )
848  */
849 static void
850 pfseek(ficlVm *pVM)
851 {
852 	int fd, pos, whence;
853 
854 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1);
855 
856 	whence = ficlStackPopInteger(ficlVmGetDataStack(pVM));
857 	pos = ficlStackPopInteger(ficlVmGetDataStack(pVM));
858 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM));
859 	ficlStackPushInteger(ficlVmGetDataStack(pVM), lseek(fd, pos, whence));
860 }
861 
862 /*
863  * key - get a character from stdin
864  *
865  * key ( -- char )
866  */
867 static void
868 key(ficlVm *pVM)
869 {
870 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1);
871 
872 	ficlStackPushInteger(ficlVmGetDataStack(pVM), getchar());
873 }
874 
875 /*
876  * key? - check for a character from stdin (FACILITY)
877  * key? ( -- flag )
878  */
879 static void
880 keyQuestion(ficlVm *pVM)
881 {
882 #ifndef _STANDALONE
883 	char ch = -1;
884 	struct termios oldt;
885 	struct termios newt;
886 #endif
887 
888 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1);
889 
890 #ifndef _STANDALONE
891 	(void) tcgetattr(STDIN_FILENO, &oldt);
892 	newt = oldt;
893 	newt.c_lflag &= ~(ICANON | ECHO);
894 	newt.c_cc[VMIN] = 0;
895 	newt.c_cc[VTIME] = 0;
896 	(void) tcsetattr(STDIN_FILENO, TCSANOW, &newt);
897 	ch = getchar();
898 	(void) tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
899 
900 	if (ch != -1)
901 		(void) ungetc(ch, stdin);
902 
903 	ficlStackPushInteger(ficlVmGetDataStack(pVM),
904 	    ch != -1? FICL_TRUE : FICL_FALSE);
905 #else
906 	ficlStackPushInteger(ficlVmGetDataStack(pVM),
907 	    ischar()? FICL_TRUE : FICL_FALSE);
908 #endif
909 }
910 
911 /*
912  * seconds - gives number of seconds since beginning of time
913  *
914  * beginning of time is defined as:
915  *
916  *	BTX	- number of seconds since midnight
917  *	FreeBSD	- number of seconds since Jan 1 1970
918  *
919  * seconds ( -- u )
920  */
921 static void
922 pseconds(ficlVm *pVM)
923 {
924 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1);
925 
926 	ficlStackPushUnsigned(ficlVmGetDataStack(pVM),
927 	    (ficlUnsigned) time(NULL));
928 }
929 
930 /*
931  * ms - wait at least that many milliseconds (FACILITY)
932  * ms ( u -- )
933  */
934 static void
935 ms(ficlVm *pVM)
936 {
937 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
938 
939 #ifndef _STANDALONE
940 	(void) usleep(ficlStackPopUnsigned(ficlVmGetDataStack(pVM)) * 1000);
941 #else
942 	delay(ficlStackPopUnsigned(ficlVmGetDataStack(pVM)) * 1000);
943 #endif
944 }
945 
946 /*
947  * fkey - get a character from a file
948  * fkey ( file -- char )
949  */
950 static void
951 fkey(ficlVm *pVM)
952 {
953 	int i, fd;
954 	char ch;
955 
956 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 1);
957 
958 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM));
959 	i = read(fd, &ch, 1);
960 	ficlStackPushInteger(ficlVmGetDataStack(pVM), i > 0 ? ch : -1);
961 }
962 
963 /*
964  * Retrieves free space remaining on the dictionary
965  */
966 static void
967 freeHeap(ficlVm *pVM)
968 {
969 	ficlStackPushInteger(ficlVmGetDataStack(pVM),
970 	    ficlDictionaryCellsAvailable(ficlVmGetDictionary(pVM)));
971 }
972 
973 /*
974  * f i c l C o m p i l e P l a t f o r m
975  * Build FreeBSD platform extensions into the system dictionary
976  */
977 void
978 ficlSystemCompilePlatform(ficlSystem *pSys)
979 {
980 	ficlDictionary *dp = ficlSystemGetDictionary(pSys);
981 	ficlDictionary *env = ficlSystemGetEnvironment(pSys);
982 #ifdef _STANDALONE
983 	ficlCompileFcn **fnpp;
984 #endif
985 
986 	FICL_SYSTEM_ASSERT(pSys, dp);
987 	FICL_SYSTEM_ASSERT(pSys, env);
988 
989 	(void) ficlDictionarySetPrimitive(dp, ".#", displayCellNoPad,
990 	    FICL_WORD_DEFAULT);
991 	(void) ficlDictionarySetPrimitive(dp, "isdir?", isdirQuestion,
992 	    FICL_WORD_DEFAULT);
993 	(void) ficlDictionarySetPrimitive(dp, "fopen", pfopen,
994 	    FICL_WORD_DEFAULT);
995 	(void) ficlDictionarySetPrimitive(dp, "fclose", pfclose,
996 	    FICL_WORD_DEFAULT);
997 	(void) ficlDictionarySetPrimitive(dp, "fread", pfread,
998 	    FICL_WORD_DEFAULT);
999 	(void) ficlDictionarySetPrimitive(dp, "fopendir", pfopendir,
1000 	    FICL_WORD_DEFAULT);
1001 	(void) ficlDictionarySetPrimitive(dp, "freaddir", pfreaddir,
1002 	    FICL_WORD_DEFAULT);
1003 	(void) ficlDictionarySetPrimitive(dp, "fclosedir", pfclosedir,
1004 	    FICL_WORD_DEFAULT);
1005 	(void) ficlDictionarySetPrimitive(dp, "fload", pfload,
1006 	    FICL_WORD_DEFAULT);
1007 	(void) ficlDictionarySetPrimitive(dp, "fkey", fkey,
1008 	    FICL_WORD_DEFAULT);
1009 	(void) ficlDictionarySetPrimitive(dp, "fseek", pfseek,
1010 	    FICL_WORD_DEFAULT);
1011 	(void) ficlDictionarySetPrimitive(dp, "fwrite", pfwrite,
1012 	    FICL_WORD_DEFAULT);
1013 	(void) ficlDictionarySetPrimitive(dp, "key", key, FICL_WORD_DEFAULT);
1014 	(void) ficlDictionarySetPrimitive(dp, "key?", keyQuestion,
1015 	    FICL_WORD_DEFAULT);
1016 	(void) ficlDictionarySetPrimitive(dp, "ms", ms, FICL_WORD_DEFAULT);
1017 	(void) ficlDictionarySetPrimitive(dp, "seconds", pseconds,
1018 	    FICL_WORD_DEFAULT);
1019 	(void) ficlDictionarySetPrimitive(dp, "heap?", freeHeap,
1020 	    FICL_WORD_DEFAULT);
1021 
1022 	(void) ficlDictionarySetPrimitive(dp, "setenv", ficlSetenv,
1023 	    FICL_WORD_DEFAULT);
1024 	(void) ficlDictionarySetPrimitive(dp, "setenv?", ficlSetenvq,
1025 	    FICL_WORD_DEFAULT);
1026 	(void) ficlDictionarySetPrimitive(dp, "getenv", ficlGetenv,
1027 	    FICL_WORD_DEFAULT);
1028 	(void) ficlDictionarySetPrimitive(dp, "unsetenv", ficlUnsetenv,
1029 	    FICL_WORD_DEFAULT);
1030 	(void) ficlDictionarySetPrimitive(dp, "copyin", ficlCopyin,
1031 	    FICL_WORD_DEFAULT);
1032 	(void) ficlDictionarySetPrimitive(dp, "copyout", ficlCopyout,
1033 	    FICL_WORD_DEFAULT);
1034 	(void) ficlDictionarySetPrimitive(dp, "findfile", ficlFindfile,
1035 	    FICL_WORD_DEFAULT);
1036 	(void) ficlDictionarySetPrimitive(dp, "ccall", ficlCcall,
1037 	    FICL_WORD_DEFAULT);
1038 	(void) ficlDictionarySetPrimitive(dp, "uuid-from-string",
1039 	    ficlUuidFromString, FICL_WORD_DEFAULT);
1040 	(void) ficlDictionarySetPrimitive(dp, "uuid-to-string",
1041 	    ficlUuidToString, FICL_WORD_DEFAULT);
1042 	(void) ficlDictionarySetPrimitive(dp, "fb-setpixel", ficl_fb_setpixel,
1043 	    FICL_WORD_DEFAULT);
1044 	(void) ficlDictionarySetPrimitive(dp, "fb-line", ficl_fb_line,
1045 	    FICL_WORD_DEFAULT);
1046 	(void) ficlDictionarySetPrimitive(dp, "fb-bezier", ficl_fb_bezier,
1047 	    FICL_WORD_DEFAULT);
1048 	(void) ficlDictionarySetPrimitive(dp, "fb-drawrect", ficl_fb_drawrect,
1049 	    FICL_WORD_DEFAULT);
1050 	(void) ficlDictionarySetPrimitive(dp, "fb-putimage", ficl_fb_putimage,
1051 	    FICL_WORD_DEFAULT);
1052 	(void) ficlDictionarySetPrimitive(dp, "term-drawrect",
1053 	    ficl_term_drawrect, FICL_WORD_DEFAULT);
1054 #ifdef _STANDALONE
1055 	/* Register words from linker set. */
1056 	SET_FOREACH(fnpp, Xficl_compile_set)
1057 		(*fnpp)(pSys);
1058 #endif
1059 
1060 #if defined(__i386__) || defined(__amd64__)
1061 	(void) ficlDictionarySetConstant(env, "arch-i386", FICL_TRUE);
1062 	(void) ficlDictionarySetConstant(env, "arch-sparc", FICL_FALSE);
1063 #endif
1064 #ifdef __sparc
1065 	(void) ficlDictionarySetConstant(env, "arch-i386", FICL_FALSE);
1066 	(void) ficlDictionarySetConstant(env, "arch-sparc", FICL_TRUE);
1067 #endif
1068 }
1069