1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * The MDB command buffer is a simple structure that keeps track of the 31 * command history list, and provides operations to manipulate the current 32 * buffer according to the various emacs editing options. The terminal 33 * code uses this code to keep track of the actual contents of the command 34 * line, and then uses this content to perform redraw operations. 35 */ 36 37 #include <strings.h> 38 #include <stdio.h> 39 #include <ctype.h> 40 41 #include <mdb/mdb_modapi.h> 42 #include <mdb/mdb_cmdbuf.h> 43 #include <mdb/mdb_debug.h> 44 #include <mdb/mdb.h> 45 46 #define CMDBUF_LINELEN BUFSIZ /* Length of each buffer line */ 47 #define CMDBUF_TABLEN 8 /* Length of a tab in spaces */ 48 49 static void 50 cmdbuf_shiftr(mdb_cmdbuf_t *cmd, size_t nbytes) 51 { 52 bcopy(&cmd->cmd_buf[cmd->cmd_bufidx], 53 &cmd->cmd_buf[cmd->cmd_bufidx + nbytes], 54 cmd->cmd_buflen - cmd->cmd_bufidx); 55 } 56 57 void 58 mdb_cmdbuf_create(mdb_cmdbuf_t *cmd) 59 { 60 size_t i; 61 62 /* 63 * This is pretty weak, but good enough for the moment: just allocate 64 * BUFSIZ-sized chunks in advance for every history element. Later 65 * it would be nice to replace this with either code that allocates 66 * space for the history list on-the-fly so as not to waste so much 67 * memory, or that keeps a mapped history file like the shell. 68 */ 69 cmd->cmd_history = mdb_alloc(mdb.m_histlen * sizeof (char *), UM_SLEEP); 70 cmd->cmd_linebuf = mdb_alloc(CMDBUF_LINELEN, UM_SLEEP); 71 72 for (i = 0; i < mdb.m_histlen; i++) 73 cmd->cmd_history[i] = mdb_alloc(CMDBUF_LINELEN, UM_SLEEP); 74 75 cmd->cmd_buf = cmd->cmd_history[0]; 76 cmd->cmd_linelen = CMDBUF_LINELEN; 77 cmd->cmd_histlen = mdb.m_histlen; 78 cmd->cmd_buflen = 0; 79 cmd->cmd_bufidx = 0; 80 cmd->cmd_hold = 0; 81 cmd->cmd_hnew = 0; 82 cmd->cmd_hcur = 0; 83 cmd->cmd_hlen = 0; 84 } 85 86 void 87 mdb_cmdbuf_destroy(mdb_cmdbuf_t *cmd) 88 { 89 size_t i; 90 91 for (i = 0; i < cmd->cmd_histlen; i++) 92 mdb_free(cmd->cmd_history[i], CMDBUF_LINELEN); 93 94 mdb_free(cmd->cmd_linebuf, CMDBUF_LINELEN); 95 mdb_free(cmd->cmd_history, cmd->cmd_histlen * sizeof (char *)); 96 } 97 98 int 99 mdb_cmdbuf_caninsert(mdb_cmdbuf_t *cmd, size_t nbytes) 100 { 101 return (cmd->cmd_buflen + nbytes < cmd->cmd_linelen); 102 } 103 104 int 105 mdb_cmdbuf_atstart(mdb_cmdbuf_t *cmd) 106 { 107 return (cmd->cmd_bufidx == 0); 108 } 109 110 int 111 mdb_cmdbuf_atend(mdb_cmdbuf_t *cmd) 112 { 113 return (cmd->cmd_bufidx == cmd->cmd_buflen); 114 } 115 116 int 117 mdb_cmdbuf_insert(mdb_cmdbuf_t *cmd, int c) 118 { 119 if (c == '\t') { 120 if (cmd->cmd_buflen + CMDBUF_TABLEN < cmd->cmd_linelen) { 121 int i; 122 123 if (cmd->cmd_buflen != cmd->cmd_bufidx) 124 cmdbuf_shiftr(cmd, CMDBUF_TABLEN); 125 126 for (i = 0; i < CMDBUF_TABLEN; i++) 127 cmd->cmd_buf[cmd->cmd_bufidx++] = ' '; 128 129 cmd->cmd_buflen += CMDBUF_TABLEN; 130 return (0); 131 } 132 133 return (-1); 134 } 135 136 if (c < ' ' || c > '~') 137 return (-1); 138 139 if (cmd->cmd_buflen < cmd->cmd_linelen) { 140 if (cmd->cmd_buflen != cmd->cmd_bufidx) 141 cmdbuf_shiftr(cmd, 1); 142 143 cmd->cmd_buf[cmd->cmd_bufidx++] = (char)c; 144 cmd->cmd_buflen++; 145 146 return (0); 147 } 148 149 return (-1); 150 } 151 152 const char * 153 mdb_cmdbuf_accept(mdb_cmdbuf_t *cmd) 154 { 155 if (cmd->cmd_bufidx < cmd->cmd_linelen) { 156 cmd->cmd_buf[cmd->cmd_buflen++] = '\0'; 157 (void) strcpy(cmd->cmd_linebuf, cmd->cmd_buf); 158 159 /* 160 * Don't bother inserting empty buffers into the history ring. 161 */ 162 if (cmd->cmd_buflen > 1) { 163 cmd->cmd_hnew = (cmd->cmd_hnew + 1) % cmd->cmd_histlen; 164 cmd->cmd_buf = cmd->cmd_history[cmd->cmd_hnew]; 165 cmd->cmd_hcur = cmd->cmd_hnew; 166 167 if (cmd->cmd_hlen + 1 == cmd->cmd_histlen) 168 cmd->cmd_hold = 169 (cmd->cmd_hold + 1) % cmd->cmd_histlen; 170 else 171 cmd->cmd_hlen++; 172 } 173 174 cmd->cmd_bufidx = 0; 175 cmd->cmd_buflen = 0; 176 177 return ((const char *)cmd->cmd_linebuf); 178 } 179 180 return (NULL); 181 } 182 183 /*ARGSUSED*/ 184 int 185 mdb_cmdbuf_backspace(mdb_cmdbuf_t *cmd, int c) 186 { 187 if (cmd->cmd_bufidx > 0) { 188 if (cmd->cmd_buflen != cmd->cmd_bufidx) { 189 bcopy(&cmd->cmd_buf[cmd->cmd_bufidx], 190 &cmd->cmd_buf[cmd->cmd_bufidx - 1], 191 cmd->cmd_buflen - cmd->cmd_bufidx); 192 } 193 194 cmd->cmd_bufidx--; 195 cmd->cmd_buflen--; 196 197 return (0); 198 } 199 200 return (-1); 201 } 202 203 /*ARGSUSED*/ 204 int 205 mdb_cmdbuf_delchar(mdb_cmdbuf_t *cmd, int c) 206 { 207 if (cmd->cmd_bufidx < cmd->cmd_buflen) { 208 if (cmd->cmd_bufidx < --cmd->cmd_buflen) { 209 bcopy(&cmd->cmd_buf[cmd->cmd_bufidx + 1], 210 &cmd->cmd_buf[cmd->cmd_bufidx], 211 cmd->cmd_buflen - cmd->cmd_bufidx); 212 } 213 214 return (0); 215 } 216 217 return (-1); 218 } 219 220 /*ARGSUSED*/ 221 int 222 mdb_cmdbuf_fwdchar(mdb_cmdbuf_t *cmd, int c) 223 { 224 if (cmd->cmd_bufidx < cmd->cmd_buflen) { 225 cmd->cmd_bufidx++; 226 return (0); 227 } 228 229 return (-1); 230 } 231 232 /*ARGSUSED*/ 233 int 234 mdb_cmdbuf_backchar(mdb_cmdbuf_t *cmd, int c) 235 { 236 if (cmd->cmd_bufidx > 0) { 237 cmd->cmd_bufidx--; 238 return (0); 239 } 240 241 return (-1); 242 } 243 244 int 245 mdb_cmdbuf_transpose(mdb_cmdbuf_t *cmd, int c) 246 { 247 if (cmd->cmd_bufidx > 0 && cmd->cmd_buflen > 1) { 248 c = cmd->cmd_buf[cmd->cmd_bufidx - 1]; 249 250 if (cmd->cmd_bufidx == cmd->cmd_buflen) { 251 cmd->cmd_buf[cmd->cmd_bufidx - 1] = 252 cmd->cmd_buf[cmd->cmd_bufidx - 2]; 253 cmd->cmd_buf[cmd->cmd_bufidx - 2] = (char)c; 254 } else { 255 cmd->cmd_buf[cmd->cmd_bufidx - 1] = 256 cmd->cmd_buf[cmd->cmd_bufidx]; 257 cmd->cmd_buf[cmd->cmd_bufidx++] = (char)c; 258 } 259 260 return (0); 261 } 262 263 return (-1); 264 } 265 266 /*ARGSUSED*/ 267 int 268 mdb_cmdbuf_home(mdb_cmdbuf_t *cmd, int c) 269 { 270 cmd->cmd_bufidx = 0; 271 return (0); 272 } 273 274 /*ARGSUSED*/ 275 int 276 mdb_cmdbuf_end(mdb_cmdbuf_t *cmd, int c) 277 { 278 cmd->cmd_bufidx = cmd->cmd_buflen; 279 return (0); 280 } 281 282 static size_t 283 fwdword_index(mdb_cmdbuf_t *cmd) 284 { 285 size_t i = cmd->cmd_bufidx + 1; 286 287 ASSERT(cmd->cmd_bufidx < cmd->cmd_buflen); 288 289 while (i < cmd->cmd_buflen && isspace(cmd->cmd_buf[i])) 290 i++; 291 292 while (i < cmd->cmd_buflen && !isspace(cmd->cmd_buf[i]) && 293 !isalnum(cmd->cmd_buf[i]) && cmd->cmd_buf[i] != '_') 294 i++; 295 296 while (i < cmd->cmd_buflen && 297 (isalnum(cmd->cmd_buf[i]) || cmd->cmd_buf[i] == '_')) 298 i++; 299 300 return (i); 301 } 302 303 /*ARGSUSED*/ 304 int 305 mdb_cmdbuf_fwdword(mdb_cmdbuf_t *cmd, int c) 306 { 307 if (cmd->cmd_bufidx == cmd->cmd_buflen) 308 return (-1); 309 310 cmd->cmd_bufidx = fwdword_index(cmd); 311 312 return (0); 313 } 314 315 /*ARGSUSED*/ 316 int 317 mdb_cmdbuf_killfwdword(mdb_cmdbuf_t *cmd, int c) 318 { 319 size_t i; 320 321 if (cmd->cmd_bufidx == cmd->cmd_buflen) 322 return (-1); 323 324 i = fwdword_index(cmd); 325 326 bcopy(&cmd->cmd_buf[i], &cmd->cmd_buf[cmd->cmd_bufidx], 327 cmd->cmd_buflen - i); 328 329 cmd->cmd_buflen -= i - cmd->cmd_bufidx; 330 331 return (0); 332 } 333 334 static size_t 335 backword_index(mdb_cmdbuf_t *cmd) 336 { 337 size_t i = cmd->cmd_bufidx - 1; 338 339 ASSERT(cmd->cmd_bufidx != 0); 340 341 while (i != 0 && isspace(cmd->cmd_buf[i])) 342 i--; 343 344 while (i != 0 && !isspace(cmd->cmd_buf[i]) && 345 !isalnum(cmd->cmd_buf[i]) && cmd->cmd_buf[i] != '_') 346 i--; 347 348 while (i != 0 && (isalnum(cmd->cmd_buf[i]) || cmd->cmd_buf[i] == '_')) 349 i--; 350 351 if (i != 0) 352 i++; 353 354 return (i); 355 } 356 357 /*ARGSUSED*/ 358 int 359 mdb_cmdbuf_backword(mdb_cmdbuf_t *cmd, int c) 360 { 361 if (cmd->cmd_bufidx == 0) 362 return (-1); 363 364 cmd->cmd_bufidx = backword_index(cmd); 365 366 return (0); 367 } 368 369 /*ARGSUSED*/ 370 int 371 mdb_cmdbuf_killbackword(mdb_cmdbuf_t *cmd, int c) 372 { 373 size_t i; 374 375 if (cmd->cmd_bufidx == 0) 376 return (-1); 377 378 i = backword_index(cmd); 379 380 bcopy(&cmd->cmd_buf[cmd->cmd_bufidx], &cmd->cmd_buf[i], 381 cmd->cmd_buflen - cmd->cmd_bufidx); 382 383 cmd->cmd_buflen -= cmd->cmd_bufidx - i; 384 cmd->cmd_bufidx = i; 385 386 return (0); 387 } 388 389 /*ARGSUSED*/ 390 int 391 mdb_cmdbuf_kill(mdb_cmdbuf_t *cmd, int c) 392 { 393 cmd->cmd_buflen = cmd->cmd_bufidx; 394 return (0); 395 } 396 397 /*ARGSUSED*/ 398 int 399 mdb_cmdbuf_reset(mdb_cmdbuf_t *cmd, int c) 400 { 401 cmd->cmd_buflen = 0; 402 cmd->cmd_bufidx = 0; 403 return (0); 404 } 405 406 /*ARGSUSED*/ 407 int 408 mdb_cmdbuf_prevhist(mdb_cmdbuf_t *cmd, int c) 409 { 410 if (cmd->cmd_hcur != cmd->cmd_hold) { 411 if (cmd->cmd_hcur-- == cmd->cmd_hnew) { 412 cmd->cmd_buf[cmd->cmd_buflen] = 0; 413 (void) strcpy(cmd->cmd_linebuf, cmd->cmd_buf); 414 } 415 416 if (cmd->cmd_hcur < 0) 417 cmd->cmd_hcur = cmd->cmd_histlen - 1; 418 419 (void) strcpy(cmd->cmd_buf, cmd->cmd_history[cmd->cmd_hcur]); 420 cmd->cmd_bufidx = strlen(cmd->cmd_buf); 421 cmd->cmd_buflen = cmd->cmd_bufidx; 422 423 return (0); 424 } 425 426 return (-1); 427 } 428 429 /*ARGSUSED*/ 430 int 431 mdb_cmdbuf_nexthist(mdb_cmdbuf_t *cmd, int c) 432 { 433 if (cmd->cmd_hcur != cmd->cmd_hnew) { 434 cmd->cmd_hcur = (cmd->cmd_hcur + 1) % cmd->cmd_histlen; 435 436 if (cmd->cmd_hcur == cmd->cmd_hnew) { 437 (void) strcpy(cmd->cmd_buf, cmd->cmd_linebuf); 438 } else { 439 (void) strcpy(cmd->cmd_buf, 440 cmd->cmd_history[cmd->cmd_hcur]); 441 } 442 443 cmd->cmd_bufidx = strlen(cmd->cmd_buf); 444 cmd->cmd_buflen = cmd->cmd_bufidx; 445 446 return (0); 447 } 448 449 return (-1); 450 } 451 452 /*ARGSUSED*/ 453 int 454 mdb_cmdbuf_findhist(mdb_cmdbuf_t *cmd, int c) 455 { 456 ssize_t i, n; 457 458 if (cmd->cmd_buflen != 0) { 459 cmd->cmd_hcur = cmd->cmd_hnew; 460 cmd->cmd_buf[cmd->cmd_buflen] = 0; 461 (void) strcpy(cmd->cmd_linebuf, cmd->cmd_buf); 462 } 463 464 for (i = cmd->cmd_hcur, n = 0; n < cmd->cmd_hlen; n++) { 465 if (--i < 0) 466 i = cmd->cmd_histlen - 1; 467 468 if (strstr(cmd->cmd_history[i], cmd->cmd_linebuf) != NULL) { 469 (void) strcpy(cmd->cmd_buf, cmd->cmd_history[i]); 470 cmd->cmd_bufidx = strlen(cmd->cmd_buf); 471 cmd->cmd_buflen = cmd->cmd_bufidx; 472 cmd->cmd_hcur = i; 473 474 return (0); 475 } 476 } 477 478 cmd->cmd_hcur = cmd->cmd_hnew; 479 480 cmd->cmd_bufidx = 0; 481 cmd->cmd_buflen = 0; 482 483 return (-1); 484 } 485