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