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