/* VTDECODE.C - VT100 decoder. */

#include        <ctype.h>                       /* character typing macros */
#include        <stdio.h>                       /* standard I/O definitions */
#include        "vt.h"                          /* vt100 definitions */
#include        "conlib.h"
#include        "display.h"
#include        "chartab.h"

static int null_termid() { return(1) ;}         /* null terminal ID routine */
static void null_input(struct vt *v,char *Buf,int Len) {} ;

#if !defined(VIA_SMG)
#define CHARSET_ASCII               0
#define CHARSET_SPEC_GRAPHICS       1
#else
#define CHARSET_ASCII               SMG$M_ASCII
#define CHARSET_SPEC_GRAPHICS       SMG$M_SPECIAL_GRAPHICS
#endif

void (*scroll_rtn)(int row) = NULL ;
#define CTL(_c)  ((_c)-'@')                     /* control character */

#if defined(VIA_SMG) || defined(_CONSOLE)
#define PUTCHAR(_x)  (*o++ = (_x))
#define DUMPBUF if (o!=outbuf) smg_write(v,outbuf,&o)
#if defined(_CONSOLE)
#define smg$return_cursor_pos(d,r,c) CurPos(r,c)
#define smg$set_cursor_abs(d,r,c) SetPos(r,c)
#endif
#else
#define PUTCHAR(_x)  putchar(_x)
#define DUMPBUF
#endif

#define EXTRA_ROWS 0
#if defined(_CONSOLE)
static HANDLE  hStdout ;
#undef EXTRA_ROWS
#define EXTRA_ROWS 1
#endif
#if defined(VIA_SMG) || defined(_CONSOLE)
static char    outbuf[VT_OUTBUF_SIZE] ;        /* local output buffer */
static char    *o = outbuf ;                   /* -> output buffer */
#endif

#if defined(VIA_SMG)

/* SMG_WRITE.C - Write buffer via SMG. */

smg_write(v,outbuf,o)

        struct vt_info *v ;                     /* -> vt info */
        char    *outbuf ;                       /* output buffer */
        char    **o ;                           /* next avail. pos in outbuf */
{
        struct  dsc$descriptor outbuf_desc ;    /* descriptor */

        outbuf_desc.dsc$w_length = (*o)-outbuf ;        /* set length */
        if (outbuf_desc.dsc$w_length > 0)  {    /* if something to write */
          outbuf_desc.dsc$b_dtype = DSC$K_DTYPE_T ;     /* text */
          outbuf_desc.dsc$b_class = DSC$K_CLASS_S ;     /* static */
          outbuf_desc.dsc$a_pointer = outbuf ;  /* pointer */
          smg$begin_display_update(&(v->display_id)) ;
          smg$put_chars(                        /* write the characters */
                        &(v->display_id),       /* display id */
                        &outbuf_desc,           /* buffer */
                        0,0,                    /* start row, column */
                        0,                      /* flags */
                        &(v->rendition),        /* rendition set */
                        &0,                     /* rendition complement */
                        &(v->charset[v->cs_index])      /* character set */
                        ) ;
          smg$end_display_update(&(v->display_id)) ;
        }
        *o = outbuf ;                           /* reset pointer */
}
#endif

#if defined(_CONSOLE)

int
smg_write(
    struct vt_info *v,                     /* -> vt info */
    char    *outbuf,                       /* output buffer */
    char    **o                            /* next avail. pos in outbuf */
){
    DWORD   Len ;

    WriteFile(hStdout,outbuf,*o-outbuf,&Len,NULL) ;
    *o = outbuf ;
    return(1) ;
}

int
CurPos(
    int *row,
    int *col
){
    CONSOLE_SCREEN_BUFFER_INFO ScreenInfo ;

    GetConsoleScreenBufferInfo(hStdout,&ScreenInfo) ;
    *row = ScreenInfo.dwCursorPosition.Y+1 ;
    *col = ScreenInfo.dwCursorPosition.X+1 ;
    return(1) ;
}

