Subversion Repositories DevTools

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 dpurdie 1
/*
2
 * MS-DOS SHELL - Command Line Editing
3
 *
4
 * MS-DOS SHELL - Copyright (c) 1990,4 Data Logic Limited and Charles Forsyth
5
 *
6
 * This code is based on (in part) the EMACS and VI editing code from Simon
7
 * J. Gerraty's Public Domain Korn Shell and is subject to the following
8
 * copyright restrictions.  The VI Command Editing was originally based on
9
 * code written by John Rochester and modified by Larry Bouzane, Eric Gisin
10
 * and Mike Jetzer.  The EMACS Command Editing was originally based on code
11
 * written by Ron Natalie and modified by Doug Kingston, Doug Gwyn, Lou
12
 * Salkind, Eric Gisin and Kai Uwe Rommel.
13
 *
14
 * 1.  Redistribution and use in source and binary forms are permitted
15
 *     provided that the above copyright notice is duplicated in the
16
 *     source form and the copyright notice in file sh6.c is displayed
17
 *     on entry to the program.
18
 *
19
 * 2.  The sources (or parts thereof) or objects generated from the sources
20
 *     (or parts of sources) cannot be sold under any circumstances.
21
 *
22
 *
23
 *    $Header: /cvsroot/device/DEVL/UTILS/SH/Sh13.c,v 1.1 2002/08/02 06:49:34 adamy Exp $
24
 *
25
 *    $Log: Sh13.c,v $
26
 *    Revision 1.1  2002/08/02 06:49:34  adamy
27
 *    imported (reference only)
28
 *
29
 *    Revision 1.1  2001/07/20 05:55:44  ayoung
30
 *    WIN32 support
31
 *
32
 *    Revision 1.1.1.1  1999/12/02 01:11:12  gordonh
33
 *    UTIL
34
 *
35
 * Revision 1.10  1994/08/25  20:49:11  istewart
36
 * MS Shell 2.3 Release
37
 *
38
 * Revision 1.9  1994/02/01  10:25:20  istewart
39
 * Release 2.3 Beta 2, including first NT port
40
 *
41
 * Revision 1.8  1994/01/20  14:51:43  istewart
42
 * Release 2.3 Beta 1
43
 *
44
 * Revision 1.7  1994/01/11  17:55:25  istewart
45
 * Release 2.3 Beta 0 patches
46
 *
47
 * Revision 1.6  1993/12/02  09:29:04  istewart
48
 * Fix incorrect ifdef for EMACS/GMACS
49
 *
50
 * Revision 1.5  1993/11/09  10:39:49  istewart
51
 * Beta 226 checking
52
 *
53
 * Revision 1.4  1993/08/25  16:03:57  istewart
54
 * Beta 225 - see Notes file
55
 *
56
 * Revision 1.3  1993/07/02  10:21:35  istewart
57
 * 224 Beta fixes
58
 *
59
 * Revision 1.2  1993/06/14  11:01:44  istewart
60
 * More changes for 223 beta
61
 *
62
 */
63
 
64
#include <sys/types.h>
65
#include <sys/stat.h>
66
#include <stdio.h>
67
#include <string.h>
68
#include <limits.h>
69
#include <setjmp.h>
70
#include <unistd.h>
71
#include <signal.h>
72
#include <fcntl.h>
73
#include <ctype.h>
74
#include <errno.h>
75
#include <stdlib.h>
76
#include <dirent.h>
77
#include "sh.h"
78
 
79
/*
80
 * VI Functions
81
 */
82
 
83
#ifdef FLAGS_VI
84
static int F_LOCAL	VI_MainLoop (void);
85
static int F_LOCAL	VI_GetNextCharacter (void);
86
static bool F_LOCAL	VI_StateMachine (int);
87
static int F_LOCAL	VI_GetNextState (int);
88
static int F_LOCAL	VI_InsertCharacter (int);
89
static int F_LOCAL	VI_ExecuteCommand (int, char *);
90
static int F_LOCAL	VI_ExecuteMove (int, char *, bool);
91
static int F_LOCAL	VI_RedoInsert (int);
92
static void F_LOCAL	VI_YankSelection (int, int);
93
static int F_LOCAL	VI_GetBracketType (int);
94
static void F_LOCAL	VI_Refresh (bool);
95
static void F_LOCAL	VI_CopyInput2Hold (void);
96
static void F_LOCAL	VI_CopyHold2Input (void);
97
static void F_LOCAL	VI_RedrawLine (void);
98
static void F_LOCAL	VI_CreateWindowBuffers (void);
99
static void F_LOCAL	VI_DeleteRange (int, int);
100
static bool F_LOCAL	VI_GetEventFromHistory (bool, int);
101
static int F_LOCAL	VI_FindEventFromHistory (bool, int, bool, char *);
102
static int F_LOCAL	VI_InsertIntoBuffer (char *, int, bool);
103
static bool F_LOCAL	VI_OutOfWindow (void);
104
static int F_LOCAL	VI_FindCharacter (int, int, bool, bool);
105
static void F_LOCAL	VI_ReWindowBuffer (void);
106
static void F_LOCAL	VI_YankDelete (int, int);
107
static int F_LOCAL	VI_AdvanceColumn (int, int);
108
static void F_LOCAL	VI_DisplayWindow (char *, char *, bool);
109
static void F_LOCAL	VI_MoveToColumn (int, char *);
110
static void F_LOCAL	VI_OutputPrompt (bool);
111
static bool F_LOCAL	VI_MoveThroughHistory (int);
112
static bool F_LOCAL	VI_EditLine (int);
113
static void F_LOCAL	VI_SaveUndoBuffer (int, char *);
114
static bool F_LOCAL	VI_ChangeCommand (int, char *);
115
static bool F_LOCAL	VI_CommandPut (int, char);
116
static void F_LOCAL	VI_UndoCommand (void);
117
static bool F_LOCAL	VI_ResetLineState (void);
118
static bool F_LOCAL	VI_ExecuteSearch (char *);
119
static bool F_LOCAL	VI_InsertWords (int);
120
static bool F_LOCAL	VI_ChangeCase (int);
121
static bool F_LOCAL	VI_ExecuteCompletion (char *);
122
static bool F_LOCAL	VI_HandleInputAlias (char *);
123
 
124
static int F_LOCAL	VI_ForwardWord (int);
125
static int F_LOCAL	VI_BackwardWord (int);
126
static int F_LOCAL	VI_EndofWord (int);
127
static int F_LOCAL	VI_ForwardToWhiteSpace (int);
128
static int F_LOCAL	VI_BackwardToWhiteSpace (int);
129
static int F_LOCAL	VI_ForwardToEndOfNonWhiteSpace (int);
130
#endif
131
 
132
/*
133
 * EMACS Edit Functions
134
 */
135
 
136
#if defined (FLAGS_EMACS) || defined (FLAGS_GMACS)
137
static int F_LOCAL	EMACS_MainLoop (void);
138
static int F_LOCAL	EMACS_AutoInsert (int);
139
static int F_LOCAL	EMACS_InsertMacroString (int);
140
static void F_LOCAL	EMACS_InsertString (char *);
141
static int F_LOCAL	EMACS_DeleteCharacterBackwards (int);
142
static int F_LOCAL	EMACS_DeleteCurrentCharacter (int);
143
static int F_LOCAL	EMACS_DeleteString (int);
144
static int F_LOCAL	EMACS_DeletePreviousWord (int);
145
static int F_LOCAL	EMACS_MoveBackAWord (int);
146
static int F_LOCAL	EMACS_MoveForwardAWord (int);
147
static int F_LOCAL	EMACS_DeleteNextWord (int);
148
static int F_LOCAL	EMACS_GetPreviousWord (void);
149
static int F_LOCAL	EMACS_GetNextWord (void);
150
static int F_LOCAL	EMACS_GotoColumn (char *);
151
static int F_LOCAL	EMACS_GetDisplayStringSize (char *);
152
static int F_LOCAL	EMACS_PreviousCharacter (int);
153
static int F_LOCAL	EMACS_NextCharacter (int);
154
static int F_LOCAL	EMACS_FindCharacter (int, char *);
155
static int F_LOCAL	EMACS_ForwardToCharacter (int);
156
static int F_LOCAL	EMACS_BackwardToCharacter (int);
157
static int F_LOCAL	EMACS_NewLine (int);
158
static int F_LOCAL	EMACS_EndOfInput (int);
159
static int F_LOCAL	EMACS_GetFirstHistory (int);
160
static int F_LOCAL	EMACS_GetLastHistory (int);
161
static int F_LOCAL	EMACS_GetPreviousCommand (int);
162
static int F_LOCAL	EMACS_GetNextCommand (int);
163
static int F_LOCAL	EMACS_LoadFromHistory (int);
164
static int F_LOCAL	EMACS_OperateOnLine (int);
165
static int F_LOCAL	EMACS_SearchHistory (int);
166
static int F_LOCAL	EMACS_SearchMatch (char *, int, int);
167
static int F_LOCAL	EMACS_PatternMatch (char *, char *);
168
static int F_LOCAL	EMACS_EOTOrDelete (int);
169
static int F_LOCAL	EMACS_KillLine (int);
170
static int F_LOCAL	EMACS_GotoEnd (int);
171
static int F_LOCAL	EMACS_GotoStart (int);
172
static int F_LOCAL	EMACS_RedrawLine (int);
173
static int F_LOCAL	EMACS_Transpose (int);
174
static int F_LOCAL	EMACS_LiteralValue (int);
175
static int F_LOCAL	EMACS_Prefix1 (int);
176
static int F_LOCAL	EMACS_Prefix2 (int);
177
static int F_LOCAL	EMACS_Prefix3 (int);
178
static int F_LOCAL	EMACS_KillToEndOfLine (int);
179
static void F_LOCAL	EMACS_StackText (char *, int);
180
static void F_LOCAL	EMACS_ResetInput (void);
181
static int F_LOCAL	EMACS_YankText (int);
182
static int F_LOCAL	EMACS_PutText (int);
183
static int F_LOCAL	EMACS_Abort (int);
184
static int F_LOCAL	EMACS_Error (int);
185
static int F_LOCAL	EMACS_FullReset (int);
186
static void F_LOCAL	EMACS_MapInKeyStrokes (char *);
187
static void F_LOCAL	EMACS_MapOutKeystrokes (unsigned int);
188
static void F_LOCAL	EMACS_PrintMacros (int, int);
189
static int F_LOCAL	EMACS_SetMark (int);
190
static int F_LOCAL	EMACS_KillRegion (int);
191
static int F_LOCAL	EMACS_ExchangeCurrentAndMark (int);
192
static int F_LOCAL	EMACS_NoOp (int);
193
static int F_LOCAL	EMACS_CompleteFile (int);
194
static int F_LOCAL	EMACS_ListFiles (int);
195
static int F_LOCAL	EMACS_SubstituteFiles (int);
196
static int F_LOCAL	EMACS_FindLongestMatch (char *, char *);
197
static int F_LOCAL	EMACS_SetArgValue (int);
198
static int F_LOCAL	EMACS_Multiply (int);
199
static int F_LOCAL	EMACS_GetWordsFromHistory (int);
200
static int F_LOCAL	EMACS_FoldCase (int);
201
static int F_LOCAL	EMACS_ClearScreen (int);
202
static int F_LOCAL	EMACS_Comment (int);
203
static int F_LOCAL	EMACS_AliasInsert (int);
204
static int F_LOCAL	EMACS_GetNextCharacter (void);
205
static int F_LOCAL	EMACS_GetNonFunctionKey (void);
206
static int F_LOCAL	EMACS_FileCompletion (int);
207
static void F_LOCAL	EMACS_SaveFileName (char *, char *);
208
static void F_LOCAL	EMACS_ListSavedFileNames (void);
209
static int F_LOCAL	EMACS_YankPop (int);
210
static int F_LOCAL	EMACS_PushText (int);
211
static void F_LOCAL	EMACS_CheckArgCount (void);
212
static int F_LOCAL	EMACS_YankError (char *);
213
 
214
#  if (OS_TYPE != OS_DOS)
215
static int F_LOCAL	EMACS_DisplayJobList (int);
216
#  endif
217
#endif
218
 
219
/*
220
 * General Edit functions
221
 */
222
 
223
#if defined (FLAGS_EMACS) || defined (FLAGS_VI) || defined (FLAGS_GMACS)
224
static void F_LOCAL	GEN_BackspaceOver (int);
225
static int F_LOCAL	GEN_GetCharacterSize (int);
226
static char * F_LOCAL	GEN_FindLastVisibleCharacter (void);
227
static void F_LOCAL	GEN_OutputCharacterWithControl (int);
228
static void F_LOCAL	GEN_AdjustOutputString (char *);
229
static void F_LOCAL	GEN_Redraw (int);
230
static void F_LOCAL	GEN_PutAString (char *);
231
static void F_LOCAL	GEN_PutACharacter (int);
232
static void F_LOCAL	GEN_AdjustRedraw (void);
233
static char * F_LOCAL	GEN_FindAliasMatch (int);
234
#endif
235
 
236
/*
237
 * VI command types
238
 */
239
 
240
#if defined (FLAGS_VI)
241
#define VI_COMMAND	0x01
242
#define VI_C_MOVE	0x02
243
#define VI_C_EXTEND	0x04
244
#define VI_C_LONG	0x08
245
#define VI_C_NOTUNDO	0x10
246
#define VI_C_BAD	0x20
247
#define VI_C_META	0x40
248
#define VI_C_SEARCH	0x80
249
#define VI_C_COMMAND	(VI_C_MOVE | VI_C_EXTEND | VI_COMMAND | VI_C_NOTUNDO)
250
 
251
#define VI_IsBad(c)		(classify[c] & VI_C_BAD)
252
#define VI_IsCommand(c)		(classify[c] & VI_C_COMMAND)
253
#define VI_IsMove(c)		(classify[c] & VI_C_MOVE)
254
#define VI_IsExtend(c)		(classify[c] & VI_C_EXTEND)
255
#define VI_IsLong(c)		(classify[c] & VI_C_LONG)
256
#define VI_IsMeta(c)		(classify[c] & VI_C_META)
257
#define VI_IsUndoable(c)	(!(classify[c] & VI_C_NOTUNDO))
258
#define VI_IsSearch(c)		(classify[c] & VI_C_SEARCH)
259
 
260
static unsigned char	classify[256] = {
261
    VI_C_BAD,			/* Ctrl @ - 				*/
262
    0,				/* Ctrl A - 				*/
263
    0,				/* Ctrl B - 				*/
264
    0,				/* Ctrl C - Interrupt			*/
265
    0,				/* Ctrl D - EOF 			*/
266
    0,				/* Ctrl E - 				*/
267
    VI_C_META,			/* Ctrl F - 				*/
268
    0,				/* Ctrl G - 				*/
269
    VI_COMMAND | VI_C_MOVE,	/* Ctrl H - Delete previous char	*/
270
    0,				/* Ctrl I - 				*/
271
    VI_C_META,			/* Ctrl J - End input			*/
272
    0,				/* Ctrl K - 				*/
273
    VI_C_META | VI_C_NOTUNDO,	/* Ctrl L - Re-print line		*/
274
    VI_C_META,			/* Ctrl M - End input			*/
275
    VI_C_META,			/* Ctrl N - 				*/
276
    0,				/* Ctrl O - 				*/
277
 
278
    VI_C_META,			/* Ctrl P -				*/
279
    0,				/* Ctrl Q -				*/
280
    0,				/* Ctrl R -				*/
281
    0,				/* Ctrl S -				*/
282
    0,				/* Ctrl T -				*/
283
    0,				/* Ctrl U -				*/
284
    0,				/* Ctrl V - escape next char		*/
285
    0,				/* Ctrl W - delete previous space word	*/
286
    0,				/* Ctrl X -				*/
287
    0,				/* Ctrl Y -				*/
288
    VI_C_META,			/* Ctrl Z - EOF?			*/
289
    0,				/* Ctrl [ -				*/
290
    0,				/* Ctrl \ -				*/
291
    0,				/* Ctrl ] -				*/
292
    0,				/* Ctrl ^ -				*/
293
    0,				/* Ctrl _ -				*/
294
 
295
    VI_COMMAND | VI_C_MOVE,	/* [count]  - Move right		*/
296
    0,				/* ! -					*/
297
    0,				/* " -					*/
298
    VI_COMMAND,			/* # - Insert comment char		*/
299
    VI_C_MOVE,			/* $ - move to end of line		*/
300
    VI_COMMAND,			/* % - Match brackets			*/
301
    0,				/* & -					*/
302
    0,				/* ' -					*/
303
    0,				/* ( -					*/
304
    0,				/* ) -					*/
305
    VI_COMMAND,			/* * - File name substitution		*/
306
    VI_COMMAND,			/* [count] + - see j			*/
307
    VI_C_MOVE,			/* [count] , - repeat find		*/
308
    VI_COMMAND,			/* [count] - - see k			*/
309
    0,				/* [count] . - Redo			*/
310
    VI_COMMAND | VI_C_SEARCH,	/* [count] / - Def forward search	*/
311
 
312
    VI_C_MOVE,			/* 0 - move to start of line		*/
313
    0,				/* 1 - all digits are counts		*/
314
    0,				/* 2 -					*/
315
    0,				/* 3 -					*/
316
    0,				/* 4 -					*/
317
    0,				/* 5 -					*/
318
    0,				/* 6 -					*/
319
    0,				/* 7 -					*/
320
    0,				/* 8 -					*/
321
    0,				/* 9 -					*/
322
    0,				/* : -					*/
323
    VI_C_MOVE,			/* [count] ; - repeat find		*/
324
    0,				/* < -					*/
325
    VI_COMMAND,			/* = - Lists directory			*/
326
    0,				/* > -					*/
327
    VI_COMMAND | VI_C_SEARCH,	/* [count] ? - Def prev search string	*/
328
 
329
    VI_COMMAND | VI_C_LONG,	/* @ - Insert Alias			*/
330
    VI_COMMAND,			/* A - append to end of line		*/
331
    VI_C_MOVE,			/* [count] B - back a spaced word	*/
332
    VI_COMMAND,			/* C - change to end of line		*/
333
    VI_COMMAND,			/* D - delete to end of line		*/
334
    VI_C_MOVE,			/* [count] E - go to end of spaced word	*/
335
    VI_C_MOVE | VI_C_LONG,	/* [count] F - find previous char	*/
336
    VI_COMMAND,			/* G - Get history entry		*/
337
    0,				/* H -					*/
338
    VI_COMMAND,			/* I - Insert at start of line		*/
339
    0,				/* J -					*/
340
    0,				/* K -					*/
341
    0,				/* L -					*/
342
    0,				/* M -					*/
343
    VI_COMMAND,			/* N - Search backwards			*/
344
    0,				/* O -					*/
345
 
346
    VI_COMMAND,			/* P - Place previous mod before	*/
347
    0,				/* Q -					*/
348
    VI_COMMAND,			/* R - Replace til ESC			*/
349
    VI_COMMAND,			/* S - Substitute whole line		*/
350
    VI_C_MOVE | VI_C_LONG,	/* T - equiv to F l			*/
351
    VI_COMMAND,			/* U - Undo all				*/
352
    0,				/* V -					*/
353
    VI_C_MOVE,			/* [count] W - Move to next spaced word	*/
354
    VI_COMMAND,			/* [count] X - delete previous		*/
355
    VI_COMMAND,			/* Y - Yank rest of link		*/
356
    0,				/* Z -					*/
357
    0,				/* [ -					*/
358
    VI_COMMAND,			/* \ - File Name completion		*/
359
    0,				/* ] -					*/
360
    VI_C_MOVE,			/* ^ - Move to first non-blank in line	*/
361
    VI_COMMAND,			/* [count] _ - Get word from previous C	*/
362
 
363
    0,				/* ` -					*/
364
    VI_COMMAND,			/* a - insert after cursor		*/
365
    VI_C_MOVE,			/* [count] b - Move backward a word	*/
366
    VI_C_EXTEND,		/* [count] c - Change chars		*/
367
    VI_C_EXTEND,		/* [count] d - Delete chars		*/
368
    VI_C_MOVE,			/* [count] e - Move to end of word	*/
369
    VI_C_MOVE | VI_C_LONG,	/* [count] f - Find next char		*/
370
    0,				/* g -					*/
371
    VI_C_MOVE,			/* [count] h - Move left a char		*/
372
    VI_COMMAND,			/* i - insert before			*/
373
    VI_COMMAND,			/* [count] j - Get next history		*/
374
    VI_COMMAND,			/* [count] k - Get pre history		*/
375
    VI_C_MOVE,			/* [count] l - Move right a char	*/
376
    0,				/* m -					*/
377
    VI_COMMAND,			/* [count] n - Search next		*/
378
    0,				/* o -					*/
379
 
380
    VI_COMMAND,			/* p - Place previous mod after		*/
381
    0,				/* q -					*/
382
    VI_COMMAND,			/* [count] r - replace chars		*/
383
    VI_COMMAND,			/* [count] s - substitute chars		*/
384
    VI_C_MOVE | VI_C_LONG,	/* t - equiv to f l			*/
385
    VI_COMMAND | VI_C_NOTUNDO,	/* u - undo				*/
386
    VI_COMMAND | VI_C_NOTUNDO,	/* v - invoke editor			*/
387
    VI_C_MOVE,			/* [count] w - Move forward a word	*/
388
    VI_COMMAND,			/* [count] x - Delete current character	*/
389
    VI_C_EXTEND,		/* [count] y - Yank count		*/
390
    0,				/* z -					*/
391
    0,				/* { -					*/
392
    VI_C_MOVE,			/* [count] | - Move to column		*/
393
    0,				/* } -					*/
394
    VI_COMMAND,			/* [count] ~ - Change case		*/
395
 
396
};
397
 
398
/*
399
 * Map ini keyboard functions to vi functions.  Some are not yet supported.
400
 */
401
 
402
static unsigned char	VI_IniMapping[] = {
403
    '?', 				/* Scan backwards in history	*/
404
    '/',				/* Scan forewards in history	*/
405
    'k',				/* Previous command		*/
406
    'j',				/* Next command			*/
407
    'h',				/* Left one character		*/
408
    'l',				/* Right one character		*/
409
    'w',				/* Right one word		*/
410
    'b',				/* Left one word		*/
411
    '0',				/* Move to start of line	*/
412
    'C',				/* Clear input line		*/
413
    'D',				/* Flush to end of line		*/
414
    CHAR_END_LINE,			/* End of line			*/
415
    'i',				/* Insert mode switch		*/
416
    'x',				/* Delete right character	*/
417
    'X',				/* Delete left character	*/
418
    CHAR_META,				/* Complete file name		*/
419
    '=',				/* Complete directory function	*/
420
    0,					/* Clear screen			*/
421
    0,					/* Print Job tree		*/
422
    0,					/* Transpose characters		*/
423
    0x016,				/* Quote character		*/
424
};
425
 
426
#define VI_MAX_CMD_LENGTH	3
427
#define VI_MAX_SRCH_LENGTH	40
428
 
429
#define VI_UNDEF_MODE		0	/* Undefined			*/
430
#define VI_INSERT_MODE		1	/* Insert mode			*/
431
#define VI_REPLACE_MODE		2	/* Replace mode			*/
432
 
433
#define VI_S_NORMAL		0	/* Normal input mode		*/
434
#define VI_S_ARG1		1	/* Getting argument 1		*/
435
#define VI_S_EXTENDED_CMD	2	/* Extended command		*/
436
#define VI_S_ARG2		3	/* Getting argument 2		*/
437
#define VI_S_EXCHANGE		4
438
#define VI_S_FAIL		5	/* Error state			*/
439
#define VI_S_EXECUTE		6	/* Execute command		*/
440
#define VI_S_REDO		7	/* Redo last command		*/
441
#define VI_S_LIT		8
442
#define VI_S_SEARCH		9	/* Search mode			*/
443
#define VI_S_REPLACE1CHAR	10	/* Replace single char		*/
444
 
445
/*
446
 * VI Editor status structure
447
 */
448
 
449
struct edstate {
450
    int		WindowLeftColumn;
451
    int		InputLength;
452
    int		CursorColumn;
453
};
454
 
455
/*
456
 * The VI editor status and undo buffer status
457
 */
458
 
459
static struct edstate	vi_EditorState;
460
static struct edstate	vi_UndoState;
461
 
462
#define VI_InputLength		vi_EditorState.InputLength
463
#define VI_CurrentColumn	vi_EditorState.CursorColumn
464
 
465
/*
466
 * The VI insert buffer
467
 */
468
 
469
static char	vi_InsertBuffer[LINE_MAX + 1];/* input buffer		*/
470
static int	vi_InsertBufferLength;	/* length of input buffer	*/
471
 
472
					/* last search pattern		*/
473
static char	vi_SearchPattern[VI_MAX_SRCH_LENGTH];
474
static int	vi_SearchPatternLength;	/* length of current search pattern */
475
					/* last search command		*/
476
static int	vi_LastSearchCommand = CHAR_SPACE;
477
 
478
					/* last find command		*/
479
static int	vi_LastFindCommand = CHAR_SPACE;
480
					/* character to find		*/
481
static int	vi_LastFindCharacter;
482
					/* The Yank buffer		*/
483
static char	*vi_YankBuffer = (char *)NULL;
484
					/* last non-move command	*/
