Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2014 Intel Corporation.
3 : : * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
4 : : * All rights reserved.
5 : : */
6 : :
7 : : #include <stdlib.h>
8 : : #include <stdio.h>
9 : : #include <string.h>
10 : : #include <errno.h>
11 : : #include <ctype.h>
12 : :
13 : : #include "cmdline_cirbuf.h"
14 : : #include "cmdline_private.h"
15 : : #include "cmdline_rdline.h"
16 : :
17 : : static void rdline_puts(struct rdline *rdl, const char *buf);
18 : : static void rdline_miniprintf(struct rdline *rdl,
19 : : const char *buf, unsigned int val);
20 : :
21 : : static void rdline_remove_old_history_item(struct rdline *rdl);
22 : : static void rdline_remove_first_history_item(struct rdline *rdl);
23 : : static unsigned int rdline_get_history_size(struct rdline *rdl);
24 : :
25 : :
26 : : /* isblank() needs _XOPEN_SOURCE >= 600 || _ISOC99_SOURCE, so use our
27 : : * own. */
28 : : static int
29 : : isblank2(char c)
30 : : {
31 : 0 : if (c == ' ' ||
32 [ # # # # : 0 : c == '\t' )
# # # # ]
33 : : return 1;
34 : : return 0;
35 : : }
36 : :
37 : : int
38 : 131 : rdline_init(struct rdline *rdl,
39 : : rdline_write_char_t *write_char,
40 : : rdline_validate_t *validate,
41 : : rdline_complete_t *complete,
42 : : void *opaque)
43 : : {
44 [ + + + + ]: 131 : if (!rdl || !write_char || !validate || !complete)
45 : : return -EINVAL;
46 : : memset(rdl, 0, sizeof(*rdl));
47 : 128 : rdl->validate = validate;
48 : 128 : rdl->complete = complete;
49 : 128 : rdl->write_char = write_char;
50 : 128 : rdl->opaque = opaque;
51 : 128 : rdl->status = RDLINE_INIT;
52 : 128 : return cirbuf_init(&rdl->history, rdl->history_buf, 0, RDLINE_HISTORY_BUF_SIZE);
53 : : }
54 : :
55 : : struct rdline *
56 : 3 : rdline_new(rdline_write_char_t *write_char,
57 : : rdline_validate_t *validate,
58 : : rdline_complete_t *complete,
59 : : void *opaque)
60 : : {
61 : : struct rdline *rdl;
62 : :
63 : 3 : rdl = malloc(sizeof(*rdl));
64 [ + - ]: 3 : if (rdline_init(rdl, write_char, validate, complete, opaque) < 0) {
65 : 3 : free(rdl);
66 : : rdl = NULL;
67 : : }
68 : 3 : return rdl;
69 : : }
70 : :
71 : : void
72 : 2 : rdline_free(struct rdline *rdl)
73 : : {
74 : 2 : free(rdl);
75 : 2 : }
76 : :
77 : : void
78 : 249 : rdline_newline(struct rdline *rdl, const char *prompt)
79 : : {
80 : : unsigned int i;
81 : :
82 [ + + ]: 249 : if (!rdl || !prompt)
83 : : return;
84 : :
85 : 247 : vt100_init(&rdl->vt100);
86 : 247 : cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
87 : 247 : cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
88 : :
89 : 247 : rdl->prompt_size = strnlen(prompt, RDLINE_PROMPT_SIZE-1);
90 [ + - ]: 247 : if (prompt != rdl->prompt)
91 : 247 : memcpy(rdl->prompt, prompt, rdl->prompt_size);
92 : 247 : rdl->prompt[RDLINE_PROMPT_SIZE-1] = '\0';
93 : :
94 [ + + ]: 1483 : for (i=0 ; i<rdl->prompt_size ; i++)
95 : 1236 : rdl->write_char(rdl, rdl->prompt[i]);
96 : 247 : rdl->status = RDLINE_RUNNING;
97 : :
98 : 247 : rdl->history_cur_line = -1;
99 : : }
100 : :
101 : : void
102 : 1 : rdline_stop(struct rdline *rdl)
103 : : {
104 [ - + ]: 1 : if (!rdl)
105 : : return;
106 : 0 : rdl->status = RDLINE_INIT;
107 : : }
108 : :
109 : : void
110 : 2 : rdline_quit(struct rdline *rdl)
111 : : {
112 [ + + ]: 2 : if (!rdl)
113 : : return;
114 : 1 : rdl->status = RDLINE_EXITED;
115 : : }
116 : :
117 : : void
118 : 1 : rdline_restart(struct rdline *rdl)
119 : : {
120 [ - + ]: 1 : if (!rdl)
121 : : return;
122 : 0 : rdl->status = RDLINE_RUNNING;
123 : : }
124 : :
125 : : void
126 : 1 : rdline_reset(struct rdline *rdl)
127 : : {
128 [ - + ]: 1 : if (!rdl)
129 : : return;
130 : 0 : vt100_init(&rdl->vt100);
131 : 0 : cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
132 : 0 : cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
133 : :
134 : 0 : rdl->status = RDLINE_RUNNING;
135 : :
136 : 0 : rdl->history_cur_line = -1;
137 : : }
138 : :
139 : : const char *
140 : 245 : rdline_get_buffer(struct rdline *rdl)
141 : : {
142 [ + + ]: 245 : if (!rdl)
143 : : return NULL;
144 : : unsigned int len_l, len_r;
145 : 244 : cirbuf_align_left(&rdl->left);
146 : 244 : cirbuf_align_left(&rdl->right);
147 : :
148 : 244 : len_l = CIRBUF_GET_LEN(&rdl->left);
149 : 244 : len_r = CIRBUF_GET_LEN(&rdl->right);
150 : 244 : memcpy(rdl->left_buf+len_l, rdl->right_buf, len_r);
151 : :
152 : 244 : rdl->left_buf[len_l + len_r] = '\n';
153 : 244 : rdl->left_buf[len_l + len_r + 1] = '\0';
154 : 244 : return rdl->left_buf;
155 : : }
156 : :
157 : : static void
158 : 2164 : display_right_buffer(struct rdline *rdl, int force)
159 : : {
160 : : unsigned int i;
161 : : char tmp;
162 : :
163 [ + - - + ]: 2164 : if (!force && CIRBUF_IS_EMPTY(&rdl->right))
164 : : return;
165 : :
166 : : rdline_puts(rdl, vt100_clear_right);
167 [ # # ]: 0 : CIRBUF_FOREACH(&rdl->right, i, tmp) {
168 : 0 : rdl->write_char(rdl, tmp);
169 : : }
170 [ # # ]: 0 : if (!CIRBUF_IS_EMPTY(&rdl->right))
171 : 0 : rdline_miniprintf(rdl, vt100_multi_left,
172 : : CIRBUF_GET_LEN(&rdl->right));
173 : : }
174 : :
175 : : void
176 : 1 : rdline_redisplay(struct rdline *rdl)
177 : : {
178 : : unsigned int i;
179 : : char tmp;
180 : :
181 [ - + ]: 1 : if (!rdl)
182 : : return;
183 : :
184 : : rdline_puts(rdl, vt100_home);
185 [ # # ]: 0 : for (i=0 ; i<rdl->prompt_size ; i++)
186 : 0 : rdl->write_char(rdl, rdl->prompt[i]);
187 [ # # ]: 0 : CIRBUF_FOREACH(&rdl->left, i, tmp) {
188 : 0 : rdl->write_char(rdl, tmp);
189 : : }
190 : 0 : display_right_buffer(rdl, 1);
191 : : }
192 : :
193 : : int
194 : 2290 : rdline_char_in(struct rdline *rdl, char c)
195 : : {
196 : : unsigned int i;
197 : : int cmd;
198 : : char tmp;
199 : : char *buf;
200 : :
201 [ + + ]: 2290 : if (!rdl)
202 : : return -EINVAL;
203 : :
204 [ + - ]: 2289 : if (rdl->status == RDLINE_EXITED)
205 : : return RDLINE_RES_EXITED;
206 [ + - ]: 2289 : if (rdl->status != RDLINE_RUNNING)
207 : : return RDLINE_RES_NOT_RUNNING;
208 : :
209 : 2289 : cmd = vt100_parser(&rdl->vt100, c);
210 [ + - ]: 2289 : if (cmd == -2)
211 : : return RDLINE_RES_SUCCESS;
212 : :
213 [ + + ]: 2289 : if (cmd >= 0) {
214 [ - - - - : 125 : switch (cmd) {
- - - - -
- - - - -
- + - -
- ]
215 : : /* move caret 1 char to the left */
216 : 0 : case CMDLINE_KEY_CTRL_B:
217 : : case CMDLINE_KEY_LEFT_ARR:
218 [ # # ]: 0 : if (CIRBUF_IS_EMPTY(&rdl->left))
219 : : break;
220 : 0 : tmp = cirbuf_get_tail(&rdl->left);
221 : 0 : cirbuf_del_tail(&rdl->left);
222 : 0 : cirbuf_add_head(&rdl->right, tmp);
223 : : rdline_puts(rdl, vt100_left_arr);
224 : : break;
225 : :
226 : : /* move caret 1 char to the right */
227 : 0 : case CMDLINE_KEY_CTRL_F:
228 : : case CMDLINE_KEY_RIGHT_ARR:
229 [ # # ]: 0 : if (CIRBUF_IS_EMPTY(&rdl->right))
230 : : break;
231 : 0 : tmp = cirbuf_get_head(&rdl->right);
232 : 0 : cirbuf_del_head(&rdl->right);
233 : 0 : cirbuf_add_tail(&rdl->left, tmp);
234 : : rdline_puts(rdl, vt100_right_arr);
235 : : break;
236 : :
237 : : /* move caret 1 word to the left */
238 : : /* keyboard equivalent: Alt+B */
239 : : case CMDLINE_KEY_WLEFT:
240 [ # # ]: 0 : while (! CIRBUF_IS_EMPTY(&rdl->left) &&
241 [ # # ]: 0 : (tmp = cirbuf_get_tail(&rdl->left)) &&
242 [ # # ]: 0 : isblank2(tmp)) {
243 : : rdline_puts(rdl, vt100_left_arr);
244 : 0 : cirbuf_del_tail(&rdl->left);
245 : 0 : cirbuf_add_head(&rdl->right, tmp);
246 : : }
247 [ # # ]: 0 : while (! CIRBUF_IS_EMPTY(&rdl->left) &&
248 [ # # ]: 0 : (tmp = cirbuf_get_tail(&rdl->left)) &&
249 [ # # ]: 0 : !isblank2(tmp)) {
250 : : rdline_puts(rdl, vt100_left_arr);
251 : 0 : cirbuf_del_tail(&rdl->left);
252 : 0 : cirbuf_add_head(&rdl->right, tmp);
253 : : }
254 : : break;
255 : :
256 : : /* move caret 1 word to the right */
257 : : /* keyboard equivalent: Alt+F */
258 : : case CMDLINE_KEY_WRIGHT:
259 [ # # ]: 0 : while (! CIRBUF_IS_EMPTY(&rdl->right) &&
260 [ # # ]: 0 : (tmp = cirbuf_get_head(&rdl->right)) &&
261 [ # # ]: 0 : isblank2(tmp)) {
262 : : rdline_puts(rdl, vt100_right_arr);
263 : 0 : cirbuf_del_head(&rdl->right);
264 : 0 : cirbuf_add_tail(&rdl->left, tmp);
265 : : }
266 [ # # ]: 0 : while (! CIRBUF_IS_EMPTY(&rdl->right) &&
267 [ # # ]: 0 : (tmp = cirbuf_get_head(&rdl->right)) &&
268 [ # # ]: 0 : !isblank2(tmp)) {
269 : : rdline_puts(rdl, vt100_right_arr);
270 : 0 : cirbuf_del_head(&rdl->right);
271 : 0 : cirbuf_add_tail(&rdl->left, tmp);
272 : : }
273 : : break;
274 : :
275 : : /* move caret to the left */
276 : 0 : case CMDLINE_KEY_CTRL_A:
277 [ # # ]: 0 : if (CIRBUF_IS_EMPTY(&rdl->left))
278 : : break;
279 : 0 : rdline_miniprintf(rdl, vt100_multi_left,
280 : : CIRBUF_GET_LEN(&rdl->left));
281 [ # # ]: 0 : while (! CIRBUF_IS_EMPTY(&rdl->left)) {
282 : 0 : tmp = cirbuf_get_tail(&rdl->left);
283 : 0 : cirbuf_del_tail(&rdl->left);
284 : 0 : cirbuf_add_head(&rdl->right, tmp);
285 : : }
286 : : break;
287 : :
288 : : /* move caret to the right */
289 : 0 : case CMDLINE_KEY_CTRL_E:
290 [ # # ]: 0 : if (CIRBUF_IS_EMPTY(&rdl->right))
291 : : break;
292 : 0 : rdline_miniprintf(rdl, vt100_multi_right,
293 : : CIRBUF_GET_LEN(&rdl->right));
294 [ # # ]: 0 : while (! CIRBUF_IS_EMPTY(&rdl->right)) {
295 : 0 : tmp = cirbuf_get_head(&rdl->right);
296 : 0 : cirbuf_del_head(&rdl->right);
297 : 0 : cirbuf_add_tail(&rdl->left, tmp);
298 : : }
299 : : break;
300 : :
301 : : /* delete 1 char from the left */
302 : 0 : case CMDLINE_KEY_BKSPACE:
303 : : case CMDLINE_KEY_BKSPACE2:
304 [ # # ]: 0 : if(!cirbuf_del_tail_safe(&rdl->left)) {
305 : : rdline_puts(rdl, vt100_bs);
306 : 0 : display_right_buffer(rdl, 1);
307 : : }
308 : : break;
309 : :
310 : : /* delete 1 char from the right */
311 : 0 : case CMDLINE_KEY_SUPPR:
312 : : case CMDLINE_KEY_CTRL_D:
313 [ # # ]: 0 : if (cmd == CMDLINE_KEY_CTRL_D &&
314 [ # # ]: 0 : CIRBUF_IS_EMPTY(&rdl->left) &&
315 [ # # ]: 0 : CIRBUF_IS_EMPTY(&rdl->right)) {
316 : : return RDLINE_RES_EOF;
317 : : }
318 [ # # ]: 0 : if (!cirbuf_del_head_safe(&rdl->right)) {
319 : 0 : display_right_buffer(rdl, 1);
320 : : }
321 : : break;
322 : :
323 : : /* delete 1 word from the left */
324 : : case CMDLINE_KEY_META_BKSPACE:
325 : : case CMDLINE_KEY_CTRL_W:
326 [ # # ]: 0 : while (! CIRBUF_IS_EMPTY(&rdl->left) && isblank2(cirbuf_get_tail(&rdl->left))) {
327 : : rdline_puts(rdl, vt100_bs);
328 : 0 : cirbuf_del_tail(&rdl->left);
329 : : }
330 [ # # ]: 0 : while (! CIRBUF_IS_EMPTY(&rdl->left) && !isblank2(cirbuf_get_tail(&rdl->left))) {
331 : : rdline_puts(rdl, vt100_bs);
332 : 0 : cirbuf_del_tail(&rdl->left);
333 : : }
334 : 0 : display_right_buffer(rdl, 1);
335 : 0 : break;
336 : :
337 : : /* delete 1 word from the right */
338 : : case CMDLINE_KEY_META_D:
339 [ # # ]: 0 : while (! CIRBUF_IS_EMPTY(&rdl->right) && isblank2(cirbuf_get_head(&rdl->right)))
340 : 0 : cirbuf_del_head(&rdl->right);
341 [ # # ]: 0 : while (! CIRBUF_IS_EMPTY(&rdl->right) && !isblank2(cirbuf_get_head(&rdl->right)))
342 : 0 : cirbuf_del_head(&rdl->right);
343 : 0 : display_right_buffer(rdl, 1);
344 : 0 : break;
345 : :
346 : : /* set kill buffer to contents on the right side of caret */
347 : 0 : case CMDLINE_KEY_CTRL_K:
348 : 0 : cirbuf_get_buf_head(&rdl->right, rdl->kill_buf, RDLINE_BUF_SIZE);
349 : 0 : rdl->kill_size = CIRBUF_GET_LEN(&rdl->right);
350 : 0 : cirbuf_del_buf_head(&rdl->right, rdl->kill_size);
351 : : rdline_puts(rdl, vt100_clear_right);
352 : : break;
353 : :
354 : : /* paste contents of kill buffer to the left side of caret */
355 : : case CMDLINE_KEY_CTRL_Y:
356 : : i=0;
357 : 0 : while(CIRBUF_GET_LEN(&rdl->right) + CIRBUF_GET_LEN(&rdl->left) <
358 [ # # ]: 0 : RDLINE_BUF_SIZE &&
359 [ # # ]: 0 : i < rdl->kill_size) {
360 : 0 : cirbuf_add_tail(&rdl->left, rdl->kill_buf[i]);
361 : 0 : rdl->write_char(rdl, rdl->kill_buf[i]);
362 : 0 : i++;
363 : : }
364 : 0 : display_right_buffer(rdl, 0);
365 : 0 : break;
366 : :
367 : : /* clear and newline */
368 : : case CMDLINE_KEY_CTRL_C:
369 : : rdline_puts(rdl, "\r\n");
370 : 0 : rdline_newline(rdl, rdl->prompt);
371 : 0 : break;
372 : :
373 : : /* redisplay (helps when prompt is lost in other output) */
374 : 0 : case CMDLINE_KEY_CTRL_L:
375 : 0 : rdline_redisplay(rdl);
376 : 0 : break;
377 : :
378 : : /* autocomplete */
379 : 0 : case CMDLINE_KEY_TAB:
380 : : case CMDLINE_KEY_HELP:
381 : 0 : cirbuf_align_left(&rdl->left);
382 : 0 : rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\0';
383 [ # # ]: 0 : if (rdl->complete) {
384 : : char tmp_buf[BUFSIZ];
385 : : int complete_state;
386 : : int ret;
387 : : unsigned int tmp_size;
388 : :
389 [ # # ]: 0 : if (cmd == CMDLINE_KEY_TAB)
390 : 0 : complete_state = 0;
391 : : else
392 : 0 : complete_state = -1;
393 : :
394 : : /* see in parse.h for help on complete() */
395 : 0 : ret = rdl->complete(rdl, rdl->left_buf,
396 : : tmp_buf, sizeof(tmp_buf),
397 : : &complete_state);
398 : : /* no completion or error */
399 [ # # ]: 0 : if (ret <= 0) {
400 : 0 : return RDLINE_RES_COMPLETE;
401 : : }
402 : :
403 : 0 : tmp_size = strnlen(tmp_buf, sizeof(tmp_buf));
404 : : /* add chars */
405 [ # # ]: 0 : if (ret == RDLINE_RES_COMPLETE) {
406 : : i=0;
407 : 0 : while(CIRBUF_GET_LEN(&rdl->right) + CIRBUF_GET_LEN(&rdl->left) <
408 [ # # # # ]: 0 : RDLINE_BUF_SIZE &&
409 : : i < tmp_size) {
410 : 0 : cirbuf_add_tail(&rdl->left, tmp_buf[i]);
411 : 0 : rdl->write_char(rdl, tmp_buf[i]);
412 : 0 : i++;
413 : : }
414 : 0 : display_right_buffer(rdl, 1);
415 : 0 : return RDLINE_RES_COMPLETE; /* ?? */
416 : : }
417 : :
418 : : /* choice */
419 : : rdline_puts(rdl, "\r\n");
420 [ # # ]: 0 : while (ret) {
421 : 0 : rdl->write_char(rdl, ' ');
422 [ # # ]: 0 : for (i=0 ; tmp_buf[i] ; i++)
423 : 0 : rdl->write_char(rdl, tmp_buf[i]);
424 : : rdline_puts(rdl, "\r\n");
425 : 0 : ret = rdl->complete(rdl, rdl->left_buf,
426 : : tmp_buf, sizeof(tmp_buf),
427 : : &complete_state);
428 : : }
429 : :
430 : 0 : rdline_redisplay(rdl);
431 : : }
432 : 0 : return RDLINE_RES_COMPLETE;
433 : :
434 : : /* complete buffer */
435 : 125 : case CMDLINE_KEY_RETURN:
436 : : case CMDLINE_KEY_RETURN2:
437 : 125 : rdline_get_buffer(rdl);
438 : 125 : rdl->status = RDLINE_INIT;
439 : : rdline_puts(rdl, "\r\n");
440 [ - + ]: 125 : if (rdl->history_cur_line != -1)
441 : 0 : rdline_remove_first_history_item(rdl);
442 : :
443 [ + - ]: 125 : if (rdl->validate)
444 : 125 : rdl->validate(rdl, rdl->left_buf, CIRBUF_GET_LEN(&rdl->left)+2);
445 : : /* user may have stopped rdline */
446 [ + + ]: 120 : if (rdl->status == RDLINE_EXITED)
447 : : return RDLINE_RES_EXITED;
448 : 119 : return RDLINE_RES_VALIDATED;
449 : :
450 : : /* previous element in history */
451 : 0 : case CMDLINE_KEY_UP_ARR:
452 : : case CMDLINE_KEY_CTRL_P:
453 [ # # ]: 0 : if (rdl->history_cur_line == 0) {
454 : 0 : rdline_remove_first_history_item(rdl);
455 : : }
456 [ # # ]: 0 : if (rdl->history_cur_line <= 0) {
457 : 0 : rdline_add_history(rdl, rdline_get_buffer(rdl));
458 : 0 : rdl->history_cur_line = 0;
459 : : }
460 : :
461 : 0 : buf = rdline_get_history_item(rdl, rdl->history_cur_line + 1);
462 [ # # ]: 0 : if (!buf)
463 : : break;
464 : :
465 : 0 : rdl->history_cur_line ++;
466 : 0 : vt100_init(&rdl->vt100);
467 : 0 : cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
468 : 0 : cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
469 : 0 : cirbuf_add_buf_tail(&rdl->left, buf, strnlen(buf, RDLINE_BUF_SIZE));
470 : 0 : rdline_redisplay(rdl);
471 : 0 : break;
472 : :
473 : : /* next element in history */
474 : 0 : case CMDLINE_KEY_DOWN_ARR:
475 : : case CMDLINE_KEY_CTRL_N:
476 [ # # ]: 0 : if (rdl->history_cur_line - 1 < 0)
477 : : break;
478 : :
479 : 0 : rdl->history_cur_line --;
480 : 0 : buf = rdline_get_history_item(rdl, rdl->history_cur_line);
481 [ # # ]: 0 : if (!buf)
482 : : break;
483 : 0 : vt100_init(&rdl->vt100);
484 : 0 : cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
485 : 0 : cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
486 : 0 : cirbuf_add_buf_tail(&rdl->left, buf, strnlen(buf, RDLINE_BUF_SIZE));
487 : 0 : rdline_redisplay(rdl);
488 : :
489 : 0 : break;
490 : :
491 : :
492 : : default:
493 : : break;
494 : : }
495 : :
496 : 0 : return RDLINE_RES_SUCCESS;
497 : : }
498 : :
499 [ + - ]: 2164 : if (!isprint((int)c))
500 : : return RDLINE_RES_SUCCESS;
501 : :
502 : : /* standard chars */
503 [ + - ]: 2164 : if (CIRBUF_GET_LEN(&rdl->left) + CIRBUF_GET_LEN(&rdl->right) >= RDLINE_BUF_SIZE)
504 : : return RDLINE_RES_SUCCESS;
505 : :
506 [ + - ]: 2164 : if (cirbuf_add_tail_safe(&rdl->left, c))
507 : : return RDLINE_RES_SUCCESS;
508 : :
509 : 2164 : rdl->write_char(rdl, c);
510 : 2164 : display_right_buffer(rdl, 0);
511 : :
512 : 2164 : return RDLINE_RES_SUCCESS;
513 : : }
514 : :
515 : :
516 : : /* HISTORY */
517 : :
518 : : static void
519 : 0 : rdline_remove_old_history_item(struct rdline * rdl)
520 : : {
521 : : char tmp;
522 : :
523 [ # # ]: 0 : while (! CIRBUF_IS_EMPTY(&rdl->history) ) {
524 : 0 : tmp = cirbuf_get_head(&rdl->history);
525 : 0 : cirbuf_del_head(&rdl->history);
526 [ # # ]: 0 : if (!tmp)
527 : : break;
528 : : }
529 : 0 : }
530 : :
531 : : static void
532 : 0 : rdline_remove_first_history_item(struct rdline * rdl)
533 : : {
534 : : char tmp;
535 : :
536 [ # # ]: 0 : if ( CIRBUF_IS_EMPTY(&rdl->history) ) {
537 : : return;
538 : : }
539 : : else {
540 : 0 : cirbuf_del_tail(&rdl->history);
541 : : }
542 : :
543 [ # # ]: 0 : while (! CIRBUF_IS_EMPTY(&rdl->history) ) {
544 : 0 : tmp = cirbuf_get_tail(&rdl->history);
545 [ # # ]: 0 : if (!tmp)
546 : : break;
547 : 0 : cirbuf_del_tail(&rdl->history);
548 : : }
549 : : }
550 : :
551 : : static unsigned int
552 : : rdline_get_history_size(struct rdline * rdl)
553 : : {
554 : : unsigned int i, tmp, ret=0;
555 : :
556 [ - + ]: 119 : CIRBUF_FOREACH(&rdl->history, i, tmp) {
557 [ # # ]: 0 : if (tmp == 0)
558 : 0 : ret ++;
559 : : }
560 : :
561 : : return ret;
562 : : }
563 : :
564 : : char *
565 : 120 : rdline_get_history_item(struct rdline * rdl, unsigned int idx)
566 : : {
567 : : unsigned int len, i, tmp;
568 : :
569 [ + + ]: 120 : if (!rdl)
570 : : return NULL;
571 : :
572 : : len = rdline_get_history_size(rdl);
573 [ - + ]: 119 : if ( idx >= len ) {
574 : : return NULL;
575 : : }
576 : :
577 : 0 : cirbuf_align_left(&rdl->history);
578 : :
579 [ # # ]: 0 : CIRBUF_FOREACH(&rdl->history, i, tmp) {
580 [ # # ]: 0 : if ( idx == len - 1) {
581 : 0 : return rdl->history_buf + i;
582 : : }
583 [ # # ]: 0 : if (tmp == 0)
584 : : len --;
585 : : }
586 : :
587 : : return NULL;
588 : : }
589 : :
590 : : size_t
591 : 1 : rdline_get_history_buffer_size(struct rdline *rdl)
592 : : {
593 : 1 : return sizeof(rdl->history_buf);
594 : : }
595 : :
596 : : void *
597 : 1 : rdline_get_opaque(struct rdline *rdl)
598 : : {
599 [ - + ]: 1 : return rdl != NULL ? rdl->opaque : NULL;
600 : : }
601 : :
602 : : int
603 : 121 : rdline_add_history(struct rdline * rdl, const char * buf)
604 : : {
605 : : unsigned int len, i;
606 : :
607 [ + + ]: 121 : if (!rdl || !buf)
608 : : return -EINVAL;
609 : :
610 : 119 : len = strnlen(buf, RDLINE_BUF_SIZE);
611 [ + - ]: 2209 : for (i=0; i<len ; i++) {
612 [ + + ]: 2209 : if (buf[i] == '\n') {
613 : : len = i;
614 : : break;
615 : : }
616 : : }
617 : :
618 [ + - ]: 119 : if ( len >= RDLINE_HISTORY_BUF_SIZE )
619 : : return -1;
620 : :
621 [ - + ]: 119 : while ( len >= CIRBUF_GET_FREELEN(&rdl->history) ) {
622 : 0 : rdline_remove_old_history_item(rdl);
623 : : }
624 : :
625 : 119 : cirbuf_add_buf_tail(&rdl->history, buf, len);
626 : 119 : cirbuf_add_tail(&rdl->history, 0);
627 : :
628 : 119 : return 0;
629 : : }
630 : :
631 : : void
632 : 1 : rdline_clear_history(struct rdline * rdl)
633 : : {
634 [ - + ]: 1 : if (!rdl)
635 : : return;
636 : 0 : cirbuf_init(&rdl->history, rdl->history_buf, 0, RDLINE_HISTORY_BUF_SIZE);
637 : : }
638 : :
639 : :
640 : : /* STATIC USEFUL FUNCS */
641 : :
642 : : static void
643 : : rdline_puts(struct rdline * rdl, const char * buf)
644 : : {
645 : : char c;
646 [ - - - - : 375 : while ( (c = *(buf++)) != '\0' ) {
- - - - -
- - - - -
- - - - -
- - - - -
- - + + -
- - - ]
647 : 250 : rdl->write_char(rdl, c);
648 : : }
649 : : }
650 : :
651 : : /* a very very basic printf with one arg and one format 'u' */
652 : : static void
653 : 0 : rdline_miniprintf(struct rdline *rdl, const char * buf, unsigned int val)
654 : : {
655 : : char c, started=0, div=100;
656 : :
657 [ # # ]: 0 : while ( (c=*(buf++)) ) {
658 [ # # ]: 0 : if (c != '%') {
659 : 0 : rdl->write_char(rdl, c);
660 : 0 : continue;
661 : : }
662 : 0 : c = *(buf++);
663 [ # # ]: 0 : if (c != 'u') {
664 : 0 : rdl->write_char(rdl, '%');
665 : 0 : rdl->write_char(rdl, c);
666 : 0 : continue;
667 : : }
668 : : /* val is never more than 255 */
669 [ # # ]: 0 : while (div) {
670 : 0 : c = (char)(val / div);
671 [ # # ]: 0 : if (c || started) {
672 : 0 : rdl->write_char(rdl, (char)(c+'0'));
673 : : started = 1;
674 : : }
675 : 0 : val %= div;
676 : 0 : div /= 10;
677 : : }
678 : : }
679 : 0 : }
|