chiark / gitweb /
*** empty log message ***
[sympathy.git] / src / ansi.c
index bdc3a56ce899911288267b2352c042f39e75b9d2..16d9970194bb634c95b67692deee2952dbbd8c90 100644 (file)
@@ -10,6 +10,15 @@ 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 ***
+ *
+ * Revision 1.6  2008/02/06 17:53:28  james
+ * *** empty log message ***
+ *
  * Revision 1.5  2008/02/06 15:53:22  james
  * *** empty log message ***
  *
@@ -28,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);
 }
 
@@ -216,6 +261,7 @@ ansi_set_attr (ANSI * a, int attr)
         }
       else
         {
+          ansi_write (a, "\033[21m", 5);
           ansi_write (a, "\033[22m", 5);
         }
     }
@@ -267,8 +313,7 @@ ansi_draw (ANSI * a, CRT * c)
 {
   CRT_Pos p;
   int o;
-
-  ansi_showhide_cursor (a, 1);
+  int hidden_cursor = 0;
 
   for (p.y = 0; p.y < CRT_ROWS; ++p.y)
     {
@@ -281,6 +326,7 @@ ansi_draw (ANSI * a, CRT * c)
             continue;
           if (crt_ca_cmp (a->crt.screen[o], c->screen[o]))
             {
+              ansi_showhide_cursor (a, 1);
               a->crt.screen[o] = c->screen[o];
 
               ansi_move (a, p);
@@ -289,6 +335,28 @@ ansi_draw (ANSI * a, CRT * c)
         }
     }
 
+
+  if ((CRT_COLS > a->size.x) || (CRT_ROWS > a->size.y))
+    {
+      char msg[] = "Window is too small";
+      p.x = 0;
+      p.y = 0;
+
+      ansi_showhide_cursor (a, 1);
+      ansi_set_attr (a, CRT_ATTR_REVERSE);
+      ansi_move (a, p);
+
+      ansi_write (a, msg, sizeof (msg));
+      a->pos.x = ANSI_INVAL;
+    }
+
+
+  if ((c->pos.x >= a->size.x) || (c->pos.y >= a->size.y))
+    {
+      ansi_showhide_cursor (a, 1);
+      return;
+    }
+
   a->crt.pos = c->pos;
   ansi_move (a, a->crt.pos);
 
@@ -309,5 +377,176 @@ 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)
+{
+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)
+{
+while (len--) 
+ansi_parse_char(a,*(buf++),v);
+}
+
+int ansi_dispatch(ANSI *a,VT102 *v)
+{
+char buf[1024];
+int red;
+
+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;
+}