Subversion Repositories DevTools

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 dpurdie 1
/*
2
 * MS-DOS SHELL - History Processing
3
 *
4
 * MS-DOS SHELL - Copyright (c) 1990,4 Data Logic Limited
5
 *
6
 * This code is subject to the following copyright restrictions:
7
 *
8
 * 1.  Redistribution and use in source and binary forms are permitted
9
 *     provided that the above copyright notice is duplicated in the
10
 *     source form and the copyright notice in file sh6.c is displayed
11
 *     on entry to the program.
12
 *
13
 * 2.  The sources (or parts thereof) or objects generated from the sources
14
 *     (or parts of sources) cannot be sold under any circumstances.
15
 *
16
 *    $Header: /cvsroot/device/DEVL/UTILS/SH/Sh9.c,v 1.1 2002/08/02 06:49:35 adamy Exp $
17
 *
18
 *    $Log: Sh9.c,v $
19
 *    Revision 1.1  2002/08/02 06:49:35  adamy
20
 *    imported (reference only)
21
 *
22
 *    Revision 1.1  2001/07/20 05:55:45  ayoung
23
 *    WIN32 support
24
 *
25
 *    Revision 1.1.1.1  1999/12/02 01:11:12  gordonh
26
 *    UTIL
27
 *
28
 *	Revision 2.18  1994/08/25  20:49:11  istewart
29
 *	MS Shell 2.3 Release
30
 *
31
 *	Revision 2.17  1994/02/23  09:23:38  istewart
32
 *	Beta 233 updates
33
 *
34
 *	Revision 2.16  1994/02/01  10:25:20  istewart
35
 *	Release 2.3 Beta 2, including first NT port
36
 *
37
 *	Revision 2.15  1994/01/20  14:51:43  istewart
38
 *	Release 2.3 Beta 1
39
 *
40
 *	Revision 2.14  1994/01/11  17:55:25  istewart
41
 *	Release 2.3 Beta 0 patches
42
 *
43
 *	Revision 2.13  1993/11/09  10:39:49  istewart
44
 *	Beta 226 checking
45
 *
46
 *	Revision 2.12  1993/08/25  16:03:57  istewart
47
 *	Beta 225 - see Notes file
48
 *
49
 *	Revision 2.11  1993/07/02  10:21:35  istewart
50
 *	224 Beta fixes
51
 *
52
 *	Revision 2.10  1993/06/16  13:50:00  istewart
53
 *	Fix defaults for Key initialisation
54
 *
55
 *	Revision 2.9  1993/06/14  11:00:12  istewart
56
 *	More changes for 223 beta
57
 *
58
 *	Revision 2.8  1993/06/02  09:52:35  istewart
59
 *	Beta 223 Updates - see Notes file
60
 *
61
 *	Revision 2.7  1993/02/16  16:03:15  istewart
62
 *	Beta 2.22 Release
63
 *
64
 *	Revision 2.6  1993/01/26  18:35:09  istewart
65
 *	Release 2.2 beta 0
66
 *
67
 *	Revision 2.5  1992/12/14  10:54:56  istewart
68
 *	BETA 215 Fixes and 2.1 Release
69
 *
70
 *	Revision 2.4  1992/11/06  10:03:44  istewart
71
 *	214 Beta test updates
72
 *
73
 *	Revision 2.3  1992/09/03  18:54:45  istewart
74
 *	Beta 213 Updates
75
 *
76
 *	Revision 2.2  1992/07/16  14:33:34  istewart
77
 *	Beta 212 Baseline
78
 *
79
 *	Revision 2.1  1992/07/10  10:52:48  istewart
80
 *	211 Beta updates
81
 *
82
 *	Revision 2.0  1992/05/07  21:33:35  Ian_Stewartson
83
 *	MS-Shell 2.0 Baseline release
84
 *
85
 */
86
 
87
#include <sys/types.h>
88
#include <sys/stat.h>
89
#include <stdio.h>
90
#include <string.h>
91
#include <ctype.h>
92
#include <signal.h>
93
#include <stdlib.h>
94
#include <stddef.h>
95
#include <errno.h>
96
#include <setjmp.h>
97
#include <limits.h>
98
#include <unistd.h>
99
#include <dirent.h>
100
#include "sh.h"
101
 
102
#if (OS_TYPE == OS_UNIX)
103
#  include <termios.h>
104
#endif
105
 
106
#if (OS_TYPE == OS_DOS)
107
#  ifndef _NKEYBRD_READ
108
#    define _NKEYBRD_READ		0x10	/* read next char from kbd */
109
#    define _NKEYBRD_READY		0x11	/* check for keystroke	*/
110
#    define _NKEYBRD_SHIFTSTATUS	0x12	/* get shift key status	*/
111
#  endif
112
 
113
#  ifndef _KEYBRD_READ		
114
#    define _KEYBRD_READ       		0x00	/* read next char from kbd */
115
#    define _KEYBRD_READY      		0x01	/* check for keystroke	*/
116
#    define _KEYBRD_SHIFTSTATUS		0x02	/* get shift key status	*/
117
#  endif
118
 
119
#  if defined (__TURBOC__)
120
#    define _bios_keybrd(a)		bioskey (a)
121
#  elif defined (__EMX__)
122
unsigned int	 			_bios_keybrd (unsigned int);
123
#  endif
124
#endif
125
 
126
/* Keyboard functions */
127
 
128
#define KF_LENGTH			ARRAY_SIZE (KF_List)
129
 
130
/*
131
 * Saved command line structure
132
 */
133
 
134
struct	cmd_history {
135
    int		number;
136
    char	*command;
137
};
138
 
139
/* Function Declarations */
140
 
141
static bool F_LOCAL	ProcessAlphaNumericKey (int);
142
static bool F_LOCAL	ProcessFunctionKey (int);
143
static bool F_LOCAL	Process_History (int);
144
static bool F_LOCAL	ScanHistory (void);
145
static void F_LOCAL	ReDisplayInputLine (void);
146
static void F_LOCAL	PageHistoryRecord (int);
147
static bool F_LOCAL	UpdateConsoleInputLine (char *);
148
static bool F_LOCAL	ReStartInput (char *);
149
static void F_LOCAL	GenerateNewCursorPosition (void);
150
static void F_LOCAL	EraseToEndOfLine (void);
151
static bool F_LOCAL	CompleteFileName (char *, bool);
152
static void F_LOCAL	InitialiseInput (bool);
153
static void F_LOCAL	PrintOutHistory (FILE *, bool, struct cmd_history *);
154
static void F_LOCAL	ReleaseCommandMemory (struct cmd_history *);
155
static void F_LOCAL	SaveCurrentHistory (void);
156
static void F_LOCAL     memrcpy (char *, const char *, int);
157
static FILE * F_LOCAL   OpenHistoryFile (const char *);
158
static void F_LOCAL	GetLineFromConsole (void);
159
#ifdef KEYDEBUG
160
static void		DisplayKeyCode (unsigned int, unsigned int);
161
#else
162
#  define DisplayKeyCode(a,b)
163
#endif
164
 
165
 
166
#if (OS_TYPE != OS_DOS) 
167
static void F_LOCAL	ChangeKeyboardMode (bool);
168
#else
169
#  define ChangeKeyboardMode(a)
170
#endif
171
 
172
#if (OS_TYPE == OS_NT)
173
static bool F_LOCAL	DoNTKeyMap (KEY_EVENT_RECORD *);
174
#endif
175
 
176
#if (OS_TYPE == OS_DOS) && (OS_SIZE == OS_16)
177
static bool		DESQviewActive = FALSE;/* Poll keyboard		*/
178
#endif
179
 
180
static bool F_LOCAL	InsertACharacter (int);
181
static int F_LOCAL	OutputACharacter (int);
182
static int F_LOCAL	GetLineFromDevice (void);
183
 
184
#if (OS_TYPE == OS_DOS)
185
static void F_LOCAL	CheckKeyboardPolling (void);
186
					/* Read keyboard parameter	*/
187
static unsigned int	ReadKeyboardOption = _KEYBRD_READ;
188
#else
189
#  define CheckKeyboardPolling()
190
#endif
191
 
192
static bool	InsertMode = FALSE;
193
static char	*c_buffer_pos;		/* Position in command line	*/
194
static char	*EndOfCurrentLine;	/* End of command line		*/
195
static int	m_line = 0;		/* Max write line number	*/
196
static int	c_history = -1;		/* Current entry		*/
197
static int	l_history = 0;		/* End of history array		*/
198
static int	M_length = -1;		/* Match length			*/
199
static int	MaxLength = 0;		/* Max line length		*/
200
static int	OldMaxLength = 0;	/* Previous Max line length	*/
201
static int	CurrentHistorySize = 0;	/* Current Length of History	*/
202
					/* Array			*/
203
static bool	AppendHistory = FALSE;	/* Append to history		*/
204
static bool	SaveHistory = FALSE;	/* Save history			*/
205
static char	*No_prehistory   = "No previous commands";
206
static char	*No_MatchHistory = "No history match found";
207
static char	*No_posthistory  = "No more commands";
208
static char	*History_2long   = "History line too long";
209
 
210
#if (OS_TYPE == OS_NT)
211
static HANDLE	NT_StdIn;		/* Standard Input handler	*/
212
static HANDLE	NT_StdOut;		/* Standard Ouput handler	*/
213
 
214
#define CTRL_PRESSED	((LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
215
#define ALT_PRESSED	((LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
216
 
217
/* Scan codes to ignore on input */
218
 
219
static WORD	IgnoreScanCode[] = {
220
    0x1d,				/* Control key			*/
221
    0x38,				/* Alt key			*/
222
    0x2a,				/* Shift key			*/
223
    0x36,				/* Shift key			*/
224
    0x3a,				/* Caps key			*/
225
    0x45				/* Numlock key			*/
226
};
227
 
228
#define IGNORE_CNT	ARRAY_SIZE (IgnoreScanCode) 
229
 
230
/* Mapping table because we don't get converted scan codes */
231
 
232
 
233
struct NT_KFMap {
234
    unsigned char	Normal;		/* Normal scancode	*/
235
    unsigned char	Shift;		/* shift scancode	*/
236
    unsigned char	Control;	/* Control scancode	*/
237
    unsigned char	Alt;		/* Alt scancode		*/
238
} NT_KFMap [] =  {
239
    /* Key 		Normal  Shift-  Control-  Alt-	*/
240
    { /* F1 */		0x3b,   0x54,   0x5E,     0x68 },
241
    { /* F2 */		0x3c,   0x55,   0x5F,     0x69 },
242
    { /* F3 */		0x3d,   0x56,   0x60,     0x6A },
243
    { /* F4 */		0x3e,   0x57,   0x61,     0x6B },
244
    { /* F5 */		0x3f,   0x58,   0x62,     0x6C },
245
    { /* F6 */		0x40,   0x59,   0x63,     0x6D },
246
    { /* F7 */		0x41,   0x5A,   0x64,     0x6E },
247
    { /* F8 */		0x42,   0x5B,   0x65,     0x6F },
248
    { /* F9 */		0x43,   0x5C,   0x66,     0x70 },
249
    { /* F10 */		0x44,   0x5D,   0x67,     0x71 },
250
    { /* F11 */		0x85,   0x87,   0x89,     0x8b },
251
    { /* F12 */		0x86,   0x88,   0x8a,     0x8c },
252
 
253
    { /* INSERT */	0x52,   0x52,   0x00,     0x00 },
254
    { /* HOME */	0x47,   0x47,   0x77,     0x00 },
255
    { /* PAGE UP */	0x49,   0x49,   0x84,     0x00 },
256
    { /* DELETE */	0x53,   0x53,   0x00,     0x00 },
257
    { /* END */		0x4f,   0x4f,   0x75,     0x00 },
258
    { /* PAGE DOWN */	0x51,   0x51,   0x76,     0x00 },
259
 
260
    { /* UP ARROW */	0x48,   0x48,   0x00,     0x00 },
261
    { /* LEFT ARROW */	0x4b,   0x4b,   0x73,     0x00 },
262
    { /* DOWN ARROW */	0x50,   0x50,   0x00,     0x00 },
263
    { /* RIGHT ARROW */	0x4d,   0x4d,   0x74,     0x00 },
264
};
265
 
266
#define MAX_NT_FKMAP	ARRAY_SIZE (NT_KFMap)
267
#endif
268
 
269
/* Function Key table */
270
 
271
static struct Key_Fun_List {
272
    char		*kf_name;
273
    unsigned char	akey;
274
    unsigned char	fkey;
275
    unsigned char	fcode;
276
} KF_List[] = {
277
    { "ScanBackward",	0,	'I',	KF_SCANBACKWARD },
278
    { "ScanForeward",	0,	'Q',	KF_SCANFOREWARD },
279
    { "Previous",	0,	'H',	KF_PREVIOUS },
280
    { "Next",		0,	'P',	KF_NEXT },
281
    { "Left",		0,	'K',	KF_LEFT },
282
    { "Right",		0,	'M',	KF_RIGHT },
283
    { "WordRight",	0,	't',	KF_WORDRIGHT },
284
    { "WordLeft",	0,	's',	KF_WORDLEFT },
285
    { "Start",		0,	'G',	KF_START },
286
    { "Clear",		0x0ff,	'v',	KF_CLEAR },
287
    { "Flush",		0,	'u',	KF_FLUSH },
288
    { "End",		0,	'O',	KF_END },
289
    { "Insert",		0,	'R',	KF_INSERT },
290
    { "DeleteRight",	0,	'S',	KF_DELETERIGHT },
291
    { "DeleteLeft",	CHAR_BACKSPACE,	0,	KF_DELETELEFT },
292
    { "Complete",	0,	'w',	KF_COMPLETE },
293
    { "Directory",	0,	0x0f,	KF_DIRECTORY },
294
    { "ClearScreen",	0,	0x84,	KF_CLEARSCREEN },
295
    { "Jobs",		0,	0x68,	KF_JOBS },
296
    { "Transpose",	0x14,	0,	KF_TRANSPOSE },
297
    { "Quote",		0x11,	0,	KF_QUOTE },
298
 
299
/* End of function keys - flags */
300
 
301
    { "Bell",		1,	0,	KF_RINGBELL },
302
    { "HalfHeight",	0,	0,	KF_HALFHEIGTH },
303
    { "InsertMode",	0,	0,	KF_INSERTMODE },
304
    { "InsertCursor",	1,	0,	KF_INSERTCURSOR },
305
    { "RootDrive",	0,	0,	KF_ROOTDRIVE },
306
    { "EOFKey",		4,	0,	KF_EOFKEY },
307
};
308
 