485
static char	vi_PreviousCommand[VI_MAX_CMD_LENGTH];
486
static int	vi_PrevCmdArgCount;	/* argcnt for vi_PreviousCommand*/
487
static char	*vi_HoldBuffer = null;	/* last edit buffer		*/
488
 
489
static bool	vi_InputBufferChanged;	/* buffer has been "modified"	*/
490
static int	vi_Insert;		/* non-zero in insert mode	*/
491
static int	vi_State;
492
static int	vi_WhichWindow;		/* window buffer in use		*/
493
static char	vi_MoreIndicator;	/* more char at right of window	*/
494
					/* Alias input buffer		*/
495
static char	*vi_AliasBuffer = (char *)NULL;
496
					/* The undo save buffer		*/
497
static char	*vi_UndoBuffer = null;
498
#endif
499
 
500
/*
501
 * EMACS statics
502
 */
503
 
504
#if defined (FLAGS_EMACS) || defined (FLAGS_GMACS)
505
 
506
/* File Completion functions */
507
 
508
#define EMACS_FN_LIST		0
509
#define EMACS_FN_COMPLETE	1
510
#define EMACS_FN_SUBSTITUTE	2
511
 
512
/* Values returned by keyboard functions */
513
 
514
#define	EMACS_KEY_NORMAL	0
515
#define	EMACS_KEY_META		1		/* ^[, ^X */
516
#define	EMACS_KEY_EOL		2		/* ^M, ^J */
517
#define	EMACS_KEY_INTERRUPT	3		/* ^G, ^C */
518
#define	EMACS_KEY_NOOP		4
519
 
520
/* Function table structure */
521
 
522
typedef struct EMACS_FunctionMap  {
523
    int			(F_LOCAL * xf_func)(int);
524
    char		*emacs_FunctionName;
525
    char		emacs_TableNumber;
526
    unsigned char	emacs_KeyStroke;
527
    unsigned char	emacs_FunctionFlags;
528
} EMACS_FunctionMap;
529
 
530
/* emacs_FunctionFlags values */
531
 
532
#define	EMACS_MEMORY_ALLOC	0x40	/* ALlocate memory		*/
533
#define	EMACS_NO_BIND		0x80	/* No binding			*/
534
#define EMACS_INI_MASK		0x1f	/* bottom 5 bits		*/
535
 
536
					/* Check for word separator	*/
537
#define	EMACS_IS_SPACE(c)	(!(isalnum (c)|| c == '$'))
538
 
539
#define EMACS_KEYDEF_TABLES	4	/* number of keydef tables etc	*/
540
#define EMACS_KEYDEF_ENTRIES	256	/* size of keydef tables etc	*/
541
#define	EMACS_KILL_SIZE		20	/* Yank/Kill stack size		*/
542
 
543
static int	emacs_Prefix1 = CHAR_OPEN_BRACKETS & 0x01f;
544
static int	emacs_Prefix2 = 'X' & 0x01f;
545
static int	emacs_Prefix3 = 0xE0;
546
static char	*emacs_MarkPointer;		/* mark pointer		*/
547
static int	emacs_NextCommandIs = -1;	/* for newline-and-next	*/
548
static int	(F_LOCAL *emacs_LastCommand)(int) = (int (F_LOCAL *)(int))NULL;
549
 
550
static int	emacs_UnGetCharacter = -1;	/* Unget character	*/
551
static char	*emacs_NTY = "\nnothing to yank";
552
 
553
/*
554
 * Key and macro structures
555
 */
556
 
557
static EMACS_FunctionMap *(*emacs_KeyDefinitions)[EMACS_KEYDEF_ENTRIES] = NULL;
558
static char		 *(*emacs_MacroDefinitions)[EMACS_KEYDEF_ENTRIES] = NULL;
559
 
560
						/* Stack info		*/
561
static char		*emacs_Stack[EMACS_KILL_SIZE];
562
static int		emacs_StackPointer;
563
static int		emacs_TopOfStack;
564
 
565
static int		emacs_CurrentPrefix;
566
static char		*emacs_CurrentMacroString;
567
static int		emacs_MaxFilenameSize;	/* to determine column width */
568
static Word_B		*EMACS_Flist = (Word_B *)NULL;
569
 
570
static int		emacs_ArgumentCount = 0;/* general purpose arg	*/
571
 
572
/*
573
 * EMACS command table
574
 */
575
 
576
static EMACS_FunctionMap	EMACS_FunctionMaps[] = {
577
    {EMACS_AutoInsert,	"auto-insert",		0,	0,
578
		    	KF_INSERT },
579
    {EMACS_Error,	"error",		0,	0,		0 },
580
    {EMACS_InsertMacroString,
581
			"macro-string",		0,	0,
582
					EMACS_NO_BIND | EMACS_MEMORY_ALLOC },
583
    {EMACS_AliasInsert,	null,			0,	 0,		0 },
584
 
585
#define	EMACS_INSERT_MAP	&EMACS_FunctionMaps[0]
586
#define	EMACS_ERROR_MAP		&EMACS_FunctionMaps[1]
587
#define	EMACS_MACRO_MAP		&EMACS_FunctionMaps[2]
588
#define EMACS_ALIAS_MAP		&EMACS_FunctionMaps[3]
589
 
590
/* Do not move the above!!! */
591
 
592
/*
593
 * Movement and delete functions
594
 */
595
 
596
    {EMACS_GotoEnd,	"end-of-line",		0,	'E' & 0x01f,
597
    			KF_END },
598
    {EMACS_GotoStart,	"beginning-of-line",	0,	'A' & 0x01f,
599
    			KF_START },
600
    {EMACS_KillLine,	"kill-line",		0, 	'U' & 0x01f,
601
    			KF_CLEAR },
602
    {EMACS_KillToEndOfLine,
603
			"kill-to-eol",		0, 	'K' & 0x01f,
604
			KF_FLUSH },
605
 
606
    {EMACS_NextCharacter,
607
			"forward-char",		0,	'F' & 0x01f,
608
			KF_RIGHT },
609
    {EMACS_MoveForwardAWord,
610
			"forward-word",		1,	'F',
611
			KF_WORDRIGHT },
612
    {EMACS_PreviousCharacter,
613
			"backward-char",	0,	'B' & 0x01f,
614
			KF_LEFT },
615
    {EMACS_MoveBackAWord,
616
			"backward-word", 	1,	'B',
617
			KF_WORDLEFT },
618
 
619
    {EMACS_DeleteCurrentCharacter,
620
			"delete-char-forward",	0,	0,
621
			KF_DELETERIGHT },
622
    {EMACS_DeleteNextWord,
623
			"delete-word-forward", 	1,	'D',		0 },
624
 
625
    {EMACS_DeleteCharacterBackwards,
626
			"delete-char-backward",	0,	CHAR_BACKSPACE,
627
			KF_DELETELEFT },
628
    {EMACS_DeletePreviousWord,
629
			"delete-word-backward",	1,	CHAR_BACKSPACE,	0 },
630
    {EMACS_DeletePreviousWord,
631
			"delete-word-backward",	1,	'H',		0 },
632
 
633
/*
634
 * Search character functions
635
 */
636
 
637
    {EMACS_ForwardToCharacter,
638
			"search-char-forward",	0,	']' & 0x01f,	0 },
639
    {EMACS_BackwardToCharacter,
640
			"search-char-backward", 1,	']' & 0x01f,	0 },
641
 
642
/*
643
 * End of text functions
644
 */
645
 
646
    {EMACS_NewLine,	"newline",		0,	CHAR_RETURN,	0 },
647
    {EMACS_NewLine,	"newline",		0,	CHAR_NEW_LINE,	0 },
648
    {EMACS_EndOfInput,	"eot",			0,	'_' & 0x01f,	0 },
649
    {EMACS_Abort,	"abort",		0,	'G' & 0x01f,	0 },
650
    {EMACS_NoOp,	"no-op",		0,	0,		0 },
651
    {EMACS_EOTOrDelete, "eot-or-delete",	0,	'D' & 0x01f,	0 },
652
 
653
/*
654
 * History functions
655
 */
656
 
657
    {EMACS_GetPreviousCommand,
658
			"up-history",		0,	'P' & 0x01f,
659
			KF_PREVIOUS },
660
    {EMACS_GetNextCommand,
661
			"down-history",		0,	'N' & 0x01f,
662
			KF_NEXT},
663
    {EMACS_SearchHistory,
664
			"search-history",	0,	'R' & 0x01f,
665
			KF_SCANFOREWARD },
666
    {EMACS_GetFirstHistory,
667
			"beginning-of-history",	1,	'<',		0 },
668
    {EMACS_GetLastHistory,
669
			"end-of-history",	1,	'>',		0 },
670
    {EMACS_OperateOnLine,
671
			"operate",		0, 	'O' & 0x01f,	0 },
672
    {EMACS_GetWordsFromHistory,
673
			"prev-hist-word", 	1,	CHAR_PERIOD,	0 },
674
    {EMACS_GetWordsFromHistory,
675
			"copy-last-arg", 	1,	'_',		0 },
676
 
677
    {EMACS_RedrawLine,	"redraw",		0, 	'L' & 0x01f,	0 },
678
    {EMACS_ClearScreen,	"clear-screen",		0,	0,
679
			KF_CLEARSCREEN },
680
    {EMACS_Prefix1,	"prefix-1",		0,	CHAR_ESCAPE,	0 },
681
    {EMACS_Prefix2,	"prefix-2",		0,	'X' & 0x01f,	0 },
682
    {EMACS_Prefix3,	"prefix-3",		0, 	0xE0,		0 },
683
    {EMACS_LiteralValue,
684
			"quote",		0, 	'^' & 0x01f,	0 },
685
    {EMACS_LiteralValue,
686
			"quote",		0, 	CHAR_META,
687
			KF_QUOTE },
688
 
689
    {EMACS_PushText,	"push-text",		1, 	'p',		0 },
690
    {EMACS_YankText,	"yank-text",		1, 	'P',		0 },
691
    {EMACS_PutText,	"pop-text", 		0,	'Y' & 0x01f,	0 },
692
    {EMACS_YankPop,	"yank-pop", 		1,	'y',		0 },
693
    {EMACS_Transpose,	"transpose-chars",	0, 	'T' & 0x01f,
694
			KF_TRANSPOSE },
695
    {EMACS_SetMark,	"set-mark",		1,	CHAR_SPACE,	0 },
696
    {EMACS_KillRegion,	"kill-region",		0, 	'W' & 0x01f,	0 },
697
    {EMACS_ExchangeCurrentAndMark,
698
			"exchange-point-and-mark", 2,	'X' & 0x01f,	0 },
699
 
700
    {EMACS_FullReset, 	"reset",		0,	 0,		0 },
701
 
702
    {EMACS_CompleteFile,
703
			"complete",		1, 	CHAR_ESCAPE,
704
			KF_COMPLETE },
705
    {EMACS_SubstituteFiles,
706
			"complete-list",	1,	'*',		0 },
707
    {EMACS_ListFiles,	"list",			1,	'=',
708
			KF_DIRECTORY },
709
 
710
#  if (OS_TYPE != OS_DOS)
711
    {EMACS_DisplayJobList,
712
			"jobs",		        2,	'j',
713
			KF_JOBS },
714
#  endif
715
 
716
    {EMACS_Comment,	"comment-execute",      1,	'#',    	0 },
717
 
718
    {EMACS_SetArgValue,	null,			1,	'0',		0 },
719
    {EMACS_SetArgValue,	null,			1,	'1',		0 },
720
    {EMACS_SetArgValue,	null,			1,	'2',		0 },
721
    {EMACS_SetArgValue,	null,			1,	'3',		0 },
722
    {EMACS_SetArgValue,	null,			1,	'4',		0 },
723
    {EMACS_SetArgValue,	null,			1,	'5',		0 },
724
    {EMACS_SetArgValue,	null,			1,	'6',		0 },
725
    {EMACS_SetArgValue,	null,			1,	'7',		0 },
726
    {EMACS_SetArgValue,	null,			1,	'8',		0 },
727
    {EMACS_SetArgValue,	null,			1,	'9',		0 },
728
    {EMACS_Multiply,	"multiply",		1, 	'M',		0 },
729
 
730
    {EMACS_FoldCase,	"upcase-word",		1,	'U',		0 },
731
    {EMACS_FoldCase,	"downcase-word",	1,	'L',		0 },
732
    {EMACS_FoldCase,	"capitalise-word",	1,	'C',		0 },
733
    {EMACS_FoldCase,	"upcase-char",		1,	'u',		0 },
734
    {EMACS_FoldCase,	"downcase-char",	1,	'l',		0 },
735
    {EMACS_FoldCase,	"capitalise-char",	1,	'c',		0 },
736
    { NULL }
737
};
738
 
739
#endif
740
 
741
/*
742
 * General statics
743
 */
744
 
745
#if defined (FLAGS_EMACS) || defined (FLAGS_VI) || defined (FLAGS_GMACS)
746
static bool	LastVisibleCharValid = FALSE;
747
static int	CurrentScreenPosition;	/* current column on line	*/
748
static int	PromptWidth;		/* width of prompt		*/
749
static int	WindowWidth;		/* width of window		*/
750
					/* The window buffers		*/
751
static char	*WindowBuffer[] = { (char *)NULL, (char *)NULL };
752
static int	CurrentHistoryEvent;	/* position in history		*/
753
 
754
static char	*emacs_CurrentPosition;	/* current position		*/
755
static char	*emacs_EndOfLine;	/* current end of line		*/
756
static char	*emacs_StartVisible;	/* start of visible portion of	*/
757
					/* input buffer			*/
758
					/* last char visible on screen	*/
759
static char	*emacs_LastVisibleCharacter;
760
 
761
/*
762
 * we use AdjustDone so that functions can tell
763
 * whether GEN_AdjustRedraw () has been called while they are active.
764
 */
765
 
766
static int	AdjustDone = 0;
767
static bool	AdjustOK = TRUE;
768
static int	CurrentScreenColumn = 0;
769
static int	DisplayWidth;
770
#endif
771
 
772
/*
773
 * VI mode functions
774
 *
775
 * The VI State machine
776
 */
777
 
778
#if defined (FLAGS_VI)
779
static bool F_LOCAL VI_StateMachine (int ch)
780
{
781
    static char		curcmd[VI_MAX_CMD_LENGTH];
782
    static char		locpat[VI_MAX_SRCH_LENGTH];
783
    static int		cmdlen;
784
    static int		argc1, argc2;
785
 
786
    if ((vi_State != VI_S_SEARCH) &&
787
        ((ch == CHAR_RETURN || ch == CHAR_NEW_LINE)))
788
    {
789
	GEN_PutACharacter (CHAR_RETURN);
790
	GEN_PutACharacter (CHAR_NEW_LINE);
791
	FlushStreams ();
792
	return TRUE;
793
    }
794
 
795
    switch (vi_State)
796
    {
797
	case VI_S_REPLACE1CHAR:
798
	    curcmd[cmdlen++] = (char)ch;
799
	    vi_State = VI_S_EXECUTE;
800
	    break;
801
 
802
	case VI_S_NORMAL:
803
	    if (vi_Insert != VI_UNDEF_MODE)
804
	    {
805
		if ((ch == ('V' & 0x01f)) || (ch == CHAR_META))
806
		{
807
		    vi_State = VI_S_LIT;
808
		    ch = (ch == ('V' & 0x01f)) ? '^' : CHAR_META;
809
		}
810
 
811
		if (VI_InsertCharacter (ch) != 0)
812
		{
813
		    RingWarningBell ();
814
		    vi_State = VI_S_NORMAL;
815
		}
816
 
817
		else if (vi_State == VI_S_LIT)
818
		{
819
		    VI_CurrentColumn--;
820
		    VI_Refresh (FALSE);
821
		}
822
 
823
		else
824
		    VI_Refresh (C2bool (vi_Insert != VI_UNDEF_MODE));
825
	    }
826
 
827
	    else
828
	    {
829
		cmdlen = 0;
830
		argc1 = 0;
831
 
832
		if ((ch != '0') && isdigit (ch))
833
		{
834
		    argc1 = ch - '0';
835
		    vi_State = VI_S_ARG1;
836
		}
837
 
838
		else
839
		{
840
		    curcmd[cmdlen++] = (char)ch;
841
		    vi_State = VI_GetNextState (ch);
842
 
843
		    if (vi_State == VI_S_SEARCH)
844
		    {
845
			VI_CopyInput2Hold ();
846
			VI_CurrentColumn = 0;
847
   			ConsoleLineBuffer[VI_InputLength = 0] = 0;
848
 
849
			if (ch == '/')
850
			{
851
			    if (VI_InsertIntoBuffer (DirectorySeparator, 1,
852
			    			     FALSE) != 0)
853
				return TRUE;
854
			}
855
 
856
			else if (VI_InsertIntoBuffer ("?", 1, FALSE) != 0)
857
			    return TRUE;
858
 
859
			VI_Refresh (FALSE);
860
		    }
861
		}
862
	    }
863
 
864
	    break;
865
 
866
	case VI_S_LIT:
867
	    if (VI_IsBad (ch))
868
	    {
869
		VI_DeleteRange (VI_CurrentColumn, VI_CurrentColumn + 1);
870
		RingWarningBell ();
871
	    }
872
 
873
/* If control V - then replace ^ with character */
874
 
875
	    else if (ConsoleLineBuffer[VI_CurrentColumn] == '^')
876
		ConsoleLineBuffer[VI_CurrentColumn++] = (char)ch;
877
 
878
/* If \, the check for specials and replace \ with special.  Otherwise,
879
 * include the \ as well
880
 */
881
 
882
	    else
883
	    {
884
	        switch (ch)
885
		{
886
		    case CHAR_ESCAPE:
887
		    case 0x7f:
888
		    case CHAR_BACKSPACE:
889
		    case 'U' & 0x01f:
890
		    case 'W' & 0x01f:
891
		    case CHAR_META:
892
			ConsoleLineBuffer[VI_CurrentColumn++] = (char)ch;
893
			break;
894
 
895
/* Insert the real character */
896
 
897
		    default:
898
			VI_CurrentColumn++;
899
			if (VI_InsertCharacter (ch) != 0)
900
			    RingWarningBell ();
901
	    	}
902
	    }
903
 
904
	    VI_Refresh (TRUE);
905
	    vi_State = VI_S_NORMAL;
906
	    break;
907
 
908
	case VI_S_ARG1:
909
	    if (IS_Numeric (ch))
910
		argc1 = argc1 * 10 + ch - '0';
911
 
912
	    else
913
	    {
914
		curcmd[cmdlen++] = (char)ch;
915
		vi_State = VI_GetNextState (ch);
916
	    }
917
 
918
	    break;
919
 
920
	case VI_S_EXTENDED_CMD:
921
	    argc2 = 0;
922
 
923
	    if (ch >= '1' && ch <= '9')
924
	    {
925
		argc2 = ch - '0';
926
		vi_State = VI_S_ARG2;
927
		return FALSE;
928
	    }
929
 
930
	    else
931
	    {
932
		curcmd[cmdlen++] = (char)ch;
933
 
934
		if (ch == curcmd[0])
935
		    vi_State = VI_S_EXECUTE;
936
 
937
		else if (VI_IsMove (ch))
938
		    vi_State = VI_GetNextState (ch);
939
 
940
		else
941
		    vi_State = VI_S_FAIL;
942
	    }
943
 
944
	    break;
945
 
946
	case VI_S_ARG2:
947
	    if (IS_Numeric (ch))
948
		argc2 = argc2 * 10 + ch - '0';
949
 
950
	    else
951
	    {
952
		if (argc1 == 0)
953
		    argc1 = argc2;
954
 
955
		else
956
		    argc1 *= argc2;
957
 
958
		curcmd[cmdlen++] = (char)ch;
959
 
960
		if (ch == curcmd[0])
961
		    vi_State = VI_S_EXECUTE;
962
 
963
		else if (VI_IsMove (ch))
964
		    vi_State = VI_GetNextState (ch);
965
 
966
		else
967
		    vi_State = VI_S_FAIL;
968
	    }
969
 
970
	    break;
971
 
972
	case VI_S_EXCHANGE:
973
	    if (ch == CHAR_ESCAPE)
974
		vi_State = VI_S_NORMAL;
975
 
976
	    else
977
	    {
978
		curcmd[cmdlen++] = (char)ch;
979
		vi_State = VI_S_EXECUTE;
980
	    }
981
	    break;
982
 
983
	case VI_S_SEARCH:
984
	    switch (ch)
985
	    {
986
		case CHAR_RETURN:
987
		case CHAR_NEW_LINE:
988
		    locpat[vi_SearchPatternLength] = 0;
989
		    strcpy (vi_SearchPattern, locpat);
990
		    /* VI_RedrawLine(); */
991
		    vi_State = VI_S_EXECUTE;
992
		    break;
993
 
994
		case 0x7f:
995
		case 0x08:
996
		    if (vi_SearchPatternLength == 0)
997
		    {
998
			VI_CopyHold2Input ();
999
			vi_State = VI_S_NORMAL;
1000
		    }
1001
 
1002
		    else
1003
		    {
1004
			vi_SearchPatternLength--;
1005
 
1006
			if ((locpat[vi_SearchPatternLength] < CHAR_SPACE) ||
1007
			    (locpat[vi_SearchPatternLength] == 0x7f))
1008
			    VI_InputLength--;
1009
 
1010
			VI_InputLength--;
1011
   			ConsoleLineBuffer[VI_CurrentColumn =
1012
							VI_InputLength] = 0;
1013
 
1014
			VI_Refresh (FALSE);
1015
			return FALSE;
1016
		    }
1017
 
1018
		    VI_Refresh (FALSE);
1019
		    break;
1020
 
1021
		case ('U' & 0x01f):
1022
		    vi_SearchPatternLength = 0;
1023
		    ConsoleLineBuffer[1] = 0;
1024
		    VI_InputLength = 1;
1025
		    VI_CurrentColumn = 1;
1026
		    VI_Refresh (FALSE);
1027
		    return FALSE;
1028
 
1029
		default:
1030
		    if (vi_SearchPatternLength == VI_MAX_SRCH_LENGTH - 1)
1031
			RingWarningBell ();
1032
 
1033
		    else
1034
		    {
1035
			locpat[vi_SearchPatternLength++] = (char)ch;
1036
 
1037
			if ((ch < CHAR_SPACE) || (ch == 0x7f))
1038
			{
1039
			    ConsoleLineBuffer[VI_InputLength++] = '^';
1040
			    ConsoleLineBuffer[VI_InputLength++] =
1041
						(char)(ch ^ '@');
1042
			}
1043
 
1044
			else
1045
			    ConsoleLineBuffer[VI_InputLength++] = (char)ch;
1046
 
1047
   			ConsoleLineBuffer[VI_CurrentColumn =
1048
					VI_InputLength] = 0;
1049
 
1050
			VI_Refresh (FALSE);
1051
		    }
1052
 
1053
		    return FALSE;
1054
	    }
1055
 
1056
	    break;
1057
    }
1058
 
1059
    switch (vi_State)
1060
    {
1061
	case VI_S_EXECUTE:
1062
	    vi_State = VI_S_NORMAL;
1063
 
1064
	    switch (VI_ExecuteCommand (argc1, curcmd))
1065
	    {
1066
		case -1:
1067
		    RingWarningBell ();
1068
		    break;
1069
 
1070
		case 0:
1071
		    if (vi_Insert != VI_UNDEF_MODE)
1072
			vi_InsertBufferLength = 0;
1073
 
1074
		    VI_Refresh (C2bool (vi_Insert != VI_UNDEF_MODE));
1075
		    break;
1076
 
1077
		case 1:
1078
		    VI_Refresh (FALSE);
1079
		    GEN_PutACharacter (CHAR_RETURN);
1080
		    GEN_PutACharacter (CHAR_NEW_LINE);
1081
		    FlushStreams ();
1082
		    return TRUE;
1083
	    }
1084
 
1085
	    break;
1086
 
1087
	case VI_S_REDO:
1088
	    vi_State = VI_S_NORMAL;
1089
 
1090
	    if (argc1 != 0)
1091
		vi_PrevCmdArgCount = argc1;
1092
 
1093
	    switch (VI_ExecuteCommand (vi_PrevCmdArgCount, vi_PreviousCommand))
1094
	    {
1095
		case -1:
1096
		    RingWarningBell ();
1097
		    VI_Refresh (FALSE);
1098
		    break;
1099
 
1100
		case 0:
1101
		    if (vi_Insert != VI_UNDEF_MODE)
1102
		    {
1103
			if ((vi_PreviousCommand[0] == 's') ||
1104
			    (vi_PreviousCommand[0] == 'c') ||
1105
			    (vi_PreviousCommand[0] == 'C'))
1106
			{
1107
			    if (VI_RedoInsert (1) != 0)
1108
				RingWarningBell ();
1109
			}
1110
 
1111
			else if (VI_RedoInsert (vi_PrevCmdArgCount) != 0)
1112
			    RingWarningBell ();
1113
		    }
1114
 
1115
		    VI_Refresh (FALSE);
1116
		    break;
1117
 
1118
		case 1:
1119
		    VI_Refresh (FALSE);
1120
		    GEN_PutACharacter (CHAR_RETURN);
1121
		    GEN_PutACharacter (CHAR_NEW_LINE);
1122
		    FlushStreams ();
1123
		    return TRUE;
1124
	    }
1125
 
1126
	    break;
1127
 
1128
	case VI_S_FAIL:
1129
	    vi_State = VI_S_NORMAL;
1130
	    RingWarningBell ();
1131
	    break;
1132
    }
1133
 
1134
    return FALSE;
1135
}
1136
 
