w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

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