int
ScreenSize(
    int *row,
    int *col
){
    CONSOLE_SCREEN_BUFFER_INFO ScreenInfo ;

    GetConsoleScreenBufferInfo(hStdout,&ScreenInfo) ;
    *row = ScreenInfo.dwSize.Y ;
    *col = ScreenInfo.dwSize.X ;
    return(1) ;
}

int
SetPos(
    int *row,
    int *col
){
    COORD   CursorPos ;

    CursorPos.X = *col-1 ;
    CursorPos.Y = *row-1 ;
    return(SetConsoleCursorPosition(hStdout,CursorPos)) ;
}

#endif

/* VT_RCVALID.C - Make sure row/column are valid. */

void
vt_rcvalid(
        struct vt_info *v                       /* -> VT info */
){
        if (v->row < 1)  v->row = 1 ;
        if (v->row > (v->rows+EXTRA_ROWS))  v->row = v->rows ;
        if (v->col < 1)  v->col = 1 ;
        if (v->col > v->wcols)  v->col = v->wcols ;
}

/* VT_LINEFEED.C - Do a linefeed. */

void
vt_linefeed(
        struct vt_info *v                       /* -> vt info */
){
#if defined(VIA_SMG) || defined(_CONSOLE)
        smg$return_cursor_pos(&did,&(v->row),&(v->col)) ;
        if (v->row == v->scr_bottom)  {  /* if btm of scroll region */
#if defined(VIA_SMG)
            smg$insert_line(            /* insert a line */
                &did,          /* display id */
                &(v->row),     /* at current row */
                0,             /* character string */
                &SMG$M_UP      /* scrolling direction */
            ) ;
#endif
#if defined(_CONSOLE)
            if (scroll_rtn != NULL)  {
                (*scroll_rtn)(v->scr_top) ; /* inform scroll routine */
            }
            if (v->scr_bottom != v->rows)  {
                scroll_up(1,v->scr_top,v->wcols,v->scr_bottom,1) ;
            }
            else  {
                PUTCHAR('\n') ;
            }
#endif
        }
        else  {
            v->row += 1 ;               /* increment the row */
        }
        smg$set_cursor_abs(&did,&(v->row),&(v->col)) ;
#else
        if (++v->row > v->scr_bottom)  {      /* if already at end */
            v->row = v->scr_bottom ;            /* leave it there */
        }
#endif
}

/* VT_SETARG.C - Set up defaults for arguments. */

void
vt_setarg(
        struct vt_info *v,              /* -> vt info */
        int     n                       /* # of arguments */
){
        int     i ;                     /* loop control */

        for (i=v->arg+1 ; i<n ; i++)  { /* for each missing one */
          v->args[i] = 1 ;              /* set default value */
        }
        for (i=0 ; i<=v->arg ; i++)  {  /* for each specified one */
          if (v->args[i] == 0)  {       /* if it's zero */
            v->args[i] = 1 ;            /* make it one */
          }
        }
}

/* VT_RESET.C - Reset the terminal. */

void
vt_reset(
        struct vt_info *v                       /* -> vt info */
){
        for (v->row=1 ; v->row<=VT_ROWS ; v->row++)  {
          for (v->col=1 ; v->col<=VT_COLS ; v->col++)  {
            v->screen[v->row][v->col] = ' ' ;           /* blank it out */
          }
        }
        for (v->col=0 ; v->col<sizeof v->tabs ; v->col++)  {
          if (((v->col-1)&7) == 0)  {   /* if this is a tab stop */
            v->tabs[v->col] = 1 ;       /* set the tab */
          }
          else  {
            v->tabs[v->col] = 0 ;       /* clear the tab */
          }
        }
        v->row = v->col = 1 ;           /* reset cursor to upper left */
        v->save_row = v->save_col = 1 ; /*  and saved copy too */
        v->altchar = 0 ;                /* no alternate charset */
        v->state = VS_CHAR ;            /* character mode */
        v->wide_mode = RESET ;          /* reset wide mode */
        if (v->termid == 0)  {          /* if no terminal id set up yet */
          v->termid = null_termid ;     /* null terminal identifier */
        }
        if (v->tty_input == 0)  {       /* no tty input routine */
            v->tty_input = null_input ;
        }
        v->charset[G0] = CHARSET_ASCII ;  /* select default G0 character set */
        v->charset[G1] = CHARSET_SPEC_GRAPHICS ;  /*  and G1 character set */
        v->cs_index = G0 ;              /* map G0 into GL */

#if defined(VIA_SMG)
        smg$set_display_scroll_region(&(v->display_id),&1,&v->rows) ;
#endif

#if defined(_CONSOLE)
        ScreenSize(&v->rows,&v->wcols) ;
#endif
        v->scr_top = 1 ;                /* reset top of scrolling region */
        v->scr_bottom = v->rows ;       /*  and bottom */
}