1137
/* Probably could have been done more elegantly than by creating a new
1138
 * state, but it works
1139
 */
1140
 
1141
static int F_LOCAL VI_GetNextState (int ch)
1142
{
1143
    if (ch == 'r')
1144
	return VI_S_REPLACE1CHAR;
1145
 
1146
    else if (VI_IsExtend (ch))
1147
	return VI_S_EXTENDED_CMD;
1148
 
1149
    else if (VI_IsSearch (ch))
1150
	return VI_S_SEARCH;
1151
 
1152
    else if (VI_IsLong (ch))
1153
	return VI_S_EXCHANGE;
1154
 
1155
    else if (ch == CHAR_PERIOD)
1156
	return VI_S_REDO;
1157
 
1158
    else if (VI_IsCommand (ch))
1159
	return VI_S_EXECUTE;
1160
 
1161
    else
1162
	return VI_S_FAIL;
1163
}
1164
 
1165
/*
1166
 * Insert a character into the VI line buffer
1167
 */
1168
 
1169
static int F_LOCAL VI_InsertCharacter (int ch)
1170
{
1171
    int		tcursor;
1172
 
1173
    switch (ch)
1174
    {
1175
	case 0:
1176
	    return -1;
1177
 
1178
	case CHAR_ESCAPE:
1179
	    if ((vi_PreviousCommand[0] == 's') ||
1180
	        (vi_PreviousCommand[0] == 'c') ||
1181
		(vi_PreviousCommand[0] == 'C'))
1182
		return VI_RedoInsert (0);
1183
 
1184
	    else
1185
		return VI_RedoInsert (vi_PrevCmdArgCount - 1);
1186
 
1187
	case 0x7f:			/* delete */
1188
	case CHAR_BACKSPACE:		/* delete */
1189
	    if (VI_CurrentColumn != 0)
1190
	    {
1191
		if (vi_InsertBufferLength > 0)
1192
		    vi_InsertBufferLength--;
1193
 
1194
		VI_CurrentColumn--;
1195
 
1196
		if (vi_Insert != VI_REPLACE_MODE)
1197
		{
1198
		    memmove (&ConsoleLineBuffer[VI_CurrentColumn],
1199
		    	     &ConsoleLineBuffer[VI_CurrentColumn+1],
1200
			     VI_InputLength - VI_CurrentColumn);
1201
 
1202
		    VI_InputLength--;
1203
		    ConsoleLineBuffer[VI_InputLength] = 0;
1204
		}
1205
	    }
1206
 
1207
	    break;
1208
 
1209
	case ('U' & 0x01f):
1210
	    if (VI_CurrentColumn != 0)
1211
	    {
1212
		vi_InsertBufferLength = 0;
1213
		memmove (ConsoleLineBuffer,
1214
			 &ConsoleLineBuffer[VI_CurrentColumn],
1215
			 VI_InputLength - VI_CurrentColumn);
1216
 
1217
		VI_InputLength -= VI_CurrentColumn;
1218
		ConsoleLineBuffer[VI_InputLength] = 0;
1219
		VI_CurrentColumn = 0;
1220
	    }
1221
 
1222
	    break;
1223
 
1224
	case ('W' & 0x01f):
1225
	    if (VI_CurrentColumn != 0)
1226
	    {
1227
		tcursor = VI_BackwardWord(1);
1228
		memmove (&ConsoleLineBuffer[tcursor],
1229
			 &ConsoleLineBuffer[VI_CurrentColumn],
1230
			 VI_InputLength - VI_CurrentColumn);
1231
 
1232
		VI_InputLength -= VI_CurrentColumn - tcursor;
1233
		ConsoleLineBuffer[VI_InputLength] = 0;
1234
 
1235
		if (vi_InsertBufferLength < VI_CurrentColumn - tcursor)
1236
		    vi_InsertBufferLength = 0;
1237
 
1238
		else
1239
		    vi_InsertBufferLength -= VI_CurrentColumn - tcursor;
1240
 
1241
		VI_CurrentColumn = tcursor;
1242
	    }
1243
 
1244
	    break;
1245
 
1246
	default:
1247
	    if (VI_InputLength == LINE_MAX)
1248
		return -1;
1249
 
1250
	    vi_InsertBuffer[vi_InsertBufferLength++] = (char)ch;
1251
 
1252
	    if (vi_Insert == VI_INSERT_MODE)
1253
	    {
1254
		memmove (&ConsoleLineBuffer[VI_CurrentColumn + 1],
1255
			 &ConsoleLineBuffer[VI_CurrentColumn],
1256
			 VI_InputLength - VI_CurrentColumn);
1257
 
1258
		VI_InputLength++;
1259
	    }
1260
 
1261
	    ConsoleLineBuffer[VI_CurrentColumn++] = (char)ch;
1262
 
1263
	    if ((vi_Insert == VI_REPLACE_MODE) &&
1264
	        (VI_CurrentColumn > VI_InputLength))
1265
		VI_InputLength++;
1266
 
1267
	    ConsoleLineBuffer[VI_InputLength] = 0;
1268
    }
1269
 
1270
    return 0;
1271
}
1272
 
1273
/*
1274
 * Process the current command
1275
 */
1276
 
1277
static int F_LOCAL VI_ExecuteCommand (int argcnt, char *cmd)
1278
{
1279
    int			cur;
1280
 
1281
    if ((argcnt == 0) && (*cmd != '_') && (*cmd != 'v'))
1282
    {
1283
	if (*cmd == 'G')
1284
	    argcnt = GetLastHistoryEvent () + 1;
1285
 
1286
	else
1287
	    argcnt = 1;
1288
    }
1289
 
1290
    if (VI_IsMove ((int)*cmd))
1291
    {
1292
	if ((cur = VI_ExecuteMove (argcnt, cmd, FALSE)) >= 0)
1293
	{
1294
	    if ((cur == VI_InputLength) && cur)
1295
		cur--;
1296
 
1297
	    VI_CurrentColumn = cur;
1298
	}
1299
 
1300
	else
1301
	    return -1;
1302
    }
1303
 
1304
    else
1305
    {
1306
	if (VI_IsUndoable ((int)*cmd))
1307
	    VI_SaveUndoBuffer (argcnt, cmd);
1308
 
1309
	switch (*cmd)
1310
	{
1311
	    case 'v':
1312
	    {
1313
	        bool	res = VI_EditLine (argcnt);
1314
 
1315
		VI_RedrawLine ();
1316
 
1317
		if (!res)
1318
		    return -1;
1319
 
1320
		break;
1321
	    }
1322
 
1323
	    case ('L' & 0x01f):
1324
		VI_RedrawLine ();
1325
		break;
1326
 
1327
	    case 'a':
1328
		vi_InputBufferChanged = TRUE;
1329
 
1330
		if (VI_InputLength != 0)
1331
		    VI_CurrentColumn++;
1332
 
1333
		vi_Insert = VI_INSERT_MODE;
1334
 
1335
		break;
1336
 
1337
	    case 'A':
1338
		vi_InputBufferChanged = TRUE;
1339
		VI_DeleteRange (0, 0);
1340
		VI_CurrentColumn = VI_InputLength;
1341
		vi_Insert = VI_INSERT_MODE;
1342
		break;
1343
 
1344
	    case 'c':
1345
	    case 'd':
1346
	    case 'y':
1347
		if (!VI_ChangeCommand (argcnt, cmd))
1348
		    return -1;
1349
 
1350
		break;
1351
 
1352
	    case 'p':
1353
	    case 'P':
1354
		if (!VI_CommandPut (argcnt, *cmd))
1355
		    return -1;
1356
 
1357
		break;
1358
 
1359
	    case 'Y':			/* Yank to end of line		*/
1360
		VI_YankSelection (VI_CurrentColumn, VI_InputLength);
1361
		break;
1362
 
1363
	    case 'S':			/* Substitute the whole line	*/
1364
		VI_YankSelection (0, VI_InputLength);
1365
	        VI_CurrentColumn = 0;
1366
 
1367
	    case 'C':			/* Change to the end of line	*/
1368
		vi_InputBufferChanged = TRUE;
1369
		VI_DeleteRange (VI_CurrentColumn, VI_InputLength);
1370
		vi_Insert = VI_INSERT_MODE;
1371
		break;
1372
 
1373
	    case 'D': 			/* Delete to the end of line	*/
1374
		VI_YankDelete (VI_CurrentColumn, VI_InputLength);
1375
 
1376
		if (VI_CurrentColumn != 0)
1377
		    VI_CurrentColumn--;
1378
 
1379
		break;
1380
 
1381
	    case 'G':			/* Go to history event		*/
1382
		if (!VI_GetEventFromHistory (vi_InputBufferChanged, argcnt))
1383
		    return -1;
1384
 
1385
		else
1386
		{
1387
		    vi_InputBufferChanged = FALSE;
1388
		    CurrentHistoryEvent = argcnt;
1389
		}
1390
 
1391
		break;
1392
 
1393
	    case 'I':			/* Insert at beginning of line	*/
1394
		VI_CurrentColumn = 0;
1395
 
1396
	    case 'i':			/* Insert			*/
1397
		vi_InputBufferChanged = TRUE;
1398
		vi_Insert = VI_INSERT_MODE;
1399
		break;
1400
 
1401
	    case CHAR_PLUS:
1402
	    case 'j':
1403
		if (!VI_MoveThroughHistory (argcnt))
1404
		    return -1;
1405
 
1406
		break;
1407
 
1408
	    case CHAR_HYPHEN:
1409
	    case 'k':
1410
		if (!VI_MoveThroughHistory (-argcnt))
1411
		    return -1;
1412
 
1413
		break;
1414
 
1415
	    case 'r':
1416
		if (VI_InputLength == 0)
1417
		    return -1;
1418
 
1419
		vi_InputBufferChanged = TRUE;
1420
		ConsoleLineBuffer[VI_CurrentColumn] = cmd[1];
1421
		break;
1422
 
1423
	    case 'R':
1424
		vi_InputBufferChanged = TRUE;
1425
		vi_Insert = VI_REPLACE_MODE;
1426
		break;
1427
 
1428
	    case 's':
1429
		if (VI_InputLength == 0)
1430
		    return -1;
1431
 
1432
		vi_InputBufferChanged = TRUE;
1433
 
1434
		if (VI_CurrentColumn + argcnt > VI_InputLength)
1435
		    argcnt = VI_InputLength - VI_CurrentColumn;
1436
 
1437
		VI_DeleteRange (VI_CurrentColumn, VI_CurrentColumn + argcnt);
1438
		vi_Insert = VI_INSERT_MODE;
1439
		break;
1440
 
1441
	    case 'x':
1442
		if (VI_InputLength == 0)
1443
		    return -1;
1444
 
1445
		vi_InputBufferChanged = TRUE;
1446
 
1447
		if (VI_CurrentColumn + argcnt > VI_InputLength)
1448
		    argcnt = VI_InputLength - VI_CurrentColumn;
1449
 
1450
		VI_YankDelete (VI_CurrentColumn, VI_CurrentColumn + argcnt);
1451
		break;
1452
 
1453
	    case 'X':
1454
		if (VI_CurrentColumn <= 0)
1455
		    return -1;
1456
 
1457
		vi_InputBufferChanged = TRUE;
1458
 
1459
		if (VI_CurrentColumn < argcnt)
1460
		    argcnt = VI_CurrentColumn;
1461
 
1462
		VI_YankDelete (VI_CurrentColumn - argcnt, VI_CurrentColumn);
1463
		VI_CurrentColumn -= argcnt;
1464
		break;
1465
 
1466
/* This is not as simple as it looks, because the current State always uses
1467
 * the ConsoleLineBuffer
1468
 */
1469
 
1470
	    case 'u':
1471
		VI_UndoCommand ();
1472
		break;
1473
 
1474
/* Restore the current history event or the null line */
1475
 
1476
	    case 'U':
1477
		VI_ResetLineState ();
1478
		break;
1479
 
1480
/* Search commands */
1481
 
1482
	    case '?':
1483
	    case '/':
1484
	    case 'n':
1485
	    case 'N':
1486
		if (!VI_ExecuteSearch (cmd))
1487
		    return -1;
1488
 
1489
		break;
1490
 
1491
	    case CHAR_TILDE:
1492
		if (!VI_ChangeCase (argcnt))
1493
		    return -1;
1494
 
1495
		break;
1496
 
1497
	    case '@':
1498
		if (!VI_HandleInputAlias (cmd))
1499
		    return -1;
1500
 
1501
		break;
1502
 
1503
	    case '_':
1504
		if (!VI_InsertWords (argcnt))
1505
		    return -1;
1506
 
1507
		break;
1508
 
1509
	    case CHAR_COMMENT:
1510
		VI_CurrentColumn = 0;
1511
 
1512
		if (VI_InsertIntoBuffer ("#", 1, FALSE) != 0)
1513
		    return -1;
1514
 
1515
		return 1;
1516
 
1517
	    case '*':
1518
	    case '=':
1519
	    case '\\':
1520
		if (!VI_ExecuteCompletion (cmd))
1521
		    return -1;
1522
 
1523
		break;
1524
	}
1525
 
1526
	if ((vi_Insert == VI_UNDEF_MODE) && (VI_CurrentColumn != 0) &&
1527
	    (VI_CurrentColumn >= VI_InputLength))
1528
	    VI_CurrentColumn--;
1529
    }
1530
 
1531
    return 0;
1532
}
1533
 
1534
/*
1535
 * Handle an Input alias
1536
 */
1537
 
1538
static bool F_LOCAL VI_HandleInputAlias (char *cmd)
1539
{
1540
    return C2bool ((vi_AliasBuffer = GEN_FindAliasMatch (cmd[1]))
1541
				   != (char *)NULL);
1542
}
1543
 
1544
 
1545
/*
1546
 * Yank and delete some text
1547
 */
1548
 
1549
static void F_LOCAL VI_YankDelete (int start, int end)
1550
{
1551
    VI_YankSelection (start, end);
1552
    VI_DeleteRange (start, end);
1553
}
1554
 
1555
/*
1556
 * Undo the previous command
1557
 */
1558
 
1559
static void F_LOCAL VI_UndoCommand (void)
1560
{
1561
    char	*cp;
1562
    int		InputLength = VI_InputLength;
1563
    int		cursor  = VI_CurrentColumn;
1564
    int		WindowLeftColumn = vi_EditorState.WindowLeftColumn;
1565
 
1566
/* Save the current input line and the editor state */
1567
 
1568
    ConsoleLineBuffer[VI_InputLength] = 0;
1569
    cp = StringCopy (ConsoleLineBuffer);
1570
 
1571
/* Move to the undo information */
1572
 
1573
    vi_EditorState = vi_UndoState;
1574
 
1575
/* If the undo state has a buffer, restore that buffer to the Console
1576
 * line buffer
1577
 */
1578
 
1579
    if (vi_UndoBuffer != null)
1580
    {
1581
	strcpy (ConsoleLineBuffer, vi_UndoBuffer);
1582
	ReleaseMemoryCell (vi_UndoBuffer);
1583
    }
1584
 
1585
    else
1586
	memset (ConsoleLineBuffer, 0, LINE_MAX + 1);
1587
 
1588
/* Set up the undo status information */
1589
 
1590
    vi_UndoBuffer		  = cp;
1591
    vi_UndoState.InputLength      = InputLength;
1592
    vi_UndoState.CursorColumn     = cursor;
1593
    vi_UndoState.WindowLeftColumn = WindowLeftColumn;
1594
}
1595
 
1596
/*
1597
 * Reset the line to its original state
1598
 */
1599
 
1600
static bool F_LOCAL VI_ResetLineState (void)
1601
{
1602
    char	*hptr = null;
1603
    int		lasthistory;
1604
 
1605
    if ((CurrentHistoryEvent < 0) ||
1606
	(CurrentHistoryEvent > (lasthistory = GetLastHistoryEvent ())))
1607
	return FALSE;
1608
 
1609
    if ((lasthistory != CurrentHistoryEvent) &&
1610
	((hptr = GetHistoryRecord (CurrentHistoryEvent)) == (char *)NULL))
1611
	return FALSE;
1612
 
1613
    strcpy (ConsoleLineBuffer, hptr);
1614
    VI_InputLength = strlen (hptr);
1615
    VI_CurrentColumn = 0;
1616
    vi_InputBufferChanged = FALSE;
1617
    return TRUE;
1618
}
1619
 
1620
/*
1621
 * Execute a search for a string
1622
 */
1623
 
1624
static bool F_LOCAL VI_ExecuteSearch (char *cmd)
1625
{
1626
    int		NewCE;
1627
    bool	Direction;
1628
 
1629
/* Set start position */
1630
 
1631
    if (*cmd == '?')
1632
	CurrentHistoryEvent = -1;
1633
 
1634
/* Reset save info for next search command */
1635
 
1636
    if (tolower (*cmd) != 'n')
1637
    {
1638
	vi_SearchPatternLength = 0;
1639
	vi_LastSearchCommand = *cmd;
1640
    }
1641
 
1642
/* Check we know which direction to go */
1643
 
1644
    if (vi_LastSearchCommand == CHAR_SPACE)
1645
	return FALSE;
1646
 
1647
    Direction = C2bool (vi_LastSearchCommand == '?');
1648
 
1649
    if (*cmd == 'N')
1650
	Direction = (bool)!Direction;
1651
 
1652
    if ((NewCE = VI_FindEventFromHistory (vi_InputBufferChanged,
1653
					  CurrentHistoryEvent, Direction,
1654
					  vi_SearchPattern)) < 0)
1655
    {
1656
	if (tolower (*cmd) != 'n')
1657
	{
1658
	    VI_CopyHold2Input ();
1659
	    VI_Refresh (FALSE);
1660
	}
1661
 
1662
	return FALSE;
1663
    }
1664
 
1665
/* Found match !! */
1666
 
1667
    vi_InputBufferChanged = FALSE;
1668
    CurrentHistoryEvent = NewCE;
1669
    return TRUE;
1670
}
1671
 
1672
/*
1673
 * Insert words from previous command into the buffer
1674
 */
1675
 
1676
static bool F_LOCAL VI_InsertWords (int argcnt)
1677
{
1678
    int		space;
1679
    char	*p, *sp;
1680
 
1681
    if ((p = GetHistoryRecord (GetLastHistoryEvent () - 1)) == (char *)NULL)
1682
	return FALSE;
1683
 
1684
    if (argcnt)
1685
    {
1686
	while (*p && isspace (*p))
1687
	    p++;
1688
 
1689
	while (*p && --argcnt)
1690
	{
1691
	    p = SkipToWhiteSpace (p);
1692
 
1693
	    while (*p && isspace (*p))
1694
		p++;
1695
	}
1696
 
1697
	if (!*p)
1698
	    return FALSE;
1699
 
1700
	sp = p;
1701
    }
1702
 
1703
    else
1704
    {
1705
	sp = p;
1706
	space = 0;
1707
 
1708
	while (*p)
1709
	{
1710
	    if (isspace (*p))
1711
		space = 1;
1712
 
1713
	    else if (space)
1714
	    {
1715
		space = 0;
1716
		sp = p;
1717
	    }
1718
 
1719
	    p++;
1720
	}
1721
 
1722
	p = sp;
1723
    }
1724
 
1725
    vi_InputBufferChanged = TRUE;
1726
 
1727
    if (VI_InputLength != 0)
1728
	VI_CurrentColumn++;
1729
 
1730
    while (*p && !isspace (*p))
1731
    {
1732
	argcnt++;
1733
	p++;
1734
    }
1735
 
1736
    if (VI_InsertIntoBuffer (" ", 1, FALSE) != 0)
1737
	argcnt = -1;
1738
 
1739
    else if (VI_InsertIntoBuffer (sp, argcnt, FALSE) != 0)
1740
	argcnt = -1;
1741
 
1742
    if (argcnt < 0)
1743
    {
1744
	if (VI_CurrentColumn != 0)
1745
	    VI_CurrentColumn--;
1746
 
1747
	return FALSE;
1748
    }
1749
 
1750
    vi_Insert = VI_INSERT_MODE;
1751
    return TRUE;
1752
}
1753
 
1754
/*
1755
 * Change case of characters
1756
 */
1757
 
1758
static bool F_LOCAL VI_ChangeCase (int argcnt)
1759
{
1760
    char	*p;
1761
 
1762
    if (VI_InputLength == 0)
1763
	return FALSE;
1764
 
1765
    p = &ConsoleLineBuffer[VI_CurrentColumn];
1766
 
1767
    while (argcnt--)
1768
    {
1769
	if (islower (*p))
1770
	{
1771
	    vi_InputBufferChanged = TRUE;
1772
	    *p = (char)toupper (*p);
1773
	}
1774
 
1775
	else if (isupper (*p))
1776
	{
1777
	    vi_InputBufferChanged = TRUE;
1778
	    *p = (char)tolower (*p);
1779
	}
1780
 
1781
	if (VI_CurrentColumn < VI_InputLength - 1)
1782
	{
1783
	    VI_CurrentColumn++;
1784
	    p++;
1785
	}
1786
 
1787
	else
1788
	    break;
1789
    }
1790
 
1791
    return TRUE;
1792
}
1793
 
1794
/*
1795
 * Completion functions
1796
 */
1797
 
1798
static bool F_LOCAL VI_ExecuteCompletion (char *cmd)
1799
{
1800
    int		rval = 0;
1801
    int		start, end;
1802
    char	**FileList;
1803
    char	**ap;
1804
    int		Count;
1805
 
1806
    if (isspace (ConsoleLineBuffer[VI_CurrentColumn]))
1807
	return FALSE;
1808
 
1809
    start = VI_CurrentColumn;
1810
 
1811
    while (start > -1 && !isspace (ConsoleLineBuffer[start]))
1812
	start--;
1813
 
1814
/* Get the file name */
1815
 
1816
    start++;
1817
    end = VI_CurrentColumn;
1818
 
1819
    while ((end < VI_InputLength) && !isspace (ConsoleLineBuffer[end]))
1820
	end++;
1821
 
1822
/* Build the list of file names */
1823
 
1824
    if ((FileList = BuildCompletionList (&ConsoleLineBuffer[start],
1825
					 end - start,
1826
    					 &Count, C2bool (*cmd != '=')))
1827
		  == (char **)NULL)
1828
	return FALSE;
1829
 
1830
/* Display the directory contents */
1831
 
1832
    if (*cmd == '=')
1833
    {
1834
	feputc (CHAR_NEW_LINE);
1835
	PrintAList (Count, FileList);
1836
	ReleaseAList (FileList);
1837
	FlushStreams ();
1838
 
1839
	if (VI_InputLength != 0)
1840
	    VI_CurrentColumn++;
1841
 
1842
	VI_RedrawLine ();
1843
	vi_Insert = VI_INSERT_MODE;
1844
	vi_State = VI_S_NORMAL;
1845
	return TRUE;
1846
    }
1847
 
1848
/* Insert a list of files or the completion */
1849
 
1850
    ap = FileList;
1851
 
1852
/*
1853
* If completion, get the common part and check the length to see if
1854
* we've go some new data
1855
*/
1856
 
1857
    if ((*cmd == '\\') && (Count > 1) &&
1858
    	(GetCommonPartOfFileList (FileList) <= (size_t)(end - start)))
1859
    {
1860
	ReleaseAList (FileList);
1861
	return FALSE;
1862
    }
1863
 
1864
/* Delete the old name and insert the new */
1865
 
1866
    VI_DeleteRange (start, end);
1867
    VI_CurrentColumn = start;
1868
 
1869
/* For each file name, insert it into the command line.  In the case of
1870
 * completion, we only use the first name, because that has the common
1871
 * part
1872
 */
1873
 
1874
    while (TRUE)
1875
    {
1876
	if (VI_InsertIntoBuffer (*ap, strlen (*ap), FALSE) != 0)
1877
	{
1878
	    rval = -1;
1879
	    break;
1880
	}
1881
 
1882
/* If there was only 1 match on completion and is a directory, append a
1883
 * directory
1884
 */
1885
	if ((*cmd == '\\') && (Count == 1) && IsDirectory (*ap) &&
1886
	    (VI_InsertIntoBuffer (DirectorySeparator, 1, FALSE) != 0))
1887
	    rval = -1;
1888
 
1889
/* If no more or completion - stop */
1890
 
1891
	if ((*cmd == '\\') || (*(++ap) == (char *)NULL))
1892
	    break;
1893
 
1894
	if (VI_InsertIntoBuffer (" ", 1, FALSE) != 0)
1895
	{
1896
	    rval = -1;
1897
	    break;
1898
	}
1899
    }
1900
 
1901
    ReleaseAList (FileList);
1902
    vi_InputBufferChanged = TRUE;
1903
    vi_Insert = VI_INSERT_MODE;
1904
    VI_Refresh (FALSE);
1905
 
1906
    return C2bool (rval == 0);
1907
}
1908
 
1909
/*
1910
 * Handle the change, delete and yank commands (c, d, y)
1911
 */
1912
 
