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