]>
git.proxmox.com Git - ceph.git/blob - ceph/src/dpdk/lib/librte_cmdline/cmdline_rdline.c
4 * Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
36 * All rights reserved.
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions are met:
40 * * Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * * Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * * Neither the name of the University of California, Berkeley nor the
46 * names of its contributors may be used to endorse or promote products
47 * derived from this software without specific prior written permission.
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
50 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
51 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
52 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
53 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
54 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
55 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
56 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
57 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
58 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
69 #include "cmdline_cirbuf.h"
70 #include "cmdline_rdline.h"
72 static void rdline_puts(struct rdline
*rdl
, const char *buf
);
73 static void rdline_miniprintf(struct rdline
*rdl
,
74 const char *buf
, unsigned int val
);
76 static void rdline_remove_old_history_item(struct rdline
*rdl
);
77 static void rdline_remove_first_history_item(struct rdline
*rdl
);
78 static unsigned int rdline_get_history_size(struct rdline
*rdl
);
81 /* isblank() needs _XOPEN_SOURCE >= 600 || _ISOC99_SOURCE, so use our
93 rdline_init(struct rdline
*rdl
,
94 rdline_write_char_t
*write_char
,
95 rdline_validate_t
*validate
,
96 rdline_complete_t
*complete
)
98 if (!rdl
|| !write_char
|| !validate
|| !complete
)
100 memset(rdl
, 0, sizeof(*rdl
));
101 rdl
->validate
= validate
;
102 rdl
->complete
= complete
;
103 rdl
->write_char
= write_char
;
104 rdl
->status
= RDLINE_INIT
;
105 return cirbuf_init(&rdl
->history
, rdl
->history_buf
, 0, RDLINE_HISTORY_BUF_SIZE
);
109 rdline_newline(struct rdline
*rdl
, const char *prompt
)
116 vt100_init(&rdl
->vt100
);
117 cirbuf_init(&rdl
->left
, rdl
->left_buf
, 0, RDLINE_BUF_SIZE
);
118 cirbuf_init(&rdl
->right
, rdl
->right_buf
, 0, RDLINE_BUF_SIZE
);
120 rdl
->prompt_size
= strnlen(prompt
, RDLINE_PROMPT_SIZE
-1);
121 if (prompt
!= rdl
->prompt
)
122 memcpy(rdl
->prompt
, prompt
, rdl
->prompt_size
);
123 rdl
->prompt
[RDLINE_PROMPT_SIZE
-1] = '\0';
125 for (i
=0 ; i
<rdl
->prompt_size
; i
++)
126 rdl
->write_char(rdl
, rdl
->prompt
[i
]);
127 rdl
->status
= RDLINE_RUNNING
;
129 rdl
->history_cur_line
= -1;
133 rdline_stop(struct rdline
*rdl
)
137 rdl
->status
= RDLINE_INIT
;
141 rdline_quit(struct rdline
*rdl
)
145 rdl
->status
= RDLINE_EXITED
;
149 rdline_restart(struct rdline
*rdl
)
153 rdl
->status
= RDLINE_RUNNING
;
157 rdline_reset(struct rdline
*rdl
)
161 vt100_init(&rdl
->vt100
);
162 cirbuf_init(&rdl
->left
, rdl
->left_buf
, 0, RDLINE_BUF_SIZE
);
163 cirbuf_init(&rdl
->right
, rdl
->right_buf
, 0, RDLINE_BUF_SIZE
);
165 rdl
->status
= RDLINE_RUNNING
;
167 rdl
->history_cur_line
= -1;
171 rdline_get_buffer(struct rdline
*rdl
)
175 unsigned int len_l
, len_r
;
176 cirbuf_align_left(&rdl
->left
);
177 cirbuf_align_left(&rdl
->right
);
179 len_l
= CIRBUF_GET_LEN(&rdl
->left
);
180 len_r
= CIRBUF_GET_LEN(&rdl
->right
);
181 memcpy(rdl
->left_buf
+len_l
, rdl
->right_buf
, len_r
);
183 rdl
->left_buf
[len_l
+ len_r
] = '\n';
184 rdl
->left_buf
[len_l
+ len_r
+ 1] = '\0';
185 return rdl
->left_buf
;
189 display_right_buffer(struct rdline
*rdl
, int force
)
194 if (!force
&& CIRBUF_IS_EMPTY(&rdl
->right
))
197 rdline_puts(rdl
, vt100_clear_right
);
198 CIRBUF_FOREACH(&rdl
->right
, i
, tmp
) {
199 rdl
->write_char(rdl
, tmp
);
201 if (!CIRBUF_IS_EMPTY(&rdl
->right
))
202 rdline_miniprintf(rdl
, vt100_multi_left
,
203 CIRBUF_GET_LEN(&rdl
->right
));
207 rdline_redisplay(struct rdline
*rdl
)
215 rdline_puts(rdl
, vt100_home
);
216 for (i
=0 ; i
<rdl
->prompt_size
; i
++)
217 rdl
->write_char(rdl
, rdl
->prompt
[i
]);
218 CIRBUF_FOREACH(&rdl
->left
, i
, tmp
) {
219 rdl
->write_char(rdl
, tmp
);
221 display_right_buffer(rdl
, 1);
225 rdline_char_in(struct rdline
*rdl
, char c
)
235 if (rdl
->status
== RDLINE_EXITED
)
236 return RDLINE_RES_EXITED
;
237 if (rdl
->status
!= RDLINE_RUNNING
)
238 return RDLINE_RES_NOT_RUNNING
;
240 cmd
= vt100_parser(&rdl
->vt100
, c
);
242 return RDLINE_RES_SUCCESS
;
246 /* move caret 1 char to the left */
247 case CMDLINE_KEY_CTRL_B
:
248 case CMDLINE_KEY_LEFT_ARR
:
249 if (CIRBUF_IS_EMPTY(&rdl
->left
))
251 tmp
= cirbuf_get_tail(&rdl
->left
);
252 cirbuf_del_tail(&rdl
->left
);
253 cirbuf_add_head(&rdl
->right
, tmp
);
254 rdline_puts(rdl
, vt100_left_arr
);
257 /* move caret 1 char to the right */
258 case CMDLINE_KEY_CTRL_F
:
259 case CMDLINE_KEY_RIGHT_ARR
:
260 if (CIRBUF_IS_EMPTY(&rdl
->right
))
262 tmp
= cirbuf_get_head(&rdl
->right
);
263 cirbuf_del_head(&rdl
->right
);
264 cirbuf_add_tail(&rdl
->left
, tmp
);
265 rdline_puts(rdl
, vt100_right_arr
);
268 /* move caret 1 word to the left */
269 /* keyboard equivalent: Alt+B */
270 case CMDLINE_KEY_WLEFT
:
271 while (! CIRBUF_IS_EMPTY(&rdl
->left
) &&
272 (tmp
= cirbuf_get_tail(&rdl
->left
)) &&
274 rdline_puts(rdl
, vt100_left_arr
);
275 cirbuf_del_tail(&rdl
->left
);
276 cirbuf_add_head(&rdl
->right
, tmp
);
278 while (! CIRBUF_IS_EMPTY(&rdl
->left
) &&
279 (tmp
= cirbuf_get_tail(&rdl
->left
)) &&
281 rdline_puts(rdl
, vt100_left_arr
);
282 cirbuf_del_tail(&rdl
->left
);
283 cirbuf_add_head(&rdl
->right
, tmp
);
287 /* move caret 1 word to the right */
288 /* keyboard equivalent: Alt+F */
289 case CMDLINE_KEY_WRIGHT
:
290 while (! CIRBUF_IS_EMPTY(&rdl
->right
) &&
291 (tmp
= cirbuf_get_head(&rdl
->right
)) &&
293 rdline_puts(rdl
, vt100_right_arr
);
294 cirbuf_del_head(&rdl
->right
);
295 cirbuf_add_tail(&rdl
->left
, tmp
);
297 while (! CIRBUF_IS_EMPTY(&rdl
->right
) &&
298 (tmp
= cirbuf_get_head(&rdl
->right
)) &&
300 rdline_puts(rdl
, vt100_right_arr
);
301 cirbuf_del_head(&rdl
->right
);
302 cirbuf_add_tail(&rdl
->left
, tmp
);
306 /* move caret to the left */
307 case CMDLINE_KEY_CTRL_A
:
308 if (CIRBUF_IS_EMPTY(&rdl
->left
))
310 rdline_miniprintf(rdl
, vt100_multi_left
,
311 CIRBUF_GET_LEN(&rdl
->left
));
312 while (! CIRBUF_IS_EMPTY(&rdl
->left
)) {
313 tmp
= cirbuf_get_tail(&rdl
->left
);
314 cirbuf_del_tail(&rdl
->left
);
315 cirbuf_add_head(&rdl
->right
, tmp
);
319 /* move caret to the right */
320 case CMDLINE_KEY_CTRL_E
:
321 if (CIRBUF_IS_EMPTY(&rdl
->right
))
323 rdline_miniprintf(rdl
, vt100_multi_right
,
324 CIRBUF_GET_LEN(&rdl
->right
));
325 while (! CIRBUF_IS_EMPTY(&rdl
->right
)) {
326 tmp
= cirbuf_get_head(&rdl
->right
);
327 cirbuf_del_head(&rdl
->right
);
328 cirbuf_add_tail(&rdl
->left
, tmp
);
332 /* delete 1 char from the left */
333 case CMDLINE_KEY_BKSPACE
:
334 if(!cirbuf_del_tail_safe(&rdl
->left
)) {
335 rdline_puts(rdl
, vt100_bs
);
336 display_right_buffer(rdl
, 1);
340 /* delete 1 char from the right */
341 case CMDLINE_KEY_SUPPR
:
342 case CMDLINE_KEY_CTRL_D
:
343 if (cmd
== CMDLINE_KEY_CTRL_D
&&
344 CIRBUF_IS_EMPTY(&rdl
->left
) &&
345 CIRBUF_IS_EMPTY(&rdl
->right
)) {
346 return RDLINE_RES_EOF
;
348 if (!cirbuf_del_head_safe(&rdl
->right
)) {
349 display_right_buffer(rdl
, 1);
353 /* delete 1 word from the left */
354 case CMDLINE_KEY_META_BKSPACE
:
355 case CMDLINE_KEY_CTRL_W
:
356 while (! CIRBUF_IS_EMPTY(&rdl
->left
) && isblank2(cirbuf_get_tail(&rdl
->left
))) {
357 rdline_puts(rdl
, vt100_bs
);
358 cirbuf_del_tail(&rdl
->left
);
360 while (! CIRBUF_IS_EMPTY(&rdl
->left
) && !isblank2(cirbuf_get_tail(&rdl
->left
))) {
361 rdline_puts(rdl
, vt100_bs
);
362 cirbuf_del_tail(&rdl
->left
);
364 display_right_buffer(rdl
, 1);
367 /* delete 1 word from the right */
368 case CMDLINE_KEY_META_D
:
369 while (! CIRBUF_IS_EMPTY(&rdl
->right
) && isblank2(cirbuf_get_head(&rdl
->right
)))
370 cirbuf_del_head(&rdl
->right
);
371 while (! CIRBUF_IS_EMPTY(&rdl
->right
) && !isblank2(cirbuf_get_head(&rdl
->right
)))
372 cirbuf_del_head(&rdl
->right
);
373 display_right_buffer(rdl
, 1);
376 /* set kill buffer to contents on the right side of caret */
377 case CMDLINE_KEY_CTRL_K
:
378 cirbuf_get_buf_head(&rdl
->right
, rdl
->kill_buf
, RDLINE_BUF_SIZE
);
379 rdl
->kill_size
= CIRBUF_GET_LEN(&rdl
->right
);
380 cirbuf_del_buf_head(&rdl
->right
, rdl
->kill_size
);
381 rdline_puts(rdl
, vt100_clear_right
);
384 /* paste contents of kill buffer to the left side of caret */
385 case CMDLINE_KEY_CTRL_Y
:
387 while(CIRBUF_GET_LEN(&rdl
->right
) + CIRBUF_GET_LEN(&rdl
->left
) <
389 i
< rdl
->kill_size
) {
390 cirbuf_add_tail(&rdl
->left
, rdl
->kill_buf
[i
]);
391 rdl
->write_char(rdl
, rdl
->kill_buf
[i
]);
394 display_right_buffer(rdl
, 0);
397 /* clear and newline */
398 case CMDLINE_KEY_CTRL_C
:
399 rdline_puts(rdl
, "\r\n");
400 rdline_newline(rdl
, rdl
->prompt
);
403 /* redisplay (helps when prompt is lost in other output) */
404 case CMDLINE_KEY_CTRL_L
:
405 rdline_redisplay(rdl
);
409 case CMDLINE_KEY_TAB
:
410 case CMDLINE_KEY_HELP
:
411 cirbuf_align_left(&rdl
->left
);
412 rdl
->left_buf
[CIRBUF_GET_LEN(&rdl
->left
)] = '\0';
414 char tmp_buf
[BUFSIZ
];
417 unsigned int tmp_size
;
419 if (cmd
== CMDLINE_KEY_TAB
)
424 /* see in parse.h for help on complete() */
425 ret
= rdl
->complete(rdl
, rdl
->left_buf
,
426 tmp_buf
, sizeof(tmp_buf
),
428 /* no completion or error */
430 return RDLINE_RES_COMPLETE
;
433 tmp_size
= strnlen(tmp_buf
, sizeof(tmp_buf
));
435 if (ret
== RDLINE_RES_COMPLETE
) {
437 while(CIRBUF_GET_LEN(&rdl
->right
) + CIRBUF_GET_LEN(&rdl
->left
) <
440 cirbuf_add_tail(&rdl
->left
, tmp_buf
[i
]);
441 rdl
->write_char(rdl
, tmp_buf
[i
]);
444 display_right_buffer(rdl
, 1);
445 return RDLINE_RES_COMPLETE
; /* ?? */
449 rdline_puts(rdl
, "\r\n");
451 rdl
->write_char(rdl
, ' ');
452 for (i
=0 ; tmp_buf
[i
] ; i
++)
453 rdl
->write_char(rdl
, tmp_buf
[i
]);
454 rdline_puts(rdl
, "\r\n");
455 ret
= rdl
->complete(rdl
, rdl
->left_buf
,
456 tmp_buf
, sizeof(tmp_buf
),
460 rdline_redisplay(rdl
);
462 return RDLINE_RES_COMPLETE
;
464 /* complete buffer */
465 case CMDLINE_KEY_RETURN
:
466 case CMDLINE_KEY_RETURN2
:
467 rdline_get_buffer(rdl
);
468 rdl
->status
= RDLINE_INIT
;
469 rdline_puts(rdl
, "\r\n");
470 if (rdl
->history_cur_line
!= -1)
471 rdline_remove_first_history_item(rdl
);
474 rdl
->validate(rdl
, rdl
->left_buf
, CIRBUF_GET_LEN(&rdl
->left
)+2);
475 /* user may have stopped rdline */
476 if (rdl
->status
== RDLINE_EXITED
)
477 return RDLINE_RES_EXITED
;
478 return RDLINE_RES_VALIDATED
;
480 /* previous element in history */
481 case CMDLINE_KEY_UP_ARR
:
482 case CMDLINE_KEY_CTRL_P
:
483 if (rdl
->history_cur_line
== 0) {
484 rdline_remove_first_history_item(rdl
);
486 if (rdl
->history_cur_line
<= 0) {
487 rdline_add_history(rdl
, rdline_get_buffer(rdl
));
488 rdl
->history_cur_line
= 0;
491 buf
= rdline_get_history_item(rdl
, rdl
->history_cur_line
+ 1);
495 rdl
->history_cur_line
++;
496 vt100_init(&rdl
->vt100
);
497 cirbuf_init(&rdl
->left
, rdl
->left_buf
, 0, RDLINE_BUF_SIZE
);
498 cirbuf_init(&rdl
->right
, rdl
->right_buf
, 0, RDLINE_BUF_SIZE
);
499 cirbuf_add_buf_tail(&rdl
->left
, buf
, strnlen(buf
, RDLINE_BUF_SIZE
));
500 rdline_redisplay(rdl
);
503 /* next element in history */
504 case CMDLINE_KEY_DOWN_ARR
:
505 case CMDLINE_KEY_CTRL_N
:
506 if (rdl
->history_cur_line
- 1 < 0)
509 rdl
->history_cur_line
--;
510 buf
= rdline_get_history_item(rdl
, rdl
->history_cur_line
);
513 vt100_init(&rdl
->vt100
);
514 cirbuf_init(&rdl
->left
, rdl
->left_buf
, 0, RDLINE_BUF_SIZE
);
515 cirbuf_init(&rdl
->right
, rdl
->right_buf
, 0, RDLINE_BUF_SIZE
);
516 cirbuf_add_buf_tail(&rdl
->left
, buf
, strnlen(buf
, RDLINE_BUF_SIZE
));
517 rdline_redisplay(rdl
);
526 return RDLINE_RES_SUCCESS
;
529 if (!isprint((int)c
))
530 return RDLINE_RES_SUCCESS
;
533 if (CIRBUF_GET_LEN(&rdl
->left
) + CIRBUF_GET_LEN(&rdl
->right
) >= RDLINE_BUF_SIZE
)
534 return RDLINE_RES_SUCCESS
;
536 if (cirbuf_add_tail_safe(&rdl
->left
, c
))
537 return RDLINE_RES_SUCCESS
;
539 rdl
->write_char(rdl
, c
);
540 display_right_buffer(rdl
, 0);
542 return RDLINE_RES_SUCCESS
;
549 rdline_remove_old_history_item(struct rdline
* rdl
)
553 while (! CIRBUF_IS_EMPTY(&rdl
->history
) ) {
554 tmp
= cirbuf_get_head(&rdl
->history
);
555 cirbuf_del_head(&rdl
->history
);
562 rdline_remove_first_history_item(struct rdline
* rdl
)
566 if ( CIRBUF_IS_EMPTY(&rdl
->history
) ) {
570 cirbuf_del_tail(&rdl
->history
);
573 while (! CIRBUF_IS_EMPTY(&rdl
->history
) ) {
574 tmp
= cirbuf_get_tail(&rdl
->history
);
577 cirbuf_del_tail(&rdl
->history
);
582 rdline_get_history_size(struct rdline
* rdl
)
584 unsigned int i
, tmp
, ret
=0;
586 CIRBUF_FOREACH(&rdl
->history
, i
, tmp
) {
595 rdline_get_history_item(struct rdline
* rdl
, unsigned int idx
)
597 unsigned int len
, i
, tmp
;
602 len
= rdline_get_history_size(rdl
);
607 cirbuf_align_left(&rdl
->history
);
609 CIRBUF_FOREACH(&rdl
->history
, i
, tmp
) {
610 if ( idx
== len
- 1) {
611 return rdl
->history_buf
+ i
;
621 rdline_add_history(struct rdline
* rdl
, const char * buf
)
628 len
= strnlen(buf
, RDLINE_BUF_SIZE
);
629 for (i
=0; i
<len
; i
++) {
630 if (buf
[i
] == '\n') {
636 if ( len
>= RDLINE_HISTORY_BUF_SIZE
)
639 while ( len
>= CIRBUF_GET_FREELEN(&rdl
->history
) ) {
640 rdline_remove_old_history_item(rdl
);
643 cirbuf_add_buf_tail(&rdl
->history
, buf
, len
);
644 cirbuf_add_tail(&rdl
->history
, 0);
650 rdline_clear_history(struct rdline
* rdl
)
654 cirbuf_init(&rdl
->history
, rdl
->history_buf
, 0, RDLINE_HISTORY_BUF_SIZE
);
658 /* STATIC USEFUL FUNCS */
661 rdline_puts(struct rdline
* rdl
, const char * buf
)
664 while ( (c
= *(buf
++)) != '\0' ) {
665 rdl
->write_char(rdl
, c
);
669 /* a very very basic printf with one arg and one format 'u' */
671 rdline_miniprintf(struct rdline
*rdl
, const char * buf
, unsigned int val
)
673 char c
, started
=0, div
=100;
675 while ( (c
=*(buf
++)) ) {
677 rdl
->write_char(rdl
, c
);
682 rdl
->write_char(rdl
, '%');
683 rdl
->write_char(rdl
, c
);
686 /* val is never more than 255 */
688 c
= (char)(val
/ div
);
690 rdl
->write_char(rdl
, (char)(c
+'0'));