1913
static bool F_LOCAL VI_ChangeCommand (int argcnt, char *cmd)
1914
{
1915
    int		c2;
1916
    int		c3 = 0;
1917
    int		ncursor;
1918
 
1919
    if (*cmd == cmd[1])
1920
	c2 = VI_InputLength;
1921
 
1922
    else if (!VI_IsMove ((int)cmd[1]))
1923
	return FALSE;
1924
 
1925
    else
1926
    {
1927
	if ((ncursor = VI_ExecuteMove (argcnt, &cmd[1], TRUE)) < 0)
1928
	    return FALSE;
1929
 
1930
	if ((*cmd == 'c') && ((cmd[1] == 'w') || (cmd[1] == 'W')) &&
1931
	    !isspace (ConsoleLineBuffer[VI_CurrentColumn]))
1932
	{
1933
	    while (isspace (ConsoleLineBuffer[--ncursor]))
1934
		continue;
1935
 
1936
	    ncursor++;
1937
	}
1938
 
1939
	if (ncursor > VI_CurrentColumn)
1940
	{
1941
	    c3 = VI_CurrentColumn;
1942
	    c2 = ncursor;
1943
	}
1944
 
1945
	else
1946
	{
1947
	    c3 = ncursor;
1948
	    c2 = VI_CurrentColumn;
1949
	}
1950
    }
1951
 
1952
    if ((*cmd != 'c') && (c3 != c2))
1953
	VI_YankSelection (c3, c2);
1954
 
1955
    if (*cmd != 'y')
1956
    {
1957
	VI_DeleteRange (c3, c2);
1958
	VI_CurrentColumn = c3;
1959
    }
1960
 
1961
    if (*cmd == 'c')
1962
    {
1963
	vi_InputBufferChanged = TRUE;
1964
	vi_Insert = VI_INSERT_MODE;
1965
    }
1966
 
1967
    return TRUE;
1968
}
1969
 
1970
/*
1971
 * Handle the Put commands (p, P)
1972
 */
1973
 
1974
static bool F_LOCAL VI_CommandPut (int argcnt, char cmd)
1975
{
1976
    int	YBLen;
1977
 
1978
    if ((cmd == 'p') && (VI_InputLength != 0))
1979
	VI_CurrentColumn++;
1980
 
1981
    if (vi_YankBuffer == (char *)NULL)
1982
	return FALSE;
1983
 
1984
    vi_InputBufferChanged = TRUE;
1985
    YBLen = strlen (vi_YankBuffer);
1986
 
1987
    while ((VI_InsertIntoBuffer (vi_YankBuffer, YBLen, FALSE) == 0) &&
1988
	   (--argcnt > 0))
1989
	continue;
1990
 
1991
    if (VI_CurrentColumn != 0)
1992
	VI_CurrentColumn--;
1993
 
1994
    return C2bool (argcnt == 0);
1995
}
1996
 
1997
/*
1998
 * Save undo buffer
1999
 */
2000
 
2001
static void F_LOCAL VI_SaveUndoBuffer (int argcnt, char *cmd)
2002
{
2003
    if (vi_UndoBuffer != null)
2004
	ReleaseMemoryCell (vi_UndoBuffer);
2005
 
2006
    ConsoleLineBuffer[VI_InputLength] = 0;
2007
 
2008
    vi_UndoBuffer = StringSave (ConsoleLineBuffer);
2009
    vi_UndoState  = vi_EditorState;
2010
 
2011
    vi_PrevCmdArgCount = argcnt;
2012
    memmove (vi_PreviousCommand, cmd, VI_MAX_CMD_LENGTH);
2013
}
2014
 
2015
 
2016
/*
2017
 * Edit the line using VI
2018
 */
2019
 
2020
static bool F_LOCAL VI_EditLine (int argcnt)
2021
{
2022
    char		*Temp;
2023
    char		*NewArg[3];
2024
    char		*hptr;
2025
    FILE		*fp;
2026
    int			fd;
2027
    void                (_SIGDECL *save_signal)(int);
2028
 
2029
/* Get the current signal setting */
2030
 
2031
    save_signal = signal (SIGINT, SIG_IGN);
2032
    signal (SIGINT, save_signal);
2033
 
2034
    if ((hptr = (argcnt) ? GetHistoryRecord (argcnt) : ConsoleLineBuffer)
2035
	      == (char *)NULL)
2036
        return FALSE;
2037
 
2038
    fputchar (CHAR_NEW_LINE);
2039
 
2040
/* Check status */
2041
 
2042
    if ((fp = FOpenFile ((Temp = GenerateTemporaryFileName ()),
2043
			sOpenWriteBinaryMode)) == (FILE *)NULL)
2044
    {
2045
	PrintWarningMessage ("cannot create %s", Temp);
2046
	return FALSE;
2047
    }
2048
 
2049
    fputs (hptr, fp);
2050
    fputc (CHAR_NEW_LINE, fp);
2051
    CloseFile (fp);
2052
 
2053
/* Invoke the editor */
2054
 
2055
    if (((NewArg[0] = GetVariableAsString (VisualVariable, FALSE)) == null) &&
2056
	((NewArg[0] = GetVariableAsString (EditorVariable, FALSE)) == null))
2057
	NewArg[0] = "vi";
2058
 
2059
    NewArg[1] = Temp;
2060
    NewArg[2] = (char *)NULL;
2061
 
2062
    if (ExecuteACommand (NewArg, 0) == -1)
2063
    {
2064
	unlink (Temp);
2065
	signal (SIGINT, save_signal);
2066
	return FALSE;
2067
    }
2068
 
2069
/* Restore signals which are changed by ExecuteACommand */
2070
 
2071
    signal (SIGINT, save_signal);
2072
 
2073
/* Now execute it */
2074
 
2075
    if ((fd = S_open (TRUE, Temp, O_RMASK)) < 0)
2076
    {
2077
	unlink (Temp);
2078
	PrintWarningMessage ("cannot re-open edit file (%s)", Temp);
2079
	return FALSE;
2080
    }
2081
 
2082
    argcnt = read (fd, ConsoleLineBuffer, LINE_MAX - 1);
2083
    S_close (fd, TRUE);
2084
 
2085
    if (argcnt <= 0)
2086
	return FALSE;
2087
 
2088
/* Strip off trailing EOFs and EOLs */
2089
 
2090
    CleanUpBuffer (argcnt, ConsoleLineBuffer, 0x1a);
2091
    VI_InputLength		    = strlen (ConsoleLineBuffer);
2092
    VI_CurrentColumn		    = 0;
2093
    vi_EditorState.WindowLeftColumn = 0;
2094
    vi_InputBufferChanged = TRUE;
2095
    return TRUE;
2096
}
2097
 
2098
/*
2099
 * Move through the history file
2100
 */
2101
 
2102
static bool F_LOCAL VI_MoveThroughHistory (int argcnt)
2103
{
2104
    if (!VI_GetEventFromHistory (vi_InputBufferChanged,
2105
				 CurrentHistoryEvent + argcnt))
2106
	return FALSE;
2107
 
2108
    vi_InputBufferChanged = FALSE;
2109
    CurrentHistoryEvent += argcnt;
2110
    return TRUE;
2111
}
2112
 
2113
/*
2114
 * Execute a move
2115
 */
2116
 
2117
static int F_LOCAL VI_ExecuteMove (int argcnt, char *cmd, bool sub)
2118
{
2119
    int		ncursor = 0;
2120
 
2121
    switch (*cmd)
2122
    {
2123
	case '|':
2124
	    if (argcnt > VI_InputLength)
2125
	        return -1;
2126
 
2127
	    ncursor = argcnt;
2128
	    break;
2129
 
2130
	case 'b':
2131
	    if ((!sub) && (VI_CurrentColumn == 0))
2132
		return -1;
2133
 
2134
	    ncursor = VI_BackwardWord (argcnt);
2135
	    break;
2136
 
2137
	case 'B':
2138
	    if ((!sub) && (VI_CurrentColumn == 0))
2139
		return -1;
2140
 
2141
	    ncursor = VI_BackwardToWhiteSpace (argcnt);
2142
	    break;
2143
 
2144
	case 'e':
2145
	    if ((!sub) &&
2146
	        (VI_CurrentColumn + 1 >= VI_InputLength))
2147
		return -1;
2148
 
2149
	    ncursor = VI_EndofWord (argcnt);
2150
 
2151
	    if (sub)
2152
		ncursor++;
2153
 
2154
	    break;
2155
 
2156
	case 'E':
2157
	    if ((!sub) &&
2158
	        (VI_CurrentColumn + 1 >= VI_InputLength))
2159
		return -1;
2160
 
2161
	    ncursor = VI_ForwardToEndOfNonWhiteSpace (argcnt);
2162
 
2163
	    if (sub)
2164
		ncursor++;
2165
 
2166
	    break;
2167
 
2168
	case 'f':
2169
	case 'F':
2170
	case 't':
2171
	case 'T':
2172
	    vi_LastFindCommand = *cmd;
2173
	    vi_LastFindCharacter = cmd[1];
2174
		/* drop through */
2175
 
2176
/* XXX -- should handle \^ escape? */
2177
	case ';':
2178
        {
2179
	    bool	incr;
2180
	    bool	forward;
2181
 
2182
	    if (vi_LastFindCommand == CHAR_SPACE)
2183
		return -1;
2184
 
2185
	    incr = C2bool ((vi_LastFindCommand == 'f') ||
2186
	    		   (vi_LastFindCommand == 'F'));
2187
	    forward = C2bool (vi_LastFindCommand > 'a');
2188
 
2189
	    if (*cmd == ',')
2190
		forward = (bool)!forward;
2191
 
2192
	    if ((ncursor = VI_FindCharacter (vi_LastFindCharacter,
2193
	    			   	     argcnt, forward, incr)) < 0)
2194
		return -1;
2195
 
2196
	    if (sub && forward)
2197
		ncursor++;
2198
 
2199
	    break;
2200
	}
2201
 
2202
	case 'h':
2203
		/* tmp fix */
2204
	case CHAR_BACKSPACE:
2205
	    if (!sub && (VI_CurrentColumn == 0))
2206
		return -1;
2207
 
2208
	    if ((ncursor = VI_CurrentColumn - argcnt) < 0)
2209
		ncursor = 0;
2210
 
2211
	    break;
2212
 
2213
	case CHAR_SPACE:
2214
	case 'l':
2215
	    if (!sub && (VI_CurrentColumn + 1 >= VI_InputLength))
2216
		return -1;
2217
 
2218
	    if (VI_InputLength != 0)
2219
	    {
2220
		ncursor = VI_CurrentColumn + argcnt;
2221
 
2222
		if (ncursor >= VI_InputLength)
2223
		    ncursor = VI_InputLength - 1;
2224
	    }
2225
 
2226
	    break;
2227
 
2228
	case 'w':
2229
	    if (!sub && VI_CurrentColumn + 1 >= VI_InputLength)
2230
		return -1;
2231
 
2232
	    ncursor = VI_ForwardWord (argcnt);
2233
	    break;
2234
 
2235
	case 'W':
2236
	    if (!sub && (VI_CurrentColumn + 1 >= VI_InputLength))
2237
		return -1;
2238
 
2239
	    ncursor = VI_ForwardToWhiteSpace (argcnt);
2240
	    break;
2241
 
2242
	case '0':
2243
	    ncursor = 0;
2244
	    break;
2245
 
2246
	case CHAR_BEGIN_LINE:
2247
	    ncursor = 0;
2248
	    while ((ncursor < VI_InputLength - 1) &&
2249
	           isspace (ConsoleLineBuffer[ncursor]))
2250
		ncursor++;
2251
 
2252
	    break;
2253
 
2254
	case CHAR_END_LINE:
2255
	    if (VI_InputLength != 0)
2256
		ncursor = VI_InputLength;
2257
 
2258
	    else
2259
		ncursor = 0;
2260
 
2261
	    break;
2262
 
2263
	case '%':
2264
        {
2265
	    int		bcount;
2266
	    int		i = 0;
2267
	    int		t;
2268
 
2269
	    ncursor = VI_CurrentColumn;
2270
 
2271
	    while ((ncursor < VI_InputLength) &&
2272
		   (i = VI_GetBracketType (ConsoleLineBuffer[ncursor])) == 0)
2273
		ncursor++;
2274
 
2275
	    if (ncursor == VI_InputLength)
2276
		return -1;
2277
 
2278
	    bcount = 1;
2279
 
2280
	    do
2281
	    {
2282
		if (i > 0)
2283
		{
2284
		    if (++ncursor >= VI_InputLength)
2285
			return -1;
2286
		}
2287
 
2288
		else if (--ncursor < 0)
2289
		    return -1;
2290
 
2291
		if ((t = VI_GetBracketType (ConsoleLineBuffer[ncursor]))
2292
		       == 1)
2293
		    bcount++;
2294
 
2295
		else if (t == -i)
2296
		    bcount--;
2297
 
2298
	    } while (bcount != 0);
2299
 
2300
	    if (sub)
2301
		ncursor++;
2302
 
2303
	    break;
2304
	}
2305
 
2306
	default:
2307
	    return -1;
2308
    }
2309
 
2310
    return ncursor;
2311
}
2312
 
2313
static int F_LOCAL VI_RedoInsert (int count)
2314
{
2315
    while (count-- > 0)
2316
    {
2317
	if (VI_InsertIntoBuffer (vi_InsertBuffer, vi_InsertBufferLength,
2318
		    C2bool (vi_Insert == VI_REPLACE_MODE)) != 0)
2319
	    return -1;
2320
    }
2321
 
2322
    if (VI_CurrentColumn > 0)
2323
	VI_CurrentColumn--;
2324
 
2325
    vi_Insert = VI_UNDEF_MODE;
2326
    return 0;
2327
}
2328
 
2329
static void F_LOCAL VI_YankSelection (int a, int b)
2330
{
2331
    int		len = b - a;
2332
 
2333
    if (!len)
2334
        return;
2335
 
2336
    if (vi_YankBuffer != (char *)NULL)
2337
	ReleaseMemoryCell (vi_YankBuffer);
2338
 
2339
    vi_YankBuffer = GetAllocatedSpace (len + 1);
2340
    SetMemoryAreaNumber (vi_YankBuffer, 0);
2341
    memcpy (vi_YankBuffer, &ConsoleLineBuffer[a], len);
2342
    vi_YankBuffer[len] = 0;
2343
}
2344
 
2345
/*
2346
 * Get the Bracket type
2347
 */
2348
 
2349
static int F_LOCAL VI_GetBracketType (int ch)
2350
{
2351
    switch (ch)
2352
    {
2353
	case CHAR_OPEN_PARATHENSIS:
2354
	    return 1;
2355
 
2356
	case CHAR_OPEN_BRACKETS:
2357
	    return 2;
2358
 
2359
	case CHAR_OPEN_BRACES:
2360
	    return 3;
2361
 
2362
	case CHAR_CLOSE_PARATHENSIS:
2363
	    return -1;
2364
 
2365
	case CHAR_CLOSE_BRACKETS:
2366
	    return -2;
2367
 
2368
	case CHAR_CLOSE_BRACES:
2369
	    return -3;
2370
 
2371
	default:
2372
	    return 0;
2373
    }
2374
}
2375
 
2376
/*
2377
 * Save and Restore the Input line in the Hold buffer
2378
 */
2379
 
2380
static void F_LOCAL VI_CopyInput2Hold (void)
2381
{
2382
    if (vi_HoldBuffer != null)
2383
	ReleaseMemoryCell (vi_HoldBuffer);
2384
 
2385
    vi_HoldBuffer = null;
2386
    vi_HoldBuffer = StringSave (ConsoleLineBuffer);
2387
}
2388
 
2389
static void F_LOCAL VI_CopyHold2Input (void)
2390
{
2391
    VI_CurrentColumn = 0;
2392
    strcpy (ConsoleLineBuffer, vi_HoldBuffer);
2393
    VI_InputLength = strlen (ConsoleLineBuffer);
2394
}
2395
 
2396
/*
2397
 * Insert the String into the input buffer
2398
 */
2399
 
2400
static int F_LOCAL VI_InsertIntoBuffer (char *buf, int len, bool repl)
2401
{
2402
    if (len == 0)
2403
	return 0;
2404
 
2405
    if (repl)
2406
    {
2407
	if ((VI_CurrentColumn + len) >= LINE_MAX)
2408
	    return -1;
2409
 
2410
	if ((VI_CurrentColumn + len) > VI_InputLength)
2411
	    VI_InputLength = VI_CurrentColumn + len;
2412
    }
2413
 
2414
    else
2415
    {
2416
	if ((VI_InputLength + len) >= LINE_MAX)
2417
	    return -1;
2418
 
2419
	memmove (&ConsoleLineBuffer[VI_CurrentColumn + len],
2420
		 &ConsoleLineBuffer[VI_CurrentColumn],
2421
		 VI_InputLength - VI_CurrentColumn);
2422
 
2423
	VI_InputLength += len;
2424
    }
2425
 
2426
    memmove (&ConsoleLineBuffer[VI_CurrentColumn], buf, len);
2427
    VI_CurrentColumn += len;
2428
    ConsoleLineBuffer[VI_InputLength] = 0;
2429
    return 0;
2430
}
2431
 
2432
/*
2433
 * Delete a range of characters from the input buffer
2434
 */
2435
 
2436
static void F_LOCAL VI_DeleteRange (int a, int b)
2437
{
2438
    if (VI_InputLength != b)
2439
	memmove (&ConsoleLineBuffer[a],
2440
		 &ConsoleLineBuffer[b],
2441
		 VI_InputLength - b);
2442
 
2443
     ConsoleLineBuffer[VI_InputLength -= b - a] = 0;
2444
}
2445
 
2446
static int F_LOCAL VI_FindCharacter (int ch, int cnt, bool forw, bool incl)
2447
{
2448
    int		ncursor;
2449
 
2450
    if (VI_InputLength == 0)
2451
	return -1;
2452
 
2453
    ncursor = VI_CurrentColumn;
2454
 
2455
    while (cnt--)
2456
    {
2457
	do
2458
	{
2459
	    if (forw)
2460
	    {
2461
		if (++ncursor == VI_InputLength)
2462
		    return -1;
2463
	    }
2464
 
2465
	    else if (--ncursor < 0)
2466
		return -1;
2467
 
2468
	} while (ConsoleLineBuffer[ncursor] != (char)ch);
2469
    }
2470
 
2471
    if (!incl)
2472
    {
2473
	if (forw)
2474
	    ncursor--;
2475
 
2476
	else
2477
	    ncursor++;
2478
    }
2479
 
2480
    return ncursor;
2481
}
2482
 
2483
/*
2484
 * Move forward to next white space character
2485
 */
2486
 
2487
static int F_LOCAL VI_ForwardToWhiteSpace (int argcnt)
2488
{
2489
    int		 ncursor = VI_CurrentColumn;
2490
 
2491
    while ((ncursor < VI_InputLength) && argcnt--)
2492
    {
2493
	while (!isspace (ConsoleLineBuffer[ncursor]) &&
2494
	       (++ncursor < VI_InputLength))
2495
	    continue;
2496
 
2497
	while (isspace (ConsoleLineBuffer[ncursor]) &&
2498
	       (++ncursor < VI_InputLength))
2499
	    continue;
2500
    }
2501
 
2502
    return ncursor;
2503
}
2504
 
2505
/*
2506
 * Move forward to start of next word
2507
 */
2508
 
2509
static int F_LOCAL VI_ForwardWord (int argcnt)
2510
{
2511
    int		 ncursor = VI_CurrentColumn;
2512
 
2513
    while (ncursor < VI_InputLength && argcnt--)
2514
    {
2515
	if (IS_AlphaNumeric ((int)ConsoleLineBuffer[ncursor]))
2516
	{
2517
	    while (IS_AlphaNumeric ((int)ConsoleLineBuffer[ncursor]) &&
2518
	           (++ncursor < VI_InputLength))
2519
		continue;
2520
	}
2521
 
2522
	else if (!isspace (ConsoleLineBuffer[ncursor]))
2523
	{
2524
	    while (!IS_AlphaNumeric ((int)ConsoleLineBuffer[ncursor]) &&
2525
	           !isspace (ConsoleLineBuffer[ncursor]) &&
2526
		   (++ncursor < VI_InputLength))
2527
		continue;
2528
	}
2529
 
2530
	while (isspace (ConsoleLineBuffer[ncursor]) &&
2531
	       (++ncursor < VI_InputLength))
2532
	    continue;
2533
    }
2534
 
2535
    return ncursor;
2536
}
2537
 
2538
/*
2539
 * Move backward to start of word
2540
 */
2541
 
2542
static int F_LOCAL VI_BackwardWord (int argcnt)
2543
{
2544
    int		 ncursor = VI_CurrentColumn;
2545
 
2546
    while (ncursor > 0 && argcnt--)
2547
    {
2548
	while ((--ncursor > 0) && isspace (ConsoleLineBuffer[ncursor]))
2549
	    continue;
2550
 
2551
	if (ncursor > 0)
2552
	{
2553
	    if (IS_AlphaNumeric ((int)ConsoleLineBuffer[ncursor]))
2554
	    {
2555
		while ((--ncursor >= 0) &&
2556
		       IS_AlphaNumeric ((int)ConsoleLineBuffer[ncursor]))
2557
		    continue;
2558
	    }
2559
 
2560
	    else
2561
	    {
2562
		while ((--ncursor >= 0) &&
2563
		       !IS_AlphaNumeric ((int)ConsoleLineBuffer[ncursor]) &&
2564
		       !isspace (ConsoleLineBuffer[ncursor]))
2565
		    continue;
2566
	    }
2567
 
2568
	    ncursor++;
2569
	}
2570
    }
2571
 
2572
    return ncursor;
2573
}
2574
 
2575
/*
2576
 * Move to the end of the word
2577
 */
2578
 
2579
static int F_LOCAL VI_EndofWord (int argcnt)
2580
{
2581
    int		 ncursor = VI_CurrentColumn;
2582
 
2583
    while ((ncursor < VI_InputLength) && argcnt--)
2584
    {
2585
	while ((++ncursor < VI_InputLength - 1) &&
2586
	       isspace (ConsoleLineBuffer[ncursor]))
2587
	    continue;
2588
 
2589
	if (ncursor < VI_InputLength - 1)
2590
	{
2591
	    if (IS_AlphaNumeric ((int)ConsoleLineBuffer[ncursor]))
2592
	    {
2593
		while ((++ncursor < VI_InputLength) &&
2594
		       IS_AlphaNumeric ((int)ConsoleLineBuffer[ncursor]))
2595
		    continue;
2596
	    }
2597
 
2598
	    else
2599
	    {
2600
		while ((++ncursor < VI_InputLength) &&
2601
		       !IS_AlphaNumeric ((int)ConsoleLineBuffer[ncursor]) &&
2602
		       !isspace (ConsoleLineBuffer[ncursor]))
2603
		    continue;
2604
	    }
2605
 
2606
	    ncursor--;
2607
	}
2608
    }
2609
 
2610
    return ncursor;
2611
}
2612
 
2613
/*
2614
 * Move backward to previous white space
2615
 */
2616
 
2617
static int F_LOCAL VI_BackwardToWhiteSpace (int argcnt)
2618
{
2619
    int		 ncursor = VI_CurrentColumn;
2620
 
2621
    while ((ncursor > 0) && argcnt--)
2622
    {
2623
	while ((--ncursor >= 0) && isspace (ConsoleLineBuffer[ncursor]))
2624
	    continue;
2625
 
2626
	while ((ncursor >= 0) && !isspace (ConsoleLineBuffer[ncursor]))
2627
	    ncursor--;
2628
 
2629
	ncursor++;
2630
    }
2631
 
2632
    return ncursor;
2633
}
2634
 
2635
/*
2636
 * Move to end of non-white space
2637
 */
2638
 
2639
static int F_LOCAL VI_ForwardToEndOfNonWhiteSpace (int argcnt)
2640
{
2641
    int		 ncursor = VI_CurrentColumn;
2642
 
2643
    while (ncursor < VI_InputLength - 1 && argcnt--)
2644
    {
2645
	while ((++ncursor < VI_InputLength - 1) &&
2646
	       isspace (ConsoleLineBuffer[ncursor]))
2647
	    continue;
2648
 
2649
	if (ncursor < VI_InputLength - 1)
2650
	{
2651
	    while (++ncursor < VI_InputLength &&
2652
	           !isspace (ConsoleLineBuffer[ncursor]))
2653
		continue;
2654
 
2655
	    ncursor--;
2656
	}
2657
    }
2658
 
2659
    return ncursor;
2660
}
2661
 
2662
/*
2663
 * Get a specific history event
2664
 */
2665
 
2666
static bool F_LOCAL VI_GetEventFromHistory (bool save, int n)
2667
{
2668
    char	*hptr;
2669
    int		lasthistory;
2670
 
2671
    if ((n < 0) || (n > (lasthistory = GetLastHistoryEvent ())))
2672
	return FALSE;
2673
 
2674
    if (n == lasthistory)
2675
    {
2676
	VI_CopyHold2Input ();
2677
	return TRUE;
2678
    }
2679
 
2680
    if ((hptr = GetHistoryRecord (n)) == (char *)NULL)
2681
	return FALSE;
2682
 
2683
    if (save)
2684
	VI_CopyInput2Hold ();
2685
 
2686
    strcpy (ConsoleLineBuffer, hptr);
2687
    VI_InputLength = strlen (hptr);
2688
    VI_CurrentColumn = 0;
2689
    return TRUE;
2690
}
2691
 
2692
/*
2693
 * Search the history for an event
2694
 */
2695
 
