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