home *** CD-ROM | disk | FTP | other *** search
- /* MS-DOS SHELL - History Processing
- *
- * MS-DOS SHELL - Copyright (c) 1990 Data Logic Limited
- *
- * This code is subject to the following copyright restrictions:
- *
- * 1. Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice is duplicated in the
- * source form and the copyright notice in file sh6.c is displayed
- * on entry to the program.
- *
- * 2. The sources (or parts thereof) or objects generated from the sources
- * (or parts of sources) cannot be sold under any circumstances.
- *
- * $Header: C:/SRC/SHELL/RCS/sh9.c 1.12 90/05/31 10:39:26 MS_user Exp $
- *
- * $Log: sh9.c $
- * Revision 1.12 90/05/31 10:39:26 MS_user
- * Initialise the input buffer in case of interrupts
- *
- * Revision 1.11 90/03/27 20:22:07 MS_user
- * Fix problem with paging down history file - the last item was incorrect
- *
- * Revision 1.10 90/03/26 04:10:53 MS_user
- * Scan_History uses the Match length and not the string length for matching
- *
- * Revision 1.9 90/03/21 14:05:26 MS_user
- * History search sometimes includes the optionals in the search string.
- *
- * Revision 1.8 90/03/14 13:23:48 MS_user
- * Change names of configuration fields to reflect function
- *
- * Revision 1.7 90/03/13 18:36:07 MS_user
- * Add initialisation file processing
- *
- * Revision 1.6 90/03/09 16:07:40 MS_user
- * Add SH_ALT_KEYS processing
- * Fix bottom line processing so that cursor doesn't disappear
- * Fix EGA detection so we get the correct screen size
- *
- * Revision 1.5 90/03/06 16:50:57 MS_user
- * Add disable history option
- *
- * Revision 1.4 90/03/06 15:14:40 MS_user
- * Complete changes for file name completion
- * Add find Max Lines function
- *
- * Revision 1.3 90/03/05 13:54:28 MS_user
- * Fix get previous command request
- * Add filename completion
- * Add Max Columns from BIOS
- * Add cursor position check function
- * Add !! option
- * Change erase to end of line processing to remove ANSI.SYS dependency
- *
- * Revision 1.2 90/02/19 15:42:39 MS_user
- * Remove dependency on ANSI.SYS
- *
- * Revision 1.1 90/01/26 17:25:19 MS_user
- * Initial revision
- *
- *
- */
-
- #include <sys/types.h>
- #include <stdio.h>
- #include <conio.h>
- #include <string.h>
- #include <memory.h>
- #include <ctype.h>
- #include <signal.h>
- #include <stdlib.h>
- #include <stddef.h>
- #include <errno.h>
- #include <setjmp.h>
- #include <limits.h>
- #include <dos.h>
- #include <unistd.h>
- #include <dirent.h>
- #include "sh.h"
-
- /* Keyboard functions */
-
- #define KF_LENGTH (sizeof (KF_List) / sizeof (KF_List[0]))
- #define KF_SCANBACKWARD 0x00 /* Scan backwards in history */
- #define KF_SCANFOREWARD 0x01 /* Scan forewards in history */
- #define KF_PREVIOUS 0x02 /* Previous command */
- #define KF_NEXT 0x03 /* Next command */
- #define KF_LEFT 0x04 /* Left one character */
- #define KF_RIGHT 0x05 /* Right one character */
- #define KF_WORDRIGHT 0x06 /* Right one word */
- #define KF_WORDLEFT 0x07 /* Left one word */
- #define KF_START 0x08 /* Move to start of line */
- #define KF_CLEAR 0x09 /* Clear input line */
- #define KF_FLUSH 0x0a /* Flush to end of line */
- #define KF_END 0x0b /* End of line */
- #define KF_INSERT 0x0c /* Insert mode switch */
- #define KF_DELETERIGHT 0x0d /* Delete right character */
- #define KF_DELETELEFT 0x0e /* Delete left character */
- #define KF_COMPLETE 0x0f /* Complete file name */
- #define KF_DIRECTORY 0x10 /* Complete directory function */
- #define KF_END_FKEYS 0x11 /* End of function keys */
- #define KF_RINGBELL 0x11 /* Ring bell */
- #define KF_HALFHEIGTH 0x12 /* Half height cursor */
-
- /* Function Declarations */
-
- #ifndef NO_HISTORY
- static bool alpha_numeric (int);
- static bool function (int);
- static bool Process_History (int);
- static bool Scan_History (void);
- static void Redisplay_Line (void);
- static void Process_Stdin (void);
- static void Page_History (int);
- static bool UpDate_CLine (char *);
- static bool Re_start (char *);
- static void memrcpy (char *, char *, int);
- static void set_cursor_position (int);
- static void gen_cursor_position (void);
- static void erase_to_end_of_line (void);
- static void set_cursor_shape (bool);
- static bool Complete_file (char *, bool);
- static void Init_Input (bool);
- #endif
- static void read_cursor_position (void);
- static void Get_Screen_Params (void);
-
- static int s_cursor; /* Start cursor position */
- static int Max_Cols = 80; /* Max columns */
- static int Max_Lines = 25; /* Max Lines */
- #ifndef NO_HISTORY
- static bool insert_mode = FALSE;
- static char *c_buffer_pos; /* Position in command line */
- static char *end_buffer; /* End of command line */
- static int m_line = 0; /* Max write line number */
- static int c_history = -1; /* Current entry */
- static int l_history = 0; /* End of history array */
- static int M_length = -1; /* Match length */
- static int Max_Length = 0; /* Max line length */
- static char l_buffer[LINE_MAX + 1];
- static char *No_prehistory = "history: No previous commands";
- static char *No_MatchHistory = "history: No history match found";
- static char *No_posthistory = "history: No more commands";
- static char *History_2long = "history: History line too long";
- static char *H_TooLongI = "History file line too long - ignored (%d)\n";
-
- /* Function Key table */
-
- static struct Key_Fun_List {
- char *kf_name;
- char akey;
- char fkey;
- char fcode;
- } KF_List[] = {
- { "ScanBackward", 0, 'I', KF_SCANBACKWARD },
- { "ScanForeward", 0, 'Q', KF_SCANFOREWARD },
- { "Previous", 0, 'H', KF_PREVIOUS },
- { "Next", 0, 'P', KF_NEXT },
- { "Left", 0, 'K', KF_LEFT },
- { "Right", 0, 'M', KF_RIGHT },
- { "WordRight", 0, 't', KF_WORDRIGHT },
- { "WordLeft", 0, 's', KF_WORDLEFT },
- { "Start", 0, 'G', KF_START },
- { "Clear", 0, 'v', KF_CLEAR },
- { "Flush", 0, 'u', KF_FLUSH },
- { "End", 0, 'O', KF_END },
- { "Insert", 0, 'R', KF_INSERT },
- { "DeleteRight", 0, 'S', KF_DELETERIGHT },
- { "DeleteLeft", 0x08, 0, KF_DELETELEFT },
- { "Complete", 0, 'w', KF_COMPLETE },
- { "Directory", 0, 0x0f, KF_DIRECTORY },
-
- /* End of function keys - flags */
-
- { "Bell", 1, 0, KF_RINGBELL },
- { "HalfHeight", 0, 0, KF_HALFHEIGTH }
- };
-
- /* Arrary of history Items */
-
- static struct cmd_history {
- int number;
- char *command;
- } cmd_history[HISTORY_MAX];
-
- /* Processing standard input */
-
- int Get_stdin (ap)
- register IO_Args *ap;
- {
- int coff = (int)ap->afpos;
- char rv;
-
- /* Is there anything in the input buffer. If not, add the previous line to
- * the history buffer and get the next line
- */
-
- if (!coff)
- Process_Stdin (); /* No - get input */
-
- /* Get the next character */
-
- if ((rv = l_buffer[coff]) == NL)
- {
- l_buffer[coff] = 0;
- ap->afpos = 0L;
- }
-
- /* Check for end of file */
-
- else if (rv == 0x1a)
- {
- l_buffer[coff] = 0;
- ap->afpos = 0L;
- rv = 0;
- }
-
- else
- ap->afpos++;
-
- return rv;
- }
-
- /* Input processing function */
-
- static void Process_Stdin ()
- {
- char a_key, f_key;
- int i;
-
- /* Set to last history item */
-
- c_history = l_history;
- memset (l_buffer, 0, LINE_MAX + 1);
-
- /* Process the input */
-
- while (TRUE)
- {
- Init_Input (FALSE); /* Initialise */
-
- while (((a_key = (char)getch ()) != 0x1a) && (a_key != NL) &&
- (a_key != '\r'))
- {
-
- /* If function key, get the fkey value */
-
- if (!a_key)
- f_key = (char)getch ();
-
- /* Look up the keystroke to see if it is one of our functions */
-
- for (i = 0; (i < KF_END_FKEYS); ++i)
- {
- if (KF_List[i].akey != a_key)
- continue;
-
- if ((a_key != 0) || (KF_List[i].fkey == f_key))
- break;
- }
-
- /* If this is a function key and is not ours, ignore it */
-
- if ((i == KF_END_FKEYS) && (!a_key))
- continue;
-
- if (((i == KF_END_FKEYS) ? alpha_numeric (a_key)
- : function (KF_List[i].fcode)))
- Redisplay_Line ();
-
- /* Reposition the cursor */
-
- gen_cursor_position ();
- }
-
- /* Terminate the line */
-
- *end_buffer = 0;
- v1_putc (NL);
- s_cursor = -1;
-
- /* Line input - check for history */
-
- if ((*l_buffer == '!') && Process_History (0))
- {
- v1a_puts (l_buffer);
- break;
- }
-
- else if (*l_buffer != '!')
- break;
- }
-
- set_cursor_shape (FALSE);
- *end_buffer = (char)((a_key == '\r') ? NL : a_key);
- }
-
- /* Handler Alpha_numeric characters */
-
- static bool alpha_numeric (c)
- int c;
- {
- bool redisplay = FALSE;
-
- /* Normal character processing */
-
- if ((c_buffer_pos - l_buffer) == LINE_MAX)
- {
- v1_putc (0x07); /* Ring bell */
- return FALSE;
- }
-
- else if (!insert_mode)
- {
- if (c_buffer_pos == end_buffer)
- ++end_buffer;
-
- else if (iscntrl (*c_buffer_pos) || iscntrl (c))
- redisplay = TRUE;
-
- *(c_buffer_pos++) = (char)c;
-
- if (redisplay || (c == '\t'))
- return TRUE;
-
- if (iscntrl (c))
- {
- v1_putc ('^');
- c += '@';
- }
-
- v1_putc ((char)c);
- return FALSE;
- }
-
- else if ((end_buffer - l_buffer) == LINE_MAX)
- {
- v1_putc (0x07); /* Ring bell - line full */
- return FALSE;
- }
-
- else
- {
- if (c_buffer_pos != end_buffer)
- memrcpy (end_buffer + 1, end_buffer, end_buffer - c_buffer_pos + 1);
-
- ++end_buffer;
- *(c_buffer_pos++) = (char)c;
- return TRUE;
- }
- }
-
- /* Process function keys */
-
- static bool function (fn)
- int fn;
- {
- bool fn_search = FALSE;
-
- switch (fn)
- {
- case KF_SCANBACKWARD: /* Scan backwards in history */
- case KF_SCANFOREWARD: /* Scan forewards in history */
- *end_buffer = 0;
-
- if (M_length == -1)
- M_length = strlen (l_buffer);
-
- Page_History ((fn == KF_SCANBACKWARD) ? -1 : 1);
- return TRUE;
-
- case KF_PREVIOUS: /* Previous command */
- *end_buffer = 0;
- Process_History (-1);
- return TRUE;
-
- case KF_NEXT: /* Next command line */
- Process_History (1);
- return TRUE;
-
- case KF_LEFT: /* Cursor left */
- if (c_buffer_pos != l_buffer)
- --c_buffer_pos;
-
- else
- v1_putc (0x07);
-
- return FALSE;
-
- case KF_RIGHT: /* Cursor right */
- if (c_buffer_pos != end_buffer)
- ++c_buffer_pos;
-
- else
- v1_putc (0x07);
-
- return FALSE;
-
- case KF_WORDLEFT: /* Cursor left a word */
- if (c_buffer_pos != l_buffer)
- {
- --c_buffer_pos; /* Reposition on previous char */
-
- while (isspace (*c_buffer_pos) && (c_buffer_pos != l_buffer))
- --c_buffer_pos;
-
- while (!isspace (*c_buffer_pos) && (c_buffer_pos != l_buffer))
- --c_buffer_pos;
-
- if (c_buffer_pos != l_buffer)
- ++c_buffer_pos;
- }
-
- else
- v1_putc (0x07);
-
- return FALSE;
-
- case KF_WORDRIGHT: /* Cursor right a word */
- if (c_buffer_pos != end_buffer)
- {
-
- /* Skip to the end of the current word */
-
- while (!isspace (*c_buffer_pos) && (c_buffer_pos != end_buffer))
- ++c_buffer_pos;
-
- /* Skip over the white space */
-
- while (isspace (*c_buffer_pos) && (c_buffer_pos != end_buffer))
- ++c_buffer_pos;
- }
-
- else
- v1_putc (0x07);
-
- return FALSE;
-
- case KF_START: /* Cursor home */
- c_buffer_pos = l_buffer;
- return FALSE;
-
- case KF_CLEAR: /* Erase buffer */
- c_buffer_pos = l_buffer;
-
- case KF_FLUSH: /* Flush to end */
- memset (c_buffer_pos, ' ', end_buffer - c_buffer_pos);
- end_buffer = c_buffer_pos;
- return TRUE;
-
- case KF_END: /* Cursor end of command */
- if (*l_buffer == '!')
- {
- *end_buffer = 0;
- Process_History (2);
- return TRUE;
- }
-
- c_buffer_pos = end_buffer;
- return FALSE;
-
- case KF_INSERT: /* Switch insert mode */
- insert_mode = (insert_mode) ? FALSE : TRUE;
- set_cursor_shape (insert_mode);
- return FALSE;
-
- case KF_DELETERIGHT: /* Delete right character */
- if (c_buffer_pos == end_buffer)
- return FALSE;
-
- memcpy (c_buffer_pos, c_buffer_pos + 1, end_buffer - c_buffer_pos);
-
- if (end_buffer == l_buffer)
- {
- v1_putc (0x07);
- return TRUE;
- }
-
- if (--end_buffer < c_buffer_pos)
- --c_buffer_pos;
-
- return TRUE;
-
- case KF_DIRECTORY: /* File name directory */
- fn_search = TRUE;
-
- case KF_COMPLETE: /* File name completion */
- {
- char *fn_start = c_buffer_pos;
-
- *end_buffer = 0;
-
- if (isspace (*fn_start))
- --fn_start;
-
- if (isspace (*fn_start) || (fn_start < l_buffer))
- break;
-
- return Complete_file (fn_start, fn_search);
- }
-
- case KF_DELETELEFT: /* Delete left character */
- if (c_buffer_pos == l_buffer)
- {
- v1_putc (0x07); /* Ring bell */
- return FALSE;
- }
-
- /* Decrement current position */
-
- --c_buffer_pos;
- memcpy (c_buffer_pos, c_buffer_pos + 1, end_buffer - c_buffer_pos);
- --end_buffer;
- return TRUE;
- }
- }
-
- /* Set cursor shape */
-
- static void set_cursor_shape (mode)
- bool mode;
- {
- union REGS r;
-
- /* Get the current cursor position to get the cursor lines */
-
- r.h.ah = 0x03;
- int86 (0x10, &r, &r);
-
- /* Reset the type */
-
- r.h.ah = 0x01;
- r.h.ch = (unsigned char)(!mode ? r.h.cl - 1
- : (KF_List[KF_HALFHEIGTH].akey
- ? (r.h.cl / 2) + 1 : 1));
- int86 (0x10, &r, &r);
- }
- #endif
-
- /* Read Cursor position */
-
- static void read_cursor_position ()
- {
- union REGS r;
-
- r.h.ah = 0x03; /* Read cursor position */
- r.h.bh = 0; /* Page zero */
- int86 (0x10, &r, &r);
- s_cursor = (r.h.dh * Max_Cols) + r.h.dl;
- }
-
- /* Re-position the cursor */
-
- #ifndef NO_HISTORY
- static void set_cursor_position (new)
- int new;
- {
- int diff;
- union REGS r;
-
- r.h.ah = 0x02; /* Set new position */
- r.h.bh = 0; /* Page zero */
- r.h.dh = (unsigned char)(new / Max_Cols);
- r.h.dl = (unsigned char)(new % Max_Cols);
-
- /* Are we at the bottom of the page? */
-
- if (r.h.dh >= (unsigned char)Max_Lines)
- {
- diff = r.h.dh + 1 - Max_Lines;
- r.h.dh = (unsigned char)(Max_Lines - 1);
- s_cursor -= Max_Cols * diff;
- }
-
- int86 (0x10, &r, &r);
- }
-
- /* Erase to end of line (avoid need for STUPID ansi.sys memory eater!) */
-
- static void erase_to_end_of_line ()
- {
- union REGS r;
- unsigned char backg;
-
- /* Get the background attribute of the cursor */
-
- r.h.ah = 0x08;
- r.h.bh = 0;
- int86 (0x10, &r, &r);
- backg = r.h.ah & 0x07;
-
- r.h.ah = 0x03;
- r.h.bh = 0;
- int86 (0x10, &r, &r);
-
- /* Check that we use the correct m_line */
-
- if (m_line < r.h.dh)
- m_line = r.h.dh;
-
- if ((r.x.cx = Max_Cols - r.h.dl + (m_line - r.h.dh) * Max_Cols) > 0)
- {
- r.x.ax = 0x0a20;
- r.x.bx = backg;
- int86 (0x10, &r, &r);
- }
- }
-
- /* Generate the new cursor position */
-
- static void gen_cursor_position ()
- {
- char *cp = l_buffer - 1;
- int off = s_cursor;
-
- /* Search to current position */
-
- while (++cp != c_buffer_pos)
- {
- if (*cp == '\t')
- while ((++off) % 8);
-
- else if (iscntrl (*cp))
- off += 2;
-
- else
- ++off;
- }
-
- /* Position the cursor */
-
- set_cursor_position (off);
- }
-
- /* Redisplay the current line */
-
- static void Redisplay_Line ()
- {
- char *control = "^x";
- char *cp = l_buffer;
- int off = s_cursor;
-
- /* Reposition to start of line */
-
- set_cursor_position (s_cursor);
-
- /* Output the line */
-
- while (cp != end_buffer)
- {
- if (*cp == '\t')
- {
- do
- {
- v1_putc (SP);
- } while ((++off) % 8);
- }
-
- else if (iscntrl (*cp))
- {
- control[1] = *cp + '@';
- v1_puts (control);
- off += 2;
- }
-
- else
- {
- ++off;
- v1_putc (*cp);
- }
-
- ++cp;
- }
-
- if ((m_line = ((s_cursor + Max_Length) / Max_Cols) + 1) >= Max_Lines)
- m_line = Max_Lines - 1;
-
- erase_to_end_of_line (); /* clear to end of line */
- Max_Length = end_buffer - l_buffer;
- }
-
- /* Process history command
- *
- * -1: Previous command
- * 1: Next command
- * 0: Current command
- * 2: Current command with no options processing
- */
-
- static bool Process_History (direction)
- int direction;
- {
- char *optionals = null;
-
- c_buffer_pos = l_buffer;
- end_buffer = l_buffer;
- c_history += (direction == 2) ? 0 : direction;
-
- switch (direction)
- {
- case -1: /* Move up one line */
- if (c_history < 0)
- {
- c_history = -1;
- return Re_start (No_prehistory);
- }
-
- break;
-
- case 1: /* Move to next history line */
- if (c_history >= l_history)
- {
- c_history = l_history;
- return Re_start (No_posthistory);
- }
-
- break;
-
- case 0: /* Check out l_buffer */
- optionals = l_buffer; /* Are there any additions to */
- /* the history line */
-
- /* Find the end of the first part */
-
- while (!isspace (*optionals) && *optionals)
- {
- if (*optionals == '!')
- {
-
- /* Terminate at !! */
-
- if (*(optionals + 1) == '!')
- {
- optionals += 2;
- break;
- }
-
- /* Terminate at a numeric value */
-
- else if (isdigit (*(optionals + 1)) ||
- (*(optionals + 1) == '-'))
- {
- optionals += 2;
- while (isdigit (*optionals))
- ++optionals;
-
- break;
- }
- }
-
- ++optionals;
- }
-
- /* Copy selected item into line buffer */
-
- case 2:
- M_length = (optionals == null) ? strlen (l_buffer) - 1
- : optionals - l_buffer - 1;
-
- if (!Scan_History ())
- return FALSE;
-
- break;
- }
-
- return UpDate_CLine (optionals);
- }
-
- /* Ok c_history points to the new line. Move optionals after history
- * and the copy in history and add a space
- */
-
- static bool UpDate_CLine (optionals)
- char *optionals;
- {
- int opt_len;
-
- end_buffer = &l_buffer[strlen (cmd_history[c_history].command)];
-
- if ((end_buffer - l_buffer + (opt_len = strlen (optionals)) + 1) >= LINE_MAX)
- return Re_start (History_2long);
-
- if (end_buffer > optionals)
- memrcpy (end_buffer + opt_len, optionals + opt_len, opt_len + 1);
-
- else
- strcpy (end_buffer, optionals);
-
- strncpy (l_buffer, cmd_history[c_history].command, (end_buffer - l_buffer));
- end_buffer = &l_buffer[strlen (l_buffer)];
- c_buffer_pos = end_buffer;
- return TRUE;
- }
-
- /* Scan the line buffer for a history match */
-
- static bool Scan_History ()
- {
- char *cp = l_buffer + 1;
- char *ep;
- int i = (int)strtol (cp, &ep, 10);
-
- /* Get the previous command ? (single ! or double !!) */
-
- if ((M_length == 0) || (*cp == '!'))
- {
- if (c_history >= l_history)
- c_history = l_history - 1;
-
- if (c_history < 0)
- return Re_start (No_prehistory);
-
- return TRUE;
- }
-
- /* Request for special history number item. Check History file empty */
-
- if (l_history == 0)
- return Re_start (No_MatchHistory);
-
- /* Check for number */
-
- if ((*l_buffer == '!') && (ep > cp) && M_length)
- {
- M_length = -1;
-
- for (c_history = l_history - 1;
- (cmd_history[c_history].number != i) && (c_history >= 0);
- --c_history);
- }
-
- /* No - scan for a match */
-
- else
- {
- for (c_history = l_history - 1;
- (strncmp (cp, cmd_history[c_history].command, M_length) != 0)
- && (c_history >= 0);
- --c_history);
- }
-
- /* Anything found ? */
-
- if (c_history == -1)
- {
- c_history = l_history - 1;
- return Re_start (No_MatchHistory);
- }
-
- return TRUE;
- }
-
- /* Scan back or forward from current history */
-
- static void Page_History (direction)
- int direction;
- {
- c_buffer_pos = l_buffer;
- end_buffer = l_buffer;
-
- if (l_history == 0)
- {
- Re_start (No_MatchHistory);
- return;
- }
-
- /* scan for a match */
-
- while (((c_history += direction) >= 0) && (c_history != l_history) &&
- (strncmp (l_buffer, cmd_history[c_history].command, M_length) != 0));
-
- /* Anything found ? */
-
- if ((c_history < 0) || (c_history >= l_history))
- {
- c_history = l_history - 1;
- Re_start (No_MatchHistory);
- }
-
- else
- UpDate_CLine (null);
- }
-
- /* Load history file */
-
- void Load_History ()
- {
- FILE *fp;
- char *cp;
- int i = 0;
- Var_List *lset;
-
- /* Initialise history array */
-
- memset (cmd_history, 0, sizeof (struct cmd_history) * HISTORY_MAX);
- c_history = -1; /* Current entry */
- l_history = 0; /* End of history array */
-
- if ((lset = lookup (history_file, TRUE))->value == null)
- {
- setval (lset, (cp = Build_H_Filename ("history.sh")));
- DELETE (cp);
- }
-
- if (!History_Enabled || ((fp = fopen (lset->value, "rt")) == (FILE *)NULL))
- return;
-
- /* Read in file */
-
- while (fgets (l_buffer, LINE_MAX, fp) != (char *)NULL)
- {
- ++i;
-
- if ((cp = strchr (l_buffer, NL)) == (char *)NULL)
- print_warn (H_TooLongI, i);
-
- else
- {
- *cp = 0;
- Add_History (TRUE);
- }
- }
-
- fclose (fp);
- }
-
- /* Add entry to history file */
-
- void Add_History (past)
- bool past; /* Past history? */
- {
- int i;
-
- if ((!History_Enabled) || (strlen (l_buffer) == 0))
- return;
-
- /* If adding past history, decrement all numbers previous */
-
- if ((past) && l_history)
- {
- for (i = 0; i < l_history; i++)
- --(cmd_history[i].number);
- }
-
- /* If the array is full, remove the last item */
-
- if (l_history == HISTORY_MAX)
- {
- if (cmd_history[0].command != null)
- DELETE (cmd_history[0].command);
-
- --l_history;
- memcpy (&cmd_history[0], &cmd_history[1],
- sizeof (struct cmd_history) * (HISTORY_MAX - 1));
- }
-
- /* If there are any items in the array */
-
- c_history = l_history;
- Current_Event = (l_history) ? cmd_history[l_history - 1].number + 1 : 0;
- cmd_history[l_history].number = Current_Event;
-
- /* Save the string */
-
- cmd_history[l_history++].command = strsave (l_buffer, 0);
- }
-
- /* Print history */
-
- void Display_History ()
- {
- int i;
- struct cmd_history *cp = cmd_history;
-
- if (!l_history)
- return;
-
- for (i = 0; i < l_history; ++cp, ++i)
- {
- v1printf ("%5d: ", cp->number);
- v1a_puts (cp->command);
- }
- }
-
- /* Dump history to file */
-
- void Dump_History ()
- {
- int i;
- struct cmd_history *cp = cmd_history;
- FILE *fp;
-
- if (!History_Enabled ||
- ((fp = fopen (lookup (history_file, FALSE)->value, "wt")) ==
- (FILE *)NULL))
- return;
-
- for (i = 0; i < l_history; ++cp, ++i)
- {
- fputs (cp->command, fp);
- fputc (NL, fp);
- }
-
- fclose (fp);
- }
-
- /* Clear out history */
-
- void Clear_History ()
- {
- int i;
- struct cmd_history *cp = cmd_history;
-
- for (i = 0; i < l_history; ++cp, ++i)
- {
- if (cp->command != null)
- DELETE (cp->command);
- }
-
- memset (cmd_history, 0, sizeof (struct cmd_history) * HISTORY_MAX);
-
- c_history = -1; /* Current entry */
- l_history = 0; /* End of history array */
- Current_Event = 0;
- }
-
- /* Output warning message and prompt */
-
- static bool Re_start (cp)
- char *cp;
- {
- if (cp != (char *)NULL)
- {
- if (strlen (l_buffer) && (s_cursor != -1))
- S_putc (NL);
-
- print_warn (cp);
- erase_to_end_of_line ();
- v1_putc (NL);
- }
-
- put_prompt (last_prompt);
-
- /* Re-initialise */
-
- Init_Input (insert_mode);
- return FALSE;
- }
-
- /* Copy backwards */
-
- static void memrcpy (sp1, sp, cnt)
- char *sp1;
- char *sp;
- int cnt;
- {
- while (cnt--)
- *(sp1--) = *(sp--);
- }
-
- /* Complete file name */
-
- static bool Complete_file (fn_start, fn_search)
- char *fn_start;
- bool fn_search;
- {
- char *fn_end, *cp, *fn_mstart, fn_es, *fn_dir;
- int fn_len, pre_len, i;
- DIR *dn;
- char d_name [NAME_MAX + 1];
- struct dirent *d_ce;
- int found_cnt = 0;
- int max_per_line;
- static char *ms_drive = "a:/";
-
- while (!isspace (*fn_start) && (fn_start != l_buffer))
- --fn_start;
-
- if (isspace (*fn_start))
- ++fn_start;
-
- fn_end = fn_start;
-
- while (!isspace (*fn_end) && (fn_end != end_buffer))
- ++fn_end;
-
- /* Get the directory name */
-
- if (fn_end != end_buffer)
- {
- fn_es = *fn_end;
- *fn_end = 0;
- }
-
- /* Find the directory name */
-
- if ((cp = strrchr (fn_start, '/')) != (char *)NULL)
- {
- fn_mstart = cp + 1;
- fn_dir = fn_start;
- }
-
- /* No directory flag - Drive specifier? */
-
- else if (*(fn_start + 1) == ':')
- {
- *(fn_dir = ms_drive) = *fn_start;
- *(fn_dir + 2) = '.';
- fn_mstart = fn_start + 2;
- }
-
- /* No drive specifier */
-
- else
- {
- fn_dir = ".";
- fn_mstart = fn_start;
- }
-
- /* Set up some values - length and end */
-
- fn_len = fn_end - fn_mstart;
-
- if (fn_end != end_buffer)
- *fn_end = fn_es;
-
- /* Get the match length which must be nonzero unless we are doing a display
- * of the directory
- */
-
- if (!fn_len && !fn_search)
- {
- v1_putc (0x07);
- return FALSE;
- }
-
- /* Reset the / to a zero to terminate the directory name */
-
- if (cp != (char *)NULL)
- *cp = 0;
-
- /* Check for some special cases - root */
-
- if ((i = strlen (fn_dir)) == 0)
- fn_dir = "/";
-
- else if ((i == 2) && (*(fn_dir + 1) == ':'))
- {
- *(fn_dir = ms_drive) = *fn_start;
- *(fn_dir + 2) = '/';
- }
-
- /* Get the prefix length and open the directory */
-
- pre_len = fn_mstart - l_buffer;
- dn = opendir (fn_dir);
-
- if (cp != (char *)NULL)
- *cp = '/';
-
- if (dn == (DIR *)NULL)
- {
- v1_putc (0x07);
- return FALSE;
- }
-
- /* Initialise the save buffer for a search or a match. In the case of a
- * search, we alway want to output NAME_MAX characters. In the case of a
- * match we want to know if we found it.
- */
-
- d_name[NAME_MAX] = 0;
- *d_name = 0;
- max_per_line = (Max_Cols / (((NAME_MAX / 8) + 1) * 8));
-
- /* Scan the directory */
-
- while ((d_ce = readdir (dn)) != (struct dirent *)NULL)
- {
- if (strnicmp (d_ce->d_name, fn_mstart, fn_len) == 0)
- {
-
- /* Are we displaying the directory or just searching */
-
- if (fn_search)
- {
- v1_putc ((char)((found_cnt % max_per_line == 0) ? NL : '\t'));
- memset (d_name, ' ', NAME_MAX);
- memcpy (d_name, d_ce->d_name, strlen (d_ce->d_name));
- v1_puts (d_name);
- }
-
- /* Just search - check for first entry match */
-
- else if (!*d_name)
- strcpy (d_name, d_ce->d_name);
-
- else
- {
- for (i = fn_len; d_name[i] == d_ce->d_name[i] ; i++);
- d_name[i] = 0;
- }
-
- /* Increment counter */
-
- ++found_cnt;
- }
- }
-
- closedir (dn);
-
- /* If we are searching and we found something - redraw */
-
- if (fn_search && found_cnt)
- {
- v1_putc (NL);
- put_prompt (last_prompt);
- read_cursor_position ();
- return TRUE;
- }
-
- /* Did I find anything? - no exit */
-
- if (!*d_name)
- {
- v1_putc (0x07);
- return FALSE;
- }
-
- /* Check that the line is not too long and if there is an end bit, we can
- * save a copy of it.
- */
-
- cp = null;
- fn_len = strlen (fn_end);
-
- if (((fn_len + strlen (d_name) + pre_len) >= LINE_MAX) ||
- ((fn_len != 0) && ((cp = strdup (fn_end)) == (char *)NULL)))
- {
- v1_putc (0x07);
- return FALSE;
- }
-
- /* Append the new end of line bits */
-
- strcpy (fn_mstart, d_name);
- strcat (fn_mstart, cp);
-
- if (cp != null)
- free (cp);
-
- end_buffer = &l_buffer[strlen (l_buffer)];
- c_buffer_pos = end_buffer;
-
- /* Beep if more than one */
-
- if (found_cnt > 1)
- v1_putc (0x07);
-
- return TRUE;
- }
-
- /* Initialise input */
-
- static void Init_Input (im)
- bool im;
- {
- c_buffer_pos = l_buffer; /* Initialise */
- end_buffer = l_buffer;
- insert_mode = im;
- M_length = -1;
-
- /* Reset max line length and get the number of columns */
-
- Max_Length = 0;
- Get_Screen_Params ();
-
- /* Save the cursor position */
-
- read_cursor_position ();
- }
-
- /* Configure Keyboard I/O */
-
- void Configure_Keys ()
- {
- char *sp; /* Line pointers */
- char *cp;
- FILE *fp;
- char *line; /* Input line */
- char c; /* Save character */
- int i, fval, cval;
- int line_len;
-
- /* Get some memory for the input line and the file name */
-
- line_len = max (strlen (Program_Name) + 4, 200);
- if ((line = getcell (line_len)) == (char *)NULL)
- return;
-
- strcpy (line, Program_Name);
-
- /* Find the .exe in the name */
-
- if ((cp = strrchr (line, '/')) != (char *)NULL)
- ++cp;
-
- else
- cp = line;
-
- if ((cp = strrchr (cp, '.')) == (char *)NULL)
- cp = &line[strlen (line)];
-
- strcpy (cp, ".ini");
-
- if ((fp = fopen (line, "rt")) == (FILE *)NULL)
- {
- DELETE (line);
- return;
- }
-
- while (fgets (line, line_len - 1, fp) != (char *)NULL)
- {
-
- /* Ignore comment lines */
-
- if (*line == '#')
- continue;
-
- /* Remove the EOL */
-
- if ((cp = strchr (line, '\n')) != (char *)NULL)
- *cp = 0;
-
- /* Find the keyword */
-
- cp = line;
- while (!isspace (*cp) && *cp && (*cp != '='))
- ++cp;
-
- if (!*cp)
- continue;
-
- c = *cp;
- *cp = 0;
-
- /* Look up the keyword name */
-
- for (i = 0; (i < KF_LENGTH) &&
- (stricmp (line, KF_List[i].kf_name) != 0); ++i);
-
- /* Ignore no matches */
-
- if (i == KF_LENGTH)
- continue;
-
- /* Find the equals */
-
- *cp = c;
- while (isspace (*cp))
- ++cp;
-
- if (*(cp++) != '=')
- continue;
-
- while (isspace (*cp))
- ++cp;
-
- /* Get the value */
-
- errno = 0;
- cval = 0;
-
- fval = (int)strtol (cp, &sp, 0);
-
- /* Check for correct terminator */
-
- if (errno || (fval < 0) ||
- ((fval != 0) && *sp) ||
- ((fval == 0) &&
- (((i < KF_END_FKEYS) && !isspace (*sp)) ||
- ((i >= KF_END_FKEYS) && *sp))))
- continue;
-
- if ((fval == 0) && (i < KF_END_FKEYS))
- {
- cp = sp;
- while (isspace (*cp))
- ++cp;
-
- errno = 0;
- cval = (int)strtol (cp, &sp, 0);
-
- if (errno || (cval == 0) || *sp)
- continue;
- }
-
- /* OK we have a valid value, save it */
-
- KF_List[i].akey = (char)fval;
- KF_List[i].fkey = (char)cval;
- }
-
- DELETE (line);
- fclose (fp);
- }
- #endif
-
- /* Check cursor is in column zero */
-
- void In_Col_Zero ()
- {
- union REGS r;
-
- Get_Screen_Params ();
- read_cursor_position ();
-
- r.h.ah = 0x08;
- r.h.bh = 0x00;
- int86 (0x10, &r, &r);
-
- if ((s_cursor % Max_Cols) || (r.h.al != ' '))
- v1_putc (NL);
- }
-
- /* Get screen parameters */
-
- static void Get_Screen_Params ()
- {
- union REGS r;
-
- Max_Cols = *(int *)(0x0040004aL);
- Max_Lines = 25;
-
- /* Is this an EGA? This test was found in NANSI.SYS */
-
- r.h.ah = 0x12;
- r.x.bx = 0xff10;
- int86 (0x10, &r, &r);
-
- if (r.x.bx & 0xfefc)
- return;
-
- /* Else read the number of rows */
-
- r.x.ax = 0x1130;
- r.h.bh = 0;
- int86 (0x10, &r, &r);
- Max_Lines = r.h.dl + 1;
- }
-
- /* Ring Bell ? */
-
- bool Ring_Bell ()
- {
- #ifdef NO_HISTORY
- return TRUE;
- #else
- return (bool)(KF_List[KF_RINGBELL].akey ? TRUE : FALSE);
- #endif
- }
-