309
/* Arrary of history Items */
310
 
311
static struct cmd_history	*cmd_history = (struct cmd_history *)NULL;
312
 
313
/*
314
 * Processing standard input.  Editting is only supported on OS/2 at the
315
 * moment.
316
 */
317
 
318
int GetConsoleInput (void)
319
{
320
    bool	console = C2bool (IS_Console (0));
321
    int		RetVal = 0;
322
 
323
/* Has dofc set the flag to say use the console buffer ? */
324
 
325
    if (UseConsoleBuffer)
326
    {
327
	UseConsoleBuffer = FALSE;
328
	SaveHistory = TRUE;
329
	SaveCurrentHistory ();
330
	SaveHistory = FALSE;
331
    }
332
 
333
/*
334
 * Read in a line from the console
335
 */
336
 
337
    else
338
    {
339
 
340
/* Set to last history item */
341
 
342
	if (FL_TEST (FLAG_INTERACTIVE) || (IS_TTY (0) && IS_TTY (1)))
343
	    SaveCurrentHistory ();
344
 
345
/* Zap the line and output the prompt.  Save history status info */
346
 
347
	memset (ConsoleLineBuffer, 0, LINE_MAX + 1);
348
 
349
	if (FL_TEST (FLAG_INTERACTIVE) || (IS_TTY (0) && IS_TTY (1)))
350
	{
351
	    bool	o_SaveHistory = SaveHistory;
352
 
353
	    OutputUserPrompt (LastUserPrompt);
354
	    SaveHistory = o_SaveHistory;
355
	}
356
 
357
/* Only if we are working on the console and not via a pipe or file do we
358
 * need to set up the console
359
 */
360
 
361
	if (console)
362
	{
363
	    CheckKeyboardPolling ();
364
 
365
	    if (ChangeInitLoad)
366
	    {
367
		ChangeInitLoad = FALSE;
368
		Configure_Keys ();
369
	    }
370
 
371
	    GetScreenParameters ();
372
	}
373
 
374
/*
375
 * Process the input.  If this is not the console, read from standard input
376
 */
377
 
378
	if (!console)
379
	    RetVal = GetLineFromDevice ();
380
 
381
	else 
382
	{
383
	    ChangeKeyboardMode (FALSE);
384
 
385
#if defined (FLAGS_VI) || defined (FLAGS_EMACS) || defined (FLAGS_GMACS)
386
	    if (ShellGlobalFlags & FLAGS_EDITORS)
387
		RetVal = EditorInput ();
388
 
389
	    else
390
#endif
391
		GetLineFromConsole ();
392
 
393
	    ChangeKeyboardMode (TRUE);
394
	}
395
 
396
	if (LastUserPrompt == PS1)
397
	    LastUserPrompt = PS2;
398
 
399
/* Clean up */
400
 
401
	FlushStreams ();
402
 
403
	if (console)
404
	    SetCursorShape (FALSE);
405
    }
406
 
407
/* Return any errors */
408
 
409
    if (RetVal < 0)
410
        return 0;
411
 
412
/* If we are reading from the console, check for end of file.  From file or
413
 * pipe, we detect this differently
414
 */
415
 
416
    if (console)
417
    {
418
	if (*ConsoleLineBuffer == (char)KF_List[KF_EOFKEY].akey)
419
	    *ConsoleLineBuffer = 0;
420
 
421
	else
422
	    strcat (ConsoleLineBuffer, LIT_NewLine);
423
    }
424
 
425
    return strlen (ConsoleLineBuffer);
426
}
427
 
428
/*
429
 * Read a line from a file or pipe - well pipe really.
430
 */
431
 
432
static int F_LOCAL GetLineFromDevice (void)
433
{
434
    while (fgets (ConsoleLineBuffer, LINE_MAX, stdin) != (char *)NULL)
435
    {
436
	if (*ConsoleLineBuffer != CHAR_HISTORY)
437
	    return 0;
438
 
439
	else if (Process_History (0))
440
	{
441
	    puts (ConsoleLineBuffer);
442
	    return 0;
443
	}
444
    }
445
 
446
/* EOF detected - return that fact */
447
 
448
    return -1;
449
}
450
 
451
/*
452
 * Read line from Console
453
 */
454
 
455
static void F_LOCAL GetLineFromConsole (void)
456
{
457
    unsigned char	a_key = 0, f_key;
458
    int			i;
459
 
460
/* Process the input */
461
 
462
    for ( ; ; )
463
    {
464
	InitialiseInput ((bool)KF_List[KF_INSERTMODE].akey);
465
 
466
	while (((a_key = ReadKeyBoard (&f_key)) != KF_List[KF_EOFKEY].akey) &&
467
	       (a_key != CHAR_NEW_LINE) && (a_key != CHAR_RETURN))
468
	{
469
 
470
/* Handle Resize event */
471
 
472
	    if (a_key == KT_RESIZE)
473
	    {
474
		fputchar (CHAR_NEW_LINE);
475
		GetScreenParameters ();
476
		OutputUserPrompt (LastUserPrompt);
477
		ReDisplayInputLine ();
478
		continue;
479
	    }
480
 
481
/* Look up the keystroke to see if it is one of our functions */
482
 
483
        i = LookUpKeyBoardFunction (a_key, f_key);
484
	    if ( !i )
485
		continue;
486
 
487
	    if (((i > 0) ? ProcessAlphaNumericKey (i)
488
	    		 : ProcessFunctionKey ((-i) - 1)))
489
		ReDisplayInputLine ();
490
 
491
/* Handle a special case on insert mode on line 25 */
492
 
493
	    if ((InsertMode) && (MaxLength > OldMaxLength) &&
494
		(((StartCursorPosition + MaxLength) / MaximumColumns)
495
			== MaximumLines) &&
496
		(((StartCursorPosition + MaxLength) % MaximumColumns) == 0))
497
		StartCursorPosition -= MaximumColumns;
498
 
499
/* Reposition the cursor */
500
 
501
	    GenerateNewCursorPosition ();
502
 
503
/* Save old line length */
504
 
505
	    OldMaxLength = MaxLength;
506
	}
507
 
508
/* Terminate the line */
509
 
510
	*(c_buffer_pos = EndOfCurrentLine) = 0;
511
	GenerateNewCursorPosition ();
512
	fputchar (CHAR_NEW_LINE);
513
	StartCursorPosition = -1;
514
	FlushStreams ();
515
 
516
/* Line input - check for history */
517
 
518
	if ((*ConsoleLineBuffer == CHAR_HISTORY) && Process_History (0))
519
	{
520
	    puts (ConsoleLineBuffer);
521
	    break;
522
	}
523
 
524
	else if (*ConsoleLineBuffer != CHAR_HISTORY)
525
	    break;
526
    }
527
 
528
    if (a_key == KF_List[KF_EOFKEY].akey)
529
	*EndOfCurrentLine = KF_List[KF_EOFKEY].akey;
530
}
531
 
532
/*
533
 * Handler Alpha_numeric characters
534
 */
535
 
536
static bool F_LOCAL ProcessAlphaNumericKey (int c)
537
{
538
    bool	redisplay = FALSE;
539
 
540
/* Normal character processing */
541
 
542
    if ((c_buffer_pos - ConsoleLineBuffer) == LINE_MAX)
543
	return RingWarningBell ();
544
 
545
    else if (!InsertMode)
546
    {
547
	if (c_buffer_pos == EndOfCurrentLine)
548
	    ++EndOfCurrentLine;
549
 
550
	else if (iscntrl (*c_buffer_pos) || iscntrl (c))
551
	    redisplay = TRUE;
552
 
553
	*(c_buffer_pos++) = (char)c;
554
 
555
	if (redisplay || (c == CHAR_TAB))
556
	    return TRUE;
557
 
558
/* Output the character */
559
 
560
	OutputACharacter (c);
561
	return FALSE;
562
    }
563
 
564
    else
565
	return InsertACharacter (c);
566
}
567
 
568
/* Process function keys */
569
 
570
static bool F_LOCAL ProcessFunctionKey (int fn)
571
{
572
    bool	fn_search = FALSE;
573
    char	tmp;
574
 
575
    switch (fn)
576
    {
577
	case KF_SCANBACKWARD:		/* Scan backwards in history	*/
578
	case KF_SCANFOREWARD:		/* Scan forewards in history	*/
579
	    *EndOfCurrentLine = 0;
580
 
581
	    if (M_length == -1)
582
		M_length = strlen (ConsoleLineBuffer);
583
 
584
	    PageHistoryRecord ((fn == KF_SCANBACKWARD) ? -1 : 1);
585
	    return TRUE;
586
 
587
	case KF_PREVIOUS:		/* Previous command		*/
588
	    *EndOfCurrentLine = 0;
589
	    Process_History (-1);
590
	    return TRUE;
591
 
592
	case KF_NEXT:			/* Next command line		*/
593
	    Process_History (1);
594
	    return TRUE;
595
 
596
	case KF_LEFT:			/* Cursor left			*/
597
	    if (c_buffer_pos != ConsoleLineBuffer)
598
		--c_buffer_pos;
599
 
600
	    else
601
		RingWarningBell ();
602
 
603
	    return FALSE;
604
 
605
	case KF_RIGHT:			/* Cursor right			*/
606
	    if (c_buffer_pos != EndOfCurrentLine)
607
		++c_buffer_pos;
608
 
609
	    else
610
		RingWarningBell ();
611
 
612
	    return FALSE;
613
 
614
	case KF_WORDLEFT:		/* Cursor left a word		*/
615
	    if (c_buffer_pos != ConsoleLineBuffer)
616
	    {
617
		--c_buffer_pos;		/* Reposition on previous char	*/
618
 
619
		while (isspace (*c_buffer_pos) &&
620
		       (c_buffer_pos != ConsoleLineBuffer))
621
		    --c_buffer_pos;
622
 
623
		while (!isspace (*c_buffer_pos) &&
624
		       (c_buffer_pos != ConsoleLineBuffer))
625
		    --c_buffer_pos;
626
 
627
		if (c_buffer_pos != ConsoleLineBuffer)
628
		    ++c_buffer_pos;
629
	    }
630
 
631
	    else
632
		RingWarningBell ();
633
 
634
	    return FALSE;
635
 
636
	case KF_WORDRIGHT:		/* Cursor right a word		*/
637
	    if (c_buffer_pos != EndOfCurrentLine)
638
	    {
639
 
640
/* Skip to the end of the current word */
641
 
642
		while (!isspace (*c_buffer_pos) &&
643
		       (c_buffer_pos != EndOfCurrentLine))
644
		    ++c_buffer_pos;
645
 
646
/* Skip over the white space */
647
 
648
		while (isspace (*c_buffer_pos) &&
649
		       (c_buffer_pos != EndOfCurrentLine))
650
		    ++c_buffer_pos;
651
	    }
652
 
653
	    else
654
		RingWarningBell ();
655
 
656
	    return FALSE;
657
 
658
	case KF_START:			/* Cursor home			*/
659
	    c_buffer_pos = ConsoleLineBuffer;
660
	    return FALSE;
661
 
662
	case KF_CLEAR:			/* Erase buffer			*/
663
	    c_buffer_pos = ConsoleLineBuffer;
664
 
665
	case KF_FLUSH:			/* Flush to end			*/
666
	    memset (c_buffer_pos, CHAR_SPACE, EndOfCurrentLine - c_buffer_pos);
667
	    EndOfCurrentLine = c_buffer_pos;
668
	    return TRUE;
669
 
670
	case KF_END:			/* Cursor end of command	*/
671
	    if (*ConsoleLineBuffer == CHAR_HISTORY)
672
	    {
673
		*EndOfCurrentLine = 0;
674
		Process_History (2);
675
		return TRUE;
676
	    }
677
 
678
	    c_buffer_pos = EndOfCurrentLine;
679
	    return FALSE;
680
 
681
	case KF_INSERT:			/* Switch insert mode		*/
682
	    InsertMode = C2bool (!InsertMode);
683
	    SetCursorShape (InsertMode);
684
	    return FALSE;
685
 
686
	case KF_CLEARSCREEN:		/* Clear the screen		*/
687
	    return ClearScreen ();
688
 
689
	case KF_TRANSPOSE:		/* Transpose characters		*/
690
	    if(c_buffer_pos == ConsoleLineBuffer)
691
		return RingWarningBell ();
692
 
693
	    if (c_buffer_pos == EndOfCurrentLine)
694
		--c_buffer_pos;
695
 
696
	    tmp = *(c_buffer_pos - 1);
697
	    *(c_buffer_pos - 1) = *c_buffer_pos;
698
	    *c_buffer_pos = tmp;
699
 
700
	    if (c_buffer_pos != EndOfCurrentLine)
701
		++c_buffer_pos;
702
 
703
	    return TRUE;
704
 
705
	case KF_QUOTE:			/* Quote characters		*/
706
	    return ProcessAlphaNumericKey ((int)ReadKeyBoard ((unsigned char *)&tmp));
707
 
708
#if (OS_TYPE != OS_DOS)
709
	case KF_JOBS:			/* Print Job Tree		*/
710
	    fputchar (CHAR_NEW_LINE);
711
#  if (OS_TYPE == OS_NT)
712
	    PrintJobs (TRUE);
713
#  else
714
	    PrintProcessTree (getpid ());
715
#  endif
716
	    OutputUserPrompt (LastUserPrompt);
717
	    StartCursorPosition = ReadCursorPosition ();
718
	    return TRUE;
719
#endif
720
 
721
	case KF_DELETERIGHT:		/* Delete right character	*/
722
	    if (c_buffer_pos == EndOfCurrentLine)
723
		return FALSE;
724
 
725
	    memcpy (c_buffer_pos, c_buffer_pos + 1,
726
		    EndOfCurrentLine - c_buffer_pos);
727
 
728
	    if (EndOfCurrentLine == ConsoleLineBuffer)
729
	    {
730
		RingWarningBell ();
731
		return TRUE;
732
	    }
733
 
734
	    if (--EndOfCurrentLine < c_buffer_pos)
735
		--c_buffer_pos;
736
 
737
   	    return TRUE;
738
 
739
	case KF_DIRECTORY:		/* File name directory		*/
740
	    fn_search = TRUE;
741
 
742
	case KF_COMPLETE:		/* File name completion		*/
743
	{
744
	    *EndOfCurrentLine = 0;
745
	    return CompleteFileName (c_buffer_pos, fn_search);
746
	}
747
 
748
	case KF_DELETELEFT:		/* Delete left character	*/
749
	    if (c_buffer_pos == ConsoleLineBuffer)
750
		return RingWarningBell ();
751
 
752
/* Decrement current position */
753
 
754
	    --c_buffer_pos;
755
	    memcpy (c_buffer_pos, c_buffer_pos + 1,
756
		    EndOfCurrentLine - c_buffer_pos);
757
	    --EndOfCurrentLine;
758
	    return TRUE;
759
    }
760
 
761
    return FALSE;
762
}
763
 
