#include #include #include #include #include #include #include #include "myc_mem.h" #include "sys_select.h" #define ESC_TMO 1000 #define REF_TMO 100 #define HISTORY_LINES 256 #define L_ARROW '\200' #define R_ARROW '\201' #define U_ARROW '\202' #define D_ARROW '\203' #define EVT_CHAR '\0' #define DEL_CHAR '\b' #define RET_CHAR '\n' static char esc_key='\0'; static fd_set regMask; static int lastFd=-1; void term_reg_socket(int fd) { FD_SET(fd, ®Mask); } void term_unr_socket(int fd) { FD_CLR(fd, ®Mask); } int term_raw_key(char *key, int msecTmo) { fd_set mask; mask=regMask; return(sys_select_or_key(&mask, msecTmo, key)); } int term_wait_fd(int fd, int msecTmo) { fd_set mask; struct timeval tmo; FD_ZERO(&mask); FD_SET(fd, &mask); tmo.tv_sec=msecTmo / 1000; tmo.tv_usec=(msecTmo % 1000) * 1000+1; return(select(FD_SETSIZE, &mask, NULL, NULL, &tmo)); } int term_get_key(char *key, int msecTmo) { int iret; char k; if (esc_key==0) { iret=term_raw_key(&k, msecTmo); } else { k=esc_key; } while (k==27) { /* esc */ iret=term_raw_key(&k, ESC_TMO); switch (k) { case 'O': k='\217'; break; /* ss3 */ case '[': k='\233'; break; /* csi */ default: break; } } if (iret!=STDIN_FILENO) { esc_key=k; *key='\0'; return(iret); } switch (k) { case '\233': /* csi */ iret=term_raw_key(&k, ESC_TMO); while (k>='0' && k <='9') { iret=term_raw_key(&k, ESC_TMO); } if (iret!=STDIN_FILENO) { esc_key=k; *key='\0'; return(iret); } switch (k) { /* L,R,U,D arrows */ case 'D': k=L_ARROW; break; case 'C': k=R_ARROW; break; case 'A': k=U_ARROW; break; case 'B': k=D_ARROW; break; default: k='?'; } break; case '\217': /* ss3 */ iret=term_raw_key(&k, ESC_TMO); if (iret!=STDIN_FILENO) { esc_key=k; *key='\0'; return(iret); } if (k=='M') { /* enter */ k=RET_CHAR; } else if (k >= 'l' && k <= 'y') { k=k-64; } else { k='?'; } break; case '\177': /* del */ case '\b': /* bs */ k=DEL_CHAR; break; case '\r': /* cr */ case '\n': /* lf */ k=RET_CHAR; break; case EVT_CHAR: /* time out*/ break; default: if (k<' ' || k>'\176') k='?'; } *key=k; esc_key='\0'; return (STDIN_FILENO); } static char *history[HISTORY_LINES]={NULL}; /* history array: it's a cyclic buffer, when it is full, the oldest values are overwritten. */ static int hist_pos=0; /* position when scrolling through the history */ static int hist_end=0; /* end of history. Always history[hist_end]==NULL */ int term_get_line(char *buf, int size, int *pos, char *prompt, fd_set *mask) { char key, *lin; int i,j,l,iret,buflen; char tmp[512]; buf[size-1]='\0'; /* make sure buf is null terminated */ l=strlen(buf); if (*pos>l) { *pos=l; } else if (*pos<0) { *pos=0; } iret=term_get_key(&key, 0); while (1) { if (iret==-1 || key == RET_CHAR || key==EVT_CHAR) { /* refresh after a short timeout */ assert(l*2+20+strlen(prompt)*pos; i--) { tmp[j]='\b'; j++; } tmp[j]='\0'; fputs(tmp, stdout); if (iret==-1) { iret=term_get_key(&key, -1); /* no timeout */ } } switch (key) { case EVT_CHAR: fputs("\r\033[K", stdout); return(iret); /* interrupted EXIT */ case RET_CHAR: /* fputs("\r\033[K", stdout); */ i=hist_end-1; if (i<0) i=HISTORY_LINES-1; if ((history[i]==NULL || 0!=strcmp(history[i], buf)) && buf[0]!='\0') { /* do not save equal and empty lines */ buflen=strlen(buf)+1; lin=MALLOC(buflen); strncpy(lin, buf, buflen); history[hist_end]=lin; hist_end++; if (hist_end>=HISTORY_LINES) hist_end=0; if (history[hist_end]!=NULL) { FREE(history[hist_end]); /* clear line at end of history */ } history[hist_end]==NULL; } hist_pos=hist_end; return(STDIN_FILENO); /* normal EXIT */ case DEL_CHAR: if (*pos>0) { for (i=*pos; buf[i]!='\0'; i++) { buf[i-1] = buf [i]; } buf[i-1]='\0'; (*pos)--; l--; } break; case L_ARROW: if (*pos>0) (*pos)--; break; case R_ARROW: if (buf[*pos]!='\0') (*pos)++; break; case U_ARROW: case D_ARROW: if (key==U_ARROW) { i=hist_pos-1; if (i<0) i=HISTORY_LINES-1; } else { i=hist_pos+1; if (i>=HISTORY_LINES) i=0; } if (history[i]!=NULL) { strncpy(buf, history[i], size-1); buf[size-1]='\0'; hist_pos=i; l=strlen(buf); *pos=l; } break; default: if (l*pos; i--) { buf[i]=buf[i-1]; } (*pos)++; l++; buf[i]=key; buf[l]='\0'; } break; } iret=term_get_key(&key, REF_TMO); } }