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