764
/* Set cursor shape */
765
 
766
#if (OS_TYPE == OS_OS2)
767
void	SetCursorShape (bool mode)
768
{
769
    VIOCURSORINFO	viociCursor;
770
 
771
    VioGetCurType (&viociCursor, 0);
772
 
773
    if (mode && KF_List[KF_INSERTCURSOR].akey)
774
	viociCursor.yStart = (USHORT)((KF_List[KF_HALFHEIGTH].akey
775
					    ? (viociCursor.cEnd / 2) + 1 : 1));
776
 
777
    else
778
	viociCursor.yStart = (USHORT)(viociCursor.cEnd - 1);
779
 
780
    VioSetCurType (&viociCursor, 0);
781
}
782
#endif
783
 
784
/* NT version */
785
 
786
#if (OS_TYPE == OS_NT)
787
void	SetCursorShape (bool mode)
788
{
789
    CONSOLE_CURSOR_INFO		ConsoleCursorInfo;
790
 
791
    GetConsoleCursorInfo (NT_StdOut, &ConsoleCursorInfo);
792
 
793
    if (mode && KF_List[KF_INSERTCURSOR].akey)
794
	ConsoleCursorInfo.dwSize = (KF_List[KF_HALFHEIGTH].akey ? 50 : 90);
795
 
796
    else
797
	ConsoleCursorInfo.dwSize = 10;
798
 
799
    ConsoleCursorInfo.bVisible = TRUE;
800
    SetConsoleCursorInfo (NT_StdOut, &ConsoleCursorInfo);
801
}
802
#endif
803
 
804
/* DOS version */
805
 
806
#if (OS_TYPE == OS_DOS)
807
void	SetCursorShape (bool mode)
808
{
809
    union REGS		r;
810
 
811
/* Get the current cursor position to get the cursor lines */
812
 
813
    r.h.ah = 0x03;
814
    SystemInterrupt (0x10, &r, &r);
815
 
816
/* Reset the type */
817
 
818
    r.h.ah = 0x01;
819
 
820
    if (mode && KF_List[KF_INSERTCURSOR].akey)
821
	r.h.ch = (unsigned char)((KF_List[KF_HALFHEIGTH].akey
822
					? (r.h.cl / 2) + 1 : 1));
823
 
824
    else
825
	r.h.ch = (unsigned char)(r.h.cl - 1);
826
 
827
    SystemInterrupt (0x10, &r, &r);
828
}
829
#endif
830
 
831
/* UNIX version */
832
 
833
#if (OS_TYPE == OS_UNIX)
834
void	SetCursorShape (bool mode)
835
{
836
}
837
#endif
838
 
839
/*
840
 * Read Cursor position
841
 */
842
 
843
#if (OS_TYPE == OS_OS2)
844
int	ReadCursorPosition (void)
845
{
846
    USHORT	usRow;
847
    USHORT	usColumn;
848
 
849
    VioGetCurPos (&usRow, &usColumn, 0);
850
    return (MaximumColumns * usRow) + usColumn;
851
}
852
#endif
853
 
854
/* NT Version */
855
 
856
#if (OS_TYPE == OS_NT)
857
int	ReadCursorPosition (void)
858
{
859
    CONSOLE_SCREEN_BUFFER_INFO	CSI;
860
 
861
    GetConsoleScreenBufferInfo (NT_StdOut, &CSI);
862
 
863
    return (MaximumColumns * CSI.dwCursorPosition.Y) + CSI.dwCursorPosition.X;
864
}
865
#endif
866
 
867
/* DOS Version */
868
 
869
#if (OS_TYPE == OS_DOS) 
870
int	ReadCursorPosition (void)
871
{
872
    union REGS	r;
873
 
874
    FlushStreams ();
875
 
876
    r.h.ah = 0x03;				/* Read cursor position	*/
877
    r.h.bh = 0;					/* Page zero		*/
878
    SystemInterrupt (0x10, &r, &r);
879
    return (r.h.dh * MaximumColumns) + r.h.dl;
880
}
881
#endif
882
 
883
/*
884
 * Re-position the cursor
885
 */
886
 
887
#if (OS_TYPE == OS_OS2)
888
void	SetCursorPosition (int new)
889
{
890
    int		diff;
891
    USHORT	usRow;
892
    USHORT	usColumn;
893
 
894
    FlushStreams ();
895
 
896
    usRow = (USHORT)(new / MaximumColumns);
897
    usColumn = (USHORT)(new % MaximumColumns);
898
 
899
/* Are we at the bottom of the page? */
900
 
901
    if (usRow >= (unsigned char)MaximumLines)
902
    {
903
	diff = usRow + 1 - MaximumLines;
904
	usRow = (unsigned char)(MaximumLines - 1);
905
	StartCursorPosition -= MaximumColumns * diff;
906
    }
907
 
908
    VioSetCurPos (usRow, usColumn, 0);
909
}
910
#endif
911
 
912
/* NT Version */
913
 
914
#if (OS_TYPE == OS_NT)
915
void	SetCursorPosition (int newpos)
916
{
917
    int		diff;
918
    COORD	Cp;
919
 
920
    FlushStreams ();
921
 
922
    Cp.Y = (USHORT)(newpos / MaximumColumns);
923
    Cp.X = (USHORT)(newpos % MaximumColumns);
924
 
925
/* Are we at the bottom of the page? */
926
 
927
    if (Cp.Y >= (USHORT)MaximumLines)
928
    {
929
	diff = Cp.Y + 1 - MaximumLines;
930
	Cp.Y = (USHORT)(MaximumLines - 1);
931
	StartCursorPosition -= MaximumColumns * diff;
932
    }
933
 
934
    SetConsoleCursorPosition (NT_StdOut, Cp);
935
}
936
#endif
937
 
938
/* DOS Version */
939
 
940
#if (OS_TYPE == OS_DOS) 
941
void	SetCursorPosition (int new)
942
{
943
    int		diff;
944
    union REGS	r;
945
 
946
    FlushStreams ();
947
 
948
    r.h.ah = 0x02;				/* Set new position	*/
949
    r.h.bh = 0;					/* Page zero		*/
950
    r.h.dh = (unsigned char)(new / MaximumColumns);
951
    r.h.dl = (unsigned char)(new % MaximumColumns);
952
 
953
/* Are we at the bottom of the page? */
954
 
955
    if (r.h.dh >= (unsigned char)MaximumLines)
956
    {
957
	diff = r.h.dh + 1 - MaximumLines;
958
	r.h.dh = (unsigned char)(MaximumLines - 1);
959
	StartCursorPosition -= MaximumColumns * diff;
960
    }
961
 
962
    SystemInterrupt (0x10, &r, &r);
963
}
964
#endif
965
 
966
/* Erase to end of line (avoid need for STUPID ansi.sys memory eater!) */
967
 
968
#if (OS_TYPE == OS_OS2) 
969
static void F_LOCAL EraseToEndOfLine (void)
970
{
971
    BYTE	abCell[2];
972
    USHORT	usRow;
973
    USHORT	usColumn;
974
    USHORT	cb = sizeof (abCell);
975
 
976
    FlushStreams ();
977
 
978
/* Read attribute under cursor */
979
 
980
    VioGetCurPos (&usRow, &usColumn, 0);
981
    VioReadCellStr (abCell, &cb , usRow, usColumn, 0);
982
 
983
    abCell[0] = CHAR_SPACE;
984
 
985
    if (m_line < (int)usRow)
986
	m_line = usRow;
987
 
988
    if ((cb = MaximumColumns - usColumn +
989
		((m_line - usRow) * MaximumColumns)) > 0)
990
	VioWrtNCell (abCell, cb, usRow, usColumn, 0);
991
}
992
#endif
993
 
994
/* NT Version */
995
 
996
#if (OS_TYPE == OS_NT)
997
static void F_LOCAL EraseToEndOfLine (void)
998
{
999
    WORD			Atts[2];
1000
    CONSOLE_SCREEN_BUFFER_INFO	CSI;
1001
    DWORD			ActionCount;
1002
    DWORD			cb;
1003
    WORD			*ostring;
1004
    DWORD			i;
1005
 
1006
    FlushStreams ();
1007
 
1008
/* Read attribute under cursor */
1009
 
1010
    GetConsoleScreenBufferInfo (NT_StdOut, &CSI);
1011
 
1012
    ReadConsoleOutputAttribute (NT_StdOut, Atts, 1, CSI.dwCursorPosition,
1013
    				&ActionCount);
1014
 
1015
/* How much to write ? */
1016
 
1017
    if (m_line < (int) CSI.dwCursorPosition.Y)
1018
	m_line = CSI.dwCursorPosition.Y;
1019
 
1020
/* Write it.  What a pain!!! */
1021
 
1022
    if ((cb = MaximumColumns - CSI.dwCursorPosition.X +
1023
		((m_line - CSI.dwCursorPosition.Y) * MaximumColumns)) > 0)
1024
    {
1025
	ostring = (WORD *)AllocateMemoryCell (cb * sizeof (WORD));
1026
	memset (ostring, CHAR_SPACE, cb);
1027
 
1028
	WriteConsoleOutputCharacter (NT_StdOut, (char *)ostring, cb,
1029
				     CSI.dwCursorPosition, &ActionCount);
1030
 
1031
/* Set up attributes */
1032
 
1033
    	for (i = 0; i < cb; i++)
1034
	    ostring[i] = Atts[0];
1035
 
1036
	WriteConsoleOutputAttribute (NT_StdOut, ostring, cb,
1037
				     CSI.dwCursorPosition, &ActionCount);
1038
        ReleaseMemoryCell (ostring);
1039
    }
1040
}
1041
#endif
1042
 
1043
/* DOS Version */
1044
 
1045
#if (OS_TYPE == OS_DOS) 
1046
static void F_LOCAL EraseToEndOfLine (void)
1047
{
1048
    union REGS		r;
1049
    unsigned char	backg;
1050
 
1051
    FlushStreams ();
1052
 
1053
/* Get the background attribute of the cursor */
1054
 
1055
    r.h.ah = 0x08;
1056
    r.h.bh = 0;
1057
    SystemInterrupt (0x10, &r, &r);
1058
    backg = (unsigned char)(r.h.ah & 0x07);
1059
 
1060
    r.h.ah = 0x03;
1061
    r.h.bh = 0;
1062
    SystemInterrupt (0x10, &r, &r);
1063
 
1064
/* Check that we use the correct m_line */
1065
 
1066
    if (m_line < (int)r.h.dh)
1067
	m_line = r.h.dh;
1068
 
1069
    if ((r.x.REG_CX = MaximumColumns - r.h.dl +
1070
		      ((m_line - r.h.dh) * MaximumColumns)) > 0)
1071
    {
1072
	r.x.REG_AX = 0x0a20;
1073
	r.x.REG_BX = backg;
1074
	SystemInterrupt (0x10, &r, &r);
1075
    }
1076
}
1077
#endif
1078
 
1079
/* DOS Version */
1080
 
1081
#if (OS_TYPE == OS_UNIX) 
1082
static void F_LOCAL EraseToEndOfLine (void)
1083
{
1084
    fputs ("UNIX: EraseToEndOfLine NI\n", stderr);
1085
}
1086
#endif
1087
 
1088
/*
1089
 * Generate the new cursor position
1090
 */
1091
 
1092
static void F_LOCAL GenerateNewCursorPosition (void)
1093
{
1094
    char	*cp = ConsoleLineBuffer - 1;
1095
    int		off = StartCursorPosition;
1096
 
1097
/* Search to current position */
1098
 
1099
    while (++cp != c_buffer_pos)
1100
    {
1101
	if (*cp == CHAR_TAB)
1102
	    while ((++off) % 8);
1103
 
1104
	else
1105
	    off += (iscntrl (*cp)) ? 2 : 1;
1106
    }
1107
 
1108
/* Position the cursor */
1109
 
1110
    SetCursorPosition (off);
1111
}
1112
 
1113
/* Redisplay the current line */
1114
 
