blob: 9acc704c97d94b5cfa2c6ef7887d5933b4c5aa11 [file] [log] [blame]
Alexandre Julliard18f92e71996-07-17 20:02:21 +00001/*
2 * Line-editing routines
3 *
4 * Copyright 1992 Simmule Turner and Rich Salz. All rights reserved.
5 *
6 *
7 * This software is not subject to any license of the American Telephone
8 * and Telegraph Company or of the Regents of the University of California.
9 *
10 * Permission is granted to anyone to use this software for any purpose on
11 * any computer system, and to alter it and redistribute it freely, subject
12 * to the following restrictions:
13 * 1. The authors are not responsible for the consequences of use of this
14 * software, no matter how awful, even if they arise from flaws in it.
15 * 2. The origin of this software must not be misrepresented, either by
16 * explicit claim or by omission. Since few users ever read sources,
17 * credits must appear in the documentation.
18 * 3. Altered versions must be plainly marked as such, and must not be
19 * misrepresented as being the original software. Since few users
20 * ever read sources, credits must appear in the documentation.
21 * 4. This notice may not be removed or altered.
22 *
23 * The code was heavily simplified for inclusion in Wine. -- AJ
24 */
25
26#include "config.h"
Alexandre Julliardf0b23541993-09-29 12:21:49 +000027#include <ctype.h>
Alexandre Julliard18f92e71996-07-17 20:02:21 +000028#include <stdio.h>
Alexandre Julliardecc37121994-11-22 16:31:29 +000029#include <stdlib.h>
Alexandre Julliard18f92e71996-07-17 20:02:21 +000030#include <string.h>
Alexandre Julliard18f92e71996-07-17 20:02:21 +000031
Jim Aston2e1cafa1999-03-14 16:35:05 +000032#include "windef.h"
Ove Kaavendda17c61999-04-25 12:24:42 +000033#include "debugger.h"
Alexandre Julliardf0b23541993-09-29 12:21:49 +000034
35/*
36** Manifest constants.
37*/
38#define SCREEN_WIDTH 80
39#define SCREEN_ROWS 24
40#define NO_ARG (-1)
41#define DEL 127
42#define CTL(x) ((x) & 0x1F)
43#define ISCTL(x) ((x) && (x) < ' ')
44#define UNCTL(x) ((x) + 64)
45#define META(x) ((x) | 0x80)
46#define ISMETA(x) ((x) & 0x80)
47#define UNMETA(x) ((x) & 0x7F)
48#if !defined(HIST_SIZE)
49#define HIST_SIZE 20
50#endif /* !defined(HIST_SIZE) */
Alexandre Julliard18f92e71996-07-17 20:02:21 +000051#define CRLF "\r\n"
52#define MEM_INC 64
53#define SCREEN_INC 256
54
Ove Kaavendda17c61999-04-25 12:24:42 +000055#define DISPOSE(p) DBG_free((char *)(p))
Alexandre Julliard18f92e71996-07-17 20:02:21 +000056#define NEW(T, c) \
Ove Kaavendda17c61999-04-25 12:24:42 +000057 ((T *)DBG_alloc((unsigned int)(sizeof (T) * (c))))
Alexandre Julliard18f92e71996-07-17 20:02:21 +000058#define RENEW(p, T, c) \
Ove Kaavendda17c61999-04-25 12:24:42 +000059 (p = (T *)DBG_realloc((char *)(p), (unsigned int)(sizeof (T) * (c))))
Alexandre Julliard18f92e71996-07-17 20:02:21 +000060#define COPYFROMTO(new, p, len) \
61 (void)memcpy((char *)(new), (char *)(p), (int)(len))
Alexandre Julliardf0b23541993-09-29 12:21:49 +000062
63/*
64** Command status codes.
65*/
66typedef enum _STATUS {
67 CSdone, CSeof, CSmove, CSdispatch, CSstay
68} STATUS;
69
70/*
71** The type of case-changing to perform.
72*/
73typedef enum _CASE {
74 TOupper, TOlower
75} CASE;
76
77/*
78** Key to command mapping.
79*/
80typedef struct _KEYMAP {
81 CHAR Key;
82 STATUS (*Function)();
83} KEYMAP;
84
85/*
86** Command history structure.
87*/
88typedef struct _HISTORY {
89 int Size;
90 int Pos;
91 CHAR *Lines[HIST_SIZE];
92} HISTORY;
93
94/*
95** Globals.
96*/
Alexandre Julliard18f92e71996-07-17 20:02:21 +000097static int rl_eof;
98static int rl_erase;
99static int rl_intr;
100static int rl_kill;
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000101
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000102static CHAR NIL[] = "";
103static const CHAR *Input = NIL;
104static CHAR *Line;
105static const char *Prompt;
106static CHAR *Yanked;
107static char *Screen;
108static char NEWLINE[]= CRLF;
109static HISTORY H;
110static int rl_quit;
111static int Repeat;
112static int End;
113static int Mark;
114static int OldPoint;
115static int Point;
116static int PushBack;
117static int Pushed;
118static KEYMAP Map[33];
119static KEYMAP MetaMap[16];
120static size_t Length;
121static size_t ScreenCount;
122static size_t ScreenSize;
123static char *backspace;
124static int TTYwidth;
125static int TTYrows;
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000126
127/* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */
128int rl_meta_chars = 1;
129
130/*
131** Declarations.
132*/
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000133static CHAR *editinput();
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000134
135/*
136** TTY input/output functions.
137*/
138
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000139static void
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000140rl_ttyset(int Reset)
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000141{
Eric Pouech04c16b82000-04-30 12:21:15 +0000142 static DWORD old_mode;
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000143
Eric Pouech04c16b82000-04-30 12:21:15 +0000144 if (Reset == 0) {
145 GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &old_mode);
146 SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), 0 /*ENABLE_PROCESSED_INPUT|ENABLE_WINDOW_INPUT|ENABLE_MOUSE_INPUT*/);
147 } else {
148 SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), old_mode);
149 }
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000150}
151
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000152static void
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000153TTYflush(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000154{
155 if (ScreenCount) {
Eric Pouech04c16b82000-04-30 12:21:15 +0000156 DEBUG_Output(DBG_CHN_MESG, Screen, ScreenCount);
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000157 ScreenCount = 0;
158 }
159}
160
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000161static void
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000162TTYput(CHAR c)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000163{
164 Screen[ScreenCount] = c;
165 if (++ScreenCount >= ScreenSize - 1) {
166 ScreenSize += SCREEN_INC;
167 RENEW(Screen, char, ScreenSize);
168 }
169}
170
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000171static void
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000172TTYputs(CHAR *p)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000173{
174 while (*p)
175 TTYput(*p++);
176}
177
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000178static void
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000179TTYshow(CHAR c)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000180{
181 if (c == DEL) {
182 TTYput('^');
183 TTYput('?');
184 }
185 else if (ISCTL(c)) {
186 TTYput('^');
187 TTYput(UNCTL(c));
188 }
189 else if (rl_meta_chars && ISMETA(c)) {
190 TTYput('M');
191 TTYput('-');
192 TTYput(UNMETA(c));
193 }
194 else
195 TTYput(c);
196}
197
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000198static void
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000199TTYstring(CHAR *p)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000200{
201 while (*p)
202 TTYshow(*p++);
203}
204
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000205static unsigned int
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000206TTYget(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000207{
208 CHAR c;
Eric Pouech04c16b82000-04-30 12:21:15 +0000209 DWORD retv;
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000210
211 TTYflush();
212 if (Pushed) {
213 Pushed = 0;
214 return PushBack;
215 }
216 if (*Input)
217 return *Input++;
Alexandre Julliard638f1691999-01-17 16:32:32 +0000218
Eric Pouech04c16b82000-04-30 12:21:15 +0000219 for (;;) {
220 /* data available ? */
221 if (ReadConsole(GetStdHandle(STD_INPUT_HANDLE), &c, 1, &retv, NULL) &&
222 retv == 1)
223 return c;
224 switch (WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), INFINITE)) {
225 case WAIT_OBJECT_0:
226 break;
227 default:
228 DEBUG_Printf(DBG_CHN_FIXME, "shouldn't happen\n");
229 /* fall thru */
230 case WAIT_ABANDONED:
231 case WAIT_TIMEOUT:
232 return EOF;
233 }
Alexandre Julliard638f1691999-01-17 16:32:32 +0000234 }
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000235}
236
237#define TTYback() (backspace ? TTYputs((CHAR *)backspace) : TTYput('\b'))
238
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000239static void
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000240TTYbackn(int n)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000241{
242 while (--n >= 0)
243 TTYback();
244}
245
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000246static void
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000247TTYinfo(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000248{
Eric Pouech04c16b82000-04-30 12:21:15 +0000249 COORD c = GetLargestConsoleWindowSize(GetStdHandle(STD_INPUT_HANDLE));
250 TTYwidth = c.x;
251 TTYrows = c.y;
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000252}
253
254
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000255
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000256static void
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000257reposition(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000258{
259 int i;
260 CHAR *p;
261
262 TTYput('\r');
263 TTYputs((CHAR *)Prompt);
264 for (i = Point, p = Line; --i >= 0; p++)
265 TTYshow(*p);
266}
267
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000268static void
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000269left(STATUS Change)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000270{
271 TTYback();
272 if (Point) {
273 if (ISCTL(Line[Point - 1]))
274 TTYback();
275 else if (rl_meta_chars && ISMETA(Line[Point - 1])) {
276 TTYback();
277 TTYback();
278 }
279 }
280 if (Change == CSmove)
281 Point--;
282}
283
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000284static void
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000285right(STATUS Change)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000286{
287 TTYshow(Line[Point]);
288 if (Change == CSmove)
289 Point++;
290}
291
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000292static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000293ring_bell(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000294{
295 TTYput('\07');
296 TTYflush();
297 return CSstay;
298}
299
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000300static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000301do_macro(unsigned int c)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000302{
303 CHAR name[4];
304
305 name[0] = '_';
306 name[1] = c;
307 name[2] = '_';
308 name[3] = '\0';
309
310 if ((Input = (CHAR *)getenv((char *)name)) == NULL) {
311 Input = NIL;
312 return ring_bell();
313 }
314 return CSstay;
315}
316
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000317static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000318do_forward(STATUS move)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000319{
320 int i;
321 CHAR *p;
322
323 i = 0;
324 do {
325 p = &Line[Point];
326 for ( ; Point < End && (*p == ' ' || !isalnum(*p)); Point++, p++)
327 if (move == CSmove)
328 right(CSstay);
329
330 for (; Point < End && isalnum(*p); Point++, p++)
331 if (move == CSmove)
332 right(CSstay);
333
334 if (Point == End)
335 break;
336 } while (++i < Repeat);
337
338 return CSstay;
339}
340
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000341static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000342do_case(CASE type)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000343{
344 int i;
345 int end;
346 int count;
347 CHAR *p;
348
349 (void)do_forward(CSstay);
350 if (OldPoint != Point) {
351 if ((count = Point - OldPoint) < 0)
352 count = -count;
353 Point = OldPoint;
354 if ((end = Point + count) > End)
355 end = End;
356 for (i = Point, p = &Line[i]; i < end; i++, p++) {
357 if (type == TOupper) {
358 if (islower(*p))
359 *p = toupper(*p);
360 }
361 else if (isupper(*p))
362 *p = tolower(*p);
363 right(CSmove);
364 }
365 }
366 return CSstay;
367}
368
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000369static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000370case_down_word(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000371{
372 return do_case(TOlower);
373}
374
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000375static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000376case_up_word(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000377{
378 return do_case(TOupper);
379}
380
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000381static void
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000382ceol(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000383{
384 int extras;
385 int i;
386 CHAR *p;
387
388 for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) {
389 TTYput(' ');
390 if (ISCTL(*p)) {
391 TTYput(' ');
392 extras++;
393 }
394 else if (rl_meta_chars && ISMETA(*p)) {
395 TTYput(' ');
396 TTYput(' ');
397 extras += 2;
398 }
399 }
400
401 for (i += extras; i > Point; i--)
402 TTYback();
403}
404
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000405static void
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000406clear_line(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000407{
408 Point = -strlen(Prompt);
409 TTYput('\r');
410 ceol();
411 Point = 0;
412 End = 0;
413 Line[0] = '\0';
414}
415
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000416static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000417insert_string(CHAR *p)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000418{
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000419 size_t len;
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000420 int i;
421 CHAR *new;
422 CHAR *q;
423
424 len = strlen((char *)p);
425 if (End + len >= Length) {
426 if ((new = NEW(CHAR, Length + len + MEM_INC)) == NULL)
427 return CSstay;
428 if (Length) {
429 COPYFROMTO(new, Line, Length);
430 DISPOSE(Line);
431 }
432 Line = new;
433 Length += len + MEM_INC;
434 }
435
436 for (q = &Line[Point], i = End - Point; --i >= 0; )
437 q[len + i] = q[i];
438 COPYFROMTO(&Line[Point], p, len);
439 End += len;
440 Line[End] = '\0';
441 TTYstring(&Line[Point]);
442 Point += len;
443
444 return Point == End ? CSstay : CSmove;
445}
446
447
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000448static CHAR *
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000449next_hist(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000450{
451 return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];
452}
453
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000454static CHAR *
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000455prev_hist()
456{
457 return H.Pos == 0 ? NULL : H.Lines[--H.Pos];
458}
459
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000460static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000461do_insert_hist(CHAR *p)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000462{
463 if (p == NULL)
464 return ring_bell();
465 Point = 0;
466 reposition();
467 ceol();
468 End = 0;
469 return insert_string(p);
470}
471
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000472static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000473do_hist(CHAR *(*move)(void))
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000474{
475 CHAR *p;
476 int i;
477
478 i = 0;
479 do {
480 if ((p = (*move)()) == NULL)
481 return ring_bell();
482 } while (++i < Repeat);
483 return do_insert_hist(p);
484}
485
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000486static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000487h_next(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000488{
489 return do_hist(next_hist);
490}
491
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000492static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000493h_prev(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000494{
495 return do_hist(prev_hist);
496}
497
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000498static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000499h_first(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000500{
501 return do_insert_hist(H.Lines[H.Pos = 0]);
502}
503
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000504static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000505h_last(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000506{
507 return do_insert_hist(H.Lines[H.Pos = H.Size - 1]);
508}
509
510/*
511** Return zero if pat appears as a substring in text.
512*/
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000513static int
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000514substrcmp(char *text, char *pat, int len)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000515{
516 CHAR c;
517
518 if ((c = *pat) == '\0')
519 return *text == '\0';
520 for ( ; *text; text++)
Alexandre Julliard7cbe6571995-01-09 18:21:16 +0000521 if ((CHAR)*text == c && strncmp(text, pat, len) == 0)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000522 return 0;
523 return 1;
524}
525
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000526static CHAR *
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000527search_hist(CHAR *search, CHAR *(*move)(void))
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000528{
529 static CHAR *old_search;
530 int len;
531 int pos;
532 int (*match)();
533 char *pat;
534
535 /* Save or get remembered search pattern. */
536 if (search && *search) {
537 if (old_search)
538 DISPOSE(old_search);
Ove Kaavendda17c61999-04-25 12:24:42 +0000539 old_search = (CHAR *)DBG_strdup((char *)search);
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000540 }
541 else {
542 if (old_search == NULL || *old_search == '\0')
543 return NULL;
544 search = old_search;
545 }
546
547 /* Set up pattern-finder. */
548 if (*search == '^') {
549 match = strncmp;
550 pat = (char *)(search + 1);
551 }
552 else {
553 match = substrcmp;
554 pat = (char *)search;
555 }
556 len = strlen(pat);
557
558 for (pos = H.Pos; (*move)() != NULL; )
559 if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0)
560 return H.Lines[H.Pos];
561 H.Pos = pos;
562 return NULL;
563}
564
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000565static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000566h_search(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000567{
568 static int Searching;
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000569 const char *old_prompt;
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000570 CHAR *(*move)();
571 CHAR *p;
572
573 if (Searching)
574 return ring_bell();
575 Searching = 1;
576
577 clear_line();
578 old_prompt = Prompt;
579 Prompt = "Search: ";
580 TTYputs((CHAR *)Prompt);
581 move = Repeat == NO_ARG ? prev_hist : next_hist;
582 p = search_hist(editinput(), move);
583 clear_line();
584 Prompt = old_prompt;
585 TTYputs((CHAR *)Prompt);
586
587 Searching = 0;
588 return do_insert_hist(p);
589}
590
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000591static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000592fd_char(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000593{
594 int i;
595
596 i = 0;
597 do {
598 if (Point >= End)
599 break;
600 right(CSmove);
601 } while (++i < Repeat);
602 return CSstay;
603}
604
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000605static void
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000606save_yank(int begin, int i)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000607{
608 if (Yanked) {
609 DISPOSE(Yanked);
610 Yanked = NULL;
611 }
612
613 if (i < 1)
614 return;
615
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000616 if ((Yanked = NEW(CHAR, (size_t)i + 1)) != NULL) {
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000617 COPYFROMTO(Yanked, &Line[begin], i);
618 Yanked[i] = '\0';
619 }
620}
621
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000622static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000623delete_string(int count)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000624{
625 int i;
626 CHAR *p;
627
628 if (count <= 0 || End == Point)
629 return ring_bell();
630
631 if (count == 1 && Point == End - 1) {
632 /* Optimize common case of delete at end of line. */
633 End--;
634 p = &Line[Point];
635 i = 1;
636 TTYput(' ');
637 if (ISCTL(*p)) {
638 i = 2;
639 TTYput(' ');
640 }
641 else if (rl_meta_chars && ISMETA(*p)) {
642 i = 3;
643 TTYput(' ');
644 TTYput(' ');
645 }
646 TTYbackn(i);
647 *p = '\0';
648 return CSmove;
649 }
650 if (Point + count > End && (count = End - Point) <= 0)
651 return CSstay;
652
653 if (count > 1)
654 save_yank(Point, count);
655
656 for (p = &Line[Point], i = End - (Point + count) + 1; --i >= 0; p++)
657 p[0] = p[count];
658 ceol();
659 End -= count;
660 TTYstring(&Line[Point]);
661 return CSmove;
662}
663
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000664static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000665bk_char(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000666{
667 int i;
668
669 i = 0;
670 do {
671 if (Point == 0)
672 break;
673 left(CSmove);
674 } while (++i < Repeat);
675
676 return CSstay;
677}
678
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000679static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000680bk_del_char(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000681{
682 int i;
683
684 i = 0;
685 do {
686 if (Point == 0)
687 break;
688 left(CSmove);
689 } while (++i < Repeat);
690
691 return delete_string(i);
692}
693
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000694static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000695redisplay(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000696{
697 TTYputs((CHAR *)NEWLINE);
698 TTYputs((CHAR *)Prompt);
699 TTYstring(Line);
700 return CSmove;
701}
702
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000703static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000704kill_line(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000705{
706 int i;
707
708 if (Repeat != NO_ARG) {
709 if (Repeat < Point) {
710 i = Point;
711 Point = Repeat;
712 reposition();
713 (void)delete_string(i - Point);
714 }
715 else if (Repeat > Point) {
716 right(CSmove);
717 (void)delete_string(Repeat - Point - 1);
718 }
719 return CSmove;
720 }
721
722 save_yank(Point, End - Point);
723 Line[Point] = '\0';
724 ceol();
725 End = Point;
726 return CSstay;
727}
728
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000729static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000730insert_char(int c)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000731{
732 STATUS s;
733 CHAR buff[2];
734 CHAR *p;
735 CHAR *q;
736 int i;
737
738 if (Repeat == NO_ARG || Repeat < 2) {
739 buff[0] = c;
740 buff[1] = '\0';
741 return insert_string(buff);
742 }
743
744 if ((p = NEW(CHAR, Repeat + 1)) == NULL)
745 return CSstay;
746 for (i = Repeat, q = p; --i >= 0; )
747 *q++ = c;
748 *q = '\0';
749 Repeat = 0;
750 s = insert_string(p);
751 DISPOSE(p);
752 return s;
753}
754
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000755static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000756meta(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000757{
758 unsigned int c;
759 KEYMAP *kp;
760
761 if ((c = TTYget()) == EOF)
762 return CSeof;
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000763 /* Also include VT-100 arrows. */
764 if (c == '[' || c == 'O')
765 switch (c = TTYget()) {
766 default: return ring_bell();
767 case EOF: return CSeof;
768 case 'A': return h_prev();
769 case 'B': return h_next();
770 case 'C': return fd_char();
771 case 'D': return bk_char();
772 }
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000773
774 if (isdigit(c)) {
775 for (Repeat = c - '0'; (c = TTYget()) != EOF && isdigit(c); )
776 Repeat = Repeat * 10 + c - '0';
777 Pushed = 1;
778 PushBack = c;
779 return CSstay;
780 }
781
782 if (isupper(c))
783 return do_macro(c);
784 for (OldPoint = Point, kp = MetaMap; kp->Function; kp++)
785 if (kp->Key == c)
786 return (*kp->Function)();
787
788 return ring_bell();
789}
790
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000791static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000792emacs(unsigned int c)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000793{
794 STATUS s;
795 KEYMAP *kp;
796
797 if (ISMETA(c)) {
798 Pushed = 1;
799 PushBack = UNMETA(c);
800 return meta();
801 }
802 for (kp = Map; kp->Function; kp++)
803 if (kp->Key == c)
804 break;
805 s = kp->Function ? (*kp->Function)() : insert_char((int)c);
806 if (!Pushed)
807 /* No pushback means no repeat count; hacky, but true. */
808 Repeat = NO_ARG;
809 return s;
810}
811
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000812static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000813TTYspecial(unsigned int c)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000814{
815 if (ISMETA(c))
816 return CSdispatch;
817
818 if (c == rl_erase || c == DEL)
819 return bk_del_char();
820 if (c == rl_kill) {
821 if (Point != 0) {
822 Point = 0;
823 reposition();
824 }
825 Repeat = NO_ARG;
826 return kill_line();
827 }
828 if (c == rl_intr || c == rl_quit) {
829 Point = End = 0;
830 Line[0] = '\0';
831 return redisplay();
832 }
833 if (c == rl_eof && Point == 0 && End == 0)
834 return CSeof;
835
836 return CSdispatch;
837}
838
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000839static CHAR *
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000840editinput(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000841{
842 unsigned int c;
843
844 Repeat = NO_ARG;
845 OldPoint = Point = Mark = End = 0;
846 Line[0] = '\0';
847
848 while ((c = TTYget()) != EOF)
849 switch (TTYspecial(c)) {
850 case CSdone:
851 return Line;
852 case CSeof:
853 return NULL;
854 case CSmove:
855 reposition();
856 break;
857 case CSdispatch:
858 switch (emacs(c)) {
859 case CSdone:
860 return Line;
861 case CSeof:
862 return NULL;
863 case CSmove:
864 reposition();
865 break;
866 case CSdispatch:
867 case CSstay:
868 break;
869 }
870 break;
871 case CSstay:
872 break;
873 }
874 return NULL;
875}
876
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000877static void
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000878hist_add(CHAR *p)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000879{
880 int i;
881
Ove Kaavendda17c61999-04-25 12:24:42 +0000882 if ((p = (CHAR *)DBG_strdup((char *)p)) == NULL)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000883 return;
884 if (H.Size < HIST_SIZE)
885 H.Lines[H.Size++] = p;
886 else {
887 DISPOSE(H.Lines[0]);
888 for (i = 0; i < HIST_SIZE - 1; i++)
889 H.Lines[i] = H.Lines[i + 1];
890 H.Lines[i] = p;
891 }
892 H.Pos = H.Size - 1;
893}
894
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000895char *
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000896readline(const char *prompt)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000897{
898 CHAR *line;
899
900 if (Line == NULL) {
901 Length = MEM_INC;
902 if ((Line = NEW(CHAR, Length)) == NULL)
903 return NULL;
904 }
905
906 TTYinfo();
907 rl_ttyset(0);
908 hist_add(NIL);
909 ScreenSize = SCREEN_INC;
910 Screen = NEW(char, ScreenSize);
911 Prompt = prompt ? prompt : (char *)NIL;
912 TTYputs((CHAR *)Prompt);
913 if ((line = editinput()) != NULL) {
Ove Kaavendda17c61999-04-25 12:24:42 +0000914 line = (CHAR *)DBG_strdup((char *)line);
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000915 TTYputs((CHAR *)NEWLINE);
916 TTYflush();
917 }
918 rl_ttyset(1);
919 DISPOSE(Screen);
920 DISPOSE(H.Lines[--H.Size]);
921 return (char *)line;
922}
923
924void
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000925add_history(char *p)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000926{
927 if (p == NULL || *p == '\0')
928 return;
929
930#if defined(UNIQUE_HISTORY)
931 if (H.Pos && strcmp(p, H.Lines[H.Pos - 1]) == 0)
932 return;
933#endif /* defined(UNIQUE_HISTORY) */
934 hist_add((CHAR *)p);
935}
936
937
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000938static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000939beg_line(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000940{
941 if (Point) {
942 Point = 0;
943 return CSmove;
944 }
945 return CSstay;
946}
947
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000948static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000949del_char(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000950{
951 return delete_string(Repeat == NO_ARG ? 1 : Repeat);
952}
953
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000954static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000955end_line(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000956{
957 if (Point != End) {
958 Point = End;
959 return CSmove;
960 }
961 return CSstay;
962}
963
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000964static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000965accept_line(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000966{
967 Line[End] = '\0';
968 return CSdone;
969}
970
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000971static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000972transpose(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000973{
974 CHAR c;
975
976 if (Point) {
977 if (Point == End)
978 left(CSmove);
979 c = Line[Point - 1];
980 left(CSstay);
981 Line[Point - 1] = Line[Point];
982 TTYshow(Line[Point - 1]);
983 Line[Point++] = c;
984 TTYshow(c);
985 }
986 return CSstay;
987}
988
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000989static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000990quote(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000991{
992 unsigned int c;
993
994 return (c = TTYget()) == EOF ? CSeof : insert_char((int)c);
995}
996
Alexandre Julliard18f92e71996-07-17 20:02:21 +0000997static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +0000998wipe(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +0000999{
1000 int i;
1001
1002 if (Mark > End)
1003 return ring_bell();
1004
1005 if (Point > Mark) {
1006 i = Point;
1007 Point = Mark;
1008 Mark = i;
1009 reposition();
1010 }
1011
1012 return delete_string(Mark - Point);
1013}
1014
Alexandre Julliard18f92e71996-07-17 20:02:21 +00001015static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +00001016mk_set(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +00001017{
1018 Mark = Point;
1019 return CSstay;
1020}
1021
Alexandre Julliard18f92e71996-07-17 20:02:21 +00001022static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +00001023exchange(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +00001024{
1025 unsigned int c;
1026
1027 if ((c = TTYget()) != CTL('X'))
1028 return c == EOF ? CSeof : ring_bell();
1029
1030 if ((c = Mark) <= End) {
1031 Mark = Point;
1032 Point = c;
1033 return CSmove;
1034 }
1035 return CSstay;
1036}
1037
Alexandre Julliard18f92e71996-07-17 20:02:21 +00001038static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +00001039yank(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +00001040{
1041 if (Yanked && *Yanked)
1042 return insert_string(Yanked);
1043 return CSstay;
1044}
1045
Alexandre Julliard18f92e71996-07-17 20:02:21 +00001046static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +00001047copy_region(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +00001048{
1049 if (Mark > End)
1050 return ring_bell();
1051
1052 if (Point > Mark)
1053 save_yank(Mark, Point - Mark);
1054 else
1055 save_yank(Point, Mark - Point);
1056
1057 return CSstay;
1058}
1059
Alexandre Julliard18f92e71996-07-17 20:02:21 +00001060static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +00001061move_to_char(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +00001062{
1063 unsigned int c;
1064 int i;
1065 CHAR *p;
1066
1067 if ((c = TTYget()) == EOF)
1068 return CSeof;
1069 for (i = Point + 1, p = &Line[i]; i < End; i++, p++)
1070 if (*p == c) {
1071 Point = i;
1072 return CSmove;
1073 }
1074 return CSstay;
1075}
1076
Alexandre Julliard18f92e71996-07-17 20:02:21 +00001077static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +00001078fd_word(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +00001079{
1080 return do_forward(CSmove);
1081}
1082
Alexandre Julliard18f92e71996-07-17 20:02:21 +00001083static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +00001084fd_kill_word(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +00001085{
1086 int i;
1087
1088 (void)do_forward(CSstay);
1089 if (OldPoint != Point) {
1090 i = Point - OldPoint;
1091 Point = OldPoint;
1092 return delete_string(i);
1093 }
1094 return CSstay;
1095}
1096
Alexandre Julliard18f92e71996-07-17 20:02:21 +00001097static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +00001098bk_word(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +00001099{
1100 int i;
1101 CHAR *p;
1102
1103 i = 0;
1104 do {
1105 for (p = &Line[Point]; p > Line && !isalnum(p[-1]); p--)
1106 left(CSmove);
1107
1108 for (; p > Line && p[-1] != ' ' && isalnum(p[-1]); p--)
1109 left(CSmove);
1110
1111 if (Point == 0)
1112 break;
1113 } while (++i < Repeat);
1114
1115 return CSstay;
1116}
1117
Alexandre Julliard18f92e71996-07-17 20:02:21 +00001118static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +00001119bk_kill_word(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +00001120{
1121 (void)bk_word();
1122 if (OldPoint != Point)
1123 return delete_string(OldPoint - Point);
1124 return CSstay;
1125}
1126
Alexandre Julliard18f92e71996-07-17 20:02:21 +00001127static int
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +00001128argify(CHAR *line, CHAR ***avp)
Alexandre Julliardf0b23541993-09-29 12:21:49 +00001129{
1130 CHAR *c;
1131 CHAR **p;
1132 CHAR **new;
1133 int ac;
1134 int i;
1135
1136 i = MEM_INC;
1137 if ((*avp = p = NEW(CHAR*, i))== NULL)
1138 return 0;
1139
1140 for (c = line; isspace(*c); c++)
1141 continue;
1142 if (*c == '\n' || *c == '\0')
1143 return 0;
1144
1145 for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) {
1146 if (isspace(*c)) {
1147 *c++ = '\0';
1148 if (*c && *c != '\n') {
1149 if (ac + 1 == i) {
1150 new = NEW(CHAR*, i + MEM_INC);
1151 if (new == NULL) {
1152 p[ac] = NULL;
1153 return ac;
1154 }
1155 COPYFROMTO(new, p, i * sizeof (char **));
1156 i += MEM_INC;
1157 DISPOSE(p);
1158 *avp = p = new;
1159 }
1160 p[ac++] = c;
1161 }
1162 }
1163 else
1164 c++;
1165 }
1166 *c = '\0';
1167 p[ac] = NULL;
1168 return ac;
1169}
1170
Alexandre Julliard18f92e71996-07-17 20:02:21 +00001171static STATUS
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +00001172last_argument(void)
Alexandre Julliardf0b23541993-09-29 12:21:49 +00001173{
1174 CHAR **av;
1175 CHAR *p;
1176 STATUS s;
1177 int ac;
1178
1179 if (H.Size == 1 || (p = H.Lines[H.Size - 2]) == NULL)
1180 return ring_bell();
1181
Ove Kaavendda17c61999-04-25 12:24:42 +00001182 if ((p = (CHAR *)DBG_strdup((char *)p)) == NULL)
Alexandre Julliardf0b23541993-09-29 12:21:49 +00001183 return CSstay;
1184 ac = argify(p, &av);
1185
1186 if (Repeat != NO_ARG)
1187 s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell();
1188 else
1189 s = ac ? insert_string(av[ac - 1]) : CSstay;
1190
1191 if (ac)
1192 DISPOSE(av);
1193 DISPOSE(p);
1194 return s;
1195}
1196
Alexandre Julliard18f92e71996-07-17 20:02:21 +00001197static KEYMAP Map[33] = {
Alexandre Julliardf0b23541993-09-29 12:21:49 +00001198 { CTL('@'), ring_bell },
1199 { CTL('A'), beg_line },
1200 { CTL('B'), bk_char },
1201 { CTL('D'), del_char },
1202 { CTL('E'), end_line },
1203 { CTL('F'), fd_char },
1204 { CTL('G'), ring_bell },
1205 { CTL('H'), bk_del_char },
Alexandre Julliarde2991ea1995-07-29 13:09:43 +00001206 { CTL('I'), ring_bell },
Alexandre Julliardf0b23541993-09-29 12:21:49 +00001207 { CTL('J'), accept_line },
1208 { CTL('K'), kill_line },
1209 { CTL('L'), redisplay },
1210 { CTL('M'), accept_line },
1211 { CTL('N'), h_next },
1212 { CTL('O'), ring_bell },
1213 { CTL('P'), h_prev },
1214 { CTL('Q'), ring_bell },
1215 { CTL('R'), h_search },
1216 { CTL('S'), ring_bell },
1217 { CTL('T'), transpose },
1218 { CTL('U'), ring_bell },
1219 { CTL('V'), quote },
1220 { CTL('W'), wipe },
1221 { CTL('X'), exchange },
1222 { CTL('Y'), yank },
1223 { CTL('Z'), ring_bell },
1224 { CTL('['), meta },
1225 { CTL(']'), move_to_char },
1226 { CTL('^'), ring_bell },
1227 { CTL('_'), ring_bell },
1228 { 0, NULL }
1229};
1230
Alexandre Julliard18f92e71996-07-17 20:02:21 +00001231static KEYMAP MetaMap[16]= {
Alexandre Julliardf0b23541993-09-29 12:21:49 +00001232 { CTL('H'), bk_kill_word },
1233 { DEL, bk_kill_word },
1234 { ' ', mk_set },
1235 { '.', last_argument },
1236 { '<', h_first },
1237 { '>', h_last },
Alexandre Julliarde2991ea1995-07-29 13:09:43 +00001238 { '?', ring_bell },
Alexandre Julliardf0b23541993-09-29 12:21:49 +00001239 { 'b', bk_word },
1240 { 'd', fd_kill_word },
1241 { 'f', fd_word },
1242 { 'l', case_down_word },
1243 { 'u', case_up_word },
1244 { 'y', yank },
1245 { 'w', copy_region },
1246 { 0, NULL }
1247};