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
cmdbuf_shiftr(mdb_cmdbuf_t * cmd,size_t nbytes)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
mdb_cmdbuf_allocchunk(mdb_cmdbuf_t * cmd)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
mdb_cmdbuf_create(mdb_cmdbuf_t * cmd)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
mdb_cmdbuf_destroy(mdb_cmdbuf_t * cmd)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
mdb_cmdbuf_caninsert(mdb_cmdbuf_t * cmd,size_t nbytes)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
mdb_cmdbuf_atstart(mdb_cmdbuf_t * cmd)119 mdb_cmdbuf_atstart(mdb_cmdbuf_t *cmd)
120 {
121 return (cmd->cmd_bufidx == 0);
122 }
123
124 int
mdb_cmdbuf_atend(mdb_cmdbuf_t * cmd)125 mdb_cmdbuf_atend(mdb_cmdbuf_t *cmd)
126 {
127 return (cmd->cmd_bufidx == cmd->cmd_buflen);
128 }
129
130 int
mdb_cmdbuf_insert(mdb_cmdbuf_t * cmd,int c)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 *
mdb_cmdbuf_accept(mdb_cmdbuf_t * cmd)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
mdb_cmdbuf_backspace(mdb_cmdbuf_t * cmd,int c)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
mdb_cmdbuf_delchar(mdb_cmdbuf_t * cmd,int c)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
mdb_cmdbuf_fwdchar(mdb_cmdbuf_t * cmd,int c)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
mdb_cmdbuf_backchar(mdb_cmdbuf_t * cmd,int c)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
mdb_cmdbuf_transpose(mdb_cmdbuf_t * cmd,int c)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
mdb_cmdbuf_home(mdb_cmdbuf_t * cmd,int c)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
mdb_cmdbuf_end(mdb_cmdbuf_t * cmd,int c)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
fwdword_index(mdb_cmdbuf_t * cmd)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
mdb_cmdbuf_fwdword(mdb_cmdbuf_t * cmd,int c)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
mdb_cmdbuf_killfwdword(mdb_cmdbuf_t * cmd,int c)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
backword_index(mdb_cmdbuf_t * cmd)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
mdb_cmdbuf_backword(mdb_cmdbuf_t * cmd,int c)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
mdb_cmdbuf_killbackword(mdb_cmdbuf_t * cmd,int c)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
mdb_cmdbuf_kill(mdb_cmdbuf_t * cmd,int c)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
mdb_cmdbuf_reset(mdb_cmdbuf_t * cmd,int c)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
mdb_cmdbuf_prevhist(mdb_cmdbuf_t * cmd,int c)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
mdb_cmdbuf_nexthist(mdb_cmdbuf_t * cmd,int c)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
mdb_cmdbuf_findhist(mdb_cmdbuf_t * cmd,int c)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