1115
static void F_LOCAL ReDisplayInputLine (void)
1116
{
1117
/* Reposition to start of line */
1118
 
1119
    SetCursorPosition (StartCursorPosition);
1120
 
1121
/* Output the line */
1122
 
1123
    *EndOfCurrentLine = 0;
1124
    DisplayLineWithControl (ConsoleLineBuffer);
1125
 
1126
    if ((m_line = ((StartCursorPosition + MaxLength) / MaximumColumns) + 1) >=
1127
	MaximumLines)
1128
	m_line = MaximumLines - 1;
1129
 
1130
    EraseToEndOfLine ();		/* clear to end of line	*/
1131
    MaxLength = EndOfCurrentLine - ConsoleLineBuffer;
1132
}
1133
 
1134
/* Process history command
1135
 *
1136
 * -1: Previous command
1137
 *  1: Next command
1138
 *  0: Current command
1139
 *  2: Current command with no options processing
1140
 */
1141
 
1142
static bool F_LOCAL Process_History (int direction)
1143
{
1144
    char	*optionals = null;
1145
 
1146
    c_buffer_pos = ConsoleLineBuffer;
1147
    EndOfCurrentLine = ConsoleLineBuffer;
1148
    c_history += (direction == 2) ? 0 : direction;
1149
 
1150
    switch (direction)
1151
    {
1152
	case -1:			/* Move up one line		*/
1153
	    if (c_history < 0)
1154
	    {
1155
		c_history = -1;
1156
		return ReStartInput (No_prehistory);
1157
	    }
1158
 
1159
	    break;
1160
 
1161
	case 1:				/* Move to next history line	*/
1162
	    if (c_history >= l_history)
1163
	    {
1164
		c_history = l_history;
1165
		return ReStartInput (No_posthistory);
1166
	    }
1167
 
1168
	    break;
1169
 
1170
	case 0:				/* Check out ConsoleLineBuffer	*/
1171
	    optionals = ConsoleLineBuffer;/* Are there any additions to	*/
1172
					/* the history line		*/
1173
 
1174
/* Find the end of the first part */
1175
 
1176
	    while (!isspace (*optionals) && *optionals)
1177
	    {
1178
		if (*optionals == CHAR_HISTORY)
1179
		{
1180
 
1181
/* Terminate at !! */
1182
 
1183
		    if (*(optionals + 1) == CHAR_HISTORY)
1184
		    {
1185
			optionals += 2;
1186
			break;
1187
		    }
1188
 
1189
/* Terminate at a numeric value */
1190
 
1191
		    else if (isdigit (*(optionals + 1)) ||
1192
			     (*(optionals + 1) == '-'))
1193
		    {
1194
			optionals += 2;
1195
			while (isdigit (*optionals))
1196
			    ++optionals;
1197
 
1198
			break;
1199
		    }
1200
		}
1201
 
1202
		++optionals;
1203
	    }
1204
 
1205
/* Copy selected item into line buffer */
1206
 
1207
	case 2:
1208
	    M_length = (optionals == null) ? strlen (ConsoleLineBuffer) - 1
1209
					   : optionals - ConsoleLineBuffer - 1;
1210
 
1211
	    if (!ScanHistory ())
1212
		return FALSE;
1213
 
1214
	    break;
1215
    }
1216
 
1217
    return UpdateConsoleInputLine (optionals);
1218
}
1219
 
1220
/* Ok c_history points to the new line.  Move optionals after history
1221
 * and the copy in history and add a space
1222
 */
1223
 
1224
static bool F_LOCAL UpdateConsoleInputLine (char *optionals)
1225
{
1226
    int		opt_len;
1227
 
1228
    EndOfCurrentLine = &ConsoleLineBuffer[strlen (cmd_history[c_history].command)];
1229
 
1230
    if ((EndOfCurrentLine - ConsoleLineBuffer +
1231
	 (opt_len = strlen (optionals)) + 1) >= LINE_MAX)
1232
	return ReStartInput (History_2long);
1233
 
1234
    if (EndOfCurrentLine > optionals)
1235
	memrcpy (EndOfCurrentLine + opt_len, optionals + opt_len, opt_len + 1);
1236
 
1237
    else
1238
	strcpy (EndOfCurrentLine, optionals);
1239
 
1240
    strncpy (ConsoleLineBuffer, cmd_history[c_history].command,
1241
	     (EndOfCurrentLine - ConsoleLineBuffer));
1242
    EndOfCurrentLine = &ConsoleLineBuffer[strlen (ConsoleLineBuffer)];
1243
    c_buffer_pos = EndOfCurrentLine;
1244
    return TRUE;
1245
}
1246
 
1247
/* Scan the line buffer for a history match */
1248
 
1249
static bool F_LOCAL ScanHistory (void)
1250
{
1251
    char	*cp = ConsoleLineBuffer + 1;
1252
    char	*ep;
1253
    int		i = (int)strtol (cp, &ep, 10);
1254
 
1255
/* Get the previous command ? (single ! or double !!) */
1256
 
1257
    if ((M_length == 0) || (*cp == CHAR_HISTORY))
1258
    {
1259
	if (c_history >= l_history)
1260
	    c_history = l_history - 1;
1261
 
1262
	if (c_history < 0)
1263
	    return ReStartInput (No_prehistory);
1264
 
1265
	return TRUE;
1266
    }
1267
 
1268
/* Request for special history number item.  Check History file empty */
1269
 
1270
    if (l_history == 0)
1271
	return ReStartInput (No_MatchHistory);
1272
 
1273
/* Check for number */
1274
 
1275
    if ((*ConsoleLineBuffer == CHAR_HISTORY) && (ep > cp) && M_length)
1276
    {
1277
	M_length = -1;
1278
 
1279
	for (c_history = l_history - 1;
1280
	    (c_history >= 0) && (cmd_history[c_history].number != i);
1281
	    --c_history)
1282
	    continue;
1283
    }
1284
 
1285
/* No - scan for a match */
1286
 
1287
    else
1288
    {
1289
	for (c_history = l_history - 1;
1290
	     (c_history >= 0) &&
1291
	     (strncmp (cp, cmd_history[c_history].command, M_length) != 0);
1292
	     --c_history)
1293
	    continue;
1294
    }
1295
 
1296
/* Anything found ? */
1297
 
1298
    if (c_history == -1)
1299
    {
1300
	c_history = l_history - 1;
1301
	return ReStartInput (No_MatchHistory);
1302
    }
1303
 
1304
    return TRUE;
1305
}
1306
 
1307
/*
1308
 * Get record associated with event
1309
 */
1310
 
1311
char	*GetHistoryRecord (int event)
1312
{
1313
    int		i = l_history - 1;
1314
 
1315
    while (i >= 0)
1316
    {
1317
        if (cmd_history[i].number == event)
1318
	    return cmd_history[i].command;
1319
 
1320
	--i;
1321
    }
1322
 
1323
    return (char *)NULL;
1324
}
1325
 
1326
/*
1327
 * Scan back or forward from current history
1328
 */
1329
 
1330
static void F_LOCAL PageHistoryRecord (int direction)
1331
{
1332
    c_buffer_pos = ConsoleLineBuffer;
1333
    EndOfCurrentLine = ConsoleLineBuffer;
1334
 
1335
    if (l_history == 0)
1336
    {
1337
	ReStartInput (No_MatchHistory);
1338
	return;
1339
    }
1340
 
1341
/* scan for a match */
1342
 
1343
    while (((c_history += direction) >= 0) && (c_history != l_history) &&
1344
	   (strncmp (ConsoleLineBuffer, cmd_history[c_history].command,
1345
		     M_length) != 0))
1346
	continue;
1347
 
1348
/* Anything found ? */
1349
 
1350
    if ((c_history < 0) || (c_history >= l_history))
1351
    {
1352
	c_history = l_history - 1;
1353
	ReStartInput (No_MatchHistory);
1354
    }
1355
 
1356
    else
1357
	UpdateConsoleInputLine (null);
1358
}
1359
 
1360
/* Load history file */
1361
 
1362
void LoadHistory (void)
1363
{
1364
    FILE		*fp;
1365
    char		*cp;
1366
    int			i = 0;
1367
    bool		Append = FALSE;
1368
 
1369
/* Initialise history array */
1370
 
1371
    c_history = -1;			/* Current entry		*/
1372
    l_history = 0;			/* End of history array		*/
1373
 
1374
    if (GetVariableAsString (HistoryFileVariable, FALSE) == null)
1375
    {
1376
	SetVariableFromString (HistoryFileVariable,
1377
			       (cp = BuildFileName ("history.sh")));
1378
	ReleaseMemoryCell ((void *)cp);
1379
    }
1380
 
1381
    if (GetVariableAsString (HistorySizeVariable, FALSE) == null)
1382
	SetVariableFromNumeric (HistorySizeVariable, 100L);
1383
 
1384
    if ((fp = OpenHistoryFile (sOpenReadMode)) == (FILE *)NULL)
1385
	return;
1386
 
1387
/* Read in file */
1388
 
1389
    cp = ConsoleLineBuffer;
1390
 
1391
    while ((i = fgetc (fp)) != EOF)
1392
    {
1393
	if (i == 0)
1394
	{
1395
	    *cp = 0;
1396
	    cp = ConsoleLineBuffer;
1397
	    AddHistory (Append);
1398
	    Append = FALSE;
1399
	}
1400
 
1401
	else if (i == CHAR_NEW_LINE)
1402
	{
1403
	    *cp = 0;
1404
	    cp = ConsoleLineBuffer;
1405
	    AddHistory (Append);
1406
	    Append = TRUE;
1407
	}
1408
 
1409
	else if ((cp - ConsoleLineBuffer) < LINE_MAX - 2)
1410
	    *(cp++) = (char)i;
1411
    }
1412
 
1413
    CloseFile (fp);
1414
}
1415
 
1416
/* Open the history file */
1417
 
1418
static FILE * F_LOCAL OpenHistoryFile (const char *mode)
1419
{
1420
#if (OS_TYPE != OS_UNIX)
1421
    char        tname[ MAX_PATH ];
1422
#endif
1423
    const char  *name;
1424
 
1425
    if (!HistoryEnabled)
1426
	return (FILE *)NULL;
1427
 
1428
    name = CheckDOSFileName (
1429
                GetVariableAsString (HistoryFileVariable, FALSE), tname);
1430
    return FOpenFile (name, mode);
1431
}
1432
 
1433
/* Add entry to history file */
1434
 
1435
void AddHistory (bool AppendToLast)
1436
{
1437
    char		*cp;
1438
    struct cmd_history	*cmd;
1439
    size_t		Len;
1440
    int			HistorySize;
1441
 
1442
/* Clean up console buffer */
1443
 
1444
    CleanUpBuffer (strlen (ConsoleLineBuffer), ConsoleLineBuffer, GetEOFKey ());
1445
 
1446
/*
1447
 * Ignore if no history or blank line
1448
 */
1449
 
1450
    if ((!HistoryEnabled) || (strlen (ConsoleLineBuffer) == 0))
1451
	return;
1452
 
1453
/* Has the size changed ? */
1454
 
1455
    HistorySize = (int)GetVariableAsNumeric (HistorySizeVariable);
1456
 
1457
    if (HistorySize != CurrentHistorySize)
1458
    {
1459
 
1460
/* Zero - empty history */
1461
 
1462
	if (!HistorySize)
1463
	    ClearHistory ();
1464
 
1465
/* Allocate a new buffer */
1466
 
1467
	else if ((cmd = (struct cmd_history *)GetAllocatedSpace
1468
			    (sizeof (struct cmd_history) * HistorySize)) ==
1469
		   (struct cmd_history *)NULL)
1470
	    /* DO NOTHING IF NO MEMORY */;
1471
 
1472
/* If new buffer is bigger, copy old to new and release */
1473
 
1474
	else if ((HistorySize > CurrentHistorySize) ||
1475
		 (l_history < HistorySize))
1476
	{
1477
	    if (cmd_history != (struct cmd_history *)NULL)
1478
	    {
1479
		int	Clen;
1480
 
1481
/* Calculate the length to copy */
1482
 
1483
		Clen = (HistorySize > CurrentHistorySize)
1484
			? CurrentHistorySize : l_history;
1485
 
1486
		memcpy (cmd, cmd_history,
1487
			sizeof (struct cmd_history) * Clen);
1488
 
1489
/* Set up new values */
1490
 
1491
		ReleaseMemoryCell (cmd_history);
1492
	    }
1493
 
1494
	    CurrentHistorySize = HistorySize;
1495
	    SetMemoryAreaNumber ((void *)(cmd_history = cmd), 0);
1496
	}
1497
 
1498
/* Less space is available, copy reduced area and update entry numbers */
1499
 
1500
	else
1501
	{
1502
	    int		i = (CurrentHistorySize - HistorySize);
1503
 
1504
/* Free entries at bottom */
1505
 
1506
	    for (Len = 0; (Len < (size_t)i) && (Len < (size_t)l_history); Len++)
1507
		ReleaseCommandMemory (&cmd_history[Len]);
1508
 
1509
/* Transfer entries at top */
1510
 
1511
	    memcpy (cmd, &cmd_history[i],
1512
		    sizeof (struct cmd_history) * HistorySize);
1513
 
1514
/* Update things */
1515
 
1516
	    if ((c_history -= i) < -1)
1517
		c_history = -1;
1518
 
1519
	    if ((l_history -= i) < 0)
1520
		l_history = 0;
1521
 
1522
/* Set up new values */
1523
 
1524
	    ReleaseMemoryCell (cmd_history);
1525
	    CurrentHistorySize = HistorySize;
1526
	    SetMemoryAreaNumber ((void *)(cmd_history = cmd), 0);
1527
	}
1528
    }
1529
 
1530
/* If there is no history space - return */
1531
 
1532
    if (!CurrentHistorySize)
1533
	return;
1534
 
1535
/* If the array is full, remove the last item */
1536
 
1537
    if (l_history == CurrentHistorySize)
1538
    {
1539
	ReleaseCommandMemory (&cmd_history[0]);
1540
 
1541
	--l_history;
1542
	memcpy (&cmd_history[0], &cmd_history[1],
1543
		sizeof (struct cmd_history) * (CurrentHistorySize - 1));
1544
    }
1545
 
1546
/* Save the string.  Is this a PS2 prompt */
1547
 
1548
    if ((AppendToLast) && l_history)
1549
    {
1550
	cmd = &cmd_history[l_history - 1];
1551
 
1552
/* Check length */
1553
 
1554
	if ((Len = strlen (cmd->command) + strlen (ConsoleLineBuffer) + 2)
1555
	    >= LINE_MAX)
1556
	{
1557
	    fprintf (stderr, BasicErrorMessage, LIT_history, History_2long);
1558
	    return;
1559
	}
1560
 
1561
/* Append to buffer, reallocate to new length */
1562
 
1563
	if ((cp = GetAllocatedSpace (Len)) == (char *)NULL)
1564
	    return;
1565
 
1566
	sprintf (cp, "%s\n%s", cmd->command, ConsoleLineBuffer);
1567
 
1568
	ReleaseCommandMemory (cmd);
1569
	cmd->command = cp;
1570
	SetMemoryAreaNumber ((void *)cp, 0);
1571
    }
1572
 
1573
/* Save the command line */
1574
 
1575
    else
1576
    {
1577
	Current_Event = GetLastHistoryEvent ();
1578
	cmd_history[l_history].number = Current_Event;
1579
 
1580
	cmd_history[l_history].command = StringSave (ConsoleLineBuffer);
1581
	c_history = ++l_history;
1582
    }
1583
}
1584
 