/* VT_TAB.C - Move to next tab stop. */

static void
vt_tab(
        struct  vt_info *v              /* -> VT info */
){
        int     i ;                     /* possible new column */

        for (i=v->col+1 ; i<v->wcols ; i++)  {/* through remainder of line */
          if (v->tabs[i])  {            /* if this is a tab stop */
            v->col = i ;                /* set new column */
            break ;                     /*  and bail */
          }
        }
}

#ifdef SCREEN_ARRAY

/* VT_FIELD.C - Add a field to be watched. */

vt_field(r,lc,rc,routine)

        int     r ;                     /* row (1-n) */
        int     lc ;                    /* leftmost column (1-n) */
        int     rc ;                    /* rightmost column (1-n) */
        int     (*routine)() ;          /* routine to be called */
{
        struct  field *f ;              /* -> new field info */

        f = (struct field *) malloc(sizeof (struct field)) ;    /* make one */
        if (f == NULL)  {               /* if didn't get one */
          return(0) ;                   /* say failure */
        }
        f -> row = r ;                  /* set row */
        f -> lcol = lc ;                /*  and left column */
        f -> rcol = rc ;                /*   and right column */
        f -> routine = routine ;        /*    and routine */

        if (first_field == NULL)  {     /* if no fields yet */
          first_field = f ;             /* this is first one */
          last_field = f ;              /*  and last one too */
        }
        else  {
          last_field -> next = f ;      /* make this new last one */
        }
        f -> next = NULL ;              /* terminate list */
        return(1) ;                     /* success */
}

#endif

/* VTDECODE.C - VT decoder. */

vtdecode(
#if defined(VIA_SMG)
w,
#endif
v,buffer,length)
#if defined(VIA_SMG)
        struct dm_window *w ;                   /* -> window */
