From 9a5bd901d8e6270cf3d919ef38429850fa6626fc Mon Sep 17 00:00:00 2001 From: cvs Date: Wed, 12 Mar 2003 13:48:24 +0000 Subject: [PATCH] added a nice java-free sics commandline client M.Z. --- tecs/six.c | 214 ++++++++++++++++++++++++++++++++++++++++++ tecs/sys_select.c | 91 ++++++++++++++++++ tecs/sys_select.h | 14 +++ tecs/term.c | 233 ++++++++++++++++++++++++++++++++++++++++++++++ tecs/term.h | 19 ++++ 5 files changed, 571 insertions(+) create mode 100644 tecs/six.c create mode 100644 tecs/sys_select.c create mode 100644 tecs/sys_select.h create mode 100644 tecs/term.c create mode 100644 tecs/term.h diff --git a/tecs/six.c b/tecs/six.c new file mode 100644 index 00000000..cfc3b081 --- /dev/null +++ b/tecs/six.c @@ -0,0 +1,214 @@ +#include +#include +#include +#include +#include +#include +#include "coc_util.h" +#include "myc_err.h" +#include "myc_str.h" +#include +#include +#include +#include "term.h" + +int CocCreateSockAdr( + struct sockaddr_in *sockaddrPtr, /* Socket address */ + const char *host, /* Host. NULL implies INADDR_ANY */ + int port) /* Port number */ +{ + struct hostent *hostent; /* Host database entry */ + struct in_addr addr; /* For 64/32 bit madness */ + + (void) memset((char *) sockaddrPtr, '\0', sizeof(struct sockaddr_in)); + sockaddrPtr->sin_family = AF_INET; + sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF)); + if (host == NULL || host[0]=='\0') { + addr.s_addr = INADDR_ANY; + } else { + hostent = gethostbyname(host); + if (hostent != NULL) { + memcpy((char *) &addr, + (char *) hostent->h_addr_list[0], (size_t) hostent->h_length); + } else { + addr.s_addr = inet_addr(host); + if (addr.s_addr == (unsigned long)-1) { + return -1; /* error */ + } + } + } + /* + * There is a rumor that this assignment may require care on + * some 64 bit machines. + */ + + sockaddrPtr->sin_addr.s_addr = addr.s_addr; + return 0; +} + +int readWrite(int fd, int skip) { + char msg[128]; + int l, i, go, iret, ires, n; + + n=0; + go=0; + ires=0; + iret=term_wait_fd(fd, skip?5000:1000); + while (iret==1) { + ERR_SI(l=recv(fd, msg, sizeof(msg)-1, 0)); + if (l==0) return(0); + msg[l]='\0'; + if (skip==4) { + ires=1; + } else if (skip==3) { + if (NULL!=strstr(msg, "Acknowledged")) ires=1; + } else if (skip==1 || skip==2) { + if (NULL!=strstr(msg, "SICS")) ires=1; + } + for (i=0; i=32) { + printf("argument too long\n"); + } else { + if (j==0) { + us=argv[i]; + j=1; + } else if (j==1) { + ps=argv[i]; + j=2; + } else { + printf("too many arguments\n"); + return 0; + } + } + } + } + if (j==1) { + printf("missing password\n"); + return(0); + } + instr=getenv("Instrument"); + if (instr==NULL || instr[0]=='\0') { + printf("Instrument is undefined\n"); + return(0); + } + ERR_I(CocCreateSockAdr(&sadr, "0", port)); + ERR_SI(fd=socket(AF_INET, SOCK_STREAM, 0)); + term_reg_socket(fd); + ERR_SI(connect(fd, (struct sockaddr *)&sadr, sizeof(sadr))); + strcpy(buf, "sicslogin Spy 007\r\n"); + ERR_SI(send(fd, buf, strlen(buf), 0)); + ERR_I(i=readWrite(fd,skip)); + if (!i) { + printf("rejected\n"); + return 0; + } + printf("reading welcome message ...\n"); + if (j==0) { + rights=getenv("six_rights"); + if (rights!=NULL && 0==strcmp(rights, instr)) { + us="lnsmanager"; + ps="lnsSICSlns"; + } else { + sprintf(ibuf, "%suser", instr); + str_lowcase(ibuf, ibuf); + us=ibuf; + ps="02lns1"; + } + } + sprintf(buf, "config Rights %s %s\r\n", us, ps); + ERR_SI(send(fd, buf, strlen(buf), 0)); + ERR_I(i=readWrite(fd,3)); + if (!i) { + us="Spy"; + } + printf("logged in to SICS as %s on %s%s\n", us, instr, sim); + if (*sim!='\0') { + strcpy(buf, "sync\r\n"); + ERR_SI(send(fd, buf, strlen(buf), 0)); + ERR_I(i=readWrite(fd,4)); + printf("synchronized (%d chars read)\n", i); + } + iret=1; + buf[0]='\0'; + pos=0; + str_lowcase(instr,instr); + sprintf(ibuf, "six[%s%s] ", instr, sim); + while (1) { + FD_ZERO(&mask); + FD_SET(fd, &mask); + iret=term_get_line(buf, sizeof(buf)-2, &pos, ibuf, &mask); + if (iret==STDIN_FILENO) { /* input line terminated */ + str_lowcase(lbuf, buf); + if (0==strcmp(lbuf,"quit")) break; + if (0==strcmp(lbuf,"exit")) break; + if (0==strcmp(lbuf,"stop")) { + strcpy(buf, "INT1712 3"); + } else if (0==strcmp(buf, "")) { + strcpy(buf, "status"); + } + fputs("\n", stdout); + skip=0; + if (0==strcmp(lbuf,"sync")) skip=4; + l=strlen(buf); +/* + printf("sent> %s[%d chars]\n", buf, l); +*/ + buf[l]=13; + buf[l+1]=10; + ERR_SI(send(fd, buf, l+2, 0)); + ERR_I(i=readWrite(fd,skip)); + if (skip==4) { + printf("synchronize (%d chars read)\n", i); + } + buf[0]='\0'; + pos=0; + } else if (iret<0) { /* ?? */ + printf("\nwhat?\n"); exit(1); + } else { /* socket iret ready to read */ + assert(fd==iret); + ERR_I(readWrite(fd,0)); + } + } + fputs("\n", stdout); + return(0); + OnError: + ErrShow("end"); + return(0); +} diff --git a/tecs/sys_select.c b/tecs/sys_select.c new file mode 100644 index 00000000..6f9e87dc --- /dev/null +++ b/tecs/sys_select.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include + +static int lastFd=-1; +static struct termios atts; + +void sys_keys_on(void) { + int iret; + + struct termios attr; + iret=tcgetattr(STDIN_FILENO,&attr); + atts=attr; /* save term. attr. */ + if (iret!=0) { perror("***\n");} + attr.c_lflag &= ~(ICANON) & ~(ECHO); /* canonical mode off, echo off */ + attr.c_cc[VMIN]=0; + attr.c_cc[VTIME]=1; /* 0.1 sec */ + iret= tcsetattr(STDIN_FILENO,TCSANOW,&attr); + if (iret!=0) {perror("***\n");} +} + +void sys_keys_off(void) { + int iret; + + iret=tcsetattr(STDIN_FILENO,TCSANOW,&atts); /* restore term. attributes */ + if (iret!=0) {perror("***\n");}; +} + +int sys_select_or_key(fd_set *mask, int msecTmo, char *key) { + int chan, fd, iret, fd1, m, chr; + struct timeval tmo, tmo0={0,0}; + fd_set rmask; + static int init=1; + + if (init) { + sys_keys_on(); + init=0; + } + rmask=*mask; + iret=select(FD_SETSIZE, &rmask, NULL, NULL, &tmo0); + if (iret<0) { + FD_ZERO(&rmask); + perror("error in select"); + } + fd1=STDIN_FILENO; + chr=fgetc(stdin); + if (chr==EOF && iret==0) { + rmask=*mask; + FD_SET(STDIN_FILENO, &rmask); + if (msecTmo>=0) { + if (msecTmo>100) { /* reduce 100 ms for the 1 tenth second in fgetc */ + msecTmo=msecTmo-100; + } else { + msecTmo=1; + } + tmo.tv_sec=msecTmo / 1000; + tmo.tv_usec=(msecTmo%1000)*1000; + iret=select(FD_SETSIZE, &rmask, NULL, NULL, &tmo); + } else { + iret=select(FD_SETSIZE, &rmask, NULL, NULL, NULL); + } + if (iret<0) { + FD_ZERO(&rmask); + perror("error in select"); + } + if (FD_ISSET(STDIN_FILENO, &rmask)) { + chr=fgetc(stdin); + } + FD_CLR(STDIN_FILENO, &rmask); + } + if (chr==EOF) { + chr=0; + fd1=-1; + for (fd=1; fdlastFd) { + fd1=fd; break; + } + } + } + } + *mask=rmask; + *key=chr; + /* + sys_keys_off(); + */ + return(fd1); +} diff --git a/tecs/sys_select.h b/tecs/sys_select.h new file mode 100644 index 00000000..ac18468a --- /dev/null +++ b/tecs/sys_select.h @@ -0,0 +1,14 @@ +#ifndef SYS_SELECT_H_ +#define SYS_SELECT_H_ + +#include + +int sys_select_or_key(fd_set *mask, int msecTmo, char *key); + +/* wait for read event on sockets included in mask or from keyboard or a timeout + result is negative for timeout, + STDIN_FILENO for a key pressed, + else socket number +*/ + +#endif /* SYS_SELECT_H_ */ diff --git a/tecs/term.c b/tecs/term.c new file mode 100644 index 00000000..94f70351 --- /dev/null +++ b/tecs/term.c @@ -0,0 +1,233 @@ +#include +#include +#include +#include +#include +#include +#include +#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; + int i,j,l,iret; + 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 */ + history[hist_end]=malloc(strlen(buf)+1); + strncpy(history[hist_end], buf, size); + 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); + } +} + diff --git a/tecs/term.h b/tecs/term.h new file mode 100644 index 00000000..34773fa3 --- /dev/null +++ b/tecs/term.h @@ -0,0 +1,19 @@ +#ifndef TERM_H_ +#define TERM_H_ + +void term_reg_socket(int fd); +/* register socket */ + +void term_unr_socket(int fd); +/* unregister socket */ + +int term_raw_key(char *key, int msecTmo); + +int term_wait_fd(int fd, int msecTmo); +/* wait for a read event on fd or timeout */ + +int term_get_key(char *key, int msecTmo); + +int term_get_line(char *buf, int size, int *pos, char *prompt, fd_set *mask); + +#endif /* TERM_H_ */