home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1993 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this software; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-
-
- #include <ctype.h>
- #include <errno.h>
- #define obstack_chunk_alloc ck_malloc
- #define obstack_chunk_free free
- #include "obstack.h"
- #include "global.h"
- #include "cmd.h"
- #include "io-term.h"
- #include "io-abstract.h"
- #include "io-generic.h"
- #include "io-utils.h"
- #include "io-edit.h"
- #include "stub.h"
- #include "ref.h"
-
- #undef MIN
- #undef MAX
- #define MIN(A,B) ((A) < (B) ? (A) : (B))
- #define MAX(A,B) ((A) > (B) ? (A) : (B))
-
- /* Bogus mapping from KEY->CODE to ranges. This is how bound
- * macros are represented.
- * This is bogus because the ranges will not be adjusted in
- * the ways they should. Variables should be used instead.
- */
- int n_bound_macros;
- struct rng *bound_macros;
- int bound_macro_vec;
-
-
-
- /* Flow of control centers around a select loop. These are the
- * fd's selected on.
- */
- SELECT_TYPE read_fd_set;
- SELECT_TYPE exception_fd_set;
- SELECT_TYPE write_fd_set;
-
- /* These are fd's returned by the last call to select.
- */
- SELECT_TYPE read_pending_fd_set;
- SELECT_TYPE exception_pending_fd_set;
- SELECT_TYPE write_pending_fd_set;
-
- /* Hooks for asynchronos i/o
- */
-
- struct select_hook file_read_hooks[SELECT_SET_SIZE] = {0};
- struct select_hook file_exception_hooks[SELECT_SET_SIZE] = {0};
- struct select_hook file_write_hooks[SELECT_SET_SIZE] = {0};
-
-
- /* The current stream from which commands are being read. */
- struct input_stream * the_input_stream = 0;
-
-
-
-
- #ifdef __STDC__
- static struct input_stream *
- default_input_stream (void)
- #else
- static struct input_stream *
- default_input_stream ()
- #endif
- {
- if (!the_input_stream)
- {
- the_input_stream =
- (struct input_stream *)ck_malloc (sizeof (struct input_stream));
- the_input_stream->_rmac = 0;
- the_input_stream->_func_arg = 0;
- obstack_init (&the_input_stream->_macro_stack);
- the_input_stream->_macro = 0;
- the_input_stream->_macro_start = 0;
- the_input_stream->_macro_size = 0;
- the_input_stream->prev_stream = 0;
- the_input_stream->_last_macro = 0;
- the_input_stream->_pushed_back_char = -1;
- }
- return the_input_stream;
- }
-
-
- /* This constructs an input stream that reads from a macro but never
- * from a keyboard. EXECUTE_CMD uses this.
- */
-
-
- #ifdef __STDC__
- static struct input_stream *
- macro_only_input_stream (struct rng * rng, char * first_line, int len,
- struct command_frame * frame)
- #else
- static struct input_stream *
- macro_only_input_stream (rng, first_line, len, frame)
- struct rng * rng;
- char * first_line;
- int len;
- struct command_frame * frame;
- #endif
- {
- struct input_stream * ret;
- ret = (struct input_stream *)ck_malloc (sizeof (struct input_stream));
- ret->_func_arg = 0;
- obstack_init (&ret->_macro_stack);
- ret->_rmac =
- (struct macro *) obstack_alloc (&ret->_macro_stack, sizeof (struct macro));
- ret->_rmac->mac_prev = 0;
- ret->_rmac->mac_rng = *rng;
- ret->_rmac->mac_row = rng->lr;
- ret->_rmac->mac_col = rng->lc;
- (void) obstack_grow (&ret->_macro_stack, first_line, len);
- (void) obstack_grow (&ret->_macro_stack, "", 1);
- ret->_rmac->mac_start = ret->_rmac->mac_exe
- = (unsigned char *) obstack_finish (&ret->_macro_stack);
- ret->_macro = 0;
- ret->_macro_start = 0;
- ret->_macro_size = 0;
- ret->_last_macro = 0;
- ret->prev_stream = frame->input;
- {
- struct input_stream * key = frame->input;
- while (frame->input == key)
- {
- frame->input = ret;
- frame = frame->prev;
- }
- }
- ret->_pushed_back_char = -1;
- return ret;
- }
-
- #ifdef __STDC__
- void
- free_input_stream (struct input_stream * stream)
- #else
- void
- free_input_stream (stream)
- struct input_stream * stream;
- #endif
- {
- if (stream->_macro_start)
- free (stream->_macro_start);
- if (stream->_last_macro)
- free (stream->_last_macro);
- obstack_free (&stream->_macro_stack, 0);
- free (stream);
- }
-
- /* This gets rid of an input stream created by macro_only_input_stream.
- * It fixes the INPUT fields of pending command frames.
- */
-
- #ifdef __STDC__
- void
- pop_input_stream (void)
- #else
- void
- pop_input_stream ()
- #endif
- {
- if (the_cmd_frame->input->prev_stream)
- {
- struct command_frame * fr = the_cmd_frame;
- struct input_stream * key = the_cmd_frame->input;
- while (fr->input == key)
- {
- fr->input = key->prev_stream;
- fr = fr->prev;
- }
- free_input_stream (key);
- return;
- }
- }
-
-
- /* Macros
- * These are the commands the user has to interact with macros.
- */
-
- #ifdef __STDC__
- void
- start_entering_macro (void)
- #else
- void
- start_entering_macro ()
- #endif
- {
- if (making_macro)
- {
- io_error_msg ("Can't define two macros at once");
- return;
- }
- making_macro_size = 20;
- making_macro = making_macro_start = ck_malloc (5 + making_macro_size);
- }
-
- #ifdef __STDC__
- void
- bound_macro (int num)
- #else
- void
- bound_macro (num)
- int num;
- #endif
- {
- struct macro *old;
- CELL *cp;
-
- cp = find_cell (bound_macros[num].lr, bound_macros[num].lc);
- if (!cp || GET_TYP (cp) != TYP_STR || cp->cell_str[0] == '\0')
- return;
- old = rmac;
- rmac =
- (struct macro *) obstack_alloc (¯o_stack, sizeof (struct macro));
- rmac->mac_prev = old;
- rmac->mac_rng = bound_macros[num];
- rmac->mac_row = bound_macros[num].lr;
- rmac->mac_col = bound_macros[num].lc;
- obstack_grow (¯o_stack, cp->cell_str, 1 + strlen (cp->cell_str));
- rmac->mac_start = rmac->mac_exe =
- (unsigned char *) obstack_finish (¯o_stack);
- }
-
- #ifdef __STDC__
- void
- run_string_as_macro (char * macro)
- #else
- void
- run_string_as_macro (macro)
- char * macro;
- #endif
- {
- struct rng rng;
- /* This is going to continue the command loop
- * as if some other command had been executed.
- * That command shouldn't receive the same prefix
- * arg that provided a repeat count.
- */
- how_many = 1;
- set_line (&raw_prefix, "");
- rng.lr = rng.hr = rng.lc = rng.hc = MIN_ROW;
- /* Reset the keystate. */
- cur_keymap = the_cmd_frame->top_keymap;
- macro_only_input_stream (&rng, macro, strlen (macro), the_cmd_frame);
- command_loop (1);
- }
-
- #ifdef __STDC__
- void
- call_last_kbd_macro (int count)
- #else
- void
- call_last_kbd_macro (count)
- int count;
- #endif
- {
- if (!last_macro)
- io_error_msg ("No keyboard macro entered.");
- while (count-- > 0)
- run_string_as_macro ((char *)last_macro);
- }
-
- /* This command is automaticly inserted into the command stream
- * when the end of a macro is reached.
- */
- #ifdef __STDC__
- void
- end_macro (void)
- #else
- void
- end_macro ()
- #endif
- {
- CELL *cp;
- struct macro *old;
-
- if (!rmac)
- {
- io_error_msg ("Not executing a macro!");
- return;
- }
- if ((rmac->mac_row == rmac->mac_rng.hr)
- && (rmac->mac_col == rmac->mac_rng.hc))
- {
- old = rmac->mac_prev;
- obstack_free (¯o_stack, rmac);
- rmac = old;
- }
- else
- {
- if (rmac->mac_row == rmac->mac_rng.hr)
- {
- rmac->mac_row = rmac->mac_rng.lr;
- rmac->mac_col++;
- }
- else
- rmac->mac_row++;
-
- cp = find_cell (rmac->mac_row, rmac->mac_col);
-
- if (!cp || GET_TYP (cp) != TYP_STR || cp->cell_str[0] == '\0')
- {
- old = rmac->mac_prev;
- obstack_free (¯o_stack, rmac);
- rmac = old;
- }
- else
- {
- obstack_grow (¯o_stack, cp->cell_str, 1 + strlen (cp->cell_str));
- rmac->mac_exe
- = (unsigned char *) obstack_finish (¯o_stack);
- }
- }
- }
-
-
- /* This command is executed by the user to stop entering a macro.
- */
- #ifdef __STDC__
- void
- stop_entering_macro (void)
- #else
- void
- stop_entering_macro ()
- #endif
- {
- if (!making_macro)
- {
- if (rmac)
- return;
- io_error_msg ("Not defining a macro!");
- return;
- }
-
- making_macro[0] = '\0';
- making_macro = 0;
- if (last_macro)
- ck_free (last_macro);
- last_macro = making_macro_start;
- making_macro_start = 0;
- free (making_macro_start);
- }
-
- #ifdef __STDC__
- void
- store_last_macro (struct rng * rng)
- #else
- void
- store_last_macro (rng)
- struct rng * rng;
- #endif
- {
- union vals z;
- z.c_s = (char *)last_macro;
- set_new_value (rng->lr, rng->lc, TYP_STR, &z);
- }
-
-
-
- /* Scheduling
- *
- * Scheduling is centered around the function real_get_chr
- * which is allowed to block until an input event has occured.
- * Before blocking, real_get_chr may evaluate cells and/or update
- * the display.
- */
-
-
- /* Error messages are delivered to the user by invoking a command
- * that prompts with the error message, and waits for the user's next
- * keypress. This command shouldn't wait indefinitely. After a short time,
- * the error message should disappear. This is accomplished by counting down
- * a timer, then destorying the error message command frame and throwing an
- * error. The error is thrown directly rather than with io_error_msg in order
- * to avoid circularity.
- */
-
- static void
- error_alarm ()
- {
- if (the_cmd_frame->cmd && the_cmd_arg.timeout_seconds)
- {
- --the_cmd_arg.timeout_seconds;
- if (!the_cmd_arg.timeout_seconds)
- {
- pop_unfinished_command ();
- alarm_table[2].freq = 0;
- longjmp (error_exception, 1);
- }
- }
- else
- alarm_table[2].freq = 0;
- }
-
- struct alarm_entry alarm_table [3] =
- {
- {cell_alarm, 1, 0},
- {error_alarm, 0, 0},
- {0, 0}
- };
-
- /* Function that get called whenever blocking times out. */
-
- #ifdef __STDC__
- static void
- alarm_hooks (void)
- #else
- static void
- alarm_hooks ()
- #endif
- {
- int x;
- time_t now = time(0);
- for (x = 0; alarm_table[x].fn; ++x)
- if (alarm_table[x].freq
- && ((now - alarm_table[x].last_time) >= alarm_table[x].freq))
- {
- alarm_table[x].last_time = now;
- alarm_table[x].fn ();
- }
- }
-
-
- #ifdef __STDC__
- static void
- select_hooks (void)
- #else
- static void
- select_hooks ()
- #endif
- {
- int x;
- for (x = 0; x < SELECT_SET_SIZE; ++x)
- {
- if (file_read_hooks[x].hook_fn && FD_ISSET (x, &read_pending_fd_set))
- file_read_hooks[x].hook_fn (x);
- FD_CLR (x, &read_pending_fd_set);
- if (file_write_hooks[x].hook_fn && FD_ISSET (x, &write_pending_fd_set))
- file_write_hooks[x].hook_fn (x);
- FD_CLR (x, &write_pending_fd_set);
- if (file_exception_hooks[x].hook_fn
- && FD_ISSET (x, &exception_pending_fd_set))
- file_exception_hooks[x].hook_fn (x);
- FD_CLR (x, &exception_pending_fd_set);
- }
- }
-
- /* Block until we get a signal (unless system calls restart),
- * can do i/o or, until we timeout (timeout is specified in seconds,
- * 0 means block indefinately). (Front end to select)
- */
- #ifdef __STDC__
- static void
- block_until_excitment (int timeout_seconds)
- #else
- static void
- block_until_excitment (timeout_seconds)
- int timeout_seconds;
- #endif
- {
- int ret;
- struct timeval timeout;
- struct timeval * time_p = 0;
-
- if (timeout_seconds)
- {
- timeout.tv_sec = timeout_seconds;
- timeout.tv_usec = 0;
- time_p = &timeout;
- }
- bcopy ((char *)&read_fd_set, (char *)&read_pending_fd_set,
- sizeof (SELECT_TYPE)) ;
- bcopy ((char *)&exception_fd_set,
- (char *)&exception_pending_fd_set, sizeof (SELECT_TYPE));
- bcopy ((char *)&write_fd_set,
- (char *)&write_pending_fd_set, sizeof (SELECT_TYPE));
- ret = select (SELECT_SET_SIZE,
- &read_pending_fd_set, &write_pending_fd_set,
- &exception_pending_fd_set, time_p);
- if (ret < 0)
- {
- FD_ZERO (&read_pending_fd_set);
- FD_ZERO (&write_pending_fd_set);
- FD_ZERO (&exception_pending_fd_set);
- }
- }
-
- /* This is the main interact loop. As quickly as possible
- * it returns a character from the keyboard. While waiting,
- * it updates cells and the display. If a macro is being defined,
- * this function save characters in the macro.
- */
-
- #ifdef __STDC__
- int
- real_get_chr (void)
- #else
- int
- real_get_chr ()
- #endif
- {
- int ch; /* The char that will be returned. */
-
- /* Characters with the meta bit set are returned as
- * two characters: ESC and a non-meta character.
- * This buffers the non-meta character between calls.
- * The value is 0 if no character is buffered, C+1 if
- * C is buffered.
- */
- static int saved_char;
-
- /* A buffer of characters read in one burst from the kbd. */
- static char ibuf[256];
- static int i_in; /* chars buffered */
- static int i_cnt; /* buffer position */
-
- alarm_hooks ();
- if (saved_char)
- {
- ch = saved_char - 1;
- saved_char = 0;
- goto fini;
- }
-
- if (i_cnt)
- {
- ch = ibuf[i_cnt++];
- if (i_cnt == i_in)
- i_cnt = i_in = 0;
- goto fini;
- }
-
- /* This loop until a character can be read. */
- while (!io_input_avail ())
- {
- alarm_hooks ();
- select_hooks ();
- io_scan_for_input (0);
- if (!io_input_avail ())
- {
- ++current_cycle;
- if (auto_recalc && eval_next_cell ())
- {
- if (bkgrnd_recalc)
- while (!io_input_avail () && eval_next_cell ())
- io_scan_for_input (0);
- else
- while (eval_next_cell ())
- ;
- io_scan_for_input (0);
- if (!io_input_avail ())
- io_redisp ();
- io_flush ();
- io_scan_for_input (0);
- }
- else
- {
- int timeout = (alarm_active
- ? (alarm_seconds == 1
- ? 1
- : (alarm_seconds / 2))
- : 0);
-
- --current_cycle;
- io_redisp ();
- io_flush ();
- io_scan_for_input (0);
- if (!io_input_avail ())
- block_until_excitment (timeout);
- }
- }
- }
-
- {
- int ret;
- ret = io_read_kbd (ibuf, sizeof (ibuf));
- if (ret == 1)
- {
- ch = ibuf[0];
- goto fini;
- }
- if (ret > 1)
- {
- i_cnt = 1;
- i_in = ret;
- ch = ibuf[0];
- goto fini;
- }
- if (ret == 0 || errno != EINTR)
- return EOF;
- }
-
- fini:
-
- if (ch & 0x80)
- {
- saved_char = 1 + (ch & 0x7f);
- ch = CTRL ('[');
- }
-
- if (making_macro)
- {
- /* This is stoopid and should be fixed.
- * Macros (and other cell strings) should be
- * `struct line' and not c-strings. -tl
- */
- if (ch == 0)
- *making_macro++ = 0x80 | 'a';
- else if (ch == '{')
- *making_macro++ = 0x80 | 'b';
- else
- *making_macro++ = ch;
- if (making_macro >= (making_macro_start + making_macro_size))
- {
- making_macro_start = ck_realloc (making_macro_start, 5
- + making_macro_size * 2);
- making_macro = (making_macro_start + making_macro_size);
- making_macro_size *= 2;
- }
- }
- return ch;
- }
-
-
-
-
- /*****************************************************************
- *
- * Command loops
- *
- * The basic cycle is that the user or a macro selects a function
- * (while oleo updates the display and evaluates cells).
- * A new command_frame is allocated in which to evaluate the selected
- * function. Arguments to the function will be stored in this frame.
- * The command loop interprets the FUNC_ARGS string of the selected function
- * and builds an argument list. If the FUNC_ARGS string specifies that
- * the user must be prompted for an argument, an editting mode is entered
- * and the command loop restarts. The queue of command_frames form
- * a stack of recursively invoked editting modes.
- *
- * When all of the arguments are ready, the command loop executes
- * the function and discards its frame.
- *
- * In principle, any number of command_frames can be created and they
- * could be evaluated in any order. It is assumed in the code though that
- * the frame the_cmd_frame->prev is the frame the user was in when
- * the_cmd_frame was created (call it the `parent' frame). Some arguments,
- * for example the prefix argument and the current row/col, are taken from the
- * parent frame. This is because those values may have changed in
- * the_cmd_frame as the user editted arguments to the function being called.
- */
-
- /* The active command frame. This is the head of a queue which is used as a
- * stack.
- */
- struct command_frame * the_cmd_frame = 0;
-
- /* This is a list (next field) of frames that are currently running (their
- * commands are active on the c stack below the error_exception jump buffer).
- */
- struct command_frame * running_frames = 0;
-
-
- /* This is called when the current frame has keymapped
- * down to some function (stored in the_cmd_frame->_cur_cmd.
- * This pushes a new frame in which the arguments to that
- * command will be stored.
- *
- * This can also be called when the_cmd_frame is 0. In that case,
- * it will create a top-level frame.
- *
- */
-
- #ifdef __STDC__
- void
- push_command_frame (struct rng * rng, char * first_line, int len)
- #else
- void
- push_command_frame (rng, first_line, len)
- struct rng * rng;
- struct line * first_line;
- int len;
- #endif
- {
- struct command_frame * new_cf =
- (struct command_frame *)ck_malloc (sizeof (*new_cf));
-
- new_cf->next = new_cf;
- new_cf->prev = new_cf;
-
- new_cf->input = (rng
- ? macro_only_input_stream (rng, first_line, len, new_cf)
- : default_input_stream ());
-
- new_cf->_setrow = NON_ROW;
- new_cf->_setcol = NON_COL;
- new_cf->_curow = MIN_ROW;
- new_cf->_cucol = MIN_COL;
- new_cf->_mkrow = NON_ROW;
- new_cf->_mkcol = NON_COL;
- new_cf->_input_active = 0;
- new_cf->_window_after_input = -1;
-
- /* These may be reset later. */
- new_cf->top_keymap = map_id ("main");
- if (new_cf->top_keymap < 0)
- new_cf->top_keymap = map_id ("universal");
- new_cf->saved_cur_keymap = -1;
- new_cf->_cur_keymap = map_id ("main");
- new_cf->_how_many = 1;
- new_cf->_cur_cmd = 0;
- new_cf->_cur_vector = 0;
- new_cf->_cur_chr = the_cmd_frame ? cur_chr : 0;
-
- init_line (&new_cf->_raw_prefix);
- new_cf->_cmd_argc = 0;
- new_cf->complex_to_user = 0;
-
- if (!the_cmd_frame)
- {
- /* This is a new top-level frame. */
- the_cmd_frame = new_cf;
- new_cf->cmd = 0;
- new_cf->top_keymap = map_id ("main");
- if (new_cf->top_keymap < 0)
- new_cf->top_keymap = map_id ("universal");
- }
- else if (cur_cmd)
- {
- new_cf->_cur_arg = 0;
- new_cf->cmd = cur_cmd;
- {
- int argc = 0;
- char ** prompt = new_cf->cmd->func_args;
- while (prompt && *prompt)
- {
- new_cf->argv[argc].do_prompt = 0;
- new_cf->argv[argc].is_set = 0;
- new_cf->argv[argc].style = 0;
- new_cf->argv[argc].arg_desc = *prompt;
- new_cf->argv[argc].prompt = 0;
- new_cf->argv[argc].expanded_prompt = 0;
- new_cf->argv[argc].prompt_info = 0;
- new_cf->argv[argc].info_line = 0;
- init_line (&new_cf->argv[argc].text);
- set_line (&new_cf->argv[argc].text, "");
- new_cf->argv[argc].cursor = 0;
- new_cf->argv[argc].overwrite = 0;
- new_cf->argv[argc].inc_cmd = 0;
- new_cf->argv[argc].timeout_seconds = 0;
- bzero (&new_cf->argv[argc].val, sizeof (union command_arg_val));
- ++argc;
- ++prompt;
- }
- if (argc && new_cf->argv[0].arg_desc[0] == '+')
- ++new_cf->argv[0].arg_desc;
- new_cf->_cmd_argc = argc;
- new_cf->_curow = curow;
- new_cf->_cucol = cucol;
- new_cf->_mkrow = mkrow;
- new_cf->_mkcol = mkcol;
- new_cf->_setrow = setrow;
- new_cf->_setcol = setcol;
- if (!rng)
- new_cf->input = the_cmd_frame->input;
- }
- }
-
- new_cf->prev = the_cmd_frame;
- new_cf->next = the_cmd_frame->next;
- new_cf->prev->next = new_cf;
- new_cf->next->prev = new_cf;
- the_cmd_frame = new_cf;
- }
-
- /* Remove a frame from the queue/stack. */
- #ifdef __STDC__
- void
- remove_cmd_frame (struct command_frame * frame)
- #else
- void
- remove_cmd_frame (frame)
- struct command_frame * frame;
- #endif
- {
- frame->next->prev = frame->prev;
- frame->prev->next = frame->next;
- if (the_cmd_frame == frame)
- the_cmd_frame = frame->prev;
- if (the_cmd_frame == frame)
- {
- the_cmd_frame = 0;
- push_command_frame (0, 0, 0);
- }
- frame->next = frame->prev = 0;
- }
-
-
- /* This frees all of the memory allocated to FRAME (including
- * the frame itself.
- */
- #ifdef __STDC__
- void
- free_cmd_frame (struct command_frame * frame)
- #else
- void
- free_cmd_frame (frame)
- struct command_frame * frame;
- #endif
- {
- if (frame->next)
- remove_cmd_frame (frame);
-
- free_line (&frame->_raw_prefix);
- if (frame->cmd)
- {
- int argc;
- for (argc = 0; argc < frame->_cmd_argc; ++argc)
- {
- if (frame->argv[argc].is_set && frame->argv[argc].style->destroy)
- frame->argv[argc].style->destroy (&frame->argv[argc]);
- free_line (&frame->argv[argc].text);
- if (frame->argv[argc].expanded_prompt &&
- (frame->argv[argc].expanded_prompt != frame->argv[argc].prompt))
- free (frame->argv[argc].expanded_prompt);
- }
- }
- ck_free (frame);
- }
-
-
- /* Discard the current frame if it contains an unexecuted commnand.
- * This is used, for example, to handle break.
- */
- #ifdef __STDC__
- void
- pop_unfinished_command (void)
- #else
- void
- pop_unfinished_command ()
- #endif
- {
- if (the_cmd_frame->cmd)
- {
- int move_cursor = 0;
- struct command_frame * frame = the_cmd_frame;
- if ( frame->_curow != frame->prev->_curow
- || frame->_cucol != frame->prev->_cucol)
- {
- io_hide_cell_cursor ();
- move_cursor = 1;
- }
- remove_cmd_frame (frame);
- if (move_cursor)
- io_display_cell_cursor ();
- free_cmd_frame (frame);
- }
- }
-
- /* This is called if an error has been signaled with io_error_msg.
- * It discards any frames that the user has never interacted with
- * and cancels all pending macros. This is properly followed by
- * generating an error message for the user and longjmp to error_exception.
- */
-
- #ifdef __STDC__
- void
- recover_from_error (void)
- #else
- void
- recover_from_error ()
- #endif
- {
- /* pop input streams until the bottom is reached. */
- while (the_cmd_frame->input->prev_stream)
- pop_input_stream ();
-
- /* cancel the current macros */
- {
- struct input_stream * stream = the_cmd_frame->input;
- if (stream->_macro_start)
- free (stream->_macro_start);
- if (stream->_last_macro)
- free (stream->_last_macro);
- obstack_free (&stream->_macro_stack, 0);
- obstack_init (&stream->_macro_stack);
- stream->_rmac = 0;
- stream->_func_arg = 0;
- stream->_macro = stream->_macro_start = stream->_last_macro = 0;
- stream->_macro_size = 0;
- stream->_pushed_back_char = -1;
- }
-
- /* pop command frames until an interactive one is reached. */
- while (the_cmd_frame->prev != the_cmd_frame
- && !the_cmd_frame->complex_to_user)
- {
- struct command_frame * fr = the_cmd_frame;
- the_cmd_frame = the_cmd_frame->prev;
- free_cmd_frame (fr);
- }
-
- /* Discard any frames that were executing */
- while (running_frames)
- {
- struct command_frame * f = running_frames;
- running_frames = running_frames->next;
- f->next = 0;
- free_cmd_frame (f);
- }
- }
-
-
-
- /* When we begin editting a new argument, this function sets up the
- * appropriate keymap, and then resets the state of the editting commands.
- *
- * The return value is 1 if the user must be prompted, 0 otherwise.
- */
- #ifdef __STDC__
- static int
- get_argument (char * prompt, struct prompt_style * style)
- #else
- static int
- get_argument (prompt, style)
- char * prompt;
- struct prompt_style * style;
- #endif
- {
- the_cmd_arg.style = style;
- the_cmd_arg.prompt = prompt;
- if (!the_cmd_arg.expanded_prompt)
- the_cmd_arg.expanded_prompt = expand_prompt (prompt);
- the_cmd_frame->top_keymap = map_id (the_cmd_arg.style->keymap);
- the_cmd_arg.is_set = 0;
- the_cmd_arg.do_prompt = 1;
- if (the_cmd_frame->top_keymap < 0)
- the_cmd_frame->top_keymap = map_id ("universal");
- if (macro_func_arg)
- {
- set_line (&the_cmd_arg.text, macro_func_arg);
- {
- char * arg_ptr;
- char * error;
- arg_ptr = the_cmd_arg.text.buf;
- error = the_cmd_arg.style->verify (&arg_ptr, &the_cmd_arg);
- if (error)
- {
- macro_func_arg = 0;
- io_error_msg ("%s", error);
- }
- else
- {
- the_cmd_arg.is_set = 1;
- if (arg_ptr)
- while (isspace (*arg_ptr))
- ++arg_ptr;
- if (arg_ptr && *arg_ptr)
- macro_func_arg = arg_ptr;
- else
- macro_func_arg = 0;
- return 0;
- }
- }
- }
- input_active = 1;
- begin_edit ();
-
- /* Functions can come with macros that initialize arguments for the user.
- * As for the call to expand_prompt -- hehehehehe
- */
- if (the_cmd_frame->cmd->init_code && the_cmd_frame->cmd->init_code[cur_arg])
- {
- char * init_code = expand_prompt(the_cmd_frame->cmd->init_code[cur_arg]);
- struct rng rng;
- rng.lr = rng.hr = rng.lc = rng.hc = 1;
- macro_only_input_stream (&rng, init_code, strlen (init_code),
- the_cmd_frame);
- command_loop (1);
- }
-
- return 1;
- }
-
- #ifdef __STDC__
- void
- exit_minibuffer (void)
- #else
- void
- exit_minibuffer ()
- #endif
- {
- if (check_editting_mode ())
- return;
- else
- {
- char * extra = the_cmd_arg.text.buf;
- char * error = the_cmd_arg.style->verify (&extra, &the_cmd_arg);
- if (error)
- {
- if (*error)
- io_error_msg ("%s", error);
- }
- else
- {
- if (extra)
- {
- while (isspace (*extra))
- ++extra;
- if (*extra)
- io_error_msg ("%s: extra characters in argument (%s)",
- the_cmd_frame->cmd->func_name, extra);
- }
- the_cmd_arg.is_set = 1;
- input_active = 0;
- window_after_input = -1;
- topclear = 2;
- }
- }
- }
-
-
-
-
- #ifdef __STDC__
- void
- setn_arg_text (struct command_arg * arg, char * text, int len)
- #else
- void
- setn_arg_text (arg, text, len)
- struct command_arg * arg;
- char * text;
- int len;
- #endif
- {
- setn_line (&arg->text, text, len);
- arg->cursor = len;
- }
-
- #ifdef __STDC__
- void
- init_arg_text (struct command_arg * arg, char * text)
- #else
- void
- init_arg_text (arg, text)
- struct command_arg * arg;
- char * text;
- #endif
- {
- setn_arg_text (arg, text, strlen (text));
- }
-
- /* This apparently useless alias is here because
- * sometime in the future i want to handle defaults
- * differently.
- */
-
- #ifdef __STDC__
- void
- set_default_arg (struct command_arg * arg, char * text, int len)
- #else
- void
- set_default_arg (arg, text, len)
- struct command_arg * arg;
- char * text;
- int len;
- #endif
- {
- setn_arg_text (arg, text, len);
- }
-
- /* This is the main loop of oleo. It reads commands and their arguments, and
- * evaluates them. It (via real_get_chr) udpates the display and performs
- * background recomputation.
- *
- * This function can also be used to evaluate a function without doing any
- * interaction. This is done by pushing a macro_only command frame
- * (see execute_command).
- */
-
- #ifdef __STDC__
- void
- command_loop (int prefix)
- #else
- void
- command_loop (prefix)
- int prefix;
- #endif
- {
-
- /* We might be re-entering after a longjmp caused by an error.
- * In that case, we use an alternate entry point:
- */
- if (the_cmd_frame->cmd)
- goto resume_getting_arguments;
-
- /* Commands (notably execute_command) just tweek the command_frame
- * state for some other command. To accomplish this, there is an
- * entry point that avoid reinitializing the command_frame.\
- */
- if (prefix)
- {
- prefix = 0;
- goto prefix_cmd_continuation;
- }
-
- while (1)
- {
- int ch; /* The next character to be keymapped. */
-
- new_cycle:
-
- if (!the_cmd_frame)
- push_command_frame (0, 0, 0);
-
- /* Reset the prefix argument. */
- how_many = 1;
- set_line (&raw_prefix, "");
- io_update_status ();
-
- /* Reset the keystate. */
- cur_keymap = the_cmd_frame->top_keymap;
-
- /* If the input area holds a prompt from the last command,
- * erase it.
- */
- io_clear_input_before ();
-
-
- /* Some commands are prefix commands: they effect the
- * user's state without beginnging a new command cyle.
- * Those commands return here:
- */
-
- prefix_cmd_continuation:
-
- /* In this loop, we look for the next command to
- * execute. This may involve reading from a macro,
- * or the keyboard. If there is time to kill, updates
- * and evalutations are done.
- *
- * This loop is exited by `goto got_command'.
- */
-
- while (1)
- {
- /* Get the next character.
- * However, if we are in a macro, and the next character
- * is '{', then the macro contains a function name
- * and keymapping is circumvented.
- */
-
- get_next_char:
-
- if (pushed_back_char >= 0)
- {
- ch = pushed_back_char;
- pushed_back_char = -1;
- }
- else if (!rmac)
- {
- io_fix_input ();
- ch = real_get_chr ();
- }
- else
- {
- int len;
- unsigned char *ptr;
-
- tryagain:
- alarm_hooks ();
- ch = *(rmac->mac_exe++);
- switch (ch)
- {
- case '\0':
- cur_vector = 0;
- cur_cmd = end_macro_cmd;
- cur_chr = 0;
- goto got_command;
-
- case 0x80 | 'a':
- ch = '\0';
- break;
-
- case 0x80 | 'b':
- ch = '{';
- break;
- case 0x80 | 'c':
- ch = '}';
- break;
-
- case '{':
- for (ptr = rmac->mac_exe;
- *ptr && *ptr != ' ' && *ptr != '}';
- ptr++);
- len = ptr - rmac->mac_exe;
- for (cur_vector = 0;
- cur_vector < num_funcs;
- cur_vector++)
- for (cur_cmd =
- &the_funcs[cur_vector][0];
- cur_cmd->func_name;
- cur_cmd++)
- if (!strincmp ((char *) (rmac->mac_exe),
- cur_cmd->func_name, len)
- && cur_cmd->func_name[len] == '\0')
- {
- cur_chr = '\0';
- goto out;
- }
- io_error_msg ("Ignoring unknown function '%.*s' in macro",
- len, rmac->mac_exe);
- while (*ptr != '\0' && *ptr != '}')
- ptr++;
- if (*ptr == '}')
- ptr++;
- rmac->mac_exe = ptr;
- goto tryagain;
-
- out:
- if (*ptr == ' ')
- {
- /* ... add argument support here ... */
- if (!cur_cmd->func_args)
- {
- io_error_msg ("Ignoring extra operand to %s",
- cur_cmd->func_name);
- while (*ptr && *ptr != '}')
- ptr++;
- if (*ptr == '}')
- ptr++;
- }
- else if (cur_cmd->func_args[0][0] == '+')
- {
- unsigned char * start = ptr;
- how_many = astol ((char **) (&ptr));
- setn_line (&raw_prefix, (char *)start,
- ptr - start);
- if (*ptr == '}')
- ptr++;
- }
- else
- {
- while (isspace(*ptr))
- ++ptr;
- macro_func_arg = (char *) ptr;
- while (*ptr && *ptr != '}')
- {
- switch (*ptr)
- {
- case 0x80 | 'b':
- *ptr = '{';
- break;
- case 0x80 | 'c':
- *ptr = '}';
- break;
- }
- ptr++;
- }
- if (*ptr == '}')
- *ptr++ = '\0';
- }
- rmac->mac_exe = ptr;
- }
- else
- rmac->mac_exe += len + 1;
- goto got_command;
- }
- }
-
- /* When control comes here, adjust the keystate according
- * to the cur_keymap and `ch';
- */
- have_character:
-
- /* This is how keymaps are searched for a binding. */
- while (1)
- {
- struct key * key;
- key = &(the_maps[cur_keymap]->keys[ch]);
- if (key->vector < 0)
- {
- if (key->code >= 0)
- {
- cur_keymap = key->code;
- goto get_next_char;
- }
- else if (the_maps[cur_keymap]->map_next)
- cur_keymap =
- the_maps[cur_keymap]->map_next->id;
- else
- {
- cur_vector = 0;
- cur_cmd = 0;
- cur_chr = ch;
- goto got_command;
- }
- }
- else
- {
- cur_vector = key->vector;
- cur_cmd =
- &(the_funcs[key->vector][key->code]);
- cur_chr = ch;
- goto got_command;
- }
- }
- }
-
-
- /* Now the next command to begin has been read from a macro
- * or the keyboard.
- */
- got_command:
-
- /* If there is anything left in the input area (e.g. old error message)
- * get rid of it (but only if we're not executing a macro).
- */
- if (!rmac)
- io_clear_input_after ();
-
- /* There are some commands that are implemented right here. */
- if (cur_cmd == break_cmd)
- {
- io_bell ();
- set_info (0);
- if (input_active)
- pop_unfinished_command (); /* Abort a complex command.*/
- goto new_cycle;
- }
-
- /* The binding of all keys associated with the prefix arg. */
- if (cur_cmd == universal_arg_cmd)
- {
- char ch = cur_chr;
- int prefix_map = map_id ("prefix");
- /* Make sure the prefix-arg keymap is in place. */
- if (cur_keymap != prefix_map)
- {
- the_cmd_frame->saved_cur_keymap = the_cmd_frame->top_keymap;
- cur_keymap = prefix_map;
- }
- /* Store the last character typed in the raw-prefix.*/
- catn_line (&raw_prefix, &ch, 1);
- /* Recompute the numeric value of the prefix. */
- {
- int x = 0;
- int presumed_digits = 0;
- int sign = 1;
-
- how_many = 1;
- while (raw_prefix.buf[x])
- {
- if (isdigit (raw_prefix.buf[x]))
- {
- if (presumed_digits)
- how_many = how_many * 10 + (raw_prefix.buf[x] - '0');
- else
- {
- presumed_digits = 1;
- how_many = raw_prefix.buf[x] - '0';
- }
- }
- else if (raw_prefix.buf[x] == '-')
- sign *= -1;
- else
- {
- if (presumed_digits)
- {
- presumed_digits = 0;
- how_many = 1;
- }
- how_many *= 4;
- }
- ++x;
- }
- how_many *= sign;
- io_update_status ();
- goto prefix_cmd_continuation;
- }
- }
-
- /* Make sure we really mapped to a command. */
- if (!cur_cmd || !cur_cmd->func_func)
- {
- /* If a character is unmapped in the prefix map,
- * retry mapping in the last-used normal keymap.
- */
- if (the_cmd_frame->saved_cur_keymap >= 0)
- {
- cur_keymap = the_cmd_frame->saved_cur_keymap;
- the_cmd_frame->saved_cur_keymap = -1;
- goto have_character;
- }
- /* Otherwise, signal an error and start from the top keymap. */
- io_bell ();
- goto new_cycle;
- }
-
-
-
- /* The next step is to gather the arguments with which to call
- * the function interactively.
- */
- /* Whever a new command is encountered, we begin by creating a
- * frame in which to store it's arguments.
- * This initializes the new frame on the basis of cur_cmd in
- * the_cmd_frame.
- */
- push_command_frame (0, 0, 0);
-
- /* After some other command finishes from underneath a complex command,
- * flow returns here.
- */
-
- resume_getting_arguments:
-
- while (cur_arg < cmd_argc)
- {
- if (the_cmd_arg.is_set)
- goto next_arg;
- else if (the_cmd_arg.prompt)
- {
- begin_edit ();
- goto new_cycle;
- }
- else
- {
- /* If we're just starting on this argument, then parse the
- * FUNC_ARGS string. To continue this loop, use `goto next_arg;'.
- *
- * If user interaction is required, the appropriate keymap,
- * editting area, etc. is set up, and the command loop resumes
- * (`goto new_cycle').
- */
- char * prompt = the_cmd_arg.arg_desc;
-
- switch (*prompt)
- {
- case 'c':
- {
- ++prompt;
- if (*prompt == '#')
- {
- ++prompt;
- the_cmd_arg.val.integer = *prompt;
- the_cmd_arg.is_set = 1;
- the_cmd_arg.do_prompt = 0;
- the_cmd_arg.style = &int_constant_style;
- {
- char c[2];
- c[0] = cur_chr;
- c[1] = '\0';
- init_arg_text (&the_cmd_arg, c);
- }
- goto next_arg;
- }
- else if (*prompt == '\'')
- {
- the_cmd_arg.timeout_seconds = 30;
- alarm_table[1].freq = 1;
- ++prompt;
- }
- if (get_argument (prompt, &char_style))
- goto new_cycle;
- goto next_arg;
- }
- case 'C':
- {
- ++prompt;
- if (get_argument (prompt, &command_style))
- goto new_cycle;
- goto next_arg;
- }
- case 'd':
- {
- ++prompt;
- if (get_argument (prompt, &double_style))
- goto new_cycle;
- goto next_arg;
- }
- case 'f':
- {
- char type;
- struct prompt_style * style;
- ++prompt;
- type = *prompt;
- ++prompt;
- switch (type)
- {
- case 'r':
- style = &read_file_style;
- break;
- case 'w':
- style = &write_file_style;
- break;
- case 'n':
- style = &file_name_style;
- break;
- default:
- style = 0; /* shutup gcc -ansi -pendantic -Wall! */
- io_error_msg ("func_args bug for %s",
- the_cmd_frame->cmd->func_name);
- }
- if (get_argument (prompt, style))
- goto new_cycle;
- goto next_arg;
- }
- case 'F':
- {
- ++prompt;
- if (get_argument (prompt, &format_style))
- goto new_cycle;
- goto next_arg;
- }
- case 'k':
- {
- ++prompt;
- the_cmd_arg.val.key.cmd.vector = -1;
- the_cmd_arg.val.key.cmd.code
- = the_cmd_frame->prev->top_keymap;
- the_cmd_arg.val.key.keys = &the_cmd_arg.text;
- if (get_argument (prompt, &keyseq_style))
- goto new_cycle;
- goto next_arg;
- }
- case 'K':
- {
- ++prompt;
- if (get_argument (prompt, &keymap_style))
- goto new_cycle;
- goto next_arg;
- }
- case 'l':
- {
- the_cmd_arg.val.integer = cur_chr;
- the_cmd_arg.is_set = 1;
- the_cmd_arg.do_prompt = 0;
- the_cmd_arg.style = &int_constant_style;
- {
- char c[2];
- c[0] = cur_chr;
- c[1] = '\0';
- init_arg_text (&the_cmd_arg, c);
- }
- goto next_arg;
- }
- case 'm':
- {
- int want_keyseq = 0;
- ++prompt;
- want_keyseq = (*prompt == '\'');
- if (want_keyseq)
- {
- char * map;
- ++prompt;
- map = expand_prompt (prompt);
- the_cmd_arg.val.key.cmd.vector = -1;
- the_cmd_arg.val.key.cmd.code = map_id (map);
- the_cmd_arg.val.key.keys = &the_cmd_arg.text;
- }
- else
- {
- if (mode_style.keymap)
- ck_free (mode_style.keymap);
- mode_style.keymap = expand_prompt (prompt);
- }
- if (get_argument (prompt, (want_keyseq
- ? &keyseq_style
- : &mode_style)))
- goto new_cycle;
- goto next_arg;
- }
- case 'M':
- if (modified)
- {
- ++prompt;
- if (get_argument (prompt, &yes_style))
- goto new_cycle;
- goto next_arg;
- }
- else
- {
- the_cmd_arg.is_set = 1;
- the_cmd_arg.do_prompt = 1;
- the_cmd_arg.style = &yes_style;
- init_arg_text (&the_cmd_arg, "yes");
- goto next_arg;
- }
- case 'p':
- {
- ++prompt;
- switch (*prompt)
- {
- default:
- the_cmd_arg.val.integer
- = the_cmd_frame->prev->_how_many;
- the_cmd_arg.is_set = 1;
- the_cmd_arg.do_prompt = 0;
- the_cmd_arg.style = &int_constant_style;
- init_arg_text
- (&the_cmd_arg,
- long_to_str ((long)the_cmd_arg.val.integer));
- break;
-
- case '?': /* Command wants to know if prefix provided */
- the_cmd_arg.val.integer =
- (the_cmd_frame->prev->_raw_prefix.alloc
- && the_cmd_frame->prev->_raw_prefix.buf[0]);
- the_cmd_arg.is_set = 1;
- the_cmd_arg.do_prompt = 0;
- the_cmd_arg.style = &int_constant_style;
- init_arg_text (&the_cmd_arg,
- the_cmd_arg.val.integer ? "1" : "0");
- break;
- }
- goto next_arg;
- }
- case 'N':
- case 'n':
- {
- long low = 0;
- long high = -1;
- char type = *prompt;
- ++prompt;
- if (*prompt == '[')
- {
- ++prompt;
- low = astol (&prompt);
- while (isspace (*prompt)) ++prompt;
- if (*prompt == ',') ++prompt;
- high = astol (&prompt);
- while (isspace (*prompt)) ++prompt;
- if (*prompt == ']') ++prompt;
- }
- if ( (type == 'N')
- && the_cmd_frame->prev->_raw_prefix.alloc
- && the_cmd_frame->prev->_raw_prefix.buf[0])
- {
- the_cmd_arg.val.integer
- = the_cmd_frame->prev->_how_many;
- the_cmd_arg.is_set = 1;
- the_cmd_arg.do_prompt = 1;
- the_cmd_arg.style = &number_style;
- if ( (low >= high)
- && ( (low > the_cmd_arg.val.integer)
- || (high < the_cmd_arg.val.integer)))
- io_error_msg
- ("Out of range %d (should be in [%d-%d]).");
- else
- init_arg_text
- (&the_cmd_arg,
- long_to_str ((long)the_cmd_arg.val.integer));
- }
- else
- {
- if (get_argument (prompt, &number_style))
- goto new_cycle;
- }
- goto next_arg;
- }
- case 'r':
- case 'R':
- {
- if (*prompt != 'R' && mkrow != NON_ROW)
- {
- the_cmd_arg.val.range.lr = MIN(mkrow, curow);
- the_cmd_arg.val.range.hr = MAX(mkrow, curow);
- the_cmd_arg.val.range.lc = MIN(mkcol, cucol);
- the_cmd_arg.val.range.hc = MAX(mkcol, cucol);
- the_cmd_arg.is_set = 1;
- the_cmd_arg.do_prompt = 1;
- the_cmd_arg.style = &range_style;
- mkrow = NON_ROW;
- mkcol = NON_COL;
- init_arg_text (&the_cmd_arg,
- range_name (&the_cmd_arg.val.range));
- goto next_arg;
- }
- else
- {
- ++prompt;
- if (get_argument (prompt, &range_style))
- goto new_cycle;
- goto next_arg;
- }
- }
- case 's':
- {
- {
- ++prompt;
- if (get_argument (prompt, &string_style))
- goto new_cycle;
- goto next_arg;
- }
- }
- case 'S':
- {
- {
- ++prompt;
- if (*prompt == '\'')
- ++prompt;
- if (get_argument (prompt, &symbol_style))
- goto new_cycle;
- goto next_arg;
- }
- }
- case 'V':
- {
- ++prompt;
- the_cmd_arg.inc_cmd = io_shift_cell_cursor;
- if (get_argument (prompt, &inc_cmd_style))
- goto new_cycle;
- goto next_arg;
- }
- case 'w':
- {
- {
- ++prompt;
- if (*prompt == '\'')
- ++prompt;
- if (get_argument (prompt, &word_style))
- goto new_cycle;
- goto next_arg;
- }
- }
- case '#':
- {
- ++prompt;
-
- init_arg_text (&the_cmd_arg, prompt);
- the_cmd_arg.val.integer = astol(&prompt);
- the_cmd_arg.is_set = 1;
- the_cmd_arg.do_prompt = 0;
- the_cmd_arg.style = &int_constant_style;
- goto next_arg;
- }
- case '=':
- {
- ++prompt;
- the_cmd_arg.expanded_prompt = expand_prompt(prompt);
- init_arg_text (&the_cmd_arg, the_cmd_arg.expanded_prompt);
- the_cmd_arg.val.string = the_cmd_arg.expanded_prompt;
- the_cmd_arg.is_set = 1;
- the_cmd_arg.do_prompt = 0;
- the_cmd_arg.style = &string_style;
- goto next_arg;
- }
- case '.':
- {
- ++prompt;
- the_cmd_arg.val.range.lr = curow;
- the_cmd_arg.val.range.lc = cucol;
- if (*prompt == '\'')
- {
- the_cmd_arg.val.range.hr = curow;
- the_cmd_arg.val.range.hc = cucol;
- }
- else
- {
- the_cmd_arg.val.range.hr = mkrow;
- the_cmd_arg.val.range.hc = mkcol;
- }
- the_cmd_arg.is_set = 1;
- the_cmd_arg.do_prompt = 0;
- init_arg_text (&the_cmd_arg,
- range_name (&the_cmd_arg.val.range));
- the_cmd_arg.style = &range_constant_style;
- goto next_arg;
- }
- case '[':
- {
- ++prompt;
- while (*prompt && (*prompt != ']'))
- if (*prompt != '\\')
- ++prompt;
- else
- {
- ++prompt;
- if (*prompt)
- ++prompt;
- }
- if (*prompt == ']')
- ++prompt;
-
- if (get_argument (prompt, &menu_style))
- goto new_cycle;
- goto next_arg;
- }
- case '$':
- {
- /* Edit a cell's formula. */
- CELL * cp = find_cell (curow, cucol);
- ++prompt;
- if (((!cp || GET_LCK (cp) == LCK_DEF)
- && (default_lock == LCK_LCK))
- || (cp && GET_LCK (cp) == LCK_LCK))
- {
- io_error_msg ("Cell %s is locked",
- cell_name (curow, cucol));
- pop_unfinished_command ();
- goto new_cycle;
- }
- the_cmd_frame->prev->_setrow = curow;
- the_cmd_frame->prev->_setcol = cucol;
- if (get_argument (prompt, &formula_style))
- {
- init_arg_text (&the_cmd_arg,
- decomp (curow, cucol, cp));
- decomp_free ();
- goto new_cycle;
- }
- goto next_arg;
- }
-
- default:
- {
- io_error_msg ("Interaction-string error!!!");
- pop_unfinished_command ();
- goto new_cycle;
- }
- }
- }
- next_arg:
- ++cur_arg;
- }
-
- /* Make sure that all the args are really there. */
- for (cur_arg = 0; cur_arg < cmd_argc; ++cur_arg)
- if (the_cmd_arg.do_prompt && !the_cmd_arg.is_set)
- goto resume_getting_arguments;
-
- /* If this point is reached, call the interactive function,
- * destroy it's frame, and restart the cycle.
- */
- {
- int move_cursor = 0;
- struct command_frame * frame = the_cmd_frame;
- cmd_invoker stub = find_stub ();
- if ( frame->_curow != frame->prev->_curow
- || frame->_cucol != frame->prev->_cucol)
- {
- move_cursor = 1;
- io_hide_cell_cursor ();
- }
- remove_cmd_frame (frame);
- /* Add frame to the list of frames to be freed on error. */
- frame->next = running_frames;
- running_frames = frame;
- if (move_cursor)
- io_display_cell_cursor ();
- if (!stub)
- io_error_msg ("Don't know how to invoke %s!!!",
- frame->cmd->func_name);
- else
- stub (frame);
- running_frames = running_frames->next;
- frame->next = 0;
- free_cmd_frame (frame);
-
- /* If command_loop was called by execute_command, it should
- * return as soon as there is no more macro to evaluate.
- */
- if (!rmac && the_cmd_frame->input->prev_stream)
- {
- pop_input_stream ();
- return;
- }
- if (the_cmd_frame->cmd)
- goto resume_getting_arguments;
- }
- }
- }
-
- /* Exectute the command called in `string'.
- * If the string begins with a proper command name,
- * it is executed as if it were embedded in "{}" in
- * a macro. Otherwise, if the string can be interpreted
- * as a range address, the macro at that address is executed.
- */
-
- static struct line exec_cmd_line = {0, 0};
-
- /* execute_command buils a macro expression of the from `{command args}'.
- * This function quotes the braces in ARGS so that the macro reader knows
- * they are literal rather than macro syntax.
- */
- static void
- quote_macro_args (args)
- char * args;
- {
- while (*args)
- {
- switch (*args)
- {
- case '{':
- *args = 0x80 | 'b';
- break;
- case '}':
- *args = 0x80 | 'c';
- break;
- }
- ++args;
- }
- }
-
- #ifdef __STDC__
- void
- execute_command (char *str)
- #else
- void
- execute_command (str)
- char *str;
- #endif
- {
- char *ptr = str;
- char * run; /* The first string to execute. */
- /* The address of the macro to execute. If the user typed a
- * command name and not a range name, then this range will be
- * set to a one cell region.
- */
- struct rng rng;
- static struct line exec_buf = {0, 0};
- int count = 1;
-
- /* Chop off the first word. */
- while (isspace (*str))
- ++str;
- if (!*str || *str == '#')
- return;
- for (ptr = str; *ptr && !isspace (*ptr); ptr++);
- if (*ptr)
- {
- setn_line (&exec_buf, str, ptr - str + 1);
- exec_buf.buf[ptr - str] = 0;
- str = exec_buf.buf;
- ++ptr;
- }
- else
- ptr = 0;
-
-
- /* First, look for a command name. */
- {
- int vector;
- struct cmd_func * cmd;
-
- if (!find_function (&vector, &cmd, str, strlen(str)))
- {
- if (ptr)
- {
- quote_macro_args (ptr);
- sprint_line (&exec_cmd_line, "{%s %s}", str, ptr);
- }
- else
- sprint_line (&exec_cmd_line, "{%s}", str);
- run = exec_cmd_line.buf;
- rng.lr = rng.hr = 1;
- rng.lc = rng.hc = 1;
- goto found_command;
- }
- }
-
- {
- /* Try for a range address. */
- CELL *cp;
- if (get_abs_rng (&str, &rng))
- {
- io_error_msg ("Unknown command %s", str);
- return;
- }
- if (ptr)
- {
- io_error_msg ("Macros can't take arguments");
- return;
- }
-
- cp = find_cell (rng.lr, rng.lc);
- if (!cp
- || GET_TYP (cp) != TYP_STR
- || cp->cell_str[0] == '\0')
- {
- io_error_msg ("No macro found at %s.", range_name (&rng));
- return;
- }
-
- run = cp->cell_str;
- /* Reset the keystate. */
- cur_keymap = the_cmd_frame->top_keymap;
- count = how_many;
- how_many = 1; /* s.o.p when executing macros; */
- set_line (&raw_prefix, ""); /* see run_string_as_macro for more info*/
- }
-
- found_command:
- while (count-- > 0)
- {
- macro_only_input_stream (&rng, run, strlen (run), the_cmd_frame);
- command_loop (1);
- }
- }
-
-
-
-
- /* Read a character. If we're in a macro, read from the macro. . . */
- #ifdef __STDC__
- int
- get_chr (void)
- #else
- int
- get_chr ()
- #endif
- {
- int ch;
-
- if (rmac)
- {
- ch = *(rmac->mac_exe++);
- switch (ch)
- {
- case '{': /* What else can we do? */
- case '\0':
- --rmac->mac_exe;
- break;
-
- case (0x80 | 'a'):
- ch = 0;
- break;
-
- case (0x80 | 'b'):
- ch = '{';
- break;
- default:
- break;
- }
- }
- else
- ch = real_get_chr ();
- return ch;
- }
-
-
- /* This is an entirely magical function. All of it's work is done
- * by the argument prompting system. All that remains to be done
- * when this is called is to push back a character the user may have
- * typed to cause the error message to go away.
- */
-
- #ifdef __STDC__
- void
- display_error_msg (char * msg, int c)
- #else
- void
- display_error_msg (msg, c)
- char * msg;
- int c;
- #endif
- {
- if (c > 0)
- pushed_back_char = c;
- }
-
- #ifdef __STDC__
- void
- pushback_keystroke (int c)
- #else
- void
- pushback_keystroke (c)
- int c;
- #endif
- {
- if (c > 0)
- pushed_back_char = c;
- }
-
- #ifdef __STDC__
- void
- io_error_msg (char *str,...)
- #else
- void
- io_error_msg (str, va_alist)
- char *str;
- va_dcl
- #endif
- {
- va_list foo;
- char buf[1000];
- char buf2[1000];
-
- /* This is made robust against errors that occur before
- * the io hooks have been initialized.
- */
- if (display_opened)
- io_bell ();
-
- var_start (foo, str);
- vsprintf (buf, str, foo);
- sprintf (buf2, "display-error-msg %s", buf);
- recover_from_error ();
- if (display_opened)
- execute_command (buf2);
- else
- fprintf (stderr, "oleo: %s\n", buf);
- longjmp (error_exception, 1);
- }
-
-
- #ifdef __STDC__
- void
- io_info_msg (char *str,...)
- #else
- void
- io_info_msg (str, va_alist)
- char *str;
- va_dcl
- #endif
- {
- va_list foo;
- char buf[1000];
- char buf2[1000];
-
- var_start (foo, str);
- vsprintf (buf, str, foo);
- sprintf (buf2, "display-error-msg %s", buf);
- execute_command (buf2);
- }
-
-
-
-
- /* Expands a string that will be used to prompt for an argument.
- * %n expands to the text of argument n (if defined -- ??? otherwise).
- * %% expands to %
- * %c expands to the name of the_cmd_frame->prev->_set{row,col}
- * If no expansion is needed, the argument is returned. Otherwise,
- * malloced memory is returned.
- */
-
- #ifdef __STDC__
- char *
- expand_prompt (char * str)
- #else
- char *
- expand_prompt (str)
- char * str;
- #endif
- {
- struct line expanded;
- init_line (&expanded);
- if (!str || !index (str, '%'))
- return ck_savestr (str);
- {
- char * last_pos = str;
- char * src_pos;
-
- for (src_pos = index (str, '%'); src_pos; src_pos = index (src_pos, '%'))
- {
- catn_line (&expanded, last_pos, src_pos - last_pos);
- ++src_pos;
- switch (*src_pos)
- {
- case '%':
- catn_line (&expanded, src_pos, 1);
- ++src_pos;
- break;
- case 'c':
- {
- struct rng rng;
- char * str;
- rng.lr = rng.hr = the_cmd_frame->prev->_setrow;
- rng.lc = rng.hc = the_cmd_frame->prev->_setcol;
- str = range_name (&rng);
- catn_line (&expanded, str, strlen(str));
- ++src_pos;
- break;
- }
- case '.':
- {
- struct rng rng;
- char * str;
- rng.lr = rng.hr = the_cmd_frame->prev->_curow;
- rng.lc = rng.hc = the_cmd_frame->prev->_cucol;
- str = range_name (&rng);
- catn_line (&expanded, str, strlen(str));
- ++src_pos;
- break;
- }
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- {
- int argn = *src_pos - '0';
- if ( (cmd_argc > argn)
- && the_cmd_frame->argv[argn].is_set
- && the_cmd_frame->argv[argn].text.buf)
- catn_line (&expanded, the_cmd_frame->argv[argn].text.buf,
- strlen (the_cmd_frame->argv[argn].text.buf));
- else
- catn_line (&expanded, "????", 4);
- ++src_pos;
- break;
- }
- default:
- catn_line (&expanded, "%", 1);
- break;
- }
- last_pos = src_pos;
- }
- catn_line (&expanded, last_pos, strlen(last_pos));
- }
- return expanded.buf;
- }
-
-
-
-
- /* Info commands */
-
- #ifdef __STDC__
- void
- set_info (char * name)
- #else
- void
- set_info (name)
- char * name;
- #endif
- {
- struct info_buffer * ib = (name ? find_or_make_info (name) : 0);
-
- if (the_cmd_frame->cmd && (the_cmd_arg.prompt_info != ib))
- {
- the_cmd_arg.info_line = 0;
- the_cmd_arg.prompt_info = ib;
- }
- if (!ib && name && *name)
- io_error_msg ("No information about %s.", name);
- }
-
-
- #ifdef __STDC__
- void
- page_info_backwards (int rep)
- #else
- void
- page_info_backwards (rep)
- int rep;
- #endif
- {
- if (rep < 0)
- page_info (-rep);
- else if (the_cmd_frame->cmd && the_cmd_arg.prompt_info)
- {
- int vis_lines = (scr_lines - input_rows) / info_rows;
- int next = the_cmd_arg.info_line - vis_lines * rep;
- the_cmd_arg.info_line = ((next >= 0) ? next : 0);
- }
- else
- io_error_msg ("No info to page.");
- }
-
- #undef MAX
- #define MAX(A,B) (((A) >= (B)) ? (A) : (B))
-
- #ifdef __STDC__
- void
- page_info (int rep)
- #else
- void
- page_info (rep)
- int rep;
- #endif
- {
- if (rep < 0)
- page_info_backwards (-rep);
- else if (the_cmd_frame->cmd && the_cmd_arg.prompt_info)
- {
- int vis_lines = (scr_lines - input_rows) / info_rows;
- int next = the_cmd_arg.info_line + vis_lines * rep;
- the_cmd_arg.info_line =
- ((next >= the_cmd_arg.prompt_info->len)
- ? MAX(0, (the_cmd_arg.prompt_info->len - vis_lines))
- : next);
- }
- else
- io_error_msg ("No info to page.");
- }
-
- #ifdef __STDC__
- void
- view_info (char * name, int ignore)
- #else
- void
- view_info (name, ignore)
- char * name;
- int ignore;
- #endif
- {}
-
-
-
- /* The C part of this function is uninteresting. The interesting part
- * is in defun.h.
- */
-
- #ifdef __STDC__
- void
- with_keymap (char * mapname)
- #else
- void
- with_keymap (mapname)
- char * mapname;
- #endif
- {}
-
- #ifdef __STDC__
- void
- one_cmd_with_keymap (char * mapname, struct key_sequence * keyseq)
- #else
- void
- one_cmd_with_keymap (mapname, keyseq)
- char * mapname;
- struct key_sequence * keyseq;
- #endif
- {
- if (keyseq->cmd.vector < 0 && keyseq->cmd.code < 0)
- io_bell ();
- else if (keyseq->cmd.vector < 0)
- io_error_msg
- ("one-command-with-keymap: %s maps to a keymap (%s), not a command.",
- keyseq->keys->buf, map_names[keyseq->cmd.code]);
- else
- execute_command
- (the_funcs[keyseq->cmd.vector][keyseq->cmd.code].func_name);
- }
-