1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/editline/editline.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1341 @@ 1.4 +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + * Copyright 1992,1993 Simmule Turner and Rich Salz. All rights reserved. 1.11 + * 1.12 + * This software is not subject to any license of the American Telephone 1.13 + * and Telegraph Company or of the Regents of the University of California. 1.14 + * 1.15 + * Permission is granted to anyone to use this software for any purpose on 1.16 + * any computer system, and to alter it and redistribute it freely, subject 1.17 + * to the following restrictions: 1.18 + * 1. The authors are not responsible for the consequences of use of this 1.19 + * software, no matter how awful, even if they arise from flaws in it. 1.20 + * 2. The origin of this software must not be misrepresented, either by 1.21 + * explicit claim or by omission. Since few users ever read sources, 1.22 + * credits must appear in the documentation. 1.23 + * 3. Altered versions must be plainly marked as such, and must not be 1.24 + * misrepresented as being the original software. Since few users 1.25 + * ever read sources, credits must appear in the documentation. 1.26 + * 4. This notice may not be removed or altered. 1.27 + */ 1.28 + 1.29 + 1.30 +/* 1.31 +** Main editing routines for editline library. 1.32 +*/ 1.33 +#include "editline.h" 1.34 +#include <signal.h> 1.35 +#include <ctype.h> 1.36 +#include <unistd.h> 1.37 + 1.38 +/* 1.39 +** Manifest constants. 1.40 +*/ 1.41 +#define SCREEN_WIDTH 80 1.42 +#define SCREEN_ROWS 24 1.43 +#define NO_ARG (-1) 1.44 +#define DEL 127 1.45 +#define CTL(x) ((x) & 0x1F) 1.46 +#define ISCTL(x) ((x) && (x) < ' ') 1.47 +#define UNCTL(x) ((x) + 64) 1.48 +#define META(x) ((x) | 0x80) 1.49 +#define ISMETA(x) ((x) & 0x80) 1.50 +#define UNMETA(x) ((x) & 0x7F) 1.51 +#if !defined(HIST_SIZE) 1.52 +#define HIST_SIZE 20 1.53 +#endif /* !defined(HIST_SIZE) */ 1.54 + 1.55 +/* 1.56 +** Command status codes. 1.57 +*/ 1.58 +typedef enum _STATUS { 1.59 + CSdone, CSeof, CSmove, CSdispatch, CSstay, CSsignal 1.60 +} STATUS; 1.61 + 1.62 +/* 1.63 +** The type of case-changing to perform. 1.64 +*/ 1.65 +typedef enum _CASE { 1.66 + TOupper, TOlower 1.67 +} CASE; 1.68 + 1.69 +/* 1.70 +** Key to command mapping. 1.71 +*/ 1.72 +typedef struct _KEYMAP { 1.73 + CHAR Key; 1.74 + STATUS (*Function)(); 1.75 +} KEYMAP; 1.76 + 1.77 +/* 1.78 +** Command history structure. 1.79 +*/ 1.80 +typedef struct _HISTORY { 1.81 + int Size; 1.82 + int Pos; 1.83 + CHAR *Lines[HIST_SIZE]; 1.84 +} HISTORY; 1.85 + 1.86 +/* 1.87 +** Globals. 1.88 +*/ 1.89 +unsigned rl_eof; 1.90 +unsigned rl_erase; 1.91 +unsigned rl_intr; 1.92 +unsigned rl_kill; 1.93 +unsigned rl_quit; 1.94 + 1.95 +STATIC CHAR NIL[] = ""; 1.96 +STATIC CONST CHAR *Input = NIL; 1.97 +STATIC CHAR *Line; 1.98 +STATIC CONST char *Prompt; 1.99 +STATIC CHAR *Yanked; 1.100 +STATIC char *Screen; 1.101 +STATIC CONST char NEWLINE[]= CRLF; 1.102 +STATIC HISTORY H; 1.103 +STATIC int Repeat; 1.104 +STATIC int End; 1.105 +STATIC int Mark; 1.106 +STATIC int OldPoint; 1.107 +STATIC int Point; 1.108 +STATIC int PushBack; 1.109 +STATIC int Pushed; 1.110 +STATIC int Signal; 1.111 +FORWARD CONST KEYMAP Map[32]; 1.112 +FORWARD CONST KEYMAP MetaMap[16]; 1.113 +STATIC SIZE_T Length; 1.114 +STATIC SIZE_T ScreenCount; 1.115 +STATIC SIZE_T ScreenSize; 1.116 +STATIC char *backspace; 1.117 +STATIC int TTYwidth; 1.118 +STATIC int TTYrows; 1.119 + 1.120 +/* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */ 1.121 +int rl_meta_chars = 0; 1.122 + 1.123 +/* 1.124 +** Declarations. 1.125 +*/ 1.126 +STATIC CHAR *editinput(); 1.127 +#if defined(USE_TERMCAP) 1.128 +#include <stdlib.h> 1.129 +#include <curses.h> 1.130 +#include <term.h> 1.131 +#endif /* defined(USE_TERMCAP) */ 1.132 + 1.133 +/* 1.134 +** TTY input/output functions. 1.135 +*/ 1.136 + 1.137 +STATIC void 1.138 +TTYflush() 1.139 +{ 1.140 + if (ScreenCount) { 1.141 + /* Dummy assignment avoids GCC warning on 1.142 + * "attribute warn_unused_result" */ 1.143 + ssize_t dummy = write(1, Screen, ScreenCount); 1.144 + (void)dummy; 1.145 + ScreenCount = 0; 1.146 + } 1.147 +} 1.148 + 1.149 +STATIC void 1.150 +TTYput(c) 1.151 + CHAR c; 1.152 +{ 1.153 + Screen[ScreenCount] = c; 1.154 + if (++ScreenCount >= ScreenSize - 1) { 1.155 + ScreenSize += SCREEN_INC; 1.156 + RENEW(Screen, char, ScreenSize); 1.157 + } 1.158 +} 1.159 + 1.160 +STATIC void 1.161 +TTYputs(p) 1.162 + CONST CHAR *p; 1.163 +{ 1.164 + while (*p) 1.165 + TTYput(*p++); 1.166 +} 1.167 + 1.168 +STATIC void 1.169 +TTYshow(c) 1.170 + CHAR c; 1.171 +{ 1.172 + if (c == DEL) { 1.173 + TTYput('^'); 1.174 + TTYput('?'); 1.175 + } 1.176 + else if (ISCTL(c)) { 1.177 + TTYput('^'); 1.178 + TTYput(UNCTL(c)); 1.179 + } 1.180 + else if (rl_meta_chars && ISMETA(c)) { 1.181 + TTYput('M'); 1.182 + TTYput('-'); 1.183 + TTYput(UNMETA(c)); 1.184 + } 1.185 + else 1.186 + TTYput(c); 1.187 +} 1.188 + 1.189 +STATIC void 1.190 +TTYstring(p) 1.191 + CHAR *p; 1.192 +{ 1.193 + while (*p) 1.194 + TTYshow(*p++); 1.195 +} 1.196 + 1.197 +STATIC unsigned int 1.198 +TTYget() 1.199 +{ 1.200 + CHAR c; 1.201 + 1.202 + TTYflush(); 1.203 + if (Pushed) { 1.204 + Pushed = 0; 1.205 + return PushBack; 1.206 + } 1.207 + if (*Input) 1.208 + return *Input++; 1.209 + return read(0, &c, (SIZE_T)1) == 1 ? c : EOF; 1.210 +} 1.211 + 1.212 +#define TTYback() (backspace ? TTYputs((CHAR *)backspace) : TTYput('\b')) 1.213 + 1.214 +STATIC void 1.215 +TTYbackn(n) 1.216 + int n; 1.217 +{ 1.218 + while (--n >= 0) 1.219 + TTYback(); 1.220 +} 1.221 + 1.222 +STATIC void 1.223 +TTYinfo() 1.224 +{ 1.225 + static int init; 1.226 +#if defined(USE_TERMCAP) 1.227 + char *term; 1.228 + char buff[2048]; 1.229 + char *bp, *p; 1.230 +#endif /* defined(USE_TERMCAP) */ 1.231 +#if defined(TIOCGWINSZ) 1.232 + struct winsize W; 1.233 +#endif /* defined(TIOCGWINSZ) */ 1.234 + 1.235 + if (init) { 1.236 +#if defined(TIOCGWINSZ) 1.237 + /* Perhaps we got resized. */ 1.238 + if (ioctl(0, TIOCGWINSZ, &W) >= 0 1.239 + && W.ws_col > 0 && W.ws_row > 0) { 1.240 + TTYwidth = (int)W.ws_col; 1.241 + TTYrows = (int)W.ws_row; 1.242 + } 1.243 +#endif /* defined(TIOCGWINSZ) */ 1.244 + return; 1.245 + } 1.246 + init++; 1.247 + 1.248 + TTYwidth = TTYrows = 0; 1.249 +#if defined(USE_TERMCAP) 1.250 + bp = &buff[0]; 1.251 + if ((term = getenv("TERM")) == NULL) 1.252 + term = "dumb"; 1.253 + if (tgetent(buff, term) < 0) { 1.254 + TTYwidth = SCREEN_WIDTH; 1.255 + TTYrows = SCREEN_ROWS; 1.256 + return; 1.257 + } 1.258 + p = tgetstr("le", &bp); 1.259 + backspace = p ? strdup(p) : NULL; 1.260 + TTYwidth = tgetnum("co"); 1.261 + TTYrows = tgetnum("li"); 1.262 +#endif /* defined(USE_TERMCAP) */ 1.263 + 1.264 +#if defined(TIOCGWINSZ) 1.265 + if (ioctl(0, TIOCGWINSZ, &W) >= 0) { 1.266 + TTYwidth = (int)W.ws_col; 1.267 + TTYrows = (int)W.ws_row; 1.268 + } 1.269 +#endif /* defined(TIOCGWINSZ) */ 1.270 + 1.271 + if (TTYwidth <= 0 || TTYrows <= 0) { 1.272 + TTYwidth = SCREEN_WIDTH; 1.273 + TTYrows = SCREEN_ROWS; 1.274 + } 1.275 +} 1.276 + 1.277 + 1.278 +STATIC void 1.279 +reposition() 1.280 +{ 1.281 + int i; 1.282 + CHAR *p; 1.283 + 1.284 + TTYput('\r'); 1.285 + TTYputs((CONST CHAR *)Prompt); 1.286 + for (i = Point, p = Line; --i >= 0; p++) 1.287 + TTYshow(*p); 1.288 +} 1.289 + 1.290 +STATIC void 1.291 +left(Change) 1.292 + STATUS Change; 1.293 +{ 1.294 + TTYback(); 1.295 + if (Point) { 1.296 + if (ISCTL(Line[Point - 1])) 1.297 + TTYback(); 1.298 + else if (rl_meta_chars && ISMETA(Line[Point - 1])) { 1.299 + TTYback(); 1.300 + TTYback(); 1.301 + } 1.302 + } 1.303 + if (Change == CSmove) 1.304 + Point--; 1.305 +} 1.306 + 1.307 +STATIC void 1.308 +right(Change) 1.309 + STATUS Change; 1.310 +{ 1.311 + TTYshow(Line[Point]); 1.312 + if (Change == CSmove) 1.313 + Point++; 1.314 +} 1.315 + 1.316 +STATIC STATUS 1.317 +ring_bell() 1.318 +{ 1.319 + TTYput('\07'); 1.320 + TTYflush(); 1.321 + return CSstay; 1.322 +} 1.323 + 1.324 +STATIC STATUS 1.325 +do_macro(c) 1.326 + unsigned int c; 1.327 +{ 1.328 + CHAR name[4]; 1.329 + 1.330 + name[0] = '_'; 1.331 + name[1] = c; 1.332 + name[2] = '_'; 1.333 + name[3] = '\0'; 1.334 + 1.335 + if ((Input = (CHAR *)getenv((char *)name)) == NULL) { 1.336 + Input = NIL; 1.337 + return ring_bell(); 1.338 + } 1.339 + return CSstay; 1.340 +} 1.341 + 1.342 +STATIC STATUS 1.343 +do_forward(move) 1.344 + STATUS move; 1.345 +{ 1.346 + int i; 1.347 + CHAR *p; 1.348 + 1.349 + i = 0; 1.350 + do { 1.351 + p = &Line[Point]; 1.352 + for ( ; Point < End && (*p == ' ' || !isalnum(*p)); Point++, p++) 1.353 + if (move == CSmove) 1.354 + right(CSstay); 1.355 + 1.356 + for (; Point < End && isalnum(*p); Point++, p++) 1.357 + if (move == CSmove) 1.358 + right(CSstay); 1.359 + 1.360 + if (Point == End) 1.361 + break; 1.362 + } while (++i < Repeat); 1.363 + 1.364 + return CSstay; 1.365 +} 1.366 + 1.367 +STATIC STATUS 1.368 +do_case(type) 1.369 + CASE type; 1.370 +{ 1.371 + int i; 1.372 + int end; 1.373 + int count; 1.374 + CHAR *p; 1.375 + 1.376 + (void)do_forward(CSstay); 1.377 + if (OldPoint != Point) { 1.378 + if ((count = Point - OldPoint) < 0) 1.379 + count = -count; 1.380 + Point = OldPoint; 1.381 + if ((end = Point + count) > End) 1.382 + end = End; 1.383 + for (i = Point, p = &Line[i]; i < end; i++, p++) { 1.384 + if (type == TOupper) { 1.385 + if (islower(*p)) 1.386 + *p = toupper(*p); 1.387 + } 1.388 + else if (isupper(*p)) 1.389 + *p = tolower(*p); 1.390 + right(CSmove); 1.391 + } 1.392 + } 1.393 + return CSstay; 1.394 +} 1.395 + 1.396 +STATIC STATUS 1.397 +case_down_word() 1.398 +{ 1.399 + return do_case(TOlower); 1.400 +} 1.401 + 1.402 +STATIC STATUS 1.403 +case_up_word() 1.404 +{ 1.405 + return do_case(TOupper); 1.406 +} 1.407 + 1.408 +STATIC void 1.409 +ceol() 1.410 +{ 1.411 + int extras; 1.412 + int i; 1.413 + CHAR *p; 1.414 + 1.415 + for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) { 1.416 + TTYput(' '); 1.417 + if (ISCTL(*p)) { 1.418 + TTYput(' '); 1.419 + extras++; 1.420 + } 1.421 + else if (rl_meta_chars && ISMETA(*p)) { 1.422 + TTYput(' '); 1.423 + TTYput(' '); 1.424 + extras += 2; 1.425 + } 1.426 + } 1.427 + 1.428 + for (i += extras; i > Point; i--) 1.429 + TTYback(); 1.430 +} 1.431 + 1.432 +STATIC void 1.433 +clear_line() 1.434 +{ 1.435 + Point = -strlen(Prompt); 1.436 + TTYput('\r'); 1.437 + ceol(); 1.438 + Point = 0; 1.439 + End = 0; 1.440 + Line[0] = '\0'; 1.441 +} 1.442 + 1.443 +STATIC STATUS 1.444 +insert_string(p) 1.445 + CHAR *p; 1.446 +{ 1.447 + SIZE_T len; 1.448 + int i; 1.449 + CHAR *new; 1.450 + CHAR *q; 1.451 + 1.452 + len = strlen((char *)p); 1.453 + if (End + len >= Length) { 1.454 + if ((new = NEW(CHAR, Length + len + MEM_INC)) == NULL) 1.455 + return CSstay; 1.456 + if (Length) { 1.457 + COPYFROMTO(new, Line, Length); 1.458 + DISPOSE(Line); 1.459 + } 1.460 + Line = new; 1.461 + Length += len + MEM_INC; 1.462 + } 1.463 + 1.464 + for (q = &Line[Point], i = End - Point; --i >= 0; ) 1.465 + q[len + i] = q[i]; 1.466 + COPYFROMTO(&Line[Point], p, len); 1.467 + End += len; 1.468 + Line[End] = '\0'; 1.469 + TTYstring(&Line[Point]); 1.470 + Point += len; 1.471 + 1.472 + return Point == End ? CSstay : CSmove; 1.473 +} 1.474 + 1.475 +STATIC STATUS 1.476 +redisplay() 1.477 +{ 1.478 + TTYputs((CONST CHAR *)NEWLINE); 1.479 + TTYputs((CONST CHAR *)Prompt); 1.480 + TTYstring(Line); 1.481 + return CSmove; 1.482 +} 1.483 + 1.484 +STATIC STATUS 1.485 +toggle_meta_mode() 1.486 +{ 1.487 + rl_meta_chars = ! rl_meta_chars; 1.488 + return redisplay(); 1.489 +} 1.490 + 1.491 + 1.492 +STATIC CHAR * 1.493 +next_hist() 1.494 +{ 1.495 + return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos]; 1.496 +} 1.497 + 1.498 +STATIC CHAR * 1.499 +prev_hist() 1.500 +{ 1.501 + return H.Pos == 0 ? NULL : H.Lines[--H.Pos]; 1.502 +} 1.503 + 1.504 +STATIC STATUS 1.505 +do_insert_hist(p) 1.506 + CHAR *p; 1.507 +{ 1.508 + if (p == NULL) 1.509 + return ring_bell(); 1.510 + Point = 0; 1.511 + reposition(); 1.512 + ceol(); 1.513 + End = 0; 1.514 + return insert_string(p); 1.515 +} 1.516 + 1.517 +STATIC STATUS 1.518 +do_hist(move) 1.519 + CHAR *(*move)(); 1.520 +{ 1.521 + CHAR *p; 1.522 + int i; 1.523 + 1.524 + i = 0; 1.525 + do { 1.526 + if ((p = (*move)()) == NULL) 1.527 + return ring_bell(); 1.528 + } while (++i < Repeat); 1.529 + return do_insert_hist(p); 1.530 +} 1.531 + 1.532 +STATIC STATUS 1.533 +h_next() 1.534 +{ 1.535 + return do_hist(next_hist); 1.536 +} 1.537 + 1.538 +STATIC STATUS 1.539 +h_prev() 1.540 +{ 1.541 + return do_hist(prev_hist); 1.542 +} 1.543 + 1.544 +STATIC STATUS 1.545 +h_first() 1.546 +{ 1.547 + return do_insert_hist(H.Lines[H.Pos = 0]); 1.548 +} 1.549 + 1.550 +STATIC STATUS 1.551 +h_last() 1.552 +{ 1.553 + return do_insert_hist(H.Lines[H.Pos = H.Size - 1]); 1.554 +} 1.555 + 1.556 +/* 1.557 +** Return zero if pat appears as a substring in text. 1.558 +*/ 1.559 +STATIC int 1.560 +substrcmp(text, pat, len) 1.561 + char *text; 1.562 + char *pat; 1.563 + int len; 1.564 +{ 1.565 + char c; 1.566 + 1.567 + if ((c = *pat) == '\0') 1.568 + return *text == '\0'; 1.569 + for ( ; *text; text++) 1.570 + if (*text == c && strncmp(text, pat, len) == 0) 1.571 + return 0; 1.572 + return 1; 1.573 +} 1.574 + 1.575 +STATIC CHAR * 1.576 +search_hist(search, move) 1.577 + CHAR *search; 1.578 + CHAR *(*move)(); 1.579 +{ 1.580 + static CHAR *old_search; 1.581 + int len; 1.582 + int pos; 1.583 + int (*match)(); 1.584 + char *pat; 1.585 + 1.586 + /* Save or get remembered search pattern. */ 1.587 + if (search && *search) { 1.588 + if (old_search) 1.589 + DISPOSE(old_search); 1.590 + old_search = (CHAR *)strdup((char *)search); 1.591 + } 1.592 + else { 1.593 + if (old_search == NULL || *old_search == '\0') 1.594 + return NULL; 1.595 + search = old_search; 1.596 + } 1.597 + 1.598 + /* Set up pattern-finder. */ 1.599 + if (*search == '^') { 1.600 + match = strncmp; 1.601 + pat = (char *)(search + 1); 1.602 + } 1.603 + else { 1.604 + match = substrcmp; 1.605 + pat = (char *)search; 1.606 + } 1.607 + len = strlen(pat); 1.608 + 1.609 + for (pos = H.Pos; (*move)() != NULL; ) 1.610 + if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0) 1.611 + return H.Lines[H.Pos]; 1.612 + H.Pos = pos; 1.613 + return NULL; 1.614 +} 1.615 + 1.616 +STATIC STATUS 1.617 +h_search() 1.618 +{ 1.619 + static int Searching; 1.620 + CONST char *old_prompt; 1.621 + CHAR *(*move)(); 1.622 + CHAR *p; 1.623 + 1.624 + if (Searching) 1.625 + return ring_bell(); 1.626 + Searching = 1; 1.627 + 1.628 + clear_line(); 1.629 + old_prompt = Prompt; 1.630 + Prompt = "Search: "; 1.631 + TTYputs((CONST CHAR *)Prompt); 1.632 + move = Repeat == NO_ARG ? prev_hist : next_hist; 1.633 + p = editinput(); 1.634 + Prompt = old_prompt; 1.635 + Searching = 0; 1.636 + TTYputs((CONST CHAR *)Prompt); 1.637 + if (p == NULL && Signal > 0) { 1.638 + Signal = 0; 1.639 + clear_line(); 1.640 + return redisplay(); 1.641 + } 1.642 + p = search_hist(p, move); 1.643 + clear_line(); 1.644 + if (p == NULL) { 1.645 + (void)ring_bell(); 1.646 + return redisplay(); 1.647 + } 1.648 + return do_insert_hist(p); 1.649 +} 1.650 + 1.651 +STATIC STATUS 1.652 +fd_char() 1.653 +{ 1.654 + int i; 1.655 + 1.656 + i = 0; 1.657 + do { 1.658 + if (Point >= End) 1.659 + break; 1.660 + right(CSmove); 1.661 + } while (++i < Repeat); 1.662 + return CSstay; 1.663 +} 1.664 + 1.665 +STATIC void 1.666 +save_yank(begin, i) 1.667 + int begin; 1.668 + int i; 1.669 +{ 1.670 + if (Yanked) { 1.671 + DISPOSE(Yanked); 1.672 + Yanked = NULL; 1.673 + } 1.674 + 1.675 + if (i < 1) 1.676 + return; 1.677 + 1.678 + if ((Yanked = NEW(CHAR, (SIZE_T)i + 1)) != NULL) { 1.679 + COPYFROMTO(Yanked, &Line[begin], i); 1.680 + Yanked[i] = '\0'; 1.681 + } 1.682 +} 1.683 + 1.684 +STATIC STATUS 1.685 +delete_string(count) 1.686 + int count; 1.687 +{ 1.688 + int i; 1.689 + CHAR *p; 1.690 + 1.691 + if (count <= 0 || End == Point) 1.692 + return ring_bell(); 1.693 + 1.694 + if (count == 1 && Point == End - 1) { 1.695 + /* Optimize common case of delete at end of line. */ 1.696 + End--; 1.697 + p = &Line[Point]; 1.698 + i = 1; 1.699 + TTYput(' '); 1.700 + if (ISCTL(*p)) { 1.701 + i = 2; 1.702 + TTYput(' '); 1.703 + } 1.704 + else if (rl_meta_chars && ISMETA(*p)) { 1.705 + i = 3; 1.706 + TTYput(' '); 1.707 + TTYput(' '); 1.708 + } 1.709 + TTYbackn(i); 1.710 + *p = '\0'; 1.711 + return CSmove; 1.712 + } 1.713 + if (Point + count > End && (count = End - Point) <= 0) 1.714 + return CSstay; 1.715 + 1.716 + if (count > 1) 1.717 + save_yank(Point, count); 1.718 + 1.719 + for (p = &Line[Point], i = End - (Point + count) + 1; --i >= 0; p++) 1.720 + p[0] = p[count]; 1.721 + ceol(); 1.722 + End -= count; 1.723 + TTYstring(&Line[Point]); 1.724 + return CSmove; 1.725 +} 1.726 + 1.727 +STATIC STATUS 1.728 +bk_char() 1.729 +{ 1.730 + int i; 1.731 + 1.732 + i = 0; 1.733 + do { 1.734 + if (Point == 0) 1.735 + break; 1.736 + left(CSmove); 1.737 + } while (++i < Repeat); 1.738 + 1.739 + return CSstay; 1.740 +} 1.741 + 1.742 +STATIC STATUS 1.743 +bk_del_char() 1.744 +{ 1.745 + int i; 1.746 + 1.747 + i = 0; 1.748 + do { 1.749 + if (Point == 0) 1.750 + break; 1.751 + left(CSmove); 1.752 + } while (++i < Repeat); 1.753 + 1.754 + return delete_string(i); 1.755 +} 1.756 + 1.757 +STATIC STATUS 1.758 +kill_line() 1.759 +{ 1.760 + int i; 1.761 + 1.762 + if (Repeat != NO_ARG) { 1.763 + if (Repeat < Point) { 1.764 + i = Point; 1.765 + Point = Repeat; 1.766 + reposition(); 1.767 + (void)delete_string(i - Point); 1.768 + } 1.769 + else if (Repeat > Point) { 1.770 + right(CSmove); 1.771 + (void)delete_string(Repeat - Point - 1); 1.772 + } 1.773 + return CSmove; 1.774 + } 1.775 + 1.776 + save_yank(Point, End - Point); 1.777 + Line[Point] = '\0'; 1.778 + ceol(); 1.779 + End = Point; 1.780 + return CSstay; 1.781 +} 1.782 + 1.783 +STATIC STATUS 1.784 +insert_char(c) 1.785 + int c; 1.786 +{ 1.787 + STATUS s; 1.788 + CHAR buff[2]; 1.789 + CHAR *p; 1.790 + CHAR *q; 1.791 + int i; 1.792 + 1.793 + if (Repeat == NO_ARG || Repeat < 2) { 1.794 + buff[0] = c; 1.795 + buff[1] = '\0'; 1.796 + return insert_string(buff); 1.797 + } 1.798 + 1.799 + if ((p = NEW(CHAR, Repeat + 1)) == NULL) 1.800 + return CSstay; 1.801 + for (i = Repeat, q = p; --i >= 0; ) 1.802 + *q++ = c; 1.803 + *q = '\0'; 1.804 + Repeat = 0; 1.805 + s = insert_string(p); 1.806 + DISPOSE(p); 1.807 + return s; 1.808 +} 1.809 + 1.810 +STATIC STATUS 1.811 +meta() 1.812 +{ 1.813 + unsigned int c; 1.814 + CONST KEYMAP *kp; 1.815 + 1.816 + if ((int)(c = TTYget()) == EOF) 1.817 + return CSeof; 1.818 +#if defined(ANSI_ARROWS) 1.819 + /* Also include VT-100 arrows. */ 1.820 + if (c == '[' || c == 'O') 1.821 + switch (c = TTYget()) { 1.822 + default: return ring_bell(); 1.823 + case EOF: return CSeof; 1.824 + case 'A': return h_prev(); 1.825 + case 'B': return h_next(); 1.826 + case 'C': return fd_char(); 1.827 + case 'D': return bk_char(); 1.828 + } 1.829 +#endif /* defined(ANSI_ARROWS) */ 1.830 + 1.831 + if (isdigit(c)) { 1.832 + for (Repeat = c - '0'; (int)(c = TTYget()) != EOF && isdigit(c); ) 1.833 + Repeat = Repeat * 10 + c - '0'; 1.834 + Pushed = 1; 1.835 + PushBack = c; 1.836 + return CSstay; 1.837 + } 1.838 + 1.839 + if (isupper(c)) 1.840 + return do_macro(c); 1.841 + for (OldPoint = Point, kp = MetaMap; kp->Function; kp++) 1.842 + if (kp->Key == c) 1.843 + return (*kp->Function)(); 1.844 + 1.845 + return ring_bell(); 1.846 +} 1.847 + 1.848 +STATIC STATUS 1.849 +emacs(c) 1.850 + unsigned int c; 1.851 +{ 1.852 + STATUS s; 1.853 + const KEYMAP *kp; 1.854 + 1.855 + if (rl_meta_chars && ISMETA(c)) { 1.856 + Pushed = 1; 1.857 + PushBack = UNMETA(c); 1.858 + return meta(); 1.859 + } 1.860 + for (kp = Map; kp->Function; kp++) 1.861 + if (kp->Key == c) 1.862 + break; 1.863 + s = kp->Function ? (*kp->Function)() : insert_char((int)c); 1.864 + if (!Pushed) 1.865 + /* No pushback means no repeat count; hacky, but true. */ 1.866 + Repeat = NO_ARG; 1.867 + return s; 1.868 +} 1.869 + 1.870 +STATIC STATUS 1.871 +TTYspecial(c) 1.872 + unsigned int c; 1.873 +{ 1.874 + if (ISMETA(c)) 1.875 + return CSdispatch; 1.876 + 1.877 + if (c == rl_erase || (int)c == DEL) 1.878 + return bk_del_char(); 1.879 + if (c == rl_kill) { 1.880 + if (Point != 0) { 1.881 + Point = 0; 1.882 + reposition(); 1.883 + } 1.884 + Repeat = NO_ARG; 1.885 + return kill_line(); 1.886 + } 1.887 + if (c == rl_eof && Point == 0 && End == 0) 1.888 + return CSeof; 1.889 + if (c == rl_intr) { 1.890 + Signal = SIGINT; 1.891 + return CSsignal; 1.892 + } 1.893 + if (c == rl_quit) { 1.894 + Signal = SIGQUIT; 1.895 + return CSeof; 1.896 + } 1.897 + 1.898 + return CSdispatch; 1.899 +} 1.900 + 1.901 +STATIC CHAR * 1.902 +editinput() 1.903 +{ 1.904 + unsigned int c; 1.905 + 1.906 + Repeat = NO_ARG; 1.907 + OldPoint = Point = Mark = End = 0; 1.908 + Line[0] = '\0'; 1.909 + 1.910 + Signal = -1; 1.911 + while ((int)(c = TTYget()) != EOF) 1.912 + switch (TTYspecial(c)) { 1.913 + case CSdone: 1.914 + return Line; 1.915 + case CSeof: 1.916 + return NULL; 1.917 + case CSsignal: 1.918 + return (CHAR *)""; 1.919 + case CSmove: 1.920 + reposition(); 1.921 + break; 1.922 + case CSdispatch: 1.923 + switch (emacs(c)) { 1.924 + case CSdone: 1.925 + return Line; 1.926 + case CSeof: 1.927 + return NULL; 1.928 + case CSsignal: 1.929 + return (CHAR *)""; 1.930 + case CSmove: 1.931 + reposition(); 1.932 + break; 1.933 + case CSdispatch: 1.934 + case CSstay: 1.935 + break; 1.936 + } 1.937 + break; 1.938 + case CSstay: 1.939 + break; 1.940 + } 1.941 + if (strlen((char *)Line)) 1.942 + return Line; 1.943 + free(Line); 1.944 + return NULL; 1.945 +} 1.946 + 1.947 +STATIC void 1.948 +hist_add(p) 1.949 + CHAR *p; 1.950 +{ 1.951 + int i; 1.952 + 1.953 + if ((p = (CHAR *)strdup((char *)p)) == NULL) 1.954 + return; 1.955 + if (H.Size < HIST_SIZE) 1.956 + H.Lines[H.Size++] = p; 1.957 + else { 1.958 + DISPOSE(H.Lines[0]); 1.959 + for (i = 0; i < HIST_SIZE - 1; i++) 1.960 + H.Lines[i] = H.Lines[i + 1]; 1.961 + H.Lines[i] = p; 1.962 + } 1.963 + H.Pos = H.Size - 1; 1.964 +} 1.965 + 1.966 +/* 1.967 +** For compatibility with FSF readline. 1.968 +*/ 1.969 +/* ARGSUSED0 */ 1.970 +void 1.971 +rl_reset_terminal(p) 1.972 + char *p; 1.973 +{ 1.974 + (void)p; 1.975 +} 1.976 + 1.977 +void 1.978 +rl_initialize() 1.979 +{ 1.980 +} 1.981 + 1.982 +char * 1.983 +readline(prompt) 1.984 + CONST char *prompt; 1.985 +{ 1.986 + CHAR *line; 1.987 + int s; 1.988 + 1.989 + if (Line == NULL) { 1.990 + Length = MEM_INC; 1.991 + if ((Line = NEW(CHAR, Length)) == NULL) 1.992 + return NULL; 1.993 + } 1.994 + 1.995 + TTYinfo(); 1.996 + rl_ttyset(0); 1.997 + hist_add(NIL); 1.998 + ScreenSize = SCREEN_INC; 1.999 + Screen = NEW(char, ScreenSize); 1.1000 + Prompt = prompt ? prompt : (char *)NIL; 1.1001 + TTYputs((CONST CHAR *)Prompt); 1.1002 + if ((line = editinput()) != NULL) { 1.1003 + line = (CHAR *)strdup((char *)line); 1.1004 + TTYputs((CONST CHAR *)NEWLINE); 1.1005 + TTYflush(); 1.1006 + } 1.1007 + rl_ttyset(1); 1.1008 + DISPOSE(Screen); 1.1009 + DISPOSE(H.Lines[--H.Size]); 1.1010 + if (Signal > 0) { 1.1011 + s = Signal; 1.1012 + Signal = 0; 1.1013 + (void)kill(getpid(), s); 1.1014 + } 1.1015 + return (char *)line; 1.1016 +} 1.1017 + 1.1018 +void 1.1019 +add_history(p) 1.1020 + char *p; 1.1021 +{ 1.1022 + if (p == NULL || *p == '\0') 1.1023 + return; 1.1024 + 1.1025 +#if defined(UNIQUE_HISTORY) 1.1026 + if (H.Size && strcmp(p, (char *)H.Lines[H.Size - 1]) == 0) 1.1027 + return; 1.1028 +#endif /* defined(UNIQUE_HISTORY) */ 1.1029 + hist_add((CHAR *)p); 1.1030 +} 1.1031 + 1.1032 + 1.1033 +STATIC STATUS 1.1034 +beg_line() 1.1035 +{ 1.1036 + if (Point) { 1.1037 + Point = 0; 1.1038 + return CSmove; 1.1039 + } 1.1040 + return CSstay; 1.1041 +} 1.1042 + 1.1043 +STATIC STATUS 1.1044 +del_char() 1.1045 +{ 1.1046 + return delete_string(Repeat == NO_ARG ? 1 : Repeat); 1.1047 +} 1.1048 + 1.1049 +STATIC STATUS 1.1050 +end_line() 1.1051 +{ 1.1052 + if (Point != End) { 1.1053 + Point = End; 1.1054 + return CSmove; 1.1055 + } 1.1056 + return CSstay; 1.1057 +} 1.1058 + 1.1059 +STATIC STATUS 1.1060 +accept_line() 1.1061 +{ 1.1062 + Line[End] = '\0'; 1.1063 + return CSdone; 1.1064 +} 1.1065 + 1.1066 +STATIC STATUS 1.1067 +transpose() 1.1068 +{ 1.1069 + CHAR c; 1.1070 + 1.1071 + if (Point) { 1.1072 + if (Point == End) 1.1073 + left(CSmove); 1.1074 + c = Line[Point - 1]; 1.1075 + left(CSstay); 1.1076 + Line[Point - 1] = Line[Point]; 1.1077 + TTYshow(Line[Point - 1]); 1.1078 + Line[Point++] = c; 1.1079 + TTYshow(c); 1.1080 + } 1.1081 + return CSstay; 1.1082 +} 1.1083 + 1.1084 +STATIC STATUS 1.1085 +quote() 1.1086 +{ 1.1087 + unsigned int c; 1.1088 + 1.1089 + return (int)(c = TTYget()) == EOF ? CSeof : insert_char((int)c); 1.1090 +} 1.1091 + 1.1092 +STATIC STATUS 1.1093 +wipe() 1.1094 +{ 1.1095 + int i; 1.1096 + 1.1097 + if (Mark > End) 1.1098 + return ring_bell(); 1.1099 + 1.1100 + if (Point > Mark) { 1.1101 + i = Point; 1.1102 + Point = Mark; 1.1103 + Mark = i; 1.1104 + reposition(); 1.1105 + } 1.1106 + 1.1107 + return delete_string(Mark - Point); 1.1108 +} 1.1109 + 1.1110 +STATIC STATUS 1.1111 +mk_set() 1.1112 +{ 1.1113 + Mark = Point; 1.1114 + return CSstay; 1.1115 +} 1.1116 + 1.1117 +STATIC STATUS 1.1118 +exchange() 1.1119 +{ 1.1120 + unsigned int c; 1.1121 + 1.1122 + if ((c = TTYget()) != CTL('X')) 1.1123 + return (int)c == EOF ? CSeof : ring_bell(); 1.1124 + 1.1125 + if ((int)(c = Mark) <= End) { 1.1126 + Mark = Point; 1.1127 + Point = c; 1.1128 + return CSmove; 1.1129 + } 1.1130 + return CSstay; 1.1131 +} 1.1132 + 1.1133 +STATIC STATUS 1.1134 +yank() 1.1135 +{ 1.1136 + if (Yanked && *Yanked) 1.1137 + return insert_string(Yanked); 1.1138 + return CSstay; 1.1139 +} 1.1140 + 1.1141 +STATIC STATUS 1.1142 +copy_region() 1.1143 +{ 1.1144 + if (Mark > End) 1.1145 + return ring_bell(); 1.1146 + 1.1147 + if (Point > Mark) 1.1148 + save_yank(Mark, Point - Mark); 1.1149 + else 1.1150 + save_yank(Point, Mark - Point); 1.1151 + 1.1152 + return CSstay; 1.1153 +} 1.1154 + 1.1155 +STATIC STATUS 1.1156 +move_to_char() 1.1157 +{ 1.1158 + unsigned int c; 1.1159 + int i; 1.1160 + CHAR *p; 1.1161 + 1.1162 + if ((int)(c = TTYget()) == EOF) 1.1163 + return CSeof; 1.1164 + for (i = Point + 1, p = &Line[i]; i < End; i++, p++) 1.1165 + if (*p == c) { 1.1166 + Point = i; 1.1167 + return CSmove; 1.1168 + } 1.1169 + return CSstay; 1.1170 +} 1.1171 + 1.1172 +STATIC STATUS 1.1173 +fd_word() 1.1174 +{ 1.1175 + return do_forward(CSmove); 1.1176 +} 1.1177 + 1.1178 +STATIC STATUS 1.1179 +fd_kill_word() 1.1180 +{ 1.1181 + int i; 1.1182 + 1.1183 + (void)do_forward(CSstay); 1.1184 + if (OldPoint != Point) { 1.1185 + i = Point - OldPoint; 1.1186 + Point = OldPoint; 1.1187 + return delete_string(i); 1.1188 + } 1.1189 + return CSstay; 1.1190 +} 1.1191 + 1.1192 +STATIC STATUS 1.1193 +bk_word() 1.1194 +{ 1.1195 + int i; 1.1196 + CHAR *p; 1.1197 + 1.1198 + i = 0; 1.1199 + do { 1.1200 + for (p = &Line[Point]; p > Line && !isalnum(p[-1]); p--) 1.1201 + left(CSmove); 1.1202 + 1.1203 + for (; p > Line && p[-1] != ' ' && isalnum(p[-1]); p--) 1.1204 + left(CSmove); 1.1205 + 1.1206 + if (Point == 0) 1.1207 + break; 1.1208 + } while (++i < Repeat); 1.1209 + 1.1210 + return CSstay; 1.1211 +} 1.1212 + 1.1213 +STATIC STATUS 1.1214 +bk_kill_word() 1.1215 +{ 1.1216 + (void)bk_word(); 1.1217 + if (OldPoint != Point) 1.1218 + return delete_string(OldPoint - Point); 1.1219 + return CSstay; 1.1220 +} 1.1221 + 1.1222 +STATIC int 1.1223 +argify(line, avp) 1.1224 + CHAR *line; 1.1225 + CHAR ***avp; 1.1226 +{ 1.1227 + CHAR *c; 1.1228 + CHAR **p; 1.1229 + CHAR **new; 1.1230 + int ac; 1.1231 + int i; 1.1232 + 1.1233 + i = MEM_INC; 1.1234 + if ((*avp = p = NEW(CHAR*, i))== NULL) 1.1235 + return 0; 1.1236 + 1.1237 + for (c = line; isspace(*c); c++) 1.1238 + continue; 1.1239 + if (*c == '\n' || *c == '\0') 1.1240 + return 0; 1.1241 + 1.1242 + for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) { 1.1243 + if (isspace(*c)) { 1.1244 + *c++ = '\0'; 1.1245 + if (*c && *c != '\n') { 1.1246 + if (ac + 1 == i) { 1.1247 + new = NEW(CHAR*, i + MEM_INC); 1.1248 + if (new == NULL) { 1.1249 + p[ac] = NULL; 1.1250 + return ac; 1.1251 + } 1.1252 + COPYFROMTO(new, p, i * sizeof (char **)); 1.1253 + i += MEM_INC; 1.1254 + DISPOSE(p); 1.1255 + *avp = p = new; 1.1256 + } 1.1257 + p[ac++] = c; 1.1258 + } 1.1259 + } 1.1260 + else 1.1261 + c++; 1.1262 + } 1.1263 + *c = '\0'; 1.1264 + p[ac] = NULL; 1.1265 + return ac; 1.1266 +} 1.1267 + 1.1268 +STATIC STATUS 1.1269 +last_argument() 1.1270 +{ 1.1271 + CHAR **av; 1.1272 + CHAR *p; 1.1273 + STATUS s; 1.1274 + int ac; 1.1275 + 1.1276 + if (H.Size == 1 || (p = H.Lines[H.Size - 2]) == NULL) 1.1277 + return ring_bell(); 1.1278 + 1.1279 + if ((p = (CHAR *)strdup((char *)p)) == NULL) 1.1280 + return CSstay; 1.1281 + ac = argify(p, &av); 1.1282 + 1.1283 + if (Repeat != NO_ARG) 1.1284 + s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell(); 1.1285 + else 1.1286 + s = ac ? insert_string(av[ac - 1]) : CSstay; 1.1287 + 1.1288 + if (ac) 1.1289 + DISPOSE(av); 1.1290 + DISPOSE(p); 1.1291 + return s; 1.1292 +} 1.1293 + 1.1294 +STATIC CONST KEYMAP Map[32] = { 1.1295 + { CTL('@'), ring_bell }, 1.1296 + { CTL('A'), beg_line }, 1.1297 + { CTL('B'), bk_char }, 1.1298 + { CTL('D'), del_char }, 1.1299 + { CTL('E'), end_line }, 1.1300 + { CTL('F'), fd_char }, 1.1301 + { CTL('G'), ring_bell }, 1.1302 + { CTL('H'), bk_del_char }, 1.1303 + { CTL('J'), accept_line }, 1.1304 + { CTL('K'), kill_line }, 1.1305 + { CTL('L'), redisplay }, 1.1306 + { CTL('M'), accept_line }, 1.1307 + { CTL('N'), h_next }, 1.1308 + { CTL('O'), ring_bell }, 1.1309 + { CTL('P'), h_prev }, 1.1310 + { CTL('Q'), ring_bell }, 1.1311 + { CTL('R'), h_search }, 1.1312 + { CTL('S'), ring_bell }, 1.1313 + { CTL('T'), transpose }, 1.1314 + { CTL('U'), ring_bell }, 1.1315 + { CTL('V'), quote }, 1.1316 + { CTL('W'), wipe }, 1.1317 + { CTL('X'), exchange }, 1.1318 + { CTL('Y'), yank }, 1.1319 + { CTL('Z'), ring_bell }, 1.1320 + { CTL('['), meta }, 1.1321 + { CTL(']'), move_to_char }, 1.1322 + { CTL('^'), ring_bell }, 1.1323 + { CTL('_'), ring_bell }, 1.1324 + { 0, NULL } 1.1325 +}; 1.1326 + 1.1327 +STATIC CONST KEYMAP MetaMap[16]= { 1.1328 + { CTL('H'), bk_kill_word }, 1.1329 + { DEL, bk_kill_word }, 1.1330 + { ' ', mk_set }, 1.1331 + { '.', last_argument }, 1.1332 + { '<', h_first }, 1.1333 + { '>', h_last }, 1.1334 + { 'b', bk_word }, 1.1335 + { 'd', fd_kill_word }, 1.1336 + { 'f', fd_word }, 1.1337 + { 'l', case_down_word }, 1.1338 + { 'm', toggle_meta_mode }, 1.1339 + { 'u', case_up_word }, 1.1340 + { 'y', yank }, 1.1341 + { 'w', copy_region }, 1.1342 + { 0, NULL } 1.1343 +}; 1.1344 +