00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <stdlib.h>
00025 #include <stdio.h>
00026 #include <string.h>
00027 #include <stdarg.h>
00028 #include <ctype.h>
00029
00030 #include <aversive/pgmspace.h>
00031
00032 #include <cirbuf.h>
00033 #include "rdline.h"
00034
00035 static void rdline_puts_P(struct rdline * rdl, const prog_char * buf);
00036 static void rdline_miniprintf_P(struct rdline * rdl,
00037 const prog_char * buf, uint8_t val);
00038
00039 #ifdef CONFIG_MODULE_RDLINE_HISTORY
00040 static void rdline_remove_old_history_item(struct rdline * rdl);
00041 static void rdline_remove_first_history_item(struct rdline * rdl);
00042 static uint8_t rdline_get_history_size(struct rdline * rdl);
00043 #endif
00044
00045
00046 void rdline_init(struct rdline *rdl,
00047 rdline_write_char_t *write_char,
00048 rdline_validate_t *validate,
00049 rdline_complete_t *complete)
00050 {
00051 memset(rdl, 0, sizeof(*rdl));
00052 rdl->validate = validate;
00053 rdl->complete = complete;
00054 rdl->write_char = write_char;
00055 rdl->status = RDLINE_INIT;
00056 #ifdef CONFIG_MODULE_RDLINE_HISTORY
00057 cirbuf_init(&rdl->history, rdl->history_buf, 0, RDLINE_HISTORY_BUF_SIZE);
00058 #endif
00059 }
00060
00061 void
00062 rdline_newline(struct rdline * rdl, const char * prompt)
00063 {
00064 uint8_t i;
00065
00066 vt100_init(&rdl->vt100);
00067 cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
00068 cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
00069
00070 if (prompt != rdl->prompt)
00071 memcpy(rdl->prompt, prompt, sizeof(rdl->prompt)-1);
00072 rdl->prompt_size = strlen(prompt);
00073
00074 for (i=0 ; i<rdl->prompt_size ; i++)
00075 rdl->write_char(rdl->prompt[i]);
00076 rdl->status = RDLINE_RUNNING;
00077
00078 #ifdef CONFIG_MODULE_RDLINE_HISTORY
00079 rdl->history_cur_line = -1;
00080 #endif
00081 }
00082
00083 void
00084 rdline_stop(struct rdline * rdl)
00085 {
00086 rdl->status = RDLINE_INIT;
00087 }
00088
00089 void
00090 rdline_restart(struct rdline * rdl)
00091 {
00092 rdl->status = RDLINE_RUNNING;
00093 }
00094
00095 const char *
00096 rdline_get_buffer(struct rdline * rdl)
00097 {
00098 uint8_t len_l, len_r;
00099 cirbuf_align_left(&rdl->left);
00100 cirbuf_align_left(&rdl->right);
00101
00102 len_l = CIRBUF_GET_LEN(&rdl->left);
00103 len_r = CIRBUF_GET_LEN(&rdl->right);
00104 memcpy(rdl->left_buf+len_l, rdl->right_buf, len_r);
00105
00106 rdl->left_buf[len_l + len_r] = '\n';
00107 rdl->left_buf[len_l + len_r + 1] = '\0';
00108 return rdl->left_buf;
00109 }
00110
00111 static void
00112 display_right_buffer(struct rdline * rdl)
00113 {
00114 uint8_t i;
00115 char tmp;
00116
00117 rdline_puts_P(rdl, PSTR(vt100_clear_right));
00118 if (!CIRBUF_IS_EMPTY(&rdl->right)) {
00119 CIRBUF_FOREACH(&rdl->right, i, tmp) {
00120 rdl->write_char(tmp);
00121 }
00122 rdline_miniprintf_P(rdl, PSTR(vt100_multi_left),
00123 CIRBUF_GET_LEN(&rdl->right));
00124 }
00125 }
00126
00127 void rdline_redisplay(struct rdline * rdl)
00128 {
00129 uint8_t i;
00130 char tmp;
00131
00132 rdline_puts_P(rdl, PSTR(vt100_home));
00133 for (i=0 ; i<rdl->prompt_size ; i++)
00134 rdl->write_char(rdl->prompt[i]);
00135 CIRBUF_FOREACH(&rdl->left, i, tmp) {
00136 rdl->write_char(tmp);
00137 }
00138 display_right_buffer(rdl);
00139 }
00140
00141 int8_t
00142 rdline_char_in(struct rdline * rdl, char c)
00143 {
00144 uint8_t i;
00145 int8_t cmd;
00146 char tmp;
00147 #ifdef CONFIG_MODULE_RDLINE_HISTORY
00148 char * buf;
00149 #endif
00150
00151 if (rdl->status != RDLINE_RUNNING)
00152 return -1;
00153
00154 cmd = vt100_parser(&rdl->vt100, c);
00155 if (cmd == -2)
00156 return 0;
00157
00158 if (cmd >= 0) {
00159 switch (cmd) {
00160 case KEY_CTRL_B:
00161 case KEY_LEFT_ARR:
00162 if (CIRBUF_IS_EMPTY(&rdl->left))
00163 break;
00164 tmp = cirbuf_get_tail(&rdl->left);
00165 cirbuf_del_tail(&rdl->left);
00166 cirbuf_add_head(&rdl->right, tmp);
00167 rdline_puts_P(rdl, PSTR(vt100_left_arr));
00168 break;
00169
00170 case KEY_CTRL_F:
00171 case KEY_RIGHT_ARR:
00172 if (CIRBUF_IS_EMPTY(&rdl->right))
00173 break;
00174 tmp = cirbuf_get_head(&rdl->right);
00175 cirbuf_del_head(&rdl->right);
00176 cirbuf_add_tail(&rdl->left, tmp);
00177 rdline_puts_P(rdl, PSTR(vt100_right_arr));
00178 break;
00179
00180 case KEY_WLEFT:
00181 while (! CIRBUF_IS_EMPTY(&rdl->left) &&
00182 (tmp = cirbuf_get_tail(&rdl->left)) &&
00183 isblank(tmp)) {
00184 rdline_puts_P(rdl, PSTR(vt100_left_arr));
00185 cirbuf_del_tail(&rdl->left);
00186 cirbuf_add_head(&rdl->right, tmp);
00187 }
00188 while (! CIRBUF_IS_EMPTY(&rdl->left) &&
00189 (tmp = cirbuf_get_tail(&rdl->left)) &&
00190 !isblank(tmp)) {
00191 rdline_puts_P(rdl, PSTR(vt100_left_arr));
00192 cirbuf_del_tail(&rdl->left);
00193 cirbuf_add_head(&rdl->right, tmp);
00194 }
00195 break;
00196
00197 case KEY_WRIGHT:
00198 while (! CIRBUF_IS_EMPTY(&rdl->right) &&
00199 (tmp = cirbuf_get_head(&rdl->right)) &&
00200 isblank(tmp)) {
00201 rdline_puts_P(rdl, PSTR(vt100_right_arr));
00202 cirbuf_del_head(&rdl->right);
00203 cirbuf_add_tail(&rdl->left, tmp);
00204 }
00205 while (! CIRBUF_IS_EMPTY(&rdl->right) &&
00206 (tmp = cirbuf_get_head(&rdl->right)) &&
00207 !isblank(tmp)) {
00208 rdline_puts_P(rdl, PSTR(vt100_right_arr));
00209 cirbuf_del_head(&rdl->right);
00210 cirbuf_add_tail(&rdl->left, tmp);
00211 }
00212 break;
00213
00214 case KEY_BKSPACE:
00215 if(!cirbuf_del_tail_safe(&rdl->left)) {
00216 rdline_puts_P(rdl, PSTR(vt100_bs));
00217 display_right_buffer(rdl);
00218 }
00219 break;
00220
00221 case KEY_META_BKSPACE:
00222 while (! CIRBUF_IS_EMPTY(&rdl->left) && isblank(cirbuf_get_tail(&rdl->left))) {
00223 rdline_puts_P(rdl, PSTR(vt100_bs));
00224 cirbuf_del_tail(&rdl->left);
00225 }
00226 while (! CIRBUF_IS_EMPTY(&rdl->left) && !isblank(cirbuf_get_tail(&rdl->left))) {
00227 rdline_puts_P(rdl, PSTR(vt100_bs));
00228 cirbuf_del_tail(&rdl->left);
00229 }
00230 display_right_buffer(rdl);
00231 break;
00232
00233 case KEY_SUPPR:
00234 case KEY_CTRL_D:
00235 if(!cirbuf_del_head_safe(&rdl->right)) {
00236 display_right_buffer(rdl);
00237 }
00238 if (cmd == KEY_CTRL_D &&
00239 CIRBUF_IS_EMPTY(&rdl->left) &&
00240 CIRBUF_IS_EMPTY(&rdl->right)) {
00241 return -2;
00242 }
00243 break;
00244
00245 case KEY_CTRL_A:
00246 if (CIRBUF_IS_EMPTY(&rdl->left))
00247 break;
00248 rdline_miniprintf_P(rdl, PSTR(vt100_multi_left),
00249 CIRBUF_GET_LEN(&rdl->left));
00250 while (! CIRBUF_IS_EMPTY(&rdl->left)) {
00251 tmp = cirbuf_get_tail(&rdl->left);
00252 cirbuf_del_tail(&rdl->left);
00253 cirbuf_add_head(&rdl->right, tmp);
00254 }
00255 break;
00256
00257 case KEY_CTRL_E:
00258 if (CIRBUF_IS_EMPTY(&rdl->right))
00259 break;
00260 rdline_miniprintf_P(rdl, PSTR(vt100_multi_right),
00261 CIRBUF_GET_LEN(&rdl->right));
00262 while (! CIRBUF_IS_EMPTY(&rdl->right)) {
00263 tmp = cirbuf_get_head(&rdl->right);
00264 cirbuf_del_head(&rdl->right);
00265 cirbuf_add_tail(&rdl->left, tmp);
00266 }
00267 break;
00268
00269 #ifdef CONFIG_MODULE_RDLINE_KILL_BUF
00270 case KEY_CTRL_K:
00271 cirbuf_get_buf_head(&rdl->right, rdl->kill_buf, RDLINE_BUF_SIZE);
00272 rdl->kill_size = CIRBUF_GET_LEN(&rdl->right);
00273 cirbuf_del_buf_head(&rdl->right, rdl->kill_size);
00274 rdline_puts_P(rdl, PSTR(vt100_clear_right));
00275 break;
00276
00277 case KEY_CTRL_Y:
00278 i=0;
00279 while(CIRBUF_GET_LEN(&rdl->right) + CIRBUF_GET_LEN(&rdl->left) <
00280 RDLINE_BUF_SIZE &&
00281 i < rdl->kill_size) {
00282 cirbuf_add_tail(&rdl->left, rdl->kill_buf[i]);
00283 rdl->write_char(rdl->kill_buf[i]);
00284 i++;
00285 }
00286 display_right_buffer(rdl);
00287 break;
00288 #endif
00289
00290 case KEY_CTRL_C:
00291 rdline_puts_P(rdl, PSTR("\r\n"));
00292 rdline_newline(rdl, rdl->prompt);
00293 break;
00294
00295 case KEY_CTRL_L:
00296 rdline_redisplay(rdl);
00297 break;
00298
00299 case KEY_TAB:
00300 case KEY_HELP:
00301 cirbuf_align_left(&rdl->left);
00302 rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\0';
00303 if (rdl->complete) {
00304 char tmp_buf[127];
00305 int16_t complete_state;
00306 int8_t ret;
00307 int tmp_size;
00308
00309 if (cmd == KEY_TAB)
00310 complete_state = 0;
00311 else
00312 complete_state = -1;
00313
00314 ret = rdl->complete(rdl->left_buf, tmp_buf, sizeof(tmp_buf),
00315 &complete_state);
00316
00317 if (ret <= 0) {
00318 return 2;
00319 }
00320
00321 tmp_size = strlen(tmp_buf);
00322
00323 if (ret == 2) {
00324 i=0;
00325 while(CIRBUF_GET_LEN(&rdl->right) + CIRBUF_GET_LEN(&rdl->left) <
00326 RDLINE_BUF_SIZE &&
00327 i < tmp_size) {
00328 cirbuf_add_tail(&rdl->left, tmp_buf[i]);
00329 rdl->write_char(tmp_buf[i]);
00330 i++;
00331 }
00332 display_right_buffer(rdl);
00333 return 2;
00334 }
00335
00336
00337 rdline_puts_P(rdl, PSTR("\r\n"));
00338 while (ret) {
00339 rdl->write_char(' ');
00340 for (i=0 ; tmp_buf[i] ; i++)
00341 rdl->write_char(tmp_buf[i]);
00342 rdline_puts_P(rdl, PSTR("\r\n"));
00343 ret = rdl->complete(rdl->left_buf, tmp_buf,
00344 sizeof(tmp_buf), &complete_state);
00345 }
00346
00347 rdline_redisplay(rdl);
00348 }
00349 return 2;
00350
00351 case KEY_RETURN:
00352 case KEY_RETURN2:
00353 rdline_get_buffer(rdl);
00354 rdl->status = RDLINE_INIT;
00355 rdline_puts_P(rdl, PSTR("\r\n"));
00356 #ifdef CONFIG_MODULE_RDLINE_HISTORY
00357 if (rdl->history_cur_line != -1)
00358 rdline_remove_first_history_item(rdl);
00359 #endif
00360
00361 if (rdl->validate)
00362 rdl->validate(rdl->left_buf, CIRBUF_GET_LEN(&rdl->left)+2);
00363 return 1;
00364
00365 #ifdef CONFIG_MODULE_RDLINE_HISTORY
00366 case KEY_UP_ARR:
00367 if (rdl->history_cur_line == 0) {
00368 rdline_remove_first_history_item(rdl);
00369 }
00370 if (rdl->history_cur_line <= 0) {
00371 rdline_add_history(rdl, rdline_get_buffer(rdl));
00372 rdl->history_cur_line = 0;
00373 }
00374
00375 buf = rdline_get_history_item(rdl, rdl->history_cur_line + 1);
00376 if (!buf)
00377 break;
00378
00379 rdl->history_cur_line ++;
00380 vt100_init(&rdl->vt100);
00381 cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
00382 cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
00383 cirbuf_add_buf_tail(&rdl->left, buf, strlen(buf));
00384 rdline_redisplay(rdl);
00385 break;
00386
00387 case KEY_DOWN_ARR:
00388 if (rdl->history_cur_line - 1 < 0)
00389 break;
00390
00391 rdl->history_cur_line --;
00392 buf = rdline_get_history_item(rdl, rdl->history_cur_line);
00393 if (!buf)
00394 break;
00395 vt100_init(&rdl->vt100);
00396 cirbuf_init(&rdl->left, rdl->left_buf, 0, RDLINE_BUF_SIZE);
00397 cirbuf_init(&rdl->right, rdl->right_buf, 0, RDLINE_BUF_SIZE);
00398 cirbuf_add_buf_tail(&rdl->left, buf, strlen(buf));
00399 rdline_redisplay(rdl);
00400
00401 break;
00402 #endif
00403
00404
00405 default:
00406 break;
00407 }
00408
00409 return 0;
00410 }
00411
00412 if (! isprint(c))
00413 return 0;
00414
00415
00416 if (CIRBUF_GET_LEN(&rdl->left) + CIRBUF_GET_LEN(&rdl->right) >= RDLINE_BUF_SIZE)
00417 return 0;
00418
00419 if (cirbuf_add_tail_safe(&rdl->left, c))
00420 return 0;
00421
00422 rdl->write_char(c);
00423 display_right_buffer(rdl);
00424
00425 return 0;
00426 }
00427
00428
00429
00430
00431 #ifdef CONFIG_MODULE_RDLINE_HISTORY
00432 static void
00433 rdline_remove_old_history_item(struct rdline * rdl)
00434 {
00435 char tmp;
00436
00437 while (! CIRBUF_IS_EMPTY(&rdl->history) ) {
00438 tmp = cirbuf_get_head(&rdl->history);
00439 cirbuf_del_head(&rdl->history);
00440 if (!tmp)
00441 break;
00442 }
00443 }
00444
00445 static void
00446 rdline_remove_first_history_item(struct rdline * rdl)
00447 {
00448 char tmp;
00449
00450 if ( CIRBUF_IS_EMPTY(&rdl->history) ) {
00451 return;
00452 }
00453 else {
00454 cirbuf_del_tail(&rdl->history);
00455 }
00456
00457 while (! CIRBUF_IS_EMPTY(&rdl->history) ) {
00458 tmp = cirbuf_get_tail(&rdl->history);
00459 if (!tmp)
00460 break;
00461 cirbuf_del_tail(&rdl->history);
00462 }
00463 }
00464
00465 static uint8_t
00466 rdline_get_history_size(struct rdline * rdl)
00467 {
00468 uint8_t i, tmp, ret=0;
00469
00470 CIRBUF_FOREACH(&rdl->history, i, tmp) {
00471 if (tmp == 0)
00472 ret ++;
00473 }
00474
00475 return ret;
00476 }
00477
00478 char *
00479 rdline_get_history_item(struct rdline * rdl, uint8_t idx)
00480 {
00481 uint8_t len, i, tmp;
00482
00483 len = rdline_get_history_size(rdl);
00484 if ( idx >= len ) {
00485 return NULL;
00486 }
00487
00488 cirbuf_align_left(&rdl->history);
00489
00490 CIRBUF_FOREACH(&rdl->history, i, tmp) {
00491 if ( idx == len - 1) {
00492 return rdl->history_buf + i;
00493 }
00494 if (tmp == 0)
00495 len --;
00496 }
00497
00498 return NULL;
00499 }
00500
00501 int8_t
00502 rdline_add_history(struct rdline * rdl, const char * buf)
00503 {
00504 cirbuf_uint len, i;
00505
00506 len = strlen(buf);
00507 for (i=0; i<len ; i++) {
00508 if (buf[i] == '\n') {
00509 len = i;
00510 break;
00511 }
00512 }
00513
00514 if ( len >= RDLINE_HISTORY_BUF_SIZE )
00515 return -1;
00516
00517 while ( len >= CIRBUF_GET_FREELEN(&rdl->history) ) {
00518 rdline_remove_old_history_item(rdl);
00519 }
00520
00521 cirbuf_add_buf_tail(&rdl->history, buf, len);
00522 cirbuf_add_tail(&rdl->history, 0);
00523
00524 return 0;
00525 }
00526
00527 void
00528 rdline_clear_history(struct rdline * rdl)
00529 {
00530 cirbuf_init(&rdl->history, rdl->history_buf, 0, RDLINE_HISTORY_BUF_SIZE);
00531 }
00532
00533 #else
00534
00535 int8_t rdline_add_history(struct rdline * rdl, const char * buf) {return -1;}
00536 void rdline_clear_history(struct rdline * rdl) {}
00537 char * rdline_get_history_item(struct rdline * rdl, uint8_t i) {return NULL;}
00538
00539
00540 #endif
00541
00542
00543
00544
00545 static void
00546 rdline_puts_P(struct rdline * rdl, const prog_char * buf)
00547 {
00548 char c;
00549 while ( (c=pgm_read_byte(buf++)) != '\0' ) {
00550 rdl->write_char(c);
00551 }
00552 }
00553
00554
00555 static void
00556 rdline_miniprintf_P(struct rdline * rdl, const prog_char * buf, uint8_t val)
00557 {
00558 char c, started=0, div=100;
00559
00560 while ( (c=pgm_read_byte(buf++)) ) {
00561 if (c=='%') {
00562 c = pgm_read_byte(buf++);
00563
00564 if (c=='u') {
00565 while (div) {
00566 c = val / div;
00567 if (c || started) {
00568 rdl->write_char(c+'0');
00569 started = 1;
00570 }
00571 val %= div;
00572 div /= 10;
00573 }
00574 }
00575 else {
00576 rdl->write_char('%');
00577 rdl->write_char(c);
00578 }
00579 }
00580 else {
00581 rdl->write_char(c);
00582 }
00583 }
00584 }
00585