1 /* $OpenBSD: db_input.c,v 1.12 2014/07/08 13:02:57 deraadt Exp $ */ 2 /* $NetBSD: db_input.c,v 1.7 1996/02/05 01:57:02 christos Exp $ */ 3 4 /* 5 * Mach Operating System 6 * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University 7 * All Rights Reserved. 8 * 9 * Permission to use, copy, modify and distribute this software and its 10 * documentation is hereby granted, provided that both the copyright 11 * notice and this permission notice appear in all copies of the 12 * software, derivative works or modified versions, and any portions 13 * thereof, and that both notices appear in supporting documentation. 14 * 15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 17 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 18 * 19 * Carnegie Mellon requests users of this software to return to 20 * 21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 22 * School of Computer Science 23 * Carnegie Mellon University 24 * Pittsburgh PA 15213-3890 25 * 26 * any improvements or extensions that they make and grant Carnegie Mellon 27 * the rights to redistribute these changes. 28 * 29 * Author: David B. Golub, Carnegie Mellon University 30 * Date: 7/90 31 */ 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/proc.h> 36 37 #include <machine/db_machdep.h> 38 39 #include <ddb/db_var.h> 40 #include <ddb/db_output.h> 41 #include <ddb/db_command.h> 42 #include <ddb/db_sym.h> 43 #include <ddb/db_extern.h> 44 45 #include <dev/cons.h> 46 47 /* 48 * Character input and editing. 49 */ 50 51 /* 52 * We don't track output position while editing input, 53 * since input always ends with a new-line. We just 54 * reset the line position at the end. 55 */ 56 char * db_lbuf_start; /* start of input line buffer */ 57 char * db_lbuf_end; /* end of input line buffer */ 58 char * db_lc; /* current character */ 59 char * db_le; /* one past last character */ 60 #if DB_HISTORY_SIZE != 0 61 char db_history[DB_HISTORY_SIZE]; /* start of history buffer */ 62 int db_history_size = DB_HISTORY_SIZE;/* size of history buffer */ 63 char * db_history_curr = db_history; /* start of current line */ 64 char * db_history_last = db_history; /* start of last line */ 65 char * db_history_prev = (char *) 0; /* start of previous line */ 66 #endif 67 68 69 #define CTRL(c) ((c) & 0x1f) 70 #define isspace(c) ((c) == ' ' || (c) == '\t') 71 #define BLANK ' ' 72 #define BACKUP '\b' 73 74 void 75 db_putstring(char *s, int count) 76 { 77 while (--count >= 0) 78 cnputc(*s++); 79 } 80 81 void 82 db_putnchars(int c, int count) 83 { 84 while (--count >= 0) 85 cnputc(c); 86 } 87 88 /* 89 * Delete N characters, forward or backward 90 */ 91 #define DEL_FWD 0 92 #define DEL_BWD 1 93 void 94 db_delete(int n, int bwd) 95 { 96 char *p; 97 98 if (bwd) { 99 db_lc -= n; 100 db_putnchars(BACKUP, n); 101 } 102 for (p = db_lc; p < db_le-n; p++) { 103 *p = *(p+n); 104 cnputc(*p); 105 } 106 db_putnchars(BLANK, n); 107 db_putnchars(BACKUP, db_le - db_lc); 108 db_le -= n; 109 } 110 111 void 112 db_delete_line(void) 113 { 114 db_delete(db_le - db_lc, DEL_FWD); 115 db_delete(db_lc - db_lbuf_start, DEL_BWD); 116 db_le = db_lc = db_lbuf_start; 117 } 118 119 #if DB_HISTORY_SIZE != 0 120 #define INC_DB_CURR() \ 121 do { \ 122 db_history_curr++; \ 123 if (db_history_curr > \ 124 db_history + db_history_size - 1) \ 125 db_history_curr = db_history; \ 126 } while (0) 127 #define DEC_DB_CURR() \ 128 do { \ 129 db_history_curr--; \ 130 if (db_history_curr < db_history) \ 131 db_history_curr = db_history + \ 132 db_history_size - 1; \ 133 } while (0) 134 #endif 135 136 /* returns TRUE at end-of-line */ 137 int 138 db_inputchar(int c) 139 { 140 switch (c) { 141 case CTRL('b'): 142 /* back up one character */ 143 if (db_lc > db_lbuf_start) { 144 cnputc(BACKUP); 145 db_lc--; 146 } 147 break; 148 case CTRL('f'): 149 /* forward one character */ 150 if (db_lc < db_le) { 151 cnputc(*db_lc); 152 db_lc++; 153 } 154 break; 155 case CTRL('a'): 156 /* beginning of line */ 157 while (db_lc > db_lbuf_start) { 158 cnputc(BACKUP); 159 db_lc--; 160 } 161 break; 162 case CTRL('e'): 163 /* end of line */ 164 while (db_lc < db_le) { 165 cnputc(*db_lc); 166 db_lc++; 167 } 168 break; 169 case CTRL('w'): 170 /* erase word back */ 171 while (db_lc > db_lbuf_start && db_lc[-1] != BLANK) 172 db_delete(1, DEL_BWD); 173 break; 174 case CTRL('h'): 175 case 0177: 176 /* erase previous character */ 177 if (db_lc > db_lbuf_start) 178 db_delete(1, DEL_BWD); 179 break; 180 case CTRL('d'): 181 /* erase next character */ 182 if (db_lc < db_le) 183 db_delete(1, DEL_FWD); 184 break; 185 case CTRL('k'): 186 /* delete to end of line */ 187 if (db_lc < db_le) 188 db_delete(db_le - db_lc, DEL_FWD); 189 break; 190 case CTRL('u'): 191 /* delete line */ 192 db_delete_line(); 193 break; 194 case CTRL('t'): 195 /* twiddle last 2 characters */ 196 if (db_lc >= db_lbuf_start + 2) { 197 c = db_lc[-2]; 198 db_lc[-2] = db_lc[-1]; 199 db_lc[-1] = c; 200 cnputc(BACKUP); 201 cnputc(BACKUP); 202 cnputc(db_lc[-2]); 203 cnputc(db_lc[-1]); 204 } 205 break; 206 #if DB_HISTORY_SIZE != 0 207 case CTRL('p'): 208 DEC_DB_CURR(); 209 while (db_history_curr != db_history_last) { 210 DEC_DB_CURR(); 211 if (*db_history_curr == '\0') 212 break; 213 } 214 db_delete_line(); 215 if (db_history_curr == db_history_last) { 216 INC_DB_CURR(); 217 db_le = db_lc = db_lbuf_start; 218 } else { 219 char *p; 220 INC_DB_CURR(); 221 for (p = db_history_curr, db_le = db_lbuf_start;*p; ) { 222 *db_le++ = *p++; 223 if (p == db_history + db_history_size) 224 p = db_history; 225 } 226 db_lc = db_le; 227 } 228 db_putstring(db_lbuf_start, db_le - db_lbuf_start); 229 break; 230 case CTRL('n'): 231 while (db_history_curr != db_history_last) { 232 if (*db_history_curr == '\0') 233 break; 234 INC_DB_CURR(); 235 } 236 if (db_history_curr != db_history_last) { 237 INC_DB_CURR(); 238 db_delete_line(); 239 if (db_history_curr != db_history_last) { 240 char *p; 241 for (p = db_history_curr, 242 db_le = db_lbuf_start; *p;) { 243 *db_le++ = *p++; 244 if (p == db_history + db_history_size) 245 p = db_history; 246 } 247 db_lc = db_le; 248 } 249 db_putstring(db_lbuf_start, db_le - db_lbuf_start); 250 } 251 break; 252 #endif 253 case CTRL('r'): 254 db_putstring("^R\n", 3); 255 if (db_le > db_lbuf_start) { 256 db_putstring(db_lbuf_start, db_le - db_lbuf_start); 257 db_putnchars(BACKUP, db_le - db_lc); 258 } 259 break; 260 case '\n': 261 case '\r': 262 #if DB_HISTORY_SIZE != 0 263 /* 264 * Check whether current line is the same 265 * as previous saved line. If it is, don`t 266 * save it. 267 */ 268 if (db_history_curr == db_history_prev) { 269 char *pp, *pc; 270 271 /* 272 * Is it the same? 273 */ 274 for (pp = db_history_prev, pc = db_lbuf_start; 275 pc != db_le && *pp; ) { 276 if (*pp != *pc) 277 break; 278 if (++pp == db_history + db_history_size) 279 pp = db_history; 280 pc++; 281 } 282 if (!*pp && pc == db_le) { 283 /* 284 * Repeated previous line. Don`t save. 285 */ 286 db_history_curr = db_history_last; 287 *db_le++ = c; 288 return TRUE; 289 } 290 } 291 if (db_le != db_lbuf_start) { 292 char *p; 293 db_history_prev = db_history_last; 294 for (p = db_lbuf_start; p != db_le; p++) { 295 *db_history_last++ = *p; 296 if (db_history_last == 297 db_history + db_history_size) 298 db_history_last = db_history; 299 } 300 *db_history_last++ = '\0'; 301 } 302 db_history_curr = db_history_last; 303 #endif 304 *db_le++ = c; 305 return TRUE; 306 default: 307 if (db_le == db_lbuf_end) { 308 cnputc('\007'); 309 } 310 else if (c >= ' ' && c <= '~') { 311 char *p; 312 313 for (p = db_le; p > db_lc; p--) 314 *p = *(p-1); 315 *db_lc++ = c; 316 db_le++; 317 cnputc(c); 318 db_putstring(db_lc, db_le - db_lc); 319 db_putnchars(BACKUP, db_le - db_lc); 320 } 321 break; 322 } 323 return FALSE; 324 } 325 326 int 327 db_readline(char *lstart, int lsize) 328 { 329 db_force_whitespace(); /* synch output position */ 330 331 db_lbuf_start = lstart; 332 db_lbuf_end = lstart + lsize - 1; 333 db_lc = lstart; 334 db_le = lstart; 335 336 while (!db_inputchar(cngetc())) 337 continue; 338 339 db_putchar('\n'); /* synch output position */ 340 341 *db_le = 0; 342 return (db_le - db_lbuf_start); 343 } 344