2696
static int F_LOCAL VI_FindEventFromHistory (bool save, int start, bool fwd,
2697
					    char *pat)
2698
{
2699
    char	*hptr;
2700
    int		lev = GetLastHistoryEvent ();
2701
    int		dir = (fwd) ? 1 : -1;
2702
 
2703
/* If we are going backwards through the history (from the current event),
2704
 * check 1. that we are not at the end of events (last) and 2) not at the
2705
 * next.
2706
 */
2707
 
2708
    if (!fwd)
2709
    {
2710
        if (start == 0)
2711
	    return -1;
2712
    }
2713
 
2714
/* Otherwise, going forward to the future.  If the future is not here, give
2715
 * up
2716
 */
2717
 
2718
    else if (start >= lev)
2719
        return -1;
2720
 
2721
    start += dir;
2722
 
2723
/* Search for match */
2724
 
2725
    while ((hptr = GetHistoryRecord (start)) != (char *)NULL)
2726
    {
2727
 
2728
/* If ^, then search for line beginning with string */
2729
 
2730
	if (*pat == CHAR_BEGIN_LINE)
2731
	{
2732
	   if (strcmp (hptr, pat + 1) == 0)
2733
	       break;
2734
	}
2735
 
2736
/* Else just check for the string */
2737
 
2738
	else if (strstr (hptr, pat) != (char *)NULL)
2739
	    break;
2740
 
2741
	start += dir;
2742
    }
2743
 
2744
    if (hptr == (char *)NULL)
2745
    {
2746
	if ((start != 0) && fwd && strcmp (vi_HoldBuffer, pat) >= 0)
2747
	{
2748
	    VI_CopyHold2Input ();
2749
	    return 0;
2750
	}
2751
 
2752
	else
2753
	    return -1;
2754
    }
2755
 
2756
    if (save)
2757
	VI_CopyInput2Hold ();
2758
 
2759
    memcpy (ConsoleLineBuffer, hptr, (VI_InputLength = strlen (hptr)));
2760
    ConsoleLineBuffer[VI_InputLength] = 0;
2761
    VI_CurrentColumn = 0;
2762
    return start;
2763
}
2764
 
2765
/*
2766
 * Redraw the current line
2767
 */
2768
 
2769
static void F_LOCAL VI_RedrawLine (void)
2770
{
2771
    GEN_PutACharacter (CHAR_NEW_LINE);
2772
    VI_OutputPrompt (TRUE);
2773
 
2774
    vi_MoreIndicator = CHAR_SPACE;
2775
    VI_CreateWindowBuffers ();
2776
}
2777
 
2778
/*
2779
 * Re-create the WindowBuffers
2780
 */
2781
 
2782
static void F_LOCAL VI_CreateWindowBuffers (void)
2783
{
2784
    int		c;
2785
 
2786
    GetScreenParameters ();
2787
    PromptWidth = (StartCursorPosition = ReadCursorPosition ()) %
2788
			MaximumColumns;
2789
    CurrentScreenPosition = PromptWidth;
2790
    WindowWidth = MaximumColumns - PromptWidth - 3;
2791
 
2792
    for (c = 0; c < 2; c++)
2793
    {
2794
	if (WindowBuffer[c] != (char *)NULL)
2795
	    ReleaseMemoryCell (WindowBuffer[c]);
2796
 
2797
	WindowBuffer[c] = GetAllocatedSpace (MaximumColumns + 1);
2798
	SetMemoryAreaNumber (WindowBuffer[c], 0);
2799
	memset (WindowBuffer[c], CHAR_SPACE, MaximumColumns + 1);
2800
    }
2801
}
2802
 
2803
/*
2804
 * Redisplay line
2805
 */
2806
 
2807
static void F_LOCAL VI_OutputPrompt (bool Prompt)
2808
{
2809
    GEN_PutACharacter (CHAR_RETURN);
2810
    FlushStreams ();
2811
 
2812
    if (Prompt)
2813
    {
2814
	OutputUserPrompt (LastUserPrompt);
2815
	StartCursorPosition = ReadCursorPosition ();
2816
    }
2817
 
2818
    else
2819
	SetCursorPosition (StartCursorPosition);
2820
 
2821
    PromptWidth = StartCursorPosition % MaximumColumns;
2822
    CurrentScreenPosition = PromptWidth;
2823
}
2824
 
2825
/*
2826
 * Refresh the current line on the screen
2827
 */
2828
 
2829
static void F_LOCAL VI_Refresh (bool leftside)
2830
{
2831
    if (VI_OutOfWindow ())
2832
	VI_ReWindowBuffer ();
2833
 
2834
    VI_DisplayWindow (WindowBuffer[1 - vi_WhichWindow],
2835
		      WindowBuffer[vi_WhichWindow], leftside);
2836
    vi_WhichWindow = 1 - vi_WhichWindow;
2837
}
2838
 
2839
/*
2840
 * Check to see if we are outside the current window
2841
 */
2842
static bool F_LOCAL VI_OutOfWindow (void)
2843
{
2844
    int	cur, col;
2845
 
2846
    if (VI_CurrentColumn < vi_EditorState.WindowLeftColumn)
2847
	return TRUE;
2848
 
2849
    col = 0;
2850
    cur = vi_EditorState.WindowLeftColumn;
2851
 
2852
    while (cur < VI_CurrentColumn)
2853
	col = VI_AdvanceColumn (ConsoleLineBuffer[cur++], col);
2854
 
2855
    return (col > WindowWidth) ? TRUE : FALSE;
2856
}
2857
 
2858
static void F_LOCAL VI_ReWindowBuffer (void)
2859
{
2860
    int		tcur = 0;
2861
    int		tcol = 0;
2862
    int		holdcur1 = 0;
2863
    int		holdcol1 = 0;
2864
    int		holdcur2 = 0;
2865
    int		holdcol2 = 0;
2866
 
2867
    while (tcur < VI_CurrentColumn)
2868
    {
2869
	if (tcol - holdcol2 > WindowWidth / 2)
2870
	{
2871
	    holdcur1 = holdcur2;
2872
	    holdcol1 = holdcol2;
2873
	    holdcur2 = tcur;
2874
	    holdcol2 = tcol;
2875
	}
2876
 
2877
	tcol = VI_AdvanceColumn (ConsoleLineBuffer[tcur++], tcol);
2878
    }
2879
 
2880
    while (tcol - holdcol1 > WindowWidth / 2)
2881
	holdcol1 = VI_AdvanceColumn (ConsoleLineBuffer[holdcur1++], holdcol1);
2882
 
2883
    vi_EditorState.WindowLeftColumn = holdcur1;
2884
}
2885
 
2886
/*
2887
 * Advance to column n
2888
 */
2889
 
2890
static int F_LOCAL VI_AdvanceColumn (int ch, int col)
2891
{
2892
    if ((ch >= CHAR_SPACE) && (ch < 0x7f))
2893
	return col + 1;
2894
 
2895
    else if (ch == CHAR_TAB)
2896
	return (col | 7) + 1;
2897
 
2898
    else
2899
	return col + 2;
2900
}
2901
 
2902
static void F_LOCAL VI_DisplayWindow (char *wb1, char *wb2, bool leftside)
2903
{
2904
    char	*twb1 = wb1;
2905
    char	*twb2;
2906
    char	mc;
2907
    int		cur = vi_EditorState.WindowLeftColumn;
2908
    int		col = 0;
2909
    int		cnt;
2910
    int		ncol = 0;
2911
    int		moreright = 0;
2912
 
2913
    while ((col < WindowWidth) && (cur < VI_InputLength))
2914
    {
2915
	if ((cur == VI_CurrentColumn) && leftside)
2916
	    ncol = col + PromptWidth;
2917
 
2918
	if ((ConsoleLineBuffer[cur] < CHAR_SPACE) ||
2919
	    (ConsoleLineBuffer[cur] == 0x7f))
2920
	{
2921
	    if (ConsoleLineBuffer[cur] == CHAR_TAB)
2922
	    {
2923
		do
2924
		{
2925
		    *(twb1++) = CHAR_SPACE;
2926
		} while ((++col < WindowWidth) && ((col & 7) != 0));
2927
	    }
2928
 
2929
	    else
2930
	    {
2931
		*(twb1++) = '^';
2932
 
2933
		if (++col < WindowWidth)
2934
		{
2935
		    *(twb1++) = (char)(ConsoleLineBuffer[cur] ^ '@');
2936
		    col++;
2937
		}
2938
	    }
2939
	}
2940
 
2941
	else
2942
	{
2943
	    *(twb1++) = ConsoleLineBuffer[cur];
2944
	    col++;
2945
	}
2946
 
2947
	if ((cur == VI_CurrentColumn) && !leftside)
2948
	    ncol = col + PromptWidth - 1;
2949
 
2950
	cur++;
2951
    }
2952
 
2953
    if (cur == VI_CurrentColumn)
2954
	ncol = col + PromptWidth;
2955
 
2956
    if (col < WindowWidth)
2957
    {
2958
	while (col < WindowWidth)
2959
	{
2960
	    *(twb1++) = CHAR_SPACE;
2961
	    col++;
2962
	}
2963
    }
2964
 
2965
    else
2966
	moreright++;
2967
 
2968
    *twb1 = CHAR_SPACE;
2969
 
2970
    col = PromptWidth;
2971
    cnt = WindowWidth;
2972
    twb1 = wb1;
2973
    twb2 = wb2;
2974
 
2975
    while (cnt--)
2976
    {
2977
	if (*twb1 != *twb2)
2978
	{
2979
	    if (CurrentScreenPosition != col)
2980
		VI_MoveToColumn (col, wb1);
2981
 
2982
	    GEN_PutACharacter (*twb1);
2983
	    CurrentScreenPosition++;
2984
	}
2985
 
2986
	twb1++;
2987
	twb2++;
2988
	col++;
2989
    }
2990
 
2991
    if ((vi_EditorState.WindowLeftColumn > 0) && moreright)
2992
	mc = CHAR_PLUS;
2993
 
2994
    else if (vi_EditorState.WindowLeftColumn > 0)
2995
	mc = '<';
2996
 
2997
    else if (moreright)
2998
	mc = '>';
2999
 
3000
    else
3001
	mc = CHAR_SPACE;
3002
 
3003
    if (mc != vi_MoreIndicator)
3004
    {
3005
	VI_MoveToColumn (MaximumColumns - 2, wb1);
3006
	GEN_PutACharacter (mc);
3007
	CurrentScreenPosition++;
3008
	vi_MoreIndicator = mc;
3009
    }
3010
 
3011
#if 0
3012
/*
3013
 * Hack to fix the ^r redraw problem, but it redraws way too much.
3014
 * Probably unacceptable at low baudrates.  Someone please fix this
3015
 */
3016
    else
3017
    {
3018
	VI_MoveToColumn (MaximumColumns - 2, wb1);
3019
    }
3020
#endif
3021
 
3022
    if (CurrentScreenPosition != ncol)
3023
	VI_MoveToColumn (ncol, wb1);
3024
}
3025
 
3026
/*
3027
 * Move to a specific column
3028
 */
3029
 
3030
static void F_LOCAL VI_MoveToColumn (int col, char *wb)
3031
{
3032
    if (col < CurrentScreenPosition)
3033
    {
3034
	if (col + 1 < CurrentScreenPosition - col)
3035
	{
3036
	    VI_OutputPrompt (FALSE);
3037
 
3038
	    while (CurrentScreenPosition++ < col)
3039
		GEN_PutACharacter (*(wb++));
3040
	}
3041
 
3042
	else
3043
	{
3044
	    while (CurrentScreenPosition-- > col)
3045
		GEN_PutACharacter (CHAR_BACKSPACE);
3046
	}
3047
    }
3048
 
3049
    else
3050
    {
3051
	wb = &wb[CurrentScreenPosition - PromptWidth];
3052
 
3053
	while (CurrentScreenPosition++ < col)
3054
	    GEN_PutACharacter (*(wb++));
3055
    }
3056
 
3057
    CurrentScreenPosition = col;
3058
}
3059
 
3060
/*
3061
 * Main loop for VI editing
3062
 */
3063
 
3064
static int F_LOCAL VI_MainLoop (void)
3065
{
3066
    int			c;
3067
 
3068
/* Initialise */
3069
 
3070
    vi_State = VI_S_NORMAL;
3071
    vi_Insert = VI_INSERT_MODE;
3072
 
3073
    vi_PreviousCommand[0] = 'a';
3074
    vi_PrevCmdArgCount = 1;
3075
    vi_InsertBufferLength = 0;
3076
    vi_InputBufferChanged = TRUE;
3077
 
3078
/* Initialise Yank Buffer */
3079
 
3080
    if (vi_YankBuffer != (char *)NULL)
3081
	ReleaseMemoryCell (vi_YankBuffer);
3082
 
3083
    vi_YankBuffer = (char *)NULL;
3084
 
3085
    if (vi_HoldBuffer != null)
3086
	ReleaseMemoryCell (vi_HoldBuffer);
3087
 
3088
    vi_HoldBuffer = null;
3089
 
3090
/* Release Alias input */
3091
 
3092
    vi_AliasBuffer = (char *)NULL;
3093
 
3094
/* Reset the VI edit information */
3095
 
3096
    VI_InputLength		    = 0;
3097
    VI_CurrentColumn		    = 0;
3098
    vi_EditorState.WindowLeftColumn = 0;
3099
 
3100
    if (vi_UndoBuffer != null)
3101
	ReleaseMemoryCell (vi_UndoBuffer);
3102
 
3103
    vi_UndoBuffer		  = null;
3104
    vi_UndoState.InputLength      = 0;
3105
    vi_UndoState.CursorColumn     = 0;
3106
    vi_UndoState.WindowLeftColumn = 0;
3107
 
3108
    /* docap(CLR_EOL, 0); */
3109
 
3110
    vi_WhichWindow = 0;
3111
    vi_MoreIndicator = CHAR_SPACE;
3112
 
3113
/* Initialise the window buffers */
3114
 
3115
    VI_CreateWindowBuffers ();
3116
 
3117
/* Get the input from the user */
3118
 
3119
    FlushStreams ();
3120
 
3121
    while ((c = VI_GetNextCharacter ()) != -1)
3122
    {
3123
	if (VI_StateMachine (c))
3124
	    break;
3125
 
3126
	FlushStreams ();
3127
    }
3128
 
3129
    SetCursorShape (FALSE);
3130
 
3131
/* Check for error */
3132
 
3133
    if (c == -1)
3134
	return -1;
3135
 
3136
/* Ensure line is terminated */
3137
 
3138
    ConsoleLineBuffer[VI_InputLength] = 0;
3139
    return VI_InputLength;
3140
}
3141
 
3142
/*
3143
 * Get next character
3144
 */
3145
 
3146
static int F_LOCAL VI_GetNextCharacter (void)
3147
{
3148
    unsigned char	a_key = 0;
3149
    unsigned char	f_key = 0;
3150
    int			i;
3151
 
3152
    SetCursorShape (C2bool ((vi_State == VI_S_NORMAL) &&
3153
			    (vi_Insert == VI_INSERT_MODE)));
3154
 
3155
    do
3156
    {
3157
	if (vi_AliasBuffer != (char *)NULL)
3158
	{
3159
	    f_key = 0;
3160
 
3161
	    if ((a_key = *(vi_AliasBuffer++)) == 0)
3162
		vi_AliasBuffer = (char *)NULL;
3163
	}
3164
 
3165
	if (vi_AliasBuffer == (char *)NULL)
3166
	    a_key = ReadKeyBoard (&f_key);
3167
 
3168
/* Only map when we are not inserting or replacing */
3169
 
3170
	if ((vi_Insert == VI_UNDEF_MODE) && (vi_State != VI_S_SEARCH))
3171
	{
3172
	    if (!(i = LookUpKeyBoardFunction (a_key, f_key)))
3173
		continue;
3174
 
3175
	    a_key = (i > 0) ? (unsigned char) i : VI_IniMapping[(-i) - 1];
3176
	}
3177
 
3178
/* Treate function keys are bad */
3179
 
3180
	else if (a_key == KT_ALTFUNCTION)
3181
	    a_key = 0;
3182
 
3183
	if (a_key == KT_FUNCTION)
3184
	    RingWarningBell ();
3185
 
3186
    } while (!a_key);
3187
 
3188
    return (a_key == (unsigned char)GetEOFKey ()) ? -1 : a_key;
3189
}
3190
#endif
3191
 
3192
/*
3193
 * Read an edited command line.  This is only called from SH9 if emacs or
3194
 * vi mode is set.
3195
 */
3196
 
3197
#if defined (FLAGS_EMACS) || defined (FLAGS_VI) || defined (FLAGS_GMACS)
3198
int	EditorInput (void)
3199
{
3200
 
3201
/*
3202
 * Check that we have set up (EMACS only)
3203
 */
3204
 
3205
#  if defined (FLAGS_EMACS) || defined (FLAGS_GMACS)
3206
    if (emacs_KeyDefinitions == NULL)
3207
	EMACS_Initialisation ();
3208
#  endif
3209
 
3210
/* Initialise history pointer */
3211
 
3212
    CurrentHistoryEvent = GetLastHistoryEvent ();
3213
 
3214
/* EMACS editing ? */
3215
 
3216
#  if defined (FLAGS_GMACS)
3217
    if (ShellGlobalFlags & FLAGS_GMACS)
3218
	return EMACS_MainLoop ();
3219
#  endif
3220
 
3221
 
3222
/* GMACS editing ? */
3223
 
3224
#  if defined (FLAGS_EMACS)
3225
    if (ShellGlobalFlags & FLAGS_EMACS)
3226
	return EMACS_MainLoop ();
3227
#  endif
3228
 
3229
/* VI editing ? */
3230
 
3231
#  ifdef FLAGS_VI
3232
    if (ShellGlobalFlags & FLAGS_VI)
3233
	return VI_MainLoop ();
3234
#  endif
3235
 
3236
    return -1;
3237
}
3238
#endif
3239
 
3240
 
3241
/*
3242
 * EMACS Functions
3243
 *
3244
 * EMACS Keyboard Input
3245
 */
3246
 
3247
#if defined (FLAGS_EMACS) || defined (FLAGS_GMACS)
3248
static int F_LOCAL EMACS_GetNextCharacter (void)
3249
{
3250
    static unsigned char	LastFkey = 0;
3251
    unsigned char		f_key = 0;
3252
    unsigned char		a_key = 0;
3253
 
3254
    a_key = (emacs_UnGetCharacter != -1)
3255
		? (unsigned char)emacs_UnGetCharacter
3256
		: ((LastFkey)
3257
		    ? LastFkey
3258
		    : ReadKeyBoard (&f_key));
3259
 
3260
    emacs_UnGetCharacter = -1;
3261
 
3262
/* If we got a function key, return 0xE0 and save the function key id */
3263
 
3264
    if ((a_key == KT_FUNCTION) || (a_key == KT_ALTFUNCTION))
3265
    {
3266
	LastFkey = f_key;
3267
	return 0xE0;
3268
    }
3269
 
3270
/* If we ungot 0xE0, return it again! */
3271
 
3272
    else if (a_key == 0xE0)
3273
	return 0xE0;
3274
 
3275
/* Otherwise, return the key and clear the saved function key id */
3276
 
3277
    else
3278
    {
3279
	LastFkey = 0;
3280
	return a_key;
3281
    }
3282
}
3283
 
3284
/*
3285
 * Get next non-function keycode
3286
 */
3287
 
3288
static int F_LOCAL EMACS_GetNonFunctionKey (void)
3289
{
3290
    int		c;
3291
 
3292
    SetCursorShape (FALSE);
3293
 
3294
    while ((c = EMACS_GetNextCharacter ()) == 0xE0)
3295
    {
3296
	EMACS_GetNextCharacter ();
3297
	RingWarningBell ();
3298
    }
3299
 
3300
    return c;
3301
}
3302
 
3303
/*
3304
 * The EMACS Main Loop
3305
 */
3306
 
3307
static int F_LOCAL EMACS_MainLoop (void)
3308
{
3309
    int		c;
3310
    int		i;
3311
    int 	(F_LOCAL *func)(int);
3312
 
3313
    EMACS_ResetInput ();
3314
 
3315
    emacs_MarkPointer = (char *)NULL;
3316
    emacs_CurrentPrefix = 0;
3317
    emacs_CurrentMacroString = null;
3318
    emacs_UnGetCharacter = -1;
3319
    emacs_ArgumentCount = 0;
3320
 
3321
    if (emacs_NextCommandIs != -1)
3322
    {
3323
	EMACS_LoadFromHistory (emacs_NextCommandIs);
3324
	emacs_NextCommandIs = -1;
3325
    }
3326
 
3327
    CurrentScreenColumn = ReadCursorPosition () % MaximumColumns;
3328
 
3329
    AdjustOK = TRUE;
3330
    DisplayWidth = MaximumColumns - 2 - CurrentScreenColumn;
3331
    AdjustDone = 0;
3332
 
3333
    while (1)
3334
    {
3335
	FlushStreams ();
3336
 
3337
	if (*emacs_CurrentMacroString)
3338
	{
3339
	    c = *(emacs_CurrentMacroString++);
3340
 
3341
	    if (*emacs_CurrentMacroString == 0)
3342
		emacs_CurrentMacroString = null;
3343
	}
3344
 
3345
	else
3346
        {
3347
	    SetCursorShape (TRUE);
3348
	    c = EMACS_GetNextCharacter ();
3349
	}
3350
 
3351
	func = (emacs_CurrentPrefix == -1)
3352
		? EMACS_AutoInsert
3353
		: emacs_KeyDefinitions[emacs_CurrentPrefix][c & 0x0ff]->xf_func;
3354
 
3355
	if (func == NULL)
3356
	    func = EMACS_Error;
3357
 
3358
	i = c | (emacs_CurrentPrefix << 8);
3359
 
3360
	emacs_CurrentPrefix = 0;
3361
 
3362
	switch (i = (*func)(i))
3363
	{
3364
	    case EMACS_KEY_NORMAL:
3365
		emacs_LastCommand = func;
3366
 
3367
	    case EMACS_KEY_META:
3368
	    case EMACS_KEY_NOOP:
3369
		break;
3370
 
3371
	    case EMACS_KEY_EOL:
3372
		i = emacs_EndOfLine - ConsoleLineBuffer;
3373
		emacs_LastCommand = (int (F_LOCAL *)(int))NULL;
3374
		return i;
3375
 
3376
	    case EMACS_KEY_INTERRUPT:	/* special case for interrupt */
3377
		raise (SIGINT);
3378
		return -1;
3379
	}
3380
    }
3381
}
3382
 
3383
/*
3384
 * Simply causes the character to appear as literal input.  (Most ordinary
3385
 * characters are bound to this.)
3386
 */
3387
 
3388
static int F_LOCAL EMACS_AutoInsert (int c)
3389
{
3390
    char	str[2];
3391
 
3392
/* Should allow tab and control chars.  */
3393
 
3394
    if (c == 0)
3395
	return EMACS_Error (0);
3396
 
3397
    str[0] = (char)c;
3398
    str[1] = 0;
3399
    EMACS_InsertString (str);
3400
 
3401
    return EMACS_KEY_NORMAL;
3402
}
3403
 
3404
/*
3405
 * Insert macro
3406
 */
3407
 
3408
static int F_LOCAL EMACS_InsertMacroString (int c)
3409
{
3410
    if (*emacs_CurrentMacroString)
3411
	return EMACS_Error (0);
3412
 
3413
    emacs_CurrentMacroString = emacs_MacroDefinitions[c>>8][c & 0x0ff];
3414
    return EMACS_KEY_NORMAL;
3415
}
3416
 
3417
static void F_LOCAL EMACS_InsertString (char *cp)
3418
{
3419
    int		count = strlen(cp);
3420
    int		adj = AdjustDone;
3421
 
3422
    if ((emacs_EndOfLine + count) >= (ConsoleLineBuffer + LINE_MAX))
3423
    {
3424
	RingWarningBell ();
3425
	return;
3426
    }
3427
 
3428
    if (emacs_CurrentPosition != emacs_EndOfLine)
3429
	memmove (emacs_CurrentPosition + count, emacs_CurrentPosition,
3430
		 emacs_EndOfLine - emacs_CurrentPosition + 1);
3431
 
3432
    else
3433
	emacs_CurrentPosition[count] = 0;
3434
 
3435
    memmove (emacs_CurrentPosition, cp, count);
3436
 
3437
/*
3438
 * GEN_AdjustOutputString() may result in a call to GEN_AdjustRedraw ()
3439
 * we want emacs_CurrentPosition to reflect the new position.
3440
 */
3441
    cp = emacs_CurrentPosition;
3442
    emacs_CurrentPosition += count;
3443
    *(emacs_EndOfLine += count) = 0;
3444
    LastVisibleCharValid = FALSE;
3445
    GEN_FindLastVisibleCharacter ();
3446
    AdjustOK = C2bool (emacs_CurrentPosition >= emacs_LastVisibleCharacter);
3447
    GEN_AdjustOutputString (cp);
3448
 
3449
    if (adj == AdjustDone)	/* has GEN_AdjustRedraw () been called? */
3450
    {
3451
      /* no */
3452
	for (cp = emacs_LastVisibleCharacter; cp > emacs_CurrentPosition; )
3453
	    GEN_BackspaceOver (*--cp);
3454
    }
3455
 
3456
    AdjustOK = TRUE;
3457
}
3458
 
