/*******************************************************************
Components for embedded applications builded for
- laboratory and medical instruments firmware
-
+ laboratory and medical instruments firmware
+
cmd_proc.h - text line command processor
designed for instruments control and setup
over RS-232 line
-
+
Copyright (C) 2001 by Pavel Pisa pisa@cmp.felk.cvut.cz
(C) 2002 by PiKRON Ltd. http://www.pikron.com
(C) 2007 by Michal Sojka <sojkam1@fel.cvut.cz>
#include <cmd_proc.h>
#include "cmd_proc_priv.h"
#include <string.h>
+#include <ctype.h>
/* cmd_io line editor */
-/**
+/**
* Adds new characters to an edit line buffer.
- *
+ *
* @param elb Edit line buffer.
* @param ch character to add.
- *
- * @return 1 in case of end of line, 0 otherwise.
+ *
+ * @return 1 in case of end of line, -1 if called at inaproprate time, 0 otherwise.
*/
int cmd_ed_line_buf(ed_line_buf_t *elb, int ch)
{
if(!lastch){
elb->inbuf=0; /* Start new line */
}
+ if(ch == '\b' || ch == 127) { /* backspace, del (sometimes backspace = 127) */
+ if (elb->inbuf > 0)
+ elb->inbuf--;
+ return 0;
+ }
if((!(elb->flg&FL_ELB_NOCRLF))&&((ch=='\n')||(ch=='\r'))){
if((lastch=='\n')&&(ch=='\r')) /* Empty line, ignore it. */
return 0;
elb->buf[elb->inbuf]=0;
return 1;
}
- if(elb->inbuf>=elb->alloc-1){
+ if(elb->inbuf>=elb->alloc-1){
/* try to reallocate buffer len not implemented */
return 0;
}
- elb->buf[elb->inbuf++]=ch;
+ elb->buf[elb->inbuf++]=ch;
return 0;
}
{
cmd_io_t* io_stack=cmd_io->priv.ed_line.io_stack;
ed_line_buf_t* ed_line_out=cmd_io->priv.ed_line.out;
-
+
if(!ed_line_out->inbuf) return 0;
if(!io_stack)
return -1;
-
+
if(!(ed_line_out->flg&FL_ELB_INSEND)){
ed_line_out->flg|=FL_ELB_INSEND;
ed_line_out->lastch=0;
return 1;
}
-/* process input */
+static void replace_history(ed_line_buf_t *el, cmd_io_t* io_stack)
+{
+ if(!el->lastch)
+ el->inbuf=0; /* Make inbuf consistent */
+ while (el->inbuf) { /* Delete previous input */
+ el->inbuf--;
+ while (cmd_io_putc(io_stack,'\b') < 0);
+ }
+ if (el->hist_idx >= 0) {
+ strncpy(el->buf, el->hist + el->hist_idx*el->alloc, el->alloc);
+ while (el->buf[el->inbuf]) {
+ el->lastch = el->buf[el->inbuf++];
+ while (cmd_io_putc(io_stack, el->lastch) < 0);
+ }
+ }
+ cmd_io_puts(io_stack, "\033[K"); /* Erase End of Line */
+}
+
+/**
+ * @return One when the character was consumed, zero otherwise.
+ */
+static int handle_history(ed_line_buf_t *el, char ch, cmd_io_t* io_stack)
+{
+ enum { NONE, UP, DOWN } dir = NONE;
+
+ if (!(el->hist && el->hist_size && el->hist_size >= 2*el->alloc))
+ return 0;
+
+ switch (ch) {
+ case 14: /* Ctrl-N */
+ dir = DOWN;
+ break;
+ case 16: /* Ctrl-P */
+ dir = UP;
+ break;
+ case '\033': /* ESC */
+ strcpy(el->esc, "\033");
+ return 1;
+ default:
+ if (!el->esc[0])
+ return 0;
+
+ char *p = el->esc+1;
+ while (*p && p < el->esc + sizeof(el->esc) - 2) p++;
+ if (!*p) {
+ p[0] = ch;
+ p[1] = 0;
+ }
+ if (isalpha(ch)) {
+ if (strcmp(el->esc, "\033[A") == 0) dir = UP;
+ else if (strcmp(el->esc, "\033[B") == 0) dir = DOWN;
+ el->esc[0] = 0;
+ }
+ if (dir == NONE)
+ return 1;
+ }
+
+ if (dir == DOWN) {
+ if (el->hist_idx >= 0)
+ el->hist_idx--;
+ else
+ return 1;
+ } else if (dir == UP) {
+ if ((el->hist_idx+2) * el->alloc <= el->hist_size &&
+ el->hist[(el->hist_idx+1) * el->alloc])
+ el->hist_idx++;
+ else
+ return 1;
+ }
+
+ replace_history(el, io_stack);
+ return 1;
+}
+
+/* process input & perform echo if requested */
int cmd_io_line_in(cmd_io_t *cmd_io)
{
int ch;
cmd_io_t* io_stack = cmd_io->priv.ed_line.io_stack;
- ed_line_buf_t *ed_line_in = cmd_io->priv.ed_line.in;
+ ed_line_buf_t *el = cmd_io->priv.ed_line.in;
if(!io_stack)
return -1;
while((ch=cmd_io_getc(io_stack))>=0){
// DPRINT("Added %c (%d)\n", ch, ch);
- int eol = cmd_ed_line_buf(ed_line_in,ch);
+ if (handle_history(el, ch, io_stack) == 1)
+ continue;
+ int eol = cmd_ed_line_buf(el,ch);
+ if (eol == -1)
+ return -1;
if(eol){
- if(ed_line_in->flg&FL_ELB_ECHO){
+ if(el->flg&FL_ELB_ECHO){
while(cmd_io_putc(io_stack,'\r')<0);
while(cmd_io_putc(io_stack,'\n')<0);
}
+ if (el->hist && el->hist_size) {
+ el->hist_idx = -1;
+ if ((el->hist[0] && strcmp(el->buf, el->hist) == 0) || /* The same command as before */
+ !el->buf[0]) /* Empty line */
+ return 1; /* Don't add to the history */
+ memmove(el->hist + el->alloc, el->hist, el->hist_size - el->alloc);
+ strncpy(el->hist, el->buf, el->alloc);
+ }
return 1;
}
- else
- if(ed_line_in->flg&FL_ELB_ECHO) {
+ else
+ if(el->flg&FL_ELB_ECHO) {
while(cmd_io_putc(io_stack,ch)<0);
+ if (ch == 127)
+ while(cmd_io_putc(io_stack,'\b')<0);
+ if (ch == '\b' || ch == 127)
+ cmd_io_puts(io_stack, "\033[K"); /* Erase End of Line */
}
}
return 0;
}
-/* char *cmd_io_line_rdline(cmd_io_t *cmd_io, int mode) */
-/* { */
-/* int ret; */
-/* while((ret=cmd_rs232_line_in(cmd_io))==0) */
-/* if(!mode) break; */
-/* if(ret<=0) return NULL; */
-/* return cmd_io->priv.ed_line.in->buf; */
-/* } */
+/* The possibly blocking read of one line, should be used only
+ when other options fails */
+char *cmd_io_line_rdline(cmd_io_t *cmd_io, int mode)
+{
+ int ret;
+ while((ret=cmd_io_line_in(cmd_io))==0)
+ if(!mode) break;
+ if(ret<=0) return NULL;
+ return cmd_io->priv.ed_line.in->buf;
+}
/* Local Variables: */
/* c-basic-offset: 2 */
-/* End */
+/* End: */