1585
/*
1586
 * Dump history to file
1587
 */
1588
 
1589
void DumpHistory (void)
1590
{
1591
    struct cmd_history	*cp = cmd_history;
1592
    FILE		*fp;
1593
    int			i;
1594
 
1595
/* If history is not enabled or we can't open the file, give up */
1596
 
1597
    if ((!HistoryEnabled) ||
1598
	((fp = OpenHistoryFile (sOpenWriteMode)) == (FILE *)NULL))
1599
	return;
1600
 
1601
/* Write history as a null terminated record */
1602
 
1603
    for (i = 0; i < l_history; ++cp, ++i)
1604
    {
1605
        fputs (cp->command, fp);
1606
	fputc (0, fp);
1607
    }
1608
 
1609
    CloseFile (fp);
1610
}
1611
 
1612
/* Clear out history */
1613
 
1614
void ClearHistory (void)
1615
{
1616
    int			i;
1617
    struct cmd_history	*cp = cmd_history;
1618
 
1619
/* Release the entries */
1620
 
1621
    for (i = 0; i < l_history; ++cp, ++i)
1622
	ReleaseCommandMemory (cp);
1623
 
1624
    ReleaseMemoryCell (cmd_history);
1625
 
1626
/* Reset data information */
1627
 
1628
    c_history = -1;			/* Current entry		*/
1629
    l_history = 0;			/* End of history array		*/
1630
    Current_Event = 0;
1631
    CurrentHistorySize = 0;
1632
    cmd_history = (struct cmd_history *)NULL;
1633
}
1634
 
1635
/* Output warning message and prompt */
1636
 
1637
static bool F_LOCAL ReStartInput (char *cp)
1638
{
1639
    if (cp != (char *)NULL)
1640
    {
1641
	if (!IS_Console (1) ||
1642
	    (strlen (ConsoleLineBuffer) && (StartCursorPosition != -1)))
1643
	    feputc (CHAR_NEW_LINE);
1644
 
1645
	PrintWarningMessage (BasicErrorMessage, LIT_history, cp);
1646
 
1647
	if (IS_Console (1))
1648
	    EraseToEndOfLine ();
1649
 
1650
	fputchar (CHAR_NEW_LINE);
1651
    }
1652
 
1653
    OutputUserPrompt (LastUserPrompt);
1654
 
1655
/* Re-initialise */
1656
 
1657
    InitialiseInput (InsertMode);
1658
    return FALSE;
1659
}
1660
 
1661
/* Copy backwards */
1662
 
1663
static void F_LOCAL memrcpy (char *sp1, const char *sp, int cnt)
1664
{
1665
    while (cnt--)
1666
	*(sp1--) = *(sp--);
1667
}
1668
 
1669
/* Complete Filename functions */
1670
 
1671
static bool F_LOCAL CompleteFileName (char *InsertPosition, bool Searching)
1672
{
1673
    int			NumberOfMatches = 0;
1674
    char		*SearchString = null;
1675
    char		*NameStart = InsertPosition;
1676
    char		*StartDirInCLB;
1677
    size_t		MatchStringLen = 0;
1678
    char		*cp;
1679
    int			i;
1680
    size_t		maxi;
1681
    bool		InsertSpace = TRUE;
1682
    char		**FileList;
1683
 
1684
/* Space or at start of line - use NULL file name */
1685
 
1686
    if ((NameStart != ConsoleLineBuffer) && isspace (*NameStart) &&
1687
	!isspace (*(NameStart - 1)))
1688
    {
1689
	--NameStart;
1690
	InsertSpace = FALSE;
1691
    }
1692
 
1693
    if (!isspace (*NameStart))
1694
    {
1695
	while (!isspace (*NameStart) && (NameStart != ConsoleLineBuffer))
1696
	    --NameStart;
1697
 
1698
	if (isspace (*NameStart))
1699
	    ++NameStart;
1700
 
1701
	MatchStringLen = InsertPosition - NameStart;
1702
 
1703
	if ((SearchString = AllocateMemoryCell (MatchStringLen + 1)) ==
1704
						(char *)NULL)
1705
	    return RingWarningBell ();
1706
 
1707
	memcpy (SearchString, NameStart, MatchStringLen);
1708
    }
1709
 
1710
/* Find the directory name */
1711
 
1712
    if ((cp = FindLastPathCharacter (SearchString)) != (char *)NULL)
1713
	StartDirInCLB = NameStart + (int)(cp - SearchString + 1);
1714
 
1715
/* No directory flag - Drive specifier? */
1716
 
1717
    else if ((strlen (SearchString) > (size_t)1) &&
1718
	     IsDriveCharacter (*(SearchString + 1)))
1719
	StartDirInCLB = NameStart + 2;
1720
 
1721
/* No drive specifier */
1722
 
1723
    else
1724
	StartDirInCLB = NameStart;
1725
 
1726
    FileList = BuildCompletionList (SearchString, strlen (SearchString),
1727
				    &NumberOfMatches, FALSE);
1728
 
1729
    if (SearchString != null)
1730
        ReleaseMemoryCell ((void *)SearchString);
1731
 
1732
/* If there are no matches, Just ring the bell */
1733
 
1734
    if (FileList == (char **)NULL)
1735
	return RingWarningBell ();
1736
 
1737
/* At this point, we have some data.  If we are searching, sort the
1738
 * filenames and display them.  Remember to release the memory allocated for
1739
 * the word block and its entries.
1740
 */
1741
 
1742
    if (Searching)
1743
    {
1744
 
1745
/* Sort the file names and display them */
1746
 
1747
	qsort (&FileList[0], NumberOfMatches, sizeof (char *), SortCompare);
1748
 
1749
/* Display. */
1750
 
1751
	fputchar (CHAR_NEW_LINE);
1752
	PrintAList (NumberOfMatches, FileList);
1753
 
1754
/* Release memory */
1755
 
1756
	ReleaseAList (FileList);
1757
 
1758
/* Redraw current line */
1759
 
1760
	OutputUserPrompt (LastUserPrompt);
1761
	StartCursorPosition = ReadCursorPosition ();
1762
	return TRUE;
1763
    }
1764
 
1765
/* OK, we are completing. Get the common part of the filename list */
1766
 
1767
    maxi = GetCommonPartOfFileList (FileList);
1768
 
1769
/* If the file name is length matches the search length, there are no unique
1770
 * parts to the filenames in the directory.  Just ring the bell and return.
1771
 */
1772
 
1773
    if ((maxi == MatchStringLen) && (NumberOfMatches > 1))
1774
    {
1775
	ReleaseAList (FileList);
1776
	return RingWarningBell ();
1777
    }
1778
 
1779
/* So, at this point, we are completing and have something to append.  Check
1780
 * that the line is not too long and if there is an end bit, we can save a
1781
 * copy of it.
1782
 */
1783
 
1784
/* Insert after spaces */
1785
 
1786
    if (InsertSpace && isspace (*InsertPosition) &&
1787
	(InsertPosition != ConsoleLineBuffer))
1788
    {
1789
	++StartDirInCLB;
1790
	++InsertPosition;
1791
    }
1792
 
1793
    cp = null;
1794
 
1795
    if (((strlen (InsertPosition) + maxi +
1796
         	(StartDirInCLB - ConsoleLineBuffer) + 3) >= LINE_MAX) ||
1797
	(strlen (InsertPosition) &&
1798
	 ((cp = StringCopy (InsertPosition)) == null)))
1799
    {
1800
	ReleaseAList (FileList);
1801
	return RingWarningBell ();
1802
    }
1803
 
1804
/* Append the new end of line bits */
1805
 
1806
    strcpy (StartDirInCLB, *FileList);
1807
    strcpy (&StartDirInCLB[i = strlen (StartDirInCLB)], " ");
1808
 
1809
/* Save the current position */
1810
 
1811
    c_buffer_pos = &ConsoleLineBuffer[strlen (ConsoleLineBuffer)];
1812
 
1813
/* If we found only 1 and its a directory, append a d sep */
1814
 
1815
    if ((NumberOfMatches == 1) && IsDirectory (NameStart))
1816
    {
1817
	StartDirInCLB[i] = CHAR_UNIX_DIRECTORY;
1818
	strcpy (c_buffer_pos, cp);
1819
    }
1820
 
1821
/* If multiple matches, position at filename and not original position */
1822
 
1823
    else
1824
    {
1825
	if (isspace (*cp))
1826
	    --c_buffer_pos;
1827
 
1828
	strcpy (c_buffer_pos, cp);
1829
 
1830
	if ((NumberOfMatches > 1) && !isspace (*cp))
1831
	    --c_buffer_pos;
1832
    }
1833
 
1834
/* Release the saved buffer and reset end of line pointer */
1835
 
1836
    if (cp != null)
1837
	ReleaseMemoryCell ((void *)cp);
1838
 
1839
    ReleaseAList (FileList);
1840
    EndOfCurrentLine = &ConsoleLineBuffer[strlen (ConsoleLineBuffer)];
1841
 
1842
/* Beep if more than one */
1843
 
1844
    if (NumberOfMatches > 1)
1845
	RingWarningBell ();
1846
 
1847
    return TRUE;
1848
}
1849
 
1850
/* Initialise input */
1851
 
1852
static void F_LOCAL InitialiseInput (bool im)
1853
{
1854
    c_buffer_pos = ConsoleLineBuffer;	/* Initialise			*/
1855
    EndOfCurrentLine = ConsoleLineBuffer;
1856
    SetCursorShape (InsertMode = im);
1857
    M_length = -1;
1858
 
1859
/* Reset max line length */
1860
 
1861
    MaxLength = 0;
1862
    OldMaxLength = 0;
1863
 
1864
/* Save the cursor position */
1865
 
1866
    if (IS_Console (1))
1867
	StartCursorPosition = ReadCursorPosition ();
1868
}
1869
 
1870
/* Configure Keyboard I/O */
1871
 
1872
void Configure_Keys (void)
1873
{
1874
    char		*cp;			/* Line pointers	*/
1875
    int			i, fval, cval;
1876
    int			nFields;
1877
    LineFields		LF;
1878
    long		value;
1879
 
1880
/* Get some memory for the input line and the file name */
1881
 
1882
    if ((LF.LineLength = strlen (cp = GetVariableAsString (ShellVariableName,
1883
    						      FALSE)) + 5) < 200)
1884
	LF.LineLength = 200;
1885
 
1886
    if ((LF.Line = AllocateMemoryCell (LF.LineLength)) == (char *)NULL)
1887
	return;
1888
 
1889
    strcpy (LF.Line, cp);
1890
 
1891
/* Find the .exe in the name */
1892
 
1893
    if ((cp = FindLastPathCharacter (LF.Line)) != (char *)NULL)
1894
	++cp;
1895
 
1896
    else
1897
	cp = LF.Line;
1898
 
1899
    if ((cp = strrchr (cp, CHAR_PERIOD)) == (char *)NULL)
1900
	cp = &LF.Line[strlen (LF.Line)];
1901
 
1902
    strcpy (cp, ".ini");
1903
 
1904
    {
1905
#if (OS_TYPE != OS_UNIX)
1906
        char    tname[ MAX_PATH ];
1907
#endif
1908
 
1909
        if ((LF.FP = FOpenFile (CheckDOSFileName (LF.Line, tname),
1910
                            sOpenReadMode)) == (FILE *)NULL)
1911
        {
1912
            ReleaseMemoryCell ((void *)LF.Line);
1913
            return;
1914
        }
1915
    }
1916
 
1917
/* Initialise the internal buffer */
1918
 
1919
    LF.Fields = (Word_B *)NULL;
1920
 
1921
/* Scan for the file */
1922
 
1923
    while ((nFields = ExtractFieldsFromLine (&LF)) != -1)
1924
    {
1925
        if (nFields < 2)
1926
            continue;
1927
 
1928
/* Look up the keyword name */
1929
 
1930
	for (i = 0;
1931
	     (i < KF_LENGTH) && (stricmp (LF.Fields->w_words[0],
1932
				 KF_List[i].kf_name) != 0);
1933
	     ++i)
1934
	    continue;
1935
 
1936
/* Ignore no matches */
1937
 
1938
	if (i == KF_LENGTH)
1939
	    continue;
1940
 
1941
/* Get the value of the second field - must be numeric */
1942
 
1943
	cval = 0;
1944
 
1945
	if (!ConvertNumericValue (LF.Fields->w_words[1], &value, 0))
1946
	    continue;
1947
 
1948
	fval = (int)value;
1949
 
1950
/* Get the value of the third field, if it exists - must be numeric */
1951
 
1952
	if (nFields == 3)
1953
	{
1954
	    if (!ConvertNumericValue (LF.Fields->w_words[2], &value, 0))
1955
		continue;
1956
 
1957
	    cval = (int)value;
1958
	}
1959
 
1960
/* OK we have a valid value, save it */
1961
 
1962
	KF_List[i].akey = (char)fval;
1963
	KF_List[i].fkey = (char)cval;
1964
    }
1965
 
1966
    ReleaseMemoryCell ((void *)LF.Line);
1967
}
1968
 