3459
/*
3460
 * Check the argument count against either the start or end of line
3461
 */
3462
 
3463
static int F_LOCAL EMACS_RetreatNCharacters (void)
3464
{
3465
    EMACS_CheckArgCount ();
3466
 
3467
    if ((emacs_CurrentPosition - ConsoleLineBuffer) < emacs_ArgumentCount)
3468
	 return emacs_CurrentPosition - ConsoleLineBuffer;
3469
 
3470
    return emacs_ArgumentCount;
3471
}
3472
 
3473
static int F_LOCAL EMACS_AdvanceNCharacters (void)
3474
{
3475
    EMACS_CheckArgCount ();
3476
 
3477
    if ((emacs_EndOfLine - emacs_CurrentPosition) < emacs_ArgumentCount)
3478
	 return emacs_EndOfLine - emacs_CurrentPosition;
3479
 
3480
    return emacs_ArgumentCount;
3481
}
3482
 
3483
/*
3484
 * Deletes the previous character.
3485
 */
3486
 
3487
static int F_LOCAL EMACS_DeleteCharacterBackwards (int c)
3488
{
3489
    int		count = EMACS_RetreatNCharacters ();
3490
 
3491
    if (emacs_CurrentPosition == ConsoleLineBuffer)
3492
	return EMACS_Error (0);
3493
 
3494
    EMACS_GotoColumn (emacs_CurrentPosition - count);
3495
    return EMACS_DeleteString (count);
3496
}
3497
 
3498
/*
3499
 * Deletes the character after the cursor.
3500
 */
3501
 
3502
static int F_LOCAL EMACS_DeleteCurrentCharacter (int c)
3503
{
3504
    if (emacs_CurrentPosition == emacs_EndOfLine)
3505
	return EMACS_Error (0);
3506
 
3507
    return EMACS_DeleteString (EMACS_AdvanceNCharacters ());
3508
}
3509
 
3510
static int F_LOCAL EMACS_DeleteString (int nc)
3511
{
3512
    int		i,j;
3513
    char	*cp;
3514
 
3515
    emacs_ArgumentCount = 0;
3516
 
3517
    if (nc == 0)
3518
	return EMACS_KEY_NORMAL;
3519
 
3520
    if (emacs_MarkPointer != (char *)NULL)
3521
    {
3522
	if (emacs_CurrentPosition + nc > emacs_MarkPointer)
3523
	    emacs_MarkPointer = emacs_CurrentPosition;
3524
 
3525
	else if (emacs_MarkPointer > emacs_CurrentPosition)
3526
	    emacs_MarkPointer -= nc;
3527
    }
3528
 
3529
/* This lets us yank a word we have deleted.  */
3530
 
3531
    if (nc > 1)
3532
	EMACS_StackText (emacs_CurrentPosition, nc);
3533
 
3534
    emacs_EndOfLine -= nc;
3535
    cp = emacs_CurrentPosition;
3536
    j = 0;
3537
    i = nc;
3538
 
3539
    while (i--)
3540
	j += GEN_GetCharacterSize (*(cp++));
3541
 
3542
/* Copy including the null */
3543
 
3544
    memmove (emacs_CurrentPosition, emacs_CurrentPosition + nc,
3545
	     emacs_EndOfLine - emacs_CurrentPosition + 1);
3546
 
3547
    AdjustOK = FALSE;				/* don't redraw */
3548
    GEN_AdjustOutputString (emacs_CurrentPosition);
3549
 
3550
/* if we are already filling the line, there is no need to ' ','\b'.   But if
3551
 * we must, make sure we do the minimum.
3552
 */
3553
 
3554
    if ((i = MaximumColumns - 2 - CurrentScreenColumn) > 0)
3555
    {
3556
	j = (j < i) ? j : i;
3557
	i = j;
3558
 
3559
	while (i--)
3560
	    GEN_PutACharacter (CHAR_SPACE);
3561
 
3562
	i = j;
3563
 
3564
	while (i--)
3565
	    GEN_PutACharacter (CHAR_BACKSPACE);
3566
    }
3567
 
3568
/* EMACS_GotoColumn (emacs_CurrentPosition); */
3569
 
3570
    AdjustOK = TRUE;
3571
    LastVisibleCharValid = FALSE;
3572
 
3573
    for (cp = GEN_FindLastVisibleCharacter (); cp > emacs_CurrentPosition; )
3574
	GEN_BackspaceOver (*(--cp));
3575
 
3576
    return EMACS_KEY_NORMAL;
3577
}
3578
 
3579
/*
3580
 * Deletes the previous word.
3581
 */
3582
 
3583
static int F_LOCAL EMACS_DeletePreviousWord (int c)
3584
{
3585
    return EMACS_DeleteString (EMACS_GetPreviousWord ());
3586
}
3587
 
3588
/*
3589
 * Moves the cursor backward one word.
3590
 */
3591
 
3592
static int F_LOCAL EMACS_MoveBackAWord (int c)
3593
{
3594
    EMACS_GetPreviousWord ();
3595
    return EMACS_KEY_NORMAL;
3596
}
3597
 
3598
/*
3599
 * Moves the cursor forward one word (a string of characters consisting of only
3600
 * letters, digits, and underscores).
3601
 */
3602
 
3603
static int F_LOCAL EMACS_MoveForwardAWord (int c)
3604
{
3605
    return EMACS_GotoColumn (emacs_CurrentPosition + EMACS_GetNextWord ());
3606
}
3607
 
3608
/*
3609
 * Deletes the current word.
3610
 */
3611
 
3612
static int F_LOCAL EMACS_DeleteNextWord (int c)
3613
{
3614
    return EMACS_DeleteString (EMACS_GetNextWord ());
3615
}
3616
 
3617
static int F_LOCAL EMACS_GetPreviousWord (void)
3618
{
3619
    int		nc = 0;
3620
    char	*cp = emacs_CurrentPosition;
3621
 
3622
    if (cp == ConsoleLineBuffer)
3623
    {
3624
	RingWarningBell ();
3625
	return 0;
3626
    }
3627
 
3628
    EMACS_CheckArgCount ();
3629
 
3630
    while (emacs_ArgumentCount--)
3631
    {
3632
	while ((cp != ConsoleLineBuffer) && EMACS_IS_SPACE (cp[-1]))
3633
	{
3634
	    cp--;
3635
	    nc++;
3636
	}
3637
 
3638
	while ((cp != ConsoleLineBuffer) && !EMACS_IS_SPACE (cp[-1]))
3639
	{
3640
	    cp--;
3641
	    nc++;
3642
	}
3643
    }
3644
 
3645
    EMACS_GotoColumn (cp);
3646
    return nc;
3647
}
3648
 
3649
/*
3650
 * Find the end of the next word
3651
 */
3652
 
3653
static int F_LOCAL EMACS_GetNextWord (void)
3654
{
3655
    int		nc = 0;
3656
    char	*cp = emacs_CurrentPosition;
3657
 
3658
    if (cp == emacs_EndOfLine)
3659
    {
3660
	RingWarningBell ();
3661
	return 0;
3662
    }
3663
 
3664
    EMACS_CheckArgCount ();
3665
 
3666
    while (emacs_ArgumentCount--)
3667
    {
3668
	while ((cp != emacs_EndOfLine) && !EMACS_IS_SPACE (*cp))
3669
	{
3670
	    cp++;
3671
	    nc++;
3672
	}
3673
 
3674
	while ((cp != emacs_EndOfLine) && EMACS_IS_SPACE (*cp))
3675
	{
3676
	    cp++;
3677
	    nc++;
3678
	}
3679
    }
3680
 
3681
    emacs_ArgumentCount = 0;
3682
    return nc;
3683
}
3684
 
3685
static int F_LOCAL EMACS_GotoColumn (char *cp)
3686
{
3687
    if (cp < emacs_StartVisible || cp >= (emacs_StartVisible + DisplayWidth))
3688
    {
3689
 
3690
/* we are heading off screen */
3691
 
3692
	emacs_CurrentPosition = cp;
3693
	GEN_AdjustRedraw ();
3694
    }
3695
 
3696
    else if (cp < emacs_CurrentPosition)		/* move back */
3697
    {
3698
	while (cp < emacs_CurrentPosition)
3699
	    GEN_BackspaceOver (*--emacs_CurrentPosition);
3700
    }
3701
 
3702
    else if (cp > emacs_CurrentPosition) 		/* move forward */
3703
    {
3704
	while (cp > emacs_CurrentPosition)
3705
	    GEN_OutputCharacterWithControl (*(emacs_CurrentPosition++));
3706
    }
3707
 
3708
    emacs_ArgumentCount = 0;
3709
    return EMACS_KEY_NORMAL;
3710
}
3711
 
3712
static int F_LOCAL EMACS_GetDisplayStringSize (char *cp)
3713
{
3714
    int		size = 0;
3715
 
3716
    while (*cp)
3717
	size += GEN_GetCharacterSize (*(cp++));
3718
 
3719
    return size;
3720
}
3721
 
3722
/*
3723
 * Moves the cursor backward (left) one character.
3724
 */
3725
 
3726
static int F_LOCAL EMACS_PreviousCharacter (int c)
3727
{
3728
    if (emacs_CurrentPosition == ConsoleLineBuffer)
3729
	return EMACS_Error (0);
3730
 
3731
    return EMACS_GotoColumn (emacs_CurrentPosition -
3732
			     EMACS_RetreatNCharacters ());
3733
}
3734
 
3735
/*
3736
 * Moves the cursor forward one position.
3737
 */
3738
 
3739
static int F_LOCAL EMACS_NextCharacter (int c)
3740
{
3741
    if (emacs_CurrentPosition == emacs_EndOfLine)
3742
	return EMACS_Error (0);
3743
 
3744
    return EMACS_GotoColumn (emacs_CurrentPosition +
3745
			     EMACS_AdvanceNCharacters ());
3746
}
3747
 
3748
/*
3749
 * Find character functions
3750
 *
3751
 * Moves the cursor forward on the current line to the indicated character.
3752
 */
3753
 
3754
static int F_LOCAL EMACS_ForwardToCharacter (int c)
3755
{
3756
    return EMACS_FindCharacter (1, emacs_EndOfLine);
3757
}
3758
 
3759
/* Search for a match */
3760
/*
3761
 * Search backwards in the current line for the next keyboard character.
3762
 * Moves the cursor backword on the current line to the indicated character.
3763
 */
3764
 
3765
static int F_LOCAL EMACS_BackwardToCharacter (int c)
3766
{
3767
    return EMACS_FindCharacter (-1, ConsoleLineBuffer);
3768
}
3769
 
3770
static int F_LOCAL EMACS_FindCharacter (int direction, char *end)
3771
{
3772
    char	*cp = emacs_CurrentPosition;
3773
    int		c;
3774
 
3775
    EMACS_CheckArgCount ();
3776
    *emacs_EndOfLine = 0;
3777
 
3778
    if (emacs_CurrentPosition == end)
3779
	return EMACS_Error (0);
3780
 
3781
    c = EMACS_GetNonFunctionKey ();
3782
 
3783
/* Search for a match */
3784
 
3785
    do
3786
    {
3787
	cp += direction;
3788
 
3789
	if ((*cp == (char)c) && (--emacs_ArgumentCount == 0))
3790
	    return EMACS_GotoColumn (cp);
3791
 
3792
    } while (cp != end);
3793
 
3794
    return EMACS_Error (0);
3795
}
3796
 
3797
/*
3798
 * New line character - execute the line
3799
 */
3800
 
3801
static int F_LOCAL EMACS_NewLine (int c)
3802
{
3803
    GEN_PutACharacter (CHAR_NEW_LINE);
3804
    FlushStreams ();
3805
    *(emacs_EndOfLine++) = CHAR_NEW_LINE;
3806
    *emacs_EndOfLine = 0;
3807
    return EMACS_KEY_EOL;
3808
}
3809
 
3810
/*
3811
 * Acts as an end-of-file.
3812
 */
3813
 
3814
static int F_LOCAL EMACS_EndOfInput (int c)
3815
{
3816
    GEN_PutACharacter (CHAR_NEW_LINE);
3817
    FlushStreams ();
3818
    *(emacs_EndOfLine++) = (char)GetEOFKey ();
3819
    *emacs_EndOfLine = 0;
3820
    return EMACS_KEY_EOL;
3821
}
3822
 
3823
/*
3824
 * History processing
3825
 *
3826
 * Fetches the least recent (oldest) history line.
3827
 */
3828
 
3829
static int F_LOCAL EMACS_GetFirstHistory (int c)
3830
{
3831
    return EMACS_LoadFromHistory (GetFirstHistoryEvent ());
3832
}
3833
 
3834
/*
3835
 * Fetches the most recent (youngest) history line.
3836
 */
3837
 
3838
static int F_LOCAL EMACS_GetLastHistory (int c)
3839
{
3840
    return EMACS_LoadFromHistory (GetLastHistoryEvent () - 1);
3841
}
3842
 
3843
/*
3844
 * Fetches the previous command.  Each time Ctrl-P is entered, the previous
3845
 * command back in time is accessed.  Moves back one line when not on the
3846
 * first line of a multiple line command.
3847
 */
3848
 
3849
static int F_LOCAL EMACS_GetPreviousCommand (int c)
3850
{
3851
    EMACS_CheckArgCount ();
3852
    return EMACS_LoadFromHistory (CurrentHistoryEvent - emacs_ArgumentCount);
3853
}
3854
 
3855
/*
3856
 * Fetches the next command line.  Each time Ctrl-N is entered, the next
3857
 * command line forward in time is accessed.
3858
 */
3859
 
3860
static int F_LOCAL EMACS_GetNextCommand (int c)
3861
{
3862
    EMACS_CheckArgCount ();
3863
    return EMACS_LoadFromHistory (CurrentHistoryEvent + emacs_ArgumentCount);
3864
}
3865
 
3866
/*
3867
 * Load the requested history record
3868
 */
3869
 
3870
static int F_LOCAL EMACS_LoadFromHistory (int event)
3871
{
3872
    int		oldsize;
3873
    char	*hp;
3874
 
3875
    if ((event < 0) || (event > GetLastHistoryEvent ()) ||
3876
	((hp = GetHistoryRecord (event)) == (char *)NULL))
3877
	return EMACS_Error (0);
3878
 
3879
    CurrentHistoryEvent = event;
3880
 
3881
    oldsize = EMACS_GetDisplayStringSize (ConsoleLineBuffer);
3882
    strcpy (ConsoleLineBuffer, hp);
3883
 
3884
    emacs_StartVisible = ConsoleLineBuffer;
3885
    emacs_CurrentPosition = ConsoleLineBuffer + strlen (hp);
3886
    *(emacs_EndOfLine = emacs_CurrentPosition) = 0;
3887
    LastVisibleCharValid = FALSE;
3888
 
3889
    if (emacs_EndOfLine > GEN_FindLastVisibleCharacter ())
3890
	EMACS_GotoColumn (emacs_EndOfLine);
3891
 
3892
    else
3893
	GEN_Redraw (oldsize);
3894
 
3895
    return EMACS_KEY_NORMAL;
3896
}
3897
 
3898
/*
3899
 * Operate - Executes the current line and fetches the next line relative to
3900
 * the current line from the history file.
3901
 */
3902
 
3903
static int F_LOCAL EMACS_OperateOnLine (int c)
3904
{
3905
    emacs_NextCommandIs = CurrentHistoryEvent + 1;
3906
    return (EMACS_NewLine (c));
3907
}
3908
 
3909
/*
3910
 * Acts as end-of-file if alone on a line; otherwise deletes current
3911
 * character.
3912
 */
3913
 
3914
static int F_LOCAL EMACS_EOTOrDelete (int c)
3915
{
3916
    return (emacs_EndOfLine == ConsoleLineBuffer)
3917
		? EMACS_EndOfInput (c)
3918
		: EMACS_DeleteCurrentCharacter (c);
3919
}
3920
 
3921
/*
3922
 * Reverses search history for a previous command line containing the string
3923
 * specified by the String parameter.  If a value of zero is given, the
3924
 * search is forward.  The specified string is terminated by an Enter
3925
 * or new-line character.  If the string is preceded by a ^ (caret character),
3926
 * the matched line must begin with String.  If the String parameter is
3927
 * omitted, then the next command line containing the most recent String is
3928
 * accessed.  In this case, a value of zero reverses the direction of the
3929
 * search.
3930
 *
3931
 * ARG COUNT not implemented
3932
 */
3933
 
3934
static int F_LOCAL EMACS_SearchHistory (int c)
3935
{
3936
    int			offset = -1;	/* offset of match in		*/
3937
					/* ConsoleLineBuffer, else -1	*/
3938
    char		pat [256 + 1];	/* pattern buffer */
3939
    char		*p = pat;
3940
    int			(F_LOCAL *func)(int);
3941
    int			direction = -1;
3942
 
3943
    *p = 0;
3944
 
3945
    if ((emacs_LastCommand == EMACS_SetArgValue) &&
3946
        (!emacs_ArgumentCount))
3947
	direction = 1;
3948
 
3949
    while (1)
3950
    {
3951
	if (offset < 0)
3952
	{
3953
	    GEN_PutAString ("\nI-search: ");
3954
	    GEN_PutAString (pat);
3955
	    GEN_AdjustOutputString (pat);
3956
	}
3957
 
3958
	FlushStreams ();
3959
 
3960
	c = EMACS_GetNonFunctionKey ();
3961
 
3962
	func = emacs_KeyDefinitions[0][c & 0x0ff]->xf_func;
3963
 
3964
	if (c == CHAR_ESCAPE)
3965
	    break;
3966
 
3967
	else if (func == EMACS_SearchHistory)
3968
	    offset = EMACS_SearchMatch (pat, offset, direction);
3969
 
3970
/* Add / Delete a character to / from the string */
3971
 
3972
	else if ((func == EMACS_DeleteCharacterBackwards) ||
3973
		 (func == EMACS_AutoInsert))
3974
	{
3975
	    if (func == EMACS_DeleteCharacterBackwards)
3976
	    {
3977
		if (p == pat)
3978
		{
3979
		    RingWarningBell ();		/* Empty string */
3980
		    continue;
3981
		}
3982
 
3983
		*(--p) = 0;
3984
 
3985
/* Empty string - no search - restart */
3986
 
3987
		if (p == pat)
3988
		{
3989
		    offset = -1;
3990
		    continue;
3991
		}
3992
	    }
3993
 
3994
/* Add character to string */
3995
 
3996
	    else if (p >= pat + 256)
3997
	    {
3998
		RingWarningBell ();		/* Too long */
3999
		continue;
4000
	    }
4001
 
4002
/* add char to pattern */
4003
 
4004
	    else
4005
	    {
4006
		*(p++) = (char)c;
4007
		*p = 0;
4008
	    }
4009
 
4010
/* Search */
4011
 
4012
	    if (offset >= 0)
4013
	    {
4014
 
4015
/* already have partial match */
4016
 
4017
		if ((offset = EMACS_PatternMatch (ConsoleLineBuffer, pat)) >= 0)
4018
		{
4019
		    EMACS_GotoColumn (ConsoleLineBuffer + offset + (p - pat) -
4020
			    (*pat == '^'));
4021
		    continue;
4022
		}
4023
	    }
4024
 
4025
	    offset = EMACS_SearchMatch (pat, offset, direction);
4026
	}
4027
 
4028
/* other command */
4029
 
4030
	else
4031
	{
4032
	    static char push[2];
4033
 
4034
	    push[0] = (char)c;
4035
	    push[1] = 0;
4036
	    emacs_CurrentMacroString = push; /* push command */
4037
	    break;
4038
	}
4039
    }
4040
 
4041
    if (offset < 0)
4042
	GEN_Redraw (-1);
4043
 
4044
    return EMACS_KEY_NORMAL;
4045
}
4046
 
4047
/*
4048
 * search backward from current line
4049
 */
4050
 
4051
static int F_LOCAL EMACS_SearchMatch (char *pat, int offset, int direction)
4052
{
4053
    int		event = CurrentHistoryEvent + direction;
4054
    char	*hp;
4055
    int		i;
4056
 
4057
    while ((hp = GetHistoryRecord (event)) != (char *)NULL)
4058
    {
4059
	if ((i = EMACS_PatternMatch (hp, pat)) >= 0)
4060
	{
4061
	    if (offset < 0)
4062
		GEN_PutACharacter (CHAR_NEW_LINE);
4063
 
4064
	    EMACS_LoadFromHistory (event);
4065
	    EMACS_GotoColumn (ConsoleLineBuffer + i + strlen (pat) -
4066
			      (*pat == '^'));
4067
	    return i;
4068
	}
4069
 
4070
	event += direction;
4071
    }
4072
 
4073
    RingWarningBell ();
4074
    CurrentHistoryEvent = GetLastHistoryEvent ();
4075
    return -1;
4076
}
4077
 
4078
/*
4079
 * Return position of first match of pattern in string, else -1
4080
 */
4081
 
4082
static int F_LOCAL EMACS_PatternMatch (char *str, char *pat)
4083
{
4084
    if (*pat == '^')
4085
	return (strncmp (str, pat + 1, strlen (pat + 1)) == 0) ? 0 : -1;
4086
 
4087
    else
4088
    {
4089
	char *q = strstr (str, pat);
4090
 
4091
	return (q == (char *)NULL) ? -1 : q - str;
4092
    }
4093
}
4094
 
4095
/*
4096
 * Kill the current line
4097
 */
4098
 
4099
static int F_LOCAL EMACS_KillLine (int c)
4100
{
4101
    int		i, j;
4102
 
4103
    *emacs_EndOfLine = 0;
4104
    i = emacs_EndOfLine - ConsoleLineBuffer;
4105
    j = EMACS_GetDisplayStringSize (ConsoleLineBuffer);
4106
    EMACS_StackText (emacs_CurrentPosition = ConsoleLineBuffer, i);
4107
 
4108
    EMACS_ResetInput ();
4109
    emacs_MarkPointer = (char *)NULL;
4110
 
4111
    if (c != -1)
4112
	GEN_Redraw (j);
4113
 
4114
    return EMACS_KEY_NORMAL;
4115
}
4116
 
4117
/*
4118
 * Move to the end of the line
4119
 */
4120
 
4121
static int F_LOCAL EMACS_GotoEnd (int c)
4122
{
4123
    return EMACS_GotoColumn (emacs_EndOfLine);
4124
}
4125
 
4126
/*
4127
 * Move to the start of the line
4128
 */
4129
 
4130
static int F_LOCAL EMACS_GotoStart (int c)
4131
{
4132
    return EMACS_GotoColumn (ConsoleLineBuffer);
4133
}
4134
 
4135
/*
4136
 * Redraw the line
4137
 */
4138
 
4139
static int F_LOCAL EMACS_RedrawLine (int c)
4140
{
4141
    GEN_Redraw (-1);
4142
    return EMACS_KEY_NORMAL;
4143
}
4144
 
4145
/*
4146
 * Transposes the current character with the next character in emacs mode.
4147
 * Transposes the two previous characters in gmacs mode.
4148
 */
4149
 
4150
static int F_LOCAL EMACS_Transpose (int c)
4151
{
4152
    char	tmp;
4153
 
4154
    if (emacs_CurrentPosition == ConsoleLineBuffer)
4155
	return EMACS_Error (0);
4156
 
4157
    else if ((emacs_CurrentPosition == emacs_EndOfLine)
4158
#  if defined (FLAGS_GMACS)
4159
	     || (ShellGlobalFlags & FLAGS_GMACS)
4160
#  endif
4161
	    )
4162
    {
4163
	if (emacs_CurrentPosition - ConsoleLineBuffer == 1)
4164
	    return EMACS_Error (0);
4165
 
4166
	tmp = emacs_CurrentPosition[-1];
4167
	emacs_CurrentPosition[-1] = emacs_CurrentPosition[-2];
4168
	emacs_CurrentPosition[-2] = tmp;
4169
 
4170
	GEN_BackspaceOver (tmp);
4171
	GEN_BackspaceOver (emacs_CurrentPosition[-1]);
4172
	GEN_OutputCharacterWithControl (tmp);
4173
	GEN_OutputCharacterWithControl (emacs_CurrentPosition[-1]);
4174
    }
4175
 
4176
/* Transpose the current and next characters */
4177
 
4178
    else if ((emacs_CurrentPosition + 1) == emacs_EndOfLine)
4179
	return EMACS_Error (0);
4180
 
4181
    else
4182
    {
4183
	tmp = emacs_CurrentPosition[0];
4184
	emacs_CurrentPosition[0] = emacs_CurrentPosition[1];
4185
	emacs_CurrentPosition[1] = tmp;
4186
	GEN_OutputCharacterWithControl (emacs_CurrentPosition[0]);
4187
	GEN_OutputCharacterWithControl (tmp);
4188
	GEN_BackspaceOver (tmp);
4189
	emacs_CurrentPosition++;
4190
    }
4191
 
4192
    return EMACS_KEY_NORMAL;
4193
}
4194
 
4195
/*
4196
 * Escapes the next character.  Editing characters can be entered in a command
4197
 * line or in a search string if preceded by a quote command.  The escape
4198
 * removes the next character's editing features, if any.
4199
 */
4200
 
4201
static int F_LOCAL EMACS_LiteralValue (int c)
4202
{
4203
    emacs_CurrentPrefix = -1;
4204
    return EMACS_KEY_NORMAL;
4205
}
4206
 
