Blame | Last modification | View Log | RSS feed
/** MS-DOS SHELL - History Processing** MS-DOS SHELL - Copyright (c) 1990,4 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: /cvsroot/device/DEVL/UTILS/SH/Sh9.c,v 1.1 2002/08/02 06:49:35 adamy Exp $** $Log: Sh9.c,v $* Revision 1.1 2002/08/02 06:49:35 adamy* imported (reference only)** Revision 1.1 2001/07/20 05:55:45 ayoung* WIN32 support** Revision 1.1.1.1 1999/12/02 01:11:12 gordonh* UTIL** Revision 2.18 1994/08/25 20:49:11 istewart* MS Shell 2.3 Release** Revision 2.17 1994/02/23 09:23:38 istewart* Beta 233 updates** Revision 2.16 1994/02/01 10:25:20 istewart* Release 2.3 Beta 2, including first NT port** Revision 2.15 1994/01/20 14:51:43 istewart* Release 2.3 Beta 1** Revision 2.14 1994/01/11 17:55:25 istewart* Release 2.3 Beta 0 patches** Revision 2.13 1993/11/09 10:39:49 istewart* Beta 226 checking** Revision 2.12 1993/08/25 16:03:57 istewart* Beta 225 - see Notes file** Revision 2.11 1993/07/02 10:21:35 istewart* 224 Beta fixes** Revision 2.10 1993/06/16 13:50:00 istewart* Fix defaults for Key initialisation** Revision 2.9 1993/06/14 11:00:12 istewart* More changes for 223 beta** Revision 2.8 1993/06/02 09:52:35 istewart* Beta 223 Updates - see Notes file** Revision 2.7 1993/02/16 16:03:15 istewart* Beta 2.22 Release** Revision 2.6 1993/01/26 18:35:09 istewart* Release 2.2 beta 0** Revision 2.5 1992/12/14 10:54:56 istewart* BETA 215 Fixes and 2.1 Release** Revision 2.4 1992/11/06 10:03:44 istewart* 214 Beta test updates** Revision 2.3 1992/09/03 18:54:45 istewart* Beta 213 Updates** Revision 2.2 1992/07/16 14:33:34 istewart* Beta 212 Baseline** Revision 2.1 1992/07/10 10:52:48 istewart* 211 Beta updates** Revision 2.0 1992/05/07 21:33:35 Ian_Stewartson* MS-Shell 2.0 Baseline release**/#include <sys/types.h>#include <sys/stat.h>#include <stdio.h>#include <string.h>#include <ctype.h>#include <signal.h>#include <stdlib.h>#include <stddef.h>#include <errno.h>#include <setjmp.h>#include <limits.h>#include <unistd.h>#include <dirent.h>#include "sh.h"#if (OS_TYPE == OS_UNIX)# include <termios.h>#endif#if (OS_TYPE == OS_DOS)# ifndef _NKEYBRD_READ# define _NKEYBRD_READ 0x10 /* read next char from kbd */# define _NKEYBRD_READY 0x11 /* check for keystroke */# define _NKEYBRD_SHIFTSTATUS 0x12 /* get shift key status */# endif# ifndef _KEYBRD_READ# define _KEYBRD_READ 0x00 /* read next char from kbd */# define _KEYBRD_READY 0x01 /* check for keystroke */# define _KEYBRD_SHIFTSTATUS 0x02 /* get shift key status */# endif# if defined (__TURBOC__)# define _bios_keybrd(a) bioskey (a)# elif defined (__EMX__)unsigned int _bios_keybrd (unsigned int);# endif#endif/* Keyboard functions */#define KF_LENGTH ARRAY_SIZE (KF_List)/** Saved command line structure*/struct cmd_history {int number;char *command;};/* Function Declarations */static bool F_LOCAL ProcessAlphaNumericKey (int);static bool F_LOCAL ProcessFunctionKey (int);static bool F_LOCAL Process_History (int);static bool F_LOCAL ScanHistory (void);static void F_LOCAL ReDisplayInputLine (void);static void F_LOCAL PageHistoryRecord (int);static bool F_LOCAL UpdateConsoleInputLine (char *);static bool F_LOCAL ReStartInput (char *);static void F_LOCAL GenerateNewCursorPosition (void);static void F_LOCAL EraseToEndOfLine (void);static bool F_LOCAL CompleteFileName (char *, bool);static void F_LOCAL InitialiseInput (bool);static void F_LOCAL PrintOutHistory (FILE *, bool, struct cmd_history *);static void F_LOCAL ReleaseCommandMemory (struct cmd_history *);static void F_LOCAL SaveCurrentHistory (void);static void F_LOCAL memrcpy (char *, const char *, int);static FILE * F_LOCAL OpenHistoryFile (const char *);static void F_LOCAL GetLineFromConsole (void);#ifdef KEYDEBUGstatic void DisplayKeyCode (unsigned int, unsigned int);#else# define DisplayKeyCode(a,b)#endif#if (OS_TYPE != OS_DOS)static void F_LOCAL ChangeKeyboardMode (bool);#else# define ChangeKeyboardMode(a)#endif#if (OS_TYPE == OS_NT)static bool F_LOCAL DoNTKeyMap (KEY_EVENT_RECORD *);#endif#if (OS_TYPE == OS_DOS) && (OS_SIZE == OS_16)static bool DESQviewActive = FALSE;/* Poll keyboard */#endifstatic bool F_LOCAL InsertACharacter (int);static int F_LOCAL OutputACharacter (int);static int F_LOCAL GetLineFromDevice (void);#if (OS_TYPE == OS_DOS)static void F_LOCAL CheckKeyboardPolling (void);/* Read keyboard parameter */static unsigned int ReadKeyboardOption = _KEYBRD_READ;#else# define CheckKeyboardPolling()#endifstatic bool InsertMode = FALSE;static char *c_buffer_pos; /* Position in command line */static char *EndOfCurrentLine; /* 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 MaxLength = 0; /* Max line length */static int OldMaxLength = 0; /* Previous Max line length */static int CurrentHistorySize = 0; /* Current Length of History *//* Array */static bool AppendHistory = FALSE; /* Append to history */static bool SaveHistory = FALSE; /* Save history */static char *No_prehistory = "No previous commands";static char *No_MatchHistory = "No history match found";static char *No_posthistory = "No more commands";static char *History_2long = "History line too long";#if (OS_TYPE == OS_NT)static HANDLE NT_StdIn; /* Standard Input handler */static HANDLE NT_StdOut; /* Standard Ouput handler */#define CTRL_PRESSED ((LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))#define ALT_PRESSED ((LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))/* Scan codes to ignore on input */static WORD IgnoreScanCode[] = {0x1d, /* Control key */0x38, /* Alt key */0x2a, /* Shift key */0x36, /* Shift key */0x3a, /* Caps key */0x45 /* Numlock key */};#define IGNORE_CNT ARRAY_SIZE (IgnoreScanCode)/* Mapping table because we don't get converted scan codes */struct NT_KFMap {unsigned char Normal; /* Normal scancode */unsigned char Shift; /* shift scancode */unsigned char Control; /* Control scancode */unsigned char Alt; /* Alt scancode */} NT_KFMap [] = {/* Key Normal Shift- Control- Alt- */{ /* F1 */ 0x3b, 0x54, 0x5E, 0x68 },{ /* F2 */ 0x3c, 0x55, 0x5F, 0x69 },{ /* F3 */ 0x3d, 0x56, 0x60, 0x6A },{ /* F4 */ 0x3e, 0x57, 0x61, 0x6B },{ /* F5 */ 0x3f, 0x58, 0x62, 0x6C },{ /* F6 */ 0x40, 0x59, 0x63, 0x6D },{ /* F7 */ 0x41, 0x5A, 0x64, 0x6E },{ /* F8 */ 0x42, 0x5B, 0x65, 0x6F },{ /* F9 */ 0x43, 0x5C, 0x66, 0x70 },{ /* F10 */ 0x44, 0x5D, 0x67, 0x71 },{ /* F11 */ 0x85, 0x87, 0x89, 0x8b },{ /* F12 */ 0x86, 0x88, 0x8a, 0x8c },{ /* INSERT */ 0x52, 0x52, 0x00, 0x00 },{ /* HOME */ 0x47, 0x47, 0x77, 0x00 },{ /* PAGE UP */ 0x49, 0x49, 0x84, 0x00 },{ /* DELETE */ 0x53, 0x53, 0x00, 0x00 },{ /* END */ 0x4f, 0x4f, 0x75, 0x00 },{ /* PAGE DOWN */ 0x51, 0x51, 0x76, 0x00 },{ /* UP ARROW */ 0x48, 0x48, 0x00, 0x00 },{ /* LEFT ARROW */ 0x4b, 0x4b, 0x73, 0x00 },{ /* DOWN ARROW */ 0x50, 0x50, 0x00, 0x00 },{ /* RIGHT ARROW */ 0x4d, 0x4d, 0x74, 0x00 },};#define MAX_NT_FKMAP ARRAY_SIZE (NT_KFMap)#endif/* Function Key table */static struct Key_Fun_List {char *kf_name;unsigned char akey;unsigned char fkey;unsigned 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", 0x0ff, 'v', KF_CLEAR },{ "Flush", 0, 'u', KF_FLUSH },{ "End", 0, 'O', KF_END },{ "Insert", 0, 'R', KF_INSERT },{ "DeleteRight", 0, 'S', KF_DELETERIGHT },{ "DeleteLeft", CHAR_BACKSPACE, 0, KF_DELETELEFT },{ "Complete", 0, 'w', KF_COMPLETE },{ "Directory", 0, 0x0f, KF_DIRECTORY },{ "ClearScreen", 0, 0x84, KF_CLEARSCREEN },{ "Jobs", 0, 0x68, KF_JOBS },{ "Transpose", 0x14, 0, KF_TRANSPOSE },{ "Quote", 0x11, 0, KF_QUOTE },/* End of function keys - flags */{ "Bell", 1, 0, KF_RINGBELL },{ "HalfHeight", 0, 0, KF_HALFHEIGTH },{ "InsertMode", 0, 0, KF_INSERTMODE },{ "InsertCursor", 1, 0, KF_INSERTCURSOR },{ "RootDrive", 0, 0, KF_ROOTDRIVE },{ "EOFKey", 4, 0, KF_EOFKEY },};/* Arrary of history Items */static struct cmd_history *cmd_history = (struct cmd_history *)NULL;/** Processing standard input. Editting is only supported on OS/2 at the* moment.*/int GetConsoleInput (void){bool console = C2bool (IS_Console (0));int RetVal = 0;/* Has dofc set the flag to say use the console buffer ? */if (UseConsoleBuffer){UseConsoleBuffer = FALSE;SaveHistory = TRUE;SaveCurrentHistory ();SaveHistory = FALSE;}/** Read in a line from the console*/else{/* Set to last history item */if (FL_TEST (FLAG_INTERACTIVE) || (IS_TTY (0) && IS_TTY (1)))SaveCurrentHistory ();/* Zap the line and output the prompt. Save history status info */memset (ConsoleLineBuffer, 0, LINE_MAX + 1);if (FL_TEST (FLAG_INTERACTIVE) || (IS_TTY (0) && IS_TTY (1))){bool o_SaveHistory = SaveHistory;OutputUserPrompt (LastUserPrompt);SaveHistory = o_SaveHistory;}/* Only if we are working on the console and not via a pipe or file do we* need to set up the console*/if (console){CheckKeyboardPolling ();if (ChangeInitLoad){ChangeInitLoad = FALSE;Configure_Keys ();}GetScreenParameters ();}/** Process the input. If this is not the console, read from standard input*/if (!console)RetVal = GetLineFromDevice ();else{ChangeKeyboardMode (FALSE);#if defined (FLAGS_VI) || defined (FLAGS_EMACS) || defined (FLAGS_GMACS)if (ShellGlobalFlags & FLAGS_EDITORS)RetVal = EditorInput ();else#endifGetLineFromConsole ();ChangeKeyboardMode (TRUE);}if (LastUserPrompt == PS1)LastUserPrompt = PS2;/* Clean up */FlushStreams ();if (console)SetCursorShape (FALSE);}/* Return any errors */if (RetVal < 0)return 0;/* If we are reading from the console, check for end of file. From file or* pipe, we detect this differently*/if (console){if (*ConsoleLineBuffer == (char)KF_List[KF_EOFKEY].akey)*ConsoleLineBuffer = 0;elsestrcat (ConsoleLineBuffer, LIT_NewLine);}return strlen (ConsoleLineBuffer);}/** Read a line from a file or pipe - well pipe really.*/static int F_LOCAL GetLineFromDevice (void){while (fgets (ConsoleLineBuffer, LINE_MAX, stdin) != (char *)NULL){if (*ConsoleLineBuffer != CHAR_HISTORY)return 0;else if (Process_History (0)){puts (ConsoleLineBuffer);return 0;}}/* EOF detected - return that fact */return -1;}/** Read line from Console*/static void F_LOCAL GetLineFromConsole (void){unsigned char a_key = 0, f_key;int i;/* Process the input */for ( ; ; ){InitialiseInput ((bool)KF_List[KF_INSERTMODE].akey);while (((a_key = ReadKeyBoard (&f_key)) != KF_List[KF_EOFKEY].akey) &&(a_key != CHAR_NEW_LINE) && (a_key != CHAR_RETURN)){/* Handle Resize event */if (a_key == KT_RESIZE){fputchar (CHAR_NEW_LINE);GetScreenParameters ();OutputUserPrompt (LastUserPrompt);ReDisplayInputLine ();continue;}/* Look up the keystroke to see if it is one of our functions */i = LookUpKeyBoardFunction (a_key, f_key);if ( !i )continue;if (((i > 0) ? ProcessAlphaNumericKey (i): ProcessFunctionKey ((-i) - 1)))ReDisplayInputLine ();/* Handle a special case on insert mode on line 25 */if ((InsertMode) && (MaxLength > OldMaxLength) &&(((StartCursorPosition + MaxLength) / MaximumColumns)== MaximumLines) &&(((StartCursorPosition + MaxLength) % MaximumColumns) == 0))StartCursorPosition -= MaximumColumns;/* Reposition the cursor */GenerateNewCursorPosition ();/* Save old line length */OldMaxLength = MaxLength;}/* Terminate the line */*(c_buffer_pos = EndOfCurrentLine) = 0;GenerateNewCursorPosition ();fputchar (CHAR_NEW_LINE);StartCursorPosition = -1;FlushStreams ();/* Line input - check for history */if ((*ConsoleLineBuffer == CHAR_HISTORY) && Process_History (0)){puts (ConsoleLineBuffer);break;}else if (*ConsoleLineBuffer != CHAR_HISTORY)break;}if (a_key == KF_List[KF_EOFKEY].akey)*EndOfCurrentLine = KF_List[KF_EOFKEY].akey;}/** Handler Alpha_numeric characters*/static bool F_LOCAL ProcessAlphaNumericKey (int c){bool redisplay = FALSE;/* Normal character processing */if ((c_buffer_pos - ConsoleLineBuffer) == LINE_MAX)return RingWarningBell ();else if (!InsertMode){if (c_buffer_pos == EndOfCurrentLine)++EndOfCurrentLine;else if (iscntrl (*c_buffer_pos) || iscntrl (c))redisplay = TRUE;*(c_buffer_pos++) = (char)c;if (redisplay || (c == CHAR_TAB))return TRUE;/* Output the character */OutputACharacter (c);return FALSE;}elsereturn InsertACharacter (c);}/* Process function keys */static bool F_LOCAL ProcessFunctionKey (int fn){bool fn_search = FALSE;char tmp;switch (fn){case KF_SCANBACKWARD: /* Scan backwards in history */case KF_SCANFOREWARD: /* Scan forewards in history */*EndOfCurrentLine = 0;if (M_length == -1)M_length = strlen (ConsoleLineBuffer);PageHistoryRecord ((fn == KF_SCANBACKWARD) ? -1 : 1);return TRUE;case KF_PREVIOUS: /* Previous command */*EndOfCurrentLine = 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 != ConsoleLineBuffer)--c_buffer_pos;elseRingWarningBell ();return FALSE;case KF_RIGHT: /* Cursor right */if (c_buffer_pos != EndOfCurrentLine)++c_buffer_pos;elseRingWarningBell ();return FALSE;case KF_WORDLEFT: /* Cursor left a word */if (c_buffer_pos != ConsoleLineBuffer){--c_buffer_pos; /* Reposition on previous char */while (isspace (*c_buffer_pos) &&(c_buffer_pos != ConsoleLineBuffer))--c_buffer_pos;while (!isspace (*c_buffer_pos) &&(c_buffer_pos != ConsoleLineBuffer))--c_buffer_pos;if (c_buffer_pos != ConsoleLineBuffer)++c_buffer_pos;}elseRingWarningBell ();return FALSE;case KF_WORDRIGHT: /* Cursor right a word */if (c_buffer_pos != EndOfCurrentLine){/* Skip to the end of the current word */while (!isspace (*c_buffer_pos) &&(c_buffer_pos != EndOfCurrentLine))++c_buffer_pos;/* Skip over the white space */while (isspace (*c_buffer_pos) &&(c_buffer_pos != EndOfCurrentLine))++c_buffer_pos;}elseRingWarningBell ();return FALSE;case KF_START: /* Cursor home */c_buffer_pos = ConsoleLineBuffer;return FALSE;case KF_CLEAR: /* Erase buffer */c_buffer_pos = ConsoleLineBuffer;case KF_FLUSH: /* Flush to end */memset (c_buffer_pos, CHAR_SPACE, EndOfCurrentLine - c_buffer_pos);EndOfCurrentLine = c_buffer_pos;return TRUE;case KF_END: /* Cursor end of command */if (*ConsoleLineBuffer == CHAR_HISTORY){*EndOfCurrentLine = 0;Process_History (2);return TRUE;}c_buffer_pos = EndOfCurrentLine;return FALSE;case KF_INSERT: /* Switch insert mode */InsertMode = C2bool (!InsertMode);SetCursorShape (InsertMode);return FALSE;case KF_CLEARSCREEN: /* Clear the screen */return ClearScreen ();case KF_TRANSPOSE: /* Transpose characters */if(c_buffer_pos == ConsoleLineBuffer)return RingWarningBell ();if (c_buffer_pos == EndOfCurrentLine)--c_buffer_pos;tmp = *(c_buffer_pos - 1);*(c_buffer_pos - 1) = *c_buffer_pos;*c_buffer_pos = tmp;if (c_buffer_pos != EndOfCurrentLine)++c_buffer_pos;return TRUE;case KF_QUOTE: /* Quote characters */return ProcessAlphaNumericKey ((int)ReadKeyBoard ((unsigned char *)&tmp));#if (OS_TYPE != OS_DOS)case KF_JOBS: /* Print Job Tree */fputchar (CHAR_NEW_LINE);# if (OS_TYPE == OS_NT)PrintJobs (TRUE);# elsePrintProcessTree (getpid ());# endifOutputUserPrompt (LastUserPrompt);StartCursorPosition = ReadCursorPosition ();return TRUE;#endifcase KF_DELETERIGHT: /* Delete right character */if (c_buffer_pos == EndOfCurrentLine)return FALSE;memcpy (c_buffer_pos, c_buffer_pos + 1,EndOfCurrentLine - c_buffer_pos);if (EndOfCurrentLine == ConsoleLineBuffer){RingWarningBell ();return TRUE;}if (--EndOfCurrentLine < c_buffer_pos)--c_buffer_pos;return TRUE;case KF_DIRECTORY: /* File name directory */fn_search = TRUE;case KF_COMPLETE: /* File name completion */{*EndOfCurrentLine = 0;return CompleteFileName (c_buffer_pos, fn_search);}case KF_DELETELEFT: /* Delete left character */if (c_buffer_pos == ConsoleLineBuffer)return RingWarningBell ();/* Decrement current position */--c_buffer_pos;memcpy (c_buffer_pos, c_buffer_pos + 1,EndOfCurrentLine - c_buffer_pos);--EndOfCurrentLine;return TRUE;}return FALSE;}/* Set cursor shape */#if (OS_TYPE == OS_OS2)void SetCursorShape (bool mode){VIOCURSORINFO viociCursor;VioGetCurType (&viociCursor, 0);if (mode && KF_List[KF_INSERTCURSOR].akey)viociCursor.yStart = (USHORT)((KF_List[KF_HALFHEIGTH].akey? (viociCursor.cEnd / 2) + 1 : 1));elseviociCursor.yStart = (USHORT)(viociCursor.cEnd - 1);VioSetCurType (&viociCursor, 0);}#endif/* NT version */#if (OS_TYPE == OS_NT)void SetCursorShape (bool mode){CONSOLE_CURSOR_INFO ConsoleCursorInfo;GetConsoleCursorInfo (NT_StdOut, &ConsoleCursorInfo);if (mode && KF_List[KF_INSERTCURSOR].akey)ConsoleCursorInfo.dwSize = (KF_List[KF_HALFHEIGTH].akey ? 50 : 90);elseConsoleCursorInfo.dwSize = 10;ConsoleCursorInfo.bVisible = TRUE;SetConsoleCursorInfo (NT_StdOut, &ConsoleCursorInfo);}#endif/* DOS version */#if (OS_TYPE == OS_DOS)void SetCursorShape (bool mode){union REGS r;/* Get the current cursor position to get the cursor lines */r.h.ah = 0x03;SystemInterrupt (0x10, &r, &r);/* Reset the type */r.h.ah = 0x01;if (mode && KF_List[KF_INSERTCURSOR].akey)r.h.ch = (unsigned char)((KF_List[KF_HALFHEIGTH].akey? (r.h.cl / 2) + 1 : 1));elser.h.ch = (unsigned char)(r.h.cl - 1);SystemInterrupt (0x10, &r, &r);}#endif/* UNIX version */#if (OS_TYPE == OS_UNIX)void SetCursorShape (bool mode){}#endif/** Read Cursor position*/#if (OS_TYPE == OS_OS2)int ReadCursorPosition (void){USHORT usRow;USHORT usColumn;VioGetCurPos (&usRow, &usColumn, 0);return (MaximumColumns * usRow) + usColumn;}#endif/* NT Version */#if (OS_TYPE == OS_NT)int ReadCursorPosition (void){CONSOLE_SCREEN_BUFFER_INFO CSI;GetConsoleScreenBufferInfo (NT_StdOut, &CSI);return (MaximumColumns * CSI.dwCursorPosition.Y) + CSI.dwCursorPosition.X;}#endif/* DOS Version */#if (OS_TYPE == OS_DOS)int ReadCursorPosition (void){union REGS r;FlushStreams ();r.h.ah = 0x03; /* Read cursor position */r.h.bh = 0; /* Page zero */SystemInterrupt (0x10, &r, &r);return (r.h.dh * MaximumColumns) + r.h.dl;}#endif/** Re-position the cursor*/#if (OS_TYPE == OS_OS2)void SetCursorPosition (int new){int diff;USHORT usRow;USHORT usColumn;FlushStreams ();usRow = (USHORT)(new / MaximumColumns);usColumn = (USHORT)(new % MaximumColumns);/* Are we at the bottom of the page? */if (usRow >= (unsigned char)MaximumLines){diff = usRow + 1 - MaximumLines;usRow = (unsigned char)(MaximumLines - 1);StartCursorPosition -= MaximumColumns * diff;}VioSetCurPos (usRow, usColumn, 0);}#endif/* NT Version */#if (OS_TYPE == OS_NT)void SetCursorPosition (int newpos){int diff;COORD Cp;FlushStreams ();Cp.Y = (USHORT)(newpos / MaximumColumns);Cp.X = (USHORT)(newpos % MaximumColumns);/* Are we at the bottom of the page? */if (Cp.Y >= (USHORT)MaximumLines){diff = Cp.Y + 1 - MaximumLines;Cp.Y = (USHORT)(MaximumLines - 1);StartCursorPosition -= MaximumColumns * diff;}SetConsoleCursorPosition (NT_StdOut, Cp);}#endif/* DOS Version */#if (OS_TYPE == OS_DOS)void SetCursorPosition (int new){int diff;union REGS r;FlushStreams ();r.h.ah = 0x02; /* Set new position */r.h.bh = 0; /* Page zero */r.h.dh = (unsigned char)(new / MaximumColumns);r.h.dl = (unsigned char)(new % MaximumColumns);/* Are we at the bottom of the page? */if (r.h.dh >= (unsigned char)MaximumLines){diff = r.h.dh + 1 - MaximumLines;r.h.dh = (unsigned char)(MaximumLines - 1);StartCursorPosition -= MaximumColumns * diff;}SystemInterrupt (0x10, &r, &r);}#endif/* Erase to end of line (avoid need for STUPID ansi.sys memory eater!) */#if (OS_TYPE == OS_OS2)static void F_LOCAL EraseToEndOfLine (void){BYTE abCell[2];USHORT usRow;USHORT usColumn;USHORT cb = sizeof (abCell);FlushStreams ();/* Read attribute under cursor */VioGetCurPos (&usRow, &usColumn, 0);VioReadCellStr (abCell, &cb , usRow, usColumn, 0);abCell[0] = CHAR_SPACE;if (m_line < (int)usRow)m_line = usRow;if ((cb = MaximumColumns - usColumn +((m_line - usRow) * MaximumColumns)) > 0)VioWrtNCell (abCell, cb, usRow, usColumn, 0);}#endif/* NT Version */#if (OS_TYPE == OS_NT)static void F_LOCAL EraseToEndOfLine (void){WORD Atts[2];CONSOLE_SCREEN_BUFFER_INFO CSI;DWORD ActionCount;DWORD cb;WORD *ostring;DWORD i;FlushStreams ();/* Read attribute under cursor */GetConsoleScreenBufferInfo (NT_StdOut, &CSI);ReadConsoleOutputAttribute (NT_StdOut, Atts, 1, CSI.dwCursorPosition,&ActionCount);/* How much to write ? */if (m_line < (int) CSI.dwCursorPosition.Y)m_line = CSI.dwCursorPosition.Y;/* Write it. What a pain!!! */if ((cb = MaximumColumns - CSI.dwCursorPosition.X +((m_line - CSI.dwCursorPosition.Y) * MaximumColumns)) > 0){ostring = (WORD *)AllocateMemoryCell (cb * sizeof (WORD));memset (ostring, CHAR_SPACE, cb);WriteConsoleOutputCharacter (NT_StdOut, (char *)ostring, cb,CSI.dwCursorPosition, &ActionCount);/* Set up attributes */for (i = 0; i < cb; i++)ostring[i] = Atts[0];WriteConsoleOutputAttribute (NT_StdOut, ostring, cb,CSI.dwCursorPosition, &ActionCount);ReleaseMemoryCell (ostring);}}#endif/* DOS Version */#if (OS_TYPE == OS_DOS)static void F_LOCAL EraseToEndOfLine (void){union REGS r;unsigned char backg;FlushStreams ();/* Get the background attribute of the cursor */r.h.ah = 0x08;r.h.bh = 0;SystemInterrupt (0x10, &r, &r);backg = (unsigned char)(r.h.ah & 0x07);r.h.ah = 0x03;r.h.bh = 0;SystemInterrupt (0x10, &r, &r);/* Check that we use the correct m_line */if (m_line < (int)r.h.dh)m_line = r.h.dh;if ((r.x.REG_CX = MaximumColumns - r.h.dl +((m_line - r.h.dh) * MaximumColumns)) > 0){r.x.REG_AX = 0x0a20;r.x.REG_BX = backg;SystemInterrupt (0x10, &r, &r);}}#endif/* DOS Version */#if (OS_TYPE == OS_UNIX)static void F_LOCAL EraseToEndOfLine (void){fputs ("UNIX: EraseToEndOfLine NI\n", stderr);}#endif/** Generate the new cursor position*/static void F_LOCAL GenerateNewCursorPosition (void){char *cp = ConsoleLineBuffer - 1;int off = StartCursorPosition;/* Search to current position */while (++cp != c_buffer_pos){if (*cp == CHAR_TAB)while ((++off) % 8);elseoff += (iscntrl (*cp)) ? 2 : 1;}/* Position the cursor */SetCursorPosition (off);}/* Redisplay the current line */static void F_LOCAL ReDisplayInputLine (void){/* Reposition to start of line */SetCursorPosition (StartCursorPosition);/* Output the line */*EndOfCurrentLine = 0;DisplayLineWithControl (ConsoleLineBuffer);if ((m_line = ((StartCursorPosition + MaxLength) / MaximumColumns) + 1) >=MaximumLines)m_line = MaximumLines - 1;EraseToEndOfLine (); /* clear to end of line */MaxLength = EndOfCurrentLine - ConsoleLineBuffer;}/* Process history command** -1: Previous command* 1: Next command* 0: Current command* 2: Current command with no options processing*/static bool F_LOCAL Process_History (int direction){char *optionals = null;c_buffer_pos = ConsoleLineBuffer;EndOfCurrentLine = ConsoleLineBuffer;c_history += (direction == 2) ? 0 : direction;switch (direction){case -1: /* Move up one line */if (c_history < 0){c_history = -1;return ReStartInput (No_prehistory);}break;case 1: /* Move to next history line */if (c_history >= l_history){c_history = l_history;return ReStartInput (No_posthistory);}break;case 0: /* Check out ConsoleLineBuffer */optionals = ConsoleLineBuffer;/* Are there any additions to *//* the history line *//* Find the end of the first part */while (!isspace (*optionals) && *optionals){if (*optionals == CHAR_HISTORY){/* Terminate at !! */if (*(optionals + 1) == CHAR_HISTORY){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 (ConsoleLineBuffer) - 1: optionals - ConsoleLineBuffer - 1;if (!ScanHistory ())return FALSE;break;}return UpdateConsoleInputLine (optionals);}/* Ok c_history points to the new line. Move optionals after history* and the copy in history and add a space*/static bool F_LOCAL UpdateConsoleInputLine (char *optionals){int opt_len;EndOfCurrentLine = &ConsoleLineBuffer[strlen (cmd_history[c_history].command)];if ((EndOfCurrentLine - ConsoleLineBuffer +(opt_len = strlen (optionals)) + 1) >= LINE_MAX)return ReStartInput (History_2long);if (EndOfCurrentLine > optionals)memrcpy (EndOfCurrentLine + opt_len, optionals + opt_len, opt_len + 1);elsestrcpy (EndOfCurrentLine, optionals);strncpy (ConsoleLineBuffer, cmd_history[c_history].command,(EndOfCurrentLine - ConsoleLineBuffer));EndOfCurrentLine = &ConsoleLineBuffer[strlen (ConsoleLineBuffer)];c_buffer_pos = EndOfCurrentLine;return TRUE;}/* Scan the line buffer for a history match */static bool F_LOCAL ScanHistory (void){char *cp = ConsoleLineBuffer + 1;char *ep;int i = (int)strtol (cp, &ep, 10);/* Get the previous command ? (single ! or double !!) */if ((M_length == 0) || (*cp == CHAR_HISTORY)){if (c_history >= l_history)c_history = l_history - 1;if (c_history < 0)return ReStartInput (No_prehistory);return TRUE;}/* Request for special history number item. Check History file empty */if (l_history == 0)return ReStartInput (No_MatchHistory);/* Check for number */if ((*ConsoleLineBuffer == CHAR_HISTORY) && (ep > cp) && M_length){M_length = -1;for (c_history = l_history - 1;(c_history >= 0) && (cmd_history[c_history].number != i);--c_history)continue;}/* No - scan for a match */else{for (c_history = l_history - 1;(c_history >= 0) &&(strncmp (cp, cmd_history[c_history].command, M_length) != 0);--c_history)continue;}/* Anything found ? */if (c_history == -1){c_history = l_history - 1;return ReStartInput (No_MatchHistory);}return TRUE;}/** Get record associated with event*/char *GetHistoryRecord (int event){int i = l_history - 1;while (i >= 0){if (cmd_history[i].number == event)return cmd_history[i].command;--i;}return (char *)NULL;}/** Scan back or forward from current history*/static void F_LOCAL PageHistoryRecord (int direction){c_buffer_pos = ConsoleLineBuffer;EndOfCurrentLine = ConsoleLineBuffer;if (l_history == 0){ReStartInput (No_MatchHistory);return;}/* scan for a match */while (((c_history += direction) >= 0) && (c_history != l_history) &&(strncmp (ConsoleLineBuffer, cmd_history[c_history].command,M_length) != 0))continue;/* Anything found ? */if ((c_history < 0) || (c_history >= l_history)){c_history = l_history - 1;ReStartInput (No_MatchHistory);}elseUpdateConsoleInputLine (null);}/* Load history file */void LoadHistory (void){FILE *fp;char *cp;int i = 0;bool Append = FALSE;/* Initialise history array */c_history = -1; /* Current entry */l_history = 0; /* End of history array */if (GetVariableAsString (HistoryFileVariable, FALSE) == null){SetVariableFromString (HistoryFileVariable,(cp = BuildFileName ("history.sh")));ReleaseMemoryCell ((void *)cp);}if (GetVariableAsString (HistorySizeVariable, FALSE) == null)SetVariableFromNumeric (HistorySizeVariable, 100L);if ((fp = OpenHistoryFile (sOpenReadMode)) == (FILE *)NULL)return;/* Read in file */cp = ConsoleLineBuffer;while ((i = fgetc (fp)) != EOF){if (i == 0){*cp = 0;cp = ConsoleLineBuffer;AddHistory (Append);Append = FALSE;}else if (i == CHAR_NEW_LINE){*cp = 0;cp = ConsoleLineBuffer;AddHistory (Append);Append = TRUE;}else if ((cp - ConsoleLineBuffer) < LINE_MAX - 2)*(cp++) = (char)i;}CloseFile (fp);}/* Open the history file */static FILE * F_LOCAL OpenHistoryFile (const char *mode){#if (OS_TYPE != OS_UNIX)char tname[ MAX_PATH ];#endifconst char *name;if (!HistoryEnabled)return (FILE *)NULL;name = CheckDOSFileName (GetVariableAsString (HistoryFileVariable, FALSE), tname);return FOpenFile (name, mode);}/* Add entry to history file */void AddHistory (bool AppendToLast){char *cp;struct cmd_history *cmd;size_t Len;int HistorySize;/* Clean up console buffer */CleanUpBuffer (strlen (ConsoleLineBuffer), ConsoleLineBuffer, GetEOFKey ());/** Ignore if no history or blank line*/if ((!HistoryEnabled) || (strlen (ConsoleLineBuffer) == 0))return;/* Has the size changed ? */HistorySize = (int)GetVariableAsNumeric (HistorySizeVariable);if (HistorySize != CurrentHistorySize){/* Zero - empty history */if (!HistorySize)ClearHistory ();/* Allocate a new buffer */else if ((cmd = (struct cmd_history *)GetAllocatedSpace(sizeof (struct cmd_history) * HistorySize)) ==(struct cmd_history *)NULL)/* DO NOTHING IF NO MEMORY */;/* If new buffer is bigger, copy old to new and release */else if ((HistorySize > CurrentHistorySize) ||(l_history < HistorySize)){if (cmd_history != (struct cmd_history *)NULL){int Clen;/* Calculate the length to copy */Clen = (HistorySize > CurrentHistorySize)? CurrentHistorySize : l_history;memcpy (cmd, cmd_history,sizeof (struct cmd_history) * Clen);/* Set up new values */ReleaseMemoryCell (cmd_history);}CurrentHistorySize = HistorySize;SetMemoryAreaNumber ((void *)(cmd_history = cmd), 0);}/* Less space is available, copy reduced area and update entry numbers */else{int i = (CurrentHistorySize - HistorySize);/* Free entries at bottom */for (Len = 0; (Len < (size_t)i) && (Len < (size_t)l_history); Len++)ReleaseCommandMemory (&cmd_history[Len]);/* Transfer entries at top */memcpy (cmd, &cmd_history[i],sizeof (struct cmd_history) * HistorySize);/* Update things */if ((c_history -= i) < -1)c_history = -1;if ((l_history -= i) < 0)l_history = 0;/* Set up new values */ReleaseMemoryCell (cmd_history);CurrentHistorySize = HistorySize;SetMemoryAreaNumber ((void *)(cmd_history = cmd), 0);}}/* If there is no history space - return */if (!CurrentHistorySize)return;/* If the array is full, remove the last item */if (l_history == CurrentHistorySize){ReleaseCommandMemory (&cmd_history[0]);--l_history;memcpy (&cmd_history[0], &cmd_history[1],sizeof (struct cmd_history) * (CurrentHistorySize - 1));}/* Save the string. Is this a PS2 prompt */if ((AppendToLast) && l_history){cmd = &cmd_history[l_history - 1];/* Check length */if ((Len = strlen (cmd->command) + strlen (ConsoleLineBuffer) + 2)>= LINE_MAX){fprintf (stderr, BasicErrorMessage, LIT_history, History_2long);return;}/* Append to buffer, reallocate to new length */if ((cp = GetAllocatedSpace (Len)) == (char *)NULL)return;sprintf (cp, "%s\n%s", cmd->command, ConsoleLineBuffer);ReleaseCommandMemory (cmd);cmd->command = cp;SetMemoryAreaNumber ((void *)cp, 0);}/* Save the command line */else{Current_Event = GetLastHistoryEvent ();cmd_history[l_history].number = Current_Event;cmd_history[l_history].command = StringSave (ConsoleLineBuffer);c_history = ++l_history;}}/** Dump history to file*/void DumpHistory (void){struct cmd_history *cp = cmd_history;FILE *fp;int i;/* If history is not enabled or we can't open the file, give up */if ((!HistoryEnabled) ||((fp = OpenHistoryFile (sOpenWriteMode)) == (FILE *)NULL))return;/* Write history as a null terminated record */for (i = 0; i < l_history; ++cp, ++i){fputs (cp->command, fp);fputc (0, fp);}CloseFile (fp);}/* Clear out history */void ClearHistory (void){int i;struct cmd_history *cp = cmd_history;/* Release the entries */for (i = 0; i < l_history; ++cp, ++i)ReleaseCommandMemory (cp);ReleaseMemoryCell (cmd_history);/* Reset data information */c_history = -1; /* Current entry */l_history = 0; /* End of history array */Current_Event = 0;CurrentHistorySize = 0;cmd_history = (struct cmd_history *)NULL;}/* Output warning message and prompt */static bool F_LOCAL ReStartInput (char *cp){if (cp != (char *)NULL){if (!IS_Console (1) ||(strlen (ConsoleLineBuffer) && (StartCursorPosition != -1)))feputc (CHAR_NEW_LINE);PrintWarningMessage (BasicErrorMessage, LIT_history, cp);if (IS_Console (1))EraseToEndOfLine ();fputchar (CHAR_NEW_LINE);}OutputUserPrompt (LastUserPrompt);/* Re-initialise */InitialiseInput (InsertMode);return FALSE;}/* Copy backwards */static void F_LOCAL memrcpy (char *sp1, const char *sp, int cnt){while (cnt--)*(sp1--) = *(sp--);}/* Complete Filename functions */static bool F_LOCAL CompleteFileName (char *InsertPosition, bool Searching){int NumberOfMatches = 0;char *SearchString = null;char *NameStart = InsertPosition;char *StartDirInCLB;size_t MatchStringLen = 0;char *cp;int i;size_t maxi;bool InsertSpace = TRUE;char **FileList;/* Space or at start of line - use NULL file name */if ((NameStart != ConsoleLineBuffer) && isspace (*NameStart) &&!isspace (*(NameStart - 1))){--NameStart;InsertSpace = FALSE;}if (!isspace (*NameStart)){while (!isspace (*NameStart) && (NameStart != ConsoleLineBuffer))--NameStart;if (isspace (*NameStart))++NameStart;MatchStringLen = InsertPosition - NameStart;if ((SearchString = AllocateMemoryCell (MatchStringLen + 1)) ==(char *)NULL)return RingWarningBell ();memcpy (SearchString, NameStart, MatchStringLen);}/* Find the directory name */if ((cp = FindLastPathCharacter (SearchString)) != (char *)NULL)StartDirInCLB = NameStart + (int)(cp - SearchString + 1);/* No directory flag - Drive specifier? */else if ((strlen (SearchString) > (size_t)1) &&IsDriveCharacter (*(SearchString + 1)))StartDirInCLB = NameStart + 2;/* No drive specifier */elseStartDirInCLB = NameStart;FileList = BuildCompletionList (SearchString, strlen (SearchString),&NumberOfMatches, FALSE);if (SearchString != null)ReleaseMemoryCell ((void *)SearchString);/* If there are no matches, Just ring the bell */if (FileList == (char **)NULL)return RingWarningBell ();/* At this point, we have some data. If we are searching, sort the* filenames and display them. Remember to release the memory allocated for* the word block and its entries.*/if (Searching){/* Sort the file names and display them */qsort (&FileList[0], NumberOfMatches, sizeof (char *), SortCompare);/* Display. */fputchar (CHAR_NEW_LINE);PrintAList (NumberOfMatches, FileList);/* Release memory */ReleaseAList (FileList);/* Redraw current line */OutputUserPrompt (LastUserPrompt);StartCursorPosition = ReadCursorPosition ();return TRUE;}/* OK, we are completing. Get the common part of the filename list */maxi = GetCommonPartOfFileList (FileList);/* If the file name is length matches the search length, there are no unique* parts to the filenames in the directory. Just ring the bell and return.*/if ((maxi == MatchStringLen) && (NumberOfMatches > 1)){ReleaseAList (FileList);return RingWarningBell ();}/* So, at this point, we are completing and have something to append. Check* that the line is not too long and if there is an end bit, we can save a* copy of it.*//* Insert after spaces */if (InsertSpace && isspace (*InsertPosition) &&(InsertPosition != ConsoleLineBuffer)){++StartDirInCLB;++InsertPosition;}cp = null;if (((strlen (InsertPosition) + maxi +(StartDirInCLB - ConsoleLineBuffer) + 3) >= LINE_MAX) ||(strlen (InsertPosition) &&((cp = StringCopy (InsertPosition)) == null))){ReleaseAList (FileList);return RingWarningBell ();}/* Append the new end of line bits */strcpy (StartDirInCLB, *FileList);strcpy (&StartDirInCLB[i = strlen (StartDirInCLB)], " ");/* Save the current position */c_buffer_pos = &ConsoleLineBuffer[strlen (ConsoleLineBuffer)];/* If we found only 1 and its a directory, append a d sep */if ((NumberOfMatches == 1) && IsDirectory (NameStart)){StartDirInCLB[i] = CHAR_UNIX_DIRECTORY;strcpy (c_buffer_pos, cp);}/* If multiple matches, position at filename and not original position */else{if (isspace (*cp))--c_buffer_pos;strcpy (c_buffer_pos, cp);if ((NumberOfMatches > 1) && !isspace (*cp))--c_buffer_pos;}/* Release the saved buffer and reset end of line pointer */if (cp != null)ReleaseMemoryCell ((void *)cp);ReleaseAList (FileList);EndOfCurrentLine = &ConsoleLineBuffer[strlen (ConsoleLineBuffer)];/* Beep if more than one */if (NumberOfMatches > 1)RingWarningBell ();return TRUE;}/* Initialise input */static void F_LOCAL InitialiseInput (bool im){c_buffer_pos = ConsoleLineBuffer; /* Initialise */EndOfCurrentLine = ConsoleLineBuffer;SetCursorShape (InsertMode = im);M_length = -1;/* Reset max line length */MaxLength = 0;OldMaxLength = 0;/* Save the cursor position */if (IS_Console (1))StartCursorPosition = ReadCursorPosition ();}/* Configure Keyboard I/O */void Configure_Keys (void){char *cp; /* Line pointers */int i, fval, cval;int nFields;LineFields LF;long value;/* Get some memory for the input line and the file name */if ((LF.LineLength = strlen (cp = GetVariableAsString (ShellVariableName,FALSE)) + 5) < 200)LF.LineLength = 200;if ((LF.Line = AllocateMemoryCell (LF.LineLength)) == (char *)NULL)return;strcpy (LF.Line, cp);/* Find the .exe in the name */if ((cp = FindLastPathCharacter (LF.Line)) != (char *)NULL)++cp;elsecp = LF.Line;if ((cp = strrchr (cp, CHAR_PERIOD)) == (char *)NULL)cp = &LF.Line[strlen (LF.Line)];strcpy (cp, ".ini");{#if (OS_TYPE != OS_UNIX)char tname[ MAX_PATH ];#endifif ((LF.FP = FOpenFile (CheckDOSFileName (LF.Line, tname),sOpenReadMode)) == (FILE *)NULL){ReleaseMemoryCell ((void *)LF.Line);return;}}/* Initialise the internal buffer */LF.Fields = (Word_B *)NULL;/* Scan for the file */while ((nFields = ExtractFieldsFromLine (&LF)) != -1){if (nFields < 2)continue;/* Look up the keyword name */for (i = 0;(i < KF_LENGTH) && (stricmp (LF.Fields->w_words[0],KF_List[i].kf_name) != 0);++i)continue;/* Ignore no matches */if (i == KF_LENGTH)continue;/* Get the value of the second field - must be numeric */cval = 0;if (!ConvertNumericValue (LF.Fields->w_words[1], &value, 0))continue;fval = (int)value;/* Get the value of the third field, if it exists - must be numeric */if (nFields == 3){if (!ConvertNumericValue (LF.Fields->w_words[2], &value, 0))continue;cval = (int)value;}/* OK we have a valid value, save it */KF_List[i].akey = (char)fval;KF_List[i].fkey = (char)cval;}ReleaseMemoryCell ((void *)LF.Line);}/* Check cursor is in column zero */#if (OS_TYPE == OS_OS2)void PositionCursorInColumnZero (void){BYTE abCell[2];USHORT usRow;USHORT usColumn;USHORT cb = sizeof (abCell);/* Get screen infor and cursor position */GetScreenParameters ();StartCursorPosition = ReadCursorPosition ();VioGetCurPos (&usRow, &usColumn, 0);VioReadCellStr (abCell, &cb , usRow, usColumn, 0);if ((StartCursorPosition % MaximumColumns) || (abCell[0] != CHAR_SPACE))fputchar (CHAR_NEW_LINE);}#endif/* NT Version */#if (OS_TYPE == OS_NT)void PositionCursorInColumnZero (void){char abCell[2];CONSOLE_SCREEN_BUFFER_INFO CSI;DWORD ActionCount;/* Get screen infor and cursor position */GetScreenParameters ();StartCursorPosition = ReadCursorPosition ();GetConsoleScreenBufferInfo (NT_StdOut, &CSI);ReadConsoleOutputCharacter (NT_StdOut, abCell, 1, CSI.dwCursorPosition,&ActionCount);if ((StartCursorPosition % MaximumColumns) || (*abCell != CHAR_SPACE))fputchar (CHAR_NEW_LINE);}#endif/* DOS Version */#if (OS_TYPE == OS_DOS)void PositionCursorInColumnZero (void){union REGS r;/* Get screen infor and cursor position */GetScreenParameters ();StartCursorPosition = ReadCursorPosition ();r.h.ah = 0x08;r.h.bh = 0x00;SystemInterrupt (0x10, &r, &r);if ((StartCursorPosition % MaximumColumns) || (r.h.al != CHAR_SPACE))fputchar (CHAR_NEW_LINE);}#endif/** Get screen parameters*/#if (OS_TYPE == OS_OS2)void GetScreenParameters (void){VIOMODEINFO viomi;viomi.cb = sizeof(viomi);VioGetMode (&viomi, 0);MaximumColumns = viomi.col;MaximumLines = viomi.row;/* Set up LINES and COLUMNS variables */SetVariableFromNumeric (LIT_LINES, (long)MaximumLines);SetVariableFromNumeric (LIT_COLUMNS, (long)MaximumColumns);}#endif/* NT Version */#if (OS_TYPE == OS_NT)void GetScreenParameters (void){CONSOLE_SCREEN_BUFFER_INFO CSI;NT_StdOut = GetStdHandle (STD_OUTPUT_HANDLE);GetConsoleScreenBufferInfo (NT_StdOut, &CSI);MaximumColumns = CSI.dwSize.X;MaximumLines = CSI.dwSize.Y;//printf( "DEBUG-----dwSize Lines: %d, Cols: %d\n", CSI.dwSize.Y, CSI.dwSize.X );//printf( "DEBUG-----dwCursorPosition Lines: %d, Cols: %d\n", CSI.dwCursorPosition.Y, CSI.dwCursorPosition.X );//printf( "DEBUG-----srWindow Left:%d, Top: %d, Right: %d, Bottom:%d\n", CSI.srWindow.Left, CSI.srWindow.Top, CSI.srWindow.Right, CSI.srWindow.Bottom );//printf( "DEBUG-----dwMaximumWindowSize Lines: %d, Cols: %d\n", CSI.dwMaximumWindowSize.Y, CSI.dwMaximumWindowSize.X );//printf( "DEBUG-----My Stuff Lines: %d, Cols: %d\n", MaximumLines, MaximumColumns );/* Set up LINES and COLUMNS variables */SetVariableFromNumeric (LIT_LINES, (long)MaximumLines);SetVariableFromNumeric (LIT_COLUMNS, (long)MaximumColumns);}#endif/* DOS version */#if (OS_TYPE == OS_DOS)void GetScreenParameters (void){union REGS r;# if (OS_SIZE == OS_16)MaximumColumns = *(int *)(0x0040004aL);# elseMaximumColumns = *(short *)(0x044aL);# endifMaximumLines = 25;/* Is this an EGA? This test was found in NANSI.SYS */r.h.ah = 0x12;r.x.REG_BX = 0xff10;SystemInterrupt (0x10, &r, &r);/* Else read the number of rows */if (!(r.x.REG_BX & 0xfefc)){r.x.REG_AX = 0x1130;r.h.bh = 0;SystemInterrupt (0x10, &r, &r);MaximumLines = r.h.dl + 1;}/* Set up LINES and COLUMNS variables */SetVariableFromNumeric (LIT_LINES, (long)MaximumLines);SetVariableFromNumeric (LIT_COLUMNS, (long)MaximumColumns);}#endif/* Ring Bell ? */bool RingWarningBell (void){if (KF_List[KF_RINGBELL].akey)#if (OS_TYPE == OS_OS2)DosBeep (1380, 500);#elif (OS_TYPE == OS_NT)Beep (1380, 500);#elsefputchar (0x07);fflush (stdout);#endifreturn FALSE;}/** Read keyboard function*/#if (OS_TYPE == OS_OS2)unsigned char ReadKeyBoard (unsigned char *f_key){KBDKEYINFO kbci;*f_key = 0;/* Wait for input */KbdCharIn (&kbci, IO_WAIT, 0);DisplayKeyCode (kbci.chChar, kbci.chScan);if (kbci.chChar == 0x03)raise (SIGINT);/* Check for non-function character */if (kbci.chChar && (kbci.chChar != 0xe0))return (unsigned char)kbci.chChar;/* Return scan code and type (normal or ALT'ed) */*f_key = (unsigned char)kbci.chScan;return (unsigned char)((kbci.fsState & (ALT | LEFTALT | RIGHTALT))? KT_ALTFUNCTION: KT_FUNCTION);}#endif/* NT Version */#if (OS_TYPE == OS_NT)unsigned char ReadKeyBoard (unsigned char *f_key){INPUT_RECORD Buffer = {0};DWORD NumberOfEventsRead;int i;*f_key = 0;/* Wait for input */for ( ; ; ){if (!ReadConsoleInput (NT_StdIn, &Buffer, 1, &NumberOfEventsRead))continue;if (Buffer.EventType == WINDOW_BUFFER_SIZE_EVENT)return KT_RESIZE;/* Ignore other non-keyboard events */if (Buffer.EventType != KEY_EVENT)continue;/* Ignore key release events */if (!Buffer.Event.KeyEvent.bKeyDown)continue;/* See if it is an ignore key? */for (i = 0; i < IGNORE_CNT; i++){if (Buffer.Event.KeyEvent.wVirtualScanCode == IgnoreScanCode[i])break;}if (i != IGNORE_CNT)continue;/* Keystroke mapping */if (DoNTKeyMap (&Buffer.Event.KeyEvent))break;/* ? wRepeatCount */}DisplayKeyCode (Buffer.Event.KeyEvent.uChar.AsciiChar,Buffer.Event.KeyEvent.wVirtualScanCode);if (Buffer.Event.KeyEvent.uChar.AsciiChar == 0x03)raise (SIGINT);/* Check for non-function character */if (Buffer.Event.KeyEvent.uChar.AsciiChar &&(Buffer.Event.KeyEvent.uChar.AsciiChar != 0xe0))return (unsigned char)Buffer.Event.KeyEvent.uChar.AsciiChar;/* Return scan code and type (normal or ALT'ed) */*f_key = (unsigned char)Buffer.Event.KeyEvent.wVirtualScanCode;return (unsigned char)((Buffer.Event.KeyEvent.dwControlKeyState &(RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))? KT_ALTFUNCTION: KT_FUNCTION);}/** Handle keyboard mapping*/static bool F_LOCAL DoNTKeyMap (KEY_EVENT_RECORD *KeyEvent){int i;if (KeyEvent->wVirtualScanCode == 0x0f) /* TAB */{if (KeyEvent->dwControlKeyState & (CTRL_PRESSED | ALT_PRESSED))return FALSE;else if (KeyEvent->dwControlKeyState & SHIFT_PRESSED)KeyEvent->uChar.AsciiChar = 0;elseKeyEvent->uChar.AsciiChar = CHAR_TAB;return TRUE;}else if ((KeyEvent->wVirtualScanCode == 0x0e) || /* BACKSPACE */(KeyEvent->wVirtualScanCode == 0x1c)) /* RETURN */return (bool) !C2bool (KeyEvent->dwControlKeyState & ALT_PRESSED);/* All other mapped characters are OK */else if (KeyEvent->uChar.AsciiChar)return TRUE;/* Handle function keys */for (i = 0; i < MAX_NT_FKMAP; i++){if (KeyEvent->wVirtualScanCode != NT_KFMap [i].Normal)continue;/* If Ctrl Alt pressed - ignore key */if ((KeyEvent->dwControlKeyState & (CTRL_PRESSED | ALT_PRESSED))== (CTRL_PRESSED | ALT_PRESSED))return FALSE;else if (KeyEvent->dwControlKeyState & CTRL_PRESSED)KeyEvent->wVirtualScanCode = NT_KFMap [i].Control;else if (KeyEvent->dwControlKeyState & ALT_PRESSED)KeyEvent->wVirtualScanCode = NT_KFMap [i].Alt;else if (KeyEvent->dwControlKeyState & SHIFT_PRESSED)KeyEvent->wVirtualScanCode = NT_KFMap [i].Shift;return TRUE;}return TRUE;}#endif/* DOS Version */#if (OS_TYPE == OS_DOS)unsigned char ReadKeyBoard (unsigned char *f_key){unsigned char a_key;union KeyCode {unsigned short Key;struct Scan {unsigned char ascii, scan;} Scan;} KeyCode;/* If DEQSview is active - we must poll the keyboard */# if (OS_SIZE == OS_16) && (0)if (DESQviewActive){if (!((KeyCode.Scan.ascii = Poll_Keyboard ())) ||(KeyCode.Scan.ascii == 0xe0))KeyCode.Scan.scan = Poll_Keyboard ();}else# endif/** Read Keyboard via interrupt 10 function 1 or 10 depending on whether we* have an extended keyboard or not!.*/{KeyCode.Key = _bios_keybrd (ReadKeyboardOption);if (KeyCode.Scan.ascii == 0xe0)KeyCode.Scan.ascii = 0;}DisplayKeyCode (KeyCode.Scan.ascii, KeyCode.Scan.scan);/* Check for interrupt */if (KeyCode.Scan.ascii == 3)raise (SIGINT);/* Set up return values */if (KeyCode.Scan.ascii == 0){a_key = KT_FUNCTION;*f_key = KeyCode.Scan.scan;/* If ALT Key set, return 0xff instead of 0 for function key */if (_bios_keybrd (_KEYBRD_SHIFTSTATUS) & 0x08)a_key = KT_ALTFUNCTION;}/* ASCII keycode - return it. */else{a_key = KeyCode.Scan.ascii;*f_key = 0;}return a_key;}#endif#ifdef KEYDEBUGstatic void DisplayKeyCode (unsigned int a, unsigned int b){int cp = ReadCursorPosition ();SetCursorPosition (23*80 + 59);printf ("ASCII %.2x SCAN %.2x\n", a, b);SetCursorPosition (cp);}#endif/** Update Initialisation value*/bool ChangeInitialisationValue (char *string, int newvalue){int i;for (i = KF_END_FKEYS; i < KF_LENGTH; ++i){if (stricmp (string, KF_List[i].kf_name) == 0){KF_List[i].akey = (char)newvalue;return TRUE;}}return FALSE;}/** Enable keyboard polling function - required if DESQview loaded*/#if (OS_TYPE == OS_DOS)static void F_LOCAL CheckKeyboardPolling (void){static bool Initialised = FALSE;union REGS r;int i;if (Initialised)return;Initialised = TRUE;/* Check to see we are running under DESQview */# if (OS_SIZE == OS_16)r.x.REG_AX = 0x2b01;r.x.REG_CX = 0x4445;r.x.REG_DX = 0x5351;DosInterrupt (&r, &r);if (r.h.al != 0xff)DESQviewActive = TRUE;# endif/* Otherwise check for extended keyboard. Stick 0xffff in the keyboard* buffer and read it back. If we find it - OK!*/ReadKeyboardOption = _KEYBRD_READ; /* Normal keyboard */r.h.ah = 0x05;r.x.REG_CX = 0xffff;SystemInterrupt (0x16, &r, &r);if (r.h.al)return;/* 16 attempts to read extended keyboard interface */for (i = 0; i < 16; i++){if ((unsigned)_bios_keybrd (_NKEYBRD_READ) == 0xffff){ReadKeyboardOption = _NKEYBRD_READ; /* Extended keyboard */return;}}}#endif/** Print a single history entry*/static void F_LOCAL PrintOutHistory (FILE *fp,bool n_flag,struct cmd_history *cmd){char *cp = cmd->command;if (n_flag){fprintf (fp, "%5d: ", cmd->number);while (*cp){putc (*cp, fp);if (*(cp++) == CHAR_NEW_LINE)fputs (" ", fp);}}elsefputs (cp, fp);putc (CHAR_NEW_LINE, fp);}/** Get the last history event number*/int GetLastHistoryEvent (void){return (l_history) ? cmd_history[l_history - 1].number + 1 : 1;}/** Get the last history event number*/int GetFirstHistoryEvent (void){return (cmd_history[0].number) ? cmd_history[0].number : 1;}/** Get the last history event*/#if (OS_TYPE != OS_DOS)char *GetLastHistoryString (void){return l_history ? cmd_history[l_history - 1].command : (char *)NULL;}#endif/** Dump history*/void PrintHistory (bool r_flag, bool n_flag, int First, int Last, FILE *fp){int i;if (r_flag){for (i = l_history - 1;(i >= 0) && (cmd_history[i].number >= First); --i){if (cmd_history[i].number <= Last)PrintOutHistory (fp, n_flag, &cmd_history[i]);}}else{for (i = 0; (i < l_history) && (cmd_history[i].number <= Last); ++i){if (cmd_history[i].number >= First)PrintOutHistory (fp, n_flag, &cmd_history[i]);}}}/** Search for an event*/int SearchHistory (char *buffer){int Length = strlen (buffer);int i;for (i = l_history - 1;(i >= 0) && strncmp (buffer, cmd_history[i].command, Length); --i)continue;return (i == -1) ? -1 : cmd_history[i].number;}/** Release Command*/static void F_LOCAL ReleaseCommandMemory (struct cmd_history *cp){if (cp->command != null)ReleaseMemoryCell ((void *)cp->command);}/** Flush history buffer. If save is set, the contents of the console* buffer will be saved.*/void FlushHistoryBuffer (void){if (SaveHistory)AddHistory (AppendHistory);memset (ConsoleLineBuffer, 0, LINE_MAX + 1);AppendHistory = FALSE;SaveHistory = FALSE;}/** Save the current console buffer*/static void F_LOCAL SaveCurrentHistory (void){c_history = l_history;if (SaveHistory)AddHistory (AppendHistory);AppendHistory = (bool)(LastUserPrompt == PS2);SaveHistory = (bool)((LastUserPrompt == PS1) || AppendHistory);}/** Insert a Character into the buffer*/static bool F_LOCAL InsertACharacter (int NewCharacter){if ((EndOfCurrentLine - ConsoleLineBuffer) == LINE_MAX)return RingWarningBell (); /* Ring bell - line full */if (c_buffer_pos != EndOfCurrentLine)memrcpy (EndOfCurrentLine + 1, EndOfCurrentLine,EndOfCurrentLine - c_buffer_pos + 1);++EndOfCurrentLine;/* Fast end of line processing */if ((c_buffer_pos == EndOfCurrentLine - 1) && (NewCharacter != CHAR_TAB)){*(c_buffer_pos++) = (char)NewCharacter;OutputACharacter (NewCharacter);return FALSE;}/* Not at end of line - redraw */*(c_buffer_pos++) = (char)NewCharacter;return TRUE;}/** Delete Last History Item*/void DeleteLastHistory (void){if (l_history)ReleaseCommandMemory (&cmd_history[--l_history]);}/** Clear the screen*/#if (OS_TYPE == OS_OS2)bool ClearScreen (void){BYTE abCell[2];USHORT usRow;USHORT usColumn;USHORT cb = sizeof (abCell);fputchar (CHAR_NEW_LINE);FlushStreams ();/* Read attribute under cursor */VioGetCurPos (&usRow, &usColumn, 0);VioReadCellStr (abCell, &cb , usRow, usColumn, 0);abCell[0] = CHAR_SPACE;VioScrollUp (0, 0, 0xffff, 0xffff, 0xffff, abCell, 0);VioSetCurPos (0, 0, 0);OutputUserPrompt (LastUserPrompt);StartCursorPosition = ReadCursorPosition ();return TRUE;}#endif/** NT Version*/#if (OS_TYPE == OS_NT)bool ClearScreen (void){WORD Atts[2];CONSOLE_SCREEN_BUFFER_INFO CSI;DWORD ActionCount;CHAR_INFO *Buffer;COORD dwBufferSize;COORD dwBufferCoord;SMALL_RECT WriteRegion;DWORD Size = MaximumColumns * MaximumLines;FlushStreams ();/* Read attribute under cursor */GetConsoleScreenBufferInfo (NT_StdOut, &CSI);ReadConsoleOutputAttribute (NT_StdOut, Atts, 1, CSI.dwCursorPosition,&ActionCount);/** Write it. What a pain!!!** Get some memory*/Buffer = (CHAR_INFO *)AllocateMemoryCell (Size * sizeof (CHAR_INFO));/* Set up attributes */for (ActionCount = 0; ActionCount < Size; ActionCount++){Buffer[ActionCount].Attributes = Atts[0];Buffer[ActionCount].Char.AsciiChar = CHAR_SPACE;}/* Size */dwBufferSize.X = (USHORT)MaximumColumns;dwBufferSize.Y = (USHORT)MaximumLines;/* Co-ordinated */dwBufferCoord.X = 0;dwBufferCoord.Y = 0;/* Set up output data */WriteRegion.Left = 0;WriteRegion.Top = 0;WriteRegion.Right = (USHORT)(MaximumColumns - 1);WriteRegion.Bottom = (USHORT)(MaximumLines - 1);WriteConsoleOutput (NT_StdOut, Buffer, dwBufferSize, dwBufferCoord,&WriteRegion);ReleaseMemoryCell (Buffer);SetConsoleCursorPosition (NT_StdOut, dwBufferCoord);OutputUserPrompt (LastUserPrompt);StartCursorPosition = ReadCursorPosition ();return TRUE;}#endif/* DOS Version */#if (OS_TYPE == OS_DOS)bool ClearScreen (void){union REGS r;unsigned char backg;fputchar (CHAR_NEW_LINE);FlushStreams ();/* Get the background attribute of the cursor */r.h.ah = 0x08;r.h.bh = 0;SystemInterrupt (0x10, &r, &r);backg = (unsigned char)(r.h.ah & 0x07);/* Clear the screen */r.x.REG_AX = 0x0600;r.h.bh = backg;r.x.REG_CX = 0;r.h.dh = (unsigned char)MaximumLines;r.h.dl = (unsigned char)MaximumColumns;SystemInterrupt (0x10, &r, &r);/* Position to top of page */r.h.ah = 0x02; /* Set new position */r.h.bh = 0; /* Page zero */r.x.REG_DX = 0x0000;SystemInterrupt (0x10, &r, &r);OutputUserPrompt (LastUserPrompt);StartCursorPosition = ReadCursorPosition ();return TRUE;}#endif/** Display a line, handling control characters*/void DisplayLineWithControl (char *line){int off = ReadCursorPosition ();/* Print characters */while (*line){/* Process TABS */if (*line == CHAR_TAB){do{fputchar (CHAR_SPACE);} while ((++off) % 8);}/* Process Control and printing characters */elseoff += OutputACharacter (*line);++line;}}/** Get the Root Disk Drive. If not defined, set it to the current drive.*/#if (OS_TYPE != OS_UNIX)int GetRootDiskDrive (void){if (!KF_List[KF_ROOTDRIVE].akey)KF_List[KF_ROOTDRIVE].akey = (char)GetCurrentDrive ();return KF_List[KF_ROOTDRIVE].akey;}#endif/** Get the EOF Key*/int GetEOFKey (void){#if (OS_TYPE == OS_UNIX)struct termios ts;return tcgetattr (1, &ts) ? 4 : ts.c_cc[VEOF];#elseif (!KF_List[KF_EOFKEY].akey)KF_List[KF_EOFKEY].akey = 0x1a;return KF_List[KF_EOFKEY].akey;#endif}/** Output a Character - excluding TABS. Return # chars output.** TABS are not checked for*/static int F_LOCAL OutputACharacter (int c){int off = 1;/* Check for control and process */if (iscntrl (c)){fputchar (CHAR_NOT);c += '@';off++;}/* Output the character */fputchar (c);return off;}/** Strip off trailing EOFs and EOLs from console buffer*/char CleanUpBuffer (int length, char *buffer, int eofc){char *cp = &buffer[length - 1];char ret;while (length && ((*cp == (char)eofc) || (*cp == CHAR_NEW_LINE))){length--;cp--;}ret = *(cp + 1);*(cp + 1) = 0;return ret;}/** Look up the keystroke to see if it is one of our functions*/int LookUpKeyBoardFunction (unsigned char a_key, unsigned char f_key){int i;for (i = 0; (i < KF_END_FKEYS); ++i){if (KF_List[i].akey != a_key)continue;/* Function or meta key? */if ((a_key != KT_FUNCTION) && (a_key != KT_ALTFUNCTION))break;else if (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 == KT_FUNCTION) ||(a_key == KT_ALTFUNCTION)))return 0;return (i == KF_END_FKEYS) ? (int)a_key: -((int)(KF_List[i].fcode) + 1);}/** Build a list of filenames for completion*/char **BuildCompletionList (char *String, size_t Length, int *Count,bool Full){char *MatchString = GetAllocatedSpace (Length + 2);char **FileList;char *vecp[2];char *cp;char **ap;size_t DiscardLength;/* Build the string to expand */*Count = 0;memmove (MatchString, String, Length);if (MatchString[Length - 1] != CHAR_MATCH_ALL){MatchString[Length] = CHAR_MATCH_ALL;MatchString[Length + 1] = 0;}elseMatchString[Length] = 0;vecp[0] = MatchString;vecp[1] = (char *)NULL;/* Expand it */FileList = ExpandWordList (vecp, EXPAND_SPLITIFS | EXPAND_GLOBBING |EXPAND_TILDE, (ExeMode *)NULL);/* Check to see if it expanded */if ((strcmp (FileList[0], MatchString) == 0) &&(FileList[1] == (char *) NULL)){ReleaseMemoryCell (FileList[0]);ReleaseMemoryCell (FileList);FileList = (char **)NULL;}ReleaseMemoryCell (MatchString);if (FileList != (char **)NULL)*Count = CountNumberArguments (FileList);/* Exit if expansion failed or we don't want directory stripping */if ((FileList == (char **)NULL) || Full)return FileList;/* Strip off directory name ..../ or x: */if ((cp = FindLastPathCharacter (FileList[0])) != (char *)NULL)cp++;else if (IsDriveCharacter (FileList[0][1]))cp = &FileList[0][2];elsereturn FileList;/* Get the discard length and remove it from the strings */DiscardLength = cp - FileList[0];ap = FileList;while ((cp = *(ap++)) != (char *)NULL)strcpy (cp, cp + DiscardLength);return FileList;}/** Get the Common part of the name from a list of files*/size_t GetCommonPartOfFileList (char **FileList){char **ap = FileList + 1;char *BaseName = *FileList;size_t maxi = strlen (*FileList);size_t i;/* Scan the list */while (*ap != (char *)NULL){for (i = 0; (BaseName[i] == (*ap)[i]) && (i < maxi); i++)continue;BaseName[maxi = i] = 0;ap++;}return maxi;}/** Return the function key information associated with an internal key* function*/#if defined (FLAGS_EMACS) || defined (FLAGS_GMACS)unsigned char GetFunctionKeyMap (int key, unsigned char *f_key){*f_key = KF_List[key].fkey;return KF_List[key].akey;}#endif/** Change Keyboard to RAW/COOKED mode*/#if (OS_TYPE == OS_OS2)static void F_LOCAL ChangeKeyboardMode (bool Cooked){KBDINFO kbstInfo;/* Get current mode */kbstInfo.cb = sizeof (kbstInfo);KbdGetStatus (&kbstInfo, 0);/* Change it */kbstInfo.fsMask &= ~(KEYBOARD_ASCII_MODE | KEYBOARD_ECHO_ON |KEYBOARD_ECHO_OFF | KEYBOARD_BINARY_MODE);kbstInfo.fsMask |= (Cooked) ? (KEYBOARD_ASCII_MODE | KEYBOARD_ECHO_ON): (KEYBOARD_ECHO_OFF | KEYBOARD_BINARY_MODE);KbdSetStatus (&kbstInfo, 0);}#endif/* NT Version */#if (OS_TYPE == OS_NT)static void F_LOCAL ChangeKeyboardMode (bool Cooked){DWORD NewMode = ENABLE_WINDOW_INPUT;/* Get handlers */NT_StdIn = GetStdHandle (STD_INPUT_HANDLE);NT_StdOut = GetStdHandle (STD_OUTPUT_HANDLE);/* Set up cooked mode if required */if (Cooked)NewMode = (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |ENABLE_ECHO_INPUT);/* Change modes */SetConsoleMode (NT_StdIn, NewMode);SetConsoleMode (NT_StdOut, ENABLE_PROCESSED_OUTPUT |ENABLE_WRAP_AT_EOL_OUTPUT);}#endif/* UNIX Version */#if (OS_TYPE == OS_UNIX)static void F_LOCAL ChangeKeyboardMode (bool Cooked){fputs ("UNIX: ChangeKeyboardMode NI\n", stderr);}#endif/** EMX needs a read keyboard function*/#if (OS_TYPE == OS_DOS) && defined (__EMX__)unsigned int _bios_keybrd (unsigned int function){union REGS r;r.h.ah = function;SystemInterrupt (0x16, &r, &r);return r.x.REG_AX;}#endif