chiark / gitweb /
*** empty log message ***
[sympathy.git] / src / ansi.c
index 4e951bba3c5a91081c2f34e5b831c0d133170b9c..16d9970194bb634c95b67692deee2952dbbd8c90 100644 (file)
@@ -10,6 +10,9 @@ static char rcsid[] = "$Id$";
 
 /*
  * $Log$
+ * Revision 1.8  2008/02/07 00:39:13  james
+ * *** empty log message ***
+ *
  * Revision 1.7  2008/02/06 20:26:57  james
  * *** empty log message ***
  *
@@ -34,9 +37,45 @@ static char rcsid[] = "$Id$";
  */
 #include "project.h"
 
+static void
+set_nonblocking (int fd)
+{
+  long arg;
+  arg = fcntl (fd, F_GETFL, arg);
+  arg |= O_NONBLOCK;
+  fcntl (fd, F_SETFL, arg);
+}
+
+static void
+set_blocking (int fd)
+{
+  long arg;
+  arg = fcntl (fd, F_GETFL, arg);
+  arg &= ~O_NONBLOCK;
+  fcntl (fd, F_SETFL, arg);
+}
+
+
+int ansi_read(ANSI *a,void *buf,int n)
+{
+int red;
+
+  set_nonblocking(a->fd);
+red=read(a->fd,buf,n);
+
+if (!red) return -1;
+
+if ((red==-1) && (errno==EAGAIN)) {
+       return 0;
+}
+
+return red;
+}
+
 void
 ansi_write (ANSI * a, char *buf, int n)
 {
+  set_blocking(a->fd);
   write (a->fd, buf, n);
 }
 
@@ -338,12 +377,154 @@ ansi_reset (ANSI * a)
   crt_reset (&a->crt);
 
   ansi_cls (a);
+  ansi_write(a,"\033=",2);
   ansi_draw (a, &a->crt);
 }
+void ansi_flush_escape(ANSI *a,VT102 *v)
+{
+ANSI_Parser *p=&a->parser;
+int i;
+
+for (i=0;i<p->escape_ptr;++i) {
+vt102_send(v,p->escape_buf[i]);
+}
+
+p->escape_ptr=0;
+p->in_escape=0;
+}
+
+void ansi_parse_deckey(ANSI *a,VT102 *v)
+{
+ANSI_Parser *p=&a->parser;
+if ((p->escape_buf[1]!='[') && (p->escape_buf[1]!='O')) {
+       ansi_flush_escape(a,v);
+       return;
+}
+       
+if ((p->escape_buf[2]>='A') || (p->escape_buf[2]<='Z')){
+       vt102_send(v,KEY_UP+(p->escape_buf[2]-'A'));
+}else if ((p->escape_buf[2]>='a') || (p->escape_buf[2]<='z')){
+       vt102_send(v,KEY_154+(p->escape_buf[2]-'a'));
+} else {
+       ansi_flush_escape(a,v);
+       return;
+}
+p->in_escape=0;
+p->escape_ptr=0;
+}
+
+void ansi_parse_ansikey(ANSI *a,VT102 *v)
+{
+ANSI_Parser *p=&a->parser;
+
+if ((p->escape_buf[1]!='[') ||(p->escape_buf[3]!='~')) {
+       ansi_flush_escape(a,v);
+       return;
+}
+if ((p->escape_buf[2]>='0') || (p->escape_buf[2]<='9')){
+       vt102_send(v,KEY_180+(p->escape_buf[2]-'0'));
+} else {
+       ansi_flush_escape(a,v);
+       return;
+}
+
+p->in_escape=0;
+p->escape_ptr=0;
+}
+
+
+
+void ansi_parse_escape(ANSI *a,VT102 *v)
+{
+ANSI_Parser *p=&a->parser;
+switch(p->escape_ptr) {
+case 0:
+case 1:
+       return;
+case 2:
+       switch (p->escape_buf[1]) {
+       case '[':
+       case 'O':
+               break;
+       default:
+               ansi_flush_escape(a,v);
+       }
+       break;
+case 3:
+       switch(p->escape_buf[1]) {
+       case 'O':
+               ansi_parse_deckey(a,v);
+               break;
+       case '[':
+               if ((p->escape_buf[2]>='A') &&
+               (p->escape_buf[2]<='Z')) 
+                       ansi_parse_deckey(a,v);
+               break;
+       default:
+               ansi_flush_escape(a,v);
+       }
+       break;
+case 4:
+       switch(p->escape_buf[1]) {
+       case '[':
+               ansi_parse_ansikey(a,v);
+               break;
+       default:
+               ansi_flush_escape(a,v);
+       }
+       break;
+case 5:
+       ansi_flush_escape(a,v);
+}
+}
+
+
+void ansi_check_escape(ANSI *a,VT102 *v)
+{
+ANSI_Parser *p=&a->parser;
+       struct timeval now,diff;
+       gettimeofday(&now,NULL);
+       timersub(&now,&p->last_escape,&diff);
+
+#if 0
+fprintf(stderr,"ie %d tl %d.%06d eb %d\n",
+       p->in_escape,diff.tv_sec,diff.tv_usec,p->escape_ptr);
+#endif
+
+if (!p->in_escape) return;
+
+
+       /*Time up?*/
+       if (diff.tv_sec || (diff.tv_usec > ANSI_ESCAPE_TIMEOUT))
+               ansi_flush_escape(a,v);
+
+}
+
 
 void ansi_parse_char(ANSI *a,int c,VT102 *v)
 {
-vt102_send(v,c);
+ANSI_Parser *p=&a->parser;
+
+
+/*See if it's time to flush the escape*/
+ansi_check_escape(a,v);
+
+if (c==033) {
+       if (p->in_escape) 
+               ansi_flush_escape(a,v);
+
+       p->in_escape++;
+       p->escape_ptr=0;
+       gettimeofday(&p->last_escape,NULL);
+}
+
+if (p->in_escape) {
+       p->escape_buf[p->escape_ptr++]=c;
+       ansi_parse_escape(a,v);
+} else {
+       vt102_send(v,c);
+}
+
 }
 
 void ansi_parse(ANSI *a,char *buf,int len,VT102 *v)
@@ -357,12 +538,15 @@ int ansi_dispatch(ANSI *a,VT102 *v)
 char buf[1024];
 int red;
 
-red=read(a.fd,buf,sizeof(buf));
-if (red<0) return -1;
-if (!red) return -1;
+ansi_check_escape(a,v);
+
+
+red=ansi_read(a,buf,sizeof(buf));
+if (red<=0) return red;
+
+if (*buf==3) return -1;
 
 ansi_parse(a,buf,red,v);
 
 return 0;
 }
-int