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 2006 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 cmd->cmd_buf[cmd->cmd_buflen++] = '\0'; 171 (void) strcpy(cmd->cmd_linebuf, cmd->cmd_buf); 172 173 /* 174 * Don't bother inserting empty buffers into the history ring. 175 */ 176 if (cmd->cmd_buflen > 1) { 177 cmd->cmd_hnew = (cmd->cmd_hnew + 1) % cmd->cmd_histlen; 178 if (cmd->cmd_hnew >= cmd->cmd_halloc) 179 mdb_cmdbuf_allocchunk(cmd); 180 181 cmd->cmd_buf = cmd->cmd_history[cmd->cmd_hnew]; 182 cmd->cmd_hcur = cmd->cmd_hnew; 183 184 if (cmd->cmd_hlen + 1 == cmd->cmd_histlen) 185 cmd->cmd_hold = 186 (cmd->cmd_hold + 1) % cmd->cmd_histlen; 187 else 188 cmd->cmd_hlen++; 189 } 190 191 cmd->cmd_bufidx = 0; 192 cmd->cmd_buflen = 0; 193 194 return ((const char *)cmd->cmd_linebuf); 195 } 196 197 return (NULL); 198 } 199 200 /*ARGSUSED*/ 201 int 202 mdb_cmdbuf_backspace(mdb_cmdbuf_t *cmd, int c) 203 { 204 if (cmd->cmd_bufidx > 0) { 205 if (cmd->cmd_buflen != cmd->cmd_bufidx) { 206 bcopy(&cmd->cmd_buf[cmd->cmd_bufidx], 207 &cmd->cmd_buf[cmd->cmd_bufidx - 1], 208 cmd->cmd_buflen - cmd->cmd_bufidx); 209 } 210 211 cmd->cmd_bufidx--; 212 cmd->cmd_buflen--; 213 214 return (0); 215 } 216 217 return (-1); 218 } 219 220 /*ARGSUSED*/ 221 int 222 mdb_cmdbuf_delchar(mdb_cmdbuf_t *cmd, int c) 223 { 224 if (cmd->cmd_bufidx < cmd->cmd_buflen) { 225 if (cmd->cmd_bufidx < --cmd->cmd_buflen) { 226 bcopy(&cmd->cmd_buf[cmd->cmd_bufidx + 1], 227 &cmd->cmd_buf[cmd->cmd_bufidx], 228 cmd->cmd_buflen - cmd->cmd_bufidx); 229 } 230 231 return (0); 232 } 233 234 return (-1); 235 } 236 237 /*ARGSUSED*/ 238 int 239 mdb_cmdbuf_fwdchar(mdb_cmdbuf_t *cmd, int c) 240 { 241 if (cmd->cmd_bufidx < cmd->cmd_buflen) { 242 cmd->cmd_bufidx++; 243 return (0); 244 } 245 246 return (-1); 247 } 248 249 /*ARGSUSED*/ 250 int 251 mdb_cmdbuf_backchar(mdb_cmdbuf_t *cmd, int c) 252 { 253 if (cmd->cmd_bufidx > 0) { 254 cmd->cmd_bufidx--; 255 return (0); 256 } 257 258 return (-1); 259 } 260 261 int 262 mdb_cmdbuf_transpose(mdb_cmdbuf_t *cmd, int c) 263 { 264 if (cmd->cmd_bufidx > 0 && cmd->cmd_buflen > 1) { 265 c = cmd->cmd_buf[cmd->cmd_bufidx - 1]; 266 267 if (cmd->cmd_bufidx == cmd->cmd_buflen) { 268 cmd->cmd_buf[cmd->cmd_bufidx - 1] = 269 cmd->cmd_buf[cmd->cmd_bufidx - 2]; 270 cmd->cmd_buf[cmd->cmd_bufidx - 2] = (char)c; 271 } else { 272 cmd->cmd_buf[cmd->cmd_bufidx - 1] = 273 cmd->cmd_buf[cmd->cmd_bufidx]; 274 cmd->cmd_buf[cmd->cmd_bufidx++] = (char)c; 275 } 276 277 return (0); 278 } 279 280 return (-1); 281 } 282 283 /*ARGSUSED*/ 284 int 285 mdb_cmdbuf_home(mdb_cmdbuf_t *cmd, int c) 286 { 287 cmd->cmd_bufidx = 0; 288 return (0); 289 } 290 291 /*ARGSUSED*/ 292 int 293 mdb_cmdbuf_end(mdb_cmdbuf_t *cmd, int c) 294 { 295 cmd->cmd_bufidx = cmd->cmd_buflen; 296 return (0); 297 } 298 299 static size_t 300 fwdword_index(mdb_cmdbuf_t *cmd) 301 { 302 size_t i = cmd->cmd_bufidx + 1; 303 304 ASSERT(cmd->cmd_bufidx < cmd->cmd_buflen); 305 306 while (i < cmd->cmd_buflen && isspace(cmd->cmd_buf[i])) 307 i++; 308 309 while (i < cmd->cmd_buflen && !isspace(cmd->cmd_buf[i]) && 310 !isalnum(cmd->cmd_buf[i]) && cmd->cmd_buf[i] != '_') 311 i++; 312 313 while (i < cmd->cmd_buflen && 314 (isalnum(cmd->cmd_buf[i]) || cmd->cmd_buf[i] == '_')) 315 i++; 316 317 return (i); 318 } 319 320 /*ARGSUSED*/ 321 int 322 mdb_cmdbuf_fwdword(mdb_cmdbuf_t *cmd, int c) 323 { 324 if (cmd->cmd_bufidx == cmd->cmd_buflen) 325 return (-1); 326 327 cmd->cmd_bufidx = fwdword_index(cmd); 328 329 return (0); 330 } 331 332 /*ARGSUSED*/ 333 int 334 mdb_cmdbuf_killfwdword(mdb_cmdbuf_t *cmd, int c) 335 { 336 size_t i; 337 338 if (cmd->cmd_bufidx == cmd->cmd_buflen) 339 return (-1); 340 341 i = fwdword_index(cmd); 342 343 bcopy(&cmd->cmd_buf[i], &cmd->cmd_buf[cmd->cmd_bufidx], 344 cmd->cmd_buflen - i); 345 346 cmd->cmd_buflen -= i - cmd->cmd_bufidx; 347 348 return (0); 349 } 350 351 static size_t 352 backword_index(mdb_cmdbuf_t *cmd) 353 { 354 size_t i = cmd->cmd_bufidx - 1; 355 356 ASSERT(cmd->cmd_bufidx != 0); 357 358 while (i != 0 && isspace(cmd->cmd_buf[i])) 359 i--; 360 361 while (i != 0 && !isspace(cmd->cmd_buf[i]) && 362 !isalnum(cmd->cmd_buf[i]) && cmd->cmd_buf[i] != '_') 363 i--; 364 365 while (i != 0 && (isalnum(cmd->cmd_buf[i]) || cmd->cmd_buf[i] == '_')) 366 i--; 367 368 if (i != 0) 369 i++; 370 371 return (i); 372 } 373 374 /*ARGSUSED*/ 375 int 376 mdb_cmdbuf_backword(mdb_cmdbuf_t *cmd, int c) 377 { 378 if (cmd->cmd_bufidx == 0) 379 return (-1); 380 381 cmd->cmd_bufidx = backword_index(cmd); 382 383 return (0); 384 } 385 386 /*ARGSUSED*/ 387 int 388 mdb_cmdbuf_killbackword(mdb_cmdbuf_t *cmd, int c) 389 { 390 size_t i; 391 392 if (cmd->cmd_bufidx == 0) 393 return (-1); 394 395 i = backword_index(cmd); 396 397 bcopy(&cmd->cmd_buf[cmd->cmd_bufidx], &cmd->cmd_buf[i], 398 cmd->cmd_buflen - cmd->cmd_bufidx); 399 400 cmd->cmd_buflen -= cmd->cmd_bufidx - i; 401 cmd->cmd_bufidx = i; 402 403 return (0); 404 } 405 406 /*ARGSUSED*/ 407 int 408 mdb_cmdbuf_kill(mdb_cmdbuf_t *cmd, int c) 409 { 410 cmd->cmd_buflen = cmd->cmd_bufidx; 411 return (0); 412 } 413 414 /*ARGSUSED*/ 415 int 416 mdb_cmdbuf_reset(mdb_cmdbuf_t *cmd, int c) 417 { 418 cmd->cmd_buflen = 0; 419 cmd->cmd_bufidx = 0; 420 return (0); 421 } 422 423 /*ARGSUSED*/ 424 int 425 mdb_cmdbuf_prevhist(mdb_cmdbuf_t *cmd, int c) 426 { 427 if (cmd->cmd_hcur != cmd->cmd_hold) { 428 if (cmd->cmd_hcur-- == cmd->cmd_hnew) { 429 cmd->cmd_buf[cmd->cmd_buflen] = 0; 430 (void) strcpy(cmd->cmd_linebuf, cmd->cmd_buf); 431 } 432 433 if (cmd->cmd_hcur < 0) 434 cmd->cmd_hcur = cmd->cmd_halloc - 1; 435 436 (void) strcpy(cmd->cmd_buf, cmd->cmd_history[cmd->cmd_hcur]); 437 cmd->cmd_bufidx = strlen(cmd->cmd_buf); 438 cmd->cmd_buflen = cmd->cmd_bufidx; 439 440 return (0); 441 } 442 443 return (-1); 444 } 445 446 /*ARGSUSED*/ 447 int 448 mdb_cmdbuf_nexthist(mdb_cmdbuf_t *cmd, int c) 449 { 450 if (cmd->cmd_hcur != cmd->cmd_hnew) { 451 cmd->cmd_hcur = (cmd->cmd_hcur + 1) % cmd->cmd_halloc; 452 453 if (cmd->cmd_hcur == cmd->cmd_hnew) { 454 (void) strcpy(cmd->cmd_buf, cmd->cmd_linebuf); 455 } else { 456 (void) strcpy(cmd->cmd_buf, 457 cmd->cmd_history[cmd->cmd_hcur]); 458 } 459 460 cmd->cmd_bufidx = strlen(cmd->cmd_buf); 461 cmd->cmd_buflen = cmd->cmd_bufidx; 462 463 return (0); 464 } 465 466 return (-1); 467 } 468 469 /*ARGSUSED*/ 470 int 471 mdb_cmdbuf_findhist(mdb_cmdbuf_t *cmd, int c) 472 { 473 ssize_t i, n; 474 475 if (cmd->cmd_buflen != 0) { 476 cmd->cmd_hcur = cmd->cmd_hnew; 477 cmd->cmd_buf[cmd->cmd_buflen] = 0; 478 (void) strcpy(cmd->cmd_linebuf, cmd->cmd_buf); 479 } 480 481 for (i = cmd->cmd_hcur, n = 0; n < cmd->cmd_hlen; n++) { 482 if (--i < 0) 483 i = cmd->cmd_halloc - 1; 484 485 if (strstr(cmd->cmd_history[i], cmd->cmd_linebuf) != NULL) { 486 (void) strcpy(cmd->cmd_buf, cmd->cmd_history[i]); 487 cmd->cmd_bufidx = strlen(cmd->cmd_buf); 488 cmd->cmd_buflen = cmd->cmd_bufidx; 489 cmd->cmd_hcur = i; 490 491 return (0); 492 } 493 } 494 495 cmd->cmd_hcur = cmd->cmd_hnew; 496 497 cmd->cmd_bufidx = 0; 498 cmd->cmd_buflen = 0; 499 500 return (-1); 501 } 502