1969
/* Check cursor is in column zero */
1970
 
1971
#if (OS_TYPE == OS_OS2)
1972
void PositionCursorInColumnZero (void)
1973
{
1974
    BYTE		abCell[2];
1975
    USHORT		usRow;
1976
    USHORT		usColumn;
1977
    USHORT		cb = sizeof (abCell);
1978
 
1979
/* Get screen infor and cursor position */
1980
 
1981
    GetScreenParameters ();
1982
    StartCursorPosition = ReadCursorPosition ();
1983
 
1984
    VioGetCurPos (&usRow, &usColumn, 0);
1985
    VioReadCellStr (abCell, &cb , usRow, usColumn, 0);
1986
 
1987
    if ((StartCursorPosition % MaximumColumns) || (abCell[0] != CHAR_SPACE))
1988
	fputchar (CHAR_NEW_LINE);
1989
}
1990
#endif
1991
 
1992
/* NT Version */
1993
 
1994
#if (OS_TYPE == OS_NT)
1995
void PositionCursorInColumnZero (void)
1996
{
1997
    char			abCell[2];
1998
    CONSOLE_SCREEN_BUFFER_INFO	CSI;
1999
    DWORD			ActionCount;
2000
 
2001
/* Get screen infor and cursor position */
2002
 
2003
    GetScreenParameters ();
2004
    StartCursorPosition = ReadCursorPosition ();
2005
 
2006
    GetConsoleScreenBufferInfo (NT_StdOut, &CSI);
2007
    ReadConsoleOutputCharacter (NT_StdOut, abCell, 1, CSI.dwCursorPosition,
2008
    				&ActionCount);
2009
 
2010
    if ((StartCursorPosition % MaximumColumns) || (*abCell != CHAR_SPACE))
2011
	fputchar (CHAR_NEW_LINE);
2012
}
2013
#endif
2014
 
2015
/* DOS Version */
2016
 
2017
#if (OS_TYPE == OS_DOS) 
2018
void PositionCursorInColumnZero (void)
2019
{
2020
    union REGS		r;
2021
 
2022
/* Get screen infor and cursor position */
2023
 
2024
    GetScreenParameters ();
2025
    StartCursorPosition = ReadCursorPosition ();
2026
 
2027
    r.h.ah = 0x08;
2028
    r.h.bh = 0x00;
2029
    SystemInterrupt (0x10, &r, &r);
2030
 
2031
    if ((StartCursorPosition % MaximumColumns) || (r.h.al != CHAR_SPACE))
2032
	fputchar (CHAR_NEW_LINE);
2033
}
2034
#endif
2035
 
2036
/*
2037
 * Get screen parameters
2038
 */
2039
 
2040
#if (OS_TYPE == OS_OS2) 
2041
void	GetScreenParameters (void)
2042
{
2043
    VIOMODEINFO		viomi;
2044
 
2045
    viomi.cb = sizeof(viomi);
2046
 
2047
    VioGetMode (&viomi, 0);
2048
    MaximumColumns = viomi.col;
2049
    MaximumLines = viomi.row;
2050
 
2051
/* Set up LINES and COLUMNS variables */
2052
 
2053
    SetVariableFromNumeric (LIT_LINES, (long)MaximumLines);
2054
    SetVariableFromNumeric (LIT_COLUMNS, (long)MaximumColumns);
2055
}
2056
#endif
2057
 
2058
/* NT Version */
2059
 
2060
#if (OS_TYPE == OS_NT) 
2061
void	GetScreenParameters (void)
2062
{
2063
    CONSOLE_SCREEN_BUFFER_INFO	CSI;
2064
 
2065
    NT_StdOut = GetStdHandle (STD_OUTPUT_HANDLE);
2066
    GetConsoleScreenBufferInfo (NT_StdOut, &CSI);
2067
 
2068
    MaximumColumns = CSI.dwSize.X;
2069
    MaximumLines = CSI.dwSize.Y;
2070
 
2071
    //printf( "DEBUG-----dwSize              Lines: %d, Cols: %d\n", CSI.dwSize.Y, CSI.dwSize.X );
2072
    //printf( "DEBUG-----dwCursorPosition    Lines: %d, Cols: %d\n", CSI.dwCursorPosition.Y, CSI.dwCursorPosition.X );
2073
    //printf( "DEBUG-----srWindow            Left:%d, Top: %d, Right: %d, Bottom:%d\n", CSI.srWindow.Left, CSI.srWindow.Top, CSI.srWindow.Right, CSI.srWindow.Bottom );
2074
    //printf( "DEBUG-----dwMaximumWindowSize Lines: %d, Cols: %d\n", CSI.dwMaximumWindowSize.Y, CSI.dwMaximumWindowSize.X );
2075
    //printf( "DEBUG-----My Stuff            Lines: %d, Cols: %d\n", MaximumLines, MaximumColumns );
2076
 
2077
 
2078
/* Set up LINES and COLUMNS variables */
2079
 
2080
    SetVariableFromNumeric (LIT_LINES, (long)MaximumLines);
2081
    SetVariableFromNumeric (LIT_COLUMNS, (long)MaximumColumns);
2082
}
2083
#endif
2084
 
2085
/* DOS version */
2086
 
2087
#if (OS_TYPE == OS_DOS) 
2088
void	GetScreenParameters (void)
2089
{
2090
    union REGS		r;
2091
 
2092
#  if (OS_SIZE == OS_16)
2093
    MaximumColumns = *(int *)(0x0040004aL);
2094
#  else
2095
    MaximumColumns = *(short *)(0x044aL);
2096
#  endif
2097
 
2098
    MaximumLines = 25;
2099
 
2100
/* Is this an EGA?  This test was found in NANSI.SYS */
2101
 
2102
    r.h.ah = 0x12;
2103
    r.x.REG_BX = 0xff10;
2104
    SystemInterrupt (0x10, &r, &r);
2105
 
2106
/* Else read the number of rows */
2107
 
2108
    if (!(r.x.REG_BX & 0xfefc))
2109
    {
2110
	r.x.REG_AX = 0x1130;
2111
	r.h.bh = 0;
2112
	SystemInterrupt (0x10, &r, &r);
2113
	MaximumLines = r.h.dl + 1;
2114
    }
2115
 
2116
/* Set up LINES and COLUMNS variables */
2117
 
2118
    SetVariableFromNumeric (LIT_LINES, (long)MaximumLines);
2119
    SetVariableFromNumeric (LIT_COLUMNS, (long)MaximumColumns);
2120
}
2121
#endif
2122
 
2123
/* Ring Bell ? */
2124
 
2125
bool	RingWarningBell (void)
2126
{
2127
    if (KF_List[KF_RINGBELL].akey)
2128
#if (OS_TYPE == OS_OS2)
2129
	DosBeep (1380, 500);
2130
#elif (OS_TYPE == OS_NT)
2131
	Beep (1380, 500);
2132
#else
2133
	fputchar (0x07);
2134
	fflush (stdout);
2135
#endif
2136
 
2137
    return FALSE;
2138
}
2139
 
2140
/*
2141
 * Read keyboard function
2142
 */
2143
 
2144
#if (OS_TYPE == OS_OS2)
2145
unsigned char	ReadKeyBoard (unsigned char *f_key)
2146
{
2147
    KBDKEYINFO		kbci;
2148
 
2149
    *f_key = 0;
2150
 
2151
/* Wait for input */
2152
 
2153
    KbdCharIn (&kbci, IO_WAIT, 0);
2154
 
2155
    DisplayKeyCode (kbci.chChar, kbci.chScan);
2156
 
2157
    if (kbci.chChar == 0x03)
2158
	raise (SIGINT);
2159
 
2160
/* Check for non-function character */
2161
 
2162
    if (kbci.chChar && (kbci.chChar != 0xe0))
2163
	return (unsigned char)kbci.chChar;
2164
 
2165
/* Return scan code and type (normal or ALT'ed) */
2166
 
2167
    *f_key = (unsigned char)kbci.chScan;
2168
    return (unsigned char)((kbci.fsState & (ALT | LEFTALT | RIGHTALT))
2169
			   ? KT_ALTFUNCTION
2170
			   : KT_FUNCTION);
2171
}
2172
#endif
2173
 
2174
/* NT Version */
2175
 
