1*abe76290Smillert /* $OpenBSD: emacs.c,v 1.90 2023/06/21 22:22:08 millert Exp $ */
27cb960a2Sdownsj
37cb960a2Sdownsj /*
47cb960a2Sdownsj * Emacs-like command line editing and history
57cb960a2Sdownsj *
67cb960a2Sdownsj * created by Ron Natalie at BRL
77cb960a2Sdownsj * modified by Doug Kingston, Doug Gwyn, and Lou Salkind
87cb960a2Sdownsj * adapted to PD ksh by Eric Gisin
9c250457eSdjm *
10c250457eSdjm * partial rewrite by Marco Peereboom <marco@openbsd.org>
11c250457eSdjm * under the same license
127cb960a2Sdownsj */
137cb960a2Sdownsj
147cb960a2Sdownsj #include "config.h"
157cb960a2Sdownsj #ifdef EMACS
167cb960a2Sdownsj
17c250457eSdjm #include <sys/queue.h>
18b608f594Smmcc #include <sys/stat.h>
19b608f594Smmcc
207cb960a2Sdownsj #include <ctype.h>
214a010e0cStb #include <stdio.h>
224a010e0cStb #include <stdlib.h>
2356018212Smmcc #include <string.h>
24a3c80d85Smillert #ifndef SMALL
25a3c80d85Smillert # include <term.h>
26a3c80d85Smillert # include <curses.h>
27a3c80d85Smillert #endif
28b608f594Smmcc
29b608f594Smmcc #include "sh.h"
307cb960a2Sdownsj #include "edit.h"
317cb960a2Sdownsj
327cb960a2Sdownsj static Area aedit;
337cb960a2Sdownsj #define AEDIT &aedit /* area for kill ring and macro defns */
347cb960a2Sdownsj
357cb960a2Sdownsj /* values returned by keyboard functions */
367cb960a2Sdownsj #define KSTD 0
377cb960a2Sdownsj #define KEOL 1 /* ^M, ^J */
387cb960a2Sdownsj #define KINTR 2 /* ^G, ^C */
397cb960a2Sdownsj
4028297e90Sjca typedef int (*kb_func)(int);
4128297e90Sjca
427cb960a2Sdownsj struct x_ftab {
4328297e90Sjca kb_func xf_func;
447cb960a2Sdownsj const char *xf_name;
457cb960a2Sdownsj short xf_flags;
467cb960a2Sdownsj };
477cb960a2Sdownsj
487cb960a2Sdownsj #define XF_ARG 1 /* command takes number prefix */
497cb960a2Sdownsj #define XF_NOBIND 2 /* not allowed to bind to function */
507cb960a2Sdownsj #define XF_PREFIX 4 /* function sets prefix */
517cb960a2Sdownsj
527cb960a2Sdownsj /* Separator for completion */
537cb960a2Sdownsj #define is_cfs(c) (c == ' ' || c == '\t' || c == '"' || c == '\'')
54e569fc7cSderaadt
55e569fc7cSderaadt /* Separator for motion */
569b414e55Sschwarze #define is_mfs(c) (!(isalnum((unsigned char)c) || \
579b414e55Sschwarze c == '_' || c == '$' || c & 0x80))
587cb960a2Sdownsj
597cb960a2Sdownsj /* Arguments for do_complete()
607cb960a2Sdownsj * 0 = enumerate M-= complete as much as possible and then list
617cb960a2Sdownsj * 1 = complete M-Esc
627cb960a2Sdownsj * 2 = list M-?
637cb960a2Sdownsj */
64b3b39737Sderaadt typedef enum {
65b3b39737Sderaadt CT_LIST, /* list the possible completions */
667cb960a2Sdownsj CT_COMPLETE, /* complete to longest prefix */
677cb960a2Sdownsj CT_COMPLIST /* complete and then list (if non-exact) */
687cb960a2Sdownsj } Comp_type;
697cb960a2Sdownsj
70c250457eSdjm /* keybindings */
71c250457eSdjm struct kb_entry {
72c250457eSdjm TAILQ_ENTRY(kb_entry) entry;
73c250457eSdjm unsigned char *seq;
74c250457eSdjm int len;
75c250457eSdjm struct x_ftab *ftab;
76c250457eSdjm void *args;
77c250457eSdjm };
78c250457eSdjm TAILQ_HEAD(kb_list, kb_entry);
79c250457eSdjm struct kb_list kblist = TAILQ_HEAD_INITIALIZER(kblist);
80c250457eSdjm
817cb960a2Sdownsj /* { from 4.9 edit.h */
827cb960a2Sdownsj /*
837cb960a2Sdownsj * The following are used for my horizontal scrolling stuff
847cb960a2Sdownsj */
857cb960a2Sdownsj static char *xbuf; /* beg input buffer */
867cb960a2Sdownsj static char *xend; /* end input buffer */
877cb960a2Sdownsj static char *xcp; /* current position */
887cb960a2Sdownsj static char *xep; /* current end */
897cb960a2Sdownsj static char *xbp; /* start of visible portion of input buffer */
905cc68a1dSschwarze static char *xlp; /* last byte visible on screen */
917cb960a2Sdownsj static int x_adj_ok;
927cb960a2Sdownsj /*
937cb960a2Sdownsj * we use x_adj_done so that functions can tell
947cb960a2Sdownsj * whether x_adjust() has been called while they are active.
957cb960a2Sdownsj */
967cb960a2Sdownsj static int x_adj_done;
977cb960a2Sdownsj
98dcacb757Sdownsj static int xx_cols;
997cb960a2Sdownsj static int x_col;
1007cb960a2Sdownsj static int x_displen;
1017cb960a2Sdownsj static int x_arg; /* general purpose arg */
1027cb960a2Sdownsj static int x_arg_defaulted;/* x_arg not explicitly set; defaulted to 1 */
1037cb960a2Sdownsj
1047cb960a2Sdownsj static int xlp_valid;
1057cb960a2Sdownsj /* end from 4.9 edit.h } */
106c250457eSdjm static int x_tty; /* are we on a tty? */
107c250457eSdjm static int x_bind_quiet; /* be quiet when binding keys */
108c250457eSdjm static int (*x_last_command)(int);
1097cb960a2Sdownsj
1107cb960a2Sdownsj static char **x_histp; /* history position */
1117cb960a2Sdownsj static int x_nextcmd; /* for newline-and-next */
1127cb960a2Sdownsj static char *xmp; /* mark pointer */
1137cb960a2Sdownsj #define KILLSIZE 20
1147cb960a2Sdownsj static char *killstack[KILLSIZE];
1157cb960a2Sdownsj static int killsp, killtp;
116c250457eSdjm static int x_literal_set;
117c250457eSdjm static int x_arg_set;
11844d96bb9Smpi static char *macro_args;
1197cb960a2Sdownsj static int prompt_skip;
120638b9e76Sbeck static int prompt_redraw;
1217cb960a2Sdownsj
122c5d5393cSotto static int x_ins(char *);
123c5d5393cSotto static void x_delete(int, int);
12469b9f96bSmillert static int x_bword(void);
12569b9f96bSmillert static int x_fword(void);
126c5d5393cSotto static void x_goto(char *);
127c5d5393cSotto static void x_bs(int);
128c5d5393cSotto static int x_size_str(char *);
129c5d5393cSotto static int x_size(int);
130c5d5393cSotto static void x_zots(char *);
131c5d5393cSotto static void x_zotc(int);
132c5d5393cSotto static void x_load_hist(char **);
133c5d5393cSotto static int x_search(char *, int, int);
134c5d5393cSotto static int x_match(char *, char *);
135c5d5393cSotto static void x_redraw(int);
136c5d5393cSotto static void x_push(int);
13769b9f96bSmillert static void x_adjust(void);
138c5d5393cSotto static void x_e_ungetc(int);
13969b9f96bSmillert static int x_e_getc(void);
1408a9faaaaSanton static int x_e_getu8(char *, int);
141c5d5393cSotto static void x_e_putc(int);
142c5d5393cSotto static void x_e_puts(const char *);
143c5d5393cSotto static int x_comment(int);
144c5d5393cSotto static int x_fold_case(int);
14569b9f96bSmillert static char *x_lastcp(void);
146c5d5393cSotto static void do_complete(int, Comp_type);
1475cc68a1dSschwarze static int isu8cont(unsigned char);
1487cb960a2Sdownsj
149c250457eSdjm /* proto's for keybindings */
150c250457eSdjm static int x_abort(int);
151c250457eSdjm static int x_beg_hist(int);
152a3c80d85Smillert static int x_clear_screen(int);
153c250457eSdjm static int x_comp_comm(int);
154c250457eSdjm static int x_comp_file(int);
155c250457eSdjm static int x_complete(int);
156c250457eSdjm static int x_del_back(int);
157c250457eSdjm static int x_del_bword(int);
158c250457eSdjm static int x_del_char(int);
159c250457eSdjm static int x_del_fword(int);
160c250457eSdjm static int x_del_line(int);
161c250457eSdjm static int x_draw_line(int);
162c250457eSdjm static int x_end_hist(int);
163c250457eSdjm static int x_end_of_text(int);
164c250457eSdjm static int x_enumerate(int);
165c250457eSdjm static int x_eot_del(int);
166c250457eSdjm static int x_error(int);
167c250457eSdjm static int x_goto_hist(int);
168c250457eSdjm static int x_ins_string(int);
169c250457eSdjm static int x_insert(int);
170c250457eSdjm static int x_kill(int);
171c250457eSdjm static int x_kill_region(int);
172c250457eSdjm static int x_list_comm(int);
173c250457eSdjm static int x_list_file(int);
174c250457eSdjm static int x_literal(int);
175c250457eSdjm static int x_meta_yank(int);
176c250457eSdjm static int x_mv_back(int);
177c250457eSdjm static int x_mv_begin(int);
178c250457eSdjm static int x_mv_bword(int);
179c250457eSdjm static int x_mv_end(int);
180c250457eSdjm static int x_mv_forw(int);
181c250457eSdjm static int x_mv_fword(int);
182c250457eSdjm static int x_newline(int);
183c250457eSdjm static int x_next_com(int);
184c250457eSdjm static int x_nl_next_com(int);
185c250457eSdjm static int x_noop(int);
186c250457eSdjm static int x_prev_com(int);
187c250457eSdjm static int x_prev_histword(int);
188c250457eSdjm static int x_search_char_forw(int);
189c250457eSdjm static int x_search_char_back(int);
190c250457eSdjm static int x_search_hist(int);
191c250457eSdjm static int x_set_mark(int);
192c250457eSdjm static int x_transpose(int);
193c250457eSdjm static int x_xchg_point_mark(int);
194c250457eSdjm static int x_yank(int);
195c250457eSdjm static int x_comp_list(int);
196c250457eSdjm static int x_expand(int);
197c250457eSdjm static int x_fold_capitalize(int);
198c250457eSdjm static int x_fold_lower(int);
199c250457eSdjm static int x_fold_upper(int);
200c250457eSdjm static int x_set_arg(int);
201c250457eSdjm static int x_comment(int);
202c250457eSdjm #ifdef DEBUG
203c250457eSdjm static int x_debug_info(int);
204c250457eSdjm #endif
2057cb960a2Sdownsj
2067cb960a2Sdownsj static const struct x_ftab x_ftab[] = {
2077cb960a2Sdownsj { x_abort, "abort", 0 },
2087cb960a2Sdownsj { x_beg_hist, "beginning-of-history", 0 },
209a3c80d85Smillert { x_clear_screen, "clear-screen", 0 },
2107cb960a2Sdownsj { x_comp_comm, "complete-command", 0 },
2117cb960a2Sdownsj { x_comp_file, "complete-file", 0 },
2127cb960a2Sdownsj { x_complete, "complete", 0 },
2137cb960a2Sdownsj { x_del_back, "delete-char-backward", XF_ARG },
2147cb960a2Sdownsj { x_del_bword, "delete-word-backward", XF_ARG },
2157cb960a2Sdownsj { x_del_char, "delete-char-forward", XF_ARG },
2167cb960a2Sdownsj { x_del_fword, "delete-word-forward", XF_ARG },
2177cb960a2Sdownsj { x_del_line, "kill-line", 0 },
2187cb960a2Sdownsj { x_draw_line, "redraw", 0 },
2197cb960a2Sdownsj { x_end_hist, "end-of-history", 0 },
2207cb960a2Sdownsj { x_end_of_text, "eot", 0 },
2217cb960a2Sdownsj { x_enumerate, "list", 0 },
2227cb960a2Sdownsj { x_eot_del, "eot-or-delete", XF_ARG },
2237cb960a2Sdownsj { x_error, "error", 0 },
2247cb960a2Sdownsj { x_goto_hist, "goto-history", XF_ARG },
2257cb960a2Sdownsj { x_ins_string, "macro-string", XF_NOBIND },
2267cb960a2Sdownsj { x_insert, "auto-insert", XF_ARG },
2277cb960a2Sdownsj { x_kill, "kill-to-eol", XF_ARG },
2287cb960a2Sdownsj { x_kill_region, "kill-region", 0 },
2297cb960a2Sdownsj { x_list_comm, "list-command", 0 },
2307cb960a2Sdownsj { x_list_file, "list-file", 0 },
2317cb960a2Sdownsj { x_literal, "quote", 0 },
2327cb960a2Sdownsj { x_meta_yank, "yank-pop", 0 },
2337cb960a2Sdownsj { x_mv_back, "backward-char", XF_ARG },
2347cb960a2Sdownsj { x_mv_begin, "beginning-of-line", 0 },
2357cb960a2Sdownsj { x_mv_bword, "backward-word", XF_ARG },
2367cb960a2Sdownsj { x_mv_end, "end-of-line", 0 },
2377cb960a2Sdownsj { x_mv_forw, "forward-char", XF_ARG },
2387cb960a2Sdownsj { x_mv_fword, "forward-word", XF_ARG },
2397cb960a2Sdownsj { x_newline, "newline", 0 },
2407cb960a2Sdownsj { x_next_com, "down-history", XF_ARG },
2417cb960a2Sdownsj { x_nl_next_com, "newline-and-next", 0 },
2427cb960a2Sdownsj { x_noop, "no-op", 0 },
2437cb960a2Sdownsj { x_prev_com, "up-history", XF_ARG },
2447cb960a2Sdownsj { x_prev_histword, "prev-hist-word", XF_ARG },
2457cb960a2Sdownsj { x_search_char_forw, "search-character-forward", XF_ARG },
2467cb960a2Sdownsj { x_search_char_back, "search-character-backward", XF_ARG },
2477cb960a2Sdownsj { x_search_hist, "search-history", 0 },
2487cb960a2Sdownsj { x_set_mark, "set-mark-command", 0 },
2497cb960a2Sdownsj { x_transpose, "transpose-chars", 0 },
2507cb960a2Sdownsj { x_xchg_point_mark, "exchange-point-and-mark", 0 },
2517cb960a2Sdownsj { x_yank, "yank", 0 },
2527cb960a2Sdownsj { x_comp_list, "complete-list", 0 },
2537cb960a2Sdownsj { x_expand, "expand-file", 0 },
254060cee32Sjmc { x_fold_capitalize, "capitalize-word", XF_ARG },
2557cb960a2Sdownsj { x_fold_lower, "downcase-word", XF_ARG },
2567cb960a2Sdownsj { x_fold_upper, "upcase-word", XF_ARG },
2577cb960a2Sdownsj { x_set_arg, "set-arg", XF_NOBIND },
258dcacb757Sdownsj { x_comment, "comment", 0 },
2597cb960a2Sdownsj { 0, 0, 0 },
2607cb960a2Sdownsj #ifdef DEBUG
2617cb960a2Sdownsj { x_debug_info, "debug-info", 0 },
2627cb960a2Sdownsj #else
2637cb960a2Sdownsj { 0, 0, 0 },
2647cb960a2Sdownsj #endif
2657cb960a2Sdownsj { 0, 0, 0 },
2667cb960a2Sdownsj };
2677cb960a2Sdownsj
2687cb960a2Sdownsj int
isu8cont(unsigned char c)2695cc68a1dSschwarze isu8cont(unsigned char c)
2705cc68a1dSschwarze {
2715cc68a1dSschwarze return (c & (0x80 | 0x40)) == 0x80;
2725cc68a1dSschwarze }
2735cc68a1dSschwarze
2745cc68a1dSschwarze int
x_emacs(char * buf,size_t len)275c5d5393cSotto x_emacs(char *buf, size_t len)
2767cb960a2Sdownsj {
277c250457eSdjm struct kb_entry *k, *kmatch = NULL;
278c250457eSdjm char line[LINE + 1];
2798a9faaaaSanton int at = 0, ntries = 0, submatch, ret;
2807cb960a2Sdownsj const char *p;
2817cb960a2Sdownsj
2827cb960a2Sdownsj xbp = xbuf = buf; xend = buf + len;
2837cb960a2Sdownsj xlp = xcp = xep = buf;
2847cb960a2Sdownsj *xcp = 0;
2850e7d3a01Smillert xlp_valid = true;
2867cb960a2Sdownsj xmp = NULL;
2877cb960a2Sdownsj x_histp = histptr + 1;
2887cb960a2Sdownsj
289dcacb757Sdownsj xx_cols = x_cols;
2907cb960a2Sdownsj x_col = promptlen(prompt, &p);
2917cb960a2Sdownsj prompt_skip = p - prompt;
2927cb960a2Sdownsj x_adj_ok = 1;
293638b9e76Sbeck prompt_redraw = 1;
294638b9e76Sbeck if (x_col > xx_cols)
295638b9e76Sbeck x_col = x_col - (x_col / xx_cols) * xx_cols;
296dcacb757Sdownsj x_displen = xx_cols - 2 - x_col;
2977cb960a2Sdownsj x_adj_done = 0;
2987cb960a2Sdownsj
2997cb960a2Sdownsj pprompt(prompt, 0);
300638b9e76Sbeck if (x_displen < 1) {
301638b9e76Sbeck x_col = 0;
302638b9e76Sbeck x_displen = xx_cols - 2;
303638b9e76Sbeck x_e_putc('\n');
304638b9e76Sbeck prompt_redraw = 0;
305638b9e76Sbeck }
3067cb960a2Sdownsj
3077cb960a2Sdownsj if (x_nextcmd >= 0) {
3087cb960a2Sdownsj int off = source->line - x_nextcmd;
3097cb960a2Sdownsj if (histptr - history >= off)
3107cb960a2Sdownsj x_load_hist(histptr - off);
3117cb960a2Sdownsj x_nextcmd = -1;
3127cb960a2Sdownsj }
3137cb960a2Sdownsj
314c250457eSdjm x_literal_set = 0;
315c250457eSdjm x_arg = -1;
316c250457eSdjm x_last_command = NULL;
3177cb960a2Sdownsj while (1) {
3187cb960a2Sdownsj x_flush();
3198a9faaaaSanton if ((at = x_e_getu8(line, at)) < 0)
3207cb960a2Sdownsj return 0;
3218a9faaaaSanton ntries++;
3226cef2a06Smillert
323c250457eSdjm if (x_arg == -1) {
3247cb960a2Sdownsj x_arg = 1;
3257cb960a2Sdownsj x_arg_defaulted = 1;
3267cb960a2Sdownsj }
327c250457eSdjm
328c250457eSdjm if (x_literal_set) {
329c250457eSdjm /* literal, so insert it */
330c250457eSdjm x_literal_set = 0;
331c250457eSdjm submatch = 0;
332c250457eSdjm } else {
333c250457eSdjm submatch = 0;
334c250457eSdjm kmatch = NULL;
335c250457eSdjm TAILQ_FOREACH(k, &kblist, entry) {
336c250457eSdjm if (at > k->len)
337c250457eSdjm continue;
338c250457eSdjm
33989253508Stedu if (memcmp(k->seq, line, at) == 0) {
340c250457eSdjm /* sub match */
341c250457eSdjm submatch++;
342c250457eSdjm if (k->len == at)
343c250457eSdjm kmatch = k;
344c250457eSdjm }
345c250457eSdjm
346c250457eSdjm /* see if we can abort search early */
347c250457eSdjm if (submatch > 1)
348c250457eSdjm break;
349c250457eSdjm }
350c250457eSdjm }
351c250457eSdjm
352c250457eSdjm if (submatch == 1 && kmatch) {
353c250457eSdjm if (kmatch->ftab->xf_func == x_ins_string &&
35444d96bb9Smpi kmatch->args && !macro_args) {
35544d96bb9Smpi /* treat macro string as input */
35644d96bb9Smpi macro_args = kmatch->args;
35744d96bb9Smpi ret = KSTD;
35844d96bb9Smpi } else
3598a9faaaaSanton ret = kmatch->ftab->xf_func(line[at - 1]);
360c250457eSdjm } else {
361c250457eSdjm if (submatch)
362c250457eSdjm continue;
3638a9faaaaSanton if (ntries > 1) {
3648a9faaaaSanton ret = x_error(0); /* unmatched meta sequence */
3658a9faaaaSanton } else if (at > 1) {
3668a9faaaaSanton x_ins(line);
3678a9faaaaSanton ret = KSTD;
3688a9faaaaSanton } else {
3698a9faaaaSanton ret = x_insert(line[0]);
3708a9faaaaSanton }
371c250457eSdjm }
372c250457eSdjm
373c250457eSdjm switch (ret) {
3747cb960a2Sdownsj case KSTD:
375c250457eSdjm if (kmatch)
376c250457eSdjm x_last_command = kmatch->ftab->xf_func;
377c250457eSdjm else
378c250457eSdjm x_last_command = NULL;
3797cb960a2Sdownsj break;
3807cb960a2Sdownsj case KEOL:
381c250457eSdjm ret = xep - xbuf;
382c250457eSdjm return (ret);
383c250457eSdjm break;
384c250457eSdjm case KINTR:
3857cb960a2Sdownsj trapsig(SIGINT);
3860e7d3a01Smillert x_mode(false);
3877cb960a2Sdownsj unwind(LSHELL);
388c250457eSdjm x_arg = -1;
389c250457eSdjm break;
390c250457eSdjm default:
391c250457eSdjm bi_errorf("invalid return code"); /* can't happen */
3927cb960a2Sdownsj }
393c250457eSdjm
394c250457eSdjm /* reset meta sequence */
3958a9faaaaSanton at = ntries = 0;
396c250457eSdjm if (x_arg_set)
397c250457eSdjm x_arg_set = 0; /* reset args next time around */
398c250457eSdjm else
399c250457eSdjm x_arg = -1;
4007cb960a2Sdownsj }
4017cb960a2Sdownsj }
4027cb960a2Sdownsj
4037cb960a2Sdownsj static int
x_insert(int c)404c5d5393cSotto x_insert(int c)
4057cb960a2Sdownsj {
4067cb960a2Sdownsj char str[2];
4077cb960a2Sdownsj
4087cb960a2Sdownsj /*
4097cb960a2Sdownsj * Should allow tab and control chars.
4107cb960a2Sdownsj */
4117cb960a2Sdownsj if (c == 0) {
4127cb960a2Sdownsj x_e_putc(BEL);
4137cb960a2Sdownsj return KSTD;
4147cb960a2Sdownsj }
4157cb960a2Sdownsj str[0] = c;
4167cb960a2Sdownsj str[1] = '\0';
4177cb960a2Sdownsj while (x_arg--)
4187cb960a2Sdownsj x_ins(str);
4197cb960a2Sdownsj return KSTD;
4207cb960a2Sdownsj }
4217cb960a2Sdownsj
4227cb960a2Sdownsj static int
x_ins_string(int c)423c5d5393cSotto x_ins_string(int c)
4247cb960a2Sdownsj {
42544d96bb9Smpi return x_insert(c);
4267cb960a2Sdownsj }
4277cb960a2Sdownsj
4287cb960a2Sdownsj static int
x_do_ins(const char * cp,size_t len)429f369c404Smmcc x_do_ins(const char *cp, size_t len)
4307cb960a2Sdownsj {
4317cb960a2Sdownsj if (xep+len >= xend) {
4327cb960a2Sdownsj x_e_putc(BEL);
4337cb960a2Sdownsj return -1;
4347cb960a2Sdownsj }
4357cb960a2Sdownsj
4367cb960a2Sdownsj memmove(xcp+len, xcp, xep - xcp + 1);
4377cb960a2Sdownsj memmove(xcp, cp, len);
4387cb960a2Sdownsj xcp += len;
4397cb960a2Sdownsj xep += len;
4407cb960a2Sdownsj return 0;
4417cb960a2Sdownsj }
4427cb960a2Sdownsj
4437cb960a2Sdownsj static int
x_ins(char * s)444c5d5393cSotto x_ins(char *s)
4457cb960a2Sdownsj {
4467cb960a2Sdownsj char *cp = xcp;
4477894b443Smillert int adj = x_adj_done;
4487cb960a2Sdownsj
4497cb960a2Sdownsj if (x_do_ins(s, strlen(s)) < 0)
4507cb960a2Sdownsj return -1;
4517cb960a2Sdownsj /*
4527cb960a2Sdownsj * x_zots() may result in a call to x_adjust()
4537cb960a2Sdownsj * we want xcp to reflect the new position.
4547cb960a2Sdownsj */
4550e7d3a01Smillert xlp_valid = false;
4567cb960a2Sdownsj x_lastcp();
4577cb960a2Sdownsj x_adj_ok = (xcp >= xlp);
4587cb960a2Sdownsj x_zots(cp);
4597a8124d8Sderaadt if (adj == x_adj_done) { /* has x_adjust() been called? */
4607cb960a2Sdownsj /* no */
4617cb960a2Sdownsj for (cp = xlp; cp > xcp; )
4627cb960a2Sdownsj x_bs(*--cp);
4637cb960a2Sdownsj }
4647cb960a2Sdownsj
4657cb960a2Sdownsj x_adj_ok = 1;
4667cb960a2Sdownsj return 0;
4677cb960a2Sdownsj }
4687cb960a2Sdownsj
4697cb960a2Sdownsj static int
x_del_back(int c)470c5d5393cSotto x_del_back(int c)
4717cb960a2Sdownsj {
4727cb960a2Sdownsj int col = xcp - xbuf;
4737cb960a2Sdownsj
4747cb960a2Sdownsj if (col == 0) {
4757cb960a2Sdownsj x_e_putc(BEL);
4767cb960a2Sdownsj return KSTD;
4777cb960a2Sdownsj }
4787cb960a2Sdownsj if (x_arg > col)
4797cb960a2Sdownsj x_arg = col;
4805cc68a1dSschwarze while (x_arg < col && isu8cont(xcp[-x_arg]))
4815cc68a1dSschwarze x_arg++;
4827cb960a2Sdownsj x_goto(xcp - x_arg);
4830e7d3a01Smillert x_delete(x_arg, false);
4847cb960a2Sdownsj return KSTD;
4857cb960a2Sdownsj }
4867cb960a2Sdownsj
4877cb960a2Sdownsj static int
x_del_char(int c)488c5d5393cSotto x_del_char(int c)
4897cb960a2Sdownsj {
4907cb960a2Sdownsj int nleft = xep - xcp;
4917cb960a2Sdownsj
4927cb960a2Sdownsj if (!nleft) {
4937cb960a2Sdownsj x_e_putc(BEL);
4947cb960a2Sdownsj return KSTD;
4957cb960a2Sdownsj }
4967cb960a2Sdownsj if (x_arg > nleft)
4977cb960a2Sdownsj x_arg = nleft;
4985cc68a1dSschwarze while (x_arg < nleft && isu8cont(xcp[x_arg]))
4995cc68a1dSschwarze x_arg++;
5000e7d3a01Smillert x_delete(x_arg, false);
5017cb960a2Sdownsj return KSTD;
5027cb960a2Sdownsj }
5037cb960a2Sdownsj
5045cc68a1dSschwarze /* Delete nc bytes to the right of the cursor (including cursor position) */
5057cb960a2Sdownsj static void
x_delete(int nc,int push)506c5d5393cSotto x_delete(int nc, int push)
5077cb960a2Sdownsj {
5087cb960a2Sdownsj int i,j;
5097cb960a2Sdownsj char *cp;
5107cb960a2Sdownsj
5117cb960a2Sdownsj if (nc == 0)
5127cb960a2Sdownsj return;
5137cb960a2Sdownsj if (xmp != NULL && xmp > xcp) {
5147cb960a2Sdownsj if (xcp + nc > xmp)
5157cb960a2Sdownsj xmp = xcp;
5167cb960a2Sdownsj else
5177cb960a2Sdownsj xmp -= nc;
5187cb960a2Sdownsj }
5197cb960a2Sdownsj
5207cb960a2Sdownsj /*
5217cb960a2Sdownsj * This lets us yank a word we have deleted.
5227cb960a2Sdownsj */
52392303ab9Sfgsch if (push)
5247cb960a2Sdownsj x_push(nc);
5257cb960a2Sdownsj
5267cb960a2Sdownsj xep -= nc;
5277cb960a2Sdownsj cp = xcp;
5287cb960a2Sdownsj j = 0;
5297cb960a2Sdownsj i = nc;
5307cb960a2Sdownsj while (i--) {
531e569fc7cSderaadt j += x_size((unsigned char)*cp++);
5327cb960a2Sdownsj }
5337cb960a2Sdownsj memmove(xcp, xcp+nc, xep - xcp + 1); /* Copies the null */
5347cb960a2Sdownsj x_adj_ok = 0; /* don't redraw */
5353e173141Sschwarze xlp_valid = false;
5367cb960a2Sdownsj x_zots(xcp);
5377cb960a2Sdownsj /*
5387cb960a2Sdownsj * if we are already filling the line,
5397cb960a2Sdownsj * there is no need to ' ','\b'.
5407cb960a2Sdownsj * But if we must, make sure we do the minimum.
5417cb960a2Sdownsj */
5427a8124d8Sderaadt if ((i = xx_cols - 2 - x_col) > 0) {
5437cb960a2Sdownsj j = (j < i) ? j : i;
5447cb960a2Sdownsj i = j;
5457cb960a2Sdownsj while (i--)
5467cb960a2Sdownsj x_e_putc(' ');
5477cb960a2Sdownsj i = j;
5487cb960a2Sdownsj while (i--)
5497cb960a2Sdownsj x_e_putc('\b');
5507cb960a2Sdownsj }
5517cb960a2Sdownsj /*x_goto(xcp);*/
5527cb960a2Sdownsj x_adj_ok = 1;
5530e7d3a01Smillert xlp_valid = false;
5547cb960a2Sdownsj for (cp = x_lastcp(); cp > xcp; )
5557cb960a2Sdownsj x_bs(*--cp);
5567cb960a2Sdownsj
5577cb960a2Sdownsj return;
5587cb960a2Sdownsj }
5597cb960a2Sdownsj
5607cb960a2Sdownsj static int
x_del_bword(int c)561c5d5393cSotto x_del_bword(int c)
5627cb960a2Sdownsj {
5630e7d3a01Smillert x_delete(x_bword(), true);
5647cb960a2Sdownsj return KSTD;
5657cb960a2Sdownsj }
5667cb960a2Sdownsj
5677cb960a2Sdownsj static int
x_mv_bword(int c)568c5d5393cSotto x_mv_bword(int c)
5697cb960a2Sdownsj {
5707cb960a2Sdownsj (void)x_bword();
5717cb960a2Sdownsj return KSTD;
5727cb960a2Sdownsj }
5737cb960a2Sdownsj
5747cb960a2Sdownsj static int
x_mv_fword(int c)575c5d5393cSotto x_mv_fword(int c)
5767cb960a2Sdownsj {
5777cb960a2Sdownsj x_goto(xcp + x_fword());
5787cb960a2Sdownsj return KSTD;
5797cb960a2Sdownsj }
5807cb960a2Sdownsj
5817cb960a2Sdownsj static int
x_del_fword(int c)582c5d5393cSotto x_del_fword(int c)
5837cb960a2Sdownsj {
5840e7d3a01Smillert x_delete(x_fword(), true);
5857cb960a2Sdownsj return KSTD;
5867cb960a2Sdownsj }
5877cb960a2Sdownsj
5887cb960a2Sdownsj static int
x_bword(void)589c5d5393cSotto x_bword(void)
5907cb960a2Sdownsj {
5917cb960a2Sdownsj int nc = 0;
5927894b443Smillert char *cp = xcp;
5937cb960a2Sdownsj
5947cb960a2Sdownsj if (cp == xbuf) {
5957cb960a2Sdownsj x_e_putc(BEL);
5967cb960a2Sdownsj return 0;
5977cb960a2Sdownsj }
5987a8124d8Sderaadt while (x_arg--) {
5997a8124d8Sderaadt while (cp != xbuf && is_mfs(cp[-1])) {
6007cb960a2Sdownsj cp--;
6017cb960a2Sdownsj nc++;
6027cb960a2Sdownsj }
6037a8124d8Sderaadt while (cp != xbuf && !is_mfs(cp[-1])) {
6047cb960a2Sdownsj cp--;
6057cb960a2Sdownsj nc++;
6067cb960a2Sdownsj }
6077cb960a2Sdownsj }
6087cb960a2Sdownsj x_goto(cp);
6097cb960a2Sdownsj return nc;
6107cb960a2Sdownsj }
6117cb960a2Sdownsj
6127cb960a2Sdownsj static int
x_fword(void)613c5d5393cSotto x_fword(void)
6147cb960a2Sdownsj {
6157cb960a2Sdownsj int nc = 0;
6167894b443Smillert char *cp = xcp;
6177cb960a2Sdownsj
6187cb960a2Sdownsj if (cp == xep) {
6197cb960a2Sdownsj x_e_putc(BEL);
6207cb960a2Sdownsj return 0;
6217cb960a2Sdownsj }
6227a8124d8Sderaadt while (x_arg--) {
6237a8124d8Sderaadt while (cp != xep && is_mfs(*cp)) {
6247cb960a2Sdownsj cp++;
6257cb960a2Sdownsj nc++;
6267cb960a2Sdownsj }
6277a8124d8Sderaadt while (cp != xep && !is_mfs(*cp)) {
6287cb960a2Sdownsj cp++;
6297cb960a2Sdownsj nc++;
6307cb960a2Sdownsj }
6317cb960a2Sdownsj }
6327cb960a2Sdownsj return nc;
6337cb960a2Sdownsj }
6347cb960a2Sdownsj
6357cb960a2Sdownsj static void
x_goto(char * cp)636c5d5393cSotto x_goto(char *cp)
6377cb960a2Sdownsj {
6387a8124d8Sderaadt if (cp < xbp || cp >= (xbp + x_displen)) {
6397cb960a2Sdownsj /* we are heading off screen */
6407cb960a2Sdownsj xcp = cp;
6417cb960a2Sdownsj x_adjust();
6427a8124d8Sderaadt } else if (cp < xcp) { /* move back */
6437cb960a2Sdownsj while (cp < xcp)
644e569fc7cSderaadt x_bs((unsigned char)*--xcp);
6457a8124d8Sderaadt } else if (cp > xcp) { /* move forward */
6467cb960a2Sdownsj while (cp > xcp)
647e569fc7cSderaadt x_zotc((unsigned char)*xcp++);
6487cb960a2Sdownsj }
6497cb960a2Sdownsj }
6507cb960a2Sdownsj
6517cb960a2Sdownsj static void
x_bs(int c)652c5d5393cSotto x_bs(int c)
6537cb960a2Sdownsj {
6547894b443Smillert int i;
6557a8124d8Sderaadt
6567cb960a2Sdownsj i = x_size(c);
6577cb960a2Sdownsj while (i--)
6587cb960a2Sdownsj x_e_putc('\b');
6597cb960a2Sdownsj }
6607cb960a2Sdownsj
6617cb960a2Sdownsj static int
x_size_str(char * cp)662c5d5393cSotto x_size_str(char *cp)
6637cb960a2Sdownsj {
6647894b443Smillert int size = 0;
6657cb960a2Sdownsj while (*cp)
6667cb960a2Sdownsj size += x_size(*cp++);
6677cb960a2Sdownsj return size;
6687cb960a2Sdownsj }
6697cb960a2Sdownsj
6707cb960a2Sdownsj static int
x_size(int c)671c5d5393cSotto x_size(int c)
6727cb960a2Sdownsj {
6737cb960a2Sdownsj if (c=='\t')
6747cb960a2Sdownsj return 4; /* Kludge, tabs are always four spaces. */
6752dee7088Smillert if (iscntrl(c)) /* control char */
6767cb960a2Sdownsj return 2;
6775cc68a1dSschwarze if (isu8cont(c))
6785cc68a1dSschwarze return 0;
6797cb960a2Sdownsj return 1;
6807cb960a2Sdownsj }
6817cb960a2Sdownsj
6827cb960a2Sdownsj static void
x_zots(char * str)683c5d5393cSotto x_zots(char *str)
6847cb960a2Sdownsj {
6857894b443Smillert int adj = x_adj_done;
6867cb960a2Sdownsj
6879b414e55Sschwarze if (str > xbuf && isu8cont(*str)) {
6889b414e55Sschwarze while (str > xbuf && isu8cont(*str))
6899b414e55Sschwarze str--;
6909b414e55Sschwarze x_e_putc('\b');
6919b414e55Sschwarze }
6927cb960a2Sdownsj x_lastcp();
6937cb960a2Sdownsj while (*str && str < xlp && adj == x_adj_done)
6947cb960a2Sdownsj x_zotc(*str++);
6957cb960a2Sdownsj }
6967cb960a2Sdownsj
6977cb960a2Sdownsj static void
x_zotc(int c)698c5d5393cSotto x_zotc(int c)
6997cb960a2Sdownsj {
7007cb960a2Sdownsj if (c == '\t') {
7017cb960a2Sdownsj /* Kludge, tabs are always four spaces. */
7027cb960a2Sdownsj x_e_puts(" ");
7032dee7088Smillert } else if (iscntrl(c)) {
7047cb960a2Sdownsj x_e_putc('^');
7057cb960a2Sdownsj x_e_putc(UNCTRL(c));
7067cb960a2Sdownsj } else
7077cb960a2Sdownsj x_e_putc(c);
7087cb960a2Sdownsj }
7097cb960a2Sdownsj
7107cb960a2Sdownsj static int
x_mv_back(int c)711c5d5393cSotto x_mv_back(int c)
7127cb960a2Sdownsj {
7137cb960a2Sdownsj int col = xcp - xbuf;
7147cb960a2Sdownsj
7157cb960a2Sdownsj if (col == 0) {
7167cb960a2Sdownsj x_e_putc(BEL);
7177cb960a2Sdownsj return KSTD;
7187cb960a2Sdownsj }
7197cb960a2Sdownsj if (x_arg > col)
7207cb960a2Sdownsj x_arg = col;
7215cc68a1dSschwarze while (x_arg < col && isu8cont(xcp[-x_arg]))
7225cc68a1dSschwarze x_arg++;
7237cb960a2Sdownsj x_goto(xcp - x_arg);
7247cb960a2Sdownsj return KSTD;
7257cb960a2Sdownsj }
7267cb960a2Sdownsj
7277cb960a2Sdownsj static int
x_mv_forw(int c)728c5d5393cSotto x_mv_forw(int c)
7297cb960a2Sdownsj {
7307cb960a2Sdownsj int nleft = xep - xcp;
7317cb960a2Sdownsj
7327cb960a2Sdownsj if (!nleft) {
7337cb960a2Sdownsj x_e_putc(BEL);
7347cb960a2Sdownsj return KSTD;
7357cb960a2Sdownsj }
7367cb960a2Sdownsj if (x_arg > nleft)
7377cb960a2Sdownsj x_arg = nleft;
7389b414e55Sschwarze while (x_arg < nleft && isu8cont(xcp[x_arg]))
7395cc68a1dSschwarze x_arg++;
7407cb960a2Sdownsj x_goto(xcp + x_arg);
7417cb960a2Sdownsj return KSTD;
7427cb960a2Sdownsj }
7437cb960a2Sdownsj
7447cb960a2Sdownsj static int
x_search_char_forw(int c)745c5d5393cSotto x_search_char_forw(int c)
7467cb960a2Sdownsj {
7477cb960a2Sdownsj char *cp = xcp;
7487cb960a2Sdownsj
7497cb960a2Sdownsj *xep = '\0';
7507cb960a2Sdownsj c = x_e_getc();
7517cb960a2Sdownsj while (x_arg--) {
7527a8124d8Sderaadt if (c < 0 ||
7537a8124d8Sderaadt ((cp = (cp == xep) ? NULL : strchr(cp + 1, c)) == NULL &&
7547a8124d8Sderaadt (cp = strchr(xbuf, c)) == NULL)) {
7557cb960a2Sdownsj x_e_putc(BEL);
7567cb960a2Sdownsj return KSTD;
7577cb960a2Sdownsj }
7587cb960a2Sdownsj }
7597cb960a2Sdownsj x_goto(cp);
7607cb960a2Sdownsj return KSTD;
7617cb960a2Sdownsj }
7627cb960a2Sdownsj
7637cb960a2Sdownsj static int
x_search_char_back(int c)764c5d5393cSotto x_search_char_back(int c)
7657cb960a2Sdownsj {
7667cb960a2Sdownsj char *cp = xcp, *p;
7677cb960a2Sdownsj
7687cb960a2Sdownsj c = x_e_getc();
7697cb960a2Sdownsj for (; x_arg--; cp = p)
7707cb960a2Sdownsj for (p = cp; ; ) {
7717cb960a2Sdownsj if (p-- == xbuf)
7727cb960a2Sdownsj p = xep;
7737cb960a2Sdownsj if (c < 0 || p == cp) {
7747cb960a2Sdownsj x_e_putc(BEL);
7757cb960a2Sdownsj return KSTD;
7767cb960a2Sdownsj }
7777cb960a2Sdownsj if (*p == c)
7787cb960a2Sdownsj break;
7797cb960a2Sdownsj }
7807cb960a2Sdownsj x_goto(cp);
7817cb960a2Sdownsj return KSTD;
7827cb960a2Sdownsj }
7837cb960a2Sdownsj
7847cb960a2Sdownsj static int
x_newline(int c)785c5d5393cSotto x_newline(int c)
7867cb960a2Sdownsj {
7877cb960a2Sdownsj x_e_putc('\r');
7887cb960a2Sdownsj x_e_putc('\n');
7897cb960a2Sdownsj x_flush();
7907cb960a2Sdownsj *xep++ = '\n';
7917cb960a2Sdownsj return KEOL;
7927cb960a2Sdownsj }
7937cb960a2Sdownsj
7947cb960a2Sdownsj static int
x_end_of_text(int c)795c5d5393cSotto x_end_of_text(int c)
7967cb960a2Sdownsj {
797de098c7aSotto x_zotc(edchars.eof);
798de098c7aSotto x_putc('\r');
799de098c7aSotto x_putc('\n');
800de098c7aSotto x_flush();
8017cb960a2Sdownsj return KEOL;
8027cb960a2Sdownsj }
8037cb960a2Sdownsj
x_beg_hist(int c)804c5d5393cSotto static int x_beg_hist(int c) { x_load_hist(history); return KSTD;}
8057cb960a2Sdownsj
x_end_hist(int c)806c5d5393cSotto static int x_end_hist(int c) { x_load_hist(histptr); return KSTD;}
8077cb960a2Sdownsj
x_prev_com(int c)808c5d5393cSotto static int x_prev_com(int c) { x_load_hist(x_histp - x_arg); return KSTD;}
8097cb960a2Sdownsj
x_next_com(int c)810c5d5393cSotto static int x_next_com(int c) { x_load_hist(x_histp + x_arg); return KSTD;}
8117cb960a2Sdownsj
8127cb960a2Sdownsj /* Goto a particular history number obtained from argument.
8137cb960a2Sdownsj * If no argument is given history 1 is probably not what you
8147cb960a2Sdownsj * want so we'll simply go to the oldest one.
8157cb960a2Sdownsj */
8167cb960a2Sdownsj static int
x_goto_hist(int c)817c5d5393cSotto x_goto_hist(int c)
8187cb960a2Sdownsj {
8197cb960a2Sdownsj if (x_arg_defaulted)
8207cb960a2Sdownsj x_load_hist(history);
8217cb960a2Sdownsj else
8227cb960a2Sdownsj x_load_hist(histptr + x_arg - source->line);
8237cb960a2Sdownsj return KSTD;
8247cb960a2Sdownsj }
8257cb960a2Sdownsj
8267cb960a2Sdownsj static void
x_load_hist(char ** hp)827c5d5393cSotto x_load_hist(char **hp)
8287cb960a2Sdownsj {
8297cb960a2Sdownsj int oldsize;
8307cb960a2Sdownsj
8317cb960a2Sdownsj if (hp < history || hp > histptr) {
8327cb960a2Sdownsj x_e_putc(BEL);
8337cb960a2Sdownsj return;
8347cb960a2Sdownsj }
8357cb960a2Sdownsj x_histp = hp;
8367cb960a2Sdownsj oldsize = x_size_str(xbuf);
8371c93b6baStdeval strlcpy(xbuf, *hp, xend - xbuf);
8387cb960a2Sdownsj xbp = xbuf;
8391c93b6baStdeval xep = xcp = xbuf + strlen(xbuf);
8400e7d3a01Smillert xlp_valid = false;
8411085a389Sotto if (xep <= x_lastcp())
8427cb960a2Sdownsj x_redraw(oldsize);
8431085a389Sotto x_goto(xep);
8447cb960a2Sdownsj }
8457cb960a2Sdownsj
8467cb960a2Sdownsj static int
x_nl_next_com(int c)847c5d5393cSotto x_nl_next_com(int c)
8487cb960a2Sdownsj {
8497cb960a2Sdownsj x_nextcmd = source->line - (histptr - x_histp) + 1;
8507cb960a2Sdownsj return (x_newline(c));
8517cb960a2Sdownsj }
8527cb960a2Sdownsj
8537cb960a2Sdownsj static int
x_eot_del(int c)854c5d5393cSotto x_eot_del(int c)
8557cb960a2Sdownsj {
8567cb960a2Sdownsj if (xep == xbuf && x_arg_defaulted)
8577cb960a2Sdownsj return (x_end_of_text(c));
8587cb960a2Sdownsj else
8597cb960a2Sdownsj return (x_del_char(c));
8607cb960a2Sdownsj }
8617cb960a2Sdownsj
86228297e90Sjca static kb_func
kb_find_hist_func(char c)863c250457eSdjm kb_find_hist_func(char c)
864c250457eSdjm {
865c250457eSdjm struct kb_entry *k;
866c250457eSdjm char line[LINE + 1];
867c250457eSdjm
868c250457eSdjm line[0] = c;
869c250457eSdjm line[1] = '\0';
870c250457eSdjm TAILQ_FOREACH(k, &kblist, entry)
871c250457eSdjm if (!strcmp(k->seq, line))
872c250457eSdjm return (k->ftab->xf_func);
873c250457eSdjm
874c250457eSdjm return (x_insert);
875c250457eSdjm }
876c250457eSdjm
8777cb960a2Sdownsj /* reverse incremental history search */
8787cb960a2Sdownsj static int
x_search_hist(int c)879c5d5393cSotto x_search_hist(int c)
8807cb960a2Sdownsj {
8817cb960a2Sdownsj int offset = -1; /* offset of match in xbuf, else -1 */
8827cb960a2Sdownsj char pat [256+1]; /* pattern buffer */
8837894b443Smillert char *p = pat;
884c250457eSdjm int (*f)(int);
8857cb960a2Sdownsj
8867cb960a2Sdownsj *p = '\0';
8877cb960a2Sdownsj while (1) {
8887cb960a2Sdownsj if (offset < 0) {
8897cb960a2Sdownsj x_e_puts("\nI-search: ");
8907cb960a2Sdownsj x_e_puts(pat);
8917cb960a2Sdownsj }
8927cb960a2Sdownsj x_flush();
8937cb960a2Sdownsj if ((c = x_e_getc()) < 0)
8947cb960a2Sdownsj return KSTD;
895c250457eSdjm f = kb_find_hist_func(c);
8962a3a8cceShalex if (c == CTRL('[') || c == CTRL('@')) {
897a030eb9bSschwarze x_e_ungetc(c);
8987cb960a2Sdownsj break;
899a030eb9bSschwarze } else if (f == x_search_hist)
9007cb960a2Sdownsj offset = x_search(pat, 0, offset);
901c250457eSdjm else if (f == x_del_back) {
9027cb960a2Sdownsj if (p == pat) {
9037cb960a2Sdownsj offset = -1;
9047cb960a2Sdownsj break;
9057cb960a2Sdownsj }
9067cb960a2Sdownsj if (p > pat)
9077cb960a2Sdownsj *--p = '\0';
9087cb960a2Sdownsj if (p == pat)
9097cb960a2Sdownsj offset = -1;
9107cb960a2Sdownsj else
9117cb960a2Sdownsj offset = x_search(pat, 1, offset);
9127cb960a2Sdownsj continue;
913c250457eSdjm } else if (f == x_insert) {
9147cb960a2Sdownsj /* add char to pattern */
9157cb960a2Sdownsj /* overflow check... */
9167cb960a2Sdownsj if (p >= &pat[sizeof(pat) - 1]) {
9177cb960a2Sdownsj x_e_putc(BEL);
9187cb960a2Sdownsj continue;
9197cb960a2Sdownsj }
9207cb960a2Sdownsj *p++ = c, *p = '\0';
9217cb960a2Sdownsj if (offset >= 0) {
9227cb960a2Sdownsj /* already have partial match */
9237cb960a2Sdownsj offset = x_match(xbuf, pat);
9247cb960a2Sdownsj if (offset >= 0) {
9257a8124d8Sderaadt x_goto(xbuf + offset + (p - pat) -
9267a8124d8Sderaadt (*pat == '^'));
9277cb960a2Sdownsj continue;
9287cb960a2Sdownsj }
9297cb960a2Sdownsj }
9307cb960a2Sdownsj offset = x_search(pat, 0, offset);
9317cb960a2Sdownsj } else { /* other command */
9327cb960a2Sdownsj x_e_ungetc(c);
9337cb960a2Sdownsj break;
9347cb960a2Sdownsj }
9357cb960a2Sdownsj }
9367cb960a2Sdownsj if (offset < 0)
9377cb960a2Sdownsj x_redraw(-1);
9387cb960a2Sdownsj return KSTD;
9397cb960a2Sdownsj }
9407cb960a2Sdownsj
9417cb960a2Sdownsj /* search backward from current line */
9427cb960a2Sdownsj static int
x_search(char * pat,int sameline,int offset)943c5d5393cSotto x_search(char *pat, int sameline, int offset)
9447cb960a2Sdownsj {
9457894b443Smillert char **hp;
9467cb960a2Sdownsj int i;
9477cb960a2Sdownsj
9487cb960a2Sdownsj for (hp = x_histp - (sameline ? 0 : 1) ; hp >= history; --hp) {
9497cb960a2Sdownsj i = x_match(*hp, pat);
9507cb960a2Sdownsj if (i >= 0) {
9517cb960a2Sdownsj if (offset < 0)
9527cb960a2Sdownsj x_e_putc('\n');
9537cb960a2Sdownsj x_load_hist(hp);
9547cb960a2Sdownsj x_goto(xbuf + i + strlen(pat) - (*pat == '^'));
9557cb960a2Sdownsj return i;
9567cb960a2Sdownsj }
9577cb960a2Sdownsj }
9587cb960a2Sdownsj x_e_putc(BEL);
9597cb960a2Sdownsj x_histp = histptr;
9607cb960a2Sdownsj return -1;
9617cb960a2Sdownsj }
9627cb960a2Sdownsj
9637cb960a2Sdownsj /* return position of first match of pattern in string, else -1 */
9647cb960a2Sdownsj static int
x_match(char * str,char * pat)965c5d5393cSotto x_match(char *str, char *pat)
9667cb960a2Sdownsj {
9677cb960a2Sdownsj if (*pat == '^') {
9687cb960a2Sdownsj return (strncmp(str, pat+1, strlen(pat+1)) == 0) ? 0 : -1;
9697cb960a2Sdownsj } else {
9707cb960a2Sdownsj char *q = strstr(str, pat);
9717cb960a2Sdownsj return (q == NULL) ? -1 : q - str;
9727cb960a2Sdownsj }
9737cb960a2Sdownsj }
9747cb960a2Sdownsj
9757cb960a2Sdownsj static int
x_del_line(int c)976c5d5393cSotto x_del_line(int c)
9777cb960a2Sdownsj {
9787cb960a2Sdownsj int i, j;
9797cb960a2Sdownsj
9807cb960a2Sdownsj *xep = 0;
9817cb960a2Sdownsj i = xep - xbuf;
9827cb960a2Sdownsj j = x_size_str(xbuf);
9837cb960a2Sdownsj xcp = xbuf;
9847cb960a2Sdownsj x_push(i);
9857cb960a2Sdownsj xlp = xbp = xep = xbuf;
9860e7d3a01Smillert xlp_valid = true;
9877cb960a2Sdownsj *xcp = 0;
9887cb960a2Sdownsj xmp = NULL;
9897cb960a2Sdownsj x_redraw(j);
9907cb960a2Sdownsj return KSTD;
9917cb960a2Sdownsj }
9927cb960a2Sdownsj
9937cb960a2Sdownsj static int
x_mv_end(int c)994c5d5393cSotto x_mv_end(int c)
9957cb960a2Sdownsj {
9967cb960a2Sdownsj x_goto(xep);
9977cb960a2Sdownsj return KSTD;
9987cb960a2Sdownsj }
9997cb960a2Sdownsj
10007cb960a2Sdownsj static int
x_mv_begin(int c)1001c5d5393cSotto x_mv_begin(int c)
10027cb960a2Sdownsj {
10037cb960a2Sdownsj x_goto(xbuf);
10047cb960a2Sdownsj return KSTD;
10057cb960a2Sdownsj }
10067cb960a2Sdownsj
10077cb960a2Sdownsj static int
x_draw_line(int c)1008c5d5393cSotto x_draw_line(int c)
10097cb960a2Sdownsj {
10107cb960a2Sdownsj x_redraw(-1);
10117cb960a2Sdownsj return KSTD;
10127cb960a2Sdownsj }
10137cb960a2Sdownsj
1014a3c80d85Smillert static int
x_clear_screen(int c)1015a3c80d85Smillert x_clear_screen(int c)
1016a3c80d85Smillert {
1017a3c80d85Smillert x_redraw(-2);
1018a3c80d85Smillert return KSTD;
1019a3c80d85Smillert }
1020a3c80d85Smillert
1021a3c80d85Smillert /* Redraw (part of) the line.
1022a3c80d85Smillert * A non-negative limit is the screen column up to which needs
1023a3c80d85Smillert * redrawing. A limit of -1 redraws on a new line, while a limit
1024a3c80d85Smillert * of -2 (attempts to) clear the screen.
1025dcacb757Sdownsj */
10267cb960a2Sdownsj static void
x_redraw(int limit)1027c5d5393cSotto x_redraw(int limit)
10287cb960a2Sdownsj {
1029638b9e76Sbeck int i, j, truncate = 0;
10307cb960a2Sdownsj char *cp;
10317cb960a2Sdownsj
10327cb960a2Sdownsj x_adj_ok = 0;
1033a3c80d85Smillert if (limit == -2) {
1034a3c80d85Smillert int cleared = 0;
1035a3c80d85Smillert #ifndef SMALL
1036a3c80d85Smillert if (cur_term != NULL && clear_screen != NULL) {
1037a3c80d85Smillert if (tputs(clear_screen, 1, x_putc) != ERR)
1038a3c80d85Smillert cleared = 1;
1039a3c80d85Smillert }
1040a3c80d85Smillert #endif
1041a3c80d85Smillert if (!cleared)
10427cb960a2Sdownsj x_e_putc('\n');
1043a3c80d85Smillert }
1044a3c80d85Smillert else if (limit == -1)
1045a3c80d85Smillert x_e_putc('\n');
1046a3c80d85Smillert else if (limit >= 0)
10477cb960a2Sdownsj x_e_putc('\r');
10487cb960a2Sdownsj x_flush();
10497a8124d8Sderaadt if (xbp == xbuf) {
1050f7654a50Snicm x_col = promptlen(prompt, NULL);
1051638b9e76Sbeck if (x_col > xx_cols)
1052638b9e76Sbeck truncate = (x_col / xx_cols) * xx_cols;
1053638b9e76Sbeck if (prompt_redraw)
1054638b9e76Sbeck pprompt(prompt + prompt_skip, truncate);
10557cb960a2Sdownsj }
1056638b9e76Sbeck if (x_col > xx_cols)
1057638b9e76Sbeck x_col = x_col - (x_col / xx_cols) * xx_cols;
1058dcacb757Sdownsj x_displen = xx_cols - 2 - x_col;
1059638b9e76Sbeck if (x_displen < 1) {
1060638b9e76Sbeck x_col = 0;
1061638b9e76Sbeck x_displen = xx_cols - 2;
1062638b9e76Sbeck }
10630e7d3a01Smillert xlp_valid = false;
1064565b7249Sjca x_lastcp();
10657cb960a2Sdownsj x_zots(xbp);
10667cb960a2Sdownsj if (xbp != xbuf || xep > xlp)
1067dcacb757Sdownsj limit = xx_cols;
10687a8124d8Sderaadt if (limit >= 0) {
10697cb960a2Sdownsj if (xep > xlp)
10707cb960a2Sdownsj i = 0; /* we fill the line */
10717cb960a2Sdownsj else
10727cb960a2Sdownsj i = limit - (xlp - xbp);
10737cb960a2Sdownsj
1074dcacb757Sdownsj for (j = 0; j < i && x_col < (xx_cols - 2); j++)
10757cb960a2Sdownsj x_e_putc(' ');
10767cb960a2Sdownsj i = ' ';
10777a8124d8Sderaadt if (xep > xlp) { /* more off screen */
10787cb960a2Sdownsj if (xbp > xbuf)
10797cb960a2Sdownsj i = '*';
10807cb960a2Sdownsj else
10817cb960a2Sdownsj i = '>';
10827a8124d8Sderaadt } else if (xbp > xbuf)
10837cb960a2Sdownsj i = '<';
10847cb960a2Sdownsj x_e_putc(i);
10857cb960a2Sdownsj j++;
10867cb960a2Sdownsj while (j--)
10877cb960a2Sdownsj x_e_putc('\b');
10887cb960a2Sdownsj }
10897cb960a2Sdownsj for (cp = xlp; cp > xcp; )
10907cb960a2Sdownsj x_bs(*--cp);
10917cb960a2Sdownsj x_adj_ok = 1;
10926465bc54Smmcc #ifdef DEBUG
10936465bc54Smmcc x_flush();
10946465bc54Smmcc #endif
10957cb960a2Sdownsj return;
10967cb960a2Sdownsj }
10977cb960a2Sdownsj
10987cb960a2Sdownsj static int
x_transpose(int c)1099c5d5393cSotto x_transpose(int c)
11007cb960a2Sdownsj {
11017cb960a2Sdownsj char tmp;
11027cb960a2Sdownsj
11037cb960a2Sdownsj /* What transpose is meant to do seems to be up for debate. This
11047cb960a2Sdownsj * is a general summary of the options; the text is abcd with the
110512e7fb2dSjmc * upper case character or underscore indicating the cursor position:
11067cb960a2Sdownsj * Who Before After Before After
11077cb960a2Sdownsj * at&t ksh in emacs mode: abCd abdC abcd_ (bell)
11087cb960a2Sdownsj * at&t ksh in gmacs mode: abCd baCd abcd_ abdc_
11097cb960a2Sdownsj * gnu emacs: abCd acbD abcd_ abdc_
11107cb960a2Sdownsj * Pdksh currently goes with GNU behavior since I believe this is the
11117cb960a2Sdownsj * most common version of emacs, unless in gmacs mode, in which case
1112060cee32Sjmc * it does the at&t ksh gmacs mode.
11137cb960a2Sdownsj * This should really be broken up into 3 functions so users can bind
11147cb960a2Sdownsj * to the one they want.
11157cb960a2Sdownsj */
11167cb960a2Sdownsj if (xcp == xbuf) {
11177cb960a2Sdownsj x_e_putc(BEL);
11187cb960a2Sdownsj return KSTD;
11197cb960a2Sdownsj } else if (xcp == xep || Flag(FGMACS)) {
11207cb960a2Sdownsj if (xcp - xbuf == 1) {
11217cb960a2Sdownsj x_e_putc(BEL);
11227cb960a2Sdownsj return KSTD;
11237cb960a2Sdownsj }
11247cb960a2Sdownsj /* Gosling/Unipress emacs style: Swap two characters before the
11257cb960a2Sdownsj * cursor, do not change cursor position
11267cb960a2Sdownsj */
11277cb960a2Sdownsj x_bs(xcp[-1]);
11287cb960a2Sdownsj x_bs(xcp[-2]);
11297cb960a2Sdownsj x_zotc(xcp[-1]);
11307cb960a2Sdownsj x_zotc(xcp[-2]);
11317cb960a2Sdownsj tmp = xcp[-1];
11327cb960a2Sdownsj xcp[-1] = xcp[-2];
11337cb960a2Sdownsj xcp[-2] = tmp;
11347cb960a2Sdownsj } else {
11357cb960a2Sdownsj /* GNU emacs style: Swap the characters before and under the
11367cb960a2Sdownsj * cursor, move cursor position along one.
11377cb960a2Sdownsj */
11387cb960a2Sdownsj x_bs(xcp[-1]);
11397cb960a2Sdownsj x_zotc(xcp[0]);
11407cb960a2Sdownsj x_zotc(xcp[-1]);
11417cb960a2Sdownsj tmp = xcp[-1];
11427cb960a2Sdownsj xcp[-1] = xcp[0];
11437cb960a2Sdownsj xcp[0] = tmp;
11447cb960a2Sdownsj x_bs(xcp[0]);
11457cb960a2Sdownsj x_goto(xcp + 1);
11467cb960a2Sdownsj }
11477cb960a2Sdownsj return KSTD;
11487cb960a2Sdownsj }
11497cb960a2Sdownsj
11507cb960a2Sdownsj static int
x_literal(int c)1151c5d5393cSotto x_literal(int c)
11527cb960a2Sdownsj {
1153c250457eSdjm x_literal_set = 1;
11547cb960a2Sdownsj return KSTD;
11557cb960a2Sdownsj }
11567cb960a2Sdownsj
11577cb960a2Sdownsj static int
x_kill(int c)1158c5d5393cSotto x_kill(int c)
11597cb960a2Sdownsj {
11607cb960a2Sdownsj int col = xcp - xbuf;
11617cb960a2Sdownsj int lastcol = xep - xbuf;
11627cb960a2Sdownsj int ndel;
11637cb960a2Sdownsj
11647cb960a2Sdownsj if (x_arg_defaulted)
11657cb960a2Sdownsj x_arg = lastcol;
11667cb960a2Sdownsj else if (x_arg > lastcol)
11677cb960a2Sdownsj x_arg = lastcol;
11685cc68a1dSschwarze while (x_arg < lastcol && isu8cont(xbuf[x_arg]))
11695cc68a1dSschwarze x_arg++;
11707cb960a2Sdownsj ndel = x_arg - col;
11717cb960a2Sdownsj if (ndel < 0) {
11727cb960a2Sdownsj x_goto(xbuf + x_arg);
11737cb960a2Sdownsj ndel = -ndel;
11747cb960a2Sdownsj }
11750e7d3a01Smillert x_delete(ndel, true);
11767cb960a2Sdownsj return KSTD;
11777cb960a2Sdownsj }
11787cb960a2Sdownsj
11797cb960a2Sdownsj static void
x_push(int nchars)1180c5d5393cSotto x_push(int nchars)
11817cb960a2Sdownsj {
11827cb960a2Sdownsj char *cp = str_nsave(xcp, nchars, AEDIT);
1183bfd561bcStedu afree(killstack[killsp], AEDIT);
11847cb960a2Sdownsj killstack[killsp] = cp;
11857cb960a2Sdownsj killsp = (killsp + 1) % KILLSIZE;
11867cb960a2Sdownsj }
11877cb960a2Sdownsj
11887cb960a2Sdownsj static int
x_yank(int c)1189c5d5393cSotto x_yank(int c)
11907cb960a2Sdownsj {
11917cb960a2Sdownsj if (killsp == 0)
11927cb960a2Sdownsj killtp = KILLSIZE;
11937cb960a2Sdownsj else
11947cb960a2Sdownsj killtp = killsp;
11957cb960a2Sdownsj killtp --;
11967cb960a2Sdownsj if (killstack[killtp] == 0) {
11977cb960a2Sdownsj x_e_puts("\nnothing to yank");
11987cb960a2Sdownsj x_redraw(-1);
11997cb960a2Sdownsj return KSTD;
12007cb960a2Sdownsj }
12017cb960a2Sdownsj xmp = xcp;
12027cb960a2Sdownsj x_ins(killstack[killtp]);
12037cb960a2Sdownsj return KSTD;
12047cb960a2Sdownsj }
12057cb960a2Sdownsj
12067cb960a2Sdownsj static int
x_meta_yank(int c)1207c5d5393cSotto x_meta_yank(int c)
12087cb960a2Sdownsj {
12097cb960a2Sdownsj int len;
1210c250457eSdjm if ((x_last_command != x_yank && x_last_command != x_meta_yank) ||
12117a8124d8Sderaadt killstack[killtp] == 0) {
1212ab8d2853Sfgsch killtp = killsp;
12137cb960a2Sdownsj x_e_puts("\nyank something first");
12147cb960a2Sdownsj x_redraw(-1);
12157cb960a2Sdownsj return KSTD;
12167cb960a2Sdownsj }
12177cb960a2Sdownsj len = strlen(killstack[killtp]);
12187cb960a2Sdownsj x_goto(xcp - len);
12190e7d3a01Smillert x_delete(len, false);
12207cb960a2Sdownsj do {
12217cb960a2Sdownsj if (killtp == 0)
12227cb960a2Sdownsj killtp = KILLSIZE - 1;
12237cb960a2Sdownsj else
12247cb960a2Sdownsj killtp--;
12257cb960a2Sdownsj } while (killstack[killtp] == 0);
12267cb960a2Sdownsj x_ins(killstack[killtp]);
12277cb960a2Sdownsj return KSTD;
12287cb960a2Sdownsj }
12297cb960a2Sdownsj
12307cb960a2Sdownsj static int
x_abort(int c)1231c5d5393cSotto x_abort(int c)
12327cb960a2Sdownsj {
12337cb960a2Sdownsj /* x_zotc(c); */
12347cb960a2Sdownsj xlp = xep = xcp = xbp = xbuf;
12350e7d3a01Smillert xlp_valid = true;
12367cb960a2Sdownsj *xcp = 0;
12377cb960a2Sdownsj return KINTR;
12387cb960a2Sdownsj }
12397cb960a2Sdownsj
12407cb960a2Sdownsj static int
x_error(int c)1241c5d5393cSotto x_error(int c)
12427cb960a2Sdownsj {
12437cb960a2Sdownsj x_e_putc(BEL);
12447cb960a2Sdownsj return KSTD;
12457cb960a2Sdownsj }
12467cb960a2Sdownsj
12477cb960a2Sdownsj static char *
kb_encode(const char * s)1248c250457eSdjm kb_encode(const char *s)
12497cb960a2Sdownsj {
1250c250457eSdjm static char l[LINE + 1];
1251c250457eSdjm int at = 0;
12527cb960a2Sdownsj
1253c250457eSdjm l[at] = '\0';
1254c250457eSdjm while (*s) {
1255c250457eSdjm if (*s == '^') {
1256c250457eSdjm s++;
1257c250457eSdjm if (*s >= '?')
1258c250457eSdjm l[at++] = CTRL(*s);
12597cb960a2Sdownsj else {
1260c250457eSdjm l[at++] = '^';
1261c250457eSdjm s--;
12627cb960a2Sdownsj }
12637cb960a2Sdownsj } else
1264c250457eSdjm l[at++] = *s;
1265c250457eSdjm l[at] = '\0';
1266c250457eSdjm s++;
12677cb960a2Sdownsj }
1268c250457eSdjm return (l);
12697cb960a2Sdownsj }
12707cb960a2Sdownsj
12717cb960a2Sdownsj static char *
kb_decode(const char * s)1272c250457eSdjm kb_decode(const char *s)
12737cb960a2Sdownsj {
1274c250457eSdjm static char l[LINE + 1];
12754c503bcdSmillert unsigned int i, at = 0;
12767cb960a2Sdownsj
1277c250457eSdjm l[0] = '\0';
1278c250457eSdjm for (i = 0; i < strlen(s); i++) {
1279a85f8ccfSmmcc if (iscntrl((unsigned char)s[i])) {
1280c250457eSdjm l[at++] = '^';
1281c250457eSdjm l[at++] = UNCTRL(s[i]);
12827cb960a2Sdownsj } else
1283c250457eSdjm l[at++] = s[i];
1284c250457eSdjm l[at] = '\0';
1285c250457eSdjm }
1286c250457eSdjm
1287c250457eSdjm return (l);
1288c250457eSdjm }
1289c250457eSdjm
1290c250457eSdjm static int
kb_match(char * s)1291c250457eSdjm kb_match(char *s)
1292c250457eSdjm {
1293c250457eSdjm int len = strlen(s);
1294c250457eSdjm struct kb_entry *k;
1295c250457eSdjm
1296c250457eSdjm TAILQ_FOREACH(k, &kblist, entry) {
1297c250457eSdjm if (len > k->len)
1298c250457eSdjm continue;
1299c250457eSdjm
130089253508Stedu if (memcmp(k->seq, s, len) == 0)
1301c250457eSdjm return (1);
1302c250457eSdjm }
1303c250457eSdjm
1304c250457eSdjm return (0);
13057cb960a2Sdownsj }
13067cb960a2Sdownsj
13077cb960a2Sdownsj static void
kb_del(struct kb_entry * k)1308c250457eSdjm kb_del(struct kb_entry *k)
13097cb960a2Sdownsj {
1310c250457eSdjm TAILQ_REMOVE(&kblist, k, entry);
1311c250457eSdjm free(k->args);
1312c250457eSdjm afree(k, AEDIT);
1313c250457eSdjm }
1314c250457eSdjm
1315c250457eSdjm static struct kb_entry *
kb_add_string(kb_func func,void * args,char * str)131628297e90Sjca kb_add_string(kb_func func, void *args, char *str)
1317c250457eSdjm {
13184c503bcdSmillert unsigned int ele, count;
1319c250457eSdjm struct kb_entry *k;
1320c250457eSdjm struct x_ftab *xf = NULL;
1321c250457eSdjm
13224c503bcdSmillert for (ele = 0; ele < NELEM(x_ftab); ele++)
13234c503bcdSmillert if (x_ftab[ele].xf_func == func) {
13244c503bcdSmillert xf = (struct x_ftab *)&x_ftab[ele];
1325c250457eSdjm break;
1326c250457eSdjm }
1327c250457eSdjm if (xf == NULL)
1328c250457eSdjm return (NULL);
1329c250457eSdjm
1330c250457eSdjm if (kb_match(str)) {
1331c250457eSdjm if (x_bind_quiet == 0)
1332c250457eSdjm bi_errorf("duplicate binding for %s", kb_decode(str));
1333c250457eSdjm return (NULL);
1334c250457eSdjm }
1335c250457eSdjm count = strlen(str);
1336c250457eSdjm
1337c250457eSdjm k = alloc(sizeof *k + count + 1, AEDIT);
1338c250457eSdjm k->seq = (unsigned char *)(k + 1);
1339c250457eSdjm k->len = count;
1340c250457eSdjm k->ftab = xf;
1341c250457eSdjm k->args = args ? strdup(args) : NULL;
1342c250457eSdjm
1343c250457eSdjm strlcpy(k->seq, str, count + 1);
1344c250457eSdjm
1345c250457eSdjm TAILQ_INSERT_TAIL(&kblist, k, entry);
1346c250457eSdjm
1347c250457eSdjm return (k);
1348c250457eSdjm }
1349c250457eSdjm
1350c250457eSdjm static struct kb_entry *
kb_add(kb_func func,...)135128297e90Sjca kb_add(kb_func func, ...)
1352c250457eSdjm {
1353c250457eSdjm va_list ap;
13548234bcc5Smillert unsigned char ch;
13558234bcc5Smillert unsigned int i;
13568234bcc5Smillert char line[LINE + 1];
1357c250457eSdjm
1358035c6fecSmillert va_start(ap, func);
13598234bcc5Smillert for (i = 0; i < sizeof(line) - 1; i++) {
13608234bcc5Smillert ch = va_arg(ap, unsigned int);
13618234bcc5Smillert if (ch == 0)
13628234bcc5Smillert break;
13638234bcc5Smillert line[i] = ch;
13648234bcc5Smillert }
1365c250457eSdjm va_end(ap);
13668234bcc5Smillert line[i] = '\0';
1367c250457eSdjm
1368035c6fecSmillert return (kb_add_string(func, NULL, line));
1369c250457eSdjm }
1370c250457eSdjm
1371c250457eSdjm static void
kb_print(struct kb_entry * k)1372c250457eSdjm kb_print(struct kb_entry *k)
1373c250457eSdjm {
1374c250457eSdjm if (!(k->ftab->xf_flags & XF_NOBIND))
1375c250457eSdjm shprintf("%s = %s\n",
1376c250457eSdjm kb_decode(k->seq), k->ftab->xf_name);
1377c250457eSdjm else if (k->args) {
1378c250457eSdjm shprintf("%s = ", kb_decode(k->seq));
1379c250457eSdjm shprintf("'%s'\n", kb_decode(k->args));
1380c250457eSdjm }
13817cb960a2Sdownsj }
13827cb960a2Sdownsj
13837cb960a2Sdownsj int
x_bind(const char * a1,const char * a2,int macro,int list)1384c5d5393cSotto x_bind(const char *a1, const char *a2,
1385c5d5393cSotto int macro, /* bind -m */
1386c5d5393cSotto int list) /* bind -l */
13877cb960a2Sdownsj {
13884c503bcdSmillert unsigned int i;
1389c250457eSdjm struct kb_entry *k, *kb;
1390c250457eSdjm char in[LINE + 1];
13917cb960a2Sdownsj
1392c250457eSdjm if (x_tty == 0) {
13937cb960a2Sdownsj bi_errorf("cannot bind, not a tty");
1394c250457eSdjm return (1);
13957cb960a2Sdownsj }
13967cb960a2Sdownsj
13977cb960a2Sdownsj if (list) {
1398c250457eSdjm /* show all function names */
1399c250457eSdjm for (i = 0; i < NELEM(x_ftab); i++) {
1400c250457eSdjm if (x_ftab[i].xf_name == NULL)
1401c250457eSdjm continue;
1402c250457eSdjm if (x_ftab[i].xf_name &&
1403c250457eSdjm !(x_ftab[i].xf_flags & XF_NOBIND))
1404c250457eSdjm shprintf("%s\n", x_ftab[i].xf_name);
1405c250457eSdjm }
1406c250457eSdjm return (0);
14077cb960a2Sdownsj }
14087cb960a2Sdownsj
14097cb960a2Sdownsj if (a1 == NULL) {
1410c250457eSdjm /* show all bindings */
1411c250457eSdjm TAILQ_FOREACH(k, &kblist, entry)
1412c250457eSdjm kb_print(k);
1413c250457eSdjm return (0);
14147cb960a2Sdownsj }
14157cb960a2Sdownsj
1416c250457eSdjm snprintf(in, sizeof in, "%s", kb_encode(a1));
14177cb960a2Sdownsj if (a2 == NULL) {
1418c250457eSdjm /* print binding */
1419c250457eSdjm TAILQ_FOREACH(k, &kblist, entry)
1420c250457eSdjm if (!strcmp(k->seq, in)) {
1421c250457eSdjm kb_print(k);
1422c250457eSdjm return (0);
1423c250457eSdjm }
1424c250457eSdjm shprintf("%s = %s\n", kb_decode(a1), "auto-insert");
1425c250457eSdjm return (0);
14267cb960a2Sdownsj }
14277cb960a2Sdownsj
1428c250457eSdjm if (strlen(a2) == 0) {
1429c250457eSdjm /* clear binding */
1430c250457eSdjm TAILQ_FOREACH_SAFE(k, &kblist, entry, kb)
1431c250457eSdjm if (!strcmp(k->seq, in)) {
1432c250457eSdjm kb_del(k);
14337cb960a2Sdownsj break;
1434c250457eSdjm }
1435c250457eSdjm return (0);
1436c250457eSdjm }
1437c250457eSdjm
1438c250457eSdjm /* set binding */
1439c250457eSdjm if (macro) {
1440c250457eSdjm /* delete old mapping */
1441c250457eSdjm TAILQ_FOREACH_SAFE(k, &kblist, entry, kb)
1442c250457eSdjm if (!strcmp(k->seq, in)) {
1443c250457eSdjm kb_del(k);
1444c250457eSdjm break;
1445c250457eSdjm }
1446c250457eSdjm kb_add_string(x_ins_string, kb_encode(a2), in);
1447c250457eSdjm return (0);
1448c250457eSdjm }
1449c250457eSdjm
1450c250457eSdjm /* set non macro binding */
1451c250457eSdjm for (i = 0; i < NELEM(x_ftab); i++) {
1452c250457eSdjm if (x_ftab[i].xf_name == NULL)
1453c250457eSdjm continue;
1454c250457eSdjm if (!strcmp(x_ftab[i].xf_name, a2)) {
1455c250457eSdjm /* delete old mapping */
1456c250457eSdjm TAILQ_FOREACH_SAFE(k, &kblist, entry, kb)
1457c250457eSdjm if (!strcmp(k->seq, in)) {
1458c250457eSdjm kb_del(k);
1459c250457eSdjm break;
1460c250457eSdjm }
1461c250457eSdjm kb_add_string(x_ftab[i].xf_func, NULL, in);
1462c250457eSdjm return (0);
1463c250457eSdjm }
1464c250457eSdjm }
14657cb960a2Sdownsj bi_errorf("%s: no such function", a2);
1466c250457eSdjm return (1);
14677cb960a2Sdownsj }
14687cb960a2Sdownsj
14697cb960a2Sdownsj void
x_init_emacs(void)1470c5d5393cSotto x_init_emacs(void)
14717cb960a2Sdownsj {
1472c250457eSdjm x_tty = 1;
14737cb960a2Sdownsj ainit(AEDIT);
14747cb960a2Sdownsj x_nextcmd = -1;
14757cb960a2Sdownsj
1476c250457eSdjm TAILQ_INIT(&kblist);
1477ee6d79f8Sderaadt
1478c250457eSdjm /* man page order */
1479035c6fecSmillert kb_add(x_abort, CTRL('G'), 0);
1480035c6fecSmillert kb_add(x_mv_back, CTRL('B'), 0);
1481035c6fecSmillert kb_add(x_mv_back, CTRL('X'), CTRL('D'), 0);
1482035c6fecSmillert kb_add(x_mv_bword, CTRL('['), 'b', 0);
1483035c6fecSmillert kb_add(x_beg_hist, CTRL('['), '<', 0);
1484035c6fecSmillert kb_add(x_mv_begin, CTRL('A'), 0);
1485035c6fecSmillert kb_add(x_fold_capitalize, CTRL('['), 'C', 0);
1486035c6fecSmillert kb_add(x_fold_capitalize, CTRL('['), 'c', 0);
1487035c6fecSmillert kb_add(x_comment, CTRL('['), '#', 0);
1488035c6fecSmillert kb_add(x_complete, CTRL('['), CTRL('['), 0);
1489035c6fecSmillert kb_add(x_comp_comm, CTRL('X'), CTRL('['), 0);
1490035c6fecSmillert kb_add(x_comp_file, CTRL('['), CTRL('X'), 0);
1491035c6fecSmillert kb_add(x_comp_list, CTRL('I'), 0);
1492035c6fecSmillert kb_add(x_comp_list, CTRL('['), '=', 0);
1493035c6fecSmillert kb_add(x_del_back, CTRL('?'), 0);
1494035c6fecSmillert kb_add(x_del_back, CTRL('H'), 0);
1495035c6fecSmillert kb_add(x_del_char, CTRL('['), '[', '3', '~', 0); /* delete */
1496035c6fecSmillert kb_add(x_del_bword, CTRL('W'), 0);
1497035c6fecSmillert kb_add(x_del_bword, CTRL('['), CTRL('?'), 0);
1498035c6fecSmillert kb_add(x_del_bword, CTRL('['), CTRL('H'), 0);
1499035c6fecSmillert kb_add(x_del_bword, CTRL('['), 'h', 0);
1500035c6fecSmillert kb_add(x_del_fword, CTRL('['), 'd', 0);
1501035c6fecSmillert kb_add(x_next_com, CTRL('N'), 0);
1502035c6fecSmillert kb_add(x_next_com, CTRL('X'), 'B', 0);
1503035c6fecSmillert kb_add(x_fold_lower, CTRL('['), 'L', 0);
1504035c6fecSmillert kb_add(x_fold_lower, CTRL('['), 'l', 0);
1505035c6fecSmillert kb_add(x_end_hist, CTRL('['), '>', 0);
1506035c6fecSmillert kb_add(x_mv_end, CTRL('E'), 0);
1507c250457eSdjm /* how to handle: eot: ^_, underneath copied from original keybindings */
1508035c6fecSmillert kb_add(x_end_of_text, CTRL('_'), 0);
1509035c6fecSmillert kb_add(x_eot_del, CTRL('D'), 0);
1510c250457eSdjm /* error */
1511035c6fecSmillert kb_add(x_xchg_point_mark, CTRL('X'), CTRL('X'), 0);
1512035c6fecSmillert kb_add(x_expand, CTRL('['), '*', 0);
1513035c6fecSmillert kb_add(x_mv_forw, CTRL('F'), 0);
1514035c6fecSmillert kb_add(x_mv_forw, CTRL('X'), 'C', 0);
1515035c6fecSmillert kb_add(x_mv_fword, CTRL('['), 'f', 0);
1516035c6fecSmillert kb_add(x_goto_hist, CTRL('['), 'g', 0);
1517c250457eSdjm /* kill-line */
1518035c6fecSmillert kb_add(x_kill, CTRL('K'), 0);
1519035c6fecSmillert kb_add(x_enumerate, CTRL('['), '?', 0);
1520035c6fecSmillert kb_add(x_list_comm, CTRL('X'), '?', 0);
1521035c6fecSmillert kb_add(x_list_file, CTRL('X'), CTRL('Y'), 0);
1522035c6fecSmillert kb_add(x_newline, CTRL('J'), 0);
1523035c6fecSmillert kb_add(x_newline, CTRL('M'), 0);
1524035c6fecSmillert kb_add(x_nl_next_com, CTRL('O'), 0);
1525c250457eSdjm /* no-op */
1526035c6fecSmillert kb_add(x_prev_histword, CTRL('['), '.', 0);
1527035c6fecSmillert kb_add(x_prev_histword, CTRL('['), '_', 0);
1528c250457eSdjm /* how to handle: quote: ^^ */
1529035c6fecSmillert kb_add(x_literal, CTRL('^'), 0);
15301c8c58f6Sjca kb_add(x_clear_screen, CTRL('L'), 0);
1531035c6fecSmillert kb_add(x_search_char_back, CTRL('['), CTRL(']'), 0);
1532035c6fecSmillert kb_add(x_search_char_forw, CTRL(']'), 0);
1533035c6fecSmillert kb_add(x_search_hist, CTRL('R'), 0);
1534035c6fecSmillert kb_add(x_set_mark, CTRL('['), ' ', 0);
1535035c6fecSmillert kb_add(x_transpose, CTRL('T'), 0);
1536035c6fecSmillert kb_add(x_prev_com, CTRL('P'), 0);
1537035c6fecSmillert kb_add(x_prev_com, CTRL('X'), 'A', 0);
1538035c6fecSmillert kb_add(x_fold_upper, CTRL('['), 'U', 0);
1539035c6fecSmillert kb_add(x_fold_upper, CTRL('['), 'u', 0);
1540035c6fecSmillert kb_add(x_literal, CTRL('V'), 0);
1541035c6fecSmillert kb_add(x_yank, CTRL('Y'), 0);
1542035c6fecSmillert kb_add(x_meta_yank, CTRL('['), 'y', 0);
1543c250457eSdjm /* man page ends here */
1544f00c5086Smillert
1545c250457eSdjm /* arrow keys */
1546035c6fecSmillert kb_add(x_prev_com, CTRL('['), '[', 'A', 0); /* up */
1547035c6fecSmillert kb_add(x_next_com, CTRL('['), '[', 'B', 0); /* down */
1548035c6fecSmillert kb_add(x_mv_forw, CTRL('['), '[', 'C', 0); /* right */
1549035c6fecSmillert kb_add(x_mv_back, CTRL('['), '[', 'D', 0); /* left */
1550035c6fecSmillert kb_add(x_prev_com, CTRL('['), 'O', 'A', 0); /* up */
1551035c6fecSmillert kb_add(x_next_com, CTRL('['), 'O', 'B', 0); /* down */
1552035c6fecSmillert kb_add(x_mv_forw, CTRL('['), 'O', 'C', 0); /* right */
1553035c6fecSmillert kb_add(x_mv_back, CTRL('['), 'O', 'D', 0); /* left */
1554c250457eSdjm
1555c250457eSdjm /* more navigation keys */
1556035c6fecSmillert kb_add(x_mv_begin, CTRL('['), '[', 'H', 0); /* home */
1557035c6fecSmillert kb_add(x_mv_end, CTRL('['), '[', 'F', 0); /* end */
1558035c6fecSmillert kb_add(x_mv_begin, CTRL('['), 'O', 'H', 0); /* home */
1559035c6fecSmillert kb_add(x_mv_end, CTRL('['), 'O', 'F', 0); /* end */
1560035c6fecSmillert kb_add(x_mv_begin, CTRL('['), '[', '1', '~', 0); /* home */
1561035c6fecSmillert kb_add(x_mv_end, CTRL('['), '[', '4', '~', 0); /* end */
1562035c6fecSmillert kb_add(x_mv_begin, CTRL('['), '[', '7', '~', 0); /* home */
1563035c6fecSmillert kb_add(x_mv_end, CTRL('['), '[', '8', '~', 0); /* end */
1564c250457eSdjm
1565c250457eSdjm /* can't be bound */
1566035c6fecSmillert kb_add(x_set_arg, CTRL('['), '0', 0);
1567035c6fecSmillert kb_add(x_set_arg, CTRL('['), '1', 0);
1568035c6fecSmillert kb_add(x_set_arg, CTRL('['), '2', 0);
1569035c6fecSmillert kb_add(x_set_arg, CTRL('['), '3', 0);
1570035c6fecSmillert kb_add(x_set_arg, CTRL('['), '4', 0);
1571035c6fecSmillert kb_add(x_set_arg, CTRL('['), '5', 0);
1572035c6fecSmillert kb_add(x_set_arg, CTRL('['), '6', 0);
1573035c6fecSmillert kb_add(x_set_arg, CTRL('['), '7', 0);
1574035c6fecSmillert kb_add(x_set_arg, CTRL('['), '8', 0);
1575035c6fecSmillert kb_add(x_set_arg, CTRL('['), '9', 0);
1576c250457eSdjm
1577c250457eSdjm /* ctrl arrow keys */
1578035c6fecSmillert kb_add(x_mv_end, CTRL('['), '[', '1', ';', '5', 'A', 0); /* ctrl up */
1579035c6fecSmillert kb_add(x_mv_begin, CTRL('['), '[', '1', ';', '5', 'B', 0); /* ctrl down */
1580035c6fecSmillert kb_add(x_mv_fword, CTRL('['), '[', '1', ';', '5', 'C', 0); /* ctrl right */
1581035c6fecSmillert kb_add(x_mv_bword, CTRL('['), '[', '1', ';', '5', 'D', 0); /* ctrl left */
1582f00c5086Smillert }
1583f00c5086Smillert
15847cb960a2Sdownsj void
x_emacs_keys(X_chars * ec)1585c5d5393cSotto x_emacs_keys(X_chars *ec)
15867cb960a2Sdownsj {
1587c250457eSdjm x_bind_quiet = 1;
1588f00c5086Smillert if (ec->erase >= 0) {
1589035c6fecSmillert kb_add(x_del_back, ec->erase, 0);
1590035c6fecSmillert kb_add(x_del_bword, CTRL('['), ec->erase, 0);
1591f00c5086Smillert }
1592f00c5086Smillert if (ec->kill >= 0)
1593035c6fecSmillert kb_add(x_del_line, ec->kill, 0);
1594f00c5086Smillert if (ec->werase >= 0)
1595035c6fecSmillert kb_add(x_del_bword, ec->werase, 0);
1596f00c5086Smillert if (ec->intr >= 0)
1597035c6fecSmillert kb_add(x_abort, ec->intr, 0);
1598f00c5086Smillert if (ec->quit >= 0)
1599035c6fecSmillert kb_add(x_noop, ec->quit, 0);
1600c250457eSdjm x_bind_quiet = 0;
16017cb960a2Sdownsj }
16027cb960a2Sdownsj
16037cb960a2Sdownsj static int
x_set_mark(int c)1604c5d5393cSotto x_set_mark(int c)
16057cb960a2Sdownsj {
16067cb960a2Sdownsj xmp = xcp;
16077cb960a2Sdownsj return KSTD;
16087cb960a2Sdownsj }
16097cb960a2Sdownsj
16107cb960a2Sdownsj static int
x_kill_region(int c)1611c5d5393cSotto x_kill_region(int c)
16127cb960a2Sdownsj {
16137cb960a2Sdownsj int rsize;
16147cb960a2Sdownsj char *xr;
16157cb960a2Sdownsj
16167cb960a2Sdownsj if (xmp == NULL) {
16177cb960a2Sdownsj x_e_putc(BEL);
16187cb960a2Sdownsj return KSTD;
16197cb960a2Sdownsj }
16207cb960a2Sdownsj if (xmp > xcp) {
16217cb960a2Sdownsj rsize = xmp - xcp;
16227cb960a2Sdownsj xr = xcp;
16237cb960a2Sdownsj } else {
16247cb960a2Sdownsj rsize = xcp - xmp;
16257cb960a2Sdownsj xr = xmp;
16267cb960a2Sdownsj }
16277cb960a2Sdownsj x_goto(xr);
16280e7d3a01Smillert x_delete(rsize, true);
16297cb960a2Sdownsj xmp = xr;
16307cb960a2Sdownsj return KSTD;
16317cb960a2Sdownsj }
16327cb960a2Sdownsj
16337cb960a2Sdownsj static int
x_xchg_point_mark(int c)1634c5d5393cSotto x_xchg_point_mark(int c)
16357cb960a2Sdownsj {
16367cb960a2Sdownsj char *tmp;
16377cb960a2Sdownsj
16387cb960a2Sdownsj if (xmp == NULL) {
16397cb960a2Sdownsj x_e_putc(BEL);
16407cb960a2Sdownsj return KSTD;
16417cb960a2Sdownsj }
16427cb960a2Sdownsj tmp = xmp;
16437cb960a2Sdownsj xmp = xcp;
16447cb960a2Sdownsj x_goto( tmp );
16457cb960a2Sdownsj return KSTD;
16467cb960a2Sdownsj }
16477cb960a2Sdownsj
16487cb960a2Sdownsj static int
x_noop(int c)1649c5d5393cSotto x_noop(int c)
16507cb960a2Sdownsj {
16517cb960a2Sdownsj return KSTD;
16527cb960a2Sdownsj }
16537cb960a2Sdownsj
16547cb960a2Sdownsj /*
16557cb960a2Sdownsj * File/command name completion routines
16567cb960a2Sdownsj */
16577cb960a2Sdownsj
16587cb960a2Sdownsj static int
x_comp_comm(int c)1659c5d5393cSotto x_comp_comm(int c)
16607cb960a2Sdownsj {
16617cb960a2Sdownsj do_complete(XCF_COMMAND, CT_COMPLETE);
16627cb960a2Sdownsj return KSTD;
16637cb960a2Sdownsj }
16647cb960a2Sdownsj static int
x_list_comm(int c)1665c5d5393cSotto x_list_comm(int c)
16667cb960a2Sdownsj {
16677cb960a2Sdownsj do_complete(XCF_COMMAND, CT_LIST);
16687cb960a2Sdownsj return KSTD;
16697cb960a2Sdownsj }
16707cb960a2Sdownsj static int
x_complete(int c)1671c5d5393cSotto x_complete(int c)
16727cb960a2Sdownsj {
16737cb960a2Sdownsj do_complete(XCF_COMMAND_FILE, CT_COMPLETE);
16747cb960a2Sdownsj return KSTD;
16757cb960a2Sdownsj }
16767cb960a2Sdownsj static int
x_enumerate(int c)1677c5d5393cSotto x_enumerate(int c)
16787cb960a2Sdownsj {
16797cb960a2Sdownsj do_complete(XCF_COMMAND_FILE, CT_LIST);
16807cb960a2Sdownsj return KSTD;
16817cb960a2Sdownsj }
16827cb960a2Sdownsj static int
x_comp_file(int c)1683c5d5393cSotto x_comp_file(int c)
16847cb960a2Sdownsj {
16857cb960a2Sdownsj do_complete(XCF_FILE, CT_COMPLETE);
16867cb960a2Sdownsj return KSTD;
16877cb960a2Sdownsj }
16887cb960a2Sdownsj static int
x_list_file(int c)1689c5d5393cSotto x_list_file(int c)
16907cb960a2Sdownsj {
16917cb960a2Sdownsj do_complete(XCF_FILE, CT_LIST);
16927cb960a2Sdownsj return KSTD;
16937cb960a2Sdownsj }
16947cb960a2Sdownsj static int
x_comp_list(int c)1695c5d5393cSotto x_comp_list(int c)
16967cb960a2Sdownsj {
16977cb960a2Sdownsj do_complete(XCF_COMMAND_FILE, CT_COMPLIST);
16987cb960a2Sdownsj return KSTD;
16997cb960a2Sdownsj }
17007cb960a2Sdownsj static int
x_expand(int c)1701c5d5393cSotto x_expand(int c)
17027cb960a2Sdownsj {
17037cb960a2Sdownsj char **words;
17047cb960a2Sdownsj int nwords = 0;
17057cb960a2Sdownsj int start, end;
17067cb960a2Sdownsj int is_command;
17077cb960a2Sdownsj int i;
17087cb960a2Sdownsj
17097a8124d8Sderaadt nwords = x_cf_glob(XCF_FILE, xbuf, xep - xbuf, xcp - xbuf,
17107cb960a2Sdownsj &start, &end, &words, &is_command);
17117cb960a2Sdownsj
17127cb960a2Sdownsj if (nwords == 0) {
17137cb960a2Sdownsj x_e_putc(BEL);
17147cb960a2Sdownsj return KSTD;
17157cb960a2Sdownsj }
17167cb960a2Sdownsj
17177cb960a2Sdownsj x_goto(xbuf + start);
17180e7d3a01Smillert x_delete(end - start, false);
1719bd21a13fSfgsch for (i = 0; i < nwords;) {
17209ecf7f57Smillert if (x_escape(words[i], strlen(words[i]), x_do_ins) < 0 ||
172196085982Snicm (++i < nwords && x_ins(" ") < 0)) {
17227cb960a2Sdownsj x_e_putc(BEL);
17237cb960a2Sdownsj return KSTD;
17247cb960a2Sdownsj }
1725bd21a13fSfgsch }
1726bd21a13fSfgsch x_adjust();
17277cb960a2Sdownsj
17287cb960a2Sdownsj return KSTD;
17297cb960a2Sdownsj }
17307cb960a2Sdownsj
17317cb960a2Sdownsj /* type == 0 for list, 1 for complete and 2 for complete-list */
17327cb960a2Sdownsj static void
do_complete(int flags,Comp_type type)1733c5d5393cSotto do_complete(int flags, /* XCF_{COMMAND,FILE,COMMAND_FILE} */
1734c5d5393cSotto Comp_type type)
17357cb960a2Sdownsj {
17367cb960a2Sdownsj char **words;
17379ca598aeScamield int nwords;
17389ca598aeScamield int start, end, nlen, olen;
17397cb960a2Sdownsj int is_command;
17409ca598aeScamield int completed = 0;
17417cb960a2Sdownsj
17429ca598aeScamield nwords = x_cf_glob(flags, xbuf, xep - xbuf, xcp - xbuf,
17437cb960a2Sdownsj &start, &end, &words, &is_command);
17449ca598aeScamield /* no match */
17457cb960a2Sdownsj if (nwords == 0) {
17467cb960a2Sdownsj x_e_putc(BEL);
17477cb960a2Sdownsj return;
17487cb960a2Sdownsj }
17499ca598aeScamield
17509ca598aeScamield if (type == CT_LIST) {
17517cb960a2Sdownsj x_print_expansions(nwords, words, is_command);
17527cb960a2Sdownsj x_redraw(0);
17539ca598aeScamield x_free_words(nwords, words);
17549ca598aeScamield return;
17557cb960a2Sdownsj }
17567cb960a2Sdownsj
17579ca598aeScamield olen = end - start;
17589ca598aeScamield nlen = x_longest_prefix(nwords, words);
1759f0c97affScamield /* complete */
1760de04cf22Sfgsch if (nwords == 1 || nlen > olen) {
17617cb960a2Sdownsj x_goto(xbuf + start);
17620e7d3a01Smillert x_delete(olen, false);
17639ecf7f57Smillert x_escape(words[0], nlen, x_do_ins);
1764953559d8Sd x_adjust();
17659ca598aeScamield completed = 1;
17669ca598aeScamield }
1767f0c97affScamield /* add space if single non-dir match */
176869b9f96bSmillert if (nwords == 1 && words[0][nlen - 1] != '/') {
176996085982Snicm x_ins(" ");
17709ca598aeScamield completed = 1;
17717cb960a2Sdownsj }
17729ca598aeScamield
17739ca598aeScamield if (type == CT_COMPLIST && !completed) {
17749ca598aeScamield x_print_expansions(nwords, words, is_command);
17759ca598aeScamield completed = 1;
17767cb960a2Sdownsj }
17779ca598aeScamield
17789ca598aeScamield if (completed)
17799ca598aeScamield x_redraw(0);
17809ca598aeScamield
17819ca598aeScamield x_free_words(nwords, words);
17827cb960a2Sdownsj }
17837cb960a2Sdownsj
17847cb960a2Sdownsj /* NAME:
17857cb960a2Sdownsj * x_adjust - redraw the line adjusting starting point etc.
17867cb960a2Sdownsj *
17877cb960a2Sdownsj * DESCRIPTION:
17887cb960a2Sdownsj * This function is called when we have exceeded the bounds
17897cb960a2Sdownsj * of the edit window. It increments x_adj_done so that
17907cb960a2Sdownsj * functions like x_ins and x_delete know that we have been
17917cb960a2Sdownsj * called and can skip the x_bs() stuff which has already
17927cb960a2Sdownsj * been done by x_redraw.
17937cb960a2Sdownsj *
17947cb960a2Sdownsj * RETURN VALUE:
17957cb960a2Sdownsj * None
17967cb960a2Sdownsj */
17977cb960a2Sdownsj
17987cb960a2Sdownsj static void
x_adjust(void)1799c5d5393cSotto x_adjust(void)
18007cb960a2Sdownsj {
18017cb960a2Sdownsj x_adj_done++; /* flag the fact that we were called. */
18027cb960a2Sdownsj /*
1803dcacb757Sdownsj * we had a problem if the prompt length > xx_cols / 2
18047cb960a2Sdownsj */
18057cb960a2Sdownsj if ((xbp = xcp - (x_displen / 2)) < xbuf)
18067cb960a2Sdownsj xbp = xbuf;
18070e7d3a01Smillert xlp_valid = false;
1808dcacb757Sdownsj x_redraw(xx_cols);
18097cb960a2Sdownsj x_flush();
18107cb960a2Sdownsj }
18117cb960a2Sdownsj
18127cb960a2Sdownsj static int unget_char = -1;
18137cb960a2Sdownsj
18147cb960a2Sdownsj static void
x_e_ungetc(int c)1815c5d5393cSotto x_e_ungetc(int c)
18167cb960a2Sdownsj {
18177cb960a2Sdownsj unget_char = c;
18187cb960a2Sdownsj }
18197cb960a2Sdownsj
18207cb960a2Sdownsj static int
x_e_getc(void)1821c5d5393cSotto x_e_getc(void)
18227cb960a2Sdownsj {
18237cb960a2Sdownsj int c;
18247cb960a2Sdownsj
18257cb960a2Sdownsj if (unget_char >= 0) {
18267cb960a2Sdownsj c = unget_char;
18277cb960a2Sdownsj unget_char = -1;
182844d96bb9Smpi } else if (macro_args) {
182944d96bb9Smpi c = *macro_args++;
183044d96bb9Smpi if (!c) {
183144d96bb9Smpi macro_args = NULL;
183244d96bb9Smpi c = x_getc();
183344d96bb9Smpi }
18347cb960a2Sdownsj } else
18357cb960a2Sdownsj c = x_getc();
18367cb960a2Sdownsj
1837c250457eSdjm return c;
18387cb960a2Sdownsj }
18397cb960a2Sdownsj
18408a9faaaaSanton static int
x_e_getu8(char * buf,int off)18418a9faaaaSanton x_e_getu8(char *buf, int off)
18428a9faaaaSanton {
18438a9faaaaSanton int c, cc, len;
18448a9faaaaSanton
18458a9faaaaSanton c = x_e_getc();
18468a9faaaaSanton if (c == -1)
18478a9faaaaSanton return -1;
18488a9faaaaSanton buf[off++] = c;
18498a9faaaaSanton
18509704c0f8Sschwarze /*
18519704c0f8Sschwarze * In the following, comments refer to violations of
18529704c0f8Sschwarze * the inequality tests at the ends of the lines.
18539704c0f8Sschwarze * See the utf8(7) manual page for details.
18549704c0f8Sschwarze */
18559704c0f8Sschwarze
18569704c0f8Sschwarze if ((c & 0xf8) == 0xf0 && c < 0xf5) /* beyond Unicode */
18578a9faaaaSanton len = 4;
18588a9faaaaSanton else if ((c & 0xf0) == 0xe0)
18598a9faaaaSanton len = 3;
18609704c0f8Sschwarze else if ((c & 0xe0) == 0xc0 && c > 0xc1) /* use single byte */
18618a9faaaaSanton len = 2;
18628a9faaaaSanton else
18638a9faaaaSanton len = 1;
18648a9faaaaSanton
18658a9faaaaSanton for (; len > 1; len--) {
18668a9faaaaSanton cc = x_e_getc();
18678a9faaaaSanton if (cc == -1)
18688a9faaaaSanton break;
18698a9faaaaSanton if (isu8cont(cc) == 0 ||
18709704c0f8Sschwarze (c == 0xe0 && len == 3 && cc < 0xa0) || /* use 2 bytes */
18719704c0f8Sschwarze (c == 0xed && len == 3 && cc > 0x9f) || /* surrogates */
18729704c0f8Sschwarze (c == 0xf0 && len == 4 && cc < 0x90) || /* use 3 bytes */
18739704c0f8Sschwarze (c == 0xf4 && len == 4 && cc > 0x8f)) { /* beyond Uni. */
18748a9faaaaSanton x_e_ungetc(cc);
18758a9faaaaSanton break;
18768a9faaaaSanton }
18778a9faaaaSanton buf[off++] = cc;
18788a9faaaaSanton }
18798a9faaaaSanton buf[off] = '\0';
18808a9faaaaSanton
18818a9faaaaSanton return off;
18828a9faaaaSanton }
18838a9faaaaSanton
18847cb960a2Sdownsj static void
x_e_putc(int c)1885c5d5393cSotto x_e_putc(int c)
18867cb960a2Sdownsj {
18877cb960a2Sdownsj if (c == '\r' || c == '\n')
18887cb960a2Sdownsj x_col = 0;
18897a8124d8Sderaadt if (x_col < xx_cols) {
18907cb960a2Sdownsj x_putc(c);
18917a8124d8Sderaadt switch (c) {
18927cb960a2Sdownsj case BEL:
18937cb960a2Sdownsj break;
18947cb960a2Sdownsj case '\r':
18957cb960a2Sdownsj case '\n':
18967cb960a2Sdownsj break;
18977cb960a2Sdownsj case '\b':
18987cb960a2Sdownsj x_col--;
18997cb960a2Sdownsj break;
19007cb960a2Sdownsj default:
19013e173141Sschwarze if (!isu8cont(c))
19027cb960a2Sdownsj x_col++;
19037cb960a2Sdownsj break;
19047cb960a2Sdownsj }
19057cb960a2Sdownsj }
1906dcacb757Sdownsj if (x_adj_ok && (x_col < 0 || x_col >= (xx_cols - 2)))
19077cb960a2Sdownsj x_adjust();
19087cb960a2Sdownsj }
19097cb960a2Sdownsj
19107cb960a2Sdownsj #ifdef DEBUG
19117cb960a2Sdownsj static int
x_debug_info(int c)1912c5d5393cSotto x_debug_info(int c)
19137cb960a2Sdownsj {
19147cb960a2Sdownsj x_flush();
1915dcacb757Sdownsj shellf("\nksh debug:\n");
1916dcacb757Sdownsj shellf("\tx_col == %d,\t\tx_cols == %d,\tx_displen == %d\n",
1917dcacb757Sdownsj x_col, xx_cols, x_displen);
1918dcacb757Sdownsj shellf("\txcp == 0x%lx,\txep == 0x%lx\n", (long) xcp, (long) xep);
1919dcacb757Sdownsj shellf("\txbp == 0x%lx,\txbuf == 0x%lx\n", (long) xbp, (long) xbuf);
1920dcacb757Sdownsj shellf("\txlp == 0x%lx\n", (long) xlp);
1921dcacb757Sdownsj shellf("\txlp == 0x%lx\n", (long) x_lastcp());
192296085982Snicm shellf("\n");
19237cb960a2Sdownsj x_redraw(-1);
19247cb960a2Sdownsj return 0;
19257cb960a2Sdownsj }
19267cb960a2Sdownsj #endif
19277cb960a2Sdownsj
19287cb960a2Sdownsj static void
x_e_puts(const char * s)1929c5d5393cSotto x_e_puts(const char *s)
19307cb960a2Sdownsj {
19317894b443Smillert int adj = x_adj_done;
19327cb960a2Sdownsj
19337cb960a2Sdownsj while (*s && adj == x_adj_done)
19347cb960a2Sdownsj x_e_putc(*s++);
19357cb960a2Sdownsj }
19367cb960a2Sdownsj
19377cb960a2Sdownsj /* NAME:
19387cb960a2Sdownsj * x_set_arg - set an arg value for next function
19397cb960a2Sdownsj *
19407cb960a2Sdownsj * DESCRIPTION:
19417cb960a2Sdownsj * This is a simple implementation of M-[0-9].
19427cb960a2Sdownsj *
19437cb960a2Sdownsj * RETURN VALUE:
19447cb960a2Sdownsj * KSTD
19457cb960a2Sdownsj */
19467cb960a2Sdownsj
19477cb960a2Sdownsj static int
x_set_arg(int c)1948c5d5393cSotto x_set_arg(int c)
19497cb960a2Sdownsj {
19507cb960a2Sdownsj int n = 0;
19517cb960a2Sdownsj int first = 1;
19527cb960a2Sdownsj
1953c250457eSdjm for (; c >= 0 && isdigit(c); c = x_e_getc(), first = 0)
19547cb960a2Sdownsj n = n * 10 + (c - '0');
19557cb960a2Sdownsj if (c < 0 || first) {
19567cb960a2Sdownsj x_e_putc(BEL);
19577cb960a2Sdownsj x_arg = 1;
19587cb960a2Sdownsj x_arg_defaulted = 1;
19597cb960a2Sdownsj } else {
19607cb960a2Sdownsj x_e_ungetc(c);
19617cb960a2Sdownsj x_arg = n;
19627cb960a2Sdownsj x_arg_defaulted = 0;
1963c250457eSdjm x_arg_set = 1;
19647cb960a2Sdownsj }
19657cb960a2Sdownsj return KSTD;
19667cb960a2Sdownsj }
19677cb960a2Sdownsj
19687cb960a2Sdownsj
1969dcacb757Sdownsj /* Comment or uncomment the current line. */
1970dcacb757Sdownsj static int
x_comment(int c)1971c5d5393cSotto x_comment(int c)
1972dcacb757Sdownsj {
1973dcacb757Sdownsj int oldsize = x_size_str(xbuf);
1974dcacb757Sdownsj int len = xep - xbuf;
1975dcacb757Sdownsj int ret = x_do_comment(xbuf, xend - xbuf, &len);
1976dcacb757Sdownsj
1977dcacb757Sdownsj if (ret < 0)
1978dcacb757Sdownsj x_e_putc(BEL);
1979dcacb757Sdownsj else {
1980dcacb757Sdownsj xep = xbuf + len;
1981dcacb757Sdownsj *xep = '\0';
1982dcacb757Sdownsj xcp = xbp = xbuf;
1983dcacb757Sdownsj x_redraw(oldsize);
1984dcacb757Sdownsj if (ret > 0)
1985dcacb757Sdownsj return x_newline('\n');
1986dcacb757Sdownsj }
1987dcacb757Sdownsj return KSTD;
1988dcacb757Sdownsj }
1989dcacb757Sdownsj
1990dcacb757Sdownsj
19917cb960a2Sdownsj /* NAME:
19927cb960a2Sdownsj * x_prev_histword - recover word from prev command
19937cb960a2Sdownsj *
19947cb960a2Sdownsj * DESCRIPTION:
19957cb960a2Sdownsj * This function recovers the last word from the previous
19967cb960a2Sdownsj * command and inserts it into the current edit line. If a
19977cb960a2Sdownsj * numeric arg is supplied then the n'th word from the
19987cb960a2Sdownsj * start of the previous command is used.
19997cb960a2Sdownsj *
20007cb960a2Sdownsj * Bound to M-.
20017cb960a2Sdownsj *
20027cb960a2Sdownsj * RETURN VALUE:
20037cb960a2Sdownsj * KSTD
20047cb960a2Sdownsj */
20057cb960a2Sdownsj
20067cb960a2Sdownsj static int
x_prev_histword(int c)2007c5d5393cSotto x_prev_histword(int c)
20087cb960a2Sdownsj {
20097894b443Smillert char *rcp;
20107cb960a2Sdownsj char *cp;
20117cb960a2Sdownsj
20123b015934Smillert cp = *histptr;
2013040161f7Smillert if (!cp)
2014040161f7Smillert x_e_putc(BEL);
2015040161f7Smillert else if (x_arg_defaulted) {
20167cb960a2Sdownsj rcp = &cp[strlen(cp) - 1];
20177cb960a2Sdownsj /*
20187cb960a2Sdownsj * ignore white-space after the last word
20197cb960a2Sdownsj */
20207cb960a2Sdownsj while (rcp > cp && is_cfs(*rcp))
20217cb960a2Sdownsj rcp--;
20227cb960a2Sdownsj while (rcp > cp && !is_cfs(*rcp))
20237cb960a2Sdownsj rcp--;
20247cb960a2Sdownsj if (is_cfs(*rcp))
20257cb960a2Sdownsj rcp++;
20267cb960a2Sdownsj x_ins(rcp);
20277cb960a2Sdownsj } else {
20287cb960a2Sdownsj rcp = cp;
20297cb960a2Sdownsj /*
20307cb960a2Sdownsj * ignore white-space at start of line
20317cb960a2Sdownsj */
20327cb960a2Sdownsj while (*rcp && is_cfs(*rcp))
20337cb960a2Sdownsj rcp++;
20347894b443Smillert while (x_arg-- > 1) {
20357cb960a2Sdownsj while (*rcp && !is_cfs(*rcp))
20367cb960a2Sdownsj rcp++;
20377cb960a2Sdownsj while (*rcp && is_cfs(*rcp))
20387cb960a2Sdownsj rcp++;
20397cb960a2Sdownsj }
20407cb960a2Sdownsj cp = rcp;
20417cb960a2Sdownsj while (*rcp && !is_cfs(*rcp))
20427cb960a2Sdownsj rcp++;
20437cb960a2Sdownsj c = *rcp;
20447cb960a2Sdownsj *rcp = '\0';
20457cb960a2Sdownsj x_ins(cp);
20467cb960a2Sdownsj *rcp = c;
20477cb960a2Sdownsj }
20487cb960a2Sdownsj return KSTD;
20497cb960a2Sdownsj }
20507cb960a2Sdownsj
20517cb960a2Sdownsj /* Uppercase N(1) words */
20527cb960a2Sdownsj static int
x_fold_upper(int c)2053c5d5393cSotto x_fold_upper(int c)
20547cb960a2Sdownsj {
20557cb960a2Sdownsj return x_fold_case('U');
20567cb960a2Sdownsj }
20577cb960a2Sdownsj
20587cb960a2Sdownsj /* Lowercase N(1) words */
20597cb960a2Sdownsj static int
x_fold_lower(int c)2060c5d5393cSotto x_fold_lower(int c)
20617cb960a2Sdownsj {
20627cb960a2Sdownsj return x_fold_case('L');
20637cb960a2Sdownsj }
20647cb960a2Sdownsj
20657cb960a2Sdownsj /* Lowercase N(1) words */
20667cb960a2Sdownsj static int
x_fold_capitalize(int c)2067c5d5393cSotto x_fold_capitalize(int c)
20687cb960a2Sdownsj {
20697cb960a2Sdownsj return x_fold_case('C');
20707cb960a2Sdownsj }
20717cb960a2Sdownsj
20727cb960a2Sdownsj /* NAME:
207312e7fb2dSjmc * x_fold_case - convert word to UPPER/lower/Capital case
20747cb960a2Sdownsj *
20757cb960a2Sdownsj * DESCRIPTION:
20767cb960a2Sdownsj * This function is used to implement M-U,M-u,M-L,M-l,M-C and M-c
20777cb960a2Sdownsj * to UPPER case, lower case or Capitalize words.
20787cb960a2Sdownsj *
20797cb960a2Sdownsj * RETURN VALUE:
20807cb960a2Sdownsj * None
20817cb960a2Sdownsj */
20827cb960a2Sdownsj
20837cb960a2Sdownsj static int
x_fold_case(int c)2084c5d5393cSotto x_fold_case(int c)
20857cb960a2Sdownsj {
20867cb960a2Sdownsj char *cp = xcp;
20877cb960a2Sdownsj
20887cb960a2Sdownsj if (cp == xep) {
20897cb960a2Sdownsj x_e_putc(BEL);
20907cb960a2Sdownsj return KSTD;
20917cb960a2Sdownsj }
20927cb960a2Sdownsj while (x_arg--) {
20937cb960a2Sdownsj /*
2094060cee32Sjmc * first skip over any white-space
20957cb960a2Sdownsj */
20967cb960a2Sdownsj while (cp != xep && is_mfs(*cp))
20977cb960a2Sdownsj cp++;
20987cb960a2Sdownsj /*
20997cb960a2Sdownsj * do the first char on its own since it may be
21007cb960a2Sdownsj * a different action than for the rest.
21017cb960a2Sdownsj */
21027cb960a2Sdownsj if (cp != xep) {
21037cb960a2Sdownsj if (c == 'L') { /* lowercase */
2104e569fc7cSderaadt if (isupper((unsigned char)*cp))
2105e569fc7cSderaadt *cp = tolower((unsigned char)*cp);
2106060cee32Sjmc } else { /* uppercase, capitalize */
2107e569fc7cSderaadt if (islower((unsigned char)*cp))
2108e569fc7cSderaadt *cp = toupper((unsigned char)*cp);
21097cb960a2Sdownsj }
21107cb960a2Sdownsj cp++;
21117cb960a2Sdownsj }
21127cb960a2Sdownsj /*
21137cb960a2Sdownsj * now for the rest of the word
21147cb960a2Sdownsj */
21157cb960a2Sdownsj while (cp != xep && !is_mfs(*cp)) {
21167cb960a2Sdownsj if (c == 'U') { /* uppercase */
2117e569fc7cSderaadt if (islower((unsigned char)*cp))
2118e569fc7cSderaadt *cp = toupper((unsigned char)*cp);
2119060cee32Sjmc } else { /* lowercase, capitalize */
2120e569fc7cSderaadt if (isupper((unsigned char)*cp))
2121e569fc7cSderaadt *cp = tolower((unsigned char)*cp);
21227cb960a2Sdownsj }
21237cb960a2Sdownsj cp++;
21247cb960a2Sdownsj }
21257cb960a2Sdownsj }
21267cb960a2Sdownsj x_goto(cp);
21277cb960a2Sdownsj return KSTD;
21287cb960a2Sdownsj }
21297cb960a2Sdownsj
21307cb960a2Sdownsj /* NAME:
21315cc68a1dSschwarze * x_lastcp - last visible byte
21327cb960a2Sdownsj *
21337cb960a2Sdownsj * SYNOPSIS:
21347cb960a2Sdownsj * x_lastcp()
21357cb960a2Sdownsj *
21367cb960a2Sdownsj * DESCRIPTION:
21375cc68a1dSschwarze * This function returns a pointer to that byte in the
21387cb960a2Sdownsj * edit buffer that will be the last displayed on the
21397cb960a2Sdownsj * screen. The sequence:
21407cb960a2Sdownsj *
21417cb960a2Sdownsj * for (cp = x_lastcp(); cp > xcp; cp)
21427cb960a2Sdownsj * x_bs(*--cp);
21437cb960a2Sdownsj *
21447cb960a2Sdownsj * Will position the cursor correctly on the screen.
21457cb960a2Sdownsj *
21467cb960a2Sdownsj * RETURN VALUE:
21477cb960a2Sdownsj * cp or NULL
21487cb960a2Sdownsj */
21497cb960a2Sdownsj
21507cb960a2Sdownsj static char *
x_lastcp(void)2151c5d5393cSotto x_lastcp(void)
21527cb960a2Sdownsj {
21537894b443Smillert char *rcp;
21547894b443Smillert int i;
21557cb960a2Sdownsj
21567894b443Smillert if (!xlp_valid) {
21577cb960a2Sdownsj for (i = 0, rcp = xbp; rcp < xep && i < x_displen; rcp++)
2158e569fc7cSderaadt i += x_size((unsigned char)*rcp);
21597cb960a2Sdownsj xlp = rcp;
21607cb960a2Sdownsj }
21610e7d3a01Smillert xlp_valid = true;
21627cb960a2Sdownsj return (xlp);
21637cb960a2Sdownsj }
21647cb960a2Sdownsj
21659a36d1f0Santon #endif /* EMACS */
2166