/*
n10.c

Device interfaces
*/

#include "tdef.h"
#include "ext.h"
#include "fns.h"
#include <ctype.h>

Term    t;      /* terminal characteristics */

int     dtab;
int     plotmode;
int     esct;

enum    { Notype = 0, Type = 1 };

static char *parse(char *s, int typeit) /* convert \0, etc to nroff driving table format */
{               /* typeit => add a type id to the front for later use */
       static char buf[100], *t, *obuf;
       int quote = 0;
       wchar_t wc;

       obuf = typeit == Type ? buf : buf+1;
#ifdef UNICODE
       if (mbtowc(&wc, s, strlen(s)) > 1) {    /* it's multibyte, */
               buf[0] = MBchar;
               strcpy(buf+1, s);
               return obuf;
       }                       /* so just hand it back */
#endif  /*UNICODE*/
       buf[0] = Troffchar;
       t = buf + 1;
       if (*s == '"') {
               s++;
               quote = 1;
       }
       for (;;) {
               if (quote && *s == '"') {
                       s++;
                       break;
               }
               if (!quote && (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\0'))
                       break;
               if (*s != '\\')
                       *t++ = *s++;
               else {
                       s++;    /* skip \\ */
                       if (isdigit(s[0]) && isdigit(s[1]) && isdigit(s[2])) {
                               *t++ = (s[0]-'0')<<6 | (s[1]-'0')<<3 | s[2]-'0';
                               s += 2;
                       } else if (isdigit(s[0])) {
                               *t++ = *s - '0';
                       } else if (*s == 'b') {
                               *t++ = '\b';
                       } else if (*s == 'n') {
                               *t++ = '\n';
                       } else if (*s == 'r') {
                               *t++ = '\r';
                       } else if (*s == 't') {
                               *t++ = '\t';
                       } else {
                               *t++ = *s;
                       }
                       s++;
               }
       }
       *t = '\0';
       return obuf;
}


static int getnrfont(FILE *fp)  /* read the nroff description file */
{
       FILE *fin;
       Chwid chtemp[NCHARS];
       static Chwid chinit;
       int i, nw, n, wid, code, type;
       char buf[100], ch[100], s1[100], s2[100], cmd[300];
       wchar_t wc;


       chinit.wid = 1;
       chinit.str = "";
       for (i = 0; i < ALPHABET; i++) {
               chtemp[i] = chinit;     /* zero out to begin with */
               chtemp[i].num = chtemp[i].code = i;     /* every alphabetic character is itself */
               chtemp[i].wid = 1;      /* default ascii widths */
       }
       skipline(fp);
       nw = ALPHABET;
       while (fgets(buf, sizeof buf, fp) != NULL) {
               sscanf(buf, "%s %s %[^\n]", ch, s1, s2);
               if (!eq(s1, "\"")) {    /* genuine new character */
                       sscanf(s1, "%d", &wid);
               } /* else it's a synonym for prev character, */
                       /* so leave previous values intact */

               /* decide what kind of alphabet it might come from */

               if (strlen(ch) == 1) {  /* it's ascii */
                       n = ch[0];      /* origin includes non-graphics */
                       chtemp[n].num = ch[0];
               } else if (ch[0] == '\\' && ch[1] == '0') {
                       n = strtol(ch+1, 0, 0); /* \0octal or \0xhex */
                       chtemp[n].num = n;
#ifdef UNICODE
               } else if (mbtowc(&wc, ch, strlen(ch)) > 1) {
                       chtemp[nw].num = chadd(ch, MBchar, Install);
                       n = nw;
                       nw++;
#endif  /*UNICODE*/
               } else {
                       if (strcmp(ch, "---") == 0) { /* no name */
                               sprintf(ch, "%d", code);
                               type = Number;
                       } else
                               type = Troffchar;
/* BUG in here somewhere when same character occurs twice in table */
                       chtemp[nw].num = chadd(ch, type, Install);
                       n = nw;
                       nw++;
               }
               chtemp[n].wid = wid;
               chtemp[n].str = strdupl(parse(s2, Type));
       }
       t.tfont.nchars = nw;
       t.tfont.wp = (Chwid *) malloc(nw * sizeof(Chwid));
       if (t.tfont.wp == NULL)
               return -1;
       for (i = 0; i < nw; i++)
               t.tfont.wp[i] = chtemp[i];
       return 1;
}


void n_ptinit(void)
{
       int i;
       char *p, *cp;
       char opt[50], cmd[100];
       FILE *fp;

       hmot = n_hmot;
       makem = n_makem;
       setabs = n_setabs;
       setch = n_setch;
       sethl = n_sethl;
       setht = n_setht;
       setslant = n_setslant;
       vmot = n_vmot;
       xlss = n_xlss;
       findft = n_findft;
       width = n_width;
       mchbits = n_mchbits;
       ptlead = n_ptlead;
       ptout = n_ptout;
       ptpause = n_ptpause;
       setfont = n_setfont;
       setps = n_setps;
       setwd = n_setwd;

       if ((p = getenv("NROFFTERM")) != 0)
               strcpy(devname, p);
       if (termtab[0] == 0)
               strcpy(termtab,DWBntermdir);
       if (fontdir[0] == 0)
               strcpy(fontdir, "");
       if (devname[0] == 0)
               strcpy(devname, NDEVNAME);
       pl = 11*INCH;
       po = PO;
       hyf = 0;
       ascii = 1;
       lg = 0;
       fontlab[1] = 'R';
       fontlab[2] = 'I';
       fontlab[3] = 'B';
       fontlab[4] = PAIR('B','I');
       fontlab[5] = 'D';
       bdtab[3] = 3;
       bdtab[4] = 3;

       /* hyphalg = 0; /* for testing */

       strcat(termtab, devname);
       if ((fp = fopen(termtab, "r")) == NULL) {
               ERROR "cannot open %s", termtab WARN;
               exit(-1);
       }


/* this loop isn't robust about input format errors. */
/* it assumes  name, name-value pairs..., charset */
/* god help us if we get out of sync. */

       fscanf(fp, "%s", cmd);  /* should be device name... */
       if (!is(devname) && trace)
               ERROR "wrong terminal name: saw %s, wanted %s", cmd, devname WARN;
       for (;;) {
               fscanf(fp, "%s", cmd);
               if (is("charset"))
                       break;
               fscanf(fp, " %[^\n]", opt);
               if (is("bset")) t.bset = atoi(opt);
               else if (is("breset")) t.breset = atoi(opt);
               else if (is("Hor")) t.Hor = atoi(opt);
               else if (is("Vert")) t.Vert = atoi(opt);
               else if (is("Newline")) t.Newline = atoi(opt);
               else if (is("Char")) t.Char = atoi(opt);
               else if (is("Em")) t.Em = atoi(opt);
               else if (is("Halfline")) t.Halfline = atoi(opt);
               else if (is("Adj")) t.Adj = atoi(opt);
               else if (is("twinit")) t.twinit = strdupl(parse(opt, Notype));
               else if (is("twrest")) t.twrest = strdupl(parse(opt, Notype));
               else if (is("twnl")) t.twnl = strdupl(parse(opt, Notype));
               else if (is("hlr")) t.hlr = strdupl(parse(opt, Notype));
               else if (is("hlf")) t.hlf = strdupl(parse(opt, Notype));
               else if (is("flr")) t.flr = strdupl(parse(opt, Notype));
               else if (is("bdon")) t.bdon = strdupl(parse(opt, Notype));
               else if (is("bdoff")) t.bdoff = strdupl(parse(opt, Notype));
               else if (is("iton")) t.iton = strdupl(parse(opt, Notype));
               else if (is("itoff")) t.itoff = strdupl(parse(opt, Notype));
               else if (is("ploton")) t.ploton = strdupl(parse(opt, Notype));
               else if (is("plotoff")) t.plotoff = strdupl(parse(opt, Notype));
               else if (is("up")) t.up = strdupl(parse(opt, Notype));
               else if (is("down")) t.down = strdupl(parse(opt, Notype));
               else if (is("right")) t.right = strdupl(parse(opt, Notype));
               else if (is("left")) t.left = strdupl(parse(opt, Notype));
               else
                       ERROR "bad tab.%s file, %s %s", devname, cmd, opt WARN;
       }

       getnrfont(fp);
       fclose(fp);

       sps = EM;
       ics = EM * 2;
       dtab = 8 * t.Em;
       for (i = 0; i < 16; i++)
               tabtab[i] = dtab * (i + 1);
       pl = 11 * INCH;
       po = PO;
       spacesz = SS;
       lss = lss1 = VS;
       ll = ll1 = lt = lt1 = LL;
       smnt = nfonts = 5;      /* R I B BI S */
       n_specnames();  /* install names like "hyphen", etc. */
       if (eqflg)
               t.Adj = t.Hor;
}


void n_specnames(void)
{

       int     i;

       for (i = 0; spnames[i].n; i++)
               *spnames[i].n = chadd(spnames[i].v, Troffchar, Install);
       if (c_isalnum == 0)
               c_isalnum = NROFFCHARS;
}

void twdone(void)
{
       if (!TROFF && t.twrest) {
               obufp = obuf;
               oputs(t.twrest);
               flusho();
               if (pipeflg) {
                       pclose(ptid);
               }
               restore_tty();
       }
}


void n_ptout(Tchar i)
{
       *olinep++ = i;
       if (olinep >= &oline[LNSIZE])
               olinep--;
       if (cbits(i) != '\n')
               return;
       olinep--;
       lead += dip->blss + lss - t.Newline;
       dip->blss = 0;
       esct = esc = 0;
       if (olinep > oline) {
               move();
               ptout1();
               oputs(t.twnl);
       } else {
               lead += t.Newline;
               move();
       }
       lead += dip->alss;
       dip->alss = 0;
       olinep = oline;
}


void ptout1(void)
{
       int k;
       char *codep;
       int w, j, phyw;
       Tchar *q, i;
       static int oxfont = FT; /* start off in roman */

       for (q = oline; q < olinep; q++) {
               i = *q;
               if (ismot(i)) {
                       j = absmot(i);
                       if (isnmot(i))
                               j = -j;
                       if (isvmot(i))
                               lead += j;
                       else
                               esc += j;
                       continue;
               }
               if ((k = cbits(i)) <= ' ') {
                       switch (k) {
                       case ' ': /*space*/
                               esc += t.Char;
                               break;
                       case '\033':
                       case '\007':
                       case '\016':
                       case '\017':
                               oput(k);
                               break;
                       }
                       continue;
               }
               phyw = w = t.Char * t.tfont.wp[k].wid;
               if (iszbit(i))
                       w = 0;
               if (esc || lead)
                       move();
               esct += w;
               xfont = fbits(i);
               if (xfont != oxfont) {
                       switch (oxfont) {
                       case ULFONT:    oputs(t.itoff); break;
                       case BDFONT:    oputs(t.bdoff); break;
                       case BIFONT:    oputs(t.itoff); oputs(t.bdoff); break;
                       }
                       switch (xfont) {
                       case ULFONT:
                               if (*t.iton & 0377) oputs(t.iton); break;
                       case BDFONT:
                               if (*t.bdon & 0377) oputs(t.bdon); break;
                       case BIFONT:
                               if (*t.bdon & 0377) oputs(t.bdon);
                               if (*t.iton & 0377) oputs(t.iton);
                               break;
                       }
                       oxfont = xfont;
               }
               if ((xfont == ulfont || xfont == BIFONT) && !(*t.iton & 0377)) {
                       for (j = w / t.Char; j > 0; j--)
                               oput('_');
                       for (j = w / t.Char; j > 0; j--)
                               oput('\b');
               }
               if (!(*t.bdon & 0377) && ((j = bdtab[xfont]) || xfont == BDFONT || xfont == BIFONT))
                       j++;
               else
                       j = 1;  /* number of overstrikes for bold */
               if (k < ALPHABET) {     /* ordinary ascii */
                       oput(k);
                       while (--j > 0) {
                               oput('\b');
                               oput(k);
                       }
               } else if (k >= t.tfont.nchars) {       /* BUG -- not really understood */
/* fprintf(stderr, "big char %d, name %s\n", k, chname(k)); /* */
                       oputs(chname(k)+1);     /* BUG: should separate Troffchar and MBchar... */
               } else if (t.tfont.wp[k].str == 0) {
/* fprintf(stderr, "nostr char %d, name %s\n", k, chname(k)); /* */
                       oputs(chname(k)+1);     /* BUG: should separate Troffchar and MBchar... */
               } else if (t.tfont.wp[k].str[0] == MBchar) {    /* parse() puts this on */
/* fprintf(stderr, "MBstr char %d, name %s\n", k, chname(k)); /* */
                       oputs(t.tfont.wp[k].str+1);
               } else {
                       int oj = j;
/* fprintf(stderr, "str char %d, name %s\n", k, chname(k)); /* */
                       codep = t.tfont.wp[k].str+1;    /* Troffchar by default */
                       while (*codep != 0) {
                               if (*codep & 0200) {
                                       codep = plot(codep);
                                       oput(' ');
                               } else {
                                       if (*codep == '%')      /* escape */
                                               codep++;
                                       oput(*codep);
                                       if (*codep == '\033')
                                               oput(*++codep);
                                       else if (*codep != '\b')
                                               for (j = oj; --j > 0; ) {
                                                       oput('\b');
                                                       oput(*codep);
                                               }
                                       codep++;
                               }
                       }
               }
               if (!w)
                       for (j = phyw / t.Char; j > 0; j--)
                               oput('\b');
       }
}


char *plot(char *x)
{
       int     i;
       char    *j, *k;

       oputs(t.ploton);
       k = x;
       if ((*k & 0377) == 0200)
               k++;
       for (; *k; k++) {
               if (*k == '%') {        /* quote char within plot mode */
                       oput(*++k);
               } else if (*k & 0200) {
                       if (*k & 0100) {
                               if (*k & 040)
                                       j = t.up;
                               else
                                       j = t.down;
                       } else {
                               if (*k & 040)
                                       j = t.left;
                               else
                                       j = t.right;
                       }
                       if ((i = *k & 037) == 0) {      /* 2nd 0200 turns it off */
                               ++k;
                               break;
                       }
                       while (i--)
                               oputs(j);
               } else
                       oput(*k);
       }
       oputs(t.plotoff);
       return(k);
}


void move(void)
{
       int k;
       char *i, *j;
       char *p, *q;
       int iesct, dt;

       iesct = esct;
       if (esct += esc)
               i = "\0";
       else
               i = "\n\0";
       j = t.hlf;
       p = t.right;
       q = t.down;
       if (lead) {
               if (lead < 0) {
                       lead = -lead;
                       i = t.flr;
                       /*      if(!esct)i = t.flr; else i = "\0";*/
                       j = t.hlr;
                       q = t.up;
               }
               if (*i & 0377) {
                       k = lead / t.Newline;
                       lead = lead % t.Newline;
                       while (k--)
                               oputs(i);
               }
               if (*j & 0377) {
                       k = lead / t.Halfline;
                       lead = lead % t.Halfline;
                       while (k--)
                               oputs(j);
               } else { /* no half-line forward, not at line begining */
                       k = lead / t.Newline;
                       lead = lead % t.Newline;
                       if (k > 0)
                               esc = esct;
                       i = "\n";
                       while (k--)
                               oputs(i);
               }
       }
       if (esc) {
               if (esc < 0) {
                       esc = -esc;
                       j = "\b";
                       p = t.left;
               } else {
                       j = " ";
                       if (hflg)
                               while ((dt = dtab - (iesct % dtab)) <= esc) {
                                       if (dt % t.Em)
                                               break;
                                       oput(TAB);
                                       esc -= dt;
                                       iesct += dt;
                               }
               }
               k = esc / t.Em;
               esc = esc % t.Em;
               while (k--)
                       oputs(j);
       }
       if ((*t.ploton & 0377) && (esc || lead)) {
               oputs(t.ploton);
               esc /= t.Hor;
               lead /= t.Vert;
               while (esc--)
                       oputs(p);
               while (lead--)
                       oputs(q);
               oputs(t.plotoff);
       }
       esc = lead = 0;
}


void n_ptlead(void)
{
       move();
}


void n_ptpause(void )
{
       char    junk;

       flusho();
       read(2, &junk, 1);
}