2176
#if (OS_TYPE == OS_NT)
2177
unsigned char	ReadKeyBoard (unsigned char *f_key)
2178
{
2179
    INPUT_RECORD	Buffer = {0};
2180
    DWORD		NumberOfEventsRead;
2181
    int			i;
2182
 
2183
    *f_key = 0;
2184
 
2185
/* Wait for input */
2186
 
2187
    for ( ; ; )
2188
    {
2189
	if (!ReadConsoleInput (NT_StdIn, &Buffer, 1, &NumberOfEventsRead))
2190
	    continue;
2191
 
2192
	if (Buffer.EventType == WINDOW_BUFFER_SIZE_EVENT)
2193
	    return KT_RESIZE;
2194
 
2195
/* Ignore other non-keyboard events */
2196
 
2197
	if (Buffer.EventType != KEY_EVENT)
2198
	    continue;
2199
 
2200
/* Ignore key release events */
2201
 
2202
	if (!Buffer.Event.KeyEvent.bKeyDown)
2203
	    continue;
2204
 
2205
/* See if it is an ignore key? */
2206
 
2207
	for (i = 0; i < IGNORE_CNT; i++)
2208
	{
2209
	    if (Buffer.Event.KeyEvent.wVirtualScanCode == IgnoreScanCode[i])
2210
	        break;
2211
	}
2212
 
2213
	if (i != IGNORE_CNT)
2214
	    continue;
2215
 
2216
/* Keystroke mapping */
2217
 
2218
	if (DoNTKeyMap (&Buffer.Event.KeyEvent))
2219
	    break;
2220
 
2221
/* ? wRepeatCount */
2222
 
2223
    }
2224
 
2225
    DisplayKeyCode (Buffer.Event.KeyEvent.uChar.AsciiChar,
2226
		    Buffer.Event.KeyEvent.wVirtualScanCode);
2227
 
2228
    if (Buffer.Event.KeyEvent.uChar.AsciiChar == 0x03)
2229
	raise (SIGINT);
2230
 
2231
/* Check for non-function character */
2232
 
2233
    if (Buffer.Event.KeyEvent.uChar.AsciiChar &&
2234
	(Buffer.Event.KeyEvent.uChar.AsciiChar != 0xe0))
2235
	return (unsigned char)Buffer.Event.KeyEvent.uChar.AsciiChar;
2236
 
2237
/* Return scan code and type (normal or ALT'ed) */
2238
 
2239
    *f_key = (unsigned char)Buffer.Event.KeyEvent.wVirtualScanCode;
2240
    return (unsigned char)((Buffer.Event.KeyEvent.dwControlKeyState &
2241
    			    (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
2242
			   ? KT_ALTFUNCTION
2243
			   : KT_FUNCTION);
2244
}
2245
 
2246
/*
2247
 * Handle keyboard mapping
2248
 */
2249
 
2250
static bool F_LOCAL  DoNTKeyMap (KEY_EVENT_RECORD *KeyEvent)
2251
{
2252
    int		i;
2253
 
2254
    if (KeyEvent->wVirtualScanCode == 0x0f)	 /* TAB */
2255
    {
2256
	if (KeyEvent->dwControlKeyState & (CTRL_PRESSED | ALT_PRESSED))
2257
	    return FALSE;
2258
 
2259
	else if (KeyEvent->dwControlKeyState & SHIFT_PRESSED)
2260
	    KeyEvent->uChar.AsciiChar = 0;
2261
 
2262
	else
2263
	    KeyEvent->uChar.AsciiChar = CHAR_TAB;
2264
 
2265
	return TRUE;
2266
    }
2267
 
2268
    else if ((KeyEvent->wVirtualScanCode == 0x0e) ||	/* BACKSPACE */
2269
	     (KeyEvent->wVirtualScanCode == 0x1c)) 	/* RETURN */
2270
	return (bool) !C2bool (KeyEvent->dwControlKeyState & ALT_PRESSED);
2271
 
2272
/* All other mapped characters are OK */
2273
 
2274
    else if (KeyEvent->uChar.AsciiChar)
2275
        return TRUE;
2276
 
2277
/* Handle function keys */
2278
 
2279
    for (i = 0; i < MAX_NT_FKMAP; i++)
2280
    {
2281
        if (KeyEvent->wVirtualScanCode != NT_KFMap [i].Normal)
2282
	    continue;
2283
 
2284
/* If Ctrl Alt pressed - ignore key */
2285
 
2286
	if ((KeyEvent->dwControlKeyState & (CTRL_PRESSED | ALT_PRESSED))
2287
		== (CTRL_PRESSED | ALT_PRESSED))
2288
	    return FALSE;
2289
 
2290
	else if (KeyEvent->dwControlKeyState & CTRL_PRESSED)
2291
	    KeyEvent->wVirtualScanCode = NT_KFMap [i].Control;
2292
 
2293
	else if (KeyEvent->dwControlKeyState & ALT_PRESSED)
2294
	    KeyEvent->wVirtualScanCode = NT_KFMap [i].Alt;
2295
 
2296
	else if (KeyEvent->dwControlKeyState & SHIFT_PRESSED)
2297
	    KeyEvent->wVirtualScanCode = NT_KFMap [i].Shift;
2298
 
2299
	return TRUE;
2300
    }
2301
 
2302
    return TRUE;
2303
}
2304
#endif
2305
 
2306
/* DOS Version */
2307
 
2308
#if (OS_TYPE == OS_DOS) 
2309
unsigned char	ReadKeyBoard (unsigned char *f_key)
2310
{
2311
    unsigned char		a_key;
2312
    union KeyCode {
2313
	unsigned short		Key;
2314
	struct Scan {
2315
	    unsigned char	ascii, scan;
2316
	}			Scan;
2317
    }				KeyCode;
2318
 
2319
/* If DEQSview is active - we must poll the keyboard */
2320
 
2321
#  if (OS_SIZE == OS_16) && (0)
2322
    if (DESQviewActive)
2323
    {
2324
	if (!((KeyCode.Scan.ascii = Poll_Keyboard ())) ||
2325
	    (KeyCode.Scan.ascii == 0xe0))
2326
	    KeyCode.Scan.scan = Poll_Keyboard ();
2327
    }
2328
 
2329
    else
2330
#  endif
2331
 
2332
/*
2333
 * Read Keyboard via interrupt 10 function 1 or 10 depending on whether we
2334
 * have an extended keyboard or not!.
2335
 */
2336
 
2337
    {
2338
	KeyCode.Key = _bios_keybrd (ReadKeyboardOption);
2339
 
2340
	if (KeyCode.Scan.ascii == 0xe0)
2341
	    KeyCode.Scan.ascii = 0;
2342
    }
2343
 
2344
    DisplayKeyCode (KeyCode.Scan.ascii, KeyCode.Scan.scan);
2345
 
2346
/* Check for interrupt */
2347
 
2348
    if (KeyCode.Scan.ascii == 3)
2349
	raise (SIGINT);
2350
 
2351
/* Set up return values */
2352
 
2353
    if (KeyCode.Scan.ascii == 0)
2354
    {
2355
	a_key = KT_FUNCTION;
2356
	*f_key = KeyCode.Scan.scan;
2357
 
2358
/* If ALT Key set, return 0xff instead of 0 for function key */
2359
 
2360
	if (_bios_keybrd (_KEYBRD_SHIFTSTATUS) & 0x08)
2361
	    a_key = KT_ALTFUNCTION;
2362
    }
2363
 
2364
/* ASCII keycode - return it. */
2365
 
2366
    else
2367
    {
2368
	a_key = KeyCode.Scan.ascii;
2369
	*f_key = 0;
2370
    }
2371
 
2372
    return a_key;
2373
}
2374
#endif
2375
 
2376
#ifdef KEYDEBUG
2377
static void	DisplayKeyCode (unsigned int a, unsigned int b)
2378
{
2379
    int		cp = ReadCursorPosition ();
2380
 
2381
    SetCursorPosition (23*80 + 59);
2382
    printf ("ASCII %.2x SCAN %.2x\n", a, b);
2383
    SetCursorPosition (cp);
2384
}
2385
#endif
2386
 
2387
/*
2388
 * Update Initialisation value
2389
 */
2390
 
2391
bool	ChangeInitialisationValue (char *string, int newvalue)
2392
{
2393
    int		i;
2394
 
2395
    for (i = KF_END_FKEYS; i < KF_LENGTH; ++i)
2396
    {
2397
	if (stricmp (string, KF_List[i].kf_name) == 0)
2398
	{
2399
	    KF_List[i].akey = (char)newvalue;
2400
	    return TRUE;
2401
	}
2402
    }
2403
 
2404
    return FALSE;
2405
}
2406
 
2407
/*
2408
 * Enable keyboard polling function - required if DESQview loaded
2409
 */
2410
 
2411
#if (OS_TYPE == OS_DOS)
2412
static void F_LOCAL CheckKeyboardPolling (void)
2413
{
2414
    static bool		Initialised = FALSE;
2415
    union REGS		r;
2416
    int			i;
2417
 
2418
    if (Initialised)
2419
	return;
2420
 
2421
    Initialised = TRUE;
2422
 
2423
/* Check to see we are running under DESQview */
2424
 
2425
#  if (OS_SIZE == OS_16)
2426
    r.x.REG_AX = 0x2b01;
2427
    r.x.REG_CX = 0x4445;
2428
    r.x.REG_DX = 0x5351;
2429
    DosInterrupt (&r, &r);
2430
 
2431
    if (r.h.al != 0xff)
2432
	DESQviewActive = TRUE;
2433
#  endif
2434
 
2435
/* Otherwise check for extended keyboard.  Stick 0xffff in the keyboard
2436
 * buffer and read it back.  If we find it - OK!
2437
 */
2438
 
2439
    ReadKeyboardOption = _KEYBRD_READ;	/* Normal keyboard		*/
2440
 
2441
    r.h.ah = 0x05;
2442
    r.x.REG_CX = 0xffff;
2443
    SystemInterrupt (0x16, &r, &r);
2444
 
2445
    if (r.h.al)
2446
	return;
2447
 
2448
/* 16 attempts to read extended keyboard interface */
2449
 
2450
    for (i = 0; i < 16; i++)
2451
    {
2452
	if ((unsigned)_bios_keybrd (_NKEYBRD_READ) == 0xffff)
2453
	{
2454
	    ReadKeyboardOption = _NKEYBRD_READ;	/* Extended keyboard	*/
2455
	    return;
2456
	}
2457
    }
2458
}
2459
#endif
2460
 
2461
/*
2462
 * Print a single history entry
2463
 */
2464
 
2465
static void F_LOCAL PrintOutHistory (FILE		*fp,
2466
				     bool		n_flag,
2467
				     struct cmd_history *cmd)
2468
{
2469
    char	*cp = cmd->command;
2470
 
2471
    if (n_flag)
2472
    {
2473
	fprintf (fp, "%5d: ", cmd->number);
2474
 
2475
	while (*cp)
2476
	{
2477
	    putc (*cp, fp);
2478
 
2479
	    if (*(cp++) == CHAR_NEW_LINE)
2480
		fputs ("       ", fp);
2481
	}
2482
    }
2483
 
2484
    else
2485
	fputs (cp, fp);
2486
 
2487
    putc (CHAR_NEW_LINE, fp);
2488
}
2489
 
2490
/*
2491
 * Get the last history event number
2492
 */
2493
 
2494
int GetLastHistoryEvent (void)
2495
{
2496
    return (l_history) ? cmd_history[l_history - 1].number + 1 : 1;
2497
}
2498
 
2499
/*
2500
 * Get the last history event number
2501
 */
2502
 
2503
int GetFirstHistoryEvent (void)
2504
{
2505
    return (cmd_history[0].number) ? cmd_history[0].number : 1;
2506
}
2507
 
2508
/*
2509
 * Get the last history event
2510
 */
2511
 
2512
#if (OS_TYPE != OS_DOS) 
2513
char *GetLastHistoryString (void)
2514
{
2515
    return l_history ? cmd_history[l_history - 1].command : (char *)NULL;
2516
}
2517
#endif
2518
 
2519
/*
2520
 * Dump history
2521
 */
2522
 
2523
void PrintHistory (bool r_flag, bool n_flag, int First, int Last, FILE *fp)
2524
{
2525
    int		i;
2526
 
2527
    if (r_flag)
2528
    {
2529
	for (i = l_history - 1;
2530
	     (i >= 0) && (cmd_history[i].number >= First); --i)
2531
	{
2532
	    if (cmd_history[i].number <= Last)
2533
		PrintOutHistory (fp, n_flag, &cmd_history[i]);
2534
	}
2535
    }
2536
 
2537
    else
2538
    {
2539
	for (i = 0; (i < l_history) && (cmd_history[i].number <= Last); ++i)
2540
	{
2541
	    if (cmd_history[i].number >= First)
2542
		PrintOutHistory (fp, n_flag, &cmd_history[i]);
2543
	}
2544
    }
2545
}
2546
 
2547
/*
2548
 * Search for an event
2549
 */
2550
 
2551
int SearchHistory (char *buffer)
2552
{
2553
    int		Length = strlen (buffer);
2554
    int		i;
2555
 
2556
    for (i = l_history - 1;
2557
	 (i >= 0) && strncmp (buffer, cmd_history[i].command, Length); --i)
2558
	continue;
2559
 
2560
    return (i == -1) ? -1 : cmd_history[i].number;
2561
}
2562
 
2563
/*
2564
 * Release Command
2565
 */
2566
 
2567
static void F_LOCAL ReleaseCommandMemory (struct cmd_history *cp)
2568
{
2569
    if (cp->command != null)
2570
	ReleaseMemoryCell ((void *)cp->command);
2571
}
2572
 
2573
/*
2574
 * Flush history buffer.  If save is set, the contents of the console
2575
 * buffer will be saved.
2576
 */
2577
 
2578
void	FlushHistoryBuffer (void)
2579
{
2580
    if (SaveHistory)
2581
	AddHistory (AppendHistory);
2582
 
2583
    memset (ConsoleLineBuffer, 0, LINE_MAX + 1);
2584
 
2585
    AppendHistory = FALSE;
2586
    SaveHistory = FALSE;
2587
}
2588
 
2589
/*
2590
 * Save the current console buffer
2591
 */
2592
 
2593
static void F_LOCAL SaveCurrentHistory (void)
2594
{
2595
    c_history = l_history;
2596
 
2597
    if (SaveHistory)
2598
	AddHistory (AppendHistory);
2599
 
2600
    AppendHistory = (bool)(LastUserPrompt == PS2);
2601
    SaveHistory = (bool)((LastUserPrompt == PS1) || AppendHistory);
2602
}
2603
 
2604
/*
2605
 * Insert a Character into the buffer
2606
 */
2607
 
2608
static bool F_LOCAL InsertACharacter (int NewCharacter)
2609
{
2610
    if ((EndOfCurrentLine - ConsoleLineBuffer) == LINE_MAX)
2611
	return RingWarningBell ();	/* Ring bell - line full	*/
2612
 
2613
    if (c_buffer_pos != EndOfCurrentLine)
2614
	memrcpy (EndOfCurrentLine + 1, EndOfCurrentLine,
2615
		 EndOfCurrentLine - c_buffer_pos + 1);
2616
 
2617
    ++EndOfCurrentLine;
2618
 
2619
/* Fast end of line processing */
2620
 
2621
    if ((c_buffer_pos == EndOfCurrentLine - 1) && (NewCharacter != CHAR_TAB))
2622
    {
2623
	*(c_buffer_pos++) = (char)NewCharacter;
2624
	OutputACharacter (NewCharacter);
2625
	return FALSE;
2626
    }
2627
 
2628
/* Not at end of line - redraw */
2629
 
2630
    *(c_buffer_pos++) = (char)NewCharacter;
2631
    return TRUE;
2632
}
2633
 
2634
/*
2635
 * Delete Last History Item
2636
 */
2637
 
2638
void DeleteLastHistory (void)
2639
{
2640
    if (l_history)
2641
	ReleaseCommandMemory (&cmd_history[--l_history]);
2642
}
2643
 
2644
/*
2645
 * Clear the screen
2646
 */
2647
 
2648
#if (OS_TYPE == OS_OS2)
2649
bool	ClearScreen (void)
2650
{
2651
    BYTE	abCell[2];
2652
    USHORT	usRow;
2653
    USHORT	usColumn;
2654
    USHORT	cb = sizeof (abCell);
2655
 
2656
    fputchar (CHAR_NEW_LINE);
2657
    FlushStreams ();
2658
 
2659
/* Read attribute under cursor */
2660
 
2661
    VioGetCurPos (&usRow, &usColumn, 0);
2662
    VioReadCellStr (abCell, &cb , usRow, usColumn, 0);
2663
 
2664
    abCell[0] = CHAR_SPACE;
2665
 
2666
    VioScrollUp (0, 0, 0xffff, 0xffff, 0xffff, abCell, 0);
2667
    VioSetCurPos (0, 0, 0);
2668
 
2669
    OutputUserPrompt (LastUserPrompt);
2670
    StartCursorPosition = ReadCursorPosition ();
2671
    return TRUE;
2672
}
2673
#endif
2674
 
2675
/*
2676
 * NT Version
2677
 */
2678
 
2679
#if (OS_TYPE == OS_NT)
2680
bool	ClearScreen (void)
2681
{
2682
    WORD			Atts[2];
2683
    CONSOLE_SCREEN_BUFFER_INFO	CSI;
2684
    DWORD			ActionCount;
2685
    CHAR_INFO			*Buffer;
2686
    COORD			dwBufferSize;
2687
    COORD			dwBufferCoord;
2688
    SMALL_RECT			WriteRegion;
2689
    DWORD			Size = MaximumColumns * MaximumLines;
2690
 
2691
    FlushStreams ();
2692
 
2693
/* Read attribute under cursor */
2694
 
2695
    GetConsoleScreenBufferInfo (NT_StdOut, &CSI);
2696
    ReadConsoleOutputAttribute (NT_StdOut, Atts, 1, CSI.dwCursorPosition,
2697
    				&ActionCount);
2698
 
2699
/*
2700
 * Write it.  What a pain!!!
2701
 *
2702
 * Get some memory
2703
 */
2704
 
2705
    Buffer = (CHAR_INFO *)AllocateMemoryCell (Size * sizeof (CHAR_INFO));
2706
 
2707
/* Set up attributes */
2708
 
2709
    for (ActionCount = 0; ActionCount < Size; ActionCount++)
2710
    {
2711
	Buffer[ActionCount].Attributes = Atts[0];
2712
	Buffer[ActionCount].Char.AsciiChar = CHAR_SPACE;
2713
    }
2714
 
2715
/* Size */
2716
 
2717
    dwBufferSize.X = (USHORT)MaximumColumns;
2718
    dwBufferSize.Y = (USHORT)MaximumLines;
2719
 
2720
/* Co-ordinated */
2721
 
2722
    dwBufferCoord.X = 0;
2723
    dwBufferCoord.Y = 0;
2724
 
2725
/* Set up output data */
2726
 
2727
    WriteRegion.Left = 0;
2728
    WriteRegion.Top = 0;
2729
    WriteRegion.Right = (USHORT)(MaximumColumns - 1);
2730
    WriteRegion.Bottom = (USHORT)(MaximumLines - 1);
2731
 
2732
    WriteConsoleOutput (NT_StdOut, Buffer, dwBufferSize, dwBufferCoord,
2733
			&WriteRegion);
2734
 
2735
    ReleaseMemoryCell (Buffer);
2736
 
2737
    SetConsoleCursorPosition (NT_StdOut, dwBufferCoord);
2738
 
2739
    OutputUserPrompt (LastUserPrompt);
2740
    StartCursorPosition = ReadCursorPosition ();
2741
    return TRUE;
2742
}
2743
#endif
2744
 
2745
/* DOS Version */
2746
 
2747
#if (OS_TYPE == OS_DOS)
2748
bool	ClearScreen (void)
2749
{
2750
    union REGS		r;
2751
    unsigned char	backg;
2752
 
2753
    fputchar (CHAR_NEW_LINE);
2754
    FlushStreams ();
2755
 
2756
/* Get the background attribute of the cursor */
2757
 
2758
    r.h.ah = 0x08;
2759
    r.h.bh = 0;
2760
    SystemInterrupt (0x10, &r, &r);
2761
    backg = (unsigned char)(r.h.ah & 0x07);
2762
 
2763
/* Clear the screen */
2764
 
2765
    r.x.REG_AX = 0x0600;
2766
    r.h.bh = backg;
2767
    r.x.REG_CX = 0;
2768
    r.h.dh = (unsigned char)MaximumLines;
2769
    r.h.dl = (unsigned char)MaximumColumns;
2770
    SystemInterrupt (0x10, &r, &r);
2771
 
2772
/* Position to top of page */
2773
 
2774
    r.h.ah = 0x02;				/* Set new position	*/
2775
    r.h.bh = 0;					/* Page zero		*/
2776
    r.x.REG_DX = 0x0000;
2777
    SystemInterrupt (0x10, &r, &r);
2778
 
2779
    OutputUserPrompt (LastUserPrompt);
2780
    StartCursorPosition = ReadCursorPosition ();
2781
    return TRUE;
2782
}
2783
#endif
2784
 
2785
/*
2786
 * Display a line, handling control characters
2787
 */
2788
 
2789
void	DisplayLineWithControl (char *line)
2790
{
2791
    int		off = ReadCursorPosition ();
2792
 
2793
/* Print characters */
2794
 
2795
    while (*line)
2796
    {
2797
 
2798
/* Process TABS */
2799
 
2800
	if (*line == CHAR_TAB)
2801
	{
2802
	    do
2803
	    {
2804
		fputchar (CHAR_SPACE);
2805
	    } while ((++off) % 8);
2806
	}
2807
 
2808
/* Process Control and printing characters */
2809
 
2810
	else
2811
	    off += OutputACharacter (*line);
2812
 
2813
	++line;
2814
    }
2815
}
2816
 
2817
/*
2818
 * Get the Root Disk Drive.  If not defined, set it to the current drive.
2819
 */
2820
 
2821
#if (OS_TYPE != OS_UNIX)
2822
int	GetRootDiskDrive (void)
2823
{
2824
    if (!KF_List[KF_ROOTDRIVE].akey)
2825
	KF_List[KF_ROOTDRIVE].akey = (char)GetCurrentDrive ();
2826
 
2827
    return KF_List[KF_ROOTDRIVE].akey;
2828
}
2829
#endif
2830
 
2831
/*
2832
 * Get the EOF Key
2833
 */
2834
 
2835
int	GetEOFKey (void)
2836
{
2837
#if (OS_TYPE == OS_UNIX)
2838
    struct termios	ts;
2839
 
2840
    return tcgetattr (1, &ts) ? 4 : ts.c_cc[VEOF];
2841
#else
2842
    if (!KF_List[KF_EOFKEY].akey)
2843
	KF_List[KF_EOFKEY].akey = 0x1a;
2844
 
2845
    return KF_List[KF_EOFKEY].akey;
2846
#endif
2847
}
2848
 
2849
/*
2850
 * Output a Character - excluding TABS.  Return # chars output.
2851
 *
2852
 * TABS are not checked for
2853
 */
2854
 
2855
static int F_LOCAL OutputACharacter (int c)
2856
{
2857
    int		off = 1;
2858
 
2859
/* Check for control and process */
2860
 
2861
    if (iscntrl (c))
2862
    {
2863
	fputchar (CHAR_NOT);
2864
	c += '@';
2865
	off++;
2866
    }
2867
 
2868
/* Output the character */
2869
 
2870
    fputchar (c);
2871
    return off;
2872
}
2873
 
2874
/*
2875
 * Strip off trailing EOFs and EOLs from console buffer
2876
 */
2877
 
2878
char	CleanUpBuffer (int length, char *buffer, int eofc)
2879
{
2880
    char	*cp = &buffer[length - 1];
2881
    char	ret;
2882
 
2883
    while (length && ((*cp == (char)eofc) || (*cp == CHAR_NEW_LINE)))
2884
    {
2885
	length--;
2886
	cp--;
2887
    }
2888
 
2889
    ret = *(cp + 1);
2890
    *(cp + 1) = 0;
2891
    return ret;
2892
}
2893
 
2894
/*
2895
 * Look up the keystroke to see if it is one of our functions
2896
 */
2897
 
2898
int	LookUpKeyBoardFunction (unsigned char a_key, unsigned char f_key)
2899
{
2900
    int		i;
2901
 
2902
    for (i = 0; (i < KF_END_FKEYS); ++i)
2903
    {
2904
	if (KF_List[i].akey != a_key)
2905
	    continue;
2906
 
2907
/* Function or meta key? */
2908
 
2909
	if ((a_key != KT_FUNCTION) && (a_key != KT_ALTFUNCTION))
2910
	    break;
2911
 
2912
	else if (KF_List[i].fkey == f_key)
2913
	    break;
2914
    }
2915
 
2916
/* If this is a function key and is not ours, ignore it */
2917
 
2918
    if ((i == KF_END_FKEYS) && ((a_key == KT_FUNCTION) ||
2919
    				(a_key == KT_ALTFUNCTION)))
2920
	return 0;
2921
 
2922
    return (i == KF_END_FKEYS) ? (int)a_key
2923
    			       : -((int)(KF_List[i].fcode) + 1);
2924
}
2925
 
2926
/*
2927
 * Build a list of filenames for completion
2928
 */
2929
 
2930
char 	**BuildCompletionList (char *String, size_t Length, int *Count,
2931
			       bool Full)
2932
{
2933
    char	*MatchString = GetAllocatedSpace (Length + 2);
2934
    char	**FileList;
2935
    char	*vecp[2];
2936
    char	*cp;
2937
    char	**ap;
2938
    size_t	DiscardLength;
2939
 
2940
/* Build the string to expand */
2941
 
2942
    *Count = 0;
2943
    memmove (MatchString, String, Length);
2944
 
2945
    if (MatchString[Length - 1] != CHAR_MATCH_ALL)
2946
    {
2947
	MatchString[Length] = CHAR_MATCH_ALL;
2948
	MatchString[Length + 1] = 0;
2949
    }
2950
 
2951
    else
2952
	MatchString[Length] = 0;
2953
 
2954
    vecp[0] = MatchString;
2955
    vecp[1] = (char *)NULL;
2956
 
2957
/* Expand it */
2958
 
2959
    FileList = ExpandWordList (vecp, EXPAND_SPLITIFS | EXPAND_GLOBBING |
2960
    				EXPAND_TILDE, (ExeMode *)NULL);
2961
 
2962
/* Check to see if it expanded */
2963
 
2964
    if ((strcmp (FileList[0], MatchString) == 0) &&
2965
	(FileList[1] == (char *) NULL))
2966
    {
2967
	ReleaseMemoryCell (FileList[0]);
2968
	ReleaseMemoryCell (FileList);
2969
        FileList = (char **)NULL;
2970
    }
2971
 
2972
    ReleaseMemoryCell (MatchString);
2973
 
2974
    if (FileList != (char **)NULL)
2975
	*Count = CountNumberArguments (FileList);
2976
 
2977
/* Exit if expansion failed or we don't want directory stripping */
2978
 
2979
    if ((FileList == (char **)NULL) || Full)
2980
	return FileList;
2981
 
2982
/* Strip off directory name ..../ or x: */
2983
 
2984
    if ((cp = FindLastPathCharacter (FileList[0])) != (char *)NULL)
2985
        cp++;
2986
 
2987
    else if (IsDriveCharacter (FileList[0][1]))
2988
        cp = &FileList[0][2];
2989
 
2990
    else
2991
        return FileList;
2992
 
2993
/* Get the discard length and remove it from the strings */
2994
 
2995
    DiscardLength = cp - FileList[0];
2996
    ap = FileList;
2997
 
2998
    while ((cp = *(ap++)) != (char *)NULL)
2999
        strcpy (cp, cp + DiscardLength);
3000
 
3001
    return FileList;
3002
}
3003
 
3004
/*
3005
 * Get the Common part of the name from a list of files
3006
 */
3007
 
3008
size_t	GetCommonPartOfFileList (char **FileList)
3009
{
3010
    char	**ap = FileList + 1;
3011
    char	*BaseName = *FileList;
3012
    size_t	maxi = strlen (*FileList);
3013
    size_t	i;
3014
 
3015
/* Scan the list */
3016
 
3017
    while (*ap != (char *)NULL)
3018
    {
3019
	for (i = 0; (BaseName[i] == (*ap)[i]) && (i < maxi); i++)
3020
	     continue;
3021
 
3022
	BaseName[maxi = i] = 0;
3023
	ap++;
3024
    }
3025
 
3026
    return maxi;
3027
}
3028
 
3029
/*
3030
 * Return the function key information associated with an internal key
3031
 * function
3032
 */
3033
 
3034
#if defined (FLAGS_EMACS) || defined (FLAGS_GMACS)
3035
unsigned char	GetFunctionKeyMap (int key, unsigned char *f_key)
3036
{
3037
    *f_key = KF_List[key].fkey;
3038
    return KF_List[key].akey;
3039
}
3040
#endif
3041
 
3042
/*
3043
 * Change Keyboard to RAW/COOKED mode
3044
 */
3045
 
3046
#if (OS_TYPE == OS_OS2)
3047
static void F_LOCAL	ChangeKeyboardMode (bool Cooked)
3048
{
3049
    KBDINFO		kbstInfo;
3050
 
3051
/* Get current mode */
3052
 
3053
    kbstInfo.cb = sizeof (kbstInfo);
3054
    KbdGetStatus (&kbstInfo, 0);
3055
 
3056
/* Change it */
3057
 
3058
    kbstInfo.fsMask &= ~(KEYBOARD_ASCII_MODE | KEYBOARD_ECHO_ON |
3059
		         KEYBOARD_ECHO_OFF   | KEYBOARD_BINARY_MODE);
3060
 
3061
    kbstInfo.fsMask |= (Cooked) ? (KEYBOARD_ASCII_MODE | KEYBOARD_ECHO_ON)
3062
    				: (KEYBOARD_ECHO_OFF | KEYBOARD_BINARY_MODE);
3063
 
3064
    KbdSetStatus (&kbstInfo, 0);
3065
}
3066
#endif
3067
 
3068
/* NT Version */
3069
 
3070
#if (OS_TYPE == OS_NT)
3071
static void F_LOCAL	ChangeKeyboardMode (bool Cooked)
3072
{
3073
    DWORD		NewMode = ENABLE_WINDOW_INPUT;
3074
 
3075
/* Get handlers */
3076
 
3077
    NT_StdIn  = GetStdHandle (STD_INPUT_HANDLE);
3078
    NT_StdOut = GetStdHandle (STD_OUTPUT_HANDLE);
3079
 
3080
/* Set up cooked mode if required */
3081
 
3082
    if (Cooked)
3083
	NewMode = (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
3084
		   ENABLE_ECHO_INPUT);
3085
 
3086
/* Change modes */
3087
 
3088
    SetConsoleMode (NT_StdIn, NewMode);
3089
    SetConsoleMode (NT_StdOut, ENABLE_PROCESSED_OUTPUT |
3090
			       ENABLE_WRAP_AT_EOL_OUTPUT);
3091
}
3092
#endif
3093
 
3094
/* UNIX Version */
3095
 
3096
#if (OS_TYPE == OS_UNIX)
3097
static void F_LOCAL	ChangeKeyboardMode (bool Cooked)
3098
{
3099
    fputs ("UNIX: ChangeKeyboardMode NI\n", stderr);
3100
}
3101
#endif
3102
 
3103
/*
3104
 * EMX needs a read keyboard function
3105
 */
3106
 
3107
#if (OS_TYPE == OS_DOS) && defined (__EMX__)
3108
unsigned int	 _bios_keybrd (unsigned int function)
3109
{
3110
    union REGS		r;
3111
 
3112
    r.h.ah = function;
3113
    SystemInterrupt (0x16, &r, &r);
3114
    return r.x.REG_AX;
3115
}
3116
#endif