#include "ufk.h"
#include "uftcap.h"

#define TERMCAP_FILE   "/etc/termcap"

#define ESCAPE    255  /* cursor control escape */
#define XY        1    /* bit for row or column, on->column */
#define BIAS      2    /* bit for bias */
#define SUB       4    /* subtract from maximum */
#define BCD       8    /* bit for BCD */
#define ASCII     16   /* bit to send position in ASCII */
#define NIL       0    /* Null pointer */
#define DIRSIZE   32   /* Terminal Directory Size */
#define NUMCAP    62   /* Number of capabilities */
#define DATABYTES 4    /* Number of bytes before pointers */

typedef int BOOLEAN;

struct ttycap cap;              /* Terminal capabilities */

int nrows;                      /* Number of rows on screen */
int ncols;                      /* Number of columns on screen */
int p_l_row;                    /* Physical last row */
int p_l_column;                 /* Physical last column */
int last_row;                   /* Last row number (0 origin) */
int last_column;                /* Last column number (0 origin) */
int delay;                      /* Screen settle time in seconds */
int cu_size;                    /* Size of cursor up string */
int cd_size;                    /* Size of cursor down string */
int cl_size;                    /* Size of cursor left string */
int cr_size;                    /* Size of cursor right string */
int hm_size;                    /* Size of home up string */
int row;                        /* Current row number (0 origin) */
int column;                     /* Current column number (0 origin) */

clreol(x,y)
int x;
int y;
{
   if (screen && !remote && !nooutput)
   {
      if (x >= 0)
         posit(x,y);
      fputs(cap.c_blank,stdout);
   }
}

clear_screen()     /* Clear screen */
{
   if (screen && !remote && !nooutput)
   {
      fputs(cap.c_clear,stdout);
      if (delay != 0)
         sleep(delay);
      row = column = 0;
   }
}

curs_on()
{
   if ((cap.c_curon != NIL) && !nooutput)
      fputs(cap.c_curon, stdout);
}

curs_off()
{
   if ((cap.c_curoff != NIL) && !nooutput)
      fputs(cap.c_curoff, stdout);
}

background()
{
   if ((cap.c_backg != NIL) && !nooutput)
      fputs(cap.c_backg, stdout);
}

foreground()
{
   if ((cap.c_foreg != NIL) && !nooutput)
      fputs(cap.c_foreg, stdout);
}

posit(x,y)       /* Move cursor to specified position */
int    x;  /* column */
int    y;  /* row */
{
   int     v;
   char    *c_ptr;
   char    ch;

   if (((c_ptr = cap.c_pos) != NIL) && screen && !remote && !nooutput)
   {                                /* can position cursor */
      if (x > last_column)
         x = last_column;           /* truncate x */
      if (y > last_row)
         y = last_row;              /* truncate y */
      while ((v = (*c_ptr++) & 0xff) != NULL)
      {
         if (v!=ESCAPE)
            putchar(v);
         else if((v = (*c_ptr++) & 0xff) != NULL)
         {
            ch = ((v & XY) == 0) ?
               ((v & SUB) == 0 ? y : p_l_row - y) :
               ((v & SUB) == 0 ? x : p_l_column - x);
            if ((v & BIAS) != 0)
               ch += (unsigned)*c_ptr++;
            if ((v & BCD) != 0)
            {
               ch = (unsigned)ch / 10 << 4 | (unsigned)ch % 10;
               putchar(ch);
            }
            else if ((v & ASCII) != 0)
            {
               putchar((unsigned)ch / 10 + '0');
               putchar((unsigned)ch % 10 + '0');
            }
            else putchar(ch);
         }
      }
      column = x;
      row = y;
   }
}

BOOLEAN terminit()                    /* Initialize terminal */
{
   if (!termcap(&cap))
      return FALSE;
   if (cap.c_pos == NIL)
      return FALSE;                   /* Cursor positioning required */
   nrows = (int)cap.c_rows;
   ncols = (int)cap.c_cols;
   p_l_row = last_row = nrows - 1;
   p_l_column = last_column = ncols - 1;
   delay = (int)cap.c_wait;
   cu_size = strlen(cap.c_up);
   cd_size = strlen(cap.c_down);
   cl_size = strlen(cap.c_left);
   cr_size = strlen(cap.c_right);
   hm_size = strlen(cap.c_home);
   if (cap.c_init != NIL)
      fputs(cap.c_init,stdout);
   clear_screen();
   return TRUE;
}

BOOLEAN termcap(cp)              /* Get terminal capabilities */
struct ttycap *cp;
{
   char **cap_ptr;
   int  i;
   int  fd;
   int  direc[DIRSIZE];
   long lseek();
   int open(), read();

   if ((fd = open(TERMCAP_FILE,0)) == ERROR)
      return FALSE;
   if ((i = read(fd, (char *)direc, sizeof(int) * DIRSIZE)) == -1
         || i != sizeof(int) * DIRSIZE
         || (i = direc[ttyslot()]) == 0
         || lseek(fd, (long)i, 0) == -1L
         || (i = read(fd, (char *)cp, sizeof(struct ttycap))) == -1
         || i != sizeof(struct ttycap))
   {
      close(fd);
      return FALSE;
   }
   close(fd);
   cap_ptr = (char **)((char *)cp + DATABYTES);
   for (i = NUMCAP; i--; cap_ptr++)
      if (*cap_ptr != NIL)
         *cap_ptr += (unsigned)cp;
   return TRUE;
}
