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