emacs.c revision 1.1 1 /*
2 * Emacs-like command line editing and history
3 *
4 * created by Ron Natalie at BRL
5 * modified by Doug Kingston, Doug Gwyn, and Lou Salkind
6 * adapted to PD ksh by Eric Gisin
7 */
8
9 #include "config.h"
10 #ifdef EMACS
11
12 #include "sh.h"
13 #include "ksh_stat.h"
14 #include "ksh_dir.h"
15 #include <ctype.h>
16 #include "edit.h"
17
18 static Area aedit;
19 #define AEDIT &aedit /* area for kill ring and macro defns */
20
21 #undef CTRL /* _BSD brain damage */
22 #define CTRL(x) ((x) == '?' ? 0x7F : (x) & 0x1F) /* ASCII */
23 #define UNCTRL(x) ((x) == 0x7F ? '?' : (x) | 0x40) /* ASCII */
24
25
26 /* values returned by keyboard functions */
27 #define KSTD 0
28 #define KEOL 1 /* ^M, ^J */
29 #define KINTR 2 /* ^G, ^C */
30
31 struct x_ftab {
32 int (*xf_func) ARGS((int c));
33 const char *xf_name;
34 short xf_flags;
35 };
36
37 /* index into struct x_ftab x_ftab[] - small is good */
38 typedef unsigned char Findex;
39
40 struct x_defbindings {
41 Findex xdb_func; /* XFUNC_* */
42 char xdb_tab;
43 unsigned char xdb_char;
44 };
45
46 #define XF_ARG 1 /* command takes number prefix */
47 #define XF_NOBIND 2 /* not allowed to bind to function */
48 #define XF_PREFIX 4 /* function sets prefix */
49
50 /* Separator for completion */
51 #define is_cfs(c) (c == ' ' || c == '\t' || c == '"' || c == '\'')
52 #define is_mfs(c) (!(isalnum(c) || c == '_' || c == '$')) /* Separator for motion */
53
54 #ifdef OS2
55 /* Deal with 8 bit chars & an extra prefix for function key (these two
56 * changes increase memory usage from 9,216 bytes to 24,416 bytes...)
57 */
58 # define CHARMASK 0xFF /* 8-bit ASCII character mask */
59 # define X_TABSZ 256 /* size of keydef tables etc */
60 # define X_NTABS 4 /* normal, meta1, meta2, meta3 */
61 static int x_prefix3 = 0xE0;
62 #else /* OS2 */
63 # define CHARMASK 0x7F /* 7-bit ASCII character mask */
64 # define X_TABSZ 128 /* size of keydef tables etc */
65 # define X_NTABS 3 /* normal, meta1, meta2 */
66 #endif /* OS2 */
67
68 /* Arguments for do_complete()
69 * 0 = enumerate M-= complete as much as possible and then list
70 * 1 = complete M-Esc
71 * 2 = list M-?
72 */
73 typedef enum { CT_LIST, /* list the possible completions */
74 CT_COMPLETE, /* complete to longest prefix */
75 CT_COMPLIST /* complete and then list (if non-exact) */
76 } Comp_type;
77
78 /* { from 4.9 edit.h */
79 /*
80 * The following are used for my horizontal scrolling stuff
81 */
82 static char *xbuf; /* beg input buffer */
83 static char *xend; /* end input buffer */
84 static char *xcp; /* current position */
85 static char *xep; /* current end */
86 static char *xbp; /* start of visible portion of input buffer */
87 static char *xlp; /* last char visible on screen */
88 static int x_adj_ok;
89 /*
90 * we use x_adj_done so that functions can tell
91 * whether x_adjust() has been called while they are active.
92 */
93 static int x_adj_done;
94
95 static int xx_cols;
96 static int x_col;
97 static int x_displen;
98 static int x_arg; /* general purpose arg */
99 static int x_arg_defaulted;/* x_arg not explicitly set; defaulted to 1 */
100
101 static int xlp_valid;
102 /* end from 4.9 edit.h } */
103
104 static int x_prefix1 = CTRL('['), x_prefix2 = CTRL('X');
105 static char **x_histp; /* history position */
106 static int x_nextcmd; /* for newline-and-next */
107 static char *xmp; /* mark pointer */
108 static Findex x_last_command;
109 static Findex (*x_tab)[X_TABSZ]; /* key definition */
110 static char *(*x_atab)[X_TABSZ]; /* macro definitions */
111 #define KILLSIZE 20
112 static char *killstack[KILLSIZE];
113 static int killsp, killtp;
114 static int x_curprefix;
115 static char *macroptr;
116 static int prompt_skip;
117
118 static int x_ins ARGS((char *cp));
119 static void x_delete ARGS((int nc, int force_push));
120 static int x_bword ARGS((void));
121 static int x_fword ARGS((void));
122 static void x_goto ARGS((char *cp));
123 static void x_bs ARGS((int c));
124 static int x_size_str ARGS((char *cp));
125 static int x_size ARGS((int c));
126 static void x_zots ARGS((char *str));
127 static void x_zotc ARGS((int c));
128 static void x_load_hist ARGS((char **hp));
129 static int x_search ARGS((char *pat, int sameline, int offset));
130 static int x_match ARGS((char *str, char *pat));
131 static void x_redraw ARGS((int limit));
132 static void x_push ARGS((int nchars));
133 static char * x_mapin ARGS((const char *cp));
134 static char * x_mapout ARGS((int c));
135 static void x_print ARGS((int prefix, int key));
136 static void x_adjust ARGS((void));
137 static void x_e_ungetc ARGS((int c));
138 static int x_e_getc ARGS((void));
139 static void x_e_putc ARGS((int c));
140 static void x_e_puts ARGS((const char *s));
141 static int x_fold_case ARGS((int c));
142 static char *x_lastcp ARGS((void));
143 static void do_complete ARGS((int flags, Comp_type type));
144
145
146 /* The lines between START-FUNC-TAB .. END-FUNC-TAB are run through a
147 * script (emacs-gen.sh) that generates emacs.out which contains:
148 * - function declarations for x_* functions
149 * - defines of the form XFUNC_<name> where <name> is function
150 * name, sans leading x_.
151 * Note that the script treats #ifdef and { 0, 0, 0} specially - use with
152 * caution.
153 */
154 #include "emacs.out"
155 static const struct x_ftab x_ftab[] = {
156 /* @START-FUNC-TAB@ */
157 { x_abort, "abort", 0 },
158 { x_beg_hist, "beginning-of-history", 0 },
159 { x_comp_comm, "complete-command", 0 },
160 { x_comp_file, "complete-file", 0 },
161 { x_complete, "complete", 0 },
162 { x_del_back, "delete-char-backward", XF_ARG },
163 { x_del_bword, "delete-word-backward", XF_ARG },
164 { x_del_char, "delete-char-forward", XF_ARG },
165 { x_del_fword, "delete-word-forward", XF_ARG },
166 { x_del_line, "kill-line", 0 },
167 { x_draw_line, "redraw", 0 },
168 { x_end_hist, "end-of-history", 0 },
169 { x_end_of_text, "eot", 0 },
170 { x_enumerate, "list", 0 },
171 { x_eot_del, "eot-or-delete", XF_ARG },
172 { x_error, "error", 0 },
173 { x_goto_hist, "goto-history", XF_ARG },
174 { x_ins_string, "macro-string", XF_NOBIND },
175 { x_insert, "auto-insert", XF_ARG },
176 { x_kill, "kill-to-eol", XF_ARG },
177 { x_kill_region, "kill-region", 0 },
178 { x_list_comm, "list-command", 0 },
179 { x_list_file, "list-file", 0 },
180 { x_literal, "quote", 0 },
181 { x_meta1, "prefix-1", XF_PREFIX },
182 { x_meta2, "prefix-2", XF_PREFIX },
183 { x_meta_yank, "yank-pop", 0 },
184 { x_mv_back, "backward-char", XF_ARG },
185 { x_mv_begin, "beginning-of-line", 0 },
186 { x_mv_bword, "backward-word", XF_ARG },
187 { x_mv_end, "end-of-line", 0 },
188 { x_mv_forw, "forward-char", XF_ARG },
189 { x_mv_fword, "forward-word", XF_ARG },
190 { x_newline, "newline", 0 },
191 { x_next_com, "down-history", XF_ARG },
192 { x_nl_next_com, "newline-and-next", 0 },
193 { x_noop, "no-op", 0 },
194 { x_prev_com, "up-history", XF_ARG },
195 { x_prev_histword, "prev-hist-word", XF_ARG },
196 { x_search_char_forw, "search-character-forward", XF_ARG },
197 { x_search_char_back, "search-character-backward", XF_ARG },
198 { x_search_hist, "search-history", 0 },
199 { x_set_mark, "set-mark-command", 0 },
200 { x_stuff, "stuff", 0 },
201 { x_stuffreset, "stuff-reset", 0 },
202 { x_transpose, "transpose-chars", 0 },
203 { x_version, "version", 0 },
204 { x_xchg_point_mark, "exchange-point-and-mark", 0 },
205 { x_yank, "yank", 0 },
206 { x_comp_list, "complete-list", 0 },
207 { x_expand, "expand-file", 0 },
208 { x_fold_capitialize, "capitalize-word", XF_ARG },
209 { x_fold_lower, "downcase-word", XF_ARG },
210 { x_fold_upper, "upcase-word", XF_ARG },
211 { x_set_arg, "set-arg", XF_NOBIND },
212 { x_comment, "comment", 0 },
213 #ifdef SILLY
214 { x_game_of_life, "play-game-of-life", 0 },
215 #else
216 { 0, 0, 0 },
217 #endif
218 #ifdef DEBUG
219 { x_debug_info, "debug-info", 0 },
220 #else
221 { 0, 0, 0 },
222 #endif
223 #ifdef OS2
224 { x_meta3, "prefix-3", XF_PREFIX },
225 #else
226 { 0, 0, 0 },
227 #endif
228 /* @END-FUNC-TAB@ */
229 };
230
231 static struct x_defbindings const x_defbindings[] = {
232 { XFUNC_del_back, 0, CTRL('?') },
233 { XFUNC_del_bword, 1, CTRL('?') },
234 { XFUNC_eot_del, 0, CTRL('D') },
235 { XFUNC_del_back, 0, CTRL('H') },
236 { XFUNC_del_bword, 1, CTRL('H') },
237 { XFUNC_del_bword, 1, 'h' },
238 { XFUNC_mv_bword, 1, 'b' },
239 { XFUNC_mv_fword, 1, 'f' },
240 { XFUNC_del_fword, 1, 'd' },
241 { XFUNC_mv_back, 0, CTRL('B') },
242 { XFUNC_mv_forw, 0, CTRL('F') },
243 { XFUNC_search_char_forw, 0, CTRL(']') },
244 { XFUNC_search_char_back, 1, CTRL(']') },
245 { XFUNC_newline, 0, CTRL('M') },
246 { XFUNC_newline, 0, CTRL('J') },
247 { XFUNC_end_of_text, 0, CTRL('_') },
248 { XFUNC_abort, 0, CTRL('G') },
249 { XFUNC_prev_com, 0, CTRL('P') },
250 { XFUNC_next_com, 0, CTRL('N') },
251 { XFUNC_nl_next_com, 0, CTRL('O') },
252 { XFUNC_search_hist, 0, CTRL('R') },
253 { XFUNC_beg_hist, 1, '<' },
254 { XFUNC_end_hist, 1, '>' },
255 { XFUNC_goto_hist, 1, 'g' },
256 { XFUNC_mv_end, 0, CTRL('E') },
257 { XFUNC_mv_begin, 0, CTRL('A') },
258 { XFUNC_draw_line, 0, CTRL('L') },
259 { XFUNC_meta1, 0, CTRL('[') },
260 { XFUNC_meta2, 0, CTRL('X') },
261 { XFUNC_kill, 0, CTRL('K') },
262 { XFUNC_yank, 0, CTRL('Y') },
263 { XFUNC_meta_yank, 1, 'y' },
264 { XFUNC_literal, 0, CTRL('^') },
265 { XFUNC_comment, 1, '#' },
266 #if defined(BRL) && defined(TIOCSTI)
267 { XFUNC_stuff, 0, CTRL('T') },
268 #else
269 { XFUNC_transpose, 0, CTRL('T') },
270 #endif
271 { XFUNC_complete, 1, CTRL('[') },
272 { XFUNC_comp_list, 1, '=' },
273 { XFUNC_enumerate, 1, '?' },
274 { XFUNC_expand, 1, '*' },
275 { XFUNC_comp_file, 1, CTRL('X') },
276 { XFUNC_comp_comm, 2, CTRL('[') },
277 { XFUNC_list_comm, 2, '?' },
278 { XFUNC_list_file, 2, CTRL('Y') },
279 { XFUNC_set_mark, 1, ' ' },
280 { XFUNC_kill_region, 0, CTRL('W') },
281 { XFUNC_xchg_point_mark, 2, CTRL('X') },
282 { XFUNC_version, 0, CTRL('V') },
283 #ifdef DEBUG
284 { XFUNC_debug_info, 1, CTRL('H') },
285 #endif
286 { XFUNC_prev_histword, 1, '.' },
287 { XFUNC_prev_histword, 1, '_' },
288 { XFUNC_set_arg, 1, '0' },
289 { XFUNC_set_arg, 1, '1' },
290 { XFUNC_set_arg, 1, '2' },
291 { XFUNC_set_arg, 1, '3' },
292 { XFUNC_set_arg, 1, '4' },
293 { XFUNC_set_arg, 1, '5' },
294 { XFUNC_set_arg, 1, '6' },
295 { XFUNC_set_arg, 1, '7' },
296 { XFUNC_set_arg, 1, '8' },
297 { XFUNC_set_arg, 1, '9' },
298 { XFUNC_fold_upper, 1, 'U' },
299 { XFUNC_fold_upper, 1, 'u' },
300 { XFUNC_fold_lower, 1, 'L' },
301 { XFUNC_fold_lower, 1, 'l' },
302 { XFUNC_fold_capitialize, 1, 'C' },
303 { XFUNC_fold_capitialize, 1, 'c' },
304 #ifdef OS2
305 { XFUNC_meta3, 0, 0xE0 },
306 { XFUNC_mv_back, 3, 'K' },
307 { XFUNC_mv_forw, 3, 'M' },
308 { XFUNC_next_com, 3, 'P' },
309 { XFUNC_prev_com, 3, 'H' },
310 #else /* OS2 */
311 /* These for ansi arrow keys: arguablely shouldn't be here by
312 * default, but its simpler/faster/smaller than using termcap
313 * entries.
314 */
315 { XFUNC_meta2, 1, '[' },
316 { XFUNC_prev_com, 2, 'A' },
317 { XFUNC_next_com, 2, 'B' },
318 { XFUNC_mv_forw, 2, 'C' },
319 { XFUNC_mv_back, 2, 'D' },
320 #endif /* OS2 */
321 };
322
323 int
324 x_emacs(buf, len)
325 char *buf;
326 size_t len;
327 {
328 int c;
329 const char *p;
330 int i;
331 Findex f;
332
333 xbp = xbuf = buf; xend = buf + len;
334 xlp = xcp = xep = buf;
335 *xcp = 0;
336 xlp_valid = TRUE;
337 xmp = NULL;
338 x_curprefix = 0;
339 macroptr = (char *) 0;
340 x_histp = histptr + 1;
341 x_last_command = XFUNC_error;
342
343 xx_cols = x_cols;
344 x_col = promptlen(prompt, &p);
345 prompt_skip = p - prompt;
346 x_adj_ok = 1;
347 x_displen = xx_cols - 2 - x_col;
348 x_adj_done = 0;
349
350 pprompt(prompt, 0);
351
352 if (x_nextcmd >= 0) {
353 int off = source->line - x_nextcmd;
354 if (histptr - history >= off)
355 x_load_hist(histptr - off);
356 x_nextcmd = -1;
357 }
358
359 while (1) {
360 x_flush();
361 if ((c = x_e_getc()) < 0)
362 return 0;
363
364 f = x_curprefix == -1 ? XFUNC_insert
365 : x_tab[x_curprefix][c&CHARMASK];
366
367 if (!(x_ftab[f].xf_flags & XF_PREFIX)
368 && x_last_command != XFUNC_set_arg)
369 {
370 x_arg = 1;
371 x_arg_defaulted = 1;
372 }
373 i = c | (x_curprefix << 8);
374 x_curprefix = 0;
375 switch (i = (*x_ftab[f].xf_func)(i)) {
376 case KSTD:
377 if (!(x_ftab[f].xf_flags & XF_PREFIX))
378 x_last_command = f;
379 break;
380 case KEOL:
381 i = xep - xbuf;
382 return i;
383 case KINTR: /* special case for interrupt */
384 trapsig(SIGINT);
385 x_mode(FALSE);
386 unwind(LSHELL);
387 }
388 }
389 }
390
391 static int
392 x_insert(c)
393 int c;
394 {
395 char str[2];
396
397 /*
398 * Should allow tab and control chars.
399 */
400 if (c == 0) {
401 x_e_putc(BEL);
402 return KSTD;
403 }
404 str[0] = c;
405 str[1] = '\0';
406 while (x_arg--)
407 x_ins(str);
408 return KSTD;
409 }
410
411 static int
412 x_ins_string(c)
413 int c;
414 {
415 if (macroptr) {
416 x_e_putc(BEL);
417 return KSTD;
418 }
419 macroptr = x_atab[c>>8][c & CHARMASK];
420 if (macroptr && !*macroptr) {
421 /* XXX bell? */
422 macroptr = (char *) 0;
423 }
424 return KSTD;
425 }
426
427 static int
428 x_do_ins(cp, len)
429 const char *cp;
430 int len;
431 {
432 if (xep+len >= xend) {
433 x_e_putc(BEL);
434 return -1;
435 }
436
437 memmove(xcp+len, xcp, xep - xcp + 1);
438 memmove(xcp, cp, len);
439 xcp += len;
440 xep += len;
441 return 0;
442 }
443
444 static int
445 x_ins(s)
446 char *s;
447 {
448 char *cp = xcp;
449 register int adj = x_adj_done;
450
451 if (x_do_ins(s, strlen(s)) < 0)
452 return -1;
453 /*
454 * x_zots() may result in a call to x_adjust()
455 * we want xcp to reflect the new position.
456 */
457 xlp_valid = FALSE;
458 x_lastcp();
459 x_adj_ok = (xcp >= xlp);
460 x_zots(cp);
461 if (adj == x_adj_done) /* has x_adjust() been called? */
462 {
463 /* no */
464 for (cp = xlp; cp > xcp; )
465 x_bs(*--cp);
466 }
467
468 x_adj_ok = 1;
469 return 0;
470 }
471
472 static int
473 x_del_back(c)
474 int c;
475 {
476 int col = xcp - xbuf;
477
478 if (col == 0) {
479 x_e_putc(BEL);
480 return KSTD;
481 }
482 if (x_arg > col)
483 x_arg = col;
484 x_goto(xcp - x_arg);
485 x_delete(x_arg, FALSE);
486 return KSTD;
487 }
488
489 static int
490 x_del_char(c)
491 int c;
492 {
493 int nleft = xep - xcp;
494
495 if (!nleft) {
496 x_e_putc(BEL);
497 return KSTD;
498 }
499 if (x_arg > nleft)
500 x_arg = nleft;
501 x_delete(x_arg, FALSE);
502 return KSTD;
503 }
504
505 /* Delete nc chars to the right of the cursor (including cursor position) */
506 static void
507 x_delete(nc, force_push)
508 int nc;
509 int force_push;
510 {
511 int i,j;
512 char *cp;
513
514 if (nc == 0)
515 return;
516 if (xmp != NULL && xmp > xcp) {
517 if (xcp + nc > xmp)
518 xmp = xcp;
519 else
520 xmp -= nc;
521 }
522
523 /*
524 * This lets us yank a word we have deleted.
525 */
526 if (nc > 1 || force_push)
527 x_push(nc);
528
529 xep -= nc;
530 cp = xcp;
531 j = 0;
532 i = nc;
533 while (i--) {
534 j += x_size(*cp++);
535 }
536 memmove(xcp, xcp+nc, xep - xcp + 1); /* Copies the null */
537 x_adj_ok = 0; /* don't redraw */
538 x_zots(xcp);
539 /*
540 * if we are already filling the line,
541 * there is no need to ' ','\b'.
542 * But if we must, make sure we do the minimum.
543 */
544 if ((i = xx_cols - 2 - x_col) > 0)
545 {
546 j = (j < i) ? j : i;
547 i = j;
548 while (i--)
549 x_e_putc(' ');
550 i = j;
551 while (i--)
552 x_e_putc('\b');
553 }
554 /*x_goto(xcp);*/
555 x_adj_ok = 1;
556 xlp_valid = FALSE;
557 for (cp = x_lastcp(); cp > xcp; )
558 x_bs(*--cp);
559
560 return;
561 }
562
563 static int
564 x_del_bword(c)
565 int c;
566 {
567 x_delete(x_bword(), FALSE);
568 return KSTD;
569 }
570
571 static int
572 x_mv_bword(c)
573 int c;
574 {
575 (void)x_bword();
576 return KSTD;
577 }
578
579 static int
580 x_mv_fword(c)
581 int c;
582 {
583 x_goto(xcp + x_fword());
584 return KSTD;
585 }
586
587 static int
588 x_del_fword(c)
589 int c;
590 {
591 x_delete(x_fword(), FALSE);
592 return KSTD;
593 }
594
595 static int
596 x_bword()
597 {
598 int nc = 0;
599 register char *cp = xcp;
600
601 if (cp == xbuf) {
602 x_e_putc(BEL);
603 return 0;
604 }
605 while (x_arg--)
606 {
607 while (cp != xbuf && is_mfs(cp[-1]))
608 {
609 cp--;
610 nc++;
611 }
612 while (cp != xbuf && !is_mfs(cp[-1]))
613 {
614 cp--;
615 nc++;
616 }
617 }
618 x_goto(cp);
619 return nc;
620 }
621
622 static int
623 x_fword()
624 {
625 int nc = 0;
626 register char *cp = xcp;
627
628 if (cp == xep) {
629 x_e_putc(BEL);
630 return 0;
631 }
632 while (x_arg--)
633 {
634 while (cp != xep && is_mfs(*cp))
635 {
636 cp++;
637 nc++;
638 }
639 while (cp != xep && !is_mfs(*cp))
640 {
641 cp++;
642 nc++;
643 }
644 }
645 return nc;
646 }
647
648 static void
649 x_goto(cp)
650 register char *cp;
651 {
652 if (cp < xbp || cp >= (xbp + x_displen))
653 {
654 /* we are heading off screen */
655 xcp = cp;
656 x_adjust();
657 }
658 else
659 {
660 if (cp < xcp) /* move back */
661 {
662 while (cp < xcp)
663 x_bs(*--xcp);
664 }
665 else
666 {
667 if (cp > xcp) /* move forward */
668 {
669 while (cp > xcp)
670 x_zotc(*xcp++);
671 }
672 }
673 }
674 }
675
676 static void
677 x_bs(c)
678 int c;
679 {
680 register i;
681 i = x_size(c);
682 while (i--)
683 x_e_putc('\b');
684 }
685
686 static int
687 x_size_str(cp)
688 register char *cp;
689 {
690 register size = 0;
691 while (*cp)
692 size += x_size(*cp++);
693 return size;
694 }
695
696 static int
697 x_size(c)
698 int c;
699 {
700 if (c=='\t')
701 return 4; /* Kludge, tabs are always four spaces. */
702 if (c < ' ' || c == 0x7F) /* ASCII control char */
703 return 2;
704 return 1;
705 }
706
707 static void
708 x_zots(str)
709 register char *str;
710 {
711 register int adj = x_adj_done;
712
713 x_lastcp();
714 while (*str && str < xlp && adj == x_adj_done)
715 x_zotc(*str++);
716 }
717
718 static void
719 x_zotc(c)
720 int c;
721 {
722 if (c == '\t') {
723 /* Kludge, tabs are always four spaces. */
724 x_e_puts(" ");
725 } else if (c < ' ' || c == 0x7F) { /* ASCII */
726 x_e_putc('^');
727 x_e_putc(UNCTRL(c));
728 } else
729 x_e_putc(c);
730 }
731
732 static int
733 x_mv_back(c)
734 int c;
735 {
736 int col = xcp - xbuf;
737
738 if (col == 0) {
739 x_e_putc(BEL);
740 return KSTD;
741 }
742 if (x_arg > col)
743 x_arg = col;
744 x_goto(xcp - x_arg);
745 return KSTD;
746 }
747
748 static int
749 x_mv_forw(c)
750 int c;
751 {
752 int nleft = xep - xcp;
753
754 if (!nleft) {
755 x_e_putc(BEL);
756 return KSTD;
757 }
758 if (x_arg > nleft)
759 x_arg = nleft;
760 x_goto(xcp + x_arg);
761 return KSTD;
762 }
763
764 static int
765 x_search_char_forw(c)
766 int c;
767 {
768 char *cp = xcp;
769
770 *xep = '\0';
771 c = x_e_getc();
772 while (x_arg--) {
773 if (c < 0
774 || ((cp = (cp == xep) ? NULL : strchr(cp + 1, c)) == NULL
775 && (cp = strchr(xbuf, c)) == NULL))
776 {
777 x_e_putc(BEL);
778 return KSTD;
779 }
780 }
781 x_goto(cp);
782 return KSTD;
783 }
784
785 static int
786 x_search_char_back(c)
787 int c;
788 {
789 char *cp = xcp, *p;
790
791 c = x_e_getc();
792 for (; x_arg--; cp = p)
793 for (p = cp; ; ) {
794 if (p-- == xbuf)
795 p = xep;
796 if (c < 0 || p == cp) {
797 x_e_putc(BEL);
798 return KSTD;
799 }
800 if (*p == c)
801 break;
802 }
803 x_goto(cp);
804 return KSTD;
805 }
806
807 static int
808 x_newline(c)
809 int c;
810 {
811 x_e_putc('\r');
812 x_e_putc('\n');
813 x_flush();
814 *xep++ = '\n';
815 return KEOL;
816 }
817
818 static int
819 x_end_of_text(c)
820 int c;
821 {
822 return KEOL;
823 }
824
825 static int x_beg_hist(c) int c; { x_load_hist(history); return KSTD;}
826
827 static int x_end_hist(c) int c; { x_load_hist(histptr); return KSTD;}
828
829 static int x_prev_com(c) int c; { x_load_hist(x_histp - x_arg); return KSTD;}
830
831 static int x_next_com(c) int c; { x_load_hist(x_histp + x_arg); return KSTD;}
832
833 /* Goto a particular history number obtained from argument.
834 * If no argument is given history 1 is probably not what you
835 * want so we'll simply go to the oldest one.
836 */
837 static int
838 x_goto_hist(c)
839 int c;
840 {
841 if (x_arg_defaulted)
842 x_load_hist(history);
843 else
844 x_load_hist(histptr + x_arg - source->line);
845 return KSTD;
846 }
847
848 static void
849 x_load_hist(hp)
850 register char **hp;
851 {
852 int oldsize;
853
854 if (hp < history || hp > histptr) {
855 x_e_putc(BEL);
856 return;
857 }
858 x_histp = hp;
859 oldsize = x_size_str(xbuf);
860 (void)strcpy(xbuf, *hp);
861 xbp = xbuf;
862 xep = xcp = xbuf + strlen(*hp);
863 xlp_valid = FALSE;
864 if (xep > x_lastcp())
865 x_goto(xep);
866 else
867 x_redraw(oldsize);
868 }
869
870 static int
871 x_nl_next_com(c)
872 int c;
873 {
874 x_nextcmd = source->line - (histptr - x_histp) + 1;
875 return (x_newline(c));
876 }
877
878 static int
879 x_eot_del(c)
880 int c;
881 {
882 if (xep == xbuf && x_arg_defaulted)
883 return (x_end_of_text(c));
884 else
885 return (x_del_char(c));
886 }
887
888 /* reverse incremental history search */
889 static int
890 x_search_hist(c)
891 int c;
892 {
893 int offset = -1; /* offset of match in xbuf, else -1 */
894 char pat [256+1]; /* pattern buffer */
895 register char *p = pat;
896 Findex f;
897
898 *p = '\0';
899 while (1) {
900 if (offset < 0) {
901 x_e_puts("\nI-search: ");
902 x_e_puts(pat);
903 }
904 x_flush();
905 if ((c = x_e_getc()) < 0)
906 return KSTD;
907 f = x_tab[0][c&CHARMASK];
908 if (c == CTRL('['))
909 break;
910 else if (f == XFUNC_search_hist)
911 offset = x_search(pat, 0, offset);
912 else if (f == XFUNC_del_back) {
913 if (p == pat) {
914 offset = -1;
915 break;
916 }
917 if (p > pat)
918 *--p = '\0';
919 if (p == pat)
920 offset = -1;
921 else
922 offset = x_search(pat, 1, offset);
923 continue;
924 } else if (f == XFUNC_insert) {
925 /* add char to pattern */
926 /* overflow check... */
927 if (p >= &pat[sizeof(pat) - 1]) {
928 x_e_putc(BEL);
929 continue;
930 }
931 *p++ = c, *p = '\0';
932 if (offset >= 0) {
933 /* already have partial match */
934 offset = x_match(xbuf, pat);
935 if (offset >= 0) {
936 x_goto(xbuf + offset + (p - pat) - (*pat == '^'));
937 continue;
938 }
939 }
940 offset = x_search(pat, 0, offset);
941 } else { /* other command */
942 x_e_ungetc(c);
943 break;
944 }
945 }
946 if (offset < 0)
947 x_redraw(-1);
948 return KSTD;
949 }
950
951 /* search backward from current line */
952 static int
953 x_search(pat, sameline, offset)
954 char *pat;
955 int sameline;
956 int offset;
957 {
958 register char **hp;
959 int i;
960
961 for (hp = x_histp - (sameline ? 0 : 1) ; hp >= history; --hp) {
962 i = x_match(*hp, pat);
963 if (i >= 0) {
964 if (offset < 0)
965 x_e_putc('\n');
966 x_load_hist(hp);
967 x_goto(xbuf + i + strlen(pat) - (*pat == '^'));
968 return i;
969 }
970 }
971 x_e_putc(BEL);
972 x_histp = histptr;
973 return -1;
974 }
975
976 /* return position of first match of pattern in string, else -1 */
977 static int
978 x_match(str, pat)
979 char *str, *pat;
980 {
981 if (*pat == '^') {
982 return (strncmp(str, pat+1, strlen(pat+1)) == 0) ? 0 : -1;
983 } else {
984 char *q = strstr(str, pat);
985 return (q == NULL) ? -1 : q - str;
986 }
987 }
988
989 static int
990 x_del_line(c)
991 int c;
992 {
993 int i, j;
994
995 *xep = 0;
996 i = xep- xbuf;
997 j = x_size_str(xbuf);
998 xcp = xbuf;
999 x_push(i);
1000 xlp = xbp = xep = xbuf;
1001 xlp_valid = TRUE;
1002 *xcp = 0;
1003 xmp = NULL;
1004 x_redraw(j);
1005 return KSTD;
1006 }
1007
1008 static int
1009 x_mv_end(c)
1010 int c;
1011 {
1012 x_goto(xep);
1013 return KSTD;
1014 }
1015
1016 static int
1017 x_mv_begin(c)
1018 int c;
1019 {
1020 x_goto(xbuf);
1021 return KSTD;
1022 }
1023
1024 static int
1025 x_draw_line(c)
1026 int c;
1027 {
1028 x_redraw(-1);
1029 return KSTD;
1030
1031 }
1032
1033 /* Redraw (part of) the line. If limit is < 0, the everything is redrawn
1034 * on a NEW line, otherwise limit is the screen column up to which needs
1035 * redrawing.
1036 */
1037 static void
1038 x_redraw(limit)
1039 int limit;
1040 {
1041 int i, j;
1042 char *cp;
1043
1044 x_adj_ok = 0;
1045 if (limit == -1)
1046 x_e_putc('\n');
1047 else
1048 x_e_putc('\r');
1049 x_flush();
1050 if (xbp == xbuf)
1051 {
1052 pprompt(prompt + prompt_skip, 0);
1053 x_col = promptlen(prompt, (const char **) 0);
1054 }
1055 x_displen = xx_cols - 2 - x_col;
1056 xlp_valid = FALSE;
1057 cp = x_lastcp();
1058 x_zots(xbp);
1059 if (xbp != xbuf || xep > xlp)
1060 limit = xx_cols;
1061 if (limit >= 0)
1062 {
1063 if (xep > xlp)
1064 i = 0; /* we fill the line */
1065 else
1066 i = limit - (xlp - xbp);
1067
1068 for (j = 0; j < i && x_col < (xx_cols - 2); j++)
1069 x_e_putc(' ');
1070 i = ' ';
1071 if (xep > xlp) /* more off screen */
1072 {
1073 if (xbp > xbuf)
1074 i = '*';
1075 else
1076 i = '>';
1077 }
1078 else
1079 if (xbp > xbuf)
1080 i = '<';
1081 x_e_putc(i);
1082 j++;
1083 while (j--)
1084 x_e_putc('\b');
1085 }
1086 for (cp = xlp; cp > xcp; )
1087 x_bs(*--cp);
1088 x_adj_ok = 1;
1089 D__(x_flush();)
1090 return;
1091 }
1092
1093 static int
1094 x_transpose(c)
1095 int c;
1096 {
1097 char tmp;
1098
1099 /* What transpose is meant to do seems to be up for debate. This
1100 * is a general summary of the options; the text is abcd with the
1101 * upper case character or underscore indicating the cursor positiion:
1102 * Who Before After Before After
1103 * at&t ksh in emacs mode: abCd abdC abcd_ (bell)
1104 * at&t ksh in gmacs mode: abCd baCd abcd_ abdc_
1105 * gnu emacs: abCd acbD abcd_ abdc_
1106 * Pdksh currently goes with GNU behavior since I believe this is the
1107 * most common version of emacs, unless in gmacs mode, in which case
1108 * it does the at&t ksh gmacs mdoe.
1109 * This should really be broken up into 3 functions so users can bind
1110 * to the one they want.
1111 */
1112 if (xcp == xbuf) {
1113 x_e_putc(BEL);
1114 return KSTD;
1115 } else if (xcp == xep || Flag(FGMACS)) {
1116 if (xcp - xbuf == 1) {
1117 x_e_putc(BEL);
1118 return KSTD;
1119 }
1120 /* Gosling/Unipress emacs style: Swap two characters before the
1121 * cursor, do not change cursor position
1122 */
1123 x_bs(xcp[-1]);
1124 x_bs(xcp[-2]);
1125 x_zotc(xcp[-1]);
1126 x_zotc(xcp[-2]);
1127 tmp = xcp[-1];
1128 xcp[-1] = xcp[-2];
1129 xcp[-2] = tmp;
1130 } else {
1131 /* GNU emacs style: Swap the characters before and under the
1132 * cursor, move cursor position along one.
1133 */
1134 x_bs(xcp[-1]);
1135 x_zotc(xcp[0]);
1136 x_zotc(xcp[-1]);
1137 tmp = xcp[-1];
1138 xcp[-1] = xcp[0];
1139 xcp[0] = tmp;
1140 x_bs(xcp[0]);
1141 x_goto(xcp + 1);
1142 }
1143 return KSTD;
1144 }
1145
1146 static int
1147 x_literal(c)
1148 int c;
1149 {
1150 x_curprefix = -1;
1151 return KSTD;
1152 }
1153
1154 static int
1155 x_meta1(c)
1156 int c;
1157 {
1158 x_curprefix = 1;
1159 return KSTD;
1160 }
1161
1162 static int
1163 x_meta2(c)
1164 int c;
1165 {
1166 x_curprefix = 2;
1167 return KSTD;
1168 }
1169
1170 #ifdef OS2
1171 static int
1172 x_meta3(c)
1173 int c;
1174 {
1175 x_curprefix = 3;
1176 return KSTD;
1177 }
1178 #endif /* OS2 */
1179
1180 static int
1181 x_kill(c)
1182 int c;
1183 {
1184 int col = xcp - xbuf;
1185 int lastcol = xep - xbuf;
1186 int ndel;
1187
1188 if (x_arg_defaulted)
1189 x_arg = lastcol;
1190 else if (x_arg > lastcol)
1191 x_arg = lastcol;
1192 ndel = x_arg - col;
1193 if (ndel < 0) {
1194 x_goto(xbuf + x_arg);
1195 ndel = -ndel;
1196 }
1197 x_delete(ndel, TRUE);
1198 return KSTD;
1199 }
1200
1201 static void
1202 x_push(nchars)
1203 int nchars;
1204 {
1205 char *cp = str_nsave(xcp, nchars, AEDIT);
1206 if (killstack[killsp])
1207 afree((void *)killstack[killsp], AEDIT);
1208 killstack[killsp] = cp;
1209 killsp = (killsp + 1) % KILLSIZE;
1210 }
1211
1212 static int
1213 x_yank(c)
1214 int c;
1215 {
1216 if (killsp == 0)
1217 killtp = KILLSIZE;
1218 else
1219 killtp = killsp;
1220 killtp --;
1221 if (killstack[killtp] == 0) {
1222 x_e_puts("\nnothing to yank");
1223 x_redraw(-1);
1224 return KSTD;
1225 }
1226 xmp = xcp;
1227 x_ins(killstack[killtp]);
1228 return KSTD;
1229 }
1230
1231 static int
1232 x_meta_yank(c)
1233 int c;
1234 {
1235 int len;
1236 if (x_last_command != XFUNC_yank && x_last_command != XFUNC_meta_yank) {
1237 x_e_puts("\nyank something first");
1238 x_redraw(-1);
1239 return KSTD;
1240 }
1241 len = strlen(killstack[killtp]);
1242 x_goto(xcp - len);
1243 x_delete(len, FALSE);
1244 do {
1245 if (killtp == 0)
1246 killtp = KILLSIZE - 1;
1247 else
1248 killtp--;
1249 } while (killstack[killtp] == 0);
1250 x_ins(killstack[killtp]);
1251 return KSTD;
1252 }
1253
1254 static int
1255 x_abort(c)
1256 int c;
1257 {
1258 /* x_zotc(c); */
1259 xlp = xep = xcp = xbp = xbuf;
1260 xlp_valid = TRUE;
1261 *xcp = 0;
1262 return KINTR;
1263 }
1264
1265 static int
1266 x_error(c)
1267 int c;
1268 {
1269 x_e_putc(BEL);
1270 return KSTD;
1271 }
1272
1273 static int
1274 x_stuffreset(c)
1275 int c;
1276 {
1277 #ifdef TIOCSTI
1278 (void)x_stuff(c);
1279 return KINTR;
1280 #else
1281 x_zotc(c);
1282 xlp = xcp = xep = xbp = xbuf;
1283 xlp_valid = TRUE;
1284 *xcp = 0;
1285 x_redraw(-1);
1286 return KSTD;
1287 #endif
1288 }
1289
1290 static int
1291 x_stuff(c)
1292 int c;
1293 {
1294 #if 0 || defined TIOCSTI
1295 char ch = c;
1296 bool_t savmode = x_mode(FALSE);
1297
1298 (void)ioctl(TTY, TIOCSTI, &ch);
1299 (void)x_mode(savmode);
1300 x_redraw(-1);
1301 #endif
1302 return KSTD;
1303 }
1304
1305 static char *
1306 x_mapin(cp)
1307 const char *cp;
1308 {
1309 char *new, *op;
1310
1311 op = new = str_save(cp, ATEMP);
1312 while (*cp) {
1313 /* XXX -- should handle \^ escape? */
1314 if (*cp == '^') {
1315 cp++;
1316 #ifdef OS2
1317 if (*cp == '0') /* To define function keys */
1318 *op++ = 0xE0;
1319 else
1320 #endif /* OS2 */
1321 if (*cp >= '?') /* includes '?'; ASCII */
1322 *op++ = CTRL(*cp);
1323 else {
1324 *op++ = '^';
1325 cp--;
1326 }
1327 } else
1328 *op++ = *cp;
1329 cp++;
1330 }
1331 *op = '\0';
1332
1333 return new;
1334 }
1335
1336 static char *
1337 x_mapout(c)
1338 int c;
1339 {
1340 static char buf[8];
1341 register char *p = buf;
1342
1343 if (c < ' ' || c == 0x7F) { /* ASCII */
1344 *p++ = '^';
1345 *p++ = (c == 0x7F) ? '?' : (c | 0x40);
1346 #ifdef OS2
1347 } else if (c == 0xE0) {
1348 *p++ = '^';
1349 *p++ = '0';
1350 #endif /* OS2 */
1351 } else
1352 *p++ = c;
1353 *p = 0;
1354 return buf;
1355 }
1356
1357 static void
1358 x_print(prefix, key)
1359 int prefix, key;
1360 {
1361 if (prefix == 1)
1362 shprintf("%s", x_mapout(x_prefix1));
1363 if (prefix == 2)
1364 shprintf("%s", x_mapout(x_prefix2));
1365 #ifdef OS2
1366 if (prefix == 3)
1367 shprintf("%s", x_mapout(x_prefix3));
1368 #endif /* OS2 */
1369 shprintf("%s = ", x_mapout(key));
1370 if (x_tab[prefix][key] != XFUNC_ins_string)
1371 shprintf("%s\n", x_ftab[x_tab[prefix][key]].xf_name);
1372 else
1373 shprintf("'%s'\n", x_atab[prefix][key]);
1374 }
1375
1376 int
1377 x_bind(a1, a2, macro, list)
1378 const char *a1, *a2;
1379 int macro; /* bind -m */
1380 int list; /* bind -l */
1381 {
1382 Findex f;
1383 int prefix, key;
1384 char *sp = NULL;
1385 char *m1, *m2;
1386
1387 if (x_tab == NULL) {
1388 bi_errorf("cannot bind, not a tty");
1389 return 1;
1390 }
1391
1392 /* List function names */
1393 if (list) {
1394 for (f = 0; f < NELEM(x_ftab); f++)
1395 if (x_ftab[f].xf_name
1396 && !(x_ftab[f].xf_flags & XF_NOBIND))
1397 shprintf("%s\n", x_ftab[f].xf_name);
1398 return 0;
1399 }
1400
1401 if (a1 == NULL) {
1402 for (prefix = 0; prefix < X_NTABS; prefix++)
1403 for (key = 0; key < X_TABSZ; key++) {
1404 f = x_tab[prefix][key];
1405 if (f == XFUNC_insert || f == XFUNC_error
1406 || (macro && f != XFUNC_ins_string))
1407 continue;
1408 x_print(prefix, key);
1409 }
1410 return 0;
1411 }
1412
1413 m1 = x_mapin(a1);
1414 prefix = key = 0;
1415 for (;; m1++) {
1416 key = *m1 & CHARMASK;
1417 if (x_tab[prefix][key] == XFUNC_meta1)
1418 prefix = 1;
1419 else if (x_tab[prefix][key] == XFUNC_meta2)
1420 prefix = 2;
1421 #ifdef OS2
1422 else if (x_tab[prefix][key] == XFUNC_meta3)
1423 prefix = 3;
1424 #endif /* OS2 */
1425 else
1426 break;
1427 }
1428
1429 if (a2 == NULL) {
1430 x_print(prefix, key);
1431 return 0;
1432 }
1433
1434 if (*a2 == 0)
1435 f = XFUNC_insert;
1436 else if (!macro) {
1437 for (f = 0; f < NELEM(x_ftab); f++)
1438 if (x_ftab[f].xf_name
1439 && strcmp(x_ftab[f].xf_name, a2) == 0)
1440 break;
1441 if (f == NELEM(x_ftab) || x_ftab[f].xf_flags & XF_NOBIND) {
1442 bi_errorf("%s: no such function", a2);
1443 return 1;
1444 }
1445 #if 0 /* This breaks the bind commands that map arrow keys */
1446 if (f == XFUNC_meta1)
1447 x_prefix1 = key;
1448 if (f == XFUNC_meta2)
1449 x_prefix2 = key;
1450 #endif /* 0 */
1451 } else {
1452 f = XFUNC_ins_string;
1453 m2 = x_mapin(a2);
1454 sp = str_save(m2, AEDIT);
1455 }
1456
1457 if (x_tab[prefix][key] == XFUNC_ins_string && x_atab[prefix][key])
1458 afree((void *)x_atab[prefix][key], AEDIT);
1459 x_tab[prefix][key] = f;
1460 x_atab[prefix][key] = sp;
1461
1462 return 0;
1463 }
1464
1465 void
1466 x_init_emacs()
1467 {
1468 register int i, j;
1469
1470 ainit(AEDIT);
1471 x_nextcmd = -1;
1472
1473 x_tab = (Findex (*)[X_TABSZ]) alloc(sizeofN(*x_tab, X_NTABS), AEDIT);
1474 for (j = 0; j < X_TABSZ; j++)
1475 x_tab[0][j] = XFUNC_insert;
1476 for (i = 1; i < X_NTABS; i++)
1477 for (j = 0; j < X_TABSZ; j++)
1478 x_tab[i][j] = XFUNC_error;
1479 for (i = 0; i < NELEM(x_defbindings); i++)
1480 x_tab[x_defbindings[i].xdb_tab][x_defbindings[i].xdb_char]
1481 = x_defbindings[i].xdb_func;
1482
1483 x_atab = (char *(*)[X_TABSZ]) alloc(sizeofN(*x_atab, X_NTABS), AEDIT);
1484 for (i = 1; i < X_NTABS; i++)
1485 for (j = 0; j < X_TABSZ; j++)
1486 x_atab[i][j] = NULL;
1487 }
1488
1489 void
1490 x_emacs_keys(ec)
1491 X_chars *ec;
1492 {
1493 x_tab[0][ec->erase] = XFUNC_del_back;
1494 x_tab[0][ec->kill] = XFUNC_del_line;
1495 x_tab[0][ec->werase] = XFUNC_del_bword;
1496 x_tab[0][ec->intr] = XFUNC_abort;
1497 x_tab[0][ec->quit] = XFUNC_noop;
1498 x_tab[1][ec->erase] = XFUNC_del_bword;
1499 }
1500
1501 static int
1502 x_set_mark(c)
1503 int c;
1504 {
1505 xmp = xcp;
1506 return KSTD;
1507 }
1508
1509 static int
1510 x_kill_region(c)
1511 int c;
1512 {
1513 int rsize;
1514 char *xr;
1515
1516 if (xmp == NULL) {
1517 x_e_putc(BEL);
1518 return KSTD;
1519 }
1520 if (xmp > xcp) {
1521 rsize = xmp - xcp;
1522 xr = xcp;
1523 } else {
1524 rsize = xcp - xmp;
1525 xr = xmp;
1526 }
1527 x_goto(xr);
1528 x_delete(rsize, TRUE);
1529 xmp = xr;
1530 return KSTD;
1531 }
1532
1533 static int
1534 x_xchg_point_mark(c)
1535 int c;
1536 {
1537 char *tmp;
1538
1539 if (xmp == NULL) {
1540 x_e_putc(BEL);
1541 return KSTD;
1542 }
1543 tmp = xmp;
1544 xmp = xcp;
1545 x_goto( tmp );
1546 return KSTD;
1547 }
1548
1549 static int
1550 x_version(c)
1551 int c;
1552 {
1553 char *o_xbuf = xbuf, *o_xend = xend;
1554 char *o_xbp = xbp, *o_xep = xep, *o_xcp = xcp;
1555 int lim = x_lastcp() - xbp;
1556
1557 xbuf = xbp = xcp = (char *) ksh_version + 4;
1558 xend = xep = (char *) ksh_version + 4 + strlen(ksh_version + 4);
1559 x_redraw(lim);
1560 x_flush();
1561
1562 c = x_e_getc();
1563 xbuf = o_xbuf;
1564 xend = o_xend;
1565 xbp = o_xbp;
1566 xep = o_xep;
1567 xcp = o_xcp;
1568 x_redraw(strlen(ksh_version));
1569
1570 if (c < 0)
1571 return KSTD;
1572 /* This is what at&t ksh seems to do... Very bizarre */
1573 if (c != ' ')
1574 x_e_ungetc(c);
1575
1576 return KSTD;
1577 }
1578
1579 static int
1580 x_noop(c)
1581 int c;
1582 {
1583 return KSTD;
1584 }
1585
1586 #ifdef SILLY
1587 static int
1588 x_game_of_life(c)
1589 int c;
1590 {
1591 char newbuf [256+1];
1592 register char *ip, *op;
1593 int i, len;
1594
1595 i = xep - xbuf;
1596 *xep = 0;
1597 len = x_size_str(xbuf);
1598 xcp = xbp = xbuf;
1599 memmove(newbuf+1, xbuf, i);
1600 newbuf[0] = 'A';
1601 newbuf[i] = 'A';
1602 for (ip = newbuf+1, op = xbuf; --i >= 0; ip++, op++) {
1603 /* Empty space */
1604 if (*ip < '@' || *ip == '_' || *ip == 0x7F) {
1605 /* Two adults, make whoopee */
1606 if (ip[-1] < '_' && ip[1] < '_') {
1607 /* Make kid look like parents. */
1608 *op = '`' + ((ip[-1] + ip[1])/2)%32;
1609 if (*op == 0x7F) /* Birth defect */
1610 *op = '`';
1611 }
1612 else
1613 *op = ' '; /* nothing happens */
1614 continue;
1615 }
1616 /* Child */
1617 if (*ip > '`') {
1618 /* All alone, dies */
1619 if (ip[-1] == ' ' && ip[1] == ' ')
1620 *op = ' ';
1621 else /* Gets older */
1622 *op = *ip-'`'+'@';
1623 continue;
1624 }
1625 /* Adult */
1626 /* Overcrowded, dies */
1627 if (ip[-1] >= '@' && ip[1] >= '@') {
1628 *op = ' ';
1629 continue;
1630 }
1631 *op = *ip;
1632 }
1633 *op = 0;
1634 x_redraw(len);
1635 return KSTD;
1636 }
1637 #endif
1638
1639 /*
1640 * File/command name completion routines
1641 */
1642
1643
1644 static int
1645 x_comp_comm(c)
1646 int c;
1647 {
1648 do_complete(XCF_COMMAND, CT_COMPLETE);
1649 return KSTD;
1650 }
1651 static int
1652 x_list_comm(c)
1653 int c;
1654 {
1655 do_complete(XCF_COMMAND, CT_LIST);
1656 return KSTD;
1657 }
1658 static int
1659 x_complete(c)
1660 int c;
1661 {
1662 do_complete(XCF_COMMAND_FILE, CT_COMPLETE);
1663 return KSTD;
1664 }
1665 static int
1666 x_enumerate(c)
1667 int c;
1668 {
1669 do_complete(XCF_COMMAND_FILE, CT_LIST);
1670 return KSTD;
1671 }
1672 static int
1673 x_comp_file(c)
1674 int c;
1675 {
1676 do_complete(XCF_FILE, CT_COMPLETE);
1677 return KSTD;
1678 }
1679 static int
1680 x_list_file(c)
1681 int c;
1682 {
1683 do_complete(XCF_FILE, CT_LIST);
1684 return KSTD;
1685 }
1686 static int
1687 x_comp_list(c)
1688 int c;
1689 {
1690 do_complete(XCF_COMMAND_FILE, CT_COMPLIST);
1691 return KSTD;
1692 }
1693 static int
1694 x_expand(c)
1695 int c;
1696 {
1697 char **words;
1698 int nwords = 0;
1699 int start, end;
1700 int is_command;
1701 int i;
1702
1703 nwords = x_cf_glob(XCF_FILE,
1704 xbuf, xep - xbuf, xcp - xbuf,
1705 &start, &end, &words, &is_command);
1706
1707 if (nwords == 0) {
1708 x_e_putc(BEL);
1709 return KSTD;
1710 }
1711
1712 x_goto(xbuf + start);
1713 x_delete(end - start, FALSE);
1714 for (i = 0; i < nwords; i++)
1715 if (x_ins(words[i]) < 0 || (i < nwords - 1 && x_ins(space) < 0))
1716 {
1717 x_e_putc(BEL);
1718 return KSTD;
1719 }
1720
1721 return KSTD;
1722 }
1723
1724 /* type == 0 for list, 1 for complete and 2 for complete-list */
1725 static void
1726 do_complete(flags, type)
1727 int flags; /* XCF_{COMMAND,FILE,COMMAND_FILE} */
1728 Comp_type type;
1729 {
1730 char **words;
1731 int nwords = 0;
1732 int start, end;
1733 int is_command;
1734 int do_glob = 1;
1735 Comp_type t = type;
1736 char *comp_word = (char *) 0;
1737
1738 if (type == CT_COMPLIST) {
1739 do_glob = 0;
1740 /* decide what we will do */
1741 nwords = x_cf_glob(flags,
1742 xbuf, xep - xbuf, xcp - xbuf,
1743 &start, &end, &words, &is_command);
1744 if (nwords > 0) {
1745 if (nwords > 1) {
1746 int len = x_longest_prefix(nwords, words);
1747
1748 t = CT_LIST;
1749 /* Do completion if prefix matches original
1750 * prefix (ie, no globbing chars), otherwise
1751 * don't bother
1752 */
1753 if (strncmp(words[0], xbuf + start, end - start)
1754 == 0)
1755 comp_word = str_nsave(words[0], len,
1756 ATEMP);
1757 else
1758 type = CT_LIST;
1759 /* Redo globing to show full paths if this
1760 * is a command.
1761 */
1762 if (is_command) {
1763 do_glob = 1;
1764 x_free_words(nwords, words);
1765 }
1766 } else
1767 type = t = CT_COMPLETE;
1768 }
1769 }
1770 if (do_glob)
1771 nwords = x_cf_glob(flags | (t == CT_LIST ? XCF_FULLPATH : 0),
1772 xbuf, xep - xbuf, xcp - xbuf,
1773 &start, &end, &words, &is_command);
1774 if (nwords == 0) {
1775 x_e_putc(BEL);
1776 return;
1777 }
1778 switch (type) {
1779 case CT_LIST:
1780 x_print_expansions(nwords, words, is_command);
1781 x_redraw(0);
1782 break;
1783
1784 case CT_COMPLIST:
1785 /* Only get here if nwords > 1 && comp_word is set */
1786 {
1787 int olen = end - start;
1788 int nlen = strlen(comp_word);
1789
1790 x_print_expansions(nwords, words, is_command);
1791 xcp = xbuf + end;
1792 x_do_ins(comp_word + olen, nlen - olen);
1793 x_redraw(0);
1794 }
1795 break;
1796
1797 case CT_COMPLETE:
1798 {
1799 int nlen = x_longest_prefix(nwords, words);
1800
1801 if (nlen > 0) {
1802 x_goto(xbuf + start);
1803 x_delete(end - start, FALSE);
1804 words[0][nlen] = '\0';
1805 x_ins(words[0]);
1806 /* If single match is not a directory, add a
1807 * space to the end...
1808 */
1809 if (nwords == 1
1810 && !ISDIRSEP(words[0][nlen - 1]))
1811 x_ins(space);
1812 } else
1813 x_e_putc(BEL);
1814 }
1815 break;
1816 }
1817 }
1818
1819 /* NAME:
1820 * x_adjust - redraw the line adjusting starting point etc.
1821 *
1822 * DESCRIPTION:
1823 * This function is called when we have exceeded the bounds
1824 * of the edit window. It increments x_adj_done so that
1825 * functions like x_ins and x_delete know that we have been
1826 * called and can skip the x_bs() stuff which has already
1827 * been done by x_redraw.
1828 *
1829 * RETURN VALUE:
1830 * None
1831 */
1832
1833 static void
1834 x_adjust()
1835 {
1836 x_adj_done++; /* flag the fact that we were called. */
1837 /*
1838 * we had a problem if the prompt length > xx_cols / 2
1839 */
1840 if ((xbp = xcp - (x_displen / 2)) < xbuf)
1841 xbp = xbuf;
1842 xlp_valid = FALSE;
1843 x_redraw(xx_cols);
1844 x_flush();
1845 }
1846
1847 static int unget_char = -1;
1848
1849 static void
1850 x_e_ungetc(c)
1851 int c;
1852 {
1853 unget_char = c;
1854 }
1855
1856 static int
1857 x_e_getc()
1858 {
1859 int c;
1860
1861 if (unget_char >= 0) {
1862 c = unget_char;
1863 unget_char = -1;
1864 } else {
1865 if (macroptr) {
1866 c = *macroptr++;
1867 if (!*macroptr)
1868 macroptr = (char *) 0;
1869 } else
1870 c = x_getc();
1871 }
1872
1873 return c <= CHARMASK ? c : (c & CHARMASK);
1874 }
1875
1876 static void
1877 x_e_putc(c)
1878 int c;
1879 {
1880 if (c == '\r' || c == '\n')
1881 x_col = 0;
1882 if (x_col < xx_cols)
1883 {
1884 x_putc(c);
1885 switch(c)
1886 {
1887 case BEL:
1888 break;
1889 case '\r':
1890 case '\n':
1891 break;
1892 case '\b':
1893 x_col--;
1894 break;
1895 default:
1896 x_col++;
1897 break;
1898 }
1899 }
1900 if (x_adj_ok && (x_col < 0 || x_col >= (xx_cols - 2)))
1901 {
1902 x_adjust();
1903 }
1904 }
1905
1906 #ifdef DEBUG
1907 static int
1908 x_debug_info(c)
1909 int c;
1910 {
1911 x_flush();
1912 shellf("\nksh debug:\n");
1913 shellf("\tx_col == %d,\t\tx_cols == %d,\tx_displen == %d\n",
1914 x_col, xx_cols, x_displen);
1915 shellf("\txcp == 0x%lx,\txep == 0x%lx\n", (long) xcp, (long) xep);
1916 shellf("\txbp == 0x%lx,\txbuf == 0x%lx\n", (long) xbp, (long) xbuf);
1917 shellf("\txlp == 0x%lx\n", (long) xlp);
1918 shellf("\txlp == 0x%lx\n", (long) x_lastcp());
1919 shellf(newline);
1920 x_redraw(-1);
1921 return 0;
1922 }
1923 #endif
1924
1925 static void
1926 x_e_puts(s)
1927 const char *s;
1928 {
1929 register int adj = x_adj_done;
1930
1931 while (*s && adj == x_adj_done)
1932 x_e_putc(*s++);
1933 }
1934
1935 /* NAME:
1936 * x_set_arg - set an arg value for next function
1937 *
1938 * DESCRIPTION:
1939 * This is a simple implementation of M-[0-9].
1940 *
1941 * RETURN VALUE:
1942 * KSTD
1943 */
1944
1945 static int
1946 x_set_arg(c)
1947 int c;
1948 {
1949 int n = 0;
1950 int first = 1;
1951
1952 c &= CHARMASK; /* strip command prefix */
1953 for (; c >= 0 && isdigit(c); c = x_e_getc(), first = 0)
1954 n = n * 10 + (c - '0');
1955 if (c < 0 || first) {
1956 x_e_putc(BEL);
1957 x_arg = 1;
1958 x_arg_defaulted = 1;
1959 } else {
1960 x_e_ungetc(c);
1961 x_arg = n;
1962 x_arg_defaulted = 0;
1963 }
1964 return KSTD;
1965 }
1966
1967
1968 /* Comment or uncomment the current line. */
1969 static int
1970 x_comment(c)
1971 int c;
1972 {
1973 int oldsize = x_size_str(xbuf);
1974 int len = xep - xbuf;
1975 int ret = x_do_comment(xbuf, xend - xbuf, &len);
1976
1977 if (ret < 0)
1978 x_e_putc(BEL);
1979 else {
1980 xep = xbuf + len;
1981 *xep = '\0';
1982 xcp = xbp = xbuf;
1983 x_redraw(oldsize);
1984 if (ret > 0)
1985 return x_newline('\n');
1986 }
1987 return KSTD;
1988 }
1989
1990
1991 /* NAME:
1992 * x_prev_histword - recover word from prev command
1993 *
1994 * DESCRIPTION:
1995 * This function recovers the last word from the previous
1996 * command and inserts it into the current edit line. If a
1997 * numeric arg is supplied then the n'th word from the
1998 * start of the previous command is used.
1999 *
2000 * Bound to M-.
2001 *
2002 * RETURN VALUE:
2003 * KSTD
2004 */
2005
2006 static int
2007 x_prev_histword(c)
2008 int c;
2009 {
2010 register char *rcp;
2011 char *cp;
2012 char **hp;
2013
2014 hp = x_histp-1;
2015 if (hp < history || hp > histptr)
2016 {
2017 x_e_putc(BEL);
2018 return KSTD;
2019 }
2020 cp = *hp;
2021 if (x_arg_defaulted) {
2022 rcp = &cp[strlen(cp) - 1];
2023 /*
2024 * ignore white-space after the last word
2025 */
2026 while (rcp > cp && is_cfs(*rcp))
2027 rcp--;
2028 while (rcp > cp && !is_cfs(*rcp))
2029 rcp--;
2030 if (is_cfs(*rcp))
2031 rcp++;
2032 x_ins(rcp);
2033 } else {
2034 int c;
2035
2036 rcp = cp;
2037 /*
2038 * ignore white-space at start of line
2039 */
2040 while (*rcp && is_cfs(*rcp))
2041 rcp++;
2042 while (x_arg-- > 1)
2043 {
2044 while (*rcp && !is_cfs(*rcp))
2045 rcp++;
2046 while (*rcp && is_cfs(*rcp))
2047 rcp++;
2048 }
2049 cp = rcp;
2050 while (*rcp && !is_cfs(*rcp))
2051 rcp++;
2052 c = *rcp;
2053 *rcp = '\0';
2054 x_ins(cp);
2055 *rcp = c;
2056 }
2057 return KSTD;
2058 }
2059
2060 /* Uppercase N(1) words */
2061 static int
2062 x_fold_upper(c)
2063 int c;
2064 {
2065 return x_fold_case('U');
2066 }
2067
2068 /* Lowercase N(1) words */
2069 static int
2070 x_fold_lower(c)
2071 int c;
2072 {
2073 return x_fold_case('L');
2074 }
2075
2076 /* Lowercase N(1) words */
2077 static int
2078 x_fold_capitialize(c)
2079 int c;
2080 {
2081 return x_fold_case('C');
2082 }
2083
2084 /* NAME:
2085 * x_fold_case - convert word to UPPER/lower/Capitial case
2086 *
2087 * DESCRIPTION:
2088 * This function is used to implement M-U,M-u,M-L,M-l,M-C and M-c
2089 * to UPPER case, lower case or Capitalize words.
2090 *
2091 * RETURN VALUE:
2092 * None
2093 */
2094
2095 static int
2096 x_fold_case(c)
2097 int c;
2098 {
2099 char *cp = xcp;
2100
2101 if (cp == xep) {
2102 x_e_putc(BEL);
2103 return KSTD;
2104 }
2105 while (x_arg--) {
2106 /*
2107 * fisrt skip over any white-space
2108 */
2109 while (cp != xep && is_mfs(*cp))
2110 cp++;
2111 /*
2112 * do the first char on its own since it may be
2113 * a different action than for the rest.
2114 */
2115 if (cp != xep) {
2116 if (c == 'L') { /* lowercase */
2117 if (isupper(*cp))
2118 *cp = tolower(*cp);
2119 } else { /* uppercase, capitialize */
2120 if (islower(*cp))
2121 *cp = toupper(*cp);
2122 }
2123 cp++;
2124 }
2125 /*
2126 * now for the rest of the word
2127 */
2128 while (cp != xep && !is_mfs(*cp)) {
2129 if (c == 'U') { /* uppercase */
2130 if (islower(*cp))
2131 *cp = toupper(*cp);
2132 } else { /* lowercase, capitialize */
2133 if (isupper(*cp))
2134 *cp = tolower(*cp);
2135 }
2136 cp++;
2137 }
2138 }
2139 x_goto(cp);
2140 return KSTD;
2141 }
2142
2143 /* NAME:
2144 * x_lastcp - last visible char
2145 *
2146 * SYNOPSIS:
2147 * x_lastcp()
2148 *
2149 * DESCRIPTION:
2150 * This function returns a pointer to that char in the
2151 * edit buffer that will be the last displayed on the
2152 * screen. The sequence:
2153 *
2154 * for (cp = x_lastcp(); cp > xcp; cp)
2155 * x_bs(*--cp);
2156 *
2157 * Will position the cursor correctly on the screen.
2158 *
2159 * RETURN VALUE:
2160 * cp or NULL
2161 */
2162
2163 static char *
2164 x_lastcp()
2165 {
2166 register char *rcp;
2167 register int i;
2168
2169 if (!xlp_valid)
2170 {
2171 for (i = 0, rcp = xbp; rcp < xep && i < x_displen; rcp++)
2172 i += x_size(*rcp);
2173 xlp = rcp;
2174 }
2175 xlp_valid = TRUE;
2176 return (xlp);
2177 }
2178
2179 #endif /* EDIT */
2180