2 * Copyright Droids Corporation (2007)
3 * Olivier MATZ <zer0@droids-corp.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * Revision : $Id: rdline.c,v 1.1.2.9 2009-02-27 21:41:31 zer0 Exp $
30 #include <aversive/pgmspace.h>
35 static void rdline_puts_P(struct rdline * rdl, const prog_char * buf);
36 static void rdline_miniprintf_P(struct rdline * rdl,
37 const prog_char * buf, uint8_t val);
39 #ifdef CONFIG_MODULE_RDLINE_HISTORY
40 static void rdline_remove_old_history_item(struct rdline * rdl);
41 static void rdline_remove_first_history_item(struct rdline * rdl);
42 static uint8_t rdline_get_history_size(struct rdline * rdl);
43 #endif /* CONFIG_MODULE_RDLINE_HISTORY */
46 void rdline_init(struct rdline *rdl,
47 rdline_write_char_t *write_char,
48 rdline_validate_t *validate,
49 rdline_complete_t *complete)
51 memset(rdl, 0, sizeof(*rdl));
52 rdl->validate = validate;
53 rdl->complete = complete;
54 rdl->write_char = write_char;
55 rdl->status = RDLINE_INIT;
56 #ifdef CONFIG_MODULE_RDLINE_HISTORY
57 cirbuf_init(&rdl->history, rdl->history_buf, 0, RDLINE_HISTORY_BUF_SIZE);
58 #endif /* CONFIG_MODULE_RDLINE_HISTORY */
62 rdline_newline(struct rdline * rdl, const char * prompt)
66 vt100_init(&rdl->vt100);
67 cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
68 cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
70 if (prompt != rdl->prompt)
71 memcpy(rdl->prompt, prompt, sizeof(rdl->prompt)-1);
72 rdl->prompt_size = strlen(prompt);
74 for (i=0 ; i<rdl->prompt_size ; i++)
75 rdl->write_char(rdl->prompt[i]);
76 rdl->status = RDLINE_RUNNING;
78 #ifdef CONFIG_MODULE_RDLINE_HISTORY
79 rdl->history_cur_line = -1;
80 #endif /* CONFIG_MODULE_RDLINE_HISTORY */
84 rdline_stop(struct rdline * rdl)
86 rdl->status = RDLINE_INIT;
90 rdline_restart(struct rdline * rdl)
92 rdl->status = RDLINE_RUNNING;
96 rdline_get_buffer(struct rdline * rdl)
99 cirbuf_align_left(&rdl->left);
100 cirbuf_align_left(&rdl->right);
102 len_l = CIRBUF_GET_LEN(&rdl->left);
103 len_r = CIRBUF_GET_LEN(&rdl->right);
104 memcpy(rdl->left_buf+len_l, rdl->right_buf, len_r);
106 rdl->left_buf[len_l + len_r] = '\n';
107 rdl->left_buf[len_l + len_r + 1] = '\0';
108 return rdl->left_buf;
112 display_right_buffer(struct rdline * rdl)
117 rdline_puts_P(rdl, PSTR(vt100_clear_right));
118 if (!CIRBUF_IS_EMPTY(&rdl->right)) {
119 CIRBUF_FOREACH(&rdl->right, i, tmp) {
120 rdl->write_char(tmp);
122 rdline_miniprintf_P(rdl, PSTR(vt100_multi_left),
123 CIRBUF_GET_LEN(&rdl->right));
127 void rdline_redisplay(struct rdline * rdl)
132 rdline_puts_P(rdl, PSTR(vt100_home));
133 for (i=0 ; i<rdl->prompt_size ; i++)
134 rdl->write_char(rdl->prompt[i]);
135 CIRBUF_FOREACH(&rdl->left, i, tmp) {
136 rdl->write_char(tmp);
138 display_right_buffer(rdl);
142 rdline_char_in(struct rdline * rdl, char c)
147 #ifdef CONFIG_MODULE_RDLINE_HISTORY
151 if (rdl->status != RDLINE_RUNNING)
154 cmd = vt100_parser(&rdl->vt100, c);
162 if (CIRBUF_IS_EMPTY(&rdl->left))
164 tmp = cirbuf_get_tail(&rdl->left);
165 cirbuf_del_tail(&rdl->left);
166 cirbuf_add_head(&rdl->right, tmp);
167 rdline_puts_P(rdl, PSTR(vt100_left_arr));
172 if (CIRBUF_IS_EMPTY(&rdl->right))
174 tmp = cirbuf_get_head(&rdl->right);
175 cirbuf_del_head(&rdl->right);
176 cirbuf_add_tail(&rdl->left, tmp);
177 rdline_puts_P(rdl, PSTR(vt100_right_arr));
181 while (! CIRBUF_IS_EMPTY(&rdl->left) &&
182 (tmp = cirbuf_get_tail(&rdl->left)) &&
184 rdline_puts_P(rdl, PSTR(vt100_left_arr));
185 cirbuf_del_tail(&rdl->left);
186 cirbuf_add_head(&rdl->right, tmp);
188 while (! CIRBUF_IS_EMPTY(&rdl->left) &&
189 (tmp = cirbuf_get_tail(&rdl->left)) &&
191 rdline_puts_P(rdl, PSTR(vt100_left_arr));
192 cirbuf_del_tail(&rdl->left);
193 cirbuf_add_head(&rdl->right, tmp);
198 while (! CIRBUF_IS_EMPTY(&rdl->right) &&
199 (tmp = cirbuf_get_head(&rdl->right)) &&
201 rdline_puts_P(rdl, PSTR(vt100_right_arr));
202 cirbuf_del_head(&rdl->right);
203 cirbuf_add_tail(&rdl->left, tmp);
205 while (! CIRBUF_IS_EMPTY(&rdl->right) &&
206 (tmp = cirbuf_get_head(&rdl->right)) &&
208 rdline_puts_P(rdl, PSTR(vt100_right_arr));
209 cirbuf_del_head(&rdl->right);
210 cirbuf_add_tail(&rdl->left, tmp);
215 if(!cirbuf_del_tail_safe(&rdl->left)) {
216 rdline_puts_P(rdl, PSTR(vt100_bs));
217 display_right_buffer(rdl);
221 case KEY_META_BKSPACE:
222 while (! CIRBUF_IS_EMPTY(&rdl->left) && isblank(cirbuf_get_tail(&rdl->left))) {
223 rdline_puts_P(rdl, PSTR(vt100_bs));
224 cirbuf_del_tail(&rdl->left);
226 while (! CIRBUF_IS_EMPTY(&rdl->left) && !isblank(cirbuf_get_tail(&rdl->left))) {
227 rdline_puts_P(rdl, PSTR(vt100_bs));
228 cirbuf_del_tail(&rdl->left);
230 display_right_buffer(rdl);
235 if(!cirbuf_del_head_safe(&rdl->right)) {
236 display_right_buffer(rdl);
238 if (cmd == KEY_CTRL_D &&
239 CIRBUF_IS_EMPTY(&rdl->left) &&
240 CIRBUF_IS_EMPTY(&rdl->right)) {
246 if (CIRBUF_IS_EMPTY(&rdl->left))
248 rdline_miniprintf_P(rdl, PSTR(vt100_multi_left),
249 CIRBUF_GET_LEN(&rdl->left));
250 while (! 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);
258 if (CIRBUF_IS_EMPTY(&rdl->right))
260 rdline_miniprintf_P(rdl, PSTR(vt100_multi_right),
261 CIRBUF_GET_LEN(&rdl->right));
262 while (! CIRBUF_IS_EMPTY(&rdl->right)) {
263 tmp = cirbuf_get_head(&rdl->right);
264 cirbuf_del_head(&rdl->right);
265 cirbuf_add_tail(&rdl->left, tmp);
269 #ifdef CONFIG_MODULE_RDLINE_KILL_BUF
271 cirbuf_get_buf_head(&rdl->right, rdl->kill_buf, RDLINE_BUF_SIZE);
272 rdl->kill_size = CIRBUF_GET_LEN(&rdl->right);
273 cirbuf_del_buf_head(&rdl->right, rdl->kill_size);
274 rdline_puts_P(rdl, PSTR(vt100_clear_right));
279 while(CIRBUF_GET_LEN(&rdl->right) + CIRBUF_GET_LEN(&rdl->left) <
281 i < rdl->kill_size) {
282 cirbuf_add_tail(&rdl->left, rdl->kill_buf[i]);
283 rdl->write_char(rdl->kill_buf[i]);
286 display_right_buffer(rdl);
288 #endif /* CONFIG_MODULE_RDLINE_KILL_BUF */
291 rdline_puts_P(rdl, PSTR("\r\n"));
292 rdline_newline(rdl, rdl->prompt);
296 rdline_redisplay(rdl);
301 cirbuf_align_left(&rdl->left);
302 rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\0';
304 char tmp_buf[127]; /* XXX */
305 int16_t complete_state;
314 ret = rdl->complete(rdl->left_buf, tmp_buf, sizeof(tmp_buf),
316 /* no completion or error */
321 tmp_size = strlen(tmp_buf);
325 while(CIRBUF_GET_LEN(&rdl->right) + CIRBUF_GET_LEN(&rdl->left) <
328 cirbuf_add_tail(&rdl->left, tmp_buf[i]);
329 rdl->write_char(tmp_buf[i]);
332 display_right_buffer(rdl);
337 rdline_puts_P(rdl, PSTR("\r\n"));
339 rdl->write_char(' ');
340 for (i=0 ; tmp_buf[i] ; i++)
341 rdl->write_char(tmp_buf[i]);
342 rdline_puts_P(rdl, PSTR("\r\n"));
343 ret = rdl->complete(rdl->left_buf, tmp_buf,
344 sizeof(tmp_buf), &complete_state);
347 rdline_redisplay(rdl);
353 rdline_get_buffer(rdl);
354 rdl->status = RDLINE_INIT;
355 rdline_puts_P(rdl, PSTR("\r\n"));
356 #ifdef CONFIG_MODULE_RDLINE_HISTORY
357 if (rdl->history_cur_line != -1)
358 rdline_remove_first_history_item(rdl);
362 rdl->validate(rdl->left_buf, CIRBUF_GET_LEN(&rdl->left)+2);
365 #ifdef CONFIG_MODULE_RDLINE_HISTORY
367 if (rdl->history_cur_line == 0) {
368 rdline_remove_first_history_item(rdl);
370 if (rdl->history_cur_line <= 0) {
371 rdline_add_history(rdl, rdline_get_buffer(rdl));
372 rdl->history_cur_line = 0;
375 buf = rdline_get_history_item(rdl, rdl->history_cur_line + 1);
379 rdl->history_cur_line ++;
380 vt100_init(&rdl->vt100);
381 cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
382 cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
383 cirbuf_add_buf_tail(&rdl->left, buf, strlen(buf));
384 rdline_redisplay(rdl);
388 if (rdl->history_cur_line - 1 < 0)
391 rdl->history_cur_line --;
392 buf = rdline_get_history_item(rdl, rdl->history_cur_line);
395 vt100_init(&rdl->vt100);
396 cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
397 cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
398 cirbuf_add_buf_tail(&rdl->left, buf, strlen(buf));
399 rdline_redisplay(rdl);
402 #endif /* CONFIG_MODULE_RDLINE_HISTORY */
416 if (CIRBUF_GET_LEN(&rdl->left) + CIRBUF_GET_LEN(&rdl->right) >= RDLINE_BUF_SIZE)
419 if (cirbuf_add_tail_safe(&rdl->left, c))
423 display_right_buffer(rdl);
431 #ifdef CONFIG_MODULE_RDLINE_HISTORY
433 rdline_remove_old_history_item(struct rdline * rdl)
437 while (! CIRBUF_IS_EMPTY(&rdl->history) ) {
438 tmp = cirbuf_get_head(&rdl->history);
439 cirbuf_del_head(&rdl->history);
446 rdline_remove_first_history_item(struct rdline * rdl)
450 if ( CIRBUF_IS_EMPTY(&rdl->history) ) {
454 cirbuf_del_tail(&rdl->history);
457 while (! CIRBUF_IS_EMPTY(&rdl->history) ) {
458 tmp = cirbuf_get_tail(&rdl->history);
461 cirbuf_del_tail(&rdl->history);
466 rdline_get_history_size(struct rdline * rdl)
468 uint8_t i, tmp, ret=0;
470 CIRBUF_FOREACH(&rdl->history, i, tmp) {
479 rdline_get_history_item(struct rdline * rdl, uint8_t idx)
483 len = rdline_get_history_size(rdl);
488 cirbuf_align_left(&rdl->history);
490 CIRBUF_FOREACH(&rdl->history, i, tmp) {
491 if ( idx == len - 1) {
492 return rdl->history_buf + i;
502 rdline_add_history(struct rdline * rdl, const char * buf)
507 for (i=0; i<len ; i++) {
508 if (buf[i] == '\n') {
514 if ( len >= RDLINE_HISTORY_BUF_SIZE )
517 while ( len >= CIRBUF_GET_FREELEN(&rdl->history) ) {
518 rdline_remove_old_history_item(rdl);
521 cirbuf_add_buf_tail(&rdl->history, buf, len);
522 cirbuf_add_tail(&rdl->history, 0);
528 rdline_clear_history(struct rdline * rdl)
530 cirbuf_init(&rdl->history, rdl->history_buf, 0, RDLINE_HISTORY_BUF_SIZE);
533 #else /* CONFIG_MODULE_RDLINE_HISTORY */
535 int8_t rdline_add_history(struct rdline * rdl, const char * buf) {return -1;}
536 void rdline_clear_history(struct rdline * rdl) {}
537 char * rdline_get_history_item(struct rdline * rdl, uint8_t i) {return NULL;}
540 #endif /* CONFIG_MODULE_RDLINE_HISTORY */
543 /* STATIC USEFUL FUNCS */
546 rdline_puts_P(struct rdline * rdl, const prog_char * buf)
549 while ( (c=pgm_read_byte(buf++)) != '\0' ) {
554 /* a very very basic printf with one arg and one format 'u' */
556 rdline_miniprintf_P(struct rdline * rdl, const prog_char * buf, uint8_t val)
558 char c, started=0, div=100;
560 while ( (c=pgm_read_byte(buf++)) ) {
562 c = pgm_read_byte(buf++);
564 if (c=='u') { /* val is never more than 255 */
568 rdl->write_char(c+'0');
576 rdl->write_char('%');