Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | /* |
2 | * ========== Copyright Header Begin ========================================== | |
3 | * | |
4 | * Hypervisor Software File: fsys.c | |
5 | * | |
6 | * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
7 | * | |
8 | * - Do no alter or remove copyright notices | |
9 | * | |
10 | * - Redistribution and use of this software in source and binary forms, with | |
11 | * or without modification, are permitted provided that the following | |
12 | * conditions are met: | |
13 | * | |
14 | * - Redistribution of source code must retain the above copyright notice, | |
15 | * this list of conditions and the following disclaimer. | |
16 | * | |
17 | * - Redistribution in binary form must reproduce the above copyright notice, | |
18 | * this list of conditions and the following disclaimer in the | |
19 | * documentation and/or other materials provided with the distribution. | |
20 | * | |
21 | * Neither the name of Sun Microsystems, Inc. or the names of contributors | |
22 | * may be used to endorse or promote products derived from this software | |
23 | * without specific prior written permission. | |
24 | * | |
25 | * This software is provided "AS IS," without a warranty of any kind. | |
26 | * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, | |
27 | * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A | |
28 | * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN | |
29 | * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR | |
30 | * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR | |
31 | * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN | |
32 | * OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR | |
33 | * FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE | |
34 | * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, | |
35 | * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF | |
36 | * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. | |
37 | * | |
38 | * You acknowledge that this software is not designed, licensed or | |
39 | * intended for use in the design, construction, operation or maintenance of | |
40 | * any nuclear facility. | |
41 | * | |
42 | * ========== Copyright Header End ============================================ | |
43 | */ | |
44 | /* | |
45 | * @(#)fsys.c 1.3 03/08/20 | |
46 | * Copyright 1985-1994 Bradley Forthware | |
47 | * Copyright 1994-2003 Sun Microsystems, Inc. All Rights Reserved | |
48 | * Copyright Use is subject to license terms. | |
49 | * | |
50 | * this file contains the routines that have the same function as | |
51 | * those in wrapper.c, except that they use the forth stack to take and | |
52 | * return arguments, effectively they are wrapper additions to the | |
53 | * forth engine hooked into the machine using the same vector interface | |
54 | * as wrapper.c. | |
55 | * | |
56 | */ | |
57 | ||
58 | #include <stdio.h> | |
59 | #include <stdlib.h> | |
60 | #include <unistd.h> | |
61 | #include <fcntl.h> | |
62 | #include <strings.h> | |
63 | ||
64 | #ifdef DLOPEN | |
65 | #include <dlfcn.h> | |
66 | #include <link.h> | |
67 | #endif | |
68 | ||
69 | #include <sys/types.h> | |
70 | #include <sys/time.h> | |
71 | #include <sys/param.h> | |
72 | #include <sys/stat.h> | |
73 | ||
74 | #include <signal.h> | |
75 | #include <termios.h> | |
76 | ||
77 | #include "wrapper.h" | |
78 | #include "xref_support.h" | |
79 | #include "defines.h" | |
80 | ||
81 | #define FPROTO(x) static fstackp x(fstackp stack) | |
82 | #define UNIMPL(xx) printf("%s:%d: Unimplemented syscall " #xx "\n", \ | |
83 | __FILE__, __LINE__); \ | |
84 | return (stack) | |
85 | ||
86 | extern char *substr(); | |
87 | extern void s_bye(long code); | |
88 | ||
89 | extern int errno; /* Wherever the error code goes */ | |
90 | ||
91 | struct termios ostate; | |
92 | struct termios lstate; | |
93 | struct termios kstate; | |
94 | struct termios kqstate; | |
95 | ||
96 | #define M_ORIG 0 | |
97 | #define M_KEY 1 | |
98 | #define M_LINE 2 | |
99 | #define M_KEYQ 3 | |
100 | static lmode = M_ORIG; | |
101 | ||
102 | static fstackp | |
103 | pop_fstring(fstackp stack, char **buf, int *len) | |
104 | { | |
105 | char *fstr; | |
106 | *len = POP(stack); | |
107 | fstr = (char *)POP(stack); | |
108 | if (*len) { | |
109 | *buf = malloc(*len+1); | |
110 | strncpy(*buf, fstr, *len); | |
111 | (*buf)[*len] = 0; | |
112 | *len++; | |
113 | } else { | |
114 | *buf = NULL; | |
115 | } | |
116 | return (stack); | |
117 | } | |
118 | ||
119 | static fstackp | |
120 | push_cstring(fstackp stack, char *buf, int len) | |
121 | { | |
122 | PUSH(len, stack); | |
123 | PUSH(buf, stack); | |
124 | return (stack); | |
125 | } | |
126 | ||
127 | static void | |
128 | initline(void) | |
129 | { | |
130 | if (lmode != M_ORIG) | |
131 | return; | |
132 | ||
133 | tcgetattr(0, &ostate); /* save old state */ | |
134 | ||
135 | tcgetattr(0, &lstate); /* base of line state */ | |
136 | lstate.c_iflag |= IXON|IXANY|IXOFF; /* XON/XOFF */ | |
137 | lstate.c_iflag |= ICRNL; /* CR/NL munging */ | |
138 | #ifndef FreeBSD | |
139 | lstate.c_iflag &= ~(IUCLC); /* no case folding */ | |
140 | #endif | |
141 | /* Always turning on ONLCR is safe, but it is a pain in an EMACS window */ | |
142 | #ifdef notdef | |
143 | lstate.c_oflag |= OPOST|ONLCR; /* Map NL to CR-LF */ | |
144 | lstate.c_oflag &= ~(OLCUC); /* No case folding */ | |
145 | lstate.c_oflag &= ~(OCRNL|ONLRET); /* Don't swap cr and lf */ | |
146 | #else | |
147 | lstate.c_oflag |= OPOST; | |
148 | #endif | |
149 | lstate.c_lflag |= ICANON|ECHO; /* Line editing on */ | |
150 | lstate.c_cc[VMIN] = 1; /* Don't hold up input */ | |
151 | lstate.c_cc[VTIME] = 0; /* No input delay */ | |
152 | ||
153 | tcgetattr(0, &kstate); /* base of key state */ | |
154 | kstate.c_iflag &= ~(IXON|IXANY|IXOFF); /* no XON/XOFF */ | |
155 | kstate.c_iflag &= ~(INLCR|ICRNL); /* no CR/NL munging */ | |
156 | #ifndef FreeBSD | |
157 | kstate.c_iflag &= ~(IUCLC); /* no case folding */ | |
158 | #endif | |
159 | /* Always turning on ONLCR is safe, but it is a pain in an EMACS window */ | |
160 | #ifdef notdef | |
161 | kstate.c_oflag |= OPOST|ONLCR; /* Map NL to CR-LF */ | |
162 | kstate.c_oflag &= ~(OLCUC); /* No case folding */ | |
163 | kstate.c_oflag &= ~(OCRNL|ONLRET); /* Don't swap cr and lf */ | |
164 | #else | |
165 | kstate.c_oflag |= OPOST; /* */ | |
166 | #endif | |
167 | kstate.c_lflag &= ~(ICANON|ECHO); /* No editing characters */ | |
168 | kstate.c_cc[VMIN] = 1; /* Don't hold up input */ | |
169 | kstate.c_cc[VTIME] = 0; /* No input delay */ | |
170 | ||
171 | kqstate = kstate; | |
172 | kqstate.c_cc[VMIN] = 0; /* Poll for character */ | |
173 | ||
174 | } | |
175 | ||
176 | static void | |
177 | linemode(void) | |
178 | { | |
179 | initline(); | |
180 | if (lmode != M_LINE) { | |
181 | tcsetattr(0, TCSANOW, &lstate); | |
182 | lmode = M_LINE; | |
183 | } | |
184 | } | |
185 | ||
186 | static void | |
187 | keyqmode(void) | |
188 | { | |
189 | initline(); | |
190 | if (lmode != M_KEYQ) { | |
191 | tcsetattr(0, TCSANOW, &kqstate); | |
192 | lmode = M_KEYQ; | |
193 | } | |
194 | } | |
195 | ||
196 | static void | |
197 | keymode(void) | |
198 | { | |
199 | initline(); | |
200 | if (lmode != M_KEY) { | |
201 | tcsetattr(0, TCSANOW, &kstate); | |
202 | lmode = M_KEY; | |
203 | } | |
204 | } | |
205 | ||
206 | static void | |
207 | restoremode(void) | |
208 | { | |
209 | initline(); | |
210 | if (lmode != M_ORIG) { | |
211 | tcsetattr(0, TCSANOW, &ostate); | |
212 | lmode = M_ORIG; | |
213 | } | |
214 | } | |
215 | ||
216 | /* | |
217 | * Function semantics: | |
218 | * | |
219 | * Functions which are the names of Unix system calls have the semantics | |
220 | * of those Unix system calls. | |
221 | * | |
222 | * char c_key(); Gets next input character | |
223 | * no echo or editing, don't wait for a newline. | |
224 | * c_emit(char c); Outputs the character. | |
225 | * long f_open(char *path, long mode); Opens a file. | |
226 | * Mode must agree with wrsys.fth | |
227 | * long f_creat(char *path, long mode); Creates a file. | |
228 | * Mode must agree with wrsys.fth | |
229 | * long f_read(long fd, char *buf, long cnt); Reads from a file | |
230 | * long f_write(long fd, char *buf, long cnt); Writes to a file | |
231 | * long f_ioctl(long fd, long code, char *buf); Is not used right now. | |
232 | * long c_keyques(); True if a keystroke is pending. | |
233 | * If you can't implement this, return false. | |
234 | * s_bye(long status); Cleans up and exits. | |
235 | * long f_lseek(long fd, long offset, long whence);Changes file position. | |
236 | * Whence: 0 - from start of file 1 - from current pos. 2 - from end | |
237 | * long f_unlink(char *path); Deletes a file. | |
238 | * long fileques(); True if input stream has been | |
239 | * redirected away from a keyboard. | |
240 | * long c_type(long len, char *addr); Outputs len characters. | |
241 | * long c_expect(long max, char *buffer); Reads an edited line of input. | |
242 | * long c_cr(); Advances to next line. | |
243 | * long f_crstr() Returns file line terminator. | |
244 | * long syserror(); Error code from the last | |
245 | * failed system call. | |
246 | */ | |
247 | ||
248 | extern char *progname; | |
249 | extern char sccs_get_cmd[128]; /* sccs get command string */ | |
250 | extern int uflag; | |
251 | extern int vflag; | |
252 | extern int xref_enabled; | |
253 | extern int show_symbols; | |
254 | ||
255 | /* | |
256 | * Returns true if a key has been typed on the keyboard since the last | |
257 | * call to c_key(). | |
258 | */ | |
259 | FPROTO(c_keyques) | |
260 | { | |
261 | int nchars = 0; | |
262 | ||
263 | fflush(stdout); | |
264 | ||
265 | #ifdef FreeBSD | |
266 | if ((nchars = stdin->_r) == 0) { | |
267 | char c[1]; | |
268 | keyqmode(); | |
269 | nchars = read(0, c, 1) > 0; | |
270 | if (nchars) | |
271 | ungetc(c[0], stdin); | |
272 | } | |
273 | #else | |
274 | #ifdef IRIS | |
275 | return (0); | |
276 | #endif | |
277 | #endif | |
278 | { | |
279 | char c[1]; | |
280 | keyqmode(); | |
281 | nchars = read(0, c, 1) > 0; | |
282 | if (nchars) | |
283 | ungetc(c[0], stdin); | |
284 | } | |
285 | ||
286 | PUSH(nchars, stack); | |
287 | return (stack); | |
288 | } | |
289 | ||
290 | FPROTO(f_bye) | |
291 | { | |
292 | int status; | |
293 | ||
294 | status = POP(stack); | |
295 | s_bye(status); | |
296 | return (stack); | |
297 | } | |
298 | ||
299 | /* | |
300 | * Get the next character from the input stream. | |
301 | */ | |
302 | /* | |
303 | * There is a minor problem under Regulus relating to interrupted system | |
304 | * calls. If the user types the INTERRUPT character (e.g. DEL) while | |
305 | * Forth is waiting for input, the read system call will be interrupted. | |
306 | * Forth will field the signal thus generated, save the state, and return | |
307 | * to the Forth interpreter. If the user then tries to restart from the | |
308 | * saved state, the restarted system call will return 0, which is the same | |
309 | * code that is returned for end-of-file. This is especially nasty when | |
310 | * using the Regulus standard-I/O package, because when it see the 0-length | |
311 | * read, it set a flag in the stdio file descriptor and returns EOF | |
312 | * forevermore. What we really want to happen is for the read system call | |
313 | * to restart cleanly and continue waiting for input, rather than returning | |
314 | * 0. | |
315 | */ | |
316 | ||
317 | FPROTO(c_key) | |
318 | { | |
319 | int c; | |
320 | ||
321 | keymode(); | |
322 | ||
323 | fflush(stdout); | |
324 | if ((c = getc(stdin)) != EOF) { | |
325 | PUSH(c, stack); | |
326 | return (stack); | |
327 | } | |
328 | s_bye(0L); | |
329 | return (NULL); | |
330 | } | |
331 | ||
332 | /* | |
333 | * Send the character c to the output stream. | |
334 | */ | |
335 | FPROTO(c_emit) | |
336 | { | |
337 | int c; | |
338 | ||
339 | c = (int)POP(stack); | |
340 | putchar(c); | |
341 | fflush(stdout); | |
342 | return (stack); | |
343 | } | |
344 | ||
345 | /* | |
346 | * This routine is called by the Forth system to determine whether | |
347 | * its input stream is connected to a file or to a terminal. | |
348 | * It uses this information to decide whether or not to | |
349 | * prompt at the beginning of a line. If you are running in an environment | |
350 | * where input cannot be redirected away from the terminal, just return 0L. | |
351 | */ | |
352 | FPROTO(fileques) | |
353 | { | |
354 | int status = !isatty(fileno(stdin)); | |
355 | PUSH(status, stack); | |
356 | return (stack); | |
357 | } | |
358 | ||
359 | /* | |
360 | * Get an edited line of input from the keyboard, placing it at buffer. | |
361 | * At most "max" characters will be placed in the buffer. | |
362 | * The line terminator character is not stored in the buffer. | |
363 | */ | |
364 | FPROTO(c_expect) | |
365 | { | |
366 | int c; | |
367 | long max; | |
368 | char *buffer; | |
369 | char *p; | |
370 | ||
371 | max = POP(stack); | |
372 | buffer = (char *)POP(stack); | |
373 | ||
374 | p = buffer; | |
375 | linemode(); | |
376 | ||
377 | fflush(stdout); | |
378 | while (max-- && ((c = getc(stdin)) != '\n') && (c != EOF)) | |
379 | *p++ = c; | |
380 | if (c == EOF) | |
381 | *p++ = '\n'; | |
382 | keymode(); | |
383 | ||
384 | PUSH((p-buffer), stack); | |
385 | return (stack); | |
386 | } | |
387 | ||
388 | /* | |
389 | * Send len characters from the buffer at addr to the output stream. | |
390 | */ | |
391 | FPROTO(c_type) | |
392 | { | |
393 | long len; | |
394 | char *addr; | |
395 | ||
396 | len = POP(stack); | |
397 | addr = (char *)POP(stack); | |
398 | ||
399 | while (len--) | |
400 | putchar(*addr++); | |
401 | fflush(stdout); | |
402 | ||
403 | return (stack); | |
404 | } | |
405 | ||
406 | /* | |
407 | * Sends an end-of-line sequence to the output stream. | |
408 | */ | |
409 | FPROTO(c_cr) | |
410 | { | |
411 | putchar('\n'); | |
412 | fflush(stdout); | |
413 | return (stack); | |
414 | } | |
415 | ||
416 | /* | |
417 | * Returns the end-of-line sequence that is used within files as | |
418 | * a packed (leading count byte) string. | |
419 | */ | |
420 | FPROTO(f_crstr) | |
421 | { | |
422 | char crstr[2] = { 0x01, '\n' }; | |
423 | PUSH(crstr, stack); | |
424 | return (stack); | |
425 | } | |
426 | ||
427 | /* Find the error code returned by the last failing system call. */ | |
428 | FPROTO(syserror) | |
429 | { | |
430 | PUSH(errno, stack); | |
431 | return (stack); | |
432 | } | |
433 | ||
434 | /* Display an error message */ | |
435 | ||
436 | FPROTO(pr_error) | |
437 | { | |
438 | errno = POP(stack); | |
439 | perror(""); | |
440 | return (stack); | |
441 | } | |
442 | ||
443 | FPROTO(f_open) | |
444 | { | |
445 | char *name; | |
446 | int flag; | |
447 | mode_t mode; | |
448 | int status; | |
449 | ||
450 | mode = (mode_t)POP(stack); | |
451 | flag = (int)POP(stack); | |
452 | name = (char *)POP(stack); | |
453 | name = expand_name(name); | |
454 | ||
455 | #ifdef SCCS | |
456 | if (uflag) | |
457 | if (isobsolete(name) == 1) | |
458 | system(sccs_get(name)); | |
459 | #endif SCCS | |
460 | if (vflag) | |
461 | printf("File: %s\n", name); | |
462 | ||
463 | status = open(name, flag, mode); | |
464 | return (stack); | |
465 | } | |
466 | ||
467 | FPROTO(f_creat) | |
468 | { | |
469 | #if 0 | |
470 | (char *name, long mode) | |
471 | name = expand_name(name); | |
472 | ||
473 | return ((long)open(name, O_RDWR|O_CREAT|O_TRUNC, (int)mode)); | |
474 | #endif | |
475 | return (stack); | |
476 | } | |
477 | ||
478 | /* f_read ( fd buf len -- #bytes ) */ | |
479 | FPROTO(f_read) | |
480 | { | |
481 | int fd; | |
482 | char *buf; | |
483 | size_t len; | |
484 | ssize_t bytes; | |
485 | ||
486 | len = POP(stack); | |
487 | buf = (char *)POP(stack); | |
488 | fd = POP(stack); | |
489 | bytes = read(fd, buf, len); | |
490 | PUSH(bytes, stack); | |
491 | return (stack); | |
492 | } | |
493 | ||
494 | /* f_write ( fd adr len -- #written ) */ | |
495 | FPROTO(f_write) | |
496 | { | |
497 | int fd; | |
498 | char *buf; | |
499 | size_t len; | |
500 | ssize_t bytes; | |
501 | ||
502 | len = POP(stack); | |
503 | buf = (char *)POP(stack); | |
504 | fd = POP(stack); | |
505 | ||
506 | bytes = write(fd, buf, len); | |
507 | PUSH(bytes, stack); | |
508 | return (stack); | |
509 | } | |
510 | ||
511 | FPROTO(f_close) | |
512 | { | |
513 | int fd, status; | |
514 | ||
515 | fd = POP(stack); | |
516 | status = close(fd); | |
517 | return (stack); | |
518 | } | |
519 | ||
520 | /* unlink ( str,len -- ok? ) */ | |
521 | FPROTO(f_unlink) | |
522 | { | |
523 | int len; | |
524 | char *buffer; | |
525 | char *path; | |
526 | int status; | |
527 | ||
528 | stack = pop_fstring(stack, &path, &len); | |
529 | #if 0 | |
530 | status = unlink(path); | |
531 | #else | |
532 | printf("UNLINK: %s\n", path); | |
533 | #endif | |
534 | free(path); | |
535 | PUSH(status, stack); | |
536 | return (stack); | |
537 | } | |
538 | ||
539 | /* f_seek ( fd offset whence -- ) */ | |
540 | FPROTO(f_lseek) | |
541 | { | |
542 | int fd; | |
543 | off_t offset; | |
544 | int whence; | |
545 | off_t status; | |
546 | ||
547 | whence = POP(stack); | |
548 | offset = POP(stack); | |
549 | fd = POP(stack); | |
550 | ||
551 | status = lseek(fd, offset, whence); | |
552 | ||
553 | PUSH(status, stack); | |
554 | return (stack); | |
555 | } | |
556 | ||
557 | FPROTO(f_ioctl) | |
558 | { | |
559 | int fd; | |
560 | char *buf; | |
561 | int code; | |
562 | int status; | |
563 | ||
564 | buf = (char *)POP(stack); | |
565 | code = POP(stack); | |
566 | fd = POP(stack); | |
567 | ||
568 | status = ioctl(fd, code, buf); | |
569 | PUSH(status, stack); | |
570 | return (stack); | |
571 | } | |
572 | ||
573 | FPROTO(s_signal) | |
574 | { | |
575 | void (*disp)(int); | |
576 | int sig; | |
577 | void (*prev)(int); | |
578 | ||
579 | disp = (void (*)())POP(stack); | |
580 | sig = POP(stack); | |
581 | prev = signal(sig, disp); | |
582 | PUSH(prev, stack); | |
583 | return (stack); | |
584 | } | |
585 | ||
586 | FPROTO(s_system) | |
587 | { | |
588 | int len, status; | |
589 | char *buf; | |
590 | char *sbuf; | |
591 | ||
592 | stack = pop_fstring(stack, &sbuf, &len); | |
593 | ||
594 | linemode(); | |
595 | status = system(sbuf); | |
596 | keymode(); | |
597 | free(sbuf); | |
598 | ||
599 | PUSH(status, stack); | |
600 | return (stack); | |
601 | } | |
602 | ||
603 | /* chdir ( str,len -- ok? ) */ | |
604 | FPROTO(s_chdir) | |
605 | { | |
606 | int len, status; | |
607 | char *buf; | |
608 | char *sbuf; | |
609 | ||
610 | stack = pop_fstring(stack, &sbuf, &len); | |
611 | status = chdir(sbuf); | |
612 | free(sbuf); | |
613 | ||
614 | PUSH(status, stack); | |
615 | return (stack); | |
616 | } | |
617 | ||
618 | /* getwd ( -- str,len ) */ | |
619 | FPROTO(s_getwd) | |
620 | { | |
621 | char *buf, *sbuf; | |
622 | int len; | |
623 | ||
624 | buf = malloc(MAXPATHLEN+1); | |
625 | sbuf = getwd(buf); | |
626 | if (sbuf != NULL) { | |
627 | len = strlen(buf); | |
628 | sbuf = strdup(buf); | |
629 | free(buf); | |
630 | buf = sbuf; | |
631 | } else { | |
632 | free(buf); | |
633 | len = 0; | |
634 | } | |
635 | PUSH(buf, stack); | |
636 | PUSH(len, stack); | |
637 | return (stack); | |
638 | } | |
639 | ||
640 | /* alloc ( len -- buf ) */ | |
641 | FPROTO(m_alloc) | |
642 | { | |
643 | size_t size; | |
644 | void *buf; | |
645 | ||
646 | #ifdef PPCSIM | |
647 | size = (size+7) & ~7; | |
648 | #endif | |
649 | buf = malloc(size); | |
650 | if (buf != NULL) | |
651 | memset(buf, 0, size); | |
652 | ||
653 | PUSH(buf, stack); | |
654 | return (stack); | |
655 | } | |
656 | ||
657 | /* free ( adr,len -- ) */ | |
658 | FPROTO(m_free) | |
659 | { | |
660 | int len; | |
661 | char *buf; | |
662 | ||
663 | len = POP(stack); | |
664 | buf = (char *)POP(stack); | |
665 | free(buf); | |
666 | return (stack); | |
667 | } | |
668 | ||
669 | /* sbrk ( size -- va ) */ | |
670 | FPROTO(m_sbrk) | |
671 | { | |
672 | intptr_t size; | |
673 | void *ptr; | |
674 | ||
675 | size = POP(stack); | |
676 | ptr = sbrk(size); | |
677 | PUSH(ptr, stack); | |
678 | return (stack); | |
679 | } | |
680 | ||
681 | #ifndef DLOPEN | |
682 | FPROTO(f_dlopen) | |
683 | { | |
684 | UNIMPL(f_dlopen); | |
685 | } | |
686 | ||
687 | FPROTO(f_dlclose) | |
688 | { | |
689 | UNIMPL(f_dlclose); | |
690 | } | |
691 | ||
692 | FPROTO(f_dlsym) | |
693 | { | |
694 | UNIMPL(f_dlsym); | |
695 | } | |
696 | ||
697 | FPROTO(f_dlerror) | |
698 | { | |
699 | UNIMPL(f_dlerror); | |
700 | } | |
701 | #else | |
702 | /* dlopen ( str,len mode -- handle ) */ | |
703 | FPROTO(f_dlopen) | |
704 | { | |
705 | int mode; | |
706 | int len; | |
707 | char *lib; | |
708 | void *handle; | |
709 | ||
710 | mode = POP(stack); | |
711 | stack = pop_fstring(stack, &lib, &len); | |
712 | ||
713 | handle = dlopen(lib, mode); | |
714 | free(lib); | |
715 | PUSH(handle, stack); | |
716 | return (stack); | |
717 | } | |
718 | ||
719 | /* dlclose ( handle -- ) */ | |
720 | FPROTO(f_dlclose) | |
721 | { | |
722 | void *handle; | |
723 | handle = (void *)POP(stack); | |
724 | dlclose(handle); | |
725 | return (stack); | |
726 | } | |
727 | ||
728 | /* dlerror ( -- str,len ) */ | |
729 | FPROTO(f_dlerror) | |
730 | { | |
731 | int len; | |
732 | char *err = dlerror(); | |
733 | ||
734 | if (err != NULL) { | |
735 | stack = push_cstring(stack, err, strlen(err)); | |
736 | } else { | |
737 | stack = push_cstring(stack, err, 0); | |
738 | } | |
739 | return (stack); | |
740 | } | |
741 | ||
742 | /* dlsym ( str,len handle -- ptr ) */ | |
743 | FPROTO(f_dlsym) | |
744 | { | |
745 | void *handle, *symptr; | |
746 | char *sym; | |
747 | int len; | |
748 | ||
749 | handle = (void *)POP(stack); | |
750 | stack = pop_fstring(stack, &sym, &len); | |
751 | symptr = dlsym(handle, sym); | |
752 | free(sym); | |
753 | PUSH(symptr, stack); | |
754 | return (stack); | |
755 | } | |
756 | #endif | |
757 | ||
758 | /* getenv ( str,len -- buf,len ) */ | |
759 | FPROTO(c_getenv) | |
760 | { | |
761 | int len, blen; | |
762 | char *cstr, *sbuf, *buf; | |
763 | ||
764 | stack = pop_fstring(stack, &sbuf, &len); | |
765 | buf = getenv(sbuf); | |
766 | free(sbuf); | |
767 | if (buf == NULL) { | |
768 | blen = 0; | |
769 | } else { | |
770 | blen = strlen(buf); | |
771 | } | |
772 | PUSH(buf, stack); | |
773 | PUSH(blen, stack); | |
774 | return (stack); | |
775 | } | |
776 | ||
777 | FPROTO(today) | |
778 | { | |
779 | long tadd; | |
780 | ||
781 | time(&tadd); | |
782 | PUSH(localtime(&tadd), stack); | |
783 | return (stack); | |
784 | } | |
785 | ||
786 | FPROTO(timez) | |
787 | { | |
788 | UNIMPL(timez); | |
789 | } | |
790 | ||
791 | FPROTO(timezstr) | |
792 | { | |
793 | UNIMPL(timezstr); | |
794 | } | |
795 | ||
796 | /* | |
797 | * Flush the data cache if necessary and possible. Used after writing | |
798 | * instructions into the dictionary. | |
799 | */ | |
800 | FPROTO(s_flushcache) | |
801 | { | |
802 | #ifdef NeXT | |
803 | asm("trap #2"); | |
804 | #endif | |
805 | UNIMPL(s_flushcache); | |
806 | } | |
807 | ||
808 | FPROTO(f_init) | |
809 | { | |
810 | UNIMPL(f_init); | |
811 | } | |
812 | ||
813 | FPROTO(f_op) | |
814 | { | |
815 | UNIMPL(f_op); | |
816 | } | |
817 | ||
818 | FPROTO(f_move) | |
819 | { | |
820 | UNIMPL(f_move); | |
821 | } | |
822 | ||
823 | FPROTO(f_rows) | |
824 | { | |
825 | UNIMPL(f_rows); | |
826 | } | |
827 | ||
828 | FPROTO(f_cols) | |
829 | { | |
830 | UNIMPL(f_cols); | |
831 | } | |
832 | ||
833 | FPROTO(pathname) | |
834 | { | |
835 | UNIMPL(pathname); | |
836 | } | |
837 | ||
838 | #ifdef SIMFORTH | |
839 | FPROTO(find_next) | |
840 | { | |
841 | int shift = POP(stack); | |
842 | int token_size = POP(stack); | |
843 | int origin = POP(stack); | |
844 | char *link = (char *)POP(stack); | |
845 | char *str = (char *)POP(stack); | |
846 | int len, nextlen; | |
847 | char *namep; | |
848 | char *p = str; | |
849 | ||
850 | len = strlen(p); | |
851 | ||
852 | if (tshift == 0) | |
853 | link = (char *)((*(unsigned long *)(link)) +(origin)); | |
854 | else | |
855 | link = (char *)((*(unsigned short *)(link) << tshift) +(origin)); | |
856 | ||
857 | while (link != (char *)origin) { | |
858 | p = str; | |
859 | namep = link - token_size - 1; | |
860 | nextlen = (*namep) & 0x1f; | |
861 | namep = namep - nextlen; | |
862 | if (len == nextlen) | |
863 | while (nextlen--) | |
864 | if (*(namep++) != *(p++)) | |
865 | break; | |
866 | if (nextlen == -1) { | |
867 | PUSH((((long)link)-token_size), stack); | |
868 | return (stack); | |
869 | } | |
870 | ||
871 | if (tshift == 0) | |
872 | link = (char *)((*(unsigned long *)(link-token_size)) | |
873 | +(origin)); | |
874 | else | |
875 | link = (char *)((*(unsigned short *)(link-token_size) | |
876 | << tshift) +(origin)); | |
877 | } | |
878 | ||
879 | PUSH(0, stack); | |
880 | return (stack); | |
881 | } | |
882 | #endif /* SIMFORTH */ | |
883 | ||
884 | /* save-image ( up,len origin,len name,len -- ) */ | |
885 | FPROTO(save_image) | |
886 | { | |
887 | char *fname; | |
888 | uchar_t *upaddr, *dicaddr; | |
889 | int flen, ulen, dlen; | |
890 | FILE *file; | |
891 | ||
892 | stack = pop_fstring(stack, &fname, &flen); | |
893 | dlen = POP(stack); | |
894 | dicaddr = (uchar_t *)POP(stack); | |
895 | ulen = POP(stack); | |
896 | upaddr = (uchar_t *)POP(stack); | |
897 | ||
898 | file = fopen(fname, "wb"); | |
899 | if (file == NULL) { | |
900 | fprintf(stderr, "save_image: failed to create %s\n", | |
901 | fname); | |
902 | return (stack); | |
903 | } | |
904 | fwrite(dicaddr, 1, dlen, file); | |
905 | fwrite(upaddr, 1, ulen, file); | |
906 | fclose(file); | |
907 | return (stack); | |
908 | } | |
909 | ||
910 | static include_file_t *includes = NULL; | |
911 | ||
912 | /* include ( str,len -- str,len ) */ | |
913 | FPROTO(includefile) | |
914 | { | |
915 | include_file_t *newfile; | |
916 | FILE *fd; | |
917 | char *cname, *name; | |
918 | char *fname; | |
919 | int len; | |
920 | fstackp current; | |
921 | ||
922 | (void) pop_fstring(stack, &cname, &len); | |
923 | ||
924 | name = expand_name(cname); | |
925 | ||
926 | #ifdef SCCS | |
927 | if (uflag) | |
928 | if (isobsolete(name) == 1) | |
929 | system(sccs_get(name)); | |
930 | #endif | |
931 | /* | |
932 | * open the file, using SCCS if required | |
933 | */ | |
934 | fd = fopen(name, "r"); | |
935 | if (fd == NULL) { | |
936 | printf("failed to open %s\n", name); | |
937 | } | |
938 | newfile = malloc(sizeof (include_file_t)); | |
939 | if (newfile == NULL) { | |
940 | printf("Malloc failed for include file: %s\n", name); | |
941 | exit(1); | |
942 | } | |
943 | newfile->next = includes; | |
944 | newfile->linenum = 0; | |
945 | newfile->name = strdup(name); | |
946 | newfile->fd = fd; | |
947 | includes = newfile; | |
948 | if (vflag) { | |
949 | printf("File: %s\n", name); | |
950 | } | |
951 | free(cname); | |
952 | return (current); | |
953 | } | |
954 | ||
955 | /* bootstrap ( str,len -- buf,len ) */ | |
956 | FPROTO(bootstrap) | |
957 | { | |
958 | int fd; | |
959 | char *cname, *name; | |
960 | struct stat sbuf; | |
961 | int flen, len; | |
962 | char *fname, *buffer; | |
963 | ||
964 | stack = pop_fstring(stack, &cname, &len); | |
965 | if (len == 0) { | |
966 | buffer = NULL; | |
967 | goto error; | |
968 | } | |
969 | name = expand_name(cname); | |
970 | ||
971 | printf("Bootstrap: %s (%s)\n", cname, name); | |
972 | #ifdef SCCS | |
973 | if (uflag) | |
974 | if (isobsolete(name) == 1) | |
975 | system(sccs_get(name)); | |
976 | #endif | |
977 | ||
978 | /* | |
979 | * open the file, using SCCS if required | |
980 | */ | |
981 | fd = open(name, O_RDONLY); | |
982 | if (fd < 0) { | |
983 | printf("failed to open bootstrap file %s\n", name); | |
984 | buffer = NULL; | |
985 | goto error; | |
986 | } | |
987 | fstat(fd, &sbuf); | |
988 | buffer = malloc(sbuf.st_size+1); | |
989 | if (buffer == NULL) { | |
990 | printf("Malloc failed for bootstrap file: %s\n", name); | |
991 | buffer = NULL; | |
992 | goto error; | |
993 | } | |
994 | len = read(fd, buffer, sbuf.st_size); | |
995 | buffer[len] = 0; | |
996 | close(fd); | |
997 | if (len != sbuf.st_size) { | |
998 | printf("Short read on bootstrap file %s\n", name); | |
999 | free(buffer); | |
1000 | buffer = NULL; | |
1001 | len = 0; | |
1002 | goto error; | |
1003 | } else { | |
1004 | if (vflag > 1) { | |
1005 | printf("Bootstrapped: %s [%d bytes]\n", | |
1006 | name, sbuf.st_size); | |
1007 | } | |
1008 | } | |
1009 | error: | |
1010 | if (cname != NULL) | |
1011 | free(cname); | |
1012 | PUSH(buffer, stack); | |
1013 | PUSH(len, stack); | |
1014 | return (stack); | |
1015 | } | |
1016 | ||
1017 | /* | |
1018 | * xref_symbol ( str,len line# state -- str,len ) | |
1019 | * state: | |
1020 | * 0 symbol_reference | |
1021 | * 1 symbol_definition | |
1022 | * 2 smybol_hide | |
1023 | * 3 symbol_reveal | |
1024 | * 4 string content | |
1025 | */ | |
1026 | FPROTO(xref_symbol) | |
1027 | { | |
1028 | int state; | |
1029 | int len; | |
1030 | char *name; | |
1031 | char *fnname = NULL; | |
1032 | int line; | |
1033 | state = POP(stack); | |
1034 | ||
1035 | #ifdef SHOWREFS | |
1036 | #define RPRINTF(x) printf x | |
1037 | #else | |
1038 | #define RPRINTF(x) | |
1039 | #endif | |
1040 | ||
1041 | if (xref_enabled) { | |
1042 | switch (state) { | |
1043 | case 0: | |
1044 | line = POP(stack); | |
1045 | pop_fstring(stack, &fnname, &len); | |
1046 | RPRINTF(("ref: %s\n", fnname)); | |
1047 | xref_add_symbol_reference(fnname, line); | |
1048 | break; | |
1049 | ||
1050 | case 1: | |
1051 | line = POP(stack); | |
1052 | pop_fstring(stack, &fnname, &len); | |
1053 | RPRINTF(("define: %s\n", fnname)); | |
1054 | xref_add_symbol_definition(fnname, line); | |
1055 | break; | |
1056 | ||
1057 | case 2: | |
1058 | pop_fstring(stack, &fnname, &len); | |
1059 | RPRINTF(("hide: %s\n", fnname)); | |
1060 | xref_modify_symbol_definition(fnname, 0); | |
1061 | break; | |
1062 | ||
1063 | case 3: | |
1064 | pop_fstring(stack, &fnname, &len); | |
1065 | RPRINTF(("reveal: %s\n", fnname)); | |
1066 | xref_modify_symbol_definition(fnname, 1); | |
1067 | break; | |
1068 | ||
1069 | case 4: | |
1070 | line = POP(stack); | |
1071 | pop_fstring(stack, &fnname, &len); | |
1072 | RPRINTF(("string: %s\n", fnname)); | |
1073 | xref_add_string(fnname, len, line); | |
1074 | break; | |
1075 | ||
1076 | default: | |
1077 | printf("%s:%d: xref_symbol invalid state %d\n", | |
1078 | __FILE__, __LINE__, state); | |
1079 | break; | |
1080 | } | |
1081 | if (fnname != NULL) | |
1082 | free(fnname); | |
1083 | } | |
1084 | return (stack); | |
1085 | } | |
1086 | ||
1087 | /* xref-file ( [name,len,-1 -- name,len] | [ 0 -- ] ) */ | |
1088 | FPROTO(xref_file) | |
1089 | { | |
1090 | int state; | |
1091 | int len; | |
1092 | char *name; | |
1093 | char *fname = NULL; | |
1094 | ||
1095 | state = POP(stack); | |
1096 | if (state) { | |
1097 | /* | |
1098 | * We dont actually pop the stack though.. | |
1099 | */ | |
1100 | pop_fstring(stack, &fname, &len); | |
1101 | #if 0 | |
1102 | printf("Pushing.. %s\n", fname); | |
1103 | #endif | |
1104 | } | |
1105 | ||
1106 | if ((xref_enabled) || 1) { | |
1107 | if (state) { | |
1108 | xref_add_file_reference(fname); | |
1109 | } else { | |
1110 | xref_remove_file_reference(); | |
1111 | } | |
1112 | } | |
1113 | if (fname != NULL) | |
1114 | free(fname); | |
1115 | return (stack); | |
1116 | } | |
1117 | ||
1118 | /* xref_trigger ( state -- ) */ | |
1119 | FPROTO(xref_trigger) | |
1120 | { | |
1121 | int what; | |
1122 | char *symbol; | |
1123 | char *preload; | |
1124 | extern int xref_enable_forward_refs; | |
1125 | ||
1126 | what = POP(stack); | |
1127 | switch (what) { | |
1128 | case 0: | |
1129 | /* | |
1130 | * Xref Off | |
1131 | * Flush the xref-file to disk. | |
1132 | */ | |
1133 | if (xref_enabled) | |
1134 | xref_generate(1); | |
1135 | xref_enabled = 0; | |
1136 | break; | |
1137 | ||
1138 | case 1: | |
1139 | /* | |
1140 | * Xref On | |
1141 | */ | |
1142 | symbol = "XREF-FILE"; | |
1143 | if (symbol_defined(symbol)) { | |
1144 | xref_enabled = 1; | |
1145 | } | |
1146 | break; | |
1147 | ||
1148 | case -1: | |
1149 | /* | |
1150 | * Init; extract the xref variables from the symbol table. | |
1151 | */ | |
1152 | symbol = "XREF-FILE"; | |
1153 | if (symbol_defined(symbol)) { | |
1154 | char *symdata = extract_symbol(symbol); | |
1155 | char *preload = extract_symbol("XREF-PRELOAD"); | |
1156 | xref_init(symdata, preload, xref_enable_forward_refs); | |
1157 | PUSH(-1, stack); | |
1158 | } else { | |
1159 | PUSH(0, stack); | |
1160 | } | |
1161 | break; | |
1162 | ||
1163 | default: | |
1164 | printf("%s:%d Unexpected Xref trigger\n", __FILE__, __LINE__); | |
1165 | break; | |
1166 | } | |
1167 | return (stack); | |
1168 | } | |
1169 | ||
1170 | /* xref_stat ( -- ) */ | |
1171 | FPROTO(xref_stat) | |
1172 | { | |
1173 | printf("Xref enabled?: %d\n", xref_enabled); | |
1174 | xref_status(); | |
1175 | return (stack); | |
1176 | } | |
1177 | ||
1178 | /* symbol-set ( data,dlen symbol,len create? -- ) */ | |
1179 | FPROTO(symbol_set) | |
1180 | { | |
1181 | int create; | |
1182 | int slen; | |
1183 | char *sname; | |
1184 | int dlen; | |
1185 | char *data; | |
1186 | char *symbol; | |
1187 | ||
1188 | create = POP(stack); | |
1189 | stack = pop_fstring(stack, &symbol, &slen); | |
1190 | if (create) { | |
1191 | stack = pop_fstring(stack, &data, &dlen); | |
1192 | if (dlen) { | |
1193 | char cstr[256]; | |
1194 | ||
1195 | snprintf(cstr, sizeof (cstr), "%s=%s", symbol, data); | |
1196 | free(data); | |
1197 | free(symbol); | |
1198 | symbol = strdup(cstr); | |
1199 | } | |
1200 | define_symbol(symbol, FORTH_DEFINE); | |
1201 | } else { | |
1202 | undef_symbol(symbol, FORTH_UNDEF); | |
1203 | } | |
1204 | free(symbol); | |
1205 | return (stack); | |
1206 | } | |
1207 | ||
1208 | /* symbol-exists( symbol,len -- exists? ) */ | |
1209 | FPROTO(symbol_exists) | |
1210 | { | |
1211 | int slen; | |
1212 | char *symname; | |
1213 | char *symbol; | |
1214 | int defined; | |
1215 | int invert = 0; | |
1216 | ||
1217 | stack = pop_fstring(stack, &symbol, &slen); | |
1218 | symname = symbol; | |
1219 | if (symname[0] == '!') { | |
1220 | symname++; | |
1221 | invert = 1; | |
1222 | } | |
1223 | defined = symbol_defined(symname); | |
1224 | if (invert) { | |
1225 | defined = !defined; | |
1226 | } | |
1227 | free(symbol); | |
1228 | PUSH(defined, stack); | |
1229 | return (stack); | |
1230 | } | |
1231 | ||
1232 | /* symbol-value( symbol,len -- value,len ) */ | |
1233 | FPROTO(symbol_value) | |
1234 | { | |
1235 | int slen; | |
1236 | int invert = 0; | |
1237 | char *symname; | |
1238 | char *symbol; | |
1239 | char *value; | |
1240 | char *symdata; | |
1241 | ||
1242 | stack = pop_fstring(stack, &symname, &slen); | |
1243 | symbol = symname; | |
1244 | if (symname[0] == '!') { | |
1245 | symbol++; | |
1246 | invert = 1; | |
1247 | } | |
1248 | if (symbol_defined(symbol)) { | |
1249 | symdata = extract_symbol(symbol); | |
1250 | if (symdata == NULL) { | |
1251 | symdata = (char *)&slen; | |
1252 | slen = 0; | |
1253 | } else { | |
1254 | slen = strlen(symdata); | |
1255 | } | |
1256 | if (invert) { | |
1257 | symdata = NULL; | |
1258 | slen = 0; | |
1259 | } | |
1260 | } else { | |
1261 | symdata = NULL; | |
1262 | if (invert) { | |
1263 | symdata = (char *)&slen; | |
1264 | } | |
1265 | slen = 0; | |
1266 | } | |
1267 | free(symname); | |
1268 | PUSH(symdata, stack); | |
1269 | PUSH(slen, stack); | |
1270 | return (stack); | |
1271 | } | |
1272 | ||
1273 | FPROTO(stack_syscall) | |
1274 | { | |
1275 | long tos; | |
1276 | int i; | |
1277 | ||
1278 | tos = POP(stack); | |
1279 | printf("Tos: %x\n", tos); | |
1280 | PUSH(1, stack); | |
1281 | PUSH(2, stack); | |
1282 | ||
1283 | return (stack); | |
1284 | } | |
1285 | ||
1286 | FPROTO(compile_info) | |
1287 | { | |
1288 | extern int compile_msgs; | |
1289 | compile_msgs++; | |
1290 | return (stack); | |
1291 | } | |
1292 | ||
1293 | FPROTO(compile_abort) | |
1294 | { | |
1295 | extern int compile_errors; | |
1296 | compile_errors++; | |
1297 | return (stack); | |
1298 | } | |
1299 | ||
1300 | FPROTO(compile_warn) | |
1301 | { | |
1302 | extern int compile_warnings; | |
1303 | compile_warnings++; | |
1304 | return (stack); | |
1305 | } | |
1306 | ||
1307 | /* | |
1308 | * Now the function table. | |
1309 | */ | |
1310 | fstackp ((*sfunctions[])(fstackp)) = { | |
1311 | /* 0 1 */ | |
1312 | c_key, c_emit, | |
1313 | ||
1314 | /* 2 3 4 5 */ | |
1315 | f_open, f_creat, f_close, f_read, | |
1316 | ||
1317 | /* 6 7 8 */ | |
1318 | f_write, f_ioctl, c_keyques, | |
1319 | ||
1320 | /* 9 10 11 12 */ | |
1321 | f_bye, f_lseek, f_unlink, fileques, | |
1322 | ||
1323 | /* 13 14 15 */ | |
1324 | c_type, c_expect, syserror, | |
1325 | ||
1326 | /* 16 17 18 */ | |
1327 | today, timez, timezstr, | |
1328 | ||
1329 | /* 19 20 */ | |
1330 | #if 0 | |
1331 | fork, execve, | |
1332 | #else | |
1333 | 0L, 0L, | |
1334 | #endif | |
1335 | /* 21 */ | |
1336 | c_getenv, | |
1337 | ||
1338 | /* 22 23 */ | |
1339 | s_system, s_signal, | |
1340 | ||
1341 | /* 24 25 */ | |
1342 | s_chdir, s_getwd, | |
1343 | ||
1344 | /* 26 27 28 */ | |
1345 | m_alloc, c_cr, f_crstr, | |
1346 | ||
1347 | /* 29 30 31 */ | |
1348 | s_flushcache, pr_error, 0, | |
1349 | ||
1350 | /* 32 */ | |
1351 | m_free, | |
1352 | ||
1353 | /* 33 34 35 36 37 */ | |
1354 | f_init, f_op, f_move, f_rows, f_cols, | |
1355 | ||
1356 | /* 38 */ | |
1357 | pathname, | |
1358 | ||
1359 | #ifdef PPCSIM | |
1360 | /* 39 40 41 42 */ | |
1361 | printnum, mmap, open, close, | |
1362 | #else | |
1363 | /* 39 */ | |
1364 | m_sbrk, | |
1365 | ||
1366 | /* 40 41 42 43 */ | |
1367 | f_dlopen, f_dlsym, f_dlerror, f_dlclose, | |
1368 | ||
1369 | /* 44 */ | |
1370 | #ifdef SIMFORTH | |
1371 | find_next, | |
1372 | #else | |
1373 | 0, | |
1374 | #endif | |
1375 | /* 45, , 46 , 47 , 48 */ | |
1376 | save_image, bootstrap, includefile, 0, | |
1377 | ||
1378 | /* 49, 50 51 , 52 */ | |
1379 | xref_symbol, xref_file, xref_trigger, xref_stat, | |
1380 | ||
1381 | /* 53, 54, 55, */ | |
1382 | symbol_set, symbol_exists, symbol_value, | |
1383 | ||
1384 | /* 56 */ | |
1385 | stack_syscall, | |
1386 | ||
1387 | /* 57 58, 59, 60 */ | |
1388 | compile_info, compile_abort, compile_warn, 0, | |
1389 | #endif | |
1390 | /* EOT */ | |
1391 | 0 | |
1392 | }; |