#endif
        struct vt_info *v ;                     /* -> VT information */
        unsigned char *buffer ;                 /* -> buffer */
        int     length ;                        /* length */
{
        unsigned char ch ;                      /* current character */
        int     i ;                             /* character index */
#if defined(SCREEN_ARRAY)
        int     j ;
        struct  field *f ;                      /* -> field */
#endif
        int     *rc ;                           /* -> row/column */
        int     inc ;                           /* row/column inc/dec */
        int     max ;                           /* row/column max value */
#if defined(VIA_SMG) || defined(_CONSOLE)
        int     did = v->display_id ;           /* SMG display ID */
        int     mode ;                          /* general mode info */
#endif

        if (!(v->initialized))  {               /* if not initialized */
#if defined(_CONSOLE)
          hStdout = GetStdHandle(STD_OUTPUT_HANDLE) ;
#endif
          vt_reset(v) ;                         /* initialize it */
          v->initialized = 1 ;                  /* flag it's initialized */
        }
        if (length == 0)  length = strlen(buffer) ;
#if defined(FOOBAR)
        if (v->state == VS_CHAR &&
            v->scr_bottom == v->rows &&
            strchr(buffer,ESC) == NULL)  {
            DWORD nb ;
            WriteFile(hStdout,buffer,length,&nb,NULL) ;
            return(1) ;
        }
#endif
        for (i=0 ; i<length ; i++)  {           /* for each character */
          ch = buffer[i] ;                      /* grab the character */
          if (v->state != VS_CHAR && (ch < ' ') && (ch != ESC))  {
            continue ;                          /* ignore control in escseq */
          }
          switch (v->state)  {          /* dispatch according to state */
/*
 * VS_CHAR - normal characters.
 *
 * includes processing for control characters as well as printables.
 * for printables, check field table for hit, and call associated routine.
 */
            case VS_CHAR:  {                    /* normal character */
output_char: ;
              switch (ch)  {                    /* dispatch on character */
                case ESC:  {                    /* ESCape */
                  DUMPBUF ;                     /* dump the buffer */
#if defined(_CONSOLE)
                  smg$return_cursor_pos(&did,&(v->row),&(v->col)) ;
#endif
                  v->state = VS_ESCSEQ ;        /* change state */
                  break ;
                }
                case CTL('N'):  {               /* Shift In */
                  v->altchar = 1 ;              /* remember in alternate set */
                  DUMPBUF ;                     /* dump buffer */
                  v->cs_index = G1 ;            /* select G1 */
                  break ;
                }
                case CTL('O'):  {               /* Shift Out */
                  v->altchar = 0 ;              /* remember in normal set */
                  DUMPBUF ;                     /* dump buffer */
                  v->cs_index = G0 ;            /* select G0 */
                  break ;
                }
                case CTL('G'):  {               /* Control-G (bell) */
#if defined(_CONSOLE)
                    beep() ;
#endif
                    break ;
                }
                case CTL('H'):                  /* Control-H (backspace) */
                case CTL('I'):                  /* Tab */
                case CTL('K'):                  /* Vertical Tab */
                case CTL('L'):  {               /* Form Feed */
                  PUTCHAR(ch) ;                 /* handle it */
                  break ;
                }
                case CTL('J'):  {               /* linefeed */
                  DUMPBUF ;                     /* dump the buffer */
                  vt_linefeed(v) ;
#if defined(LF_ONLY)
                  /*
                   * fall through to do a CR - meant to be used from C printf
                   * output and the like.
                   */
                  break ;
#endif
                }
                case CTL('M'):  {               /* Carriage Return */
#if defined(VIA_SMG) || defined(_CONSOLE)
                  DUMPBUF ;                     /* dump the buffer */
                  smg$return_cursor_pos(&did,&(v->row),&(v->col)) ;
                  v->col = 1 ;                  /* reset column */
                  smg$set_cursor_abs(&did,&(v->row),&(v->col)) ;
#else
                  v->col = 1 ;                  /* reset column */
#endif
                  break ;                       /* we done */
                }
                default:  {                     /* normal character */
                  if (ch < ' ')  {              /* if control character */
                    continue ;                  /* then ignore it */
                  }
#if 1
                  if (v->charset[v->cs_index] == CHARSET_SPEC_GRAPHICS)  {
                      ch = altchartab[ch&0x7f] ;
                  }
#endif
#ifdef VT_FIELDS
                  for (f=first_field ; f != NULL ; f=f->next)  {
                    if (f->row == v->row)  {    /* if row matches */
                      if ((v->col >= f->lcol) && (v->col <= f->rcol))  {
                        (*(f->routine))(ch,v->row,v->col,screen) ;
                      }
                    }
                  }
#endif
#ifdef SCREEN_ARRAY
                  screen[v->row][v->col] = ch ; /* stuff it */
                  if (++v->col > VT_COLS)  {    /* if wrappage */
                    v->col = 1 ;                /* left margin */
                    if (++v->row > VT_ROWS)  {  /* if scroll time */
                      v->row = VT_ROWS ;        /* remain at bottom */
                    }
                  }
#endif
                  PUTCHAR(ch) ;                 /* put it out */
                }
              }
              break ;
            }
/*
 * VS_ESCSEQ - processing an escape sequence.
 */
            case VS_ESCSEQ:  {
/*
 * first check for ESC-x sequences - most of which we just ignore.
 */
              if (v->last_ch == ESC)  {         /* if just after an escape */
                switch (ch)  {                  /* dispatch on character */
                  case '7':  {                  /* save cursor */
#if defined(VIA_SMG) || defined(_CONSOLE)
                    smg$return_cursor_pos(&did,&(v->save_row),&(v->save_col)) ;
#else
                    v -> save_row = v->row ;    /* save row */
                    v -> save_col = v->col ;    /*  and column */
#endif
                    break ;
                  }
                  case '8':  {                  /* restore cursor */
                    v -> row = v->save_row ;    /* set row */
                    v -> col = v->save_col ;    /*  and column */
#if defined(VIA_SMG) || defined(_CONSOLE)
                    goto set_cursor_abs ;       /* fix the cursor */
#else
                    break ;
#endif
                  }
#if defined(VIA_SMG)
                  case '=':  {                  /* numeric keypad mode */
                    write_tty("\033=",2) ;      /* send it through */
                    break ;
                  }
                  case '>':  {                  /* application keypad mode */
                    write_tty("\033>",2) ;      /* send it through */
                    break ;
                  }
#endif
                  case 'E':  {                  /* ESC-E - CR-LF */
                    v->col = 1 ;                /* go to left margin */
                  }
                  case 'D':  {                  /* ESC-D - linefeed */
                    vt_linefeed(v) ;            /* do linefeed */
                    break ;
                  }
                  case 'H':  {                  /* ESC-H - set tab */
                    v->tabs[v->col] = 1 ;       /* set the tab */
                    break ;
                  }
                  case 'M':  {                  /* ESC-M - reverse index */
ReverseIndex: ;
#if defined(VIA_SMG) || defined(_CONSOLE)
                    smg$return_cursor_pos(&did,&(v->row),&(v->col)) ;
                    v->col = 1 ;                /* column 1 */
                    if (v->row == v->scr_top)  {  /* if top of scroll region */
#if defined(VIA_SMG)
                      smg$insert_line(          /* insert a line */
                                 &did,          /* display id */
                                 &(v->row),     /* at current row */
                                 0,             /* character string */
                                 &SMG$M_DOWN    /* scrolling direction */
                                 ) ;
#endif
#if defined(_CONSOLE)
                      scroll_down(1,v->scr_top,v->wcols,v->scr_bottom,1) ;
#endif
                    }
                    else  {
                      v->row -= 1 ;             /* decrement the row */
                    }
                    goto set_cursor_abs ;       /* restore the cursor */
#else
                    if (--v->row < 1)  {        /* if already at top */
                      v->row = 1 ;              /* leave it there */
                    }
                    v->col = 1 ;                /* fix column */
#endif
                    break ;
                  }
                  case 'Z':  {                  /* identify terminal */
                    (*v->termid)(               /* execute ID handler */
#if defined(VIA_SMG)
                        w,                      /* -> window */
#endif
                        v,                      /* -> VT info */
                        VTID_Z                  /* type of ID request */
                        ) ;
                    break ;
                  }
                  case 'c':  {                  /* reset terminal */
                    vt_reset(v) ;               /* do it */
                    break ;
                  }
                  case CSI:  {                  /* Control Seq. Introducer */
                    v->arg = 0 ;                /* reset arg index */
                    v->args[0] = 0 ;            /* reset it */
                    v->last_ch = CSI ;          /* last was CSI */
                    continue ;                  /* handle more stuff */
                  }
                  case '(':  {                  /* G0 designator */
                    v->args[0] = G0 ;           /* remember charset */
                    goto set_charset_state ;    /* set vt charset state */
                  }
                  case ')':  {                  /* G1 designator */
                    v->args[0] = G1 ;           /* remember charset */
                    goto set_charset_state ;    /* set vt charset state */
                  }
                  case '*':  {                  /* G2 designator */
                    v->args[0] = G2 ;           /* remember charset */
                    goto set_charset_state ;    /* set vt charset state */
                  }
                  case '+':  {                  /* G3 designator */
                    v->args[0] = G3 ;           /* remember charset */
set_charset_state: ;
                    v->state = VS_CHARSET ;     /* come back on next char */
                    continue ;                  /* wait for it */
                  }
                }
                v->state = VS_CHAR ;            /* revert to character mode */
              }
              else  {                           /* not just after escape */
/*
 * if we get here, then we are processing something in the standard form
 * of ESC-CSI...
 */
                if (isdigit(ch))  {             /* if it's a digit */
                  v->args[v->arg] = v->args[v->arg]*10+(ch-'0') ;
                  continue ;
                }
                else  {
                  switch (ch)  {                /* dispatch on char */
                    case ESC:  {                /* another sequence */
                      goto output_char ;        /* abort current one for now */
                    }
                    case '?':  {                /* question mark */
                      if (v->last_ch == CSI)  { /* if was ESC-CSI */
                        v -> state = VS_CSIQUES ;       /* ESC-CSI-? */
                      }
                      continue ;                /* handle arguments */
                    }
                    case ';':  {                /* argument separator */
                      if (++(v->arg) >= VT_NARGS)  {    /* if too many */
                        v->arg = VT_NARGS-1 ;   /* reset to end of list */
                      }
                      else  {                   /* in range */
                        v->args[v->arg] = 0 ;   /* clear it out */
                      }
                      continue ;
                    }
#ifdef EXTEND
                    case 'F':  {                /* ESC [ F - up, leftmar */
                      v->col = 1 ;              /* go to left margin */
                    }
#endif
                    case 'A':  {                /* ESC [ A - cursor up */
                      rc = &(v->row) ; inc = -1 ; max = v->scr_bottom ;
                      goto mod_cursor ;         /* modify cursor */
                    }
#ifdef EXTEND
                    case 'E':  {                /* ESC [ E - down, leftmar */
                      v->col = 1 ;              /* go to left margin */
                    }
#endif
                    case 'B':  {                /* ESC [ B - cursor down */
                      rc = &(v->row) ; inc = 1 ; max = v->scr_bottom ;
                      goto mod_cursor ;         /* modify cursor */
                    }
                    case 'C':  {                /* ESC [ C - cursor right */
                      rc = &(v->col) ; inc = 1 ; max = v->wcols ;
                      goto mod_cursor ;         /* modify cursor */
                    }
                    case 'D':  {                /* ESC [ D - cursor left */
                      rc = &(v->col) ; inc = -1 ; max = v->wcols ;
/*
 * here to modify the cursor and keep it in range.
 */
mod_cursor:           if (v->args[0] != 0)  {   /* if arg was non-zero */
                        inc *= v->args[0] ;     /* get true inc/decrement */
                      }
#if defined(VIA_SMG) || defined(_CONSOLE)
                      smg$return_cursor_pos(&did,&(v->row),&(v->col)) ;
#endif
                      *rc += inc ;              /* bump the coordinate */
                      if (*rc < 1)  {           /* if too low */
                        *rc = 1 ;               /* fix it */
                      }
                      else if (*rc > max)  {    /* if too high */
                        *rc = max ;             /* fix it */
                      }
#if defined(VIA_SMG) || defined(_CONSOLE)
                      goto set_cursor_abs ;     /* set it */
#else
                      break ;
#endif
                    }
                    case 'f':                   /* ESC [ f - HVP */
                    case 'H':  {                /* ESC [ H - CUP */
                      vt_setarg(v,2) ;          /* set up for two args */
                      if (v->args[0] > v->rows)  v->args[0] = v->rows ;
                      if (v->args[1] > v->wcols)  v->args[1] = v->wcols ;
                      v->row = v->args[0] ;     /* set row */
                      v->col = v->args[1] ;     /*  and column */
                      vt_rcvalid(v) ;           /* make sure valid */
#if defined(VIA_SMG) || defined(_CONSOLE)
set_cursor_abs: ;
                      smg$set_cursor_abs(&did,&(v->row),&(v->col)) ;
#endif
                      break ;
                    }
                    case 'J':  {                /* ESC [ J - Erase */
                      v->state = VS_CHAR ;      /* get into character mode */
#if defined(VIA_SMG) || defined(_CONSOLE)
                      smg$return_cursor_pos(&did,&(v->row),&(v->col)) ;
#endif
                      switch (v->args[0])  {    /* dispatch on function */
                        case 0:  {              /* cursor to end of window */
#ifdef SCREEN_ARRAY
                          memset(&screen[v->row][v->col],' ',
                            &screen[VT_ROWS][0]-
                            &screen[v->row][v->col]) ;
#endif
#if defined(VIA_SMG)
                          smg$erase_display(&did,&(v->row),&(v->col)) ;
#endif
#if defined(_CONSOLE)
                        { int r ;
                          clreol() ;
                          for (r=v->row+1 ; r<=v->rows ; r++)  {
                              gotoxy(1,r) ;
                              clreol() ;
                          }
                          goto set_cursor_abs ;
                        }
#else
                          break ;
#endif
                        }
                        case 1:  {              /* beg. window -> cursor */
#ifdef SCREEN_ARRAY
                          memset(screen,' ',
                            &screen[v->row][v->col]-&screen[0][0]) ;
#endif
#if defined(VIA_SMG)
                          smg$erase_display(&did,&1,&1,&(v->row),&(v->col)) ;
#endif
#if defined(_CONSOLE)
                        { int r ;
                          for (r=1 ; r<v->row ; r++)  {
                              gotoxy(1,r) ;
                              clreol() ;
                          }
                          gotoxy(v->col,v->row) ;
                          clrbol() ;
                        }
#endif                          
                          break ;
                        }
                        case 2:  {              /* entire window */
#if defined(VIA_SMG)
                          smg$erase_display(&did) ;     /* kill it all */
#endif
#ifdef SCREEN_ARRAY
                          memset(v->screen,' ',sizeof v->screen) ;
#endif
#if defined(_CONSOLE)
                        { int r ;
                          for (r=1 ; r<=v->rows ; r++)  {
                              gotoxy(1,r) ;
                              clreol() ;
                          }
                          goto set_cursor_abs ;
                        }
#endif
                          break ;
                        }
                      }
                      break ;
                    }
                    case 'K':  {                /* ESC [ K - Erase in line */
                      v->state = VS_CHAR ;      /* get into character mode */
#if defined(VIA_SMG)
                      smg$return_cursor_pos(&did,&(v->row),&(v->col)) ;
#endif
                      switch (v->args[0])  {    /* dispatch on function */
                        case 0:  {              /* cursor to end of line */
#if defined(VIA_SMG)
                          smg$erase_line(&did) ;
                          goto set_cursor_abs ; /* update the cursor */
#else
#if defined(_CONSOLE)
                          clreol() ;
#endif
                          break ;
#endif
                        }
                        case 1:  {              /* beg. line -> cursor */
#if defined(VIA_SMG)
                          smg$erase_display(&did,&(v->row),&1,&(v->row),
                                      &(v->col)) ;
                          goto set_cursor_abs ; /* update the cursor */
#else
#if defined(_CONSOLE)
                          clrbol() ;
#endif
                          break ;
#endif
                        }
                        case 2:  {              /* entire line */
#if defined(VIA_SMG)
                          smg$erase_line(&did) ;        /* kill the line */
                          goto set_cursor_abs ; /* update the cursor */
#else
#if defined(_CONSOLE)
                          gotoxy(1,v->row) ;
                          clreol() ;
                          goto set_cursor_abs ;
#else
                          break ;
#endif
#endif
                        }
                      }
                      break ;
                    }
                    case 'L':  {
                        goto ReverseIndex ;
                    }
                    case 'm':  {                /* set attributes */
#if defined(VIA_SMG)
                      for (j=0 ; j<=v->arg ; j++)  {
                        switch (v->args[j])  {  /* dispatch on attribute */
                          case 0:  {            /* 0 - clear to normal */
                            v->rendition = 0 ;  /* zap it */
                            break ;
                          }
                          case 1:  {            /* 1 - bold */
                            v->rendition |= SMG$M_BOLD ;        /* set it */
                            break ;
                          }
                          case 4:  {            /* 4 - underline */
                            v->rendition |= SMG$M_UNDERLINE ;   /* set it */
                            break ;
                          }
                          case 5:  {            /* 5 - blinking */
                            v->rendition |= SMG$M_BLINK ;       /* set it */
                            break ;
                          }
                          case 7:  {            /* 7 - inverse video */
                            v->rendition |= SMG$M_REVERSE ;     /* set it */
                            break ;
                          }
                          default:  {           /* undefined attribute */
                            break ;
                          }
                        }
                      }
#endif
#if defined(_CONSOLE)
                      switch (v->args[0])  {
                        case 0:  {
                            normvideo() ;
                            break ;
                        }
                        case 7:  {
                            textattr(BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE) ;
                            break ;
                        }
                      }
#endif
                      break ;
                    }
                    case 'n':  {
                        switch (v->args[0])  {  /* dispatch on function */
                            case 6:  {          /* $[6n - screen size */
                                char    sBuf[32] ;
                                (*v->tty_input)(v->pvInputParam,sBuf,
                                    sprintf(sBuf,"\033[%d;%dR",v->rows,v->cols)) ;

                                break ;
                            }
                        }
                        break ;
                    }
                    case 'r':  {                /* define scrolling region */
                      if (v->args[0] == 0)  {   /* if no first arg */
                        v -> args[0] = 1 ;      /* default to top */
                      }
                      if (v->args[1] == 0)  {   /* if no second arg */
                        v -> args[1] = v->rows ; /* default to bottom */
                      }
                      v->row = v->col = 1 ;     /* home the cursor */
                      v->scr_top = v->args[0] ; /* remember top of it */
                      v->scr_bottom = v->args[1] ;      /*  and bottom */
#if defined(VIA_SMG)
                      smg$set_display_scroll_region(&did,&(v->args[0]),
                                        &(v->args[1])) ;
                      goto set_cursor_abs ;     /* set the cursor */
#else
                      break ;
#endif
                    }
                  }
                  v->state = VS_CHAR ;          /* back to character mode */
                }
              }
              break ;
            }
/*
 * VS_CHARSET - character set selector character.
 */
            case VS_CHARSET:  {                 /* character set selector */
              switch (ch)  {                    /* dispatch on charset char */
                default:                        /* bogus character */
                case 'B':  {                    /* normal characters */
                  v->charset[v->args[0]] = CHARSET_ASCII ; /* ascii mode */
                  break ;
                }
                case '0':  {                    /* graphics */
                  v->charset[v->args[0]] = CHARSET_SPEC_GRAPHICS ; /* set it */
                  break ;
                }
              }
              v->state = VS_CHAR ;              /* switch to char mode */
              break ;
            }
/*
 * VS_CSIQUES - processing ESC-CSI-? ...  sequence.
 */
            case VS_CSIQUES:  {                 /* ESC-CSI-?... sequence */
              if (isdigit(ch))  {               /* if it's a digit */
                v->args[v->arg] = v->args[v->arg]*10+(ch-'0') ;
                continue ;
              }
              switch (ch)  {                    /* dispatch on character */
                case ';':  {                    /* argument separator */
                  if (++(v->arg) >= VT_NARGS)  {        /* if too many */
                    v->arg = VT_NARGS-1 ;       /* reset to end of list */
                  }
                  else  {                       /* in range */
                    v->args[v->arg] = 0 ;       /* clear it out */
                  }
                  continue ;
                }
                case 'h':  {                    /* ESC CSI ? ... h - set mode */
                  mode = SET ;                  /* remember we're setting */
                  goto set_reset ;              /* handle it */
                }
                case 'l':  {                    /* ESC CSI ? ... h - reset */
                  mode = RESET ;                /* remember we're resetting */
set_reset: ;
                  DUMPBUF ;                     /* dump the buffer */
                  switch (v->args[0])  {        /* dispatch on parameter */
                    case 1:  {                  /* ESC[?1h/l - DECCKM */
#if defined(VIA_SMG)
                      write_tty((mode==SET ? "\033[?1h" : "\033[?1l"),5) ;
#endif
                      break ;
                    }
                    case 3:  {                  /* width setting */
#if defined(VIA_SMG)
                      if (v->wide_mode != mode)  {      /* if mode changing */
                        (*(w->display_width_change))(w,v,mode) ;
                        v->wide_mode = mode ;   /* remember new mode */
                      }
#endif
                      break ;
                    }
#if defined(VIA_SMG)
                    default:  {                 /* anything else bogus */
                      if (w->mode_change != 0)  {       /* if have handler */
                        (*(w->mode_change))(w,v,mode,v->arg+1,v->args) ;
                      }
                    }
#endif
                  }
                  break ;
                }
              } /* end of switch */
              v -> state = VS_CHAR ;            /* character mode */
            }
          }     /* end of switch */
          v->last_ch = ch ;                     /* remember last character */
        }       /* end of for */

        DUMPBUF ;                               /* dump the buffer */

        return(1) ;
}