4207
/*
4208
 * Change the prefix values
4209
 *
4210
 * Introduces a 2-character command sequence.
4211
 */
4212
 
4213
static int F_LOCAL EMACS_Prefix1 (int c)
4214
{
4215
    emacs_CurrentPrefix = 1;
4216
    return EMACS_KEY_META;
4217
}
4218
 
4219
/*
4220
 * Introduces a 2-character command sequence.
4221
 */
4222
 
4223
static int F_LOCAL EMACS_Prefix2 (int c)
4224
{
4225
    emacs_CurrentPrefix = 2;
4226
    return EMACS_KEY_META;
4227
}
4228
 
4229
/* Introduces a 2-character command sequence.  This prefix allows the user to
4230
 * map PC function keys onto commands.  The second character is the IBM scan
4231
 * code value of the function key to be assigned.
4232
 */
4233
 
4234
static int F_LOCAL EMACS_Prefix3 (int c)
4235
{
4236
    emacs_CurrentPrefix = 3;
4237
    return EMACS_KEY_META;
4238
}
4239
 
4240
/*
4241
 * Deletes from the cursor to the end of the line.  If preceded by a numerical
4242
 * parameter whose value is less than the current cursor position, this editing
4243
 * command deletes from the given position up to the cursor.  If preceded by a
4244
 * numerical parameter whose value is greater than the current cursor position,
4245
 * this editing command deletes from the cursor up to given cursor position.
4246
 */
4247
 
4248
static int F_LOCAL EMACS_KillToEndOfLine (int c)
4249
{
4250
    int		i = emacs_EndOfLine - emacs_CurrentPosition;
4251
    char	*cp;
4252
 
4253
/* If a count is provided */
4254
 
4255
    if (emacs_LastCommand == EMACS_SetArgValue)
4256
    {
4257
	if ((cp = ConsoleLineBuffer + emacs_ArgumentCount) > emacs_EndOfLine)
4258
	    cp = emacs_EndOfLine;
4259
 
4260
	if (cp > emacs_CurrentPosition)
4261
	    i = cp - emacs_CurrentPosition;
4262
 
4263
	else if (cp < emacs_CurrentPosition)
4264
	{
4265
	    i = emacs_CurrentPosition - cp;
4266
	    EMACS_GotoColumn (cp);
4267
	}
4268
    }
4269
 
4270
    emacs_LastVisibleCharacter = emacs_CurrentPosition;
4271
    LastVisibleCharValid = TRUE;
4272
 
4273
/* only stack text if DeleteString doesn't */
4274
 
4275
    if (i <= 1)
4276
	EMACS_StackText (emacs_CurrentPosition, i);
4277
 
4278
    return EMACS_DeleteString (i);
4279
}
4280
 
4281
/*
4282
 * Push a text string on to the circular stack
4283
 */
4284
 
4285
static void F_LOCAL EMACS_StackText (char *start, int nchars)
4286
{
4287
    char	*cp;
4288
 
4289
    SetMemoryAreaNumber (cp = GetAllocatedSpace ((size_t)(nchars + 1)), 0);
4290
 
4291
    memmove (cp, start, nchars);
4292
    cp[nchars] = 0;
4293
 
4294
    if (emacs_Stack[emacs_StackPointer] != (char *)NULL)
4295
	ReleaseMemoryCell ((void *)emacs_Stack[emacs_StackPointer]);
4296
 
4297
    emacs_Stack[emacs_StackPointer] = cp;
4298
    emacs_StackPointer = (emacs_StackPointer + 1) % EMACS_KILL_SIZE;
4299
}
4300
 
4301
/*
4302
 * Pushes the region from the cursor to the mark on the stack.
4303
 */
4304
 
4305
static int F_LOCAL EMACS_PushText (int c)
4306
{
4307
    if (emacs_MarkPointer == (char *)NULL)
4308
	return EMACS_Error (c);
4309
 
4310
    if (emacs_MarkPointer > emacs_CurrentPosition)
4311
	EMACS_StackText (emacs_CurrentPosition,
4312
			 emacs_MarkPointer - emacs_CurrentPosition);
4313
 
4314
    else
4315
	EMACS_StackText (emacs_MarkPointer,
4316
			 emacs_CurrentPosition - emacs_MarkPointer);
4317
 
4318
    return EMACS_KEY_NORMAL;
4319
 
4320
}
4321
 
4322
/*
4323
 * Restores the last item removed from line.  (Yanks the item back to the line.)
4324
 */
4325
 
4326
static int F_LOCAL EMACS_PutText (int c)
4327
{
4328
    emacs_TopOfStack = (emacs_StackPointer == 0) ? EMACS_KILL_SIZE - 1
4329
						 : emacs_StackPointer - 1;
4330
 
4331
    if (emacs_Stack[emacs_TopOfStack] == (char *)NULL)
4332
	return EMACS_YankError (emacs_NTY);
4333
 
4334
    emacs_MarkPointer = emacs_CurrentPosition;
4335
    EMACS_InsertString (emacs_Stack[emacs_TopOfStack]);
4336
    return EMACS_KEY_NORMAL;
4337
}
4338
 
4339
/*
4340
 * Yank the text - remove top stack item
4341
 */
4342
 
4343
static int F_LOCAL EMACS_YankText (int c)
4344
{
4345
    emacs_TopOfStack = (emacs_StackPointer == 0) ? EMACS_KILL_SIZE
4346
						 : emacs_StackPointer;
4347
 
4348
    if (emacs_Stack[--emacs_TopOfStack] == (char *)NULL)
4349
	return EMACS_YankError (emacs_NTY);
4350
 
4351
    emacs_MarkPointer = emacs_CurrentPosition;
4352
    EMACS_InsertString (emacs_Stack[emacs_TopOfStack]);
4353
    return EMACS_KEY_NORMAL;
4354
}
4355
 
4356
/*
4357
 * Immediately after a yank, replaces the inserted text string with the
4358
 * next previous killed text string.
4359
 */
4360
 
4361
static int F_LOCAL EMACS_YankPop (int c)
4362
{
4363
    int		len;
4364
    char	*err = (char *)NULL;
4365
    int		previous = (emacs_TopOfStack == 0) ? EMACS_KILL_SIZE - 1
4366
						   : emacs_TopOfStack - 1;
4367
 
4368
/* Check that there are enough items on the stack */
4369
 
4370
    if ((emacs_LastCommand != EMACS_YankText) &&
4371
	(emacs_LastCommand != EMACS_PutText))
4372
	err = "\nyank something first";
4373
 
4374
    else if (emacs_Stack[previous] == (char *)NULL)
4375
	err = "\nonly one item on stack";
4376
 
4377
    if (err != (char *)NULL)
4378
	return EMACS_YankError (err);
4379
 
4380
/* Remove the top of stack */
4381
 
4382
    len = strlen (emacs_Stack[emacs_TopOfStack]);
4383
    EMACS_GotoColumn (emacs_CurrentPosition - len);
4384
    EMACS_DeleteString (len);
4385
 
4386
/* Insert the previous string */
4387
 
4388
    EMACS_InsertString (emacs_Stack[emacs_TopOfStack = previous]);
4389
    return EMACS_KEY_NORMAL;
4390
}
4391
 
4392
/*
4393
 * Yank error
4394
 */
4395
 
4396
static int F_LOCAL EMACS_YankError (char *message)
4397
{
4398
    EMACS_Error (0);
4399
    GEN_PutAString (message);
4400
    GEN_Redraw (-1);
4401
    return EMACS_KEY_NORMAL;
4402
}
4403
 
4404
/*
4405
 * Error - ring the bell
4406
 */
4407
 
4408
static int F_LOCAL EMACS_Error (int c)
4409
{
4410
    RingWarningBell ();
4411
    emacs_ArgumentCount = 0;
4412
    return EMACS_KEY_NORMAL;
4413
}
4414
 
4415
/*
4416
 * Reset input, clearing the current line and yank buffers.
4417
 */
4418
 
4419
static int F_LOCAL EMACS_FullReset (int c)
4420
{
4421
    GEN_OutputCharacterWithControl (c);
4422
 
4423
    EMACS_ResetInput ();
4424
    GEN_Redraw (-1);
4425
    return EMACS_KEY_NORMAL;
4426
}
4427
 
4428
/*
4429
 * Reset the input pointers
4430
 */
4431
 
4432
static void F_LOCAL EMACS_ResetInput (void)
4433
{
4434
    emacs_StartVisible	       = ConsoleLineBuffer;
4435
    emacs_CurrentPosition      = ConsoleLineBuffer;
4436
    emacs_EndOfLine	       = ConsoleLineBuffer;
4437
    emacs_LastVisibleCharacter = ConsoleLineBuffer;
4438
 
4439
    LastVisibleCharValid = TRUE;
4440
    *emacs_CurrentPosition = 0;
4441
    emacs_ArgumentCount = 0;
4442
}
4443
 
4444
/*
4445
 * Abort the edit - Useful as a response to a request for a search-history
4446
 * pattern in order to abort the search.
4447
 */
4448
 
4449
static int F_LOCAL EMACS_Abort (int c)
4450
{
4451
    /* GEN_OutputCharacterWithControl(c); */
4452
    EMACS_ResetInput ();
4453
    EMACS_KillLine (-1);
4454
    return EMACS_KEY_INTERRUPT;
4455
}
4456
 
4457
/*
4458
 * Translate special characters in the keystroke macro to binary
4459
 */
4460
 
4461
static void F_LOCAL EMACS_MapInKeyStrokes (char *cp)
4462
{
4463
    unsigned char	*op = (unsigned char *)cp;
4464
 
4465
    while (*cp)
4466
    {
4467
 
4468
/* XXX -- should handle \^ escape? */
4469
 
4470
	if (*cp == '^')
4471
	{
4472
	    cp++;
4473
 
4474
	    if (*cp == '0')
4475
		*(op++) = 0xE0;
4476
 
4477
	    else if (*cp >= '?')	/* includes '?'; ASCII */
4478
		*(op++) = (char)(*cp == '?' ? 0x07f : *cp & 0x1F);
4479
 
4480
	    else
4481
	    {
4482
		*(op++) = '^';
4483
		cp--;
4484
	    }
4485
	}
4486
 
4487
	else
4488
	    *(op++) = *cp;
4489
 
4490
	cp++;
4491
    }
4492
 
4493
    *op = 0;
4494
}
4495
 
4496
/*
4497
 * Convert Macro keystrokes to display characters and display it
4498
 */
4499
 
4500
static void F_LOCAL EMACS_MapOutKeystrokes (unsigned int c)
4501
{
4502
 
4503
/* ASCII? */
4504
 
4505
    if ((c < CHAR_SPACE) || (c == 0x7F))
4506
    {
4507
	fputchar ('^');
4508
	c = (c == 0x7F) ? '?' : (c | 0x40);
4509
    }
4510
 
4511
    else if (c == 0xE0)
4512
    {
4513
	fputchar ('^');
4514
	c = '0';
4515
    }
4516
 
4517
    fputchar (c);
4518
}
4519
 
4520
/*
4521
 * Print a macro value
4522
 */
4523
 
4524
static void F_LOCAL EMACS_PrintMacros (int prefix, int key)
4525
{
4526
    bool	Quotes = FALSE;
4527
 
4528
    if (prefix == 1)
4529
	EMACS_MapOutKeystrokes (emacs_Prefix1);
4530
 
4531
    else if (prefix == 2)
4532
	EMACS_MapOutKeystrokes (emacs_Prefix2);
4533
 
4534
    else if (prefix == 3)
4535
	EMACS_MapOutKeystrokes (emacs_Prefix3);
4536
 
4537
    EMACS_MapOutKeystrokes (key);
4538
    foputs (" = ");
4539
 
4540
    if (emacs_KeyDefinitions[prefix][key]->xf_func != EMACS_InsertMacroString)
4541
    {
4542
	Quotes = TRUE;
4543
	fputchar (CHAR_SINGLE_QUOTE);
4544
    }
4545
 
4546
    foputs (emacs_KeyDefinitions[prefix][key]->emacs_FunctionName);
4547
 
4548
    if (Quotes)
4549
	fputchar (CHAR_SINGLE_QUOTE);
4550
 
4551
    fputchar (CHAR_NEW_LINE);
4552
}
4553
 
4554
/*
4555
 * Bind string to macro
4556
 */
4557
 
4558
int	BindKeyStroke (char *keystrokes, char *EditCommand, bool macro)
4559
{
4560
    EMACS_FunctionMap	*fp;
4561
    int			prefix, key;
4562
    char		*sp = (char *)NULL;
4563
 
4564
    if (emacs_KeyDefinitions == NULL)
4565
	return PrintWarningMessage ("bind: only available in interactive mode");
4566
 
4567
    if (keystrokes == (char *)NULL)
4568
    {
4569
	for (prefix = 0; prefix < EMACS_KEYDEF_TABLES; prefix++)
4570
	{
4571
	    for (key = 0; key < EMACS_KEYDEF_ENTRIES; key++)
4572
	    {
4573
		if (((fp = emacs_KeyDefinitions[prefix][key]) == NULL) ||
4574
		    (fp->xf_func == EMACS_AutoInsert) ||
4575
		    (fp->xf_func == EMACS_Error) ||
4576
		    (fp->emacs_FunctionName == null))
4577
			continue;
4578
 
4579
		EMACS_PrintMacros (prefix, key);
4580
	    }
4581
	}
4582
 
4583
	return 0;
4584
    }
4585
 
4586
    EMACS_MapInKeyStrokes (keystrokes);
4587
    prefix = key = 0;
4588
 
4589
    for (;; keystrokes++)
4590
    {
4591
	key = *keystrokes;
4592
 
4593
	if (emacs_KeyDefinitions[prefix][key]->xf_func == EMACS_Prefix1)
4594
	    prefix = 1;
4595
 
4596
	else if (emacs_KeyDefinitions[prefix][key]->xf_func == EMACS_Prefix2)
4597
	    prefix = 2;
4598
 
4599
	else if (emacs_KeyDefinitions[prefix][key]->xf_func == EMACS_Prefix3)
4600
	    prefix = 3;
4601
 
4602
	else
4603
	    break;
4604
    }
4605
 
4606
    if (EditCommand == (char *)NULL)
4607
    {
4608
	EMACS_PrintMacros (prefix, key);
4609
	return 0;
4610
    }
4611
 
4612
    if (*EditCommand == 0)
4613
	fp = ((prefix == 1) && ((isalpha (key)) || (key == ']' & 0x1f)))
4614
		? EMACS_ALIAS_MAP : EMACS_INSERT_MAP;
4615
 
4616
    else if (!macro)
4617
    {
4618
	for (fp = EMACS_FunctionMaps; fp->xf_func; fp++)
4619
	{
4620
	    if (strcmp(fp->emacs_FunctionName, EditCommand) == 0)
4621
		break;
4622
	}
4623
 
4624
	if (fp->xf_func == NULL || (fp->emacs_FunctionFlags & EMACS_NO_BIND))
4625
	    return PrintWarningMessage ("%s: no such function", EditCommand);
4626
 
4627
	if (fp->xf_func == EMACS_Prefix1)
4628
	    emacs_Prefix1 = key;
4629
 
4630
	if (fp->xf_func == EMACS_Prefix2)
4631
	    emacs_Prefix2 = key;
4632
 
4633
	if (fp->xf_func == EMACS_Prefix3)
4634
	    emacs_Prefix3 = key;
4635
    }
4636
 
4637
    else
4638
    {
4639
	fp = EMACS_MACRO_MAP;
4640
	EMACS_MapInKeyStrokes (EditCommand);
4641
	sp = StringSave (EditCommand);
4642
    }
4643
 
4644
    if ((emacs_KeyDefinitions[prefix][key]->emacs_FunctionFlags &
4645
		EMACS_MEMORY_ALLOC) &&
4646
	(emacs_MacroDefinitions[prefix][key] != (char *)NULL))
4647
	ReleaseMemoryCell ((void *)emacs_MacroDefinitions[prefix][key]);
4648
 
4649
    emacs_KeyDefinitions[prefix][key] = fp;
4650
    emacs_MacroDefinitions[prefix][key] = sp;
4651
    return 0;
4652
}
4653
 
4654
/*
4655
 * Initialise Emacs
4656
 */
4657
 
4658
void	EMACS_Initialisation (void)
4659
{
4660
    int			i, j;
4661
    unsigned char	a_key, f_key;
4662
    EMACS_FunctionMap	*fp;
4663
 
4664
    emacs_KeyDefinitions = (EMACS_FunctionMap *(*)[EMACS_KEYDEF_ENTRIES])
4665
		GetAllocatedSpace (sizeof (*emacs_KeyDefinitions) *
4666
				   EMACS_KEYDEF_TABLES);
4667
    SetMemoryAreaNumber (emacs_KeyDefinitions, 0);
4668
 
4669
/* Set everything to either insert character or error */
4670
 
4671
    for (j = 0; j < EMACS_KEYDEF_ENTRIES; j++)
4672
	emacs_KeyDefinitions[0][j] = EMACS_INSERT_MAP;
4673
 
4674
    for (i = 1; i < EMACS_KEYDEF_TABLES; i++)
4675
    {
4676
	for (j = 0; j < EMACS_KEYDEF_ENTRIES; j++)
4677
	    emacs_KeyDefinitions[i][j] = EMACS_ERROR_MAP;
4678
    }
4679
 
4680
/* Establish Prefix 1 aliasing ESC-letter or Esc Ctrl-] letter */
4681
 
4682
    emacs_KeyDefinitions[1][']' & 0x01f] = EMACS_ALIAS_MAP;
4683
 
4684
    for (i = 'A'; i <= 'Z'; i++)
4685
    {
4686
	emacs_KeyDefinitions[1][1] = EMACS_ALIAS_MAP;
4687
	emacs_KeyDefinitions[1][tolower(i)] = EMACS_ALIAS_MAP;
4688
    }
4689
 
4690
/* Load the default values */
4691
 
4692
    for (fp = EMACS_FunctionMaps; fp->xf_func; fp++)
4693
    {
4694
	if ((fp->emacs_KeyStroke) || (fp->emacs_TableNumber))
4695
	    emacs_KeyDefinitions[fp->emacs_TableNumber][fp->emacs_KeyStroke]
4696
				= fp;
4697
 
4698
/* Load .ini function ? */
4699
 
4700
	if ((j = fp->emacs_FunctionFlags & EMACS_INI_MASK))
4701
	{
4702
	    if (((a_key = GetFunctionKeyMap (j, &f_key)) == KT_FUNCTION) ||
4703
		 (a_key == KT_ALTFUNCTION))
4704
		emacs_KeyDefinitions[3][f_key] = fp;
4705
 
4706
	    else if (a_key != KT_RESIZE)
4707
		emacs_KeyDefinitions[0][a_key] = fp;
4708
 
4709
 
4710
/* Handle special case of scan forwards and backwards in history */
4711
 
4712
	    if (j == KF_SCANFOREWARD)
4713
	    {
4714
	        if (((a_key = GetFunctionKeyMap (KF_SCANBACKWARD,
4715
						 &f_key)) == KT_FUNCTION) ||
4716
		     (a_key == KT_ALTFUNCTION))
4717
		    emacs_KeyDefinitions[3][f_key] = fp;
4718
 
4719
		else if (a_key != KT_RESIZE)
4720
		    emacs_KeyDefinitions[0][a_key] = fp;
4721
	    }
4722
	}
4723
    }
4724
 
4725
/* Set up macro definitions */
4726
 
4727
    emacs_MacroDefinitions = (char *(*)[EMACS_KEYDEF_ENTRIES])
4728
    		GetAllocatedSpace (sizeof (*emacs_MacroDefinitions) *
4729
				   EMACS_KEYDEF_TABLES);
4730
 
4731
    SetMemoryAreaNumber (emacs_MacroDefinitions, 0);
4732
 
4733
    for (i = 1; i < EMACS_KEYDEF_TABLES; i++)
4734
    {
4735
	for (j = 0; j < EMACS_KEYDEF_ENTRIES; j++)
4736
	    emacs_MacroDefinitions[i][j] = NULL;
4737
    }
4738
}
4739
 
4740
/*
4741
 * Clear the screen and print the current line.
4742
 */
4743
 
4744
static int F_LOCAL EMACS_ClearScreen (int c)
4745
{
4746
    ClearScreen ();
4747
    GEN_Redraw (0);
4748
    return EMACS_KEY_NORMAL;
4749
}
4750
 
4751
/*
4752
 * Set a mark
4753
 */
4754
 
4755
static int F_LOCAL EMACS_SetMark (int c)
4756
{
4757
    emacs_MarkPointer = emacs_CurrentPosition;
4758
    return EMACS_KEY_NORMAL;
4759
}
4760
 
4761
/*
4762
 * Kills from the cursor to the mark.
4763
 */
4764
 
4765
static int F_LOCAL EMACS_KillRegion (int c)
4766
{
4767
    int		rsize;
4768
    char	*xr;
4769
 
4770
    if (emacs_MarkPointer == (char *)NULL)
4771
	return EMACS_Error (c);
4772
 
4773
    if (emacs_MarkPointer > emacs_CurrentPosition)
4774
    {
4775
	rsize = emacs_MarkPointer - emacs_CurrentPosition;
4776
	xr = emacs_CurrentPosition;
4777
    }
4778
 
4779
    else
4780
    {
4781
	rsize = emacs_CurrentPosition - emacs_MarkPointer;
4782
	xr = emacs_MarkPointer;
4783
    }
4784
 
4785
    EMACS_GotoColumn (xr);
4786
    EMACS_StackText (emacs_CurrentPosition, rsize);
4787
    EMACS_DeleteString (rsize);
4788
    emacs_MarkPointer = xr;
4789
    return EMACS_KEY_NORMAL;
4790
}
4791
 
4792
/*
4793
 * Exchange the current cursor position and the mark
4794
 */
4795
 
4796
static int F_LOCAL EMACS_ExchangeCurrentAndMark (int c)
4797
{
4798
    char	*tmp;
4799
 
4800
    if (emacs_MarkPointer == (char *)NULL)
4801
	return EMACS_Error (c);
4802
 
4803
    tmp = emacs_MarkPointer;
4804
    emacs_MarkPointer = emacs_CurrentPosition;
4805
    return EMACS_GotoColumn (tmp);
4806
}
4807
 
4808
/*
4809
 * No operation!
4810
 */
4811
 
4812
static int F_LOCAL EMACS_NoOp (int c)
4813
{
4814
    return EMACS_KEY_NOOP;
4815
}
4816
 
4817
/*
4818
 * File/command name completion routines
4819
 *
4820
 * Save the full file name in a list
4821
 */
4822
 
4823
static void F_LOCAL EMACS_SaveFileName (char *dirnam, char *name)
4824
{
4825
    char	*cp;
4826
    int		type = 0;		/* '*' if executable,		*/
4827
    					/* '/' if directory,		*/
4828
					/* else 0			*/
4829
    int		len = strlen (name);
4830
 
4831
    /* determine file type */
4832
 
4833
    if (dirnam != (char *)NULL)
4834
    {
4835
	struct stat	statb;
4836
	char		*buf = GetAllocatedSpace ((size_t)(strlen (dirnam) +
4837
							   len + 2));
4838
 
4839
	if (strcmp (dirnam, CurrentDirLiteral) == 0)
4840
	    *buf = 0;
4841
 
4842
	else if (strcmp (dirnam, DirectorySeparator) == 0)
4843
	    strcpy (buf, DirectorySeparator);
4844
 
4845
	else
4846
	    strcat (strcpy (buf, dirnam), DirectorySeparator);
4847
 
4848
	strcat (buf, name);
4849
 
4850
	if (S_stat (buf, &statb))
4851
	{
4852
	    if (S_ISDIR (statb.st_mode))
4853
		type = CHAR_UNIX_DIRECTORY;
4854
 
4855
	    else if (S_ISREG (statb.st_mode) && (statb.st_mode & S_IEXEC) != 0)
4856
		type = '*';
4857
	}
4858
 
4859
	if (type)
4860
	    ++len;
4861
 
4862
	ReleaseMemoryCell ((void *)buf);
4863
    }
4864
 
4865
    if (len > emacs_MaxFilenameSize)
4866
	emacs_MaxFilenameSize = len;
4867
 
4868
/* stash name for later sorting */
4869
 
4870
    cp = strcpy (GetAllocatedSpace ((size_t)(len + 1)), name);
4871
 
4872
/* append file type indicator */
4873
 
4874
    if (dirnam && type)
4875
    {
4876
	cp[len - 1] = (char)type;
4877
	cp[len] = 0;
4878
    }
4879
 
4880
    EMACS_Flist = AddWordToBlock (cp, EMACS_Flist);
4881
}
4882
 
4883
/*
4884
 * List saved filenames
4885
 */
4886
 
4887
static void F_LOCAL EMACS_ListSavedFileNames (void)
4888
{
4889
    int		items;
4890
    char	**array;
4891
 
4892
    if ((array = GetWordList (AddWordToBlock (NOWORD, EMACS_Flist)))
4893
	       == (char **)NULL)
4894
	return;
4895
 
4896
    if ((items = CountNumberArguments (array)) > 1)
4897
	qsort (array, items, sizeof (char *), SortCompare);
4898
 
4899
    feputc (CHAR_NEW_LINE);
4900
    PrintAList (items, array);
4901
    ReleaseAList (array);
4902
    FlushStreams ();
4903
 
4904
    GEN_Redraw (-1);
4905
}
4906
 
