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