summaryrefslogtreecommitdiff
path: root/usr/src/lib/efcode/engine/interactive.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/efcode/engine/interactive.c')
-rw-r--r--usr/src/lib/efcode/engine/interactive.c808
1 files changed, 808 insertions, 0 deletions
diff --git a/usr/src/lib/efcode/engine/interactive.c b/usr/src/lib/efcode/engine/interactive.c
new file mode 100644
index 0000000000..398f52a686
--- /dev/null
+++ b/usr/src/lib/efcode/engine/interactive.c
@@ -0,0 +1,808 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2000 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <setjmp.h>
+#include <sys/stat.h>
+
+#include <fcode/private.h>
+#include <fcode/log.h>
+
+void (*to_ptr)(fcode_env_t *env) = do_set_action;
+jmp_buf *jmp_buf_ptr = NULL;
+
+char *
+parse_a_string(fcode_env_t *env, int *lenp)
+{
+ parse_word(env);
+ return (pop_a_string(env, lenp));
+}
+
+void
+constant(fcode_env_t *env)
+{
+ char *name;
+ int len;
+
+ name = parse_a_string(env, &len);
+ env->instance_mode = 0;
+ make_common_access(env, name, len, 1, 0,
+ &do_constant, &do_constant, NULL);
+}
+
+void
+buffer_colon(fcode_env_t *env)
+{
+ char *name;
+ int len;
+
+ PUSH(DS, 0);
+ name = parse_a_string(env, &len);
+ make_common_access(env, name, len, 2,
+ env->instance_mode, &noop, &noop, &set_buffer_actions);
+}
+
+void
+value(fcode_env_t *env)
+{
+ char *name;
+ int len;
+
+ name = parse_a_string(env, &len);
+ make_common_access(env, name, len, 1,
+ env->instance_mode, &noop, &noop, &set_value_actions);
+}
+
+void
+variable(fcode_env_t *env)
+{
+ char *name;
+ int len;
+
+ PUSH(DS, 0);
+ name = parse_a_string(env, &len);
+ make_common_access(env, name, len, 1,
+ env->instance_mode, &instance_variable, &do_create, NULL);
+}
+
+void
+defer(fcode_env_t *env)
+{
+ static void (*crash_ptr)(fcode_env_t *env) = do_crash;
+ char *name;
+ int len;
+
+ PUSH(DS, (fstack_t)&crash_ptr);
+ name = parse_a_string(env, &len);
+ make_common_access(env, name, len, 1,
+ env->instance_mode, &noop, &noop, &set_defer_actions);
+}
+
+void
+field(fcode_env_t *env)
+{
+ char *name;
+ int len;
+
+ over(env);
+ name = parse_a_string(env, &len);
+ make_common_access(env, name, len, 1, 0, &do_field, &do_field, NULL);
+ add(env);
+}
+
+void
+bye(fcode_env_t *env)
+{
+ exit(0);
+}
+
+void
+do_resume(fcode_env_t *env)
+{
+ if (env->interactive) env->interactive--;
+ COMPLETE_INTERRUPT;
+}
+
+/*
+ * In interactive mode, jmp_buf_ptr should be non-null.
+ */
+void
+return_to_interact(fcode_env_t *env)
+{
+ if (jmp_buf_ptr)
+ longjmp(*jmp_buf_ptr, 1);
+}
+
+void
+do_interact(fcode_env_t *env)
+{
+ int level;
+ jmp_buf jmp_env;
+ jmp_buf *ojmp_ptr;
+ error_frame new;
+ input_typ *old_input = env->input;
+
+ log_message(MSG_INFO, "Type resume to return\n");
+ env->interactive++;
+ level = env->interactive;
+
+ ojmp_ptr = jmp_buf_ptr;
+ jmp_buf_ptr = &jmp_env;
+ env->input->separator = ' ';
+ env->input->maxlen = 256;
+ env->input->buffer = MALLOC(env->input->maxlen);
+ env->input->scanptr = env->input->buffer;
+
+ if (setjmp(jmp_env)) {
+ if (in_forth_abort > 1) {
+ RS = env->rs0;
+ DS = env->ds0;
+ MYSELF = 0;
+ IP = 0;
+ env->input = old_input;
+ env->order_depth = 0;
+ } else {
+ RS = new.rs;
+ DS = new.ds;
+ MYSELF = new.myself;
+ IP = new.ip;
+ env->input = old_input;
+ }
+ do_forth(env);
+ do_definitions(env);
+ in_forth_abort = 0;
+ } else {
+ new.rs = RS;
+ new.ds = DS;
+ new.myself = MYSELF;
+ new.ip = IP;
+ }
+
+ while (env->interactive == level) {
+ int wlen;
+ char *p;
+
+ DEBUGF(SHOW_RS, output_return_stack(env, 0, MSG_FC_DEBUG));
+ DEBUGF(SHOW_STACK, output_data_stack(env, MSG_FC_DEBUG));
+
+#define USE_READLINE
+#ifdef USE_READLINE
+ {
+ char *line;
+ void read_line(fcode_env_t *);
+
+ read_line(env);
+ if ((line = pop_a_string(env, NULL)) == NULL)
+ continue;
+
+ env->input->scanptr = strcpy(env->input->buffer, line);
+ }
+#else
+ if (isatty(fileno(stdin)))
+ printf("ok ");
+
+ env->input->scanptr = fgets(env->input->buffer,
+ env->input->maxlen, stdin);
+
+ if (feof(stdin))
+ break;
+
+ if (env->input->scanptr == NULL)
+ continue;
+#endif
+
+ if ((p = strpbrk(env->input->scanptr, "\n\r")) != NULL)
+ *p = '\0';
+
+ if ((wlen = strlen(env->input->scanptr)) == 0)
+ continue;
+
+ PUSH(DS, (fstack_t)env->input->buffer);
+ PUSH(DS, wlen);
+ evaluate(env);
+ }
+
+ jmp_buf_ptr = ojmp_ptr;
+ FREE(env->input->buffer);
+}
+
+static void
+temp_base(fcode_env_t *env, fstack_t base)
+{
+ fstack_t obase;
+
+ obase = env->num_base;
+ env->num_base = base;
+ parse_word(env);
+ evaluate(env);
+ env->num_base = obase;
+}
+
+static void
+temp_decimal(fcode_env_t *env)
+{
+ temp_base(env, 10);
+}
+
+static void
+temp_hex(fcode_env_t *env)
+{
+ temp_base(env, 0x10);
+}
+
+static void
+temp_binary(fcode_env_t *env)
+{
+ temp_base(env, 2);
+}
+
+static void
+do_hex(fcode_env_t *env)
+{
+ env->num_base = 0x10;
+}
+
+static void
+do_decimal(fcode_env_t *env)
+{
+ env->num_base = 10;
+}
+
+static void
+do_binary(fcode_env_t *env)
+{
+ env->num_base = 2;
+}
+
+static void
+do_clear(fcode_env_t *env)
+{
+ DS = env->ds0;
+}
+
+static void
+action_one(fcode_env_t *env)
+{
+
+ do_tick(env);
+ if (env->state) {
+ COMPILE_TOKEN(&to_ptr);
+ } else {
+ PUSH(DS, 1);
+ perform_action(env);
+ }
+}
+
+void
+do_if(fcode_env_t *env)
+{
+ branch_common(env, 1, 1, 0);
+}
+
+void
+do_else(fcode_env_t *env)
+{
+ branch_common(env, 1, 0, 1);
+ bresolve(env);
+}
+
+void
+do_then(fcode_env_t *env)
+{
+ bresolve(env);
+}
+
+void
+do_of(fcode_env_t *env)
+{
+ branch_common(env, 0, 2, 0);
+}
+
+void
+load_file(fcode_env_t *env)
+{
+ int fd;
+ int len, n;
+ char *name;
+ char *buffer;
+ struct stat buf;
+
+ CHECK_DEPTH(env, 2, "load-file");
+ name = pop_a_string(env, &len);
+ log_message(MSG_INFO, "load_file: '%s'\n", name);
+ fd = open(name, O_RDONLY);
+ if (fd < 0) {
+ forth_perror(env, "Can't open '%s'", name);
+ }
+ fstat(fd, &buf);
+ len = buf.st_size;
+ buffer = MALLOC(len);
+ if (buffer == 0)
+ forth_perror(env, "load_file: MALLOC(%d)", len);
+
+ if ((n = read(fd, buffer, len)) < 0)
+ forth_perror(env, "read error '%s'", name);
+
+ close(fd);
+ PUSH(DS, (fstack_t)buffer);
+ PUSH(DS, (fstack_t)n);
+}
+
+void
+load(fcode_env_t *env)
+{
+ parse_word(env);
+ if (TOS > 0)
+ load_file(env);
+}
+
+void
+fevaluate(fcode_env_t *env)
+{
+ char *buffer;
+ int bytes, len;
+
+ two_dup(env);
+ buffer = pop_a_string(env, &len);
+ for (bytes = 0; bytes < len; bytes++) {
+ if ((buffer[bytes] == '\n') || (buffer[bytes] == '\r'))
+ buffer[bytes] = ' ';
+ }
+ evaluate(env);
+}
+
+void
+fload(fcode_env_t *env)
+{
+ char *buffer;
+
+ load(env);
+ two_dup(env);
+ buffer = pop_a_string(env, NULL);
+ fevaluate(env);
+ FREE(buffer);
+}
+
+#include <sys/termio.h>
+
+#define MAX_LINE_BUF 20
+
+static char *history_lines[MAX_LINE_BUF];
+int num_lines = 0;
+
+static void
+add_line_to_history(fcode_env_t *env, char *line)
+{
+ int i;
+
+ if (num_lines < MAX_LINE_BUF)
+ history_lines[num_lines++] = STRDUP(line);
+ else {
+ FREE(history_lines[0]);
+ for (i = 0; i < MAX_LINE_BUF - 1; i++)
+ history_lines[i] = history_lines[i + 1];
+ history_lines[MAX_LINE_BUF - 1] = STRDUP(line);
+ }
+}
+
+static void
+do_emit_chars(fcode_env_t *env, char c, int n)
+{
+ int i;
+
+ for (i = 0; i < n; i++)
+ do_emit(env, c);
+}
+
+static void
+do_emit_str(fcode_env_t *env, char *str, int n)
+{
+ int i;
+
+ for (i = 0; i < n; i++)
+ do_emit(env, *str++);
+}
+
+static char *
+find_next_word(char *cursor, char *eol)
+{
+ while (cursor < eol && *cursor != ' ')
+ cursor++;
+ while (cursor < eol && *cursor == ' ')
+ cursor++;
+ return (cursor);
+}
+
+static char *
+find_prev_word(char *buf, char *cursor)
+{
+ int skippedword = 0;
+
+ if (cursor == buf)
+ return (cursor);
+ cursor--;
+ while (cursor > buf && *cursor == ' ')
+ cursor--;
+ while (cursor > buf && *cursor != ' ') {
+ skippedword++;
+ cursor--;
+ }
+ if (skippedword && *cursor == ' ')
+ cursor++;
+ return (cursor);
+}
+
+void
+redraw_line(fcode_env_t *env, char *prev_l, char *prev_cursor, char *prev_eol,
+ char *new_l, char *new_cursor, char *new_eol)
+{
+ int len;
+
+ /* backup to beginning of previous line */
+ do_emit_chars(env, '\b', prev_cursor - prev_l);
+
+ /* overwrite new line */
+ do_emit_str(env, new_l, new_eol - new_l);
+
+ /* Output blanks to erase previous line chars if old line was longer */
+ len = max(0, (prev_eol - prev_l) - (new_eol - new_l));
+ do_emit_chars(env, ' ', len);
+
+ /* Backup cursor for new line */
+ do_emit_chars(env, '\b', len + (new_eol - new_cursor));
+}
+
+#define MAX_LINE_SIZE 256
+
+static void
+do_save_buf(char *save_buf, char *buf, int n)
+{
+ n = max(0, min(n, MAX_LINE_SIZE));
+ memcpy(save_buf, buf, n);
+ save_buf[n] = '\0';
+}
+
+char prompt_string[80] = "ok ";
+
+void
+read_line(fcode_env_t *env)
+{
+ char buf[MAX_LINE_SIZE+1], save_buf[MAX_LINE_SIZE+1];
+ char save_line[MAX_LINE_SIZE+1];
+ char *p, *cursor, *eol, *tp, *cp;
+ fstack_t d;
+ int saw_esc = 0, do_quote = 0, i, cur_line, len, my_line, save_cursor;
+ struct termio termio, savetermio;
+
+ if (!isatty(fileno(stdin))) {
+ fgets(buf, sizeof (buf), stdin);
+ push_string(env, buf, strlen(buf));
+ return;
+ }
+ printf(prompt_string);
+ fflush(stdout);
+ ioctl(fileno(stdin), TCGETA, &termio);
+ savetermio = termio;
+ termio.c_lflag &= ~(ICANON|ECHO|ECHOE|IEXTEN);
+ termio.c_cc[VTIME] = 0;
+ termio.c_cc[VMIN] = 1;
+ ioctl(fileno(stdin), TCSETA, &termio);
+ my_line = cur_line = num_lines;
+ save_buf[0] = '\0';
+ for (cursor = eol = buf; ; ) {
+ for (d = FALSE; d == FALSE; d = POP(DS))
+ keyquestion(env);
+ key(env);
+ d = POP(DS);
+ if (do_quote) {
+ do_quote = 0;
+ if ((cursor - buf) < MAX_LINE_SIZE) {
+ *cursor++ = d;
+ if (cursor > eol)
+ eol = cursor;
+ do_emit(env, d);
+ }
+ continue;
+ }
+ if (saw_esc) {
+ saw_esc = 0;
+ switch (d) {
+
+ default: /* Ignore anything else */
+ continue;
+
+ case 'b': /* Move backward one word */
+ case 'B':
+ tp = find_prev_word(buf, cursor);
+ if (tp < cursor) {
+ do_emit_chars(env, '\b', cursor - tp);
+ cursor = tp;
+ }
+ continue;
+
+ case 'f': /* Move forward one word */
+ case 'F':
+ tp = find_next_word(cursor, eol);
+ if (tp > cursor) {
+ do_emit_str(env, tp, tp - cursor);
+ cursor = tp;
+ }
+ continue;
+
+ case 'h': /* Erase from beginning of word to */
+ case 'H': /* just before cursor, saving chars */
+ d = CTRL('w');
+ break;
+
+ case 'd':
+ case 'D':
+ tp = find_next_word(cursor, eol);
+ if (tp <= cursor)
+ continue;
+ len = tp - cursor;
+ do_save_buf(save_buf, cursor, len);
+ memmove(cursor, tp, eol - tp);
+ redraw_line(env, buf, cursor, eol, buf, cursor,
+ eol - len);
+ eol -= len;
+ continue;
+ }
+ }
+ switch (d) {
+
+ default:
+ if ((cursor - buf) < MAX_LINE_SIZE) {
+ *cursor++ = d;
+ if (cursor > eol)
+ eol = cursor;
+ do_emit(env, d);
+ }
+ continue;
+
+ case CTRL('['): /* saw esc. character */
+ saw_esc = 1;
+ continue;
+
+ case CTRL('f'): /* move forward one char */
+ if (cursor < eol)
+ do_emit(env, *cursor++);
+ continue;
+
+ case CTRL('a'): /* cursor to beginning of line */
+ do_emit_chars(env, '\b', cursor - buf);
+ cursor = buf;
+ continue;
+
+ case CTRL('e'): /* cursor to end of line */
+ do_emit_str(env, cursor, eol - cursor);
+ cursor = eol;
+ continue;
+
+
+ case CTRL('n'): /* Move to next line in buffer */
+ case CTRL('p'): /* Move to previous line in buffer */
+ if (d == CTRL('p')) {
+ if (cur_line <= 0)
+ continue;
+ if (my_line == cur_line) {
+ do_save_buf(save_line, buf, eol - buf);
+ save_cursor = cursor - buf;
+ }
+ cur_line--;
+ } else {
+ if (cur_line >= num_lines)
+ continue;
+ cur_line++;
+ if (cur_line == num_lines) {
+ len = strlen(save_line);
+ redraw_line(env, buf, cursor, eol,
+ save_line, save_line + save_cursor,
+ save_line + len);
+ strcpy(buf, save_line);
+ eol = buf + len;
+ cursor = buf + save_cursor;
+ continue;
+ }
+ }
+ p = history_lines[cur_line];
+ len = strlen(p);
+ redraw_line(env, buf, cursor, eol, p, p, p + len);
+ strcpy(buf, history_lines[cur_line]);
+ cursor = buf;
+ eol = buf + len;
+ continue;
+
+ case CTRL('o'): /* Insert newline */
+ continue;
+
+ case CTRL('k'): /* Erase from cursor to eol, saving */
+ /* chars, at eol, joins two lines */
+ if (cursor == eol) {
+ if (cur_line >= num_lines)
+ continue;
+ if (cur_line == num_lines - 1) {
+ p = save_line;
+ len = strlen(save_line);
+ num_lines -= 1;
+ my_line = num_lines;
+ } else {
+ cur_line++;
+ p = history_lines[cur_line];
+ len = strlen(p);
+ }
+ len = min(len, MAX_LINE_SIZE - (eol - buf));
+ memcpy(eol, p, len);
+ redraw_line(env, buf, cursor, eol, buf, cursor,
+ eol + len);
+ eol += len;
+ continue;
+ }
+ do_save_buf(save_buf, cursor, eol - cursor);
+ redraw_line(env, buf, cursor, eol, buf, cursor,
+ cursor);
+ eol = cursor;
+ continue;
+
+ case CTRL('w'): /* Erase word */
+ tp = find_prev_word(buf, cursor);
+ if (tp == cursor)
+ continue;
+ len = cursor - tp;
+ do_save_buf(save_buf, tp, len);
+ memmove(tp, cursor, eol - cursor);
+ redraw_line(env, buf, cursor, eol, buf, cursor - len,
+ eol - len);
+ eol -= len;
+ cursor -= len;
+ continue;
+
+ case CTRL('u'): /* Erases line, saving chars */
+ do_save_buf(save_buf, buf, eol - buf);
+ redraw_line(env, buf, cursor, eol, buf, buf, buf);
+ cursor = buf;
+ eol = buf;
+ continue;
+
+ case CTRL('y'): /* Insert save buffer before cursor */
+ len = min(strlen(save_buf),
+ MAX_LINE_SIZE - (eol - buf));
+ if (len == 0)
+ continue;
+ memmove(cursor + len, cursor, eol - cursor);
+ memcpy(cursor, save_buf, len);
+ redraw_line(env, buf, cursor, eol, buf, cursor + len,
+ eol + len);
+ cursor += len;
+ eol += len;
+ continue;
+
+ case CTRL('q'): /* Quote next char */
+ do_quote = 1;
+ continue;
+
+ case CTRL('l'): /* Display edit buffer */
+ do_emit(env, '\n');
+ for (i = 0; i < num_lines; i++) {
+ do_emit_str(env, history_lines[i],
+ strlen(history_lines[i]));
+ do_emit(env, '\n');
+ }
+ redraw_line(env, buf, buf, buf, buf, cursor, eol);
+ continue;
+
+ case CTRL('r'): /* redraw line */
+ redraw_line(env, buf, cursor, eol, buf, cursor, eol);
+ continue;
+
+ case CTRL('c'): /* Exit script editor */
+ continue;
+
+ case CTRL('b'): /* backup cursor */
+ if (cursor <= buf)
+ continue;
+ cursor--;
+ do_emit(env, '\b');
+ continue;
+
+ case CTRL('h'): /* Backspace */
+ case 0x7f: /* DEL */
+ if (cursor <= buf)
+ continue;
+ memmove(cursor - 1, cursor, eol - cursor);
+ redraw_line(env, buf, cursor, eol, buf, cursor - 1,
+ eol - 1);
+ cursor--;
+ eol--;
+ continue;
+
+ case '\r':
+ case '\n':
+ *eol = '\0';
+ do_emit(env, '\n');
+ break;
+ }
+ break;
+ }
+ add_line_to_history(env, buf);
+ ioctl(fileno(stdin), TCSETA, &savetermio);
+ push_string(env, buf, strlen(buf));
+}
+
+static void
+set_prompt(fcode_env_t *env)
+{
+ char *prompt;
+
+ if ((prompt = parse_a_string(env, NULL)) != NULL)
+ strncpy(prompt_string, prompt, sizeof (prompt_string));
+}
+
+#pragma init(_init)
+
+static void
+_init(void)
+{
+ fcode_env_t *env = initial_env;
+
+ ASSERT(env);
+ NOTICE;
+
+ FORTH(IMMEDIATE, "if", do_if);
+ FORTH(IMMEDIATE, "else", do_else);
+ FORTH(IMMEDIATE, "then", do_then);
+ FORTH(IMMEDIATE, "case", bcase);
+ FORTH(IMMEDIATE, "of", do_of);
+ FORTH(IMMEDIATE, "endof", do_else);
+ FORTH(IMMEDIATE, "endcase", bendcase);
+ FORTH(IMMEDIATE, "value", value);
+ FORTH(IMMEDIATE, "variable", variable);
+ FORTH(IMMEDIATE, "constant", constant);
+ FORTH(IMMEDIATE, "defer", defer);
+ FORTH(IMMEDIATE, "buffer:", buffer_colon);
+ FORTH(IMMEDIATE, "field", field);
+ FORTH(IMMEDIATE, "struct", zero);
+ FORTH(IMMEDIATE, "to", action_one);
+ FORTH(IMMEDIATE, "d#", temp_decimal);
+ FORTH(IMMEDIATE, "h#", temp_hex);
+ FORTH(IMMEDIATE, "b#", temp_binary);
+ FORTH(0, "decimal", do_decimal);
+ FORTH(0, "hex", do_hex);
+ FORTH(0, "binary", do_binary);
+ FORTH(0, "clear", do_clear);
+ FORTH(IMMEDIATE, "bye", bye);
+ FORTH(0, "interact", do_interact);
+ FORTH(IMMEDIATE, "resume", do_resume);
+ FORTH(0, "fload", fload);
+ FORTH(0, "load", load);
+ FORTH(0, "read-line", read_line);
+ FORTH(0, "set-prompt", set_prompt);
+}