4907
/*
4908
 * Display job list - only available for OS/2
4909
 */
4910
 
4911
#  if (OS_TYPE != OS_DOS) 
4912
static int F_LOCAL EMACS_DisplayJobList (int c)
4913
{
4914
    fputchar (CHAR_NEW_LINE);
4915
#    if (OS_TYPE == OS_NT)
4916
    PrintJobs (TRUE);
4917
#    else
4918
    PrintProcessTree (getpid ());
4919
#    endif
4920
    GEN_Redraw (-1);
4921
    return EMACS_KEY_NORMAL;
4922
}
4923
#  endif
4924
 
4925
 
4926
/*
4927
 * File name completion functions
4928
 *
4929
 * Prints a sorted, columnated list of file names (if any) that can complete
4930
 * the partial word containing the cursor.  Directory names have / postpended
4931
 * to them, and executable file names are followed by *.
4932
 */
4933
 
4934
static int F_LOCAL EMACS_ListFiles (int c)
4935
{
4936
    return EMACS_FileCompletion (EMACS_FN_LIST);
4937
}
4938
 
4939
/* File-name completion.  Replaces the current word with the longest common
4940
 * prefix of all file names that match the current word with an asterisk
4941
 * appended.  If the match is unique, a \fB/\fR (slash) is appended if the
4942
 * file is a directory and a space is appended if the file is not a directory.
4943
 */
4944
 
4945
static int F_LOCAL EMACS_CompleteFile (int c)
4946
{
4947
    return EMACS_FileCompletion (EMACS_FN_COMPLETE);
4948
}
4949
 
4950
/*
4951
 * Attempts file name substitution on the current word.  An asterisk is
4952
 * appended if the word doesn't match any file or contain any special pattern
4953
 * characters.
4954
 */
4955
 
4956
static int F_LOCAL EMACS_SubstituteFiles (int c)
4957
{
4958
    return EMACS_FileCompletion (EMACS_FN_SUBSTITUTE);
4959
}
4960
 
4961
static int F_LOCAL EMACS_FileCompletion (int type)
4962
{
4963
    char		buf [FFNAME_MAX];
4964
    char		bug [FFNAME_MAX];
4965
    char		*cp = buf;
4966
    char		*xp = emacs_CurrentPosition;
4967
    char		*lastp;
4968
    char		*dirnam;
4969
    DIR			*dirp;
4970
    struct dirent	*dp;
4971
    long		loc = -1;
4972
    int			len;
4973
    int			multi = 0;
4974
#  if (OS_TYPE == OS_UNIX)
4975
    int			(*Compare)(const char *,
4976
    				   const char *, size_t) = strncmp;
4977
#  elif defined(_MSC_VER)
4978
    int                 (__cdecl *Compare)(const char *,
4979
    				   const char *, size_t) = strnicmp;
4980
#  else
4981
    int			(*Compare)(const char *,
4982
    				   const char *, size_t) = strnicmp;
4983
#  endif
4984
 
4985
    /*
4986
     * type ==
4987
     *		0 for list
4988
     *		1 for complete
4989
     *		2 for complete-list
4990
     */
4991
 
4992
    while (xp != ConsoleLineBuffer)
4993
    {
4994
	--xp;
4995
 
4996
	if (isspace (*xp))
4997
	{
4998
	    xp++;
4999
	    break;
5000
	}
5001
    }
5002
 
5003
    if (IS_Numeric ((int)*xp) && ((xp[1] == '<') || (xp[1] == '>')))
5004
	xp++;
5005
 
5006
    while ((*xp == '<') || (*xp == '>'))
5007
	xp++;
5008
 
5009
    if (type != EMACS_FN_LIST)		/* for complete */
5010
    {
5011
	while (*emacs_CurrentPosition && !isspace (*emacs_CurrentPosition))
5012
	    GEN_OutputCharacterWithControl (*(emacs_CurrentPosition++));
5013
    }
5014
 
5015
    if (type != EMACS_FN_COMPLETE)			/* for list */
5016
    {
5017
	emacs_MaxFilenameSize = 0;
5018
	EMACS_Flist = (Word_B *)NULL;
5019
    }
5020
 
5021
    while (*xp && !isspace (*xp))
5022
	*(cp++) = *(xp++);
5023
 
5024
    *cp = 0;
5025
    strcpy (buf, cp = substitute (buf, EXPAND_TILDE));
5026
    ReleaseMemoryCell (cp);
5027
 
5028
    if ((lastp = FindLastPathCharacter (buf)) != (char *)NULL)
5029
	*lastp = 0;
5030
 
5031
    dirnam = (lastp == (char *)NULL) ? CurrentDirLiteral
5032
				     : (lastp == buf) ? DirectorySeparator
5033
						      : buf;
5034
    if ((dirp = opendir (dirnam)) == (DIR *)NULL)
5035
	return EMACS_Error (0);
5036
 
5037
    if (IsHPFSFileSystem (dirnam) && (!(ShellGlobalFlags & FLAGS_NOCASE)))
5038
	Compare = strncmp;
5039
 
5040
    if (lastp == (char *)NULL)
5041
	lastp = buf;
5042
 
5043
    else
5044
	lastp++;
5045
 
5046
    len = strlen (lastp);
5047
 
5048
    while ((dp = readdir (dirp)) != (struct dirent *)NULL)
5049
    {
5050
	cp = dp->d_name;
5051
 
5052
/* always ignore . and .. */
5053
 
5054
	if ((cp[0] == CHAR_PERIOD) &&
5055
	    ((cp[1] == 0)  || ((cp[1] == CHAR_PERIOD) && (cp[2] == 0))))
5056
	    continue;
5057
 
5058
	if ((*Compare) (lastp, cp, len) == 0)
5059
	{
5060
 
5061
/* Complete ? */
5062
 
5063
	    if (type != EMACS_FN_LIST)
5064
	    {
5065
		if (loc == -1)
5066
		{
5067
		    (void)strcpy (bug, cp);
5068
		    loc = strlen (cp);
5069
		}
5070
 
5071
		else
5072
		{
5073
		    multi = 1;
5074
		    loc = EMACS_FindLongestMatch (bug, cp);
5075
		    bug[loc] = 0;
5076
		}
5077
	    }
5078
 
5079
/* List? */
5080
 
5081
	    if (type != EMACS_FN_COMPLETE)
5082
		EMACS_SaveFileName (dirnam, cp);
5083
	}
5084
    }
5085
 
5086
/* Close up the directory */
5087
 
5088
    closedir (dirp);
5089
 
5090
/* Complete ? */
5091
 
5092
    if (type != EMACS_FN_LIST)
5093
    {
5094
	if ((loc < 0) || ((loc == 0) && (type != EMACS_FN_SUBSTITUTE)) ||
5095
	    (strlen (cp = bug + len) == 0))
5096
	    return EMACS_Error (0);
5097
 
5098
	EMACS_InsertString (cp);
5099
 
5100
	if (!multi)
5101
	{
5102
	    if (lastp == buf)
5103
		buf[0] = 0;
5104
 
5105
	    else if (lastp == buf + 1)
5106
	    {
5107
		buf[1] = 0;
5108
		buf[0] = CHAR_UNIX_DIRECTORY;
5109
	    }
5110
 
5111
	    else
5112
		strcat (buf, DirectorySeparator);
5113
 
5114
	    strcat (buf, bug);
5115
 
5116
	    if (IsDirectory (buf))
5117
		EMACS_InsertString (DirectorySeparator);
5118
 
5119
	    else
5120
		EMACS_InsertString (" ");
5121
	}
5122
    }
5123
 
5124
/* List or complete-list and ambiguous */
5125
 
5126
    if ((type == EMACS_FN_LIST) || ((type == EMACS_FN_SUBSTITUTE) && multi))
5127
	EMACS_ListSavedFileNames ();
5128
 
5129
    return EMACS_KEY_NORMAL;
5130
}
5131
 
5132
/*
5133
 * Find longest match in two strings
5134
 */
5135
 
5136
static int F_LOCAL EMACS_FindLongestMatch (char *s1, char *s2)
5137
{
5138
    char	*p = s1;
5139
 
5140
    while ((*p == *(s2++)) && *p)
5141
	p++;
5142
 
5143
    return p - s1;
5144
}
5145
 
5146
/*
5147
 * EMACS_SetArgValue - set an arg value for next function.
5148
 *
5149
 * Defines the numeric parameter.  The digits are taken as a parameter to
5150
 * the next command.  The commands that accept a parameter are forward-char,
5151
 * backward-char, backward-word, forward-word, delete-word-forward,
5152
 * delete-char-forward, delete-word-backward, delete-char-backward,
5153
 * prev-hist-word, copy-last-arg, up-history, down-history, search-history,
5154
 * upcase-word, downcase-word, capitalise-word, upcase-char, downcase-char,
5155
 * capitalise-char, kill-to-eol, search-char-forward and search-char-backward.
5156
 */
5157
 
5158
static int F_LOCAL EMACS_SetArgValue (int c)
5159
{
5160
    emacs_ArgumentCount = 0;
5161
 
5162
/* Read all digits */
5163
 
5164
    while (IS_Numeric (c & 0x0ff))
5165
    {
5166
	emacs_ArgumentCount = (emacs_ArgumentCount * 10) + (c & 0x0f);
5167
	c = EMACS_GetNonFunctionKey ();
5168
    }
5169
 
5170
/* Save the bad key as the unget */
5171
 
5172
    emacs_UnGetCharacter = c & 0x0ff;
5173
    return EMACS_KEY_NORMAL;
5174
}
5175
 
5176
/*
5177
 * Multiplies the parameter of the next command by 4.
5178
 */
5179
 
5180
static int F_LOCAL EMACS_Multiply (int c)
5181
{
5182
    if (!emacs_ArgumentCount)
5183
	emacs_ArgumentCount = 1;
5184
 
5185
    emacs_ArgumentCount *= 4;
5186
    emacs_LastCommand = EMACS_SetArgValue;
5187
 
5188
/* Not really a no-op, but we don't want emacs_LastCommand reset */
5189
 
5190
    return EMACS_KEY_NOOP;
5191
}
5192
 
5193
/*
5194
 * EMACS_GetWordsFromHistory - recover word from prev command.  This
5195
 * function recovers the last word from the previous command and inserts it
5196
 * into the current edit line.  If a numeric arg is supplied then the n'th
5197
 * word from the start of the previous command is used.
5198
 */
5199
 
5200
static int F_LOCAL EMACS_GetWordsFromHistory (int c)
5201
{
5202
    char	*rcp;
5203
    char	*cp;
5204
 
5205
    if ((cp = GetHistoryRecord (CurrentHistoryEvent - 1)) == (char *)NULL)
5206
	return EMACS_Error (0);
5207
 
5208
    if (emacs_LastCommand != EMACS_SetArgValue)
5209
    {
5210
	rcp = &cp[strlen(cp) - 1];
5211
 
5212
/* ignore white-space after the last word */
5213
 
5214
	while (rcp > cp && isspace (*rcp))
5215
	    rcp--;
5216
 
5217
	while (rcp > cp && !isspace (*rcp))
5218
	    rcp--;
5219
 
5220
	if (isspace (*rcp))
5221
	    rcp++;
5222
 
5223
	EMACS_InsertString (rcp);
5224
    }
5225
 
5226
    else
5227
    {
5228
	int c;
5229
 
5230
	rcp = cp;
5231
 
5232
/* ignore white-space at start of line */
5233
 
5234
	while (*rcp && isspace (*rcp))
5235
	    rcp++;
5236
 
5237
	while (emacs_ArgumentCount-- > 1)
5238
	{
5239
	    while (*rcp && !isspace (*rcp))
5240
		rcp++;
5241
 
5242
	    while (*rcp && isspace (*rcp))
5243
		rcp++;
5244
	}
5245
 
5246
	cp = rcp;
5247
 
5248
	while (*rcp && !isspace (*rcp))
5249
	    rcp++;
5250
 
5251
	c = *rcp;
5252
	*rcp = 0;
5253
	EMACS_InsertString (cp);
5254
	*rcp = (char)c;
5255
    }
5256
 
5257
    emacs_ArgumentCount = 0;
5258
    return EMACS_KEY_NORMAL;
5259
}
5260
 
5261
/*
5262
 * Inserts a # (pound sign) at the beginning of the line and then execute
5263
 * the line.  This causes a comment to be inserted in the history file.
5264
 */
5265
 
5266
static int F_LOCAL EMACS_Comment (int c)
5267
{
5268
    EMACS_GotoColumn (ConsoleLineBuffer);
5269
    EMACS_InsertString ("#");
5270
    return EMACS_NewLine (c);
5271
}
5272
 
5273
/*
5274
 * Search the alias list for an alias named \fI_Letter\fR.  If an alias of
5275
 * this name is defined, its value is placed into the input queue.
5276
 */
5277
 
5278
static int F_LOCAL	EMACS_AliasInsert (int c)
5279
{
5280
    char	*p = (char *)NULL;
5281
 
5282
/* Ctrl-] as the char means get the next character */
5283
 
5284
    if ((c & 0x0ff) == (']' & 0x1f))
5285
	c = EMACS_GetNonFunctionKey ();
5286
 
5287
    if (isalpha (c & 0x0ff))
5288
	p = GEN_FindAliasMatch (c & 0x0ff);
5289
 
5290
    if (p != (char *)NULL)
5291
	emacs_CurrentMacroString = p;
5292
 
5293
    else
5294
	EMACS_Error (0);
5295
 
5296
    return EMACS_KEY_NORMAL;
5297
}
5298
 
5299
/*
5300
 * EMACS_FoldCase - convert word to UPPER/lower case.  This function is used
5301
 * to implement M-u,M-l and M-c to upper case, lower case or Capitalize
5302
 * words.
5303
 */
5304
 
5305
static int F_LOCAL EMACS_FoldCase (int c)
5306
{
5307
    register char	*cp = emacs_CurrentPosition;
5308
 
5309
    if (cp == emacs_EndOfLine)
5310
    {
5311
	RingWarningBell ();
5312
	return 0;
5313
    }
5314
 
5315
    if (emacs_LastCommand != EMACS_SetArgValue)
5316
	emacs_ArgumentCount = 1;
5317
 
5318
/* Remove pre-fix */
5319
 
5320
    c &= 0x0ff;
5321
 
5322
/* Process! */
5323
 
5324
    while (emacs_ArgumentCount--)
5325
    {
5326
 
5327
/* First skip over any white-space */
5328
 
5329
	if (isupper (c))
5330
	{
5331
	    while ((cp != emacs_EndOfLine) && EMACS_IS_SPACE (*cp))
5332
	      cp++;
5333
	}
5334
 
5335
/*
5336
 * Do the first char on its own since it may be a different action than for
5337
 * the rest.
5338
 */
5339
 
5340
	if (cp != emacs_EndOfLine)
5341
	{
5342
	    if (c == 'L')			/* M-l */
5343
	    {
5344
		if (isupper (*cp))
5345
		    *cp = (char)tolower (*cp);
5346
	    }
5347
 
5348
/* M-u or M-c */
5349
 
5350
	    else if (islower (*cp))
5351
		*cp = (char)toupper (*cp);
5352
 
5353
	    cp++;
5354
	}
5355
 
5356
/* If command was in lower case, only the current character */
5357
 
5358
	if (islower (c))
5359
	    continue;
5360
 
5361
/* now for the rest of the word */
5362
 
5363
	while ((cp != emacs_EndOfLine) && !EMACS_IS_SPACE (*cp))
5364
	{
5365
	    if (c == 'U')			/* M-u */
5366
	    {
5367
		if (islower (*cp))
5368
		    *cp = (char)toupper (*cp);
5369
	    }
5370
 
5371
/* M-l or M-c */
5372
 
5373
	    else if (isupper (*cp))
5374
		*cp = (char)tolower (*cp);
5375
 
5376
	    cp++;
5377
	}
5378
    }
5379
 
5380
    EMACS_GotoColumn (cp);
5381
    return 0;
5382
}
5383
 
5384
/*
5385
 * Check argument count value
5386
 */
5387
 
5388
static void F_LOCAL	EMACS_CheckArgCount (void)
5389
{
5390
    if ((emacs_LastCommand != EMACS_SetArgValue) ||
5391
	(!emacs_ArgumentCount))
5392
	emacs_ArgumentCount = 1;
5393
}
5394
#endif
5395
 
5396
/*
5397
 * GENERAL APIs
5398
 */
5399
 
5400
#if defined (FLAGS_EMACS) || defined (FLAGS_VI) || defined (FLAGS_GMACS)
5401
 
5402
/*
5403
 * Redraw the window
5404
 */
5405
 
5406
static void F_LOCAL GEN_Redraw (int limit)
5407
{
5408
    int		i, j;
5409
    char	*cp;
5410
 
5411
    AdjustOK = FALSE;
5412
 
5413
    if (limit == -1)
5414
	GEN_PutACharacter (CHAR_NEW_LINE);
5415
 
5416
    else
5417
	GEN_PutACharacter (CHAR_RETURN);
5418
 
5419
    FlushStreams ();
5420
 
5421
    if (emacs_StartVisible == ConsoleLineBuffer)
5422
    {
5423
	OutputUserPrompt (LastUserPrompt);
5424
	CurrentScreenColumn = ReadCursorPosition () % MaximumColumns;
5425
    }
5426
 
5427
    DisplayWidth = MaximumColumns - 2 - CurrentScreenColumn;
5428
    LastVisibleCharValid = FALSE;
5429
 
5430
    cp = GEN_FindLastVisibleCharacter ();
5431
 
5432
    GEN_AdjustOutputString (emacs_StartVisible);
5433
 
5434
    if ((emacs_StartVisible != ConsoleLineBuffer) ||
5435
	(emacs_EndOfLine > emacs_LastVisibleCharacter))
5436
	limit = MaximumColumns;
5437
 
5438
    if (limit >= 0)
5439
    {
5440
	if (emacs_EndOfLine > emacs_LastVisibleCharacter)
5441
	    i = 0;			/* we fill the line */
5442
 
5443
	else
5444
	    i = limit - (emacs_LastVisibleCharacter - emacs_StartVisible);
5445
 
5446
	for (j = 0; j < i && CurrentScreenColumn < (MaximumColumns - 2); j++)
5447
	    GEN_PutACharacter (CHAR_SPACE);
5448
 
5449
	i = CHAR_SPACE;
5450
 
5451
/* more off screen ? */
5452
 
5453
	if (emacs_EndOfLine > emacs_LastVisibleCharacter)
5454
	{
5455
	    if (emacs_StartVisible > ConsoleLineBuffer)
5456
		i = '*';
5457
 
5458
	    else
5459
		i = '>';
5460
	}
5461
 
5462
	else if (emacs_StartVisible > ConsoleLineBuffer)
5463
	    i = '<';
5464
 
5465
	GEN_PutACharacter (i);
5466
	j++;
5467
 
5468
	while (j--)
5469
	    GEN_PutACharacter (CHAR_BACKSPACE);
5470
    }
5471
 
5472
    for (cp = emacs_LastVisibleCharacter; cp > emacs_CurrentPosition; )
5473
	GEN_BackspaceOver (*--cp);
5474
 
5475
    AdjustOK = TRUE;
5476
}
5477
 
5478
/*
5479
 * GEN_FindLastVisibleCharacter - last visible char.  This function returns
5480
 * a pointer to that char in the edit buffer that will be the last displayed
5481
 * on the screen.  The sequence:
5482
 *
5483
 *      for (cp = GEN_FindLastVisibleCharacter (); cp > emacs_CurrentPosition;
5484
 *	     cp)
5485
 *        GEN_BackspaceOver (*--cp);
5486
 *
5487
 * Will position the cursor correctly on the screen.
5488
 *
5489
 */
5490
 
5491
static char * F_LOCAL GEN_FindLastVisibleCharacter (void)
5492
{
5493
    register char	*rcp;
5494
    register int	i = 0;
5495
 
5496
    if (!LastVisibleCharValid)
5497
    {
5498
	for (rcp = emacs_StartVisible;
5499
	     (rcp < emacs_EndOfLine) && (i < DisplayWidth); rcp++)
5500
	    i += GEN_GetCharacterSize (*rcp);
5501
 
5502
	emacs_LastVisibleCharacter = rcp;
5503
    }
5504
 
5505
    LastVisibleCharValid = TRUE;
5506
    return (emacs_LastVisibleCharacter);
5507
}
5508
 
5509
/*
5510
 * Output character string
5511
 */
5512
 
5513
static void F_LOCAL GEN_AdjustOutputString (char *str)
5514
{
5515
    int		adj = AdjustDone;
5516
 
5517
    GEN_FindLastVisibleCharacter ();
5518
 
5519
    while (*str && (str < emacs_LastVisibleCharacter) && (adj == AdjustDone))
5520
	GEN_OutputCharacterWithControl (*(str++));
5521
}
5522
 
5523
/*
5524
 * Output character, accounting for control chars
5525
 */
5526
 
5527
static void F_LOCAL GEN_OutputCharacterWithControl (int c)
5528
{
5529
#ifdef EMACS_TABS
5530
    if (c == CHAR_TAB)
5531
	GEN_PutAString ("    ");
5532
 
5533
    else
5534
#endif
5535
 
5536
    if ((c < CHAR_SPACE) || (c == 0x7F))
5537
    {
5538
	GEN_PutACharacter (CHAR_XOR);
5539
	c += '@';
5540
    }
5541
 
5542
    GEN_PutACharacter (c);
5543
}
5544
 
5545
/*
5546
 * Backspace over a character
5547
 */
5548
 
5549
static void F_LOCAL GEN_BackspaceOver (int c)
5550
{
5551
    int		 i = GEN_GetCharacterSize (c);
5552
 
5553
    while (i--)
5554
	GEN_PutACharacter (CHAR_BACKSPACE);
5555
}
5556
 
5557
/*
5558
 * Get number of position on screen a character takes up
5559
 */
5560
 
5561
static int F_LOCAL GEN_GetCharacterSize (int c)
5562
{
5563
#ifdef EMACS_TABS
5564
    if (c == CHAR_TAB)
5565
	return 4;	/* Kludge, tabs are always four spaces. */
5566
#endif
5567
 
5568
    return ((c < CHAR_SPACE) || (c == 0x7F)) ? 2 : 1;
5569
}
5570
 
5571
/*
5572
 * Output a string
5573
 */
5574
 
5575
static void F_LOCAL GEN_PutAString (char *s)
5576
{
5577
    register int	adj = AdjustDone;
5578
 
5579
    while (*s && (adj == AdjustDone))
5580
	GEN_PutACharacter (*(s++));
5581
}
5582
 
5583
/*
5584
 * Output a character
5585
 */
5586
 
5587
static void F_LOCAL GEN_PutACharacter (int c)
5588
{
5589
    if ((c == CHAR_RETURN) || (c == CHAR_NEW_LINE))
5590
	CurrentScreenColumn = 0;
5591
 
5592
    if (CurrentScreenColumn < MaximumColumns)
5593
    {
5594
	fputchar (c);
5595
 
5596
	switch (c)
5597
	{
5598
	    case CHAR_RETURN:
5599
	    case CHAR_NEW_LINE:
5600
		break;
5601
 
5602
	    case CHAR_BACKSPACE:
5603
		CurrentScreenColumn--;
5604
		break;
5605
 
5606
	    default:
5607
		CurrentScreenColumn++;
5608
		break;
5609
	}
5610
    }
5611
 
5612
    if (AdjustOK &&
5613
	((CurrentScreenColumn < 0) ||
5614
	 (CurrentScreenColumn >= (MaximumColumns - 2))))
5615
	GEN_AdjustRedraw ();
5616
}
5617
 
5618
/*
5619
 * GEN_AdjustRedraw - redraw the line adjusting starting point etc.
5620
 *
5621
 * This function is called when we have exceeded the bounds of the edit
5622
 * window.  It increments AdjustDone so that functions like EMACS_InsertString
5623
 * and EMACS_DeleteString know that we have been called and can skip the
5624
 * GEN_BackspaceOver () stuff which has already been done by GEN_Redraw.
5625
 */
5626
 
5627
static void F_LOCAL GEN_AdjustRedraw (void)
5628
{
5629
    AdjustDone++;		/* flag the fact that we were called. */
5630
 
5631
/* we had a problem if the prompt length > MaximumColumns / 2 */
5632
 
5633
    if ((emacs_StartVisible = emacs_CurrentPosition - (DisplayWidth / 2))
5634
			    < ConsoleLineBuffer)
5635
	emacs_StartVisible = ConsoleLineBuffer;
5636
 
5637
    LastVisibleCharValid = FALSE;
5638
    GEN_Redraw (MaximumColumns);
5639
    FlushStreams ();
5640
}
5641
 
5642
/*
5643
 * General Alias Search function
5644
 */
5645
 
5646
static char * F_LOCAL GEN_FindAliasMatch (int c)
5647
{
5648
    char	RAlias[3];
5649
    AliasList	*p;
5650
 
5651
    RAlias[0] = '_';
5652
    RAlias[1] = (char)c;
5653
    RAlias[2] = 0;
5654
 
5655
    if (((p = LookUpAlias (RAlias, FALSE)) == (AliasList *)NULL) ||
5656
	(p->value == null))
5657
	return (char *)NULL;
5658
 
5659
/* Alias Found */
5660
 
5661
    return p->value;
5662
}
5663
#endif