



		    kbdisp.c                        04/24/89  1040.7rew 04/24/89  1033.1      182655



/* ********************************************
   *                                          *
   * Copyright, (C) Honeywell Bull Inc., 1988 *
   *                                          *
   ******************************************** */

/* HISTORY COMMENTS:
  1) change(88-06-13,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Created.
  2) change(88-07-25,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Documentation additions only. Added header comments to all routines.
  3) change(88-08-09,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Fix references to include files; "wstdefs.h" was split into
     "wstdefs.h" and "wsttype.h" to avoid declaration clash; also,
     various constants defined to descriptive names.
  4) change(89-01-18,Lee), approve(89-01-02,MCR8043), audit(89-03-14,Flegel),
     install(89-04-24,MR12.3-1033):
     phx21233 - Converted display_char() to display_char_prim() for handling
     primitive display function; new display_char() added which calls the
     primitive and displays only when keyboard echoing is enabled. Added
     routine get_echoed_input() for extracting only echoed input from line
     buffer.
                                                   END HISTORY COMMENTS */

#include <dos.h>
#include "wstdefs.h"
#include "wstglob.h"

/*
***********************************************************************

  Routine:            DISPLAY_CHAR_STR 

  Function:
      This routine returns the display string for a character 
  displayed in line editing. In particular, it determines how 
  non-printable characters are displayed. 

  Parameters:
     (input)          ch - specifies the ASCII character being 
                          displayed 

  Returns:            a pointer to a static string containing the 
                          displayed form of the ASCII character 

**********************************************************************/

char *display_char_str(ch)
int ch;  /* character to display */
{
    static char display_string[MAX_DISPLAY_CHAR_SIZE+1];     /* string to pass back result */
    int octval;

    /* check for non-printable control character */
    if (ch < MIN_PRINTABLE_ASCII) {
        octval = ch;
        display_string[0] = '\\';
        display_string[3] = (ch & 07) + '0';
        ch >>= 3;
        display_string[2] = (ch & 07) + '0';
        ch >>= 3;
        display_string[1] = (ch & 07) + '0';
        display_string[4] = NUL_TERMINATOR;
    }

    /* check for printable ASCII */
    else if (ch < ASCII_DEL) {
        display_string[0] = ch;
        display_string[1] = NUL_TERMINATOR;
    }

    /* check for ASCII DEL character */
    else if (ch == ASCII_DEL) {
        strcpy(display_string,"\\177");
    }

    /* extended ASCII character */
    else {
        sprintf(display_string,"<%d>", ch);
    }

    return(display_string);
}


/*
***********************************************************************

  Routine:            DISPLAY_TAB_STR 

  Function:
      This routine returns a string filled with enough blanks to pad 
  to the next tab column. 

  Parameters:
     (input)          cur_col - specifies the current column on the 
                          screen to tab from 

  Returns:            a pointer to a static string containing enough 
                          spaces to pad to the next tab position on 
                          the screen 

**********************************************************************/

char *display_tab_str(cur_col)
int cur_col;  /* specifies current cursor column coordinate */
{
    static char display_string[TAB_SIZE+1];  /* result string to pass back */
    int n_spaces;                       /* number of spaces to pad */
    register int i;                     /* working index */

    /* if column exceeds right screen edge, assume wrap around to
       leftmost edge on next line
    */
    if (cur_col >= ss.right)
        n_spaces = TAB_SIZE;

    /* handle current column within screen */
    else {
        /* calculate padding to next tab column */
        n_spaces = TAB_SIZE - ((cur_col - ss.left) % TAB_SIZE);

        /* if exceeds right edge, truncate to get to leftmost
           column on next line; this handles the case where the
           screen width is not a multiple of the tab size and
           guarantees wrap around to the leftmost column
        */
        if (cur_col + n_spaces >= ss.right)
            n_spaces = ss.right - cur_col + 1;
    }

    /* initialize the string with the correct number of spaces */
    for (i = 0; i < n_spaces; i++)
        display_string[i] = ' ';

    /* null-terminate the string */
    display_string[i] = NUL_TERMINATOR;

    return(display_string);
}


/*
***********************************************************************

  Routine:            DISPLAY_CHAR_PRIM

  Function:
      This routine displays a character entered from the keyboard in 
  an appropriate representation. It keeps track of cursor position, 
  line wrap arounds and scrolling. 

  Parameters:
     (input/output)   pos - pointer to a structure which maintains 
                          cursor position information; information is 
                          updated after the display 
     (input)          ch - specifies the ASCII character to display 

  Returns:            The number of characters displayed to represent 
                          the keyboard character 

**********************************************************************/

display_char_prim(pos,ch)
CURPOS *pos;   /* pointer to structure for keeping track of cursor position */
int ch;        /* character to display */
{
    char *display_char_str();
    char *ptr;            /* pointer to display string */
    int  display_length;  /* holds length of display string */

    /* character is the TAB character ? */
    if (ch == TAB)
        /* get the string to display for the tab */
        ptr = display_tab_str(pos->cur_col);

    /* not tab, get the string to display for the character */
    else
        ptr = display_char_str(ch);

    /* determine the length of the display string */
    display_length = strlen(ptr);

    /* display the display string, keeping track of cursor position */
    while (TRUE) {

        /* cursor column past right screen edge */
        if (pos->cur_col > ss.right) {

            /* wrap around to left edge */
            pos->cur_col = ss.left;

            /* at bottom of screen? */
            if (pos->cur_row >= ss.bottom) {

                /* scroll and tally the scroll */
                pos->scroll_flag++;
                wst_scroll();
            }

            /* not at bottom of screen, at next line */
            else
                pos->cur_row++;

            /* update the physical cursor */
            set_cursor(pos->cur_row,pos->cur_col);
        }

        /* if NUL terminator reached, exit print loop */
        if (!*ptr) break;

        /* display the character */
        putch(*ptr);

        /* point to next character in display string */
        ptr++;

        /* move the cursor forward */
        pos->cur_col++;

    }

    return(display_length);
}


/*
***********************************************************************

  Routine:            REDISPLAY 

  Function:
      This routine redisplays the edited line from a particular 
  position in the line until the end or the end of the screen is 
  reached, whichever is reached first. The fields in the line 
  structure passed to this routine are not directly altered. 

  Parameters:
     (input)          line - pointer to the structure containing the 
                          line and information about the line being 
                          edited 
     (input)          pos - specifies what position in the line to 
                          begin redisplaying 
     (output)         max_row - specifies the integer to pass back 
                          the ending row coordinate after the 
                          redisplay 
     (output)         max_col - specifies the integer to pass back 
                          the ending column coordinate after the 
                          redisplay 

  Returns:            NONE 

  Note 1 - It is assumed that the physical cursor on the screen is at 
      the line position specified by the parameter 'pos'. 
**********************************************************************/

redisplay(line,pos,max_row,max_col)
EDIT_LINE *line;
int pos;
int *max_row;
int *max_col;
{
    char *display_char_str();
    char *display_tab_str();
    char *ptr;
    int row;
    int col;
    int i;
    int tmp_row;
    int tmp_col;

    /* get a working copy of current cursor row and column coordinates */
    row = line->cur_row;
    col = line->cur_col;

    /* check that position in line buffer to start redisplay is valid */
    if (pos >= 0 && pos < line->length) {

        /* display each character until end of line */
        for (i = pos; i < line->length; i++) {

            /* check if character is a tab */
            if (line->line[i] == TAB)
                /* get tab string and update size of tab */
                ptr = display_tab_str(col);

            /* otherwise just get character string */
            else
                ptr = display_char_str(line->line[i]);

            /* phx21233 R.L. - size of 0 means character not echoed and */
            /*      should not be displayed  */
            if (line->size[i])
                line->size[i] = strlen(ptr);

            else
                continue;

            /* display character string until NUL terminator reached */
            while (*ptr) {

                /* check for wrap around past right edge of screen */
                if (check_line_wrap(line,&row,&col,max_row,max_col) < 0)
                    return;

                /* display the current character in the string */
                putch(*ptr);

                /* point to next character in the string */
                ptr++;

                /* increment cursor position */
                col++;

                /* check if a text key was hit */
                if (stop_display(line)) {

                    /* stop redisplay routine because another character
                       has been entered from the keyboard which will
                       call redisplay again to finish updating the screen
                    */
                    set_cursor(line->cur_row,line->cur_col);
                    return;
                }
            }
        }

        /* check for wrap around past right edge of screen */
        if (check_line_wrap(line,&row,&col,max_row,max_col) < 0)
            return;
    }

    /* save ending coordinates (coordinates of where line
       displayed ends)
    */
    tmp_row = row;
    tmp_col = col;

    /* reached the end of line, but must pad to ending
       coordinates with blanks to erase leftover characters
    */
    while (row < line->max_row) {
        if (col > ss.right) {
            col = ss.left;
            row++;
            set_cursor(row,col);
        }
        else {
            putch(' ');
            col++;
        }
    }

    if (row == line->max_row) {
        while (col <= line->max_col) {
            putch(' ');
            col++;
        }
    }

    /* update the physical location of the cursor */
    set_cursor(line->cur_row,line->cur_col);
    *max_row = tmp_row;
    *max_col = tmp_col;
}



/*
***********************************************************************

  Routine:            CHECK_LINE_WRAP

  Function:
      This routine checks to see if the cursor has gone past the
  defined right edge of the screen and moves the cursor to the left
  most column of the next line. If the line is wrapped at the bottom
  most line of the defined screen area, a flag in the line structure
  is set and the maximum row and col coordinates of the screen are
  past back to the caller.

  Parameters:
     (input)          line - pointer to the structure containing the 
                          line and information about the line being 
                          edited
     (input/output)   row - contains the address of the variable containing
                          the current row coordinates of the cursor
     (input/output)   col - contains the address of the variable containing
                          the current column coordinates of the cursor
     (output)         max_row - this variable is initialized to the
                          maximum screen row coordinate if the line
                          wraps on the last row
     (output)         max_col - this variable is initialized to the
                          maximum screen column coordinate if the
                          line wraps on the last row

  Returns:             0 if screen not completely filled 
                      -1 if the line extends beyond the end of the
                         screen

**********************************************************************/

check_line_wrap(line,row,col,max_row,max_col)
EDIT_LINE *line;
int *row;
int *col;
int *max_row;
int *max_col;
{
    /* check for wrap around past right edge of screen */
    if (*col > ss.right) {
        /* wrap around to left side of screen */
        *col = ss.left;

        /* reached bottom of screen? */
        if (*row >= ss.bottom) {

            /* update max row and col variables */
            *max_row = ss.bottom;
            *max_col = ss.right;

            /* flag not all characters displayed */
            line->off_screen = TRUE;

            /* restore physical cursor position */
            set_cursor(line->cur_row,line->cur_col);
            return(-1);
        }

        /* not bottom of screen, go to next line */
        else
            (*row)++;

        /* update location of physical cursor */
        set_cursor(*row,*col);
    }
    return(0);
}


/*
***********************************************************************

  Routine:            STOP_DISPLAY 

  Function:
      This routine is used to optimize screen updates by checking to 
  see if updating of the screen may be stopped before it is 
  completed. This is possible if another key is detected that 
  guarantees the redisplay routine will be called again to update the 
  screen. 

  Parameters:
     (input)          line - pointer to the structure containing the 
                          line and information about the line being 
                          edited 

  Returns:            TRUE if a key was detected that guarantees a 
                          subsequent screen update 
                      FALSE otherwise 

**********************************************************************/

stop_display(line)
EDIT_LINE *line;
{
    int ch;

    /* don't stop update if no key hit or key is not ASCII */
    if ((ch = checkkey()) < 0 || ch > ASCII_EXTEND_CODE) return(FALSE);

    switch (ch) {
        /* kill to beginning of line will update if not already at  */
        /* beginning of line                                        */
        case '@':
            if (line->index > ZERO_INDEX_VALUE) return(TRUE);
            return(FALSE);

        /* literal escape or escape does not guarantee subsequent   */
        /* redisplay                                                */
        case '\\':
        case ESC:
            return(FALSE);

        /* backspace and delete key redisplays if a character is    */
        /* deleted                                                  */
        case BACKSPACE:
        case DEL_KEY:
            if (line->index > ZERO_INDEX_VALUE) return(TRUE);
            return(FALSE);

        /* delete character key redisplays if cursor is before end  */
        /* of line                                                  */
        case CTRL_D:
            if (line->index < line->length) return(TRUE);
            return(FALSE);

        /* kill to end of line redisplays if not already at end of  */
        /* line                                                     */
        case CTRL_K:
            if (line->index < line->length) return(TRUE);
            return(FALSE);

        default:

            /* if not a tab and not a printable character, may not  */
            /* force a redraw                                       */
            if (ch != TAB &&
                (ch < MIN_PRINTABLE_ASCII || ch > MAX_PRINTABLE_ASCII))
                return(FALSE);

            /* a printable character; if in replace mode, redraws   */
            /* if not at end of line                                */
            if (line->mode) {
                if (line->length < MAX_LINE_SIZE) return(TRUE);
                return(FALSE);
            }

            /* in insert mode, redraws if maximum line size has     */
            /* not been reached                                     */
            else {
                if (line->index < MAX_LINE_SIZE) return(TRUE);
                return(FALSE);
            }
    }
}


/*
***********************************************************************

  Routine:            GET_ECHOED_INPUT

  Function:
      This routine is used to extract echoed input from a specified
  part of the edit-mode input line buffer. Only characters echoed will
  be extracted. The results are passed back in a static string, along
  with the length of the extracted input item.
  
  Parameters:
     (input)          line - pointer to the structure containing the 
                          line and information about the line being 
                          edited
     (input)          item_pos - index to position in line buffer
                          to begin extracting
     (input)          item_size - number of characters in line buffer
                          from which to extract
     (output)         display_str - pointer to the string extracted
     (output)         display_len - length of string extract

  Returns:            None

**********************************************************************/

get_echoed_input(line,item_pos,item_size,display_str,display_len)
EDIT_LINE *line;
int item_pos;
int item_size;
char **display_str;
int *display_len;
{
    static char echoed_str[MAX_LINE_SIZE+1];
    register int i;
    register int count;

    /* ensure specified position for extraction is valid */
    if (item_pos > line->length) item_pos = line->length;
    else if (item_pos < 0) item_pos = 0;

    /* ensure specified number of chars for extraction is valid */
    if (item_pos+item_size > line->length)
        item_size = line->length - item_pos;

    /* tally and copy over the echoed input characters from input buffer */
    count = 0;
    for (i = item_pos; i < item_size; i++)
        /* if represented by at least 1 character */
        if (line->size[i] > 0)
            echoed_str[count++] = line->line[i];
    echoed_str[count] = 0;

    /* pass back the results */
    *display_str = echoed_str;
    *display_len = count;
}



/*
***********************************************************************

  Routine:            DISPLAY_CHAR

  Function:
      This routine displays a character entered from the keyboard in 
  an appropriate representation by calling display_char_prim() if
  keyboard echoing is enabled. If echoing is disabled, nothing is
  displayed and 0 is returned.

  Parameters:
     (input/output)   pos - pointer to a structure which maintains 
                          cursor position information; information is 
                          updated after the display 
     (input)          ch - specifies the ASCII character to display 

  Returns:            The number of characters displayed to represent 
                          the keyboard character if keyboard echoing enabled
                      0 if keyboard character echoing is disabled

**********************************************************************/

display_char(pos,ch)
CURPOS *pos;   /* pointer to structure for keeping track of cursor position */
int ch;        /* character to display */
{
    if (!kb.echo)
        return(0);

    return(display_char_prim(pos,ch));
}

 



		    kbedit.c                        04/24/89  1040.7rew 04/24/89  1034.0      321660



/* ********************************************
   *                                          *
   * Copyright, (C) Honeywell Bull Inc., 1988 *
   *                                          *
   ******************************************** */

/* HISTORY COMMENTS:
  1) change(88-06-13,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Created.
  2) change(88-07-22,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Added support routines to capitalize, uppercase, lowercase
     and transpose words; added support routine to transpose characters.
  3) change(88-07-25,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Documentation additions only. Added header comments to all routines.
  4) change(88-08-09,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Fix references to include files; "wstdefs.h" was split into
     "wstdefs.h" and "wsttype.h" to avoid declaration clash; also,
     various constants defined to descriptive names.
  5) change(88-09-16,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Modified line terminator to be always a linefeed for edit-mode;
     lfecho and crecho only applies to fullduplex modes.
  6) change(89-01-18,Lee), approve(89-01-02,MCR8043), audit(89-03-14,Flegel),
     install(89-04-24,MR12.3-1033):
     phx21233 - Modified to save only echoed input when items are killed to the
     kill buffer and when lines are saved to history buffer, kill buffer and
     audit buffers.
                                                   END HISTORY COMMENTS */

#include <stdio.h>
#include <dos.h>
#include <ctype.h>
#include "wstdefs.h"
#include "wstglob.h"
#include <wsmincap.h>

/*
**********************************************************************

  Routine:            DELETE_CHARS 

  Function:
      This routine will delete a specified number of characters at 
  the logical cursor position on the line and force the line to be 
  updated on the screen. 

  Parameters:
     (input/output)   line - pointer to the structure containing the 
                          line and information about the line being 
                          edited 
     (input)          n_chars - specifies the number of characters to 
                          delete at the current cursor position
     (input)          save_sw - if TRUE, specifies that the deleted
                          characters are to be put into the kill buffer

  Returns:            NONE 

**********************************************************************/

delete_chars(line,n_chars,save_sw)
EDIT_LINE *line;
int n_chars;
{
    int chars_to_eol;
    int chars_to_del;
    int i, j;
    char *echoed_input;
    int echoed_length;

    /* determine number of characters from logical cursor position  */
    /* to end of line                                               */
    chars_to_eol = line->length - line->index;

    /* make sure number of characters to delete does not exceed     */
    /* number of characters to the end of line                      */
    if (chars_to_eol < n_chars)
        chars_to_del = chars_to_eol;
    else
        chars_to_del = n_chars;

    /* save item to killbuffer if save switch is on */
    if (save_sw && chars_to_del > 0 && kb.echo) {
        /* phx21233 R.L. - save only echoed input to kill buffer */
        get_echoed_input(line,line->index,chars_to_del,&echoed_input,
            &echoed_length);
        save_to_killbuff(echoed_input,echoed_length);
    }

    /* copy rest of line over the deleted part of the line */
    for (i = line->index, j = line->index+chars_to_del;
        j < line->length; i++,j++) {

        /* copy over text in line buffer */
        line->line[i] = line->line[j];

        /* copy over count of display chars for text characters */
        line->size[i] = line->size[j];
    }

    /* update line length */
    line->length -= chars_to_del;

    /* force redraw from logical cursor position to end of line */
    redisplay(line,line->index,&(line->max_row),&(line->max_col));
}



/*
**********************************************************************

  Routine:            KILL_TO_BOL 

  Function:
      This routine deletes all text from the current cursor position 
  to the end of the line and then updates the screen. 

  Parameters:
     (input/output)   line - pointer to the structure containing the 
                          line and information about the line being 
                          edited 

  Returns:            NONE 

**********************************************************************/

kill_to_bol(line)
EDIT_LINE *line;
{
    int i;
    int n_chars;

    /* do only if logical cursor not already at beginning of line */
    if (line->index > 0) {

        /* number of characters to delete is logical cursor         */
        /* position                                                 */
        n_chars = line->index;

        /* check if beginning of line has scrolled off top of       */
        /* screen                                                   */
        if (line->scrolled_flag) {

            /* redisplay line from top of the screen */
            set_cursor(ss.top,ss.left);

            /* pad over to original display column */
            for (i = ss.left; i < line->orig_col; i++)
                putch(' ');

            /* update line cursor position information */
            line->orig_row = ss.top;
            line->scrolled_flag = FALSE;

            /* move physical and logical cursor to beginning of     */
            /* line                                                 */
            line->cur_row = ss.top;
            line->cur_col = line->orig_col;
            set_cursor(line->cur_row,line->cur_col);
            line->index = 0;

            /* delete the characters and force a redraw */
            delete_chars(line,n_chars,KILLBUFF_SAVE);
        }

        /* coordinates for beginning of line on screen */
        else {

            /* move logical and physical cursor to beginning of     */
            /* line                                                 */
            line->index = 0;
            line->cur_row = line->orig_row;
            line->cur_col = line->orig_col;
            set_cursor(line->cur_row,line->cur_col);

            /* perform the delete and force a screen update */
            delete_chars(line,n_chars,KILLBUFF_SAVE);
        }
    }
}


/*
**********************************************************************

  Routine:            KILL_TO_EOL 

  Function:
      This routine deletes all text from the current cursor position 
  to the end of the line, updating the screen. 

  Parameters:
     (input/output)   line - pointer to the structure containing the 
                          line and information about the line being 
                          edited 

  Returns:            NONE 

**********************************************************************/

kill_to_eol(line)
EDIT_LINE *line;
{

    /* if not already at end of the line */
    if (line->index < line->length)

        /* delete the number of characters from the end of the      */
        /* line to the current logical cursor position              */

        delete_chars(line,line->length-line->index,KILLBUFF_SAVE);
}



/*
**********************************************************************

  Routine:            ADD_TEXT 

  Function:
      This routine adds text into the line being edited 

  Parameters:
     (input/output)   line - pointer to the structure containing the 
                          line and information about the line 
     (input)          ch - specifies the character to add as text to 
                          the line being edited 
     (input)          n_times - specifies the number of times that 
                          the text character is to be added 

  Returns:            NONE 

**********************************************************************/

add_text(line,ch,n_times)
EDIT_LINE *line;
int ch;
int n_times;
{

    /* determine if editing is in replace mode */
    if (!line->mode)
        replace_text(line,ch,n_times);

    /* if not, then is in insert mode */
    else
        insert_text(line,ch,n_times);
}



/*
**********************************************************************

  Routine:            INSERT_TEXT 

  Function:
      This routine displays and inserts one or more characters into 
  the edit line buffer and updates the screen. 

  Parameters:
     (input/output)   line - pointer to the structure containing the 
                          line and information about the line 
     (input)          ch - specifies the ASCII character to insert 
                          into the line edited as text 
     (input)          n_times - specifies the number of times that 
                          the specified character is to be inserted 

  Returns:            TRUE if successful 
                      FALSE if unsuccessful 

**********************************************************************/

insert_text(line,ch,n_times)
EDIT_LINE *line;
int ch;
int n_times;
{
    CURPOS tpos;
    int i, j;
    int actual_times;
    int chars_to_eol;

    /* determine how much space is available to insert text */
    chars_to_eol = MAX_LINE_SIZE - line->length;

    /* check for 0 or less characters to insert */
    if (n_times < 1)
        return(FALSE);

    /* check for no more space in edit line buffer for insert */
    if (chars_to_eol < 1) {
        beep();
        return(FALSE);
    }

    /* make sure number of characters to insert does not exceed     */
    /* space available for insert                                   */
    if (n_times > chars_to_eol) {
        actual_times = chars_to_eol;
        beep();
    }
    else
        actual_times = n_times;

    /* initialize cursor position information */
    init_temp_curpos(&tpos,line);

    /* make a gap in the line buffer for the insert */
    for (i = line->length+actual_times, j = line->length;
        j >= line->index; i--, j--) {
        line->line[i] = line->line[j];
        line->size[i] = line->size[j];
    }

    /* copy the text into the gap */
    for (i = line->index, j = 0; j < actual_times; i++, j++) {
        line->line[i] = ch;
        line->size[i] = display_char(&tpos,ch);
    }

    /* update the line length and logical cursor position */
    line->length += actual_times;
    line->index += actual_times;

    /* update cursor position information */
    line->cur_row = tpos.cur_row;
    line->cur_col = tpos.cur_col;
    line->orig_row -= tpos.scroll_flag;
    if (line->orig_row < ss.top)
        line->scrolled_flag = TRUE;

    /* update the changes to the screen */
    redisplay(line,line->index,&(line->max_row),&(line->max_col));
    return(TRUE);
}



/*
**********************************************************************

  Routine:            REPLACE_TEXT 

  Function:
      This routine replaces the character(s) at the cursor position 
  in the edit line and updates the screen 

  Parameters:
     (input/output)   line - specifies the structure containing the 
                          line and information about the line being 
                          edited 
     (input)          key - specifies the ASCII character to replace 
                          the current character(s) with 
     (input)          n_times - specifies the number of characters to 
                          replace with the specified ASCII character 

  Returns:            FALSE if unsuccessful 
                      TRUE if successful 

**********************************************************************/

replace_text(line,key,n_times)
EDIT_LINE *line;
int key;
int n_times;
{
    CURPOS tpos;
    int i;
    int ch;
    int actual_times;
    int chars_to_eol;

    /* determine space available for adding text */
    chars_to_eol = MAX_LINE_SIZE - line->index;

    /* do nothing if replacing 0 or less characters */
    if (n_times < 1)
        return(FALSE);

    /* beep and return if no more space available to add text */
    if (chars_to_eol < 1) {
        beep();
        return(FALSE);
    }

    /* make sure number of characters to replace does not exceed    */
    /* space available; beep if it does                             */
    if (n_times > chars_to_eol) {
        actual_times = chars_to_eol;
        beep();
    }
    else
        actual_times = n_times;

    /* get character to replace */
    ch = key;

    /* initialize structure for keeping track of cursor position */
    init_temp_curpos(&tpos,line);

    /* perform the replace and display the character(s) being       */
    /* added                                                        */
    for (i = 0; i < actual_times; i++) {
        line->line[line->index] = ch;
        line->size[line->index] = display_char(&tpos,ch);
        line->index++;
    }

    /* update line length if line got extended */
    if (line->index > line->length) line->length = line->index;

    /* update cursor position information in line structure */
    line->cur_row = tpos.cur_row;
    line->cur_col = tpos.cur_col;
    line->orig_row -= tpos.scroll_flag;
    if (line->orig_row < ss.top)
        line->scrolled_flag = TRUE;

    /* update the changes to the screen */
    redisplay(line,line->index,&(line->max_row),&(line->max_col));

    return(TRUE);
}



/*
**********************************************************************

  Routine:            FORWARD_DELETE_WORD 

  Function:
      This routine deletes text to the right of the cursor up to the 
  end of the next word in the line. The screen is then updated. 

  Parameters:
     (input/output)   line - specifies the structure containing the 
                          line and information about the line being 
                          edited 
     (input)          n_times - specifies the number of times to 
                          repeat this delete function 

  Returns:            NONE 

**********************************************************************/

forward_delete_word(line,n_times)
EDIT_LINE *line;
int n_times;
{
    int i;

    /* do nothing if already at end of the line */
    if (line->index >= line->length) return;

    /* get current logical cursor position */
    i = line->index;

    /* perform for the specified number of times or until end of    */
    /* line reached                                                 */
    while (n_times > 0 && i < line->length) {

        /* skip any word delimiters */
        while (i < line->length && is_word_delim(line->line[i]))
            i++;

        /* skip until word delimiter reached */
        while (i < line->length && !is_word_delim(line->line[i]))
            i++;

        /* tally number of times performed */
        n_times--;

    }

    /* check if new position is different */
    if (i == line->index)
        return;

    /* delete the difference in positions and update the screen */
    delete_chars(line,i-line->index,KILLBUFF_SAVE);
}


/*
**********************************************************************

  Routine:            BACKWARD_DELETE_WORD 

  Function:
      This routine deletes text to the left of the cursor up to the 
  beginning of the previous word. The screen is updated. 

  Parameters:
     (input/output)   line - specifies the structure containing the 
                          line and information about the line being 
                          edited 
     (input)          n_times - specifies the number of times to 
                          perform this function 

  Returns:            NONE 

**********************************************************************/

backward_delete_word(line,n_times)
EDIT_LINE *line;
int n_times;
{
    int i;
    int n_chars;

    /* do only if not at beginning of line */
    if (line->index < 1) return;

    /* begin at one position before the cursor */
    i = line->index - 1;

    /* do the specified number of times or until beginning of line  */
    /* reached                                                      */
    while (n_times > 0 && i >= 0) {

        /* skip word delimiters to the left */
        while (i >= 0 && is_word_delim(line->line[i]))
            i--;

        /* skip word to the left */
        while (i >= 0 && !is_word_delim(line->line[i]))
            i--;

        /* tally the times performed */
        n_times--;
    }

    /* restore cursor position one position to the right */
    i++;

    /* determine the number of characters to the left to delete */
    n_chars = line->index - i;

    /* move the physical and logical cursor there, updating the     */
    /* screen                                                       */
    cursor_left(line,n_chars);

    /* perform the delete and update the screen */
    delete_chars(line,n_chars,KILLBUFF_SAVE);
}



/*
**********************************************************************

  Routine:            ADD_CHAR 

  Function:
      This routine adds a character into the line being edited and 
  updates the screen without moving the cursor forward. This routine 
  is used for handling literal escaping of characters. 

  Parameters:
     (input/output)   line - specifies the structure containing the 
                          line and information about the line being 
                          edited 
     (input)          ch - specifies the ASCII character to add into 
                          the line 

  Returns:            TRUE if successful 
                      FALSE if unsuccessful 

**********************************************************************/

add_char(line,ch)
EDIT_LINE *line;
int ch;
{
    int code;

    /* determine if in edit replace mode */
    if (!line->mode)
        code = replace_char(line,ch);

    /* no, in edit insert mode */
    else
        code = insert_char(line,ch);

    /* return the status to caller */
    return(code);
}



/*
**********************************************************************

  Routine:            REPLACE_CHAR 

  Function:
      This routine will replace the current character of the line 
  being edited. The cursor position is NOT changed. 

  Parameters:
     (input/output)   line - specifies the structure containing the 
                          line and information about the line being 
                          edited 
     (input)          key - specifies the ASCII character to replace 
                          the current character with 

  Returns:            FALSE if unsuccessful 
                      TRUE if successful 

**********************************************************************/

replace_char(line,key)
EDIT_LINE *line;
int key;
{
    CURPOS tpos;
    int ch;
    int chars_to_eol;

    /* determine space available for replacing line buffer text */
    chars_to_eol = MAX_LINE_SIZE - line->index;

    /* if no more space left, beep and return */
    if (chars_to_eol < 1) {
        beep();
        return(FALSE);
    }

    /* get character to insert */
    ch = key;

    /* initialize cursor positioning information */
    init_temp_curpos(&tpos,line);

    /* do the replace and display the new character */
    line->line[line->index] = ch;
    line->size[line->index] = display_char(&tpos,ch);

    /* update the line length if line is extended */
    if (line->index+1 > line->length) line->length = line->index+1;

    /* update cursor position */
    line->cur_row = tpos.cur_row;
    line->cur_col = tpos.cur_col;
    line->orig_row -= tpos.scroll_flag;
    if (line->orig_row < ss.top)
        line->scrolled_flag = TRUE;

    /* update the line to the screen */
    redisplay(line,line->index+1,&(line->max_row),&(line->max_col));

    return(TRUE);
}



/*
**********************************************************************

  Routine:            INSERT_CHAR 

  Function:
      This routine inserts a character into the line being edited. 
  The cursor position is not moved forward. 

  Parameters:
     (input/output)   line - specifies the structure containing the 
                          line and information about the line being 
                          edited 
     (input)          ch - specifies the ASCII character to insert 
                          into the line 

  Returns:            TRUE if successful 
                      FALSE if unsuccessful 

**********************************************************************/

insert_char(line,ch)
EDIT_LINE *line;
int ch;
{
    CURPOS tpos;
    int i, j;

    int chars_to_eol;

    /* determine space available in line for inserting */
    chars_to_eol = MAX_LINE_SIZE - line->length;

    /* beep and return if no space for insert */
    if (chars_to_eol < 1) {
        beep();
        return(FALSE);
    }

    /* initialize cursor position information */
    init_temp_curpos(&tpos,line);

    /* create gap in line buffer for the character to insert */
    for (i = line->length+1, j = line->length;
        j >= line->index; i--, j--) {
        line->line[i] = line->line[j];
        line->size[i] = line->size[j];
    }

    /* copy in the character */
    line->line[line->index] = ch;
    line->size[line->index] = display_char(&tpos,ch);

    /* update the line length */
    line->length++;

    /* update the cursor position information */
    line->cur_row = tpos.cur_row;
    line->cur_col = tpos.cur_col;
    line->orig_row -= tpos.scroll_flag;
    if (line->orig_row < ss.top)
        line->scrolled_flag = TRUE;

    /* update the line to the screen */
    redisplay(line,line->index+1,&(line->max_row),&(line->max_col));
    return(TRUE);
}



/*
**********************************************************************

  Routine:            INSERT_DISPLAY_CHAR 

  Function:
      This routine inserts characters on the screen only. It allows 
  partial input of a backslash sequence to be displayed before it is 
  entered into the line being edited. 

  Parameters:
     (input/output)   line - specifies the structure containing the 
                          line and information about the line being 
                          edited 
     (input)          ch - specifies the character to insert at the 
                          cursor position in the screen 

  Returns:            NONE 

**********************************************************************/

insert_display_char(line,ch)
EDIT_LINE *line;
int ch;
{
    CURPOS tpos;

    /* initialize cursor position information */
    init_temp_curpos(&tpos,line);

    /* store the character in the buffer for handling literal       */
    /* escaping                                                     */
    line->literal_buff[line->literal_dex++] = ch;

    /* display the character */
    display_char(&tpos,ch);

    /* update the line structure with cursor position information */
    line->cur_row = tpos.cur_row;
    line->cur_col = tpos.cur_col;
    line->orig_row -= tpos.scroll_flag;
    if (line->orig_row < ss.top)
        line->scrolled_flag = TRUE;

    /* update the line to the screen */
    redisplay(line,line->index+1,&(line->max_row),&(line->max_col));
}



/*
**********************************************************************

  Routine:            CHANGE_CASE_WORD 

  Function:
      This routine converts all alphabetic characters in the current 
  word of the line being edited (in edit mode) to a specified case. If
  the cursor is not on a word, the word to the left of the cursor is 
  converted to the specified case. The screen is then updated and the
  cursor is positioned at the end of the word that has been converted.
  The cases specified may be upper case, lower case or capitalized.

  Parameters:
     (input/output)   line - pointer to the structure containing the 
                          line and information about the line being 
                          edited (in edit mode) 
     (input)          case_flag - specifies the case to convert the
                          word(s) to:
                          KB_UPPER_CASE for upper case,
                          KB_LOWER_CASE for lower case,
                          KB_CAPITALIZED for first letter of word
                              in upper case, and rest in lower case

  Returns:            NONE 

**********************************************************************/

change_case_word(line,case_flag)
EDIT_LINE *line;
int case_flag;
{
    int i;
    int orig_index;

    /* get copy of keyboard buffer index */
    i = line->index;
    if (i >= line->length) i--;
    orig_index = i;

    /* cursor on word delimiter or space? */
    if (is_word_delim(line->line[i])) {

        /* go left to previous word */
        while (i >= 0 && is_word_delim(line->line[i])) i--;

        /* check for no word on left */
        if (i < 0) {

            /* no previous word, move right to use next word */
            i = orig_index;
            while (i < line->length && is_word_delim(line->line[i])) i++;

            /* past end of line, is a blank line, do nothing */
            if (i >= line->length)
                return;
        }
    }

    /* make sure is at beginning of word */
    while (i >= 0 && !is_word_delim(line->line[i])) i--;
    i++;

    /* move physical cursor to beginning of the word for case change */
    if (i < line->index)
        cursor_left(line,line->index-i);
    else if (i > line->index)
        cursor_right(line,i-line->index);

    /* lower case first character if LOWER CASE specified */
    if (case_flag == KB_LOWER_CASE)
        line->line[i] = tolower(line->line[i]);

    /* upper case first character for UPPER CASE or CAPITALIZE */
    else
        line->line[i] = toupper(line->line[i]);
    i++;

    /* handle rest of word */
    while (i < line->length && !is_word_delim(line->line[i])) {

        /* upper case rest of word if UPPER CASE */
        if (case_flag == KB_UPPER_CASE)
            line->line[i] = toupper(line->line[i]);

        /* lower case rest of word if LOWER CASE or CAPITALIZE */
        else
            line->line[i] = tolower(line->line[i]);

        i++;

    }

    /* update the screen */
    redisplay(line,line->index,&(line->max_row),&(line->max_col));

    /* position cursor to end of last word upper cased */
    cursor_right(line,i-line->index);
}



/*
**********************************************************************

  Routine:            TRANSPOSE_CHARS 

  Function:
      This routine exchanges the positions of the two characters to 
  the left of the cursor. If there isn't two characters to the left 
  of the cursor, the routine will sound a beep and do nothing. The 
  screen is updated and the cursor position is unchanged. 

  Parameters:
     (input/output)   line - specifies the structure containing the 
                          line and information about the line being 
                          edited (in edit mode) 

  Returns:            NONE 

**********************************************************************/

transpose_chars(line)
EDIT_LINE *line;
{
    int i;
    int tmp_ch;

    /* check if two characters exist to left of cursor */
    if (line->length < 2 || line->index < 2) {
        beep();
        return;
    }

    /* position temporary index to two positions before cursor */
    i = line->index - 2;

    /* move cursor two characters back */
    cursor_left(line,2);

    /* swap the two characters */
    tmp_ch = line->line[i];
    line->line[i] = line->line[i+1];
    line->line[i+1] = tmp_ch;

    /* update the screen */
    redisplay(line,line->index,&(line->max_row),&(line->max_col));

    /* restore cursor position */
    cursor_right(line,2);
}



/*
**********************************************************************

  Routine:            TRANSPOSE_WORDS 

  Function:
      This routine interchanges the positions of the current word 
  (under the cursor) and the word to its left. If the cursor is not 
  on a word, the two words to the left of the cursor are 
  interchanged. The screen is updated and the cursor is positioned at 
  the end of the interchanged words. If there are no words to 
  interchange (e.g. at beginning of the line), the routine will beep 
  and do nothing. 

  Parameters:
     (input/output)   line - specifies the structure containing the 
                          line and information about the line being 
                          edited (in edit mode) 

  Returns:            NONE 

**********************************************************************/

transpose_words(line)
EDIT_LINE *line;
{
    int i;
    int word1_index, word1_len;
    int word2_index, word2_len;
    int delim_len;
    char *tmp_buff, *malloc();
    int tmp_index;
    int final_index;

    /* get cursor position and make sure it points to valid data */
    /* if at end of line */
    i = line->index;
    if (i >= line->length) i--;

    /* check if in middle of a word */
    if (!is_word_delim(line->line[i]))
        /* go to end of word */
        while (i < line->length && !is_word_delim(line->line[i]))
            i++;

    /* go left to right, skip trailing blanks */
    i--;
    while (i >= 0 && is_word_delim(line->line[i]))
       i--;

    /* save the index to the end of this second word */
    final_index = i+1;

    /* determine length and starting position of this second word */
    word2_len = 0;
    while (i >= 0 && !is_word_delim(line->line[i])) {
        i--;
        word2_len++;
    }
    word2_index = i+1;

    /* no word to transpose with if past beginning of line */
    if (i < 0) {
        beep();
        return;
    }

    /* determine number of delimiter characters to left of second word */
    delim_len = 0;
    while (i >= 0 && is_word_delim(line->line[i])) {
       delim_len++;
       i--;
    }

    /* no words to transpose with if past beginning of line */
    if (i < 0) {
        beep();
        return;
    }

    /* determine length and position of first word */
    word1_len = 0;
    while (i >= 0 && !is_word_delim(line->line[i])) {
        i--;
        word1_len++;
    }
    word1_index = i+1;

    /* allocate buffer big enough to hold both words and delimiter */
    tmp_buff = malloc(word1_len+delim_len+word2_len+1);
    if (tmp_buff == NULL) return;

    /* move cursor to beginning of first word */
    i = line->index - word1_index;
    cursor_left(line,i);

    /* copy the two words and delimiter in between with the word positions
       interchanged to temporary buffer
    */
    tmp_index = 0;
    for (i = 0; i < word2_len; i++)
        tmp_buff[tmp_index++] = line->line[word2_index+i];
    for (i = 0; i < delim_len; i++)
        tmp_buff[tmp_index++] = line->line[word1_index+word1_len+i];
    for (i = 0; i < word1_len; i++)
        tmp_buff[tmp_index++] = line->line[word1_index+i];

    /* copy back from temporary buffer to line buffer */
    for (i = 0; i < tmp_index; i++)
        line->line[word1_index+i] = tmp_buff[i];

    /* deallocate temporary buffer */
    free(tmp_buff);

    /* update the screen */
    redisplay(line,line->index,&(line->max_row),&(line->max_col));

    /* position cursor at end of words */
    cursor_right(line,final_index-line->index);
}



/*
**********************************************************************

  Routine:            KB_EDIT_LF_RETURN 

  Function:
      This function passes processes a line in edit-mode when a
  linefeed or carriage return is entered, before the line is to
  be sent to the host. Processing includes moving the cursor to
  the end of the line, saving the line in the history and kill
  buffer, file or printer audit the lines if auditing is enabled,
  and updating any cursor position variables. The line is then
  sent to the host.

  Parameters:
     (input/output)   line - pointer to the structure containing the 
                          line and information about the line to be 
                          saved and sent to the host 
     (input)          key - specifies the line terminator key that
                          was entered

  Returns:            NONE 

**********************************************************************/

kb_edit_lf_return(line,key)
EDIT_LINE *line;
int key;
{
    char *dptr;
    char *echoed_input;
    int  echoed_length;

    /* position cursor to end of line (to prevent incoming messages
       from overwriting the input
    */
    cursor_eol(line);

    /* Handle moving the cursor to the next line. */
    /* Don't move to beginning of next line if CR hit and mowse is */
    /* not active; in glass tty mode, when using edit mode, */
    /* the terminal modes should be ^echoplex,lfecho. A linefeed */
    /* will be echoed from Multics anyways. */

    if (!mowse_active && key == CR)
        line->cur_col = ss.left;

    else if (line->cur_row >= ss.bottom) {
        wst_scroll();
        line->cur_row = ss.bottom;
        line->cur_col = ss.left;
    }
    else {
        line->cur_row++;
        line->cur_col = ss.left;
    }

    cursor_move(line->cur_row,line->cur_col);

    /* re-initialize screen information */
    screen.curlin = line->cur_row;
    screen.curcol = line->cur_col;
    screen.EOP_ct = 0;                 /* input resets page line counter */

    /* phx21233 R.L. - saved only echoed input to history and kill buffers */
    get_echoed_input(line,0,line->length,&echoed_input,&echoed_length);

    /* non-empty lines saved to history buffer */
    if (echoed_length > 0) {
        save_to_histbuff(echoed_input,echoed_length);
        save_to_killbuff(echoed_input,echoed_length);
    }

    if (mowse_active)

        /* terminate line with line delimiter; a linefeed character is */
        /* always used so the line gets interpreted by the host; the */
        /* modes lfecho and crecho do not affect edit-mode since */
        /* characters are echoed locally, and not by the host. The lfecho */
        /* and crecho modes are meaningful in full duplex */

        line->line[line->length++] = LF;

    /* otherwise send whatever line terminator was entered */
    else
        line->line[line->length++] = key;

    /* terminate string */
    line->line[line->length] = NUL_TERMINATOR;

    /* phx21233 R.L. - LF terminate echoed input and audit only echoed input */
    echoed_input[echoed_length++] = LF;

    /* audit input if necessary */
    if (wst_f_audit)
        f_audit_msg(echoed_input,echoed_length);

    if (wst_p_audit)
        p_audit_msg(echoed_input,echoed_length,NULL);

    /* just send the message to host if not in glass tty mode */
    if (mowse_active)
        puttdata (FG_TERMINAL_DATA, line->line, line->length);

    /* kludge to minimize line overrun for long input lines when */
    /* Multics is echoing; this problems shows up when the user */
    /* is in non-packet (glass tty) mode and long input lines are */
    /* echoed. The echoed input from Multics sometimes causes the PC */
    /* to stall, resulting in a Multics interpreting a QUIT signal. */
    /* This fix slows long input from being sent too quickly so that */
    /* echoed characters are received less quickly. */
    else {
        /* send characters out in 4 character chunks, delaying in between */
        dptr = line->line;
        while (line->length > 4) {

            puttdata(FG_TERMINAL_DATA, dptr, 4);
            dptr += 4;
            line->length -= 4;
            delay();
        }

        puttdata(FG_TERMINAL_DATA, dptr, line->length);
    }

    /* reset edit mode line length and buffer index to indicate 0 length */
    line->length = 0;
    line->index = 0;
}




		    kbinit.c                        10/12/88  1357.1rew 10/12/88  1331.3       55125



/* ********************************************
   *                                          *
   * Copyright, (C) Honeywell Bull Inc., 1988 *
   *                                          *
   ******************************************** */

/* HISTORY COMMENTS:
  1) change(88-06-13,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Created.
  2) change(88-07-25,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Documentation additions only. Added header comments to all routines.
  3) change(88-08-09,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Fix references to include files; "wstdefs.h" was split into
     "wstdefs.h" and "wsttype.h" to avoid declaration clash; also,
     various constants defined to descriptive names.
                                                   END HISTORY COMMENTS */

#include <dos.h>
#include "wstdefs.h"
#include "wstglob.h"

/*
**********************************************************************

  Routine:            INIT_KB_SCREEN 

  Function:
      This routine initializes a structure used by the edit mode 
  editing routines which specifies the size of the display screen. 

  Parameters:
     (input)          rows - specifies the height of the screen in 
                          rows 
     (input)          cols - specifies the width of the screen in 
                          columns 

  Returns:            NONE 

**********************************************************************/

init_kb_screen(rows,cols)
int rows;  /* screen height in rows */
int cols;  /* screen width in columns */
{
    ss.top = CURSOR_HOME_ROW;   /* top screen edge coordinate */
    ss.left = CURSOR_HOME_COL;  /* left screen edge coordinate */
    ss.bottom = rows-1;         /* bottom screen edge coordinate */
                                /* (subtract 1 to get coordinate value) */
    ss.right = cols-2;          /* right screen edge coordinate */
                                /* (subtract 1 to get coordinate value */
                                /* and another to prevent last screen */
                                /* column to be written since it may */
                                /* automatic cursor advancement or  */
                                /* scrolling which is not desirable) */
}


/*
**********************************************************************

  Routine:            INIT_LINE 

  Function:
      This routine initializes the structure containing the line 
  being edited and information about the line in edit mode. The 
  values that are used for initializing will indicate an empty line 
  being edited. 

  Parameters:
     (input/output)   line - a pointer to the structure which 
                          contains the line and information about the 
                          line being edited 

  Returns:            NONE 

**********************************************************************/

init_line(line)
EDIT_LINE *line;
{

    line->mode = KB_REPLACE_MODE;     /* insert/replace mode is replace */
    line->orig_row = CURSOR_HOME_ROW; /* assume starting at top row */
    line->orig_col = CURSOR_HOME_COL; /* assume starting at leftmost column */
    line->length = 0;                 /* line length is 0 (empty line) */
    line->index = 0;                  /* logical cursor position is 0 */
    line->literal_dex = 0;         /* count of numeric digits for escape arg */
    line->line[0] = NUL_TERMINATOR;   /* NUL terminate keyboard buffer */
    line->escape_arg = NO_ESC_ARG;    /* initialize escape argument counter */
    line->escape_flag = NO_ESC_FUNC;  /* initialize escape/literal key flag */
}


/*
**********************************************************************

  Routine:            INIT_CURPOS 

  Function:
      This routine initializes the cursor position fields of the 
  structure containing the edit mode line. The position is obtained 
  by fetching the current location of the physical cursor. 

  Parameters:
     (input/output)   line - pointer to the structure containing the 
                          line being edited in edit mode 

  Returns:            NONE 

**********************************************************************/

init_curpos(line)
EDIT_LINE *line;
{
    /* get cursor position as starting cursor coordinates */
    cursor_pos(&(line->orig_row),&(line->orig_col));

    /* assume empty line, finishing coordinates same as current
       coordinates same as starting coordinates
    */
    line->cur_row = line->max_row = line->orig_row;
    line->cur_col = line->max_col = line->orig_col;

    /* empty line, keyboard display did not scroll */
    line->scrolled_flag = FALSE;

    /* empty line, nothing in keyboard buffer beyond what is displayed
       at bottom of screen
    */
    line->off_screen = FALSE;
}


/*
**********************************************************************

  Routine:            INIT_TEMP_CURPOS 

  Function:
      This routine initializes a structure used for temporarily 
  keeping track of cursor positioning. The values used for 
  initialization are taken from the structure containing the edit 
  mode line and line information. 

  Parameters:
     (input/output)   pos - pointer to the structure for temporarily 
                          keeping track of cursor position 
     (input)          line - pointer to the structure containing the 
                          line and line information for the edit mode 
                          line 

  Returns:            NONE 

**********************************************************************/

init_temp_curpos(pos,line)
CURPOS *pos;
EDIT_LINE *line;
{
    pos->orig_row = line->orig_row;    /* get starting coordinates */
    pos->orig_col = line->orig_col;

    pos->cur_row = line->cur_row;       /* get current coordinates */
    pos->cur_col = line->cur_col;

    pos->max_row = line->max_row;       /* get ending coordinates */
    pos->max_col = line->max_col;

    pos->scroll_flag = FALSE;
}

   



		    kbmvcur.c                       10/12/88  1357.1rew 10/12/88  1331.2      240093



/* ********************************************
   *                                          *
   * Copyright, (C) Honeywell Bull Inc., 1988 *
   *                                          *
   ******************************************** */

/* HISTORY COMMENTS:
  1) change(88-06-13,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Created.
  2) change(88-07-25,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Documentation additions only. Added header comments to all routines.
  3) change(88-08-09,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Fix references to include files; "wstdefs.h" was split into
     "wstdefs.h" and "wsttype.h" to avoid declaration clash; also,
     various constants defined to descriptive names.
                                                   END HISTORY COMMENTS */

#include <dos.h>
#include <ctype.h>
#include "wstdefs.h"
#include "wstglob.h"

/*
**********************************************************************

  Routine:            CURSOR_BOL 

  Function:
      This routine moves the cursor to the beginning of the line. 
  Since the entire input line may span several rows on the screen, 
  this routine may be required to handle the case where the beginning 
  of the line has scrolled off the top of the screen. 

  Parameters:
     (input/output)   line - pointer to the structure containing the 
                          line and information about the line being 
                          edited in edit mode 

  Returns:            NONE 

**********************************************************************/

cursor_bol(line)
EDIT_LINE *line;
{
    int i;

    /* check that line is not empty */
    if (line->index > 0) {

        /* check if beginning of line displayed has scrolled */
        if (line->scrolled_flag) {

            /* need to redraw from beginning of display screen */
            set_cursor(ss.top,ss.left);

            /* blank pad to original display column */
            for (i = ss.left; i < line->orig_col; i++)
                putch(' ');

            /* start coordinates now beginning of screen */
            line->orig_row = ss.top;

            /* no longer scrolled, redisplaying the beginning */
            line->scrolled_flag = FALSE;

            /* set current cursor coordinates */
            line->cur_row = ss.top;
            line->cur_col = line->orig_col;

            /* update the physical cursor location */
            set_cursor(line->cur_row,line->cur_col);
            line->index = 0;

            /* redisplay from beginning of line */
            redisplay(line,line->index,&(line->max_row),&(line->max_col));
        }

        /* no, beginning of line still on display */
        else {

            /* set keyboard buffer index to beginning of line */
            line->index = 0;

            /* move the physical cursor to the beginning of line on
               the display
            */
            line->cur_row = line->orig_row;
            line->cur_col = line->orig_col;
            set_cursor(line->cur_row,line->cur_col);
        }
    }
}


/*
**********************************************************************

  Routine:            CURSOR_EOL 

  Function:
      This routine moves the cursor to the end of the line in edit 
  mode. Since it is possible for the end of the line to be shifted 
  past the end of the screen due to inserting text, this routine has 
  to determine and handle scrolling in this case. 

  Parameters:
     (input/output)   line - pointer to the structure containing the 
                          line and information about the line being 
                          edited in edit mode 

  Returns:            NONE 

  Note 1 - Some care must be taken to maintain consistency in the 
      appearance of the screen when using this and other cursor 
      movement routines. Going to the end of the line using a series 
      of commands to move the cursor to the right or going directly 
      to the end of the line using this routine should yield the same 
      display of the line being edited. 
**********************************************************************/

cursor_eol(line)
EDIT_LINE *line;
{
    int cnt;
    int row;
    int col;
    int screen_width;
    int screen_height;
    int chars_to_pad;
    int i;
    char *ptr, *display_char_str();
    int offset;
    int lines_scrolled;

    /* determine screen width */
    screen_width = ss.right - ss.left + 1;
    screen_height = ss.bottom - ss.top + 1;

    /* get absolute row coordinate */
    row = line->cur_row - ss.top;

    /* get absolute column coordinate */
    col = line->cur_col - ss.left;
    cnt = 0;

    /* determine number of character positions needed to
       display from current cursor position (index) to end of line (in cnt);
       keep track of where the cursor will end up when all text to end
       of line is displayed (in row, col).
    */
    for (i = line->index; i < line->length; i++) {
        cnt += line->size[i];
        row += (col + line->size[i]) / screen_width;
        col = (col + line->size[i]) % screen_width;
    }

    /* if cursor would still be within screen boundary */
    if (row < screen_height) {

        /* just move the cursor to the calculated position */
        line->cur_row = row + ss.top;
        line->cur_col = col + ss.left;
        set_cursor(line->cur_row,line->cur_col);

        /* set current position (index) to end of line position */
        line->index = line->length;
        return;
    }

    else {
        lines_scrolled = row - screen_height + 1;

        /* We want to cursor to end up at the column position
           calculated above (in col) but displayed at the bottom row of the
           screen; determine number of character positions needed
           to fill from the beginning of the screen
        */
        chars_to_pad = (screen_height - 1) * screen_width;
        chars_to_pad += col;

        /* "cnt" contains the number of display locations
           required to display from the end of the line to
           the "i"th character
        */
        cnt = 0;
        for (i = line->length-1; i >= 0; i--) {
            cnt += line->size[i];
            if (cnt >= chars_to_pad)
                break;
        }

        /* if the character locations needed to display the
           entire line is less than that needed to pad to the
           beginning of the line, then line starts within the
           screen display but part of the line extends beyond
           what is displayed on the screen
        */
        if (i < 0 || cnt < chars_to_pad) {

            /* scroll enough lines for the last line to be displayed */
            for (i = 0; i < lines_scrolled; i++)
                wst_scroll();

            /* calculate where the cursor should end up */
            i = 0;
            offset = ((screen_height - 1) * screen_width) + col;
            offset -= cnt;
            row = offset / screen_width;
            col = offset % screen_width;

            row += ss.top;
            col += ss.left;

            /* move the physical cursor to the calculated location */
            set_cursor(row,col);

        }

        /* enough character to pad from the beginning of display to
           end of line starting from the "i"th position
        */
        else {

            /* move physical cursor to start of display screen */
            row = ss.top;
            col = ss.left;
            set_cursor(row,col);

            /* if total display locations starting from character the
               "i"th position is more than that needed to pad to the
               beginning of the screen, then only part of the "i"th
               character displayed needs to be displayed at the beginning
               of the display screen
            */
            if (cnt > chars_to_pad) {

                /* get a pointer to the display string of that character */
                ptr = display_char_str(line->line[i]);

                /* index into the portion of the display string
                   needed to pad to fill the screen
                */
                ptr += strlen(ptr) - (cnt - chars_to_pad);

                /* display that portion of the character string */
                while (*ptr) {
                    putch(*ptr);
                    ptr++;
                    col++;
                }

                /* start redisplay from next character */
                i++;
            }
        }


        /* move keyboard buffer index to end of line */
        line->index = line->length;

        /* initialize coordinates values to where to begin redisplay */
        line->cur_row = row;
        line->cur_col = col;

        /* do the redisplay */
        redisplay(line,i,&(line->max_row),&(line->max_col));

        /* update the start and current cursor coordinates */
        line->cur_row = line->max_row;
        line->cur_col = line->max_col;

        /* check if screen has scrolled */
        line->orig_row -= lines_scrolled;
        if (line->orig_row < ss.top)
            line->scrolled_flag = TRUE;

        /* update location of physical cursor */
        set_cursor(line->cur_row,line->cur_col);
    }
}


/*
**********************************************************************

  Routine:            CURSOR_LEFT 

  Function:
      This routine moves the physical and logical cursor to the 
  previous character in the edit mode line, if that character exists 
  (i.e. when not at the beginning of the line). Since it is possible 
  for part of the line to have scrolled off the top of the screen, 
  this routine has to detect and handle scrolling the line back down. 

  Parameters:
     (input/output)   line - pointer to the structure containing the 
                          line and information about the line being 
                          edited in edit mode 
     (input)          n_times - specifies the number of character 
                          locations to move the cursor backwards (to 
                          the left) 

  Returns:            The actual number of characters that the cursor 
                          was moved back. 

  Note 1 - If the number of characters from the current cursor 
      location to the beginning of the line is less than value 
      specified by 'n_times', the cursor is moved to the beginning of 
      the line. This condition may be checked by the caller by 
      checking if the value passed for 'n_times' is less than the 
      return value. 
**********************************************************************/

cursor_left(line,n_times)
EDIT_LINE *line;
int n_times;
{
    int i;
    int size;
    int row_diff;
    int col_diff;
    int chars_to_bos;
    int screen_width;
    int chars_to_pad;
    int new_index;
    int pad;
    int new_col;
    char *ptr, *display_char_str();
    int actual_times;

    /* don't do anything if at beginning of line or moving left 0 times */
    if (line->index < 1 || n_times < 1)
        return(0);

    /* limit the number of times to move to the number number of */
    /* characters from current position to beginning of line */
    if (n_times > line->index)
        actual_times = line->index;
    else
        actual_times = n_times;

    /* determine the number of display characters to move left from the
       current location and position the line index there
    */
    size = 0;
    for (i = 0; i < actual_times; i++) {
        line->index--;
        size += line->size[line->index];
    }

    /* determine the number of display characters from the current location
       to the beginning of the display window
    */
    row_diff = line->cur_row - ss.top;
    col_diff = line->cur_col - ss.left;
    screen_width = ss.right - ss.left + 1;
    chars_to_bos = (row_diff * screen_width) + col_diff;

    /* handle case for moving left beyond display window origin:
           redisplay() will automatically update to the right of
           the cursor if the current coordinates in line->cur_row
           and line->cur_col are set and the index into the actual
           line buffer is given. The cursor will be on the first
           row of the display window. We need to calculate the column
           position based on the number of times moved left. Also,
           we need to fill the beginning of the first line up to the
           calculated column position since redisplay() won't do it.
    */

    if (chars_to_bos < size) {

        /* need to scroll back, so redraw always start at window origin */

        line->cur_row = ss.top;
        line->cur_col = ss.left;
        set_cursor(line->cur_row,line->cur_col);

        /* determine which column on the starting row that cursor
           should be positioned at
        */

        chars_to_pad = screen_width -
           ((size - chars_to_bos) % screen_width);

        /* handle wrap around case */
        if (chars_to_pad == screen_width) chars_to_pad = 0;

        /* calculate absolute screen coordinates */
        new_col = ss.left + chars_to_pad;

        /* check if updating to the left of cursor is necessary */
        if (chars_to_pad > 0) {

            new_index = line->index - 1;

            pad = 0;
            for (i = new_index; i >= 0; i--) {
                pad += line->size[i];
                if (pad >= chars_to_pad)
                    break;
            }

            /* if not enough characters to pad to beginning of line, then
               line must have started somewhere in the middle of the display
               window, just blank fill the beginning of the line and then
               redisplay
            */
            if (i < 0) {

                for (i = 0; i < chars_to_pad - pad; i++) {
                    line->cur_col++;
                    putch(' ');
                }
                redisplay(line,0,&(line->max_row),&(line->max_col));

                /* set cursor to the column position determined */
                line->cur_col = new_col;
                set_cursor(line->cur_row,line->cur_col);

                return(actual_times);
            }

            /* a single character may need 2 or more characters to display
               the character, e.g. 10 blanks for a tab or \ 0 0 0
               for a NUL. Check if line starts in the middle of
               one of these and if so, print out the portion needed to
               pad the beginning of the line
            */
            if (pad > chars_to_pad) {

                /* get the string representing the current character */
                ptr = display_char_str(line->line[i]);

                /* index into the string the portion needed to pad the line */
                ptr += (strlen(ptr) - (pad - chars_to_pad));

                /* display this portion of the string */
                while (*ptr) {
                    putch(*ptr);
                    ptr++;
                    line->cur_col++;
                }
                /* start redisplaying at the next character in buffer */
                i++;
            }
        }

        /* no padding at beginning of line necessary, redisplay at current
           index position */
        else
            i = line->index;

        redisplay(line,i,&(line->max_row),&(line->max_col));

        /* position the cursor to the calculated location */
        line->cur_row = ss.top;
        line->cur_col = new_col;
        set_cursor(line->cur_row,line->cur_col);

        return(actual_times);
               
    }

    /* final location is still on the screen, back up and reposition there */
    else {
        for (i = 0; i < size; i++) {
            line->cur_col--;
            if (line->cur_col < ss.left) {
                line->cur_col = ss.right;
                line->cur_row--;
            }
        }
        set_cursor(line->cur_row,line->cur_col);
        return(actual_times);
    }
}


/*
**********************************************************************

  Routine:            CURSOR_RIGHT 

  Function:
      This routine moves the physical and logical cursor one 
  character forward (to the right). The routine detects and handles 
  the case of scrolling the screen when the end of the screen is 
  reached. 

  Parameters:
     (input/output)   line - specifies the structure containing the 
                          line and information about the line being 
                          edited in edit mode 
     (input)          n_times - specifies the number of times to the 
                          cursor a character position to the right 

  Returns:            The actual number of times the cursor was moved 
                          forward (to the right) 

  Note 1 - If the number of characters from the current cursor 
      location to the end of the line is less than the value 
      specified by 'n_times', the cursor is moved to the end of the 
      line. This condition may be checked by the caller by checking 
      if the value passed for 'n_times' is less than the return 
      value. 
**********************************************************************/

cursor_right(line,n_times)
EDIT_LINE *line;
int n_times;
{
    int i;
    int size;
    int row_diff;
    int col_diff;
    int chars_to_eos;
    CURPOS tpos;
    int actual_times;
    int chars_to_eol;

    /* check that we're not already at the end of the line */
    if (line->index >= line->length)
        return(0);

    /* determine the number of characters from current cursor position to
       the end of the line
    */
    chars_to_eol = line->length - line->index;

    /* if number of times to move cursor right exceeds number of
       characters to the right of the cursor, set the actual number
       of times to move to the number of characters to the right of cursor
    */
    if (chars_to_eol > n_times)
        actual_times = n_times;
    else
        actual_times = chars_to_eol;

    /* calculate the display columns to move to the right (a character
       may require more than one display column, e.g. tab may require 10)
    */
    size = 0;
    for (i = 0; i < actual_times; i++)
        size += line->size[line->index+i];

    /* calculate the number of display columns to end of screen */
    row_diff = ss.bottom - line->cur_row;
    col_diff = ss.right - line->cur_col;
    chars_to_eos = (row_diff * (ss.right - ss.left + 1)) + col_diff;

    /* determine if new cursor location passes end of screen */
    if (chars_to_eos >= size) {

        /* no, just move calculate where the cursor will end up */
        for (i = 0; i < size; i++) {
            line->cur_col++;
            if (line->cur_col > ss.right) {
                line->cur_col = ss.left;
                line->cur_row++;
            }
        }

        /* move the physical cursor there */
        set_cursor(line->cur_row,line->cur_col);

        /* move keyboard buffer index to the right */
        line->index += actual_times;
    }

    /* new cursor location passes end of screen */
    else {

        /* initialize structure for keeping track of cursor */
        init_temp_curpos(&tpos,line);

        /* display each character (scrolling if necessary)
           until the specified number of characters to the right
           has been displayed
        */
        for (i = 0; i < actual_times; i++) {
            display_char(&tpos,line->line[line->index]);
            line->index++;
        }

        /* update current cursor coordinate values */
        line->cur_row = tpos.cur_row;
        line->cur_col = tpos.cur_col;
        line->orig_row -= tpos.scroll_flag;

        if (line->orig_row < ss.top)
            line->scrolled_flag = TRUE;

        /* redisplay rest of line to end of screen */
        redisplay(line,line->index,&(line->max_row),&(line->max_col));
    }

    /* return the actual amount moved to the right */
    return(actual_times);
}



/*
**********************************************************************

  Routine:            FORWARD_WORD 

  Function:
      This routine moves the physical and logical cursor forward 
  until the end of a word is reached. The number of times this 
  operation is repeated may be specified. 

  Parameters:
     (input/output)   line - pointer to the structure containing the 
                          line and information about the line being 
                          edited in edit mode 
     (input)          n_times - specifies the number of times to move 
                          the cursor forward a word 

  Returns:            NONE 

**********************************************************************/

forward_word(line,n_times)
EDIT_LINE *line;
int n_times;
{
    int i;
    int tmp_index;
    int loop_cnt;

    /* do nothing if already at end of line */
    if (line->index >= line->length) return;

    /* get copy of keyboard buffer index */
    i = line->index;

    loop_cnt = 0;

    /* perform the specified number of times or until end of line reached */
    while (loop_cnt < n_times && i < line->length) {

        /* save index in case no words skipped */
        tmp_index = i;

        /* skip any word delimiters */
        while (i < line->length && is_word_delim(line->line[i]))
            i++;

        /* no next word, do nothing */
        if (i >= line->length) {
            /* restore to position before word delimiters skipped */
            i = tmp_index;
            break;
        }

        /* skip any characters until word delimiter reached */
        while (i < line->length && !is_word_delim(line->line[i]))
            i++;

        /* tally the word skipped */
        loop_cnt++;

    }

    /* move and update cursor only if moved forward at least 1 word */
    if (loop_cnt > 0) {
        /* if keyboard buffer did not change, just return */
        if (i == line->index)
            return;

        /* move the keyboard right the calculated number of times */
        cursor_right(line,i-line->index);
    }
}



/*
**********************************************************************

  Routine:            BACKWARD_WORD 

  Function:
      This routine moves the physical and logical cursor to the 
  beginning of the previous word. The number of times this operation 
  is repeated may be specified. 

  Parameters:
     (input/output)   line - pointer to the structure containing the 
                          line and information about the line being 
                          edited in edit mode 
     (input)          n_times - specifies the number of times to move 
                          the cursor backward a word 

  Returns:            NONE 

**********************************************************************/

backward_word(line,n_times)
EDIT_LINE *line;
int n_times;
{
    int i;
    int tmp_index;
    int loop_cnt;

    /* do nothing if already at beginning of line */
    if (line->index < 1) return;

    /* assume starting at one character before cursor */
    i = line->index - 1;

    loop_cnt = 0;
   /* move specified number of words back or until beginning of line reached */
    while (loop_cnt < n_times && i >= 0) {

        /* save index in case no words skipped */
        tmp_index = i;

        /* skip over any word delimiters */
        while (i >= 0 && is_word_delim(line->line[i]))
            i--;

        /* do nothing if no previous word */
        if (i < 0) {
            /* don't move cursor position if just word delimiters */
            i = tmp_index;
            break;
        }

        /* skip until a word delimiter is reached */
        while (i >= 0 && !is_word_delim(line->line[i]))
            i--;

        /* tally the word skipped */
        loop_cnt++;
    }

    /* move and update cursor only if moved backwards least one word */
    if (loop_cnt > 0) {
        /* restore index position from delimiter reached (or past beginning
           of line) to beginning of word (or start of line)
        */
        i++;

        /* move the cursor left the calculated number of times */
        cursor_left(line,line->index-i);
    }
}



/*
**********************************************************************

  Routine:            IS_WORD_DELIM 

  Function:
      This function, given an ASCII character, specifies whether that 
  character is a word delimiter or not. This function is used by the 
  forward_word and backward_word routines. 

  Parameters:
     (input)          ch - specifies the ASCII character being 
                          checked as a word delimiter character 

  Returns:            TRUE if the specifies character is a word 
                          delimiter 
                      FALSE if the character is NOT a word delimiter 

**********************************************************************/

is_word_delim(ch)
int ch;
{
    /* if valid ASCII character and is a space character, then word delimter */
    if (ch < ASCII_DEL && isspace(ch)) return(TRUE);

    /* check for special punctuations that are not word delimiters */
    if (ch < ASCII_DEL && ispunct(ch)) {
        if (ch == '_' || ch == '$' || ch == '-')
            return(FALSE);
        return(TRUE);
    }
    return(FALSE);
}



/*
**********************************************************************

  Routine:            BACKUP_CURSOR 

  Function:
      This routine just moves the physical cursor backwards a 
  specified number of character positions on the screen and updates 
  the cursor position fields in the structure containing the line and 
  information about the line being edited in edit mode. 

  Parameters:
     (input/output)   line - pointer to the structure containing the 
                          line and information about the line being 
                          edited in edit mode 
     (input)          n_times - specifies the number of times to move 
                          the cursor backwards a character 

  Returns:            NONE 

**********************************************************************/

backup_cursor(line,n_times)
EDIT_LINE *line;
int n_times;
{
    int i;

    /* perform the specified number of times */
    for (i = 0; i < n_times; i++) {

        /* decrement cursor column value */
        line->cur_col--;

        /* past left edge? */
        if (line->cur_col < ss.left) {

            /* go to end of previous line */
            line->cur_col = ss.right;
            line->cur_row--;
        }
    }

    /* update the physical cursor location */
    set_cursor(line->cur_row,line->cur_col);
}
   



		    kbprim.c                        04/24/89  1040.7rew 04/24/89  1032.9       56322



/* ********************************************
   *                                          *
   * Copyright, (C) Honeywell Bull Inc., 1988 *
   *                                          *
   ******************************************** */

/* HISTORY COMMENTS:
  1) change(88-06-13,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Created.
  2) change(88-07-25,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Documentation additions only. Added header comments to all routines.
  3) change(88-08-09,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Fix references to include files; "wstdefs.h" was split into
     "wstdefs.h" and "wsttype.h" to avoid declaration clash; also,
     various constants defined to descriptive names.
  4) change(89-01-18,Lee), approve(89-01-02,MCR8043), audit(89-03-14,Flegel),
     install(89-04-24,MR12.3-1033):
     Separated input and output parameters to int86() to avoid confusion
     when parameters are used.
                                                   END HISTORY COMMENTS */

#include <dos.h>
#include "wstdefs.h"
#include "wstglob.h"

/*
**********************************************************************

  Routine:            GETKEY 

  Function:
      This routine will fetch a keyboard key press. A flag is 
  specified to determine whether the routine should wait blocked if 
  no key was hit or whether to return -1. 

  Parameters:
     (input)          block_flag - if this value is TRUE, the routine 
                          will wait in a blocked state for input; if 
                          false, the routine will return immediately 
                          with an error code if there is not keyboard 
                          key hit 

  Returns:            -1 if 'block_flag' is FALSE and no keyboard key 
                          was pressed 
                      the ASCII character entered from the keyboard, 
                          if otherwise successful 

**********************************************************************/

getkey(block_flag)
int block_flag;
{
    union REGS reg, outreg;
    int cpu_flags;
    int code;

    /* break key hit buffered? */
    if (break_flag) {
        break_flag = FALSE;
        return(BREAK_KEY);
    }

    /* if not block, just do a quick check to see if a hit was hit */
    if (!block_flag) {
        reg.h.ah = BIOS_KB_STATUS;
        cpu_flags = int86(BIOS_KB,&reg,&outreg);
        if (cpu_flags & Z_FLAG_MASK)
            return(-1);
    }

    /* fetch a key, waiting if necessary */
    reg.h.ah = BIOS_KB_READ;
    int86(BIOS_KB,&reg,&outreg);

    /* break key hit after waiting blocked? */
    if (break_flag) {
        break_flag = FALSE;
        return(BREAK_KEY);
    }

    /* if not an extended ASCII code, just return the ASCII code */
    if (outreg.h.al)
        return((int)outreg.h.al);

    /* encode to get a unique extended ASCII value */
    code = ASCII_EXTEND_CODE + outreg.h.ah;
    return(code);
}



/*
**********************************************************************

  Routine:            SET_CURSOR 

  Function:
      This routine moves the physical cursor (the cursor on the 
  screen) to a specified screen coordinate. 

  Parameters:
     (input)          row - specifies which row (with 0 being the top 
                          of the screen) to move to 
     (input)          col - specifies which column (with 0 being the 
                          left of the screen) to move to 

  Returns:            NONE 

  Note 1 - This routine is called by routines other than edit mode 
      keyboard routines. 
**********************************************************************/

set_cursor(row,col)
int row;
int col;
{
    union REGS reg, outreg;

    reg.h.ah = VIDEO_CURSOR_MOVE_FUNC;   /* VIDEO cursor set */
    reg.h.dh = row;
    reg.h.dl = col;
    reg.h.bh = get_active_page();
    int86(BIOS_VIDEO,&reg,&outreg);
}



/*
**********************************************************************

  Routine:            SCROLL_DISPLAY 

  Function:
      This routine scrolls a particular region on the screen one line 
  up, filling the bottom line of the region with a blank line. 

  Parameters:         NONE

  Returns:            NONE 

**********************************************************************/

scroll_display()
{
    union REGS reg,outreg;

    reg.h.ah = VIDEO_SCROLL_UP_FUNC;    /* scroll up function */
    reg.h.al = DEFAULT_LINES_TO_SCROLL; /* number of lines to scroll up */
    reg.h.ch = CURSOR_HOME_ROW;   /* upper left row coordinate to scroll */
    reg.h.cl = CURSOR_HOME_COL;   /* upper left col coordinate to scroll */
    reg.h.dh = MAX_SCREEN_LINE;   /* lower right row coordinate to scroll */
    reg.h.dl = MAX_SCREEN_COL;    /* lower right row coordinate to scroll */
    reg.h.bh = wst_fg_screen.attr;      /* attribute of blank scroll line */
    int86(BIOS_VIDEO,&reg,&outreg);
}



/*
**********************************************************************

  Routine:            DELAY

  Function:
      This function delays for several milliseconds in a tight loop.
  The DOS time function is called to get the current time in hundredth
  of seconds. The resolution of the clock is typically 18.2 ticks
  per second so this routine delays for between 1 and 2 ticks.
  A limit is placed on the number of iterations in the event that
  the clock does not support hundredth of seconds.

  Parameters:         NONE

  Returns:            NONE 

**********************************************************************/

delay ()
{   
    int current_hundredth;
    union REGS reg;
    int ticks;
    int iterations;

    ticks = 0;
    current_hundredth = -1;

    /* limit iterations to 500 */
    for (iterations = 0; iterations < 500; iterations++) {

        /* get system time */
        reg.h.ah = SYSTEM_TIME;
        intdos (&reg, &reg);

        /* clock changed? */
        if (current_hundredth != reg.h.dl) {
            current_hundredth = reg.h.dl;

            /* tally and check for timeout */
            ticks++;
            if (ticks >= 2) break;
        }
    }
}
  



		    kbprocel.c                      04/24/89  1040.7rew 04/24/89  1033.8      269253



/* ********************************************
   *                                          *
   * Copyright, (C) Honeywell Bull Inc., 1988 *
   *                                          *
   ******************************************** */

/* HISTORY COMMENTS:
  1) change(88-06-13,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     created.
  2) change(88-07-11,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Added calls to history recall routines.
  3) change(88-07-22,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Added command keys to capitalize, upper case, lower case,
     transpose words and to transpose characters.
  4) change(88-07-25,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Documentation additions only. Added header comments to all routines.
  5) change(88-08-09,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Fix references to include files; "wstdefs.h" was split into
     "wstdefs.h" and "wsttype.h" to avoid declaration clash; also,
     various constants defined to descriptive names.
  6) change(88-09-16,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Linefeed key (^J) modified to send input line, just like carriage
     return.
  7) change(89-01-18,Lee), approve(89-01-02,MCR8043), audit(89-03-14,Flegel),
     install(89-04-24,MR12.3-1033):
     phx21233 - Modified to support the displaying and re-displaying of echoed
     input only.
                                                   END HISTORY COMMENTS */

#include <dos.h>
#include <ctype.h>
#include "wstdefs.h"
#include "wstglob.h"
#include <wsmincap.h>

/*
**********************************************************************

  Routine:            PROCESS_EDIT_LINE 

  Function:
      This routine calls checks for keyboard input and if detected, 
  passes it to the edit mode keyboard routines for processing. 

  Parameters:
     (input/output)   line - pointer to the structure containing the 
                          line being edited in edit mode 

  Returns:            1 if the <RETURN> key was processed, signifying 
                          the end of editing for the current input 
                          line. 
                      0 otherwise 

  Note 1 - All error handling is done within this module. Line 
      editing errors such as buffer overflow, invalid key, etc. are 
      normally handled by beeping and discarding of the invalid 
      input. 
**********************************************************************/

process_edit_line(line)
EDIT_LINE *line;
{
    int ch;      /* character read in */
    int code;    /* error code */

    /* process only if keyboard key hit */
    if ((ch = getkey(KB_NO_BLOCK)) < 0)
        return(0);

    /* initialize if getting a new line of input; new line if not
       currently handling escape arguments and no input buffered
    */
    if (line->length == 0 && !line->escape_flag && line->escape_arg < 0) {
        init_curpos(line);
        line->index = ZERO_INDEX_VALUE;
    }

    /* handle the character read in */
    code = proc_input(line,ch);
    return(code);
}



/*
**********************************************************************

  Routine:            UPDATE_NUM_LITERAL 

  Function:
      This routine is called to handle the case of the backslash 
  character followed by an octal value. The octal value is converted 
  to an ASCII character and placed into the line buffer. The screen 
  is then updated. 

  Parameters:
     (input/output)   line - pointer to the structure containing the 
                          line (buffer) and information about the 
                          line being edited in edit mode 

  Returns:            NONE 

**********************************************************************/

update_num_literal(line)
EDIT_LINE *line;
{
    CURPOS tpos;

    /* if there are octal digits in backslash escape */
    if (line->literal_dex > 0) {

        /* back up the cursor to whatever number of octal digits were
           entered plus one more for the backslash in preparation for
           over-writing the backslash escape sequence
        */
        if (kb.echo)    /* phx21233 R.L. - backup only if echo enabled */
            backup_cursor(line,line->literal_dex+1);

        /* initialize cursor information structure */
        init_temp_curpos(&tpos,line);

        /* null terminate the octal string entered */
        line->literal_buff[line->literal_dex] = NUL_TERMINATOR;

        /* convert octal string to ASCII value and assign to current
           character in keyboard buffer
        */
        line->line[line->index] = octal_val(line->literal_buff);

        /* redisplay it */
        line->size[line->index] = display_char(&tpos,line->line[line->index]);

        /* position to next keyboard character */
        line->index++;

        /* update screen cursor position in line structure */
        line->cur_row = tpos.cur_row;
        line->cur_col = tpos.cur_col;
        line->orig_row -= tpos.scroll_flag;
        if (line->orig_row < ss.top)
            line->scrolled_flag = TRUE;

        /* redisplay rest of line after the current character */
        redisplay(line,line->index,&(line->max_row),&(line->max_col));

        /* reset index to indicate not processing backslash escape */
        line->literal_dex = ZERO_INDEX_VALUE;
    }

    /* no octal digits, only backslash entered; backslash is already
       displayed, just position to next keyboard character
    */
    else
        line->index++;

    /* reset escape argument flags */
    line->escape_flag = NO_ESC_FUNC;
    line->escape_arg = NO_ESC_ARG;
}



/*
**********************************************************************

  Routine:            UPDATE_NON_PRT_LITERAL 

  Function:
      This routine handles input from the keyboard for the case of a 
  backslash followed by a non-printable character. The character is 
  put into the line buffer and the screen is then updated. 

  Parameters:
     (input/output)   line - pointer to the structure containing the 
                          line (buffer) and information about the 
                          line being edited in edit mode 
     (input)          ch - specifies the non-printable ASCII 
                          character following the backslash that was 
                          entered 

  Returns:            NONE 

**********************************************************************/

update_non_prt_literal(line,ch)
EDIT_LINE *line;
int ch;          /* the non-printable character following backslash */
{
    CURPOS tpos;

    /* back the cursor over the backslash */
    if (kb.echo)    /* phx21233 R.L. - backup only if echo enabled */
        backup_cursor(line,1);

    /* initialize cursor information */
    init_temp_curpos(&tpos,line);

    /* current keyboard character is assigned the non-printable character */
    line->line[line->index] = ch;

    /* display the non-printable character */
    line->size[line->index] = display_char(&tpos,ch);

    /* position to next keyboard character */
    line->index++;

    /* update the cursor information in the line structure */
    line->cur_row = tpos.cur_row;
    line->cur_col = tpos.cur_col;
    line->orig_row -= tpos.scroll_flag;
    if (line->orig_row < ss.top)
        line->scrolled_flag = TRUE;

    /* display the line following the non-printable character */
    redisplay(line,line->index,&(line->max_row),&(line->max_col));

    /* reset escape argument flags */
    line->escape_flag = NO_ESC_FUNC;
    line->escape_arg = NO_ESC_ARG;
}



/*
**********************************************************************

  Routine:            PROC_INPUT 

  Function:
      This routine handles keyboard input in edit mode a key at a 
  time. The module examines the key to determine whether it is to be 
  handled as text input or as an editing key. Also, numeric escape 
  argument (such as "<ESC> 3" to repeat a command 3 times) and 
  literal escaping (such as "\ <BACKSPACE>") is detected and 
  processed by this routine. 

  Parameters:
     (input/output)   line - pointer to the structure containing the 
                          line and information about the line being 
                          edited in edit mode 
     (input)          key - specifies the keyboard key, ASCII or 
                          function or ALT key, which was entered 
                          while in edit mode 

  Returns:            1 if the <RETURN> key was processed, signifying 
                          the end of editing for the current line 
                      0 otherwise 

  Note 1 - All error handling is done within this module. Line 
      editing errors such as buffer overflow, invalid key, etc. are 
      normally handled by beeping and discarding the invalid input. 
**********************************************************************/

proc_input(line,key)
EDIT_LINE *line;
int key;
{
    int ch;
    int code;

    ch = key;

    /* check and map DEL, ^2 and ^BREAK keys */
    if (ch > ASCII_EXTEND_CODE) {

        /* map PC's DEL key to ASCII DEL */
        if (ch == DEL_KEY)
            ch = ASCII_DEL;

        /* map PC's ^2 key to ASCII NUL */
        else if (ch == NULL_KEY)
            ch = ASCII_NUL;

        /* map PC's ^BREAK to ALT_B; BREAK_KEY code is generated only
           if WSTERM's /B command argument is specified
        */
        else if (ch == BREAK_KEY)
            ch = ALT_B;
    }
 
    /* check if previous key was an escape or literal escape and
       that current key is not a function or ALT key
    */
    if (line->escape_flag > NO_ESC_FUNC) {

        /* previous key was a backslash */
        if (line->escape_flag == KB_LITERAL_ESC) {

            /* if function or ALT key, update the backslash and fall through */
            if (ch > ASCII_EXTEND_CODE)
                update_num_literal(line);

            /* check for octal digit */
            else if (ch >= SMALLEST_OCTAL_DIGIT && ch <= LARGEST_OCTAL_DIGIT) {
                /* display the digit and insert keep track in line structure */
                insert_display_char(line,ch);

                /* if three octal digits entered, process octal sequence */
                if (line->literal_dex >= MAX_OCTAL_SEQ_DIGITS) {
                    update_num_literal(line);
                }
                return(0);
            }

            /* handle backslash followed by non-printable character */
            else if (line->literal_dex == ZERO_INDEX_VALUE &&
                (ch < MIN_PRINTABLE_ASCII ||
                 ch > MAX_PRINTABLE_ASCII ||
                 ch == char_erase ||
                 ch == line_kill)) {
                update_non_prt_literal(line,ch);
                return(0);
            }

            /* backslash followed by a printable character */
            else if (ch < ASCII_DEL) {

                if (line->literal_dex == ZERO_INDEX_VALUE) {

                    /* update line structure */
                    update_num_literal(line);

                    /* if backslash followed by backslash, don't process
                       second backslash
                    */
                    if (ch == lnc) return(0);

                    /* fall through and handle the printable character */
                }

                /* backslash octal sequence followed by printable */
                else
                    /* update backslash sequence character first */
                    update_num_literal(line);

                    /* fall through and handle the printable char */
            }
        }

        /* check for escape key numeric argument */
        else if (ch >= SMALLEST_DECI_DIGIT && ch <= LARGEST_DECI_DIGIT) {

            /* if previous key was the escape key and no previous arguments */
            if (line->escape_flag == KB_PREV_KEY_ESC && line->escape_arg < 0)
                /* set initial escape argument */
                line->escape_arg = ch - '0';

            /* calculate into previously initialize escape argument */
            else if (line->escape_arg < MAX_ARG_LIMIT) {
                line->escape_arg *= 10;
                line->escape_arg += ch - '0';
            }

            /* change flag to indicate currently handling numeric arg */
            line->escape_flag = KB_HANDLING_ESC_ARG;
            return(0);
        }

        /* previous key was escape key, check for escape editing sequence */
        else if (line->escape_flag == KB_PREV_KEY_ESC) {
            code = handle_esc_editkeys(line,ch);
            return(code);
        }
    }

    /* handle the character as an edit key */
    code = handle_editkeys(line,ch);

    /* return if handled as an edit key */
    if (code >= 0)
        return(code);

    /* Handle adding straight text */
    if (ch < ASCII_DEL) {
        if (line->escape_arg < 0)
            add_text(line,ch,1);
        else
            add_text(line,ch,line->escape_arg);

        line->escape_flag = NO_ESC_FUNC;
        line->escape_arg = NO_ESC_ARG;
        return(0);
    }

    /* handle remaining function or ALT key hit */
    else if (ch > ASCII_EXTEND_CODE) {
        local_esc(ch - ASCII_EXTEND_CODE); /* pass it decoded scan code */
        return(0);
    }

    /* reinitialize escape argument flags and beep */
    line->escape_flag = NO_ESC_FUNC;
    line->escape_arg = NO_ESC_ARG;
    beep();
    return(0);
}



/*
**********************************************************************

  Routine:            HANDLE_ESC_EDITKEYS 

  Function:
      This routine handles editing keys which are preceeded by the 
  ESC key, e.g. ESC D (delete word). 

  Parameters:
     (input/output)   line - pointer to the structure containing the 
                          line and information about the line being 
                          edited in edit mode 
     (input)          ch - specifies which escape edit key is being 
                          handled 

  Returns:            -1 if the key specified is not a recognized 
                          escape editing key 
                      0 otherwise 

  Note 1 - Unrecognized keys are handled by beeping. Flags in the 
      line structure indicating numeric escape arguments and esc key 
      being hit are all reset regardlessly before this routine 
      returns. 
**********************************************************************/

handle_esc_editkeys(line,ch)
EDIT_LINE *line;
int ch;
{
    int arg_val;
    int error_code;

    /* initialize error code to pass back */
    error_code = 0;

    /* if no numeric argument given, assume action is done once */
    if (line->escape_arg < 0)
        arg_val = 1;

    /* otherwise perform as many times as specified by numeric argument */
    else
        arg_val = line->escape_arg;

    /* handle any recognized escape edit keys */
    /*  ... the variable 'code' is set to zero if key is recognized */
    switch (ch) {

        /* esc b, backward cursor word */
        case 'b':
        case 'B':
            /* perform for specified number of times */
            backward_word(line,arg_val);
            break;

        /* esc f, forward cursor word */
        case 'f':
        case 'F':
            /* perform for specified number of times */
            forward_word(line,arg_val);
            break;

        /* esc d, delete forward word */
        case 'd':
        case 'D':
            /* perform for specified number of times */
            forward_delete_word(line,arg_val);
            break;

        /* esc DEL, delete backward word */
        case BACKSPACE:
        case ASCII_DEL:
            /* perform for specified number of times */
            backward_delete_word(line,arg_val);
            break;

        /* esc U, upper case word */
        case 'u':
        case 'U':
            change_case_word(line,KB_UPPER_CASE);
            break;

        /* esc L, lower case word */
        case 'l':
        case 'L':
            change_case_word(line,KB_LOWER_CASE);
            break;

        /* esc C, capitalize word */
        case 'c':
        case 'C':
            change_case_word(line,KB_CAPITALIZED);
            break;

        /* esc T, transpose positions of previous two words */
        case 't':
        case 'T':
            transpose_words(line);
            break;

        /* esc Y, yank previous item from yank buffer */
        case 'y':
        case 'Y':
            yank_previous(line);
            break;

        /* key not a recognized escape edit key */
        default:
            beep();
            error_code = -1;
    }

    /* reset escape flag and argument */
    line->escape_flag = NO_ESC_FUNC;
    line->escape_arg = NO_ESC_ARG;

    return(error_code);
}



/*
**********************************************************************

  Routine:            HANDLE_EDITKEYS 

  Function:
      This routine examines a specified key to see if it is an 
  editing or ALT key. If so, it calls the appropriate routines to 
  handle the editing or ALT function, otherwise nothing is changed 
  and an error code is returned. 

  Parameters:
     (input/output)   line - pointer to the structure containing the 
                          line and information about the line being 
                          edited in edit mode 
     (input)          ch - specifies the key whose function needs to 
                          be identified and handled 

  Returns:            -1 if the key is not an editing key or special 
                          ALT key 
                      0 otherwise 

**********************************************************************/

handle_editkeys(line,ch)
EDIT_LINE *line;
int ch;
{
    int n_times;

    /* check for erase, kill or lnc; these characters are variable */
    if (ch == lnc) {

        /* handle literal escape character */
        /* add and display the literal escape character */
        if (add_char(line,ch))
            line->escape_flag = KB_LITERAL_ESC;

        /* error, must line must be full */
        else {
            /* reset escape argument and flag and beep */
            line->escape_flag = NO_ESC_FUNC;
            line->escape_arg = NO_ESC_ARG;
            beep();
        }
        return(0);
    }

    else if (ch == char_erase || ch == BACKSPACE || ch == ASCII_DEL) {
        /* delete previous character */
        /* check for escape numeric argument */
        if (line->escape_arg < 0) {
            if (cursor_left(line,1) > 0)
                delete_chars(line,1,NO_KILLBUFF_SAVE);
        }
        else {
            n_times = cursor_left(line,line->escape_arg);
            delete_chars(line,n_times,NO_KILLBUFF_SAVE);
        }

        /* reset escape argument and flag */
        line->escape_flag = NO_ESC_FUNC;
        line->escape_arg = NO_ESC_ARG;
        return(0);
    }

    else if (ch == line_kill) {
        /* kill line */
        /* preceeded by literal escape char? */

        /* kill to beginning of line */
        kill_to_bol(line);

        /* reset escape argument and flag */
        line->escape_flag = NO_ESC_FUNC;
        line->escape_arg = NO_ESC_ARG;
        return(0);
    }

    switch (ch) {

        /* handle escape character */
        case ESC:
            /* if not handling an escape sequence or handling an
               escape numeric argument
            */
            if (line->escape_flag == NO_ESC_FUNC || line->escape_flag == 2)

                /* set to indicate previous key was an escape key */
                line->escape_flag = KB_PREV_KEY_ESC;

            /* escape followed by escape, reset flags and beep */
            else {
                line->escape_flag = NO_ESC_FUNC;
                line->escape_arg = NO_ESC_ARG;
                beep();
            }
            return(0);

        case TAB:
            return(-1);   /* not an editing key, treat as text */

        /* handle return key */
        case LINEFEED:
        case RETURN_KEY:
            kb_edit_lf_return(line,ch);

            /* reset escape argument and flag */
            line->escape_flag = NO_ESC_FUNC;
            line->escape_arg = NO_ESC_ARG;
            return(1);

        /* move cursor one character to the left */
        case LEFT_ARROW_KEY:
        case CTRL_B:
            /* check for escape numeric argument */
            if (line->escape_arg < 0)
                cursor_left(line,1);
            else
                cursor_left(line,line->escape_arg);

            /* reset escape argument and flag */
            line->escape_flag = NO_ESC_FUNC;
            line->escape_arg = NO_ESC_ARG;
            return(0);

        /* move cursor one character to the right */
        case RIGHT_ARROW_KEY:
        case CTRL_F:
            /* check for escape numeric argument */
            if (line->escape_arg < 0)
                cursor_right(line,1);
            else
                cursor_right(line,line->escape_arg);

            /* reset escape argument and flag */
            line->escape_flag = NO_ESC_FUNC;
            line->escape_arg = NO_ESC_ARG;
            return(0);

        /* toggle editing replace/insert mode */
        case ALT_I:
        case INS_KEY:

            /* toggle line edit flag */
            line->mode = !line->mode;

            /* update the mode change on status line */
            update_status();
            return(0);

        /* move cursor to beginning of line */
        case CTRL_A:
        case HOME_KEY:
            cursor_bol(line);

            /* reset escape argument and flag */
            line->escape_flag = NO_ESC_FUNC;
            line->escape_arg = NO_ESC_ARG;
            return(0);

        /* delete current character */
        case CTRL_D:
            /* check for escape numeric argument */
            if (line->escape_arg < 0)
                delete_chars(line,1,NO_KILLBUFF_SAVE);
            else
                delete_chars(line,line->escape_arg,NO_KILLBUFF_SAVE);

            /* reset escape argument and flag */
            line->escape_flag = NO_ESC_FUNC;
            line->escape_arg = NO_ESC_ARG;
            return(0);

        /* move cursor to end of the line */
        case CTRL_E:
        case END_KEY:
            cursor_eol(line);

            /* reset escape argument and flag */
            line->escape_flag = NO_ESC_FUNC;
            line->escape_arg = NO_ESC_ARG;
            return(0);

        /* kill to the end of the line */
        case CTRL_K:
            kill_to_eol(line);

            /* reset escape argument and flag */
            line->escape_flag = NO_ESC_FUNC;
            line->escape_arg = NO_ESC_ARG;
            return(0);

        /* forward word */
        case CTRL_RIGHT_ARROW_KEY:

            /* handle no numeric argument */
            if (line->escape_arg < 0)
                forward_word(line,1);

            /* handle numeric argument */
            else
                forward_word(line,line->escape_arg);

            /* reset escape flag and argument */
            line->escape_flag = NO_ESC_FUNC;
            line->escape_arg = NO_ESC_ARG;
            return(0);

        /* backward word */
        case CTRL_LEFT_ARROW_KEY:

            /* handle no numeric argument */
            if (line->escape_arg < 0)
                backward_word(line,1);

            /* handle numeric argument */
            else
                backward_word(line,line->escape_arg);

            /* reset escape flag and argument */
            line->escape_flag = NO_ESC_FUNC;
            line->escape_arg = NO_ESC_ARG;
            return(0);

        /* fetch and display previous history command */
        case CTRL_P:
        case UP_ARROW_KEY:

            /* no escape argument specified? */
            if (line->escape_arg < 0) {

                /* check for unsuccessful retrieval of history      */
                /* command                                          */
                if (fetch_previous_command(1,line->line,&(line->length)) < 0) {
                    line->escape_flag = NO_ESC_FUNC;
                    line->escape_arg = NO_ESC_ARG;
                    return(0);
                }
            }

            /* handle escape argument */
            else {
                /* fetch unsuccessful? */
                if (fetch_nth_command(line->escape_arg,
                    line->line,&(line->length)) < 0) {
                    line->escape_flag = NO_ESC_FUNC;
                    line->escape_arg = NO_ESC_ARG;
                    return(0);
                }
            }

            /* phx21233 R.L. - update echo flags to determine visibility */
            /*    of chars redrawn */
            update_echo_flags(line);

            /* history command successfully extracted, erase the    */
            /* existing command from the screen, reset the escape   */
            /* flags and display the new command                    */

            erase_edit_line(line);
            line->index = 0;
            line->escape_flag = NO_ESC_FUNC;
            line->escape_arg = NO_ESC_ARG;
            redraw_edit_line(line);
            cursor_eol(line);
            return(0);


        /* fetch next history command */
        case CTRL_N:
        case DOWN_ARROW_KEY:

            /* no escape argument specified? */
            if (line->escape_arg < 0) {

                /* unsuccessful history command retrieval? */
                if (fetch_next_command(1,line->line,&(line->length)) < 0) {
                    line->escape_flag = NO_ESC_FUNC;
                    line->escape_arg = NO_ESC_ARG;
                    return(0);
                }
            }

            /* handle escape argument */
            else {

                /* unsuccessful history command retrieval? */
                if (fetch_next_command(line->escape_arg,
                    line->line,&(line->length)) < 0) {
                    line->escape_flag = NO_ESC_FUNC;
                    line->escape_arg = NO_ESC_ARG;
                    return(0);
                }
            }

            /* phx21233 R.L. - update echo flags to determine visibility */
            /*    of chars redrawn */
            update_echo_flags(line);

            /* history line successfully retrieved, erase existing  */
            /* input line from screen, initialize line flags and    */
            /* display the new input line                           */

            erase_edit_line(line);
            line->index = 0;
            line->escape_flag = NO_ESC_FUNC;
            line->escape_arg = NO_ESC_ARG;
            redraw_edit_line(line);
            cursor_eol(line);
            return(0);

        /* transpose the two characters preceeding the cursor */
        case CTRL_T:
            transpose_chars(line);

            /* reset escape argument and flag */
            line->escape_flag = NO_ESC_FUNC;
            line->escape_arg = NO_ESC_ARG;
            return(0);

        /* yank item from the kill buffer */
        case CTRL_Y:
            /* phx21233 R.L. - kill/yank disabled while not echoing */
            if (!kb.echo) {
                beep();
                return(0);
            }
            yank(line);
            line->escape_flag = NO_ESC_FUNC;
            line->escape_arg = NO_ESC_ARG;
            return(0);

        /* handle invalid editing key */
        default:
            /* handle any other control character by beeping */
            if (ch < MIN_PRINTABLE_ASCII) {
                line->escape_flag = NO_ESC_FUNC;
                line->escape_arg = NO_ESC_ARG;
                beep();
                return(0);
            }
            /* Could be text or ALT or FUNCTION key; indicate not an */
            /* editing key */
            return(-1);
    }
}



/*
**********************************************************************

  Routine:            OCTAL_VAL 

  Function:
      This routine converts the ASCII string containing an octal 
  representation to an integer value. 

  Parameters:
     (input)          str - pointer to the ASCII string containing 
                          the representation of an octal value 

  Returns:            the integer value after conversion 

  Note 1 - The string is assumed to contain only octal digits. 
**********************************************************************/

octal_val(str)
char *str;
{
    int sum;

    /* initialize sum */
    sum = 0;

    /* while not end of string */
    while (*str) {

        /* multiply by octal base */
        sum *= OCTAL_BASE_VALUE;

        /* add value of current octal digit */
        sum += *str - ASCII_ZERO_BASE;

        /* increment to next character */
        str++;
    }

    /* return the converted value */
    return(sum);
}


/*
**********************************************************************

  Routine:            UPDATE_ECHO_FLAGS

  Function:
     This function updates the echo status of all input characters
  buffered in the edit mode input line.  If keyboard echoing is enabled,
  all characters are flagged as visible otherwise they are flagged
  invisible.

  Parameters:
     (input)          line - pointer to the structure containing the
                          edit mode input line

  Returns:            NONE

**********************************************************************/

update_echo_flags(line)
EDIT_LINE *line;
{
    int i;
    int echo_flag;

    /* determine echo status */
    if (kb.echo)
        echo_flag = TRUE;
    else
        echo_flag = FALSE;

    /* update display lengths of each character in the input line */
    for (i = 0; i < line->length; i++)
        line->size[i] = echo_flag;
}
   



		    kbredraw.c                      04/24/89  1040.7rew 04/24/89  1033.4       47889



/* ********************************************
   *                                          *
   * Copyright, (C) Honeywell Bull Inc., 1988 *
   *                                          *
   ******************************************** */

/* HISTORY COMMENTS:
  1) change(88-06-13,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Created.
  2) change(88-07-25,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Documentation additions only. Added header comments to all routines.
  3) change(88-08-09,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Fix references to include files; "wstdefs.h" was split into
     "wstdefs.h" and "wsttype.h" to avoid declaration clash; also,
     various constants defined to descriptive names.
  4) change(89-01-18,Lee), approve(89-01-02,MCR8043), audit(89-03-14,Flegel),
     install(89-04-24,MR12.3-1033):
     phx21233 - Changed to display only echoed input characters when redrawing
     input line.
                                                   END HISTORY COMMENTS */

#include <dos.h>
#include "wstdefs.h"
#include "wstglob.h"

/*
**********************************************************************

  Routine:            ERASE_EDIT_LINE 

  Function:
      This routine erases the portion of the screen which displays 
  the input line; the contents and the state of the line buffer 
  itself is not changed. 

  Parameters:
     (input)          line - pointer to the structure containing the 
                          line (buffer) and information about the 
                          line being edited in edit mode 

  Returns:            NONE 

**********************************************************************/

erase_edit_line(line)
EDIT_LINE *line;
{
    int row;
    int col;

    /* determine if input line displayed has scrolled off the top */
    if (line->scrolled_flag) {
        /* yes, start at beginning of display */
        row = ss.top;
        col = ss.left;
    }

    /* did not scroll off top */
    else {
        /* start at beginning line coordinates */
        row = line->orig_row;
        col = line->orig_col;
    }

    /* update physical location to starting coordinates for erase */
    line->cur_row = row;
    line->cur_col = col;
    set_cursor(row,col);

    /* blank pad the screen until ending input line coordinates reached */
    while (row < line->max_row) {
        if (col > ss.right) {
            col = ss.left;
            row++;
            set_cursor(row,col);
        }
        else {
            putch(' ');
            col++;
        }
    }

    if (row == line->max_row) {
        while (col <= line->max_col) {
            putch(' ');
            col++;
        }
    }

    /* move physical cursor back to current line position */
    set_cursor(line->cur_row,line->cur_col);

    /* ending screen coordinates now just the current line coordinates */
    line->max_row = line->cur_row;
    line->max_col = line->cur_col;
}



/*
**********************************************************************

  Routine:            REDRAW_EDIT_LINE 

  Function:
      This routine redisplays the edit mode line. Its function is to 
  allows redrawing of the edited line at another location. 

  Parameters:
     (input/output)   line - pointer to the structure containing the 
                          line and information about the line being 
                          edited 

  Returns:            TRUE always 

  Note 1 - The cursor position fields are updated. 
  Note 2 - The user may be in the middle of entering a literal escape 
      sequence (e.g. \030) when this routine is called so care must 
      be taken to identify and replicate the way the line was 
      displayed for this case as well. 
**********************************************************************/

redraw_edit_line(line)
EDIT_LINE *line;
{
    CURPOS tpos;
    int pos;
    int i;

    /* initialize structure for keeping track of cursor */
    init_temp_curpos(&tpos,line);

    /* redisplay from beginning of line until current index position */
    for (i = 0; i < line->index; i++)
        /* phx21233 R.L. - redisplay and re-initialize only echoed input */
        if (line->size[i])
            line->size[i] = display_char_prim(&tpos,line->line[i]);

    /* in the middle of handling literal escape sequence? */
    if (line->escape_flag == KB_LITERAL_ESC && line->literal_dex > 0) {

        /* if so, display the portion of the literal escape sequence */
        display_char(&tpos,line->line[i]);

        /* finish redraw at next character position */
        pos = i + 1;
        for (i = 0; i < line->literal_dex; i++)
            display_char(&tpos,line->literal_buff[i]);
    }

    /* not processing literal escape, just finish redraw at current position */
    else
        pos = i;

    /* update the cursor coordinate information */
    line->cur_row = tpos.cur_row;
    line->cur_col = tpos.cur_col;
    line->orig_row -= tpos.scroll_flag;
    if (line->orig_row < ss.top)
        line->scrolled_flag = TRUE;

    /* redisplay rest of line (or until end of screen reached) */
    redisplay(line,pos,&(line->max_row),&(line->max_col));
    return(TRUE);
}

   



		    save.asm                        10/12/88  1401.1rew 10/12/88  1327.6       56637



; ***********************************************************
; *                                                         *
; * Copyright, (C) Honeywell Bull Inc., 1987                *
; *                                                         *
; * Copyright, (C) Honeywell Information Systems Inc., 1986 *
; *                                                         *
; ***********************************************************

; HISTORY COMMENTS:
;  1) change(88-03-22,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel):
;     Created.
;  2) change(88-09-01,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel):
;     Modified to get active page from BIOS segment rather
;     than assuming page 0 is the active page.
;                                                      END HISTORY COMMENTS
;
;FUNCTION (save_screen,restore_screen)
;
; Save the contents of the display to a user-specified buffer.
; Restore the contents of the display from a user-specified buffer.
; Only the first 24 lines of the screen will be saved.
;
;*/

include dos.mac                 ;Lattice include file

;*******************************************************************
;                                       DATA
;*******************************************************************

;define variables which are maintained by BIOS in the BIOS segment

BIOS_SEG	SEGMENT AT 0040H
	org	0050H
cursor_posn	dw ?        ; holds cursor coordinates kept by BIOS
     org  0062H
active_page    db ?        ; contains current active page

BIOS_SEG	ends


dseg
; constants

BIOS_VIDEO = 10h           ; BIOS video interrupt call
BIOS_SET_CURSOR = 2        ; BIOS video set cursor position function number
BIOS_GET_CURSOR = 3        ; BIOS video get cursor position function number
BIOS_READ_CHR_ATTR = 8     ; BIOS video get character and attributes number
BIOS_WRITE_CHR_ATTR = 9    ; BIOS video write character and attributes number
DISPLAY_WIDTH = 80         ; number of columns across displayed
DISPLAY_HEIGHT = 24        ; number of lines displayed

endds

page
;**************************************************************************
;                               Program mainline
;**************************************************************************
;

pseg

public	save_screen
public	restore_screen
public    get_active_page

; save_screen(buffer)

save_screen	proc	near
	push		bp		           ; save registers used
     push      di
     push      dx
	push      cx
     push      bx
     push      es
	push		si
	mov		bp,sp	           ; set up pointer to arguments
	mov		di,[bp+16]           ; fetch argument (pointer to user-buffer)

	mov		ax,BIOS_SEG          ; BIOS segment
     mov       es,ax                ; use es to reference into BIOS segment
     call		get_active_page	 ; get active page in al
	mov		si,ax                ; save active page in si
     sal       si,1                 ; times 2 to index word offset
	mov		bh,al                ; save current active page
	mov		ah,BIOS_GET_CURSOR   ; get cursor position
	int		BIOS_VIDEO           ; BIOS video interrupt
	push		dx	                ; save cursor coordinates
	xor		dx,dx                ; set cursor position to 0,0

save_loop:
	mov		es:cursor_posn[si],dx    ; get cursor coordinates
	mov		ah,BIOS_READ_CHR_ATTR  ; get character and attribute at position
	int		BIOS_VIDEO
	mov		[di],ax              ; save into buffer
	inc		di	                ; increment buffer pointer
	inc		di
	inc		dl                   ; increment column position
	cmp		dl,DISPLAY_WIDTH	 ; past 80th column?
	jl		save_loop
	mov		dl,0		           ; reset column to 0
	inc		dh
	cmp		dh,DISPLAY_HEIGHT	 ; past 24th line?
	jl		save_loop            ; repeat for next line if not

	pop		dx		           ; restore previous cursor coordinates
	mov		ah,BIOS_SET_CURSOR
	int		BIOS_VIDEO

	pop		si
     pop       es                   ; restore registers
     pop       bx
	pop		cx
     pop       dx
     pop       di
	pop		bp

	ret                            ; return to caller

save_screen	endp


; restore_screen(buffer)

restore_screen	proc	near
	push		bp                   ; save registers used
     push      di
     push      bx
	push		cx
     push      dx
     push      es
     push		si
	mov		bp,sp                ; set up pointer to arguments
	mov		di,[bp+16]           ; fetch argument (pointer to user buffer)

	mov		ax,BIOS_SEG          ; BIOS segment
     mov       es,ax                ; use es to reference into BIOS segment

     call      get_active_page      ; get current active page in al
     mov       si,ax			 ; save active page in si
     sal       si,1                 ; times 2 to index word offset
	mov		bh,al	           ; get from current active page
	mov		ah,BIOS_GET_CURSOR   ; get cursor position
	int		BIOS_VIDEO		 ; BIOS video routine
	push		dx		           ; save cursor coordinates

	xor		dx,dx	           ; set cursor position to 0,0
	mov		cx,1		           ; number of characters for writing character
restore_loop:
	mov		es:cursor_posn[si],dx    ; get cursor coordinates
	mov		ax,[di]	           ; get character from buffer
	mov		bl,ah
	mov		ah,BIOS_WRITE_CHR_ATTR ; write character & attributes
	int		BIOS_VIDEO
	inc		di		           ; increment buffer pointer
	inc		di
	inc		dl		           ; increment column position
	cmp		dl,DISPLAY_WIDTH	 ; past 80th column?
	jl		restore_loop
	mov		dl,0		           ; reset column to 0
	inc		dh
	cmp		dh,DISPLAY_HEIGHT	 ; past 24th line?
	jl		restore_loop         ; repeat for next line if not

	pop		dx		           ; restore previous cursor coordinates
	mov		ah,BIOS_SET_CURSOR 
	int		BIOS_VIDEO

     pop		si
     pop       es                   ; restore registers
     pop       dx
     pop       cx
     pop       bx
     pop       di
	pop		bp

	ret                            ; return to caller
restore_screen	endp


; get_active_page() - this routine returns the active page in register
;    al; the active page is obtained from a variable in the BIOS segment.

get_active_page proc near
	push		es				; save segment register
	mov		ax,BIOS_SEG		; get address of BIOS segment
	mov       es,ax			; reference BIOS segment with es
     mov		al,es:active_page	; fetch active page from BIOS segment
     pop		es				; restore segment register
	ret
get_active_page endp

endps
      end
   



		    status.c                        04/24/89  1040.7rew 04/24/89  1032.8       84069



/* ********************************************
   *                                          *
   * Copyright, (C) Honeywell Bull Inc., 1988 *
   *                                          *
   ******************************************** */

/* HISTORY COMMENTS:
  1) change(88-04-26,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Created.
  2) change(88-07-25,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Documentation additions only. Added header comments to all routines.
  3) change(88-08-09,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Fix references to include files; "wstdefs.h" was split into
     "wstdefs.h" and "wsttype.h" to avoid declaration clash; also,
     various constants defined to descriptive names.
  4) change(89-01-18,Lee), approve(89-01-02,MCR8043), audit(89-03-14,Flegel),
     install(89-04-24,MR12.3-1033):
     Separated input and output parameters to int86() to avoid confusion
     when parameters are used.
                                                   END HISTORY COMMENTS */

#include <stdio.h>
#include <dos.h>
#include "wstdefs.h"
#include "wstglob.h"

/* status line should look like:
A  Edit Replace Audit(FILE,PRINTER) Paging No-Scroll [Background] [Foreground]
*/


/*
**********************************************************************

  Routine:            UPDATE_STATUS 

  Function:
      This routine updates the status line to reflect the current 
  mode settings. The current mode settings are obtained by examining 
  global flags. 

  Parameters:         NONE 

  Returns:            NONE 

  Note 1 - This routine should only be called while in the foreground 
      screen as the status line is used to display other information 
      while in other screens. 
**********************************************************************/

update_status()
{
    char *wsterm_mode_str;
    char *edit_mode_str;
    char *kb_mode_str;
    char audit_str[32];  /* enough to hold "Audit(FILE,PRINTER)" */
    char *page_str;
    char *scroll_str;
    char printbuff[SCREEN_COLS+1];

    /* determine WSTERM's mode */
    if (~mowse_active)           /* GLASS TTY MODE */
        wsterm_mode_str = "G";
    else if (sync)
        wsterm_mode_str = "S";   /* SYNC MODE */
    else
        wsterm_mode_str = "A";   /* ASYNC MODE */

    kb_mode_str = "";

    /* edit mode disabled in synchronous packet mode */
    if (mowse_active && sync)
        edit_mode_str = "";

    /* if edit mode is otherwise enabled */
    else if (wst_edit_mode) {
        edit_mode_str = "Edit";
        /* update kb ins/repl mode here as well */
        if (edlin.mode)
            kb_mode_str = "Insert";
        else
            kb_mode_str = "Replace";
    }

    /* edit mode is disabled */
    else
        edit_mode_str = "";

    /* determine audit mode modes */
    *audit_str = 0;
    if (wst_f_audit) {
        strcpy(audit_str,"Audit(FILE");
        if (wst_p_audit)
            strcat(audit_str,",PRINTER)");
        else
            strcat(audit_str,")");
    }
    else if (wst_p_audit) {
        strcpy(audit_str,"Audit(PRINTER)");
    }

    /* determine no-scroll and paging modes */
    scroll_str = wst_freeze ? "No-Scroll" : "";
    page_str = wst_paging ? "Page" : "";

    /* format to a string for displaying */
    sprintf(printbuff,
        "%1.1s %-4.4s %-7.7s %-19.19s %-6.6s %-9.9s",
            wsterm_mode_str,
            edit_mode_str,
            kb_mode_str,
            audit_str,
            page_str,
            scroll_str);

    /* display the string on the status line */
    status_line(printbuff);

    /* check for foreground message signal */
    if (fg_msg_showing)
        signal_fg(ON);

    /* check for background message signal */
    if (bk_msg_showing)
        signal_bg(ON);
}



/*
**********************************************************************

  Routine:            STATUS_LINE 

  Function:
      This routine displays a string on the status line. The cursor 
  position is preserved. 

  Parameters:
     (input)          str - pointer to the string to display 

  Returns:            NONE 

**********************************************************************/

status_line(str)
char *str;
{
    union REGS reg, outreg;
    int row, col;
    int i, j;
    int attribute;

    /* save current cursor position */
    cursor_pos(&row,&col);

    /* get default foreground screen attributes for status line */
    attribute = wst_fg_screen.attr;

    reg.h.ah = WRT_SCREEN;   /* select function to write a character */
    reg.h.bh = get_active_page();   /* write to current active page */
    reg.x.cx = 1;            /* write 1 character at a time */

    /* invert the foreground and background attributes for reverse video */
    reg.h.bl = ((attribute << N_FG_ATTR_BITS) |
        (attribute >> N_BG_ATTR_BITS)) & LOW_7_BITS;

    /* display until last screen column or end of string */
    for (i = 0; i <= MAX_SCREEN_COL && *str; i++, str++) {
        cursor_move(SCREEN_LINES,i);     /* position cursor */
        reg.h.al = *str;                  /* get character to write */
        int86(BIOS_VIDEO,&reg,&outreg);          /* write the character out */
    }

    /* blank pad the rest of the line */
    reg.h.al = ' ';
    for (j = i; j <= MAX_SCREEN_COL; j++) {
        cursor_move(SCREEN_LINES,j);     /* position cursor */
        int86(BIOS_VIDEO,&reg,&outreg);        /* write the blank */
    }

    /* restore original cursor position */
    cursor_move(row,col);
}



/*
**********************************************************************

  Routine:            SIGNAL_BG 

  Function:
      This routine turns on or off the background message signal on 
  the status line. 

  Parameters:
     (input)          sw - if this value is TRUE, the background 
                          signal is turned on; if FALSE, the signal 
                          is turned OFF 

  Returns:            NONE 

**********************************************************************/

signal_bg(sw)
int sw;
{
    int row, col;
    union REGS reg, outreg;
    int i;
    char *str;
    int attribute;

    /* save original position of cursor */
    cursor_pos(&row,&col);

    /* get default background screen attributes */
    attribute = wst_bg_screen.attr;

    reg.h.ah = WRT_SCREEN;   /* select function to write a character */
    reg.h.bh = get_active_page();  /* write to current active page */
    reg.x.cx = 1;            /* write only one character */

    /* invert the foreground and background attributes for reverse video */
    reg.h.bl = ((attribute << N_FG_ATTR_BITS) |
        (attribute >> N_BG_ATTR_BITS)) & LOW_7_BITS;

    /* if turning signal ON */
    if (sw) {

        /* set hi bit for blinking */
        reg.h.bl |= BLINK_ATTRIBUTE;

        /* initialize the message string pointer */
        str = "[Background]";

    }

    /* else turning the signal OFF, overwrite with blanks */
    else
        str = "            ";

    /* write the string out at the status line background message position; */
    /* starting coordinates on screen for background message is 24,53 */
    for (i = 53; *str; i++, str++) {
        cursor_move(SCREEN_LINES,i);
        reg.h.al = *str;
        int86(BIOS_VIDEO,&reg,&outreg);
    }

    /* restore the original cursor position */
    cursor_move(row,col);
}



/*
**********************************************************************

  Routine:            SIGNAL_FG 

  Function:
      This routine turns the foreground message signal on the status 
  line on or off. 

  Parameters:
     (input)          sw - if this value is TRUE, the foreground 
                          signal is turned ON, otherwise the signal 
                          is turned OFF. 

  Returns:            NONE 

**********************************************************************/

signal_fg(sw)
int sw;
{
    int row, col;
    union REGS reg, outreg;
    int i;
    char *str;
    int attribute;

    /* save the original cursor position */
    cursor_pos(&row,&col);

    /* get default foreground screen attributes */
    attribute = wst_fg_screen.attr;

    reg.h.ah = WRT_SCREEN;   /* select function to write a character */
    reg.h.bh = get_active_page();  /* write to current active page */
    reg.x.cx = 1;            /* write only one character */

    /* invert the foreground and background attributes for reverse video */
    reg.h.bl = ((attribute << N_FG_ATTR_BITS) |
        (attribute >> N_BG_ATTR_BITS)) & LOW_7_BITS;

    /* if turning signal ON */
    if (sw) {

        /* set hi bit for blinking */
        reg.h.bl |= BLINK_ATTRIBUTE;

        /* initialize the message string pointer */
        str = "[Foreground]";
    }

    /* else turning the signal OFF, overwrite with blanks */
    else
        str = "            ";

    /* write the string out at the status line foreground message position */
    /* starting coordinates on screen for foreground message is 24,66 */
    for (i = 66; *str; i++, str++) {
        cursor_move(SCREEN_LINES,i);
        reg.h.al = *str;
        int86(BIOS_VIDEO,&reg,&outreg);
    }

    /* restore the original cursor position */
    cursor_move(row,col);
}
   



		    tbreak.asm                      10/12/88  1401.1rew 10/12/88  1327.6       48015



; ********************************************
; *                                          *
; * Copyright, (C) Honeywell Bull Inc., 1988 *
; *                                          *
; ********************************************
;
; HISTORY COMMENTS:
;  1) change(88-01-23,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel):
;     Created.
;                                                      END HISTORY COMMENTS
;
;******************************************************************************
;
;   Module:   CTRLBRK.ASM
;
;   Function: These are a set of routines which are used to manipulate the 
;             keyboard break handler interrupt in order that the 
;             <CONTROL><BREAK> key may be handled by setting a flag
;             called "break_flag" other than being handled by the default 
;             handler.
;
;             The routine "ctrlbrk" is the handler.  What MUST be remembered 
;             is that this is an interrupt routine and MUST save and restore 
;             all registers.
;
;   Date:      January 23, 1988
;
;   Author:    Michael S. Flegel
;              908-1540-29 Street N.W.
;              Calgary, Alberta
;              Canada
;              T2N-4M1
;              (403) 289-3426
;
;   Resources: Advanced Computing Technology Centre
;              301-1620-29 Street N.W.
;              Calgary, Alberta
;              Canada
;              T2N-4L7
;              (403) 284-6400
;
;   Equipment: IBM-PC AT
;              IBM-PC DOS 3.10
;              Microsoft (R) Overlay Linker, Version 3.51
;              IBM Macro Assembler, Version 2.00
;
;******************************************************************************


include dos.mac

BREAK_PENDING  = 800h

;******************************************************************************
;                             DATA SEGMENT
;******************************************************************************

dseg

old_break_cs    dw  (?)                ; old CS of keyboard break routine
old_break_ip    dw  (?)                ; old IP of keyboard break routine

extrn  break_flag:word                 ; term's control flags

endds

;******************************************************************************
;                             PROGRAM SEGMENT
;******************************************************************************

pseg

public  ctrlbrk
public  set_break
public  reset_break

data_segment    dw  (?)                ; term's data segment register

;
;******************************************************************************
; This routine is activated whenever the <CTL><BREAK> keys are simultaneously
; struck.
;
; All that happens is that the global flag "break_flag" is set.
;******************************************************************************

ctrlbrk proc    near

        push    DS                     ; save used registers
        pushf

        push    CS:data_segment        ; set up data addressability
        pop     DS

        or      break_flag,BREAK_PENDING    ; set the break flag

        popf                           ; restore used registers
        pop     DS

        iret                           ; return from interrupt

ctrlbrk endp
;
;******************************************************************************
; This procedure sets the interrupt 1b routine (keyboard break address)
; to transfer to our "ctrlbrk" routine so that we can handle it ourselves
;******************************************************************************

set_break proc  near

        push    ax                     ; save registers
        push    bx
        push    dx
        push    ds
        push    es

; save the current DS for use by the handler

        push    ds
        pop     ax
        mov     CS:data_segment,ax

; save the control-break vector (1Bh)

        mov     ah,35h                 ; get the old vector
        mov     al,1bh
        int     21h

        mov     old_break_cs,es        ; save the old CS and IP
        mov     old_break_ip,bx

; set the new control-break vector

        mov     dx,offset ctrlbrk      ; set to our ctrlbrk routine
        push    cs
        pop     ds

        mov     ah,25h                 ; signal interrupt to set new vector
        mov     al,1bh
        int     21h

        pop     es                     ; restore registers
        pop     ds
        pop     dx
        pop     bx
        pop     ax
        ret

set_break endp
;
;******************************************************************************
; This routine restores the old interrupt 1b (keyboard break address) routine
; to the one which existed before set_break was invoked.
;******************************************************************************

reset_break proc near

        push    ax                     ; save registers
        push    dx
        push    ds

; restore saved control-break vector

        mov     dx,old_break_ip        ; restore the old CTL-BRK vector
        push    old_break_cs
        pop     ds

        mov     ah,25h                 ; signal the interrupt to restore vector
        mov     al,1bh
        int     21h

        pop     ds                     ; restore registers
        pop     dx
        pop     ax
        ret

reset_break endp

endps
        end
 



		    wstaudit.c                      04/24/89  1040.7rew 04/24/89  1032.7      167373



/* ********************************************
   *                                          *
   * Copyright, (C) Honeywell Bull Inc., 1988 *
   *                                          *
   ******************************************** */

/* HISTORY COMMENTS:
  1) change(88-03-02,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Created routines for buffering.
  2) change(88-05-31,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Added support for file and line printer auditing.
  3) change(88-07-25,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Documentation additions only. Added header comments to all routines.
  4) change(88-08-09,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Fix references to include files; "wstdefs.h" was split into
     "wstdefs.h" and "wsttype.h" to avoid declaration clash; also,
     various constants defined to descriptive names.
  5) change(89-01-18,Lee), approve(89-01-02,MCR8043), audit(89-03-14,Flegel),
     install(89-04-24,MR12.3-1033):
     Separated input and output parameters to int86() to avoid confusion
     when parameters are used.
                                                   END HISTORY COMMENTS */

#include <stdio.h>
#include <fcntl.h>
#include <dos.h>
#include <ctype.h>
#include "wstdefs.h"
#include "wstglob.h"


/* used globally but only by these routines */

static char wst_f_aud_buff[F_AUDIT_BUFF_SIZE];
static int  wst_f_aud_dex = 0;
static int  wst_f_aud_fd = -1;

static char wst_p_aud_buff[P_AUDIT_BUFF_SIZE];
static int wst_p_aud_dex;


/*
**********************************************************************

  Routine:            F_AUD_INIT 

  Function:
      This routine intializes any global file audit variables used. 

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

f_aud_init()
{
     /* file audit buffer index set to beginning */
     wst_f_aud_dex = 0;

     /* initialize file descriptor for audit file */
     wst_f_aud_fd = -1;

}



/*
**********************************************************************

  Routine:            F_AUD_OPEN 

  Function:
      This routine opens the audit file and sets up the file audit 
  buffer. 

  Parameters:         NONE 

  Returns:            -1 if unsuccessful in opening the audit file 
                      0 if no errors 

**********************************************************************/

f_aud_open()
{
    wst_f_aud_fd = open(audit_file_name,O_CREAT|O_WRONLY|O_APPEND);

    /* check for successful open or create */
    if (wst_f_aud_fd < 0)
        return(-1);

    /* initialize buffer index to beginning of buffer */
    wst_f_aud_dex = 0;

    return(0);
}



/*
**********************************************************************

  Routine:            F_AUD_CLOSE 

  Function:
      This routine flushes the contents of the audit buffer to file 
  and closes the audit file. 

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

f_aud_close()
{
    f_aud_flush();
    close(wst_f_aud_fd);
}



/*
**********************************************************************

  Routine:            BEGIN_FILE_AUDIT 

  Function:
      This routine is called to initiate a file audit session. If set 
  up and opening of the audit file and audit file buffer is 
  successful, an audit header containing the current date and time is 
  written to the audit buffer. If set up or opening of audit file is 
  unsuccessful, an error message is displayed and control passes back 
  to the call when a key is entered. 

  Parameters:         NONE 

  Returns:            -1 if unsuccessful 
                      0 if successful 

**********************************************************************/

begin_file_audit()
{
    char message[81];    /* local message buffer */

    /* if opening of audit file is unsuccessful */
    if (f_aud_open() < 0) {

        /* display an error message and wait for any key */
        sprintf(message,"Cannot open audit file: %s  <any key>-resume",
            audit_file_name);
        status_err_msg(message);

        return(-1);
    }

    /* open is successful, log an audit trace begin message containing */
    /*   the current date and time   */

    f_audit_msg("======= BEGIN WSTERM AUDIT TRACE: ",34);
    get_date_time_str(message);
    f_audit_msg(message,strlen(message));
    f_audit_msg(" =======\n",9);

    return(0);
}



/*
**********************************************************************

  Routine:            END_FILE_AUDIT 

  Function:
      This routine is called to terminate a file audit session. The 
  routine logs a terminating audit message containing the current 
  date and time, flushes the audit buffer and closes the audit file. 

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

end_file_audit()
{
    char str[MAX_DATE_TIME_STR_LENGTH];     /* local message buffer */

    /* log audit trace end message containing current date and time */
    f_audit_msg("======= END WSTERM AUDIT TRACE: ",32);
    get_date_time_str(str);
    f_audit_msg(str,strlen(str));
    f_audit_msg(" =======\n",9);

    /* close the audit file */
    f_aud_close();
}



/*
**********************************************************************

  Routine:            F_AUDIT_MSG 

  Function:
      This routine writes data to the audit file buffer which gets 
  flushed when full or when file audit is terminated. 

  Parameters:
     (input)          buff - pointer to the buffer containing the 
                          audit data 
     (input)          bytes - specifies the number of bytes of audit 
                          data to write 

  Returns:            NONE 

**********************************************************************/

f_audit_msg(buff,bytes)
char *buff;   /* data buffer */
int  bytes;   /* number of data bytes */
{
    /* fill file buffer with data until no more data or file buffer full */
    while (bytes > 0 && wst_f_aud_dex < F_AUDIT_BUFF_SIZE) {
        wst_f_aud_buff[wst_f_aud_dex++] = *buff++;
        bytes--;
    }

    /* if no more data, done */
    if (wst_f_aud_dex < F_AUDIT_BUFF_SIZE)
        return;

    /* else buffer was full, flush it */
    write(wst_f_aud_fd,wst_f_aud_buff,F_AUDIT_BUFF_SIZE);

    /* reset the file buffer index to start of buffer */
    wst_f_aud_dex = 0;

    /* will rest of data fit into buffer? */
    if (bytes < F_AUDIT_BUFF_SIZE) {

        /* yes, fill the buffer with rest of data */
        while (bytes > 0) {
            wst_f_aud_buff[wst_f_aud_dex++] = *buff++;
            bytes--;
        }
    }
    /* no, quicker to just flush all data straight to file */
    else
        write(wst_f_aud_fd,buff,bytes);
}



/*
**********************************************************************

  Routine:            F_AUD_FLUSH 

  Function:
      This routine flushes the contents of the audit buffer to the 
  audit file. 

  Parameters:         NONE 

  Returns:            NONE 

  Note 1 - The caller must ensure that the audit file is opened 
      before calling this routine as no checks are made before 
      writing to file. 
**********************************************************************/

f_aud_flush()
{
    /* if data exists in file buffer */
    if (wst_f_aud_fd > 0) {

        /* write it out */
        write(wst_f_aud_fd,wst_f_aud_buff,wst_f_aud_dex);

        /* reset the buffer index to start of buffer */
        wst_f_aud_dex = 0;
    }
}



/*
**********************************************************************

  Routine:            GET_DATE_TIME_STR 

  Function:
      This routine formats a string containing the current date and 
  time and passes the string back to the caller. 

  Parameters:
     (output)         str - pointer to the string to which the 
                          formatted date and date is to be passed 
                          backed 

  Returns:            NONE 

  Note 1 - The date and time are obtained from DOS and are meaningful 
      only if the date and time are correctly set before WSTERM is 
      invoked. 
**********************************************************************/

get_date_time_str(str)
char *str;
{
    union REGS in, date, time;

    /* call DOS routine to get the date */
    in.h.ah = DOS_GET_DATE;
    intdos(&in,&date);

    /* call DOS routine to get the time */
    in.h.ah = DOS_GET_TIME;
    intdos(&in,&time);

    /* format the date and time into the user-specified string */
    sprintf(str,"%s %d, %04d - %02d:%02d.%02d",
        month_tab[date.h.dh-1],
        date.h.dl,
        date.x.cx,
        time.h.ch,
        time.h.cl,
        time.h.dh);
}



/*
**********************************************************************

  Routine:            BEGIN_PRINTER_AUDIT 

  Function:
      This routine initiates a printer audit session by checking that 
  the printer is ready and then printing a printer audit message 
  containing the current date and time. 

  Parameters:         NONE 

  Returns:            -1 if printer error occurred 
                      0 if otherwise successful 

  Note 1 - If an error occurs, an error message is displayed on the 
      status line and the routine returns when a key is pressed. 
**********************************************************************/

begin_printer_audit()
{
    char message[SCREEN_COLS+1];        /* local message buffer */
    char *err_msg;        /* pointer to error messages displayed */

    /* check and handle printer not ready */
    if (check_printer_status(&err_msg) < 0) {

        sprintf(message,"Printer error - %s <any key>-resume", err_msg);
        status_err_msg(message);

        return(-1);
    }

    /* printer is ready, display trace begin message containing date & time */
    p_audit_msg("======= BEGIN WSTERM AUDIT TRACE: ",34,NULL);
    get_date_time_str(message);
    p_audit_msg(message,strlen(message),NULL);
    p_audit_msg(" =======\n",9,NUL);

    return(0);
}



/*
**********************************************************************

  Routine:            END_PRINTER_AUDIT 

  Function:
      This routine terminates a printer audit session by printing a 
  terminating message containing the current date and time. 

  Parameters:         NONE 

  Returns:            0 always 

**********************************************************************/

end_printer_audit()
{
    char str[MAX_DATE_TIME_STR_LENGTH];    /* local message buffer */

    /* printer a trace end message containing the date and time */
    p_audit_msg("======= END WSTERM AUDIT TRACE: ",32,NULL);
    get_date_time_str(str);
    p_audit_msg(str,strlen(str),NULL);
    p_audit_msg(" =======\n",9,NULL);
    return(0);
}



/*
**********************************************************************

  Routine:            P_AUD_INIT 

  Function:
      This routine initializes any global variables used for printer 
  auditing 

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

p_aud_init()
{
    wst_p_aud_dex = 0;
}



/*
**********************************************************************

  Routine:            P_AUDIT_MSG 

  Function:
      This routine writes printer audit data to the printer buffer. 
  The buffer is flushed (by sending to the printer) when the end of a 
  line is detected or when the buffer is full. 

  Parameters:
     (input)          str - pointer to the buffer containg the 
                          printer audit data 
     (input)          len - specifies how many bytes of printer audit 
                          data to write to the printer audit buffer 
     (input)          stat_line - specifies the status line contents to
                          restore, after the status line area has
                          been overwritten with an error message;
                          if NULL, the foreground status line is used

  Returns:            NONE

**********************************************************************/

p_audit_msg(str,len,stat_line)
char *str;
int len;
char *stat_line;
{
    /* buffer the data in the printer audit buffer, flushing the buffer
       whenever a linefeed is received or when the buffer becomes full
    */
    while (len > 0) {
        if ((wst_p_aud_buff[wst_p_aud_dex++] = *str++) == '\n' ||
            wst_p_aud_dex >= P_AUDIT_BUFF_SIZE)
            p_aud_flush(stat_line);
        len--;
    }
}



/*
**********************************************************************

  Routine:            P_AUD_FLUSH 

  Function:
      This routine flushes the audit buffer by sending each buffered 
  character to the printer port. The routine handles the case where a 
  printer error occurs in the middle of sending the buffer by keeping 
  track of where the printer occurred and preserving the unprinted 
  characters. 

  Parameters:
     (input)          stat_line - specifies the status line contents to
                          restore, after the status line area has
                          been overwritten with an error message;
                          if NULL, the foreground status line is used

  Returns:            NONE

**********************************************************************/

p_aud_flush(stat_line)
char *stat_line;
{
    int code;
    int i;
    char prt_err_msg[SCREEN_COLS+1];
    char *err_type;
    char *prev_err;

    /* print each character in buffer until no more characters */
    /*   or until error occurs in printing */
    i = ZERO_INDEX_VALUE;
    while (i < wst_p_aud_dex) {
        code = lpchar(wst_p_aud_buff[i]);
        if (code) {
            prev_err = NULL;
            while (code) {
                code = check_printer_status(&err_type);
                if (code && prev_err != err_type) {
                    sprintf(prt_err_msg,"Printer error (%s), fix printer",err_type);
                    status_line(prt_err_msg);
                    prev_err = err_type;
                }
            }
            if (stat_line == NULL)
                update_status();
            else
                status_line(stat_line);
        }
        else
            i++;
    }
    wst_p_aud_dex = ZERO_INDEX_VALUE;
}



/*
**********************************************************************

  Routine:            LPCHAR 

  Function:
      This routine sends a single character to the printer port. 

  Parameters:
     (input)          ch - specifies what character to send to the 
                          printer port 

  Returns:            TRUE if timeout occurred, indicating a printer
                          error
                      FALSE if not error

**********************************************************************/

lpchar(ch)
int ch;
{
    union REGS reg, outreg;

    /* call BIOS to send character to printer port */
    reg.h.ah = BIOS_PRT_PRINT;     /* select print function */
    reg.x.dx = wst_printer_card;
    reg.h.al = ch;
    int86(BIOS_PRT,&reg,&outreg);

    /* timeout */
    return(outreg.h.ah & 01);
}



/*
**********************************************************************

  Routine:            SET_PRINTER_TIMEOUT 

  Function:
      This routine is used to set the duration of the wait period 
  before timeout occurs for a printer error. This is accomplished by 
  modifying timeout variables kept in the BIOS segment. 

  Parameters:
     (input)          timeout_val - specifies the timeout duration 

  Returns:            NONE 

**********************************************************************/

set_printer_timeout(timeout_val)
int timeout_val;
{
    char val;

    val = timeout_val;
    poke(BIOS_SEGMENT,PRT_TIMEOUT_BASE+wst_printer_card,&val,1);
}



/*
**********************************************************************

  Routine:            SAVE_PRINTER_TIMEOUT 

  Function:
      This routine saves the default duration of the wait period 
  before timeout occurs for a printer error. This is accomplished by 
  reading and saving the timeout variable kept in the BIOS segment. 

  Parameters:
     (input)          timeout_val - specifies the timeout duration 

  Returns:            NONE 

**********************************************************************/

save_printer_timeout()
{
    char val;

    /* save timeout value for printer card used */
    peek(BIOS_SEGMENT,PRT_TIMEOUT_BASE+wst_printer_card,&val,1);
    wst_prt_timeout = val;
}


/*
**********************************************************************

  Routine:            CHECK_PRINTER_STATUS 

  Function:
      This checks the printer status. If the printer is not ready, an 
  error message is passed back to try to specify the error. 

  Parameters:
     (output)         err_msg_ptr - address of a character pointer 
                          for passing back the address of a error 
                          message string if the printer is not ready; 
                          address passed back is NULL if printer is 
                          ready 

  Returns:            0 if printer is ready 
                      -1 otherwise 

**********************************************************************/

check_printer_status(err_msg_ptr)
char **err_msg_ptr;
{
    union REGS reg, outreg;
    char *error_msg;

    /* get printer status from BIOS */
    reg.h.ah = BIOS_PRT_STATUS;
    reg.x.dx = wst_printer_card;

    int86(BIOS_PRT,&reg,&outreg);

    /* check printer ready */
    if (outreg.h.ah == PRT_READY_MODE) {
        if (*err_msg_ptr != NULL)
            *err_msg_ptr = NULL;
        return(0);
    }

    /* check printer error */
    else {

        /* pass back error string if non-NULL address specified */
        if (err_msg_ptr != NULL) {
            switch(outreg.h.ah) {
                case PRT_OFF_LINE_MODE:
                    *err_msg_ptr = print_error_list[PEL_OFF_LINE];
                    break;
                case PRT_NO_PAPER_MODE:
                    *err_msg_ptr = print_error_list[PEL_NO_PAPER];
                    break;
                default:
                    *err_msg_ptr = print_error_list[PEL_NOT_READY];
             }
        }
    }

    /* indicate printer error occurred */
    return(-1);
}
   



		    wstbkgnd.c                      10/12/88  1354.9rew 10/12/88  1335.3      125127



/* ********************************************
   *                                          *
   * Copyright, (C) Honeywell Bull Inc., 1988 *
   *                                          *
   ******************************************** */

/* HISTORY COMMENTS:
  1) change(87-05-04,Wallman), approve(87-05-04,MCR7586),
     audit(87-07-16,Flegel), install(87-08-07,MR12.1-1072):
     First release.
  2) change(88-04-28,Lee), approve(88-05-16,MCR7897),
     audit(88-09-19,Flegel), install(88-10-12,MR12.2-1160):
     Created. The previous WSTBKGND.C has been rewritten to
     handle background messages using a background screen
     instead of a 1 line minibuffer.
  3) change(88-05-31,Lee), approve(88-05-16,MCR7897),
     audit(88-09-19,Flegel), install(88-10-12,MR12.2-1160):
     Added file and printer auditing support.
  4) change(88-07-25,Lee), approve(88-05-16,MCR7897),
     audit(88-09-19,Flegel), install(88-10-12,MR12.2-1160):
     Documentation additions only. Added header comments to all routines.
  5) change(88-08-09,Lee), approve(88-05-16,MCR7897),
     audit(88-09-19,Flegel), install(88-10-12,MR12.2-1160):
     Fix references to include files; "wstdefs.h" was split into
     "wstdefs.h" and "wsttype.h" to avoid declaration clash; also,
     various constants defined to descriptive names.
                                                   END HISTORY COMMENTS */

/* WSTBKGND - handles processing of background messages using a
              background screen. Replaces previous modules which
              used 25th line to display background messages.
*/

#include    <stdio.h>
#include    <dos.h>
#include    <ws.h>
#include    <ws_mcb.h>
#include    <ws_error.h>
#include    "wstdefs.h"
#include    "wstglob.h"


/*
**********************************************************************

  Routine:            SHOW_BKMSG 

  Function:
      This routine signals the arrival of a background message 

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

show_bkmsg ()
{
    signal_bg(ON);
    bk_msg_showing = ON;
}				/* End of show_bkmsg */



/*
**********************************************************************

  Routine:            DISPLAY_BKMSG 

  Function:
      This routine saves the foreground screen and enters the 
  background screen. While in the background screen, the user may 
  display the next background message, quit, invoke the help screen 
  or invoke the background polling screen. 

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

display_bkmsg ()
{   
    char    message [MAX_BG_MESS_LENGTH+1];  /* A background message */
    int     msg_type,       /* WSINFO or WSQUERY */
            sender;         /* Sender's majcap */
    int     bg_msg_pending;          /* count of pending background messages */
    char    statline[SCREEN_COLS+1]; /* string to display in status line */
    int     ch;             /* the key hit when waiting for input */
    char    *msg_ptr;

    /* get number of background messages pending */
    bg_msg_pending = tdata_arg.background_pending_flag;

    /* turn background messages off for now, will be reset in wsterm main */
    bk_msg_showing = OFF;

    /* save foreground screen and swap to background screen */
    save_wst_screen(&wst_fg_screen);
    restore_wst_screen(&wst_bg_screen);

    /* Loop here until getbkmes says there aren't any. */
    while (ON) {

        /* if background messages in queue */
        if (bg_msg_pending > 0) {

            /* display number of background messages in queue on status line */
            sprintf(statline,"Background Screen: %d message(s). <ALT-H>-help  [<q>,<p>,<ALT-M>,<ALT-D>]",
                bg_msg_pending);
            status_line(statline);

            /* hide cursor */
            cursor_move(HIDE_CURSOR_ROW,HIDE_CURSOR_COL);

            /* wait for user to hit a valid key */
            while (TRUE) {
                ch = getkey(BLOCK);

                /* if key to quit hit */
                if (uppercase(ch) == 'Q') {
                    bg_msg_pending = 0;
                    cursor_move(wst_bg_screen.cursor_row,
                        wst_bg_screen.cursor_col);
                    exit_bg_screen();
                    return;
                }

                /* if key to display next background message */
                else if (ch == ALT_M || ch == ALT_D)
                    break;

                /* if key to enter poll loop */
                else if (uppercase(ch) == 'P') {
                    poll_bg_msg();
                    cursor_move(wst_bg_screen.cursor_row,
                        wst_bg_screen.cursor_col);                    
                    exit_bg_screen();
                    return;
                }

                /* enter help screen, giving background screen info */
                else if (ch == ALT_H) {
                    help(BG_HELP);

                    /* restore status line message when done */
                    status_line(statline);
                }

                else
                    beep();
            }

            /* get and display the next background message */
            if (getbgmes (message, &msg_type, &sender) == WSNOMESS) {
                /* if couldn't get it, continue at top of loop to */
                /* exit gracefully */
                bg_msg_pending = 0;
                continue;
            }

            /* tally background message and display it */
            bg_msg_pending--;
            msg_ptr = message;

            cursor_move(wst_bg_screen.cursor_row,
                wst_bg_screen.cursor_col);
            
            while (*msg_ptr)
                put_wst_screen(&wst_bg_screen,*msg_ptr++);
            put_wst_screen(&wst_bg_screen,'\n');

            /* hide cursor */
            cursor_move(HIDE_CURSOR_ROW,HIDE_CURSOR_COL);

            /* perform auditing if auditing enabled */
            if (wst_f_audit) {
                f_audit_msg("==BG==> ",8);
                f_audit_msg(message,strlen(message));
                f_audit_msg("\n",1);
            }

            if (wst_p_audit) {
                p_audit_msg("==BG==> ",8,statline);
                p_audit_msg(message,strlen(message),statline);
                p_audit_msg("\n",1,statline);
            }

            /* If this is a query, contruct and send the reply */
            if (msg_type == WSQUERY) {
                /* prompt user for input on status line */
                strcpy(statline,"Background Screen: Enter reply     <ALT-H>-help");
                status_line(statline);

                /* restore cursor */
                cursor_move(wst_bg_screen.cursor_row,
                    wst_bg_screen.cursor_col);

                /* read message from keyboard */
                wst_getline(&wst_bg_screen,message,statline);

                /* hide cursor */
                cursor_move(HIDE_CURSOR_ROW,HIDE_CURSOR_COL);

                /* send reply to sender of background message */
                sendqrep (message, sender);

                /* perform auditing if auditing enabled */
                if (wst_f_audit) {
                    f_audit_msg("==BGR=> ",8);
                    f_audit_msg(message,strlen(message));
                    f_audit_msg("\n",1);
                }

                if (wst_p_audit) {
                    p_audit_msg("==BGR=> ",8,statline);
                    p_audit_msg(message,strlen(message),statline);
                    p_audit_msg("\n",1,statline);
                }

            }
        }

        /* no messages */
        else {
            strcpy(statline,"Background Screen: No more messages. <ALT-H>-help  [<p>,<q>]");
            status_line(statline);

            /* hide cursor */
            cursor_move(HIDE_CURSOR_ROW,HIDE_CURSOR_COL);

            /* allow user to enter poll loop or to quit */
            while (TRUE) {
                ch = getkey(BLOCK);
                if (ch == ALT_H) {
                    help(BG_HELP);
                    status_line(statline);
                }
                else if (uppercase(ch) == 'P' || uppercase(ch) == 'Q')
                    break;
                else
                    beep();
            }

            /* background polling requested? */
            if (uppercase(ch) == 'P')
                poll_bg_msg();

            cursor_move(wst_bg_screen.cursor_row,
                wst_bg_screen.cursor_col);

            exit_bg_screen();

            return;
        }
    }
}



/*
**********************************************************************

  Routine:            EXIT_BG_SCREEN 

  Function:
      This routine saves the contents of the background screen and 
  restores the contents of the foreground screen.

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

exit_bg_screen()
{
    save_wst_screen(&wst_bg_screen);
    restore_wst_screen(&wst_fg_screen);
    update_status();
}



/*
**********************************************************************

  Routine:            POLL_BG_MSG 

  Function:
      This routine puts the user into the background polling screen. 
  Any background messages are immediately displayed upon arrival. 
  Keyboard input allows the user to quit the background screen, 
  invoke the help screen or toggle between scroll and no scroll. 

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

poll_bg_msg()
{
    int msg_type;        /* holds background message type */
    int sender;          /* holds sender of background message */
    char message[MAX_BG_MESS_LENGTH+1]; /* holds background message */
    int scroll;          /* scroll switching to control local scrolling */
    int ch;              /* holds key hit */
    char *bgp_stat_ns;   /* points to status line message in no-scroll */
    char *bgp_stat_s;    /* points to status line message in scroll */
    char *bgp_stat_q;    /* points to status line message replying to query */
    char *msg_ptr;       /* scratch message ptr */

    scroll = 1;
    bgp_stat_ns = "Background Screen(Poll): [NO-SCROLL] <ALT-H>-help  [<q>,<other>]";
    bgp_stat_s = "Background Screen(Poll):             <ALT-H>-help  [<q>,<other>]";
    bgp_stat_q = "Background Screen(Poll): Enter reply     <ALT-H>-help";

    /* update the status line */
    status_line(bgp_stat_s);

    /* poll until the user hits 'q' to quit */
    while (TRUE) {
        if (scroll && getbgmes (message, &msg_type, &sender) != WSNOMESS) {

            /* restore cursor */
            cursor_move(wst_bg_screen.cursor_row,
                wst_bg_screen.cursor_col);

            /* display the background message */
            msg_ptr = message;
            while (*msg_ptr)
                put_wst_screen(&wst_bg_screen,*msg_ptr++);
            put_wst_screen(&wst_bg_screen,'\n');

            /* perform auditing if enabled */
            if (wst_f_audit) {
                f_audit_msg("==BG==> ",8);
                f_audit_msg(message,strlen(message));
                f_audit_msg("\n",1);
            }

            if (wst_p_audit) {
                p_audit_msg("==BG==> ",8,bgp_stat_s);
                p_audit_msg(message,strlen(message),bgp_stat_s);
                p_audit_msg("\n",1,bgp_stat_s);
            }

            /* hide cursor */
            cursor_move(HIDE_CURSOR_ROW,HIDE_CURSOR_COL);

            /* If this is a query, contruct and send the reply */
            if (msg_type == WSQUERY) {

                /* restore cursor position */
                cursor_move(wst_bg_screen.cursor_row,
                    wst_bg_screen.cursor_col);

                /* update status line to indicate input state */
                status_line(bgp_stat_q);

                /* get the user input (reply) */
                wst_getline(&wst_bg_screen,message,bgp_stat_q);

                cursor_pos(&wst_bg_screen.cursor_row,
                    &wst_bg_screen.cursor_col);

                /* hide cursor */
                cursor_move(HIDE_CURSOR_ROW,HIDE_CURSOR_COL);

                /* send reply message back to sender of background message */
                sendqrep (message, sender);

                /* audit if auditing enabled */
                if (wst_f_audit) {
                    f_audit_msg("==BGR=> ",8);
                    f_audit_msg(message,strlen(message));
                    f_audit_msg("\n",1);
                }

                if (wst_p_audit) {
                    p_audit_msg("==BGR=> ",8,bgp_stat_q);
                    p_audit_msg(message,strlen(message),bgp_stat_q);
                    p_audit_msg("\n",1,bgp_stat_q);
                }

                /* update the status line to indicate polling state */
                status_line(bgp_stat_s);
            }
        }

        /* if a key has been hit */
        if (checkkey() >= 0) {

            /* get the key */
            ch = getkey(BLOCK);

            /* check if key hit was 'q' to quit */
            if (uppercase(ch) == 'Q')
                return;

            /* check if help requested */
            else if (ch == ALT_H) {
                help(BG_HELP);
                if (scroll)
                    status_line(bgp_stat_s);
                else
                    status_line(bgp_stat_ns);
            }

            /* any other key hit toggles scroll/no_scroll */
            else {

                /* toggle scroll value and update the status line */
                scroll = !scroll;
                if (scroll)
                    status_line(bgp_stat_s);
                else
                    status_line(bgp_stat_ns);
            }
        }
    }
}

 



		    wstedit.c                       10/12/88  1354.9rew 10/12/88  1330.1       68643



/* ********************************************
   *                                          *
   * Copyright, (C) Honeywell Bull Inc., 1987 *
   *                                          *
   ******************************************** */

/* HISTORY COMMENTS:
  1) change(87-05-04,Wallman), approve(87-05-04,MCR7586),
     audit(87-08-10,Flegel), install(87-08-07,MR12.1-1072):
     First release.
  2) change(87-09-02,Wallman), approve(87-09-02,MCR7586),
     audit(87-08-17,Flegel), install(87-09-10,MR12.1-1103):
     PBF to improve robustness of string handling by avoiding all str*
     functions.
  3) change(88-02-24,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Removed debugging code and unused variables; code re-formatting.
  4) change(88-04-25,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Null-terminated temporary string "trash" in edit_HT to fix bug.
  5) change(88-05-18,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Deleted hide_sw reference to function replay().
  6) change(88-05-31,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Added file and printer auditing support.
  7) change(88-07-12,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Replace calls to redundant move_abs() with calls to cursor_move().
  8) change(88-07-25,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Documentation additions only. Added header comments to all routines.
  9) change(88-08-09,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Fix references to include files; "wstdefs.h" was split into
     "wstdefs.h" and "wsttype.h" to avoid declaration clash; also,
     various constants defined to descriptive names.
 10) change(88-08-30,Lee), approve(88-09-12,MCR7986), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Removed non-edit async mode line editing routines and references
     to those routines.
                                                   END HISTORY COMMENTS */

/*  WSTEDIT - Local edit module for WSTERM                 */

/* Perform local edit action for async mode */

#include    <stdio.h>
#include    <dos.h>
#include    "wstdefs.h"
#include    "wstglob.h"
#include    <wsmincap.h>

/*
**********************************************************************

  Routine:            REPLAY 

  Function:
      This routine redisplays the input line in non-edit async mode. 

  Parameters:
     (input)          coli - specifies the column movement increment 

  Returns:            NONE 

**********************************************************************/


replay (coli)
int coli;       /* Column movement increment */
{   
    int cndx,       /* Scan index for kb.klin */
    dcol,       /* Local column position */
    dend,       /* Final column position */
    dlin,       /* Local line counter */
    dstrt,      /* Local starting column value */
    space_left,     /* Space left in current line */
    spill,      /* Line wrap spill character count */
    tab_space;  /* Tabbing space needed */

    register int    ilin;        /* Working index */

    /* Set up boundary conditions for the display */

    cndx = kb.endx;         /* Starting character */
    dstrt = ds.ccol;            /* Starting column */
    dcol = ds.ccol;
    dend = dcol + coli;     /* Ending column */
    dlin = ds.lndx;         /* Starting line index */

    if (dend > screen.maxcol)       /* Adjust ending column */
        dend %= screen.maxcol;

    if (dstrt < strlen (ds.dlin))   /* Clear needed stuff */
        putscr (EL, strlen (EL));

    ds.dlin [dstrt] = NUL;
    space_left = 0;
    spill = 0;

    /* Scan kb.klin from cndx to end */

    while (cndx < strlen (kb.klin)) {

        /* Loop thru display line */

        while (dcol < screen.maxcol && cndx < strlen (kb.klin)) { 
            kb.pos [cndx] = dcol;

            if (kb.klin [cndx] == HT)   /* Tabbing */ { 
                tab_space = next_tab (dcol);
                space_left = screen.maxcol - dcol;
                if ((space_left < tab_space) & (space_left >
                    0))
                    spill = tab_space - space_left;
                catstr (ds.dlin, spaces, tab_space,
                     "ds.dlin", sizeof (ds.dlin));

                if (spill > 0) { 
                    ds.spill [dlin] = ON;
                    if (wrap_line (dlin, dcol))   /* Non-zero if line wont fit */
                        return (ON);

                    catstr (ds.dlin, spaces,
                         spill, "ds.dlin", sizeof (ds.dlin));
                    dcol = ds.splct [dlin] = spill;
                    dstrt = 0;
                }
                else 
                    dcol = tab_space;

            } /* Control characters */

            else if (iscntrl (kb.klin [cndx])) { 
                sprintf (kb.dstr, "%c%03o", lnc, (int) kb.klin [cndx]);
                space_left = screen.maxcol - dcol;
                if ((space_left < 4) & (space_left > 0))
                    spill = (4 - space_left) % 4;

                if (space_left >= 4)        /* It fits on the line */ { 
                    catstr (ds.dlin, kb.dstr,
                         strlen (kb.dstr), "ds.dlin", sizeof (ds.dlin));

                    dcol += 4;
                }

                else /* It doesn't fit */        { 
                    if (space_left > 0)
                        catstr (ds.dlin,
                             kb.dstr, space_left, "ds.dlin",
                                    sizeof (ds.dlin));

                    putscr (ds.dlin [dstrt],
                         space_left);

                    ds.spill [dlin] = ON;
                    if (wrap_line (dlin, dcol))   /* Error if line wont fit */
                        return (ON);

                    dlin++; 
                    dstrt = 0;

                    strcpy (ds.dlin, kb.dstr [space_left]);
                    dcol = ds.splct [dlin] = spill;
                }
            }               /* End of control chars */

            else {    /* Printing graphics */
                putscr (&kb.klin [cndx], 1);

                ds.dlin [dcol++] = kb.klin [cndx];
                ds.dlin [dcol] = NUL;

            }

            cndx++;
        }               /* End of ds.lin loop */

        if (cndx < strlen (kb.klin))    /* Next line if there's more */ { 
            putscr (&ds.dlin [dstrt], strlen (&ds.dlin [dstrt]));

            if (wrap_line (dlin, dcol))   /* Error if line wont fit */
                return (ON);
            dstrt = 0;
            dcol = 0;
            setmem (ds.dlin, sizeof (ds.dlin), NUL);
            dlin++;
        }

        else { /* Copy current line to ds map */
            strcpy (&ds.map [dlin][0], ds.dlin);

        }
    }               /* End of kb.klin loop */

    if ((ilin = dlin + 1) <= ds.lct)    /* Erase leftovers */ { 
        for (; ilin <= ds.lct; ilin++)
            ;
         { 
            cursor_move (screen.curlin + ilin, 0);
            putscr (EL, strlen (EL));
        }

        ds.lct = dlin;
        cursor_move (screen.curlin + dlin, dstrt);
    }

    putscr (EL, strlen (EL));

    if (dcol != dend)
        cursor_move (screen.curlin, dend + (dlin == 0) * ds.pstrl);
    ds.lndx = dlin;
    ds.ccol = dend;

    return (0);
}               /* End of replay */


/* End of WSTEDIT */
 



		    wsterm.c                        04/24/89  1040.7rew 04/24/89  1031.7      161055



/* ***********************************************************
   *                                                         *
   * Copyright, (C) Honeywell Bull Inc., 1988                *
   *                                                         *
   * Copyright, (C) Honeywell Information Systems Inc., 1987 *
   *                                                         *
   *********************************************************** */


/* HISTORY COMMENTS:
  1) change(87-03-08,Wallman), approve(87-03-08,MCR7586),
     audit(87-07-16,Flegel), install(87-08-07,MR12.1-1072):
     First release.
  2) change(88-02-24,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Removed debugging code and unused variables, formatting.
  3) change(88-04-11,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Added calls to handled BREAK key; mapped DEL key to ASCII DEL,
     mapped ^@ (or ^2) to ASCII NUL.
  4) change(88-04-26,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Created routine check_wst_status() to update the status when
     WSTERM changes its mode (glass tty, sync or async).
  5) change(88-04-27,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Added calls to scroll_1_to_24() to prevent the status line from
     being overwritten when using FANSI-CONSOLE.
  6) change(88-05-12,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Added command line handling for /B option.
  7) change(88-05-31,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Added command line handling for /A, /P; support for file and
     printer auditing.
  8) change(88-07-20,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Default after atm changed edit mode.
  9) change(88-07-25,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Documentation additions only. Added header comments to all routines.
 10) change(88-08-09,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Fix references to include files; "wstdefs.h" was split into
     "wstdefs.h" and "wsttype.h" to avoid declaration clash; also,
     various constants defined to descriptive names.
 11) change(88-08-30,Lee), approve(88-09-12,MCR7986), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Removed non-edit async mode and references to non-edit async mode
     line editing routines.
 12) change(89-02-22,Lee), approve(89-01-02,MCR8043), audit(89-03-14,Flegel),
     install(89-04-24,MR12.3-1033):
     Separated input and output parameters to int86() to avoid confusion
     when parameters are used; enabled kb.echo flag when mowse is not active
     and in edit-mode.
                                                   END HISTORY COMMENTS */

/* WSTERM -- WorkStation TERminal Manager for Multics MOWSE */


#include  <stdio.h>
#include  <dos.h>
#include  <ws.h>
#include  <ws_error.h>
#include  <wsmincap.h>
#include  <cat.h>
#include  "wstdefs.h"
#include  "wstglob.h"

/****************************************************************************/

/* Program entrypoint */

/*
**********************************************************************

  Routine:            MAIN 

  Function:
      This is the command module for WSTERM. It analyzes command line 
  arguments, setting appropriate flags and initializes the execution 
  environment. It then enters a listener loops that continually 
  checks and handles foreground messages, background messages, and 
  keyboard input. It stays in the listener loop until the user enters 
  a local escape sequence that signals that the program should 
  terminate. While inside the listener loop, various modes and 
  facilities may be called. 

  Parameters:
     (input)          argc - indicates the number of command line 
                          arguments; standard argc argument passed to 
                          main() 
     (input)          argv - pointer to the character pointer array 
                          containing the actual command line 
                          arguments; standard argv argument passed to 
                          main() 

  Returns:            NONE 

**********************************************************************/

main (argc,argv)
int argc;
char *argv[];
{   
    /* handle command line arguments */
    if (parse_args(argc,argv) < 0)
        exit(0);

    /* if /B option specified to send break to host */
    if (break_sends_to_host)
        set_break();   /* set up our ^BREAK handler */
    else
        enable_ctl_c_check();   /* turn ^C/BREAK checking ON */

    /* initialize screen structures for screen swapping */
    wst_init_modes();

    init_kb_screen(SCREEN_LINES,SCREEN_COLS);
    init_line(&edlin);

    /* initialize wsterm structures and variables */
    if (wstinit () < 0) {
        /* MOWSE not invoked error, clean up and exit */

        /* restore scrolling region to full screen */
        reset_scroll();

        if (break_sends_to_host)
            reset_break();   /* restore original ^BREAK handler */
        else
            restore_ctl_c_check();  /* restore original ^C/BREAK checking */
        exit(0);
    }


    /* initialize wsterm's line mode flag to update on next check */
    wst_status = WST_UNKNOWN_MODE;

    /* Listener loop -- control stays in this loop until the user
       enters ALT-Q to quit the invocation. */

    while (local_action != QUIT) { 

        /* check WSTERM's status and update status line if necessary */
        check_wst_status();

        local_action = NUL;     /* Erase possible leftovers */

        /* If there is no pending foreground message, see if
           one is waiting in MOWSE */

        if (fg_msg_len == 0) { 
            fg_msg_len = gettdata (&tdata_arg);

            /* If MOWSE doesnt have a message either, check MOWSE's status */
            if (fg_msg_len == 0)
                check_MOWSE_status ();
        }

        /* Is there a foreground message? */
        if (fg_msg_len > 0) {

            /* If FB_BREAK has been sent and this is the return FG_BREAK */
            if (break_sent && tdata_arg.minor_capability == FG_BREAK) {

                break_sent = OFF;
                fg_msg_len = 0;     /* Discard the FG_BREAK message */

                if (read_active) {     /* Terminate any active read */
                    term_read = ON;
                    send_msg (nul_str, 0);
                }
            }
            else if (~sync)      /* An async message */
                async_msg (~FORCE);
            else 
                sync_msg ();    /* A sync message */
        }

        /* If mowse is active ... */
        if (mowse_active) {

            /* Is there a background message that hasn't been
               shown in line 25? */

            if (tdata_arg.background_pending_flag && ~bk_msg_showing)
                show_bkmsg ();

            /* If we're in sync mode with characters in the
               keyboard buffer and there is an active read command,
               check for echo delay timer runout */

            if (sync && read_active) { 
                if (kb.cndx > 0 && check_echo_delay ()) { 
                    if ((kb.echo && kb.cndx > kb.endx) ||
                        ~kb.echo)
                        extract_msg (~NO_BLOCK,
                             TRO, ~kb.echo, ~HIDE);
                }
            }
        }

        /* Anything from the keyboard? */

        if (!wst_edit_mode || sync) {
            if (read_keyboard (~BLOCK))
                process_kbrd_char (~HIDE);
        }
        else
            process_edit_line(&edlin);
    }               /* End of listener loop */

    /* Bid adieu to MOWSE and return to DOS */

    destinst (&wst_mcb);

    /* restore scrolling region to full screen */
    reset_scroll();

    /* move cursor to bottom of screen and display a new line */
    /* so that the DOS prompt will appear at the bottom of the screen */
    leave_screen();

    set_printer_timeout(wst_prt_timeout);

    /* if /B specified to send break to host */
    if (break_sends_to_host)
        reset_break();   /* restore original ^BREAK handler */

    else
        restore_ctl_c_check();  /* restore original ^C/BREAK checking */

    if (wst_f_audit)
        end_file_audit();

    if (wst_p_audit)
        end_printer_audit();

    exit ();

}               /* End of main */


/**** LOCAL FUNCTIONS *********************************************************/


/*
**********************************************************************

  Routine:            CHECK_ECHO_DELAY 

  Function:
      This function checks for echo delay timer runout. The echo 
  delay timer (currently set at 1 second) controls the echoing of 
  typeahead so that the user doesn't get too far ahead of the screen 
  display. 

  Parameters:         NONE 

  Returns:            ON if timer runout occurred 
                      OFF is no timer runout occurred 

**********************************************************************/

check_echo_delay ()
{   
    int newtime;        /* Current clock */
    union regs_struct regs, outregs;

    /* Record current DOS system time in 'newtime' */

    regs.hreg.ah = SYSTEM_TIME;
    intdos (&regs, &outregs);
    newtime = regs.hreg.dh & LO_BYTE_MASK; /* Use only seconds value */

    if (oldtime == -1)      /* Also set oldtime for first call */
        oldtime = newtime;
    if (newtime < oldtime)      /* Adjust for clock rollover */
        oldtime -= 60;

    /* Check for timer runout */

    if (newtime - oldtime >= echo_delay) {

        oldtime = newtime;      /* Timer runout - record newtime */
        return (ON);            /* Return true */
    }

    else 
        return (OFF);       /* No timer runout - return false */
}               /* End of check_echo_delay */



/*
**********************************************************************

  Routine:            CHECK_MOWSE_STATUS 

  Function:
      This routine checks MOWSE's status flag with WSTERM's static 
  switch to determine if there has been a change in MOWSE's status 
  (either attached or detached). If MOWSE's status has changed to 
  attached, a WSTERM capability is created; if MOWSE's status has 
  changed to detached, the WSTERM capability is destroyed; otherwise 
  there is no change in status and nothing happens. 

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

check_MOWSE_status ()
{

    /* If WSTERM's static switch says MOWSE is active but Multics MOWSE is
   detached, free WSTERM's MCB and set various static switches */

    if (mowse_active && tdata_arg.minor_capability == DETACHED) { 

        destinst(&wst_mcb);

        mowse_active = OFF;

        /* in glass tty mode, use edit mode only if the default */
        /* for glass tty mode is edit mode */
        wst_edit_mode = glass_edit_mode;

        /* RL: phx21233 - always echo in edit mode when MOWSE is not */
        /* attached since no mowse_io_ to control printer on/off */
        if (wst_edit_mode)
            kb.echo = ON;

        /* RL: phx21233 - OFF in non-edit mode to prevent double echoing */
        else
            kb.echo = OFF;

        /* Send any typeahead */

        if (kb.cndx > 0) {

            puttdata (FG_TERMINAL_DATA, kb.klin, strlen (kb.klin));

            kb.cndx = 0;            /* Wipe keyboard buffer */
            kb.endx = 0;
            kb.klin [0] = NUL;

            ds.ccol = 0;            /* Wipe keyboard display */
            ds.lct = 0;
            ds.lndx = 0;
            ds.dlin [0] = NUL;
            ds.pstrl = 0;
            ds.pstr [0] = NUL;
            screen.EOP_ct = 0;
            ds.splct [0] = NUL;
        }
    }

    /* If WSTERM's static switch says MOWSE is not active but
       Multics MOWSE is attached, tell MOWSE to put WSTERM into
       the CAT and set static switches */

    else if (~mowse_active && tdata_arg.minor_capability == ATTACHED) { 

        cretinst ("WSTERM",   /* capability name */
            NULL,             /* NULL entry function */
            0,                /* zero inbuff length */
            0,                /* zero outbuff length */
            NULL,             /* NULL data ptr */
            &wst_mcb);        /* MCB ptr */

        mowse_active = ON;
        kb.echo = ON;

        /* mowse now active, determine mode for editing; */
        /* use edit mode only if default for async is edit mode */
        wst_edit_mode = TRUE;
        crecho = OFF;
        lfecho = OFF;

    }
}               /* End of check_MOWSE_status */



/*
**********************************************************************

  Routine:            CHECK_WST_STATUS 

  Function:
      This routine checks WSTERM's MOWSE status flag against the 
  global flag 'wst_status' (which indicates the status that is 
  displayed on the status line). If a change is detected, the 
  wst_status flag is updated and the new status is displayed in the 
  status line. 

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

check_wst_status()
{
    int status;

    status = WST_UNKNOWN_MODE;

    /* determine the current mode */
    if (~mowse_active) status = WST_GLASS_TTY_MODE;
    else if (sync) status = WST_SYNC_MODE;
    else status = WST_ASYNC_MODE;

    /* if status is the same since last checked, do nothing */
    if (wst_status == status) return;

    /* update the status flag for the next check */
    wst_status = status;

    /* update the new status on the status line */
    update_status();
}



/*
**********************************************************************

  Routine:            PARSE_ARGS 

  Function:
      This routine parses WSTERM's command line arguments, setting 
  appropriate flags and variables if the command line arguments are 
  recognized. Default values are assigned to flags and variables not 
  affected by the command line arguments. The following table 
  indicates the flag/variables affected by their corresponding 
  control argument specifier: 

  global flag         default value   control argument   new value
  -----------         -------------   ----------------   ---------
  break_sent_to_host  OFF             /B                 ON
  audit_file_name     "wsterm.log"    /A                 <user file name>
  wst_printer_card    0               /P                 0-2

  Parameters:
     (input)          argc - the argc value passed to main() 
     (input)          argv - the argv value passed to main 

  Returns:            -1 if a parsing error occurred 
                      0 if no error occurred 

  Note 1 - If a parsing error is encountered, an error message is 
      displayed by this module. 
**********************************************************************/

parse_args(argc,argv)
int argc;
char *argv[];
{
    int i;
    char tmp[133]; /* trash variable for trapping invalid input */

    /* initialize with default values */
    break_sends_to_host = OFF;
    audit_file_name = DEFAULT_AUDIT_FILE;
    wst_printer_card = DEFAULT_PRINTER_CARD;

    /* loop through each argument from left to right on command line */
    for (i = 1; i < argc; i++) {

        /* check for /B */
        if (!strcmp(argv[i],"/B") || !strcmp(argv[i],"/b"))
            break_sends_to_host = ON;

        /* check for /A */
        else if (!strcmp(argv[i],"/A") || !strcmp(argv[i],"/a")) {

            i++;
            if (argc <= i || argv[i][0] == '/') {
                printf("Missing audit file name specifier for /A argument\n");
                return(-1);
            }
            audit_file_name = argv[i];
            
        }

        /* check for /P */
        else if (!strcmp(argv[i],"/P") || !strcmp(argv[i],"/p")) {

            i++;
            if (argc <= i || argv[i][0] == '/') {
                printf("Missing printer card number (0-2) for /P argument\n");
                return(-1);
            }
            if (sscanf(argv[i],"%d%s",&wst_printer_card,tmp) != 1 ||
                wst_printer_card < MIN_PRINTER_CARD_VAL ||
                wst_printer_card > MAX_PRINTER_CARD_VAL) {
                printf("Invalid printer card value; must be 0, 1 or 2.\n");
                wst_printer_card = DEFAULT_PRINTER_CARD;
                return(-1);
            }
        }

        /* not a recognized command line argument */
        else {
            printf("Invalid WSTERM argument: %s\n", argv[i]);
            return(-1);
        }
    }
    return(0);
}

    

/*
**********************************************************************

  Routine:            LEAVE_SCREEN 

  Function:
      This routine is called before exiting WSTERM to leave most of 
  WSTERM's screen on the display upon exiting. This is done by 
  scrolling the screen up one line and positioning the cursor at the 
  bottom left hand corner of the screen. 

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

leave_screen()
{
    union REGS reg, outreg;

    /* scroll screen up a line */
    reg.h.ah = VIDEO_SCROLL_UP_FUNC;
    reg.h.al = DEFAULT_LINES_TO_SCROLL;
    reg.h.ch = CURSOR_HOME_ROW;
    reg.h.cl = CURSOR_HOME_COL;
    reg.h.dh = SCREEN_LINES;
    reg.h.dl = SCREEN_COLS-1;
    reg.h.bh = wst_fg_screen.attr;
    int86(BIOS_VIDEO,&reg,&outreg);

    /* move cursor to bottom line of screen, column 0 */
    cursor_move(SCREEN_LINES,0);
}


/* End of WSTERM */
 



		    wsterm.mak                      10/12/88  1354.9rew 10/12/88  1327.6       29367



#  BEGIN MAKEFILE: WSTERM.MAK
#
#  Richard Lee - May 18, 1988
#  Makefile for compose using MICROSOFT MAKE
#
#  The following programs/utilities are needed to make WSTERM.EXE:
#    Lattice C compiler (v 2.15):     LC.COM
#    Macro Assembler:               MASM.EXE
#    Object librarian:            PLIB86.EXE
#    Linker:                        LINK.EXE
#
#  The following include files need to be kept in the current directory:
#     dos.mac
#  The following makefile variables should be assigned appropriate values:
#     SOURCE     = <directory containing all source files>
#     C_INCL     = <directory containing all C includes>
#     MOWSE_INCL = <directory containing all MOWSE includes>
#     WSTERM_INCL= <directory containing all WSTERM includes>
#     C_OBJ      = <pathname for c.obj for linking>
#     DB_OBJ     = <pathname for dblog.obj for debugging>
#     CLIB       = <pathname for C library for linking>
#     MLIB       = <pathname for MOWSE library for linking>
#

SOURCE      = \rich\wsterm\ph6_rel\\

C_INCL      = \lc\\

MOWSE_INCL  = \mowse\i\\

WSTERM_INCL = \rich\wsterm\ph6_rel\\

C_OBJ       = \lc\s\c.obj

DB_OBJ      = dblog.obj

CLIB        = \lc\s\lc.lib

MLIB        = \mowse\o\mowslib.lib

#
# COMPILATION DEFINITIONS
#

.c.obj:
        lc -ms -i$(C_INCL) -i$(MOWSE_INCL) -i$(WSTERM_INCL) -n -b $*

.asm.obj:
        masm $*,$*;

#
# OBJECTS
#

kbdisp.obj:	kbdisp.c wstdefs.h wstglob.h 

kbedit.obj:	kbedit.c wstdefs.h wstglob.h

kbinit.obj:	kbinit.c wstdefs.h 

kbmvcur.obj:	kbmvcur.c wstdefs.h wstglob.h 

kbprim.obj:	kbprim.c wstdefs.h wstglob.h 

kbprocel.obj:	kbprocel.c wstdefs.h wstglob.h 

kbredraw.obj:	kbredraw.c wstdefs.h wstglob.h 

save.obj:		save.asm

status.obj:	status.c wstdefs.h wstglob.h 

tbreak.obj:	tbreak.asm

wstaudit.obj:	wstaudit.c wstdefs.h wstglob.h

wstbkgnd.obj:   wstbkgnd.c wstdefs.h wstglob.h

wstedit.obj:    wstedit.c wstdefs.h wstglob.h

wsterm.obj:     wsterm.c wstdefs.h wstglob.h

wstfrgnd.obj:   wstfrgnd.c wstdefs.h wstglob.h

wstglob.obj:    wstglob.c wstdefs.h

wsthelp.obj:	wsthelp.c wstdefs.h wstglob.h

wsthist.obj:	wsthist.c wstdefs.h wstglob.h wsthist.h 

wstinit.obj:    wstinit.c wstdefs.h

wstkbscr.obj:   wstkbscr.c wstdefs.h wstglob.h

wstkill.obj:	wstkill.c wstkill.h wstdefs.h

wstscrn.obj:	wstscrn.c wstdefs.h wstglob.h

wstutil.obj:    wstutil.c wstglob.h

#
# LIBRARIES
#

kblib.lib:      kbdisp.obj kbedit.obj kbinit.obj kbmvcur.obj kbprim.obj \
                kbprocel.obj kbredraw.obj
	plib86 bu kblib.lib fi kbdisp,kbedit,kbinit,kbmvcur,kbprim,kbprocel,kbredraw

wstlib3.lib:     status.obj wsthelp.obj wstscrn.obj save.obj \
                tbreak.obj wstaudit.obj wsthist.obj wstkill.obj
        plib86 bu wstlib3.lib fi status,wsthelp,wstscrn,save,tbreak,wstaudit,wsthist,wstkill

wstlib1.lib:	wstedit.obj wstutil.obj
        plib86 bu wstlib1.lib fi wstedit.obj,wstutil.obj

wstlib2.lib:    wstbkgnd.obj wstfrgnd.obj wstglob.obj wstinit.obj wstkbscr.obj
        plib86 bu wstlib2.lib fi wstbkgnd,wstfrgnd,wstglob,wstinit,wstkbscr

#
# EXECUTABLE
#

wsterm.exe:     wsterm.obj wstlib3.lib wstlib1.lib wstlib2.lib kblib.lib
        link $(C_OBJ) wsterm,wsterm,,wstlib3+wstlib1+wstlib2+kblib+$(MLIB)+$(CLIB)/map
	mapsym wsterm.map

#   END MAKEFILE: WSTERM.MAK
 



		    wstfrgnd.c                      04/24/89  1040.7rew 04/24/89  1032.1       80685



/* ***********************************************************
   *                                                         *
   * Copyright, (C) Honeywell Bull Inc., 1988                *
   *                                                         *
   * Copyright, (C) Honeywell Information Systems Inc., 1987 *
   *                                                         *
   *********************************************************** */


/* HISTORY COMMENTS:
  1) change(87-03-21,Wallman), approve(87-03-21,MCR7586),
     audit(87-08-10,Flegel), install(87-08-07,MR12.1-1072):
     First release.
  2) change(87-09-02,Wallman), approve(87-09-02,MCR7586),
     audit(87-08-17,Flegel), install(87-09-10,MR12.1-1103):
     PBF to support the ABT order by flushing keyboard input.
  3) change(88-02-24,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Removed debugging code and unused variables, re-formatting.
  4) change(88-05-17,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Removed code for accessing the mini-buffer on the 25th line
     which is now used as a status line.
  5) change(88-07-25,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Documentation only, added header comments.
  6) change(88-08-09,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Fix references to include files; "wstdefs.h" was split into
     "wstdefs.h" and "wsttype.h" to avoid declaration clash; also,
     various constants defined to descriptive names.
  7) change(89-01-30,Lee), approve(89-01-02,MCR8043), audit(89-03-14,Flegel),
     install(89-04-24,MR12.3-1033):
     phx21233 - Initialize edit-mode screen size and line length variables from
     incoming mowse_io control (STM) message.
                                                   END HISTORY COMMENTS */

/* WSTFRGND - WSTERM module to process incoming foreground messages */

/* This modules holds the functions needed to process foreground messages. */

#include    <stdio.h>
#include    <dos.h>
#include    <ws.h>
#include    <ws_mcb.h>
#include    <wsmincap.h>
#include    "wstdefs.h"
#include    "wstglob.h"

/*
**********************************************************************

  Routine:            ASYNC_MSG 

  Function:
      This routine is called to handle an async message from the 
  host. 

  Parameters:
     (input)          force_sw - if TRUE, specifies that terminal 
                          messages are forced to be displayed; 
                          terminal messages are usually not displayed 
                          while handling partial keyboard input 

  Returns:            NONE 

**********************************************************************/

async_msg (force_sw)
int force_sw;       /* Force the message */

{
    /* If there's typeahead in kb.klin, the fg_msg signal is showing,
       and the force_sw is off, just return */

    if (fg_msg_showing && strlen (kb.klin) > 0 && ~force_sw)
        return;

    /* Is this a control message? */

    if (tdata_arg.minor_capability == FG_CONTROL_MESSAGE) { 
        ctrl_msg ();
        fg_msg_len = 0;
        return;
    }

    /* Its a display message */

    /* Discard message while waiting for FG_BREAK */

    if (break_sent)
        fg_msg_len = 0;

    else {

        /* Display the message if there's no typeahead or it is to be forced */
        if ((strlen (kb.klin) == 0 && edlin.length < 1) || force_sw) { 

            /* audit the message to file if file audit enabled */
            if (wst_f_audit)
                f_audit_msg(fg_msg.text,fg_msg_len);

            /* audit the message to printer if printer audit enabled */
            if (wst_p_audit)
                p_audit_msg(fg_msg.text,fg_msg_len,NULL);

            /* display the terminal message */
            emit_msg (fg_msg.text, fg_msg_len, ~PSTR);
            fg_msg_len = 0;

            if (fg_msg_showing) {    /* Erase fg_msg signal */
                signal_fg(OFF);
                fg_msg_showing = OFF;
            }
        }

        /* Otherwise, show the fg_msg signal */

        else if (~fg_msg_showing) { 
            signal_fg(ON);
            fg_msg_showing = ON;
        }
    }
}               /* End of async_msg */



/*
**********************************************************************

  Routine:            SYNC_MSG 

  Function:
      This routine is called to handle a sync message from the host. 

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

sync_msg ()
{

    /* Send any typeahead */

    if (read_active && kb.cndx > 0)
        extract_msg (~NO_BLOCK, ~TRO, TXMT_MSG, ~HIDE);

    /* Is this a control message? */

    if (tdata_arg.minor_capability == FG_CONTROL_MESSAGE)
        ctrl_msg ();

        /* Its a display message */

    else {
        if (~break_sent) { 
            emit_msg (fg_msg.text, fg_msg_len, ~PSTR);

            /* audit to file if file audit enabled */
            if (wst_f_audit)
                f_audit_msg(fg_msg.text,fg_msg_len);

            fg_msg_len = 0;
        }
    }

    fg_msg_len = 0;         /* Message is procesed */
}               /* End of sync_msg */



/*
**********************************************************************

  Routine:            CTRL_MSG 

  Function:
      This routine is called to handle control messages from the 
  host. 

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

ctrl_msg ()
{   
    char    msg_id [4]; /* Message ID */
    int no_blk_sw;      /* For no-block reads */

    strncpy (msg_id, fg_msg.ctl.hdr.id, 3);
    msg_id[3] = 0;

    /* ABORT */

    if (strcmp (msg_id, "ABT") == 0) { 
        kb.cndx = 0;
        kb.endx = 0;
        setmem (kb.pos, sizeof (kb.pos), NUL);
        setmem (kb.klin, sizeof (kb.klin), NUL);
        edlin.length = 0;           /* phx21233 R.L. - flush edit mode input */
        edlin.escape_flag = 0;
        edlin.escape_arg = -1;
        edlin.index = 0;
    }  /* PRINTER ON/OFF */

    else if (strcmp (msg_id, "PON") == 0 || strcmp (msg_id, "POF") ==
        0) { 
        kb.echo = -(strcmp (msg_id, "PON") == 0);

    }  /* SET TTY MODES */

    else if (strcmp (msg_id, "STM") == 0) { 
        line_kill = fg_msg.ctl.data.stm.kill;
        char_erase = fg_msg.ctl.data.stm.erase;
        lnc = fg_msg.ctl.data.stm.lnc;
        strncpy (erkl_chars, &fg_msg.ctl.data.stm.kill, 3);

        /* phx21233 RL - remove restriction of page and line size to screen size */
        screen.maxcol = fg_msg.ctl.data.stm.maxcol;
        screen.maxlin = fg_msg.ctl.data.stm.maxlin;

        /* Mode switches */
        sync = -((fg_msg.ctl.data.stm.modes & 1) != 0); /* Sync mode */
        crecho = -((fg_msg.ctl.data.stm.modes & 2) != 0);   /* CRECHO mode */
        lfecho = -((fg_msg.ctl.data.stm.modes & 4) != 0);   /* LFECHO mode */


    }  /* SET BREAK TABLE */

    else if (strcmp (msg_id, "SBT") == 0) { 
        strcpy (brk_table, fg_msg.ctl.data.break_table);

    }  /* ENTER SYNC MODE */

    else if (strcmp (msg_id, "ESM") == 0) { 
        strcpy (brk_table, fg_msg.ctl.data.break_table);
        sync = ON;
        kb.cndx = 0;
        kb.endx = 0;
        setmem (kb.pos, sizeof (kb.pos), NUL);
        setmem (kb.klin, sizeof (kb.klin), NUL);

        puttdata (FG_CONTROL_MESSAGE, "SME", 3);
    }  /* EXIT SYNC MODE */

    else if (strcmp (msg_id, "XSM") == 0) { 

        sync = OFF;
        kb.echo = ON;
        kb.cndx = 0;
        kb.endx = 0;
        setmem (kb.klin, sizeof (kb.klin), NUL);

        puttdata (FG_CONTROL_MESSAGE, "SMX", 3);
        clear_screen ();

    }  /* READ ... */

    else if (strcmp (msg_id, "RNE") == 0 || strcmp (msg_id, "RWE") ==
        0) {

        /* Terminate any active read */

        if (read_active) { 
            term_read = ON;
            if (kb.cndx > 0)
                extract_msg (~NO_BLOCK, ~TRO, TXMT_MSG,
                     ~HIDE);

            else
                send_msg (nul_str, 0);
        }

        read_count =  HI_BYTE_VALUE * fg_msg.ctl.data.rd_ct [0] +
            fg_msg.ctl.data.rd_ct [1];
        no_blk_sw = -(fg_msg.ctl.hdr.msb_size && NO_BLOCK_MASK);

        /* Set up the new read */

        read_active = ON;
        kb.echo = -(strcmp (msg_id, "RWE") == 0);

        /* Terminate again for a no-block read */

        if (no_blk_sw) { 
            term_read = ON;
            if (kb.cndx > 0)        /* Send typeahead */
                extract_msg (~NO_BLOCK, ~TRO, TXMT_MSG,
                     ~HIDE);

            else
                send_msg (nul_str, 0);
        }
    }  else /* Unsupported control order */  {

    }
}               /* End of ctrl_msg */


/* End of WSTFRGND */
   



		    wstglob.c                       04/24/89  1040.7rew 04/24/89  1032.9       67311



/* ***********************************************************
   *                                                         *
   * Copyright, (C) Honeywell Bull Inc., 1988                *
   *                                                         *
   * Copyright, (C) Honeywell Information Systems Inc., 1987 *
   *                                                         *
   *********************************************************** */


/* HISTORY COMMENTS:
  1) change(87-03-13,Wallman), approve(87-03-13,MCR7586),
     audit(87-08-10,Flegel), install(87-08-07,MR12.1-1072):
     First release
  2) change(87-08-14,Wallman), approve(87-08-14,MCR7586),
     audit(87-08-17,Flegel), install(87-09-10,MR12.1-1103):
     Change version to 1.01 for PBF to wstutil.
  3) change(87-09-02,Wallman), approve(87-09-02,MCR7586),
     audit(87-08-17,Flegel), install(87-09-10,MR12.1-1103):
     Change version to 1.02 for PBFs to wstutil, wstkbscr, wstedit, and
     wstfrgnd.
  4) change(87-09-17,Wallman), approve(87-09-17,PBF7586),
     audit(87-09-17,LJAdams), install(87-09-18,MR12.1-1109):
     Changed version to 1.03 for PBF to wstutil.
  5) change(88-02-24,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Removed debugging code and unused variables, re-formatting.
  6) change(88-07-25,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Documentation additions only. Added header comments to all routines.
  7) change(88-08-09,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Fix references to include files; "wstdefs.h" was split into
     "wstdefs.h" and "wsttype.h" to avoid declaration clash; also,
     various constants defined to descriptive names.
  8) change(88-08-23,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Added declarations for global variables for edit mode and
     WSTERM's various other modes.
  9) change(89-01-18,Lee), approve(89-01-18,MCR8043), audit(89-03-14,Flegel),
     install(89-04-24,MR12.3-1033):
     Updated version number to 1.08.
                                                   END HISTORY COMMENTS */


/* WSTGLOB - GLobal static data for WSTERM */

/* This module declares storage for all the global static variables used
   by WSTERM. The include file wstglob.h provides descriptions of this
   storage to the active modules. */

#include    <stdio.h>
#include    <dos.h>
#include    <ws.h>
#include    <ws_mcb.h>
#include    <ws_dcls.h>
#include    "wstdefs.h"

char    brk_table [96],         /* Break table characters */
        bs_str [2] = "\010",    /* ASCII BS as a string */
        char_erase = '#',       /* Character erase */
        erkl_chars [4],         /* Local edit chars as a string */
        F1_10 [10][4] = {       /* Normal function keys */
            "0", "2", "6", "8", ":",
            "<", ">", "P", "R", "T"  },
        F11_12 [2][4] = {       /* Shifted function keys */
            "1", "5" },

        line_kill = '@',        /* Line kill */
        lnc = '\\',             /* Literal escape character */
        local_action = NUL,     /* Local escape action char */
        nl [3] = "\015\012",    /* Multics NL as a string */
        nul_str [2] = "",       /* A null string */
        octstr [6] = "",        /* Display string for octval */
        spaces [11] = "          ",     /* Spaces for tabbing */
        version [6] = "1.08";   /* WSTERM version */

        int bk_msg_showing = OFF,   /* Message display control */
        break_sent = OFF,       /* An FG_BREAK is outstanding */
        crecho = OFF,           /* CRECHO mode switch */
        echo_delay = 1,         /* Max allowable delay for sync echo */
        fg_msg_len = 0,         /* Length of a foreground message */
        fg_msg_showing = OFF,   /* Message display control */
        lfecho = OFF,           /* LFECHO mode switch */
        mowse_active,           /* Switch showing MOWSE health */
        octsw = OFF,            /* Octal escape switch */
        octval = 0,             /* Octal escape value */
        oldtime = -1,           /* Previous clock */
        read_active = OFF,      /* Sync mode read is active */
        read_count = 0,         /* Number characters able to send */
        sync = OFF,             /* Sync (video) mode flag */
        term_read = OFF;        /* Terminate a read command */

mcb  * wst_mcb = NULL;

struct ds_struct ds;        /* Keyboard display data */

union fg_msg_struct fg_msg; /* Foreground (incoming) messages */

struct get_struc tdata_arg; /* Gettdata argument */

struct kb_struct kb;        /* Keyboard input data */

struct screen_struct screen;    /* Screen bookkeeping */



/*****
 variables used to maintain WSTERM's various modes
******/

/* set by our ^BREAK handler to indicate ^BREAK was hit */
int break_flag;

/* flag indicates WSTERM's displayed status (glass,sync,async) */
int wst_status;

/* use while filtering out escape codes */
int clr_index;

/* indicates if FANSI-CONSOLE is being used */
int wst_fansi_flag;

/* indicates if /B was specified for using ^BREAK to send a break */
int break_sends_to_host;

/* indicates if WSTERM should display EOP after a screenful */
int wst_paging;

/* indicates if WSTERM should freeze display (no scroll) */
int wst_freeze;

/* indicates if WSTERM should audit to file */
int wst_f_audit;

/* indicates if WSTERM should audit to line printer */
int wst_p_audit;

/* pointer to string containing audit file name */
char *audit_file_name;

/* specifies printer card (0-2) to use */
int wst_printer_card;

int wst_edit_mode;
int glass_edit_mode;

/* This table is used to determine whether a particular character
   is valid following an escape character. This restricts the
   number of invalid escape sequences from getting through which
   may possibly kill the screen driver.
*/
char is_esc[] = {
     0, 0, 0, 0, 0, 0, 0, 0, 
     0, 0, 0, 0, 0, 0, 0, 0, 
     0, 0, 0, 0, 0, 0, 0, 0, 
     0, 0, 0, 0, 0, 0, 0, 0, 

     0, 0, 0, 0, 0, 0, 0, 0, 
     0, 0, 0, 0, 0, 0, 0, 0, 
     0, 0, 0, 0, 0, 0, 0, 1, 
     1, 0, 0, 0, 1, 1, 1, 0, 

     0, 0, 0, 0, 1, 1, 0, 0, 
     1, 0, 1, 0, 0, 1, 0, 0, 
     0, 0, 0, 0, 0, 0, 0, 0, 
     0, 0, 1, 0, 1, 1, 1, 1, 

     0, 0, 1, 1, 0, 0, 0, 0, 
     0, 0, 0, 0, 0, 0, 1, 1, 
     0, 0, 0, 0, 0, 0, 0, 0, 
     0, 0, 0, 0, 1, 1, 1, 0
};


/* Screen buffers for scratch, background, foreground and help screens */
/* These structures are used to save the contents of a particular
   screen and the cursor position before switching to another screen.
*/
SCREEN wst_tmp_screen;
SCREEN wst_bg_screen;
SCREEN wst_fg_screen;
SCREEN wst_help_screen;

/* edit mode line and line information */
EDIT_LINE edlin;

/* edit mode screen size */
SCREEN_SIZE ss;

/* flag to indicate block or under line cursor type */
int cursor_type;

/* list of printer errors detected */
char *print_error_list[] = {
    "OFF Line",
    "No paper",
    "Printer not ready"
};

/* table of months for formatting into audit begin/end messages */
char *month_tab[] = {
"Jan.",
"Feb.",
"Mar.",
"Apr.",
"May",
"June",
"July",
"Aug.",
"Sep.",
"Oct.",
"Nov.",
"Dec."
};

int wst_prt_timeout;    /* original printer timeout value */
int orig_break_status;  /* original CTRL-C checking status */
union REGS scroll_regs; /* registers for scrolling up 1 line */

/* End of WSTGLOB */
 



		    wsthelp.c                       10/12/88  1357.2rew 10/12/88  1330.1      109998



/* ********************************************
   *                                          *
   * Copyright, (C) Honeywell Bull Inc., 1988 *
   *                                          *
   ******************************************** */

/* HISTORY COMMENTS:
  1) change(88-04-21,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Created.
  2) change(88-07-25,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Documentation additions only. Added header comments to all routines.
  3) change(88-08-09,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Fix references to include files; "wstdefs.h" was split into
     "wstdefs.h" and "wsttype.h" to avoid declaration clash; also,
     various constants defined to descriptive names.
                                                   END HISTORY COMMENTS */

#include <dos.h>
#include "wstdefs.h"
#include "wstglob.h"

char *general_help_lines[] = {
"-------------------------- WSTERM FUNCTIONS ----------------------------------",
"ALT-0  Send an ASCII NUL             |  ALT-D  Display pending foreground",
"ALT-B  Send a break to host          |         message",
"^BREAK Send a break if /B control    |  ALT-H  Enter help screen",
"       argument specified            |  ALT-M  Enter background screen",
"ALT-C  Clear the display             |  ALT-Q  Exit (quit) wsterm",
"                                     |  ALT-S  No scroll (any key resumes)",
"",
"",
"------------------------- WSTERM MODES (toggles) -----------------------------",
"ALT-I,<INS> keyboard insert/replace -|  ALT-E      edit mode ON/OFF",
"            (in edit mode only)      |  ALT-O      local paging ON/OFF",
"ALT-F       file audit ON/OFF        |  ALT-P      line printer audit ON/OFF",
"",
"",
"",

"-------------------------------- EDIT MODE -----------------------------------",
"A variety of editing and history functions are available in edit mode. While",
"in edit mode, all keyboard input is buffered and echoed, allowing various",
"editing to take place until the <RETURN> key is hit, sending the line to the",
"host. Note that before the attach_mowse/atm command is invoked, the host",
"also echoes input, resulting in a \"double echo\". Thus it may be desirable",
"to turn off echoing by the host (e.g. stty -modes ^echoplex) in this case.",
"",
"---------------------- Edit Mode cursor movement keys ------------------------",
"^A,<HOME> cursor to beginning of line|  ^E,<END>  move cursor to end of line",
"^F,->     move cursor forward a char |  ^B,->     move cursor backward a char",
"^->,esc F move cursor forward a word |  ^<-,esc B move cursor backward a word",
"",
"-------------------------- Edit Mode editing keys ----------------------------",
"Backspace erase (previous char)      |  @          kill (to beginning of line)",
"<DEL>   delete previous char         |  esc <DEL>  delete to previous word",
"^D      delete current char          |  esc D      delete to end of word",
"^K      kill to end of line          |  \\          literal escape character",
"",
"*   cursor movement and edit keys may be repeated N times by entering",
"    <ESC> N before the key. N is some unsigned integer value.",
"",
"----------------------- Edit Mode History Functions --------------------------",
"ALT-V    enter history screen        |   ^P     recall previous command",
"NN ^P    select the NNth previous    |   ^N     recall the next command",
"         command",
"",
"",
"",
"",
"",
"",
"----------------------------- Status Line ------------------------------------",
"The bottom line of the screen is the status line. It is displayed in reverse",
"video and is used to display local messages to the user. In the foreground",
"screen, WSTERM's current mode settings are displayed as follows:",
"",
"G Edit Replace Audit(FILE,PRINTER) Page No-Scroll [background] [foreground]",
"1  2     3              4            5      6           7            8",
"",
"1) G=Glass tty (before atm); A=Async (after atm); S=Sync (atm & video)",
"2) Edit=Edit mode enabled; <BLANK>=Edit mode disabled",
"3) Replace=text overstrikes; Insert=text inserts; <BLANK>=not in Edit mode",
"4) <BLANK>=No audit; Audit(FILE)=File audit; Audit(PRINTER)=Printer audit;",
"   Audit(FILE,PRINTER)=File and Printer audit",
"5) Page=local paging after atm; <BLANK>=no local page after atm",
"6) <BLANK>=scrolling; No-Scroll=local stopping of scrolling",
"7) <BLANK>-no background messages; [background]=background message(s) pending,",
"   enter background screen to examine messages.",
"8) <BLANK>-no foreground messages; [foreground]=foreground message(s) pending",
"   while entering input, hit ALT-D to display message, then resume input",
"",
"Note: The status line is also used to temporarily display error messages.",
"      Status line information is also different in other screens. See help",
"      for other screens."
};


#define N_GENERAL_HELP_LINES    (sizeof(general_help_lines)/sizeof(char *))

char *bg_help_lines[] = {
"----------------------------BACKGROUND SCREEN---------------------------------",
"This screen displays the number of pending background messages and displays",
"the next background message whenever <ALT-M> or <ALT-D> is hit. The user",
"may also enter this screen just to look at background messages which were",
"previously displayed but have not been scrolled off.",
"",
"    ALT-M,ALT-D - display next background messages if it exists",
"    Q           - quit from background screen",
"    P           - enter background polling mode",
"",
"----------------------------BACKGROUND POLLING--------------------------------",
"This screen displays all pending background messages and sits in a polling",
"loop, displaying any background message whenever it is received.",
"",
"    Q           - quit from background screen",
"    <other>     - toggle between scroll and no scroll",
"",
"-------------------- Replying to background query messages -------------------",
"When the message \"Enter Reply:\" appears on the status line, the most recent",
"background message displayed is a background query message. Any text until",
"a <RETURN> is hit will then be sent as a reply to this query.",
"",
"NOTE: Acceptable keys are listed between \"[\" and \"]\" on the status line"
};


#define N_BG_HELP_LINES    (sizeof(bg_help_lines)/sizeof(char *))

char *history_help_lines[] = {
"---------------- HISTORY SCREEN FUNCTIONS (in edit mode only) ----------------",
"This screen allows previously entered lines of input to be examined and/or",
"selected. Selecting an input line copies that line as current input, just",
"as if entered from the keyboard. Further editing may take place before",
"sending the line to the host by hitting the <RETURN> key.",
"",
" NN <RETURN> - exit the history screen and select the specified history",
"               line (beeps if invalid selection)",
" NN <L>      - shift screen left NN columns; NN defaults to 1",
" NN <R>      - shift screen right NN columns; NN defaults to 1",
" <P>         - display previous history page (beeps if no previous page)",
" <N>         - display next history page (beeps if no next page)",
" <Q>         - quit from the history screen",
"",
"",
"NOTE 1: NN refers to an unsigned integer value and is specified by entering",
"        any of the digit keys (0 thru 9).",
"NOTE 2: The status line will display the current screen offset.",
"NOTE 3: Recognized command keys are listed between \"[\" and \"]\" on the",
"        status line."
};

#define N_HISTORY_HELP_LINES    (sizeof(history_help_lines)/sizeof(char *))

/* help - this routine displays the help screen in a manner
          transparent to the caller. The parameter "cur_scr"
          specifies the screen to save the current screen
          contents to before displaying the help information.
*/


/*
**********************************************************************

  Routine:            HELP 

  Function:
      This routine saves the contents of the current screen and 
  invokes the help screen. The status line provides further 
  instructions to allow more help pages to be displayed or quitting 
  from the help screen. The original screen contents are restored on 
  quitting from help, making the invokation of help transparent to 
  the caller. 

  Parameters:
     (input)          order - flag to specify in what order the help 
                          topics should be displayed 

  Returns:            NONE 

**********************************************************************/

help(order)
int order;
{
    int i;
    int cnt;
    int ch;
    char **hlp[N_HELP_TOPICS];
    int  hlp_cnt[N_HELP_TOPICS];
    int  help_index;

    /* determine what order the topics are to be displayed */
    if (order == BG_HELP) {
        hlp[FIRST_TOPIC_INDEX] = bg_help_lines;
        hlp_cnt[FIRST_TOPIC_INDEX] = N_BG_HELP_LINES;
        hlp[SECOND_TOPIC_INDEX] = general_help_lines;
        hlp_cnt[SECOND_TOPIC_INDEX] = N_GENERAL_HELP_LINES;
        hlp[THIRD_TOPIC_INDEX] = history_help_lines;
        hlp_cnt[THIRD_TOPIC_INDEX] = N_HISTORY_HELP_LINES;
    }

    else if (order == HISTORY_HELP) {
        hlp[FIRST_TOPIC_INDEX] = history_help_lines;
        hlp_cnt[FIRST_TOPIC_INDEX] = N_HISTORY_HELP_LINES;
        hlp[SECOND_TOPIC_INDEX] = general_help_lines;
        hlp_cnt[SECOND_TOPIC_INDEX] = N_GENERAL_HELP_LINES;
        hlp[THIRD_TOPIC_INDEX] = bg_help_lines;
        hlp_cnt[THIRD_TOPIC_INDEX] = N_BG_HELP_LINES;
    }

    else {
        hlp[FIRST_TOPIC_INDEX] = general_help_lines;
        hlp_cnt[FIRST_TOPIC_INDEX] = N_GENERAL_HELP_LINES;
        hlp[SECOND_TOPIC_INDEX] = bg_help_lines;
        hlp_cnt[SECOND_TOPIC_INDEX] = N_BG_HELP_LINES;
        hlp[THIRD_TOPIC_INDEX] = history_help_lines;
        hlp_cnt[THIRD_TOPIC_INDEX] = N_HISTORY_HELP_LINES;
    }

    /* save the contents of the screen to the user specified buffer */
    save_wst_screen(&wst_tmp_screen);

    /* hide the cursor */
    cursor_move(HIDE_CURSOR_ROW,HIDE_CURSOR_COL);

    /* initialize input char, working index and line counter */
    ch = 0;
    i = 0;
    cnt = 0;

    /* initialize topic index */
    help_index = 0;

    /* clear the temporary screen buffer */
    wst_screen_clear(&wst_help_screen);

    while (TRUE) {
            if (help_index >= LAST_HELP_TOPIC_INDEX && i >= hlp_cnt[help_index])
                break;

            /* increment line counter and see if screen is full */
            if (cnt >= N_HELP_PAGE_LINES || i >= hlp_cnt[help_index]) {

                /* screen full, dump the contents of the temporary screen buffer */
                restore_wst_screen(&wst_help_screen);

                /* hide the cursor */
                cursor_move(HIDE_CURSOR_ROW,HIDE_CURSOR_COL);

                /* update the status line */
                status_line("HELP SCREEN: <q> - quit, <any other> - next");

                /* wait for key press and determine whether to quit */
                ch = getkey(BLOCK);
                if (uppercase(ch) == 'Q')
                    break;

                /* reset line counter and clear the temporary screen buffer */
                cnt = 0;
                wst_screen_clear(&wst_help_screen);

                if (i >= hlp_cnt[help_index]) {
                    help_index++;
                    i = 0;
                    if (help_index > LAST_HELP_TOPIC_INDEX) break;
                }
            }

            /* write a line of help info to the temporary screen buffer */
            wst_screen_printline(&wst_help_screen,hlp[help_index][i]);
            i++;
            cnt++;
    }

    /* if user did not hit quit to exit help screen */
    if (uppercase(ch) != 'Q') {

        /* dump contents of temporary screen buffer */
        restore_wst_screen(&wst_help_screen);

        /* hide the cursor */
        cursor_move(HIDE_CURSOR_ROW,HIDE_CURSOR_COL);

        /* update status line */
        status_line("HELP SCREEN: <any key> - quit");
        wait_for_key();
    }

    /* restore contents of original screen and turn cursor back on */
    restore_wst_screen(&wst_tmp_screen);
}
  



		    wsthist.c                       04/24/89  1040.7rew 04/24/89  1033.5      310698



/* ********************************************
   *                                          *
   * Copyright, (C) Honeywell Bull Inc., 1988 *
   *                                          *
   ******************************************** */

/* HISTORY COMMENTS:
  1) change(88-07-11,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Created.
  2) change(88-07-25,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Documentation additions only. Added header comments to all routines.
  3) change(88-08-09,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Fix references to include files; "wstdefs.h" was split into
     "wstdefs.h" and "wsttype.h" to avoid declaration clash; also,
     various constants defined to descriptive names.
  4) change(89-01-18,Lee), approve(89-01-02,MCR8043), audit(89-03-14,Flegel),
     install(89-04-24,MR12.3-1033):
     phx21233 - Updated flags to control visibility of chars redrawn, depending
     on state of keyboard echoing, for lines fetched from history buffer.
                                                   END HISTORY COMMENTS */

#include <dos.h>
#include "wstdefs.h"
#include "wstglob.h"
#include "wsthist.h"

/*
**********************************************************************

  Routine:            HISTORY_SCREEN 

  Function:
      This routine enters the history screen, allowing several 
  several options. These include displaying the next page (if enough 
  history items exist), the previous page, shifting the screen left 
  or right to allow viewing of a long history command, selecting a 
  history command or quitting the history screen. 

  Parameters:
     (output)         cur_scr - specifies the screen buffer to use 
                          for saving the screen contents to before 
                          the history screen is displayed 

  Returns:            NONE 

**********************************************************************/

history_screen(cur_scr)
SCREEN *cur_scr;
{
    int ch;
    ITEM_INFO item;
    int offset;
    int code;
    char line[SCREEN_COLS+2];
    char stat_mess[SCREEN_COLS+1];
    int selection;

    /* save the contents of the screen to the user specified buffer */
    save_wst_screen(cur_scr);

    /* hide the cursor */
    cursor_move(HIDE_CURSOR_ROW,HIDE_CURSOR_COL);

    ch = NONE;
    offset = HIST_DEFAULT_0_ARG;

    /* clear the temporary screen buffer */
    wst_screen_clear(&wst_tmp_screen);
    wst_screen_printline(&wst_tmp_screen,"");

    /* initialize structure for displaying history items */
    init_history_display(&item);

    /* loop until user enters 'q' to quit or no more to display */
    while (uppercase(ch) != 'Q' && item.start_chars_in_buff > NONE) {

        /* try to extract and display a history line */
        code = extract_hist_lines(&item,offset,line);

        if (code >= 0)
            /* write a line of help info to the temporary screen buffer */
            wst_screen_printline(&wst_tmp_screen,line);

        /* if no more history items or a pageful */
        if (code < 0 || item.cur_display_count >= HIST_MAX_LINES) {

            /* screen full, dump the contents of the temporary screen buffer */
            restore_wst_screen(&wst_tmp_screen);

            /* hide the cursor */
            cursor_move(HIDE_CURSOR_ROW,HIDE_CURSOR_COL);

            /* update the status line */
            if (item.cur_chars_in_buff < 1)
                sprintf(stat_mess,
                    "HISTORY SCREEN:       offset %3d  <ALT-H>-help  [<Q>,<RETURN>,<P>,<N>,<L>,<R>]",
                    offset);
            else
                sprintf(stat_mess,
                    "HISTORY SCREEN(more): offset %3d  <ALT-H>-help  [<Q>,<RETURN>,<P>,<N>,<L>,<R>]",
                    offset);

            status_line(stat_mess);

            /* wait for input from keyboard */
            selection = HIST_DEFAULT_0_ARG;

            while (TRUE) {
                ch = getkey(BLOCK);

                /* input is part of a numeric argument */
                if (ch >= SMALLEST_DECI_DIGIT && ch <= LARGEST_DECI_DIGIT) {
                    if (selection >= MAX_ARG_LIMIT) {
                        selection = HIST_DEFAULT_0_ARG;
                        beep();
                    }
                    else {
                        selection *= 10;
                        selection += ch - '0';
                    }
                }

                /* shift screen right */
                else if (uppercase(ch) == 'R') {

                    /* do only if screen is shifted left */
                    if (offset > NONE) {

                        /* examine numeric argument to determine amount to shift */
                        if (selection < 1) selection = 1;
                        if (offset >= selection)
                            offset -= selection;
                        else
                            offset = NONE;

                        /* redisplay from beginning of current page */
                        reset_hist_page(&item);
                        selection = HIST_DEFAULT_0_ARG;

                        /* quick check to optimize consecutive hitting
                           of screen shift keys; if next key buffered is
                           a screen shift key, just recalculate the offset
                           to minimize the number of screen redraws */

                        while (uppercase((ch = checkkey())) == 'R' ||
                            uppercase(ch) == 'L') {
                            ch = getkey(BLOCK);
                            if (uppercase(ch) == 'L') {
                                if (offset < HIST_MAX_SCREEN_SHIFT)
                                    offset++;
                            }
                            else {
                                if (offset > NONE)
                                    offset--;
                            }
                        }

                        break;
                    }
                    selection = HIST_DEFAULT_0_ARG;
                }

                /* shift screen left */
                else if (uppercase(ch) == 'L') {

                    /* do only if screen can be shift left some more */
                    if (offset < HIST_MAX_SCREEN_SHIFT) {

                        /* examine numeric argument to determine amount to shift */
                        if (selection < 1) selection = 1;
                        if (offset + selection <= HIST_MAX_SCREEN_SHIFT)
                            offset += selection;
                        else
                            offset = HIST_MAX_SCREEN_SHIFT;

                        /* redisplay from beginning of current page */
                        reset_hist_page(&item);
                        selection = HIST_DEFAULT_0_ARG;

                        /* quick check to optimize consecutive hitting
                           of screen shift keys; if next key buffered is
                           a screen shift key, just recalculate the offset
                           to minimize the number of screen redraws */

                        while (uppercase((ch = checkkey())) == 'L' ||
                            uppercase(ch) == 'R') {
                            ch = getkey(BLOCK);
                            if (uppercase(ch) == 'L') {
                                if (offset < HIST_MAX_SCREEN_SHIFT)
                                    offset++;
                            }
                            else {
                                if (offset > NONE)
                                    offset--;
                            }
                        }

                        break;
                    }
                    selection = HIST_DEFAULT_0_ARG;
                }

                /* handle selection of history command */
                else if (ch == RETURN_KEY && selection > NONE) {

                    /* if no such command */
                    if (fetch_nth_command(selection,
                        edlin.line, &edlin.length) < 0) {
                        selection = HIST_DEFAULT_0_ARG;
                    }

                    /* command successfully fetched in edlin.line */
                    else {
                        /* set flag to break out of outer loop */
                        ch = 'Q';
                        /* break out of first loop */
                        break;
                    }
                }

                /* display next history page */
                else if (ch == ' ' || uppercase(ch) == 'N') {
                    selection = HIST_DEFAULT_0_ARG;
                    if (next_hist_page(&item) >= 0)
                        break;
                    else
                        beep();
                }

                /* display previous history page */
                else if (uppercase(ch) == 'P') {
                    selection = HIST_DEFAULT_0_ARG;
                    if (previous_hist_page(&item) >= 0)
                        break;
                    else
                        beep();
                }

                /* quit from history screen */
                else if (uppercase(ch) == 'Q') {
                    /* set to 0 to indicate no history line selected */
                    selection = HIST_DEFAULT_0_ARG;
                    break;
                }

                /* display help information */
                else if (ch == ALT_H) {
                    help(HISTORY_HELP);
                    status_line(stat_mess);
                }

                /* unrecognized command, beep() */
                else {
                    selection = HIST_DEFAULT_0_ARG;
                    beep();
                }
            }

            /* clear screen buffer and leave blank line at top */
            wst_screen_clear(&wst_tmp_screen);
            wst_screen_printline(&wst_tmp_screen,"");
        }
    }

    /* restore contents of original screen and turn cursor back on */
    restore_wst_screen(cur_scr);

    /* history command selected, erase previously displayed command
       and draw the new one
    */
    if (selection > NONE) {
        /* phx21233 R.L. - update flags to determine visibility of chars redrawn */
        update_echo_flags(&edlin);

        erase_edit_line(&edlin);

        /* cursor at beginning of line */
        edlin.index = ZERO_INDEX_VALUE;
        /* reset escape flag and argument */
        edlin.escape_flag = NO_ESC_FUNC;
        edlin.escape_arg = NO_ESC_ARG;
        redraw_edit_line(&edlin);
        cursor_eol(&edlin);
    }
}



/*
**********************************************************************

  Routine:            SAVE_TO_HISTBUFF 

  Function:
      This routine saves a command to the history buffer. 

  Parameters:
     (input)          str - specifies the buffer containing the 
                          command 
     (input)          item_size - specifies the number of bytes in 
                          the command to be saved 

  Returns:            NONE 

**********************************************************************/

save_to_histbuff(str,item_size)
char *str;
int item_size;
{
    int i, j;
    int lo_byte;
    int hi_byte;
    int first_chunk;
    int buffer_empty;

    /* if item cannot fit into hist buffer */
    if (item_size+TOTAL_SIZE_SPEC_BYTES >= HIST_BUFF_SIZE) {
        beep();
        return;
    }

    /* delete items from tail until enough room */
    while (hbi.chars_free < item_size+TOTAL_SIZE_SPEC_BYTES) {

        i = (hbi.tail + hbi.tail_item_size) % HIST_BUFF_SIZE;

        /* if insertion will overwrite all existing items */
        if (i == hbi.head && hbi.chars_free == NONE) {
            /* re-initialize; otherwise, corrupted values will be used */
            init_histbuff();
            break;
        }

        /* update pointer to tail of circular buffer */
        hbi.tail = i;

        /* get size of item stored in first two bytes of item */
        lo_byte = hbi.kb[i];
        i = (i+1)%HIST_BUFF_SIZE;
        hi_byte = hbi.kb[i];

        /* update amount of chars freed */
        hbi.chars_free += hbi.tail_item_size;

        /* update size of item pointed to by tail pointer */
        hbi.tail_item_size = (hi_byte * MAX_7_BIT_VAL) + lo_byte;
    }

    /* determine if the history buffer is empty */
    if (hbi.head == hbi.tail && hbi.chars_free == HIST_BUFF_SIZE)
        buffer_empty = TRUE;
    else
        buffer_empty = FALSE;

    /* update size of item pointed to by head pointer */
    hbi.head_item_size = item_size+TOTAL_SIZE_SPEC_BYTES;
    /* update buffer space left after adding this new item */
    hbi.chars_free -= hbi.head_item_size;

    /* encode the size of new item into two bytes */
    lo_byte = hbi.head_item_size % MAX_7_BIT_VAL;
    hi_byte = hbi.head_item_size / MAX_7_BIT_VAL;

    /* copy size of items as first two bytes of item */
    i = hbi.head;
    hbi.kb[i] = lo_byte;
    i = (i+1)%HIST_BUFF_SIZE;
    hbi.kb[i] = hi_byte;
    i = (i+1)%HIST_BUFF_SIZE;

    /* copy across end boundary of buffer to beginning of buffer? */
    if (i+item_size > HIST_BUFF_SIZE) {

        /* determine amount to copy up to end of buffer */
        first_chunk = HIST_BUFF_SIZE - i;
        /* determine amount to copy starting from beginning of buffer */
        item_size -= first_chunk;

        /* copy to history buffer */
        for (j = ZERO_INDEX_VALUE; j < first_chunk; j++)
            hbi.kb[i++] = str[j];
        for (i = ZERO_INDEX_VALUE; i < item_size; i++)
            hbi.kb[i] = str[j++];

    }

    /* does not wrap around history buffer, do straight copy */
    else {
        for (j = ZERO_INDEX_VALUE; j < item_size; j++)
            hbi.kb[i++] = str[j];
    }

    /* last two bytes of item must also hold the size of the item */
    i = i % HIST_BUFF_SIZE;
    hbi.kb[i] = lo_byte;
    i = (i+1) % HIST_BUFF_SIZE;
    hbi.kb[i] = hi_byte;
    i = (i+1) % HIST_BUFF_SIZE;

    /* if buffer was empty, make tail and head the same */
    if (buffer_empty) {
        hbi.tail = hbi.head;
        hbi.tail_item_size = hbi.head_item_size;
    }
    /* head pointer to next location to add */
    hbi.head = i;

    /* reset the current pointer to head on save to history buffer */
    hbi.current = hbi.head;
    hbi.current_size = hbi.head_item_size;
    hbi.head_of_histbuff = TRUE;

    /* reset direction flag */
    hbi.direction = HIST_START_DIR;

}



/*
**********************************************************************

  Routine:            INIT_HISTBUFF 

  Function:
      This routine initializes all fields in the history buffer 
  structure to indicate an empty history buffer. 

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

init_histbuff()
{
    
    /* all indices point to beginning of history buffer */
    hbi.head = ZERO_INDEX_VALUE;
    hbi.tail = ZERO_INDEX_VALUE;
    hbi.current = ZERO_INDEX_VALUE;

    /* all items have zero size in empty history buffer */
    hbi.head_item_size = ZERO_BYTES;
    hbi.tail_item_size = ZERO_BYTES;
    hbi.current_size = ZERO_BYTES;

    /* chars free is same as size of history buffer */
    hbi.chars_free = HIST_BUFF_SIZE;

    /* currently at head of history buffer */
    hbi.head_of_histbuff = TRUE;

    /* no particular direction */
    hbi.direction = HIST_START_DIR;
}



/*
**********************************************************************

  Routine:            INIT_HISTORY_DISPLAY 

  Function:
      This routine initializes the structure used to control history 
  screen displaying. 

  Parameters:
     (output)         item - specifies the structure to initialize 

  Returns:            NONE 

**********************************************************************/

init_history_display(item)
ITEM_INFO *item;
{

    /* unique number associated with each history command */
    item->start_item_no = ZERO_BYTES;

    /* chars in the history buffer, displaying ends when no more chars */
    item->start_chars_in_buff = HIST_BUFF_SIZE - hbi.chars_free;

    /* index into history buffer of what item to display next */
    item->start_item_index = hbi.head;

    /* count of how many items displayed in current page */
    item->start_display_count = ZERO_BYTES;

    /* size of item to be displayed next */
    item->start_size = hbi.head_item_size;

    /* the running values for the above starting values */
    item->cur_item_no = item->start_item_no;
    item->cur_chars_in_buff = item->start_chars_in_buff;
    item->cur_item_index = item->start_item_index;
    item->cur_display_count = item->start_display_count;
    item->cur_size = item->start_size;
}



/*
**********************************************************************

  Routine:            RESET_HIST_PAGE 

  Function:
      This routine resets the history display control structure for 
  redisplaying the current history page. 

  Parameters:
     (input/output)   item - specifies the history display control 
                          structure to use 

  Returns:            0 always

**********************************************************************/

reset_hist_page(item)
ITEM_INFO *item;
{

    /* re-assign the running values with the starting values */
    item->cur_item_no = item->start_item_no;
    item->cur_chars_in_buff = item->start_chars_in_buff;
    item->cur_item_index = item->start_item_index;
    item->cur_display_count = item->start_display_count = ZERO_BYTES;
    item->cur_size = item->start_size;

    return(0);
}



/*
**********************************************************************

  Routine:            NEXT_HIST_PAGE 

  Function:
      This routine sets the history display control structure for 
  displaying the next history page. 

  Parameters:
     (input/output)   item - specifies the history display control 
                          structure to use 

  Returns:            -1 if no items are on the next page
                      0 if otherwise 

**********************************************************************/

next_hist_page(item)
ITEM_INFO *item;
{
    /* no action of nothing more to display */
    if (item->cur_chars_in_buff < 1)
        return(-1);

    /* starting values are assigned results of previous running values */
    item->start_item_no = item->cur_item_no;
    item->start_chars_in_buff = item->cur_chars_in_buff;
    item->start_item_index = item->cur_item_index;
    item->start_display_count = item->cur_display_count = ZERO_BYTES;
    item->start_size = item->cur_size;

    return(0);
}


/*
**********************************************************************

  Routine:            PREVIOUS_HIST_PAGE 

  Function:
      This routine sets the history display control structure for 
  displaying the previous history page. 

  Parameters:
     (input/output)   item - specifies the history display control 
                          structure to use 

  Returns:            -1 if no items are in previous page 
                      0 otherwise 

**********************************************************************/

previous_hist_page(item)
ITEM_INFO *item;
{
    int i;
    int hi, lo;
    int cnt;
    int times;

    /* no previous page if current page does not start past last line
       of first page
    */
    if (item->start_item_no < HIST_MAX_LINES)
        return(-1);

    /* traverse backward through history buffer to update item fields */
    for (times = 0; times < HIST_MAX_LINES; times++) {

        /* update pointer to next item to display */
        i = item->start_item_index;

        /* extract size of item from kill buffer */
        lo = hbi.kb[i];
        i = (i+1)%HIST_BUFF_SIZE;
        hi = hbi.kb[i];
        i = (i+1)%HIST_BUFF_SIZE;

        cnt = (hi * MAX_7_BIT_VAL) + lo;

        /* decrement item index circularly by size */
        item->start_item_index = (item->start_item_index + cnt)%HIST_BUFF_SIZE;

        /* decrement id number of history command item */
        item->start_item_no--;

        /* tally characters to be displayed in history buffer */
        item->start_chars_in_buff += cnt;

        /* update item size */
        item->start_size = cnt;

    }

    /* current values are same as starting values */
    item->cur_item_index = item->start_item_index;
    item->cur_item_no = item->start_item_no;
    item->cur_chars_in_buff = item->start_chars_in_buff;
    item->cur_display_count = item->start_display_count = ZERO_BYTES;
    item->cur_size = item->start_size;

    return(0);
}



/*
**********************************************************************

  Routine:            EXTRACT_HIST_LINES 

  Function:
      This function extracts commands from the history buffer and 
  copies it into a string. The length of the string will be at most, 
  the width of the screen. If a command exceeds the width of the 
  screen, the string will be terminated by a '$' to indicate there is 
  more that is not shown. A value is specified to allow portions of 
  long commands to be displayed starting from an offset from the 
  beginning of the command. 

  Parameters:
     (input)          item - structure containing information as to 
                          which item in the history buffer to extract 
     (input)          offset - specifies the offset from the 
                          beginning of the line to begin extracting 
     (output)         line - pointer to the string to pass back the 
                          history command; if the length of the 
                          command is less than the value of 'offset', 
                          an empty string is passed back 

  Returns:            -1 if unsuccessful 
                      0 if successful 

**********************************************************************/

extract_hist_lines(item,offset,line)
ITEM_INFO *item;
int offset;
char *line;
{
    int i, j;
    int lo, hi;
    int cnt;
    int linelen;
    int previous;

    /* entire buffer is free, nothing in buffer */
    if (item->cur_chars_in_buff < 1)
        return(-1);

    /* get index to next item to extract */
    i = item->cur_item_index;

    /* check if no more previous items */
    if (i == hbi.tail && !hbi.head_of_histbuff)
        return(-1);

    /* skip over current item and point to previous item */
    previous = (item->cur_item_index + HIST_BUFF_SIZE - item->cur_size)
               % HIST_BUFF_SIZE;
    i = previous;

    /* if history buffer is not empty */
    if (item->cur_chars_in_buff > NONE) {

        /* determine the size of this previous item */
        lo = hbi.kb[i];
        i = (i+1)%HIST_BUFF_SIZE;
        hi = hbi.kb[i];
        i = (i+1)%HIST_BUFF_SIZE;

        cnt = (hi * MAX_7_BIT_VAL) + lo;

        /* 4 bytes are used store history item size; subtract to    */
        /* get command length                                       */
        cnt -= TOTAL_SIZE_SPEC_BYTES;
        item->cur_chars_in_buff -= TOTAL_SIZE_SPEC_BYTES;

        /* format line number into resulting line */
        sprintf(line,"%3d  ", item->cur_item_no+1);
        linelen = strlen(line);

        /* copy the history command if offset does not exceed       */
        /* command's length                                         */
        if (cnt > offset) {

            /* index into specified offset of history command */
            i = (i+offset) % HIST_BUFF_SIZE;
            item->cur_chars_in_buff -= offset;
            cnt -= offset;

            /* copy the command a byte at a time */
            for (j = 0; j < cnt; j++) {

                /* make sure copies only up to screen width in      */
                /* length                                           */
                if (linelen < SCREEN_COLS) {

                    /* display control character using ^ notation   */
                    /* (e.g. NUL is ^@)                             */
                    if (hbi.kb[i] < ' ') {
                        line[linelen++] = '^';
                        line[linelen++] = hbi.kb[i] + '@';
                    }
                    else {
                        line[linelen++] = hbi.kb[i];
                    }
                }

                i = (i+1)%HIST_BUFF_SIZE;
                item->cur_chars_in_buff--;
            }
        }

        else {
            i = (i+cnt) % HIST_BUFF_SIZE;
            item->cur_chars_in_buff -= cnt;
        }

        /* overwrite last character of line with '$' if greater     */
        /* than screen width                                        */
        if (linelen > SCREEN_COLS-1) {
            line[SCREEN_COLS-1] = '$';
            line[SCREEN_COLS] = NUL_TERMINATOR;
        }
        else
            line[linelen] = NUL_TERMINATOR;

        /* tally item and update item index in history display      */
        /* control structure                                        */
        item->cur_item_no++;
        item->cur_item_index = previous;
        item->cur_display_count++;

        /* update item size field if not last item in history       */
        /* buffer                                                   */
        if (previous != hbi.tail) {
            previous = (previous + HIST_BUFF_SIZE - N_SIZE_SPEC_BYTES)
                % HIST_BUFF_SIZE;
            lo = hbi.kb[previous];
            previous = (previous+1) % HIST_BUFF_SIZE;
            hi = hbi.kb[previous];
            item->cur_size = (hi * MAX_7_BIT_VAL) + lo;
        }

        return(0);
    }
    return(-1);
}



/*
**********************************************************************

  Routine:            FETCH_NEXT_COMMAND 

  Function:
      This routine allows the next command in the history buffer 
  (entered chronologically) to be fetched from the history buffer. 

  Parameters:
     (input)          n_times - specifies the number of times to 
                          repeat the operation 
     (output)         cmd - specifies the target string for placing 
                          the extracted command 
     (output)         cmd_len - specifies the integer for passing 
                          back the length of the fetched command 

  Returns:            -1 if unsuccessful 
                      0 otherwise 

  Note 1 - if an error occurs, this routine will sound a beep. 
**********************************************************************/

fetch_next_command(n_times,cmd,cmd_len)
int n_times;
char *cmd;
int *cmd_len;
{
    int i, j;
    int cnt;
    int lo, hi;
    int times;
    int prev_index;

    /* if nothing in history buffer */
    if (hbi.chars_free == HIST_BUFF_SIZE)
        return(-1);

    prev_index = (hbi.head+HIST_BUFF_SIZE-hbi.head_item_size) % HIST_BUFF_SIZE;

    /* if changing directions and not single item in history buffer */
    if (hbi.direction == HIST_PREVIOUS_DIR && prev_index != hbi.tail)
        n_times++;

    hbi.direction = HIST_NEXT_DIR;

    for (times = 0; times < n_times; times++) {

        if (hbi.current == hbi.head) {
            hbi.head_of_histbuff = TRUE;
            beep();
            return(-1);
        }

        i = hbi.current;

        lo = hbi.kb[i];
        i = (i+1)%HIST_BUFF_SIZE;
        hi = hbi.kb[i];
        i = (i+1)%HIST_BUFF_SIZE;

        cnt = (hi * MAX_7_BIT_VAL) + lo;
        hbi.current_size = cnt;
        cnt -= TOTAL_SIZE_SPEC_BYTES;

        /* do modify parameters only last time through loop */
        if (times == n_times-1) {
            *cmd_len = cnt;
            for (j = 0; j < cnt; j++) {
                cmd[j] = hbi.kb[i];
                i = (i+1)%HIST_BUFF_SIZE;
            }
        }
        /* otherwise just skip this particular item */
        else
            i = (i+cnt)%HIST_BUFF_SIZE;

        i = (i+1)%HIST_BUFF_SIZE;
        i = (i+1)%HIST_BUFF_SIZE;

        hbi.current = i;
    }

    return(0);
}



/*
**********************************************************************

  Routine:            FETCH_PREVIOUS_COMMAND 

  Function:
      This routine allows the previous command in the history buffer 
  (reversed chronologically) to be fetched from the history buffer. 

  Parameters:
     (input)          n_times - specifies the number of times to 
                          repeat the operation 
     (output)         cmd - specifies the target string for placing 
                          the fetched command 
     (output)         cmd_len - specifies the integer for passing 
                          back the length of the fetched command 

  Returns:            -1 if unsuccessful 
                      0 otherwise 

  Note 1 - If an error occurs, this routine will sound a beep. 
**********************************************************************/

fetch_previous_command(n_times,cmd,cmd_len)
int n_times;
char *cmd;
int *cmd_len;
{
    int i, j;
    int cnt;
    int lo, hi;
    int previous;
    int times;
    int prev_index;

    /* nothing in history buffer */
    if (hbi.chars_free == HIST_BUFF_SIZE)
        return(-1);

    prev_index = (hbi.head+HIST_BUFF_SIZE-hbi.head_item_size) % HIST_BUFF_SIZE;

    /* if change of directions while extracting, then must extract  */
    /* an extra to prevent the current item to be refetched;        */
    /* check for direction change and not last item in history      */
    /* buffer                                                       */
    if (hbi.direction == HIST_NEXT_DIR && prev_index != hbi.tail)
        n_times++;

    hbi.direction = HIST_PREVIOUS_DIR;

    /* perform extraction specified number of times */
    for (times = 0; times < n_times; times++) {

        /* check if at last item */
        if (hbi.current == hbi.tail && !hbi.head_of_histbuff) {
            beep();
            return(-1);
        }

        /* index to previous item */
        previous = (hbi.current + HIST_BUFF_SIZE - hbi.current_size) %
            HIST_BUFF_SIZE;

        i = previous;

        /* get size of previous item */
        lo = hbi.kb[i];
        i = (i+1)%HIST_BUFF_SIZE;
        hi = hbi.kb[i];
        i = (i+1)%HIST_BUFF_SIZE;

        cnt = (hi * MAX_7_BIT_VAL) + lo;

        /* subtract item size bytes to get bytes in command */
        cnt -= TOTAL_SIZE_SPEC_BYTES;

        /* do extraction only for last iteration of loop */
        if (times == n_times-1) {
            *cmd_len = cnt;

            /* copy from history buffer to target string */
            for (j = 0; j < cnt; j++) {
                cmd[j] = hbi.kb[i];
                i = (i+1)%HIST_BUFF_SIZE;
            }
        }

        /* skip index over this item */
        else
            i = (i+cnt)%HIST_BUFF_SIZE;

        /* update history buffer index to previous item for next    */
        /* fetch                                                    */
        hbi.current = previous;
        if (previous != hbi.tail) {
            previous = (previous + HIST_BUFF_SIZE - N_SIZE_SPEC_BYTES)
                % HIST_BUFF_SIZE;
            lo = hbi.kb[previous];
            previous = (previous+1) % HIST_BUFF_SIZE;
            hi = hbi.kb[previous];
            hbi.current_size = (hi * MAX_7_BIT_VAL)+lo;
        }

        /* current is no longer at head of list, set flag to FALSE */
        hbi.head_of_histbuff = FALSE;
    }

    return(0);
}



/*
**********************************************************************

  Routine:            FETCH_NTH_COMMAND 

  Function:
      This routine fetches the Nth command from the history buffer. 
  Commands in the history buffer are numbered with the most recently 
  entered command being item 1, the next most recent being item 2, 
  etc. 

  Parameters:
     (input)          cmd_num - specifies the number of the history 
                          command to extract 
     (output)         cmd - specifies the target string to copy the 
                          fetched history command to 
     (output)         cmd_len - pointer to the integer for passing 
                          back the length of the fetched command 

  Returns:            -1 if unsuccessful 
                      0 otherwise 

**********************************************************************/

fetch_nth_command(cmd_num,cmd,cmd_len)
int cmd_num;
char *cmd;
int *cmd_len;
{
    int i, j;
    int cnt;
    int lo, hi;
    int previous;
    int times;
    int at_head;
    int cur_index;
    int cur_size;

    /* nothing in history buffer */
    if (hbi.chars_free == HIST_BUFF_SIZE)
        return(-1);

    /* initialize to start of history buffer */
    cur_index = hbi.head;
    cur_size = hbi.head_item_size;
    at_head = hbi.head_of_histbuff;

    /* loop specified number of times to get specified command */
    for (times = ZERO_INDEX_VALUE; times < cmd_num; times++) {

        /* if at end of history buffer */
        if (cur_index == hbi.tail && !at_head) {
            beep();
            return(-1);
        }

        /* index to previous item in circular buffer */
        previous = (cur_index + HIST_BUFF_SIZE - cur_size) %
            HIST_BUFF_SIZE;
        i = previous;

        /* get size of previous item */
        lo = hbi.kb[i];
        i = (i+1)%HIST_BUFF_SIZE;
        hi = hbi.kb[i];
        i = (i+1)%HIST_BUFF_SIZE;

        cnt = (hi * MAX_7_BIT_VAL) + lo;

        /* subtract size storage bytes to get command size */
        cnt -= TOTAL_SIZE_SPEC_BYTES;

        *cmd_len = cnt;

        /* fetch the command */
        for (j = ZERO_INDEX_VALUE; j < cnt; j++) {
            cmd[j] = hbi.kb[i];
            i = (i+1)%HIST_BUFF_SIZE;
        }

        /* update current index to previous item for next time thru loop */
        cur_index = previous;

        /* update item size if no end of history buffer */
        if (previous != hbi.tail) {
            previous = (previous + HIST_BUFF_SIZE - N_SIZE_SPEC_BYTES)
                % HIST_BUFF_SIZE;
            lo = hbi.kb[previous];
            previous = (previous+1) % HIST_BUFF_SIZE;
            hi = hbi.kb[previous];
            cur_size = (hi * MAX_7_BIT_VAL)+lo;
        }

        /* no longer at start of history buffer */
        at_head = FALSE;
    }

    /* update history information */
    hbi.current = cur_index;
    hbi.current_size = cur_size;
    hbi.head_of_histbuff = at_head;
    hbi.direction = HIST_PREVIOUS_DIR;

    return(0);
}

  



		    wstinit.c                       04/24/89  1040.7rew 04/24/89  1032.7       82359



/* ***********************************************************
   *                                                         *
   * Copyright, (C) Honeywell Bull Inc., 1988                *
   *                                                         *
   * Copyright, (C) Honeywell Information Systems Inc., 1987 *
   *                                                         *
   *********************************************************** */


/* HISTORY COMMENTS:
  1) change(87-03-21,Wallman), approve(87-03-21,MCR7586),
     audit(87-07-13,Flegel), install(87-08-07,MR12.1-1072):
     First release.
  2) change(88-06-06,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Return error code instead of exiting when MOWSE not yet invoked
     for cleanup by main().
  3) change(88-07-12,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Replaced calls to redundant move_abs() with calls to cursor_move().
  4) change(88-07-20,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Made edit mode default after atm.
  5) change(88-07-25,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Documentation only, added header comment.
  6) change(88-08-09,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Fix references to include files; "wstdefs.h" was split into
     "wstdefs.h" and "wsttype.h" to avoid declaration clash; also,
     various constants defined to descriptive names.
  7) change(88-08-23,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Added WSTERM edit mode and other mode initialization routines.
  8) change(88-08-30,Lee), approve(88-09-12,MCR7986), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Removed non-edit async mode and references to non-edit async mode
     line editing routines.
  9) change(89-01-18,Lee), approve(89-01-02,MCR8043), audit(89-03-14,Flegel),
     install(89-04-24,MR12.3-1033):
     phx21233 - Modified to initialize default glass_edit_mode value;
     separated input and output parameters to int86() to avoid confusion
     when parameters are used.
                                                   END HISTORY COMMENTS */

/* WSTINIT - Initialization module for WSTERM */

/* This module prepares the execution evironment for a WSTERM session */

#include    <stdio.h>
#include    <dos.h>
#include    <alloc.h>
#include    <ws_error.h>
#include    <wsmincap.h>
#include    "wstdefs.h"
#include    "wstglob.h"

/*
**********************************************************************

  Routine:            WSTINIT 

  Function:
      This routine initializes the screen and the execution 
  environment variables which are used by WSTERM. 

  Parameters:         NONE 

  Returns:            -1 if an error occurs during initialization; in 
                          particular, if MOWSE has not been invoked 
                          on the PC 
                      0 if no errors 

**********************************************************************/

wstinit ()
{   

    /* Clear the screen and display version id */

    clear_screen ();
    cursor_move (CURSOR_HOME_ROW, 60);
    printf ("WSTERM Vers %s", version);
    cursor_move (CURSOR_HOME_ROW, CURSOR_HOME_COL);

    /* Initialize static structures with defaults */

    setmem (&screen, sizeof (screen), 0);
    screen.maxcol = MAX_SCREEN_COL;
    screen.maxlin = MAX_SCREEN_LINE;

    setmem (&kb, sizeof (kb), 0);
    kb.key_status = -1;
    setmem (&ds, sizeof (ds), 0);
    setmem (&tdata_arg, sizeof (tdata_arg), 0);

    tdata_arg.local_buffer_pointer = (char *) fg_msg.text;
    tdata_arg.local_buffer_size = FG_MSG_SIZE;

    setmem (&fg_msg, sizeof (fg_msg), 0);
    setmem (brk_table, sizeof (brk_table), 0);

    /* Tell mowse we're here */
    mowse_active = cretinst ("WSTERM",  /* capability name */
        NULL,                           /* NULL entry function */
        0,                              /* zero inbuff length */
        0,                              /* zero outbuff length */
        NULL,                           /* NULL data block ptr */
        &wst_mcb);                      /* MCB pointer */

    if (mowse_active == WSNOTRES) { 
        printf ("MOWSE has not been invoked.\n");
        return(-1);
    }

    /****************  WSNOTPKT goes here */

    mowse_active = -(mowse_active == 0);

    /* is mowse active? */
    if (~mowse_active) {

        kb.echo = OFF;
        glass_edit_mode = FALSE;    /* phx21233 R.L. - initialize mode flags */
        wst_edit_mode = FALSE;

    }
    else  {
        kb.echo = ON;

        /* edit mode is always enabled in async packet mode */
        wst_edit_mode = TRUE;
    }

    return(0);
}               /* End of wstinit */



/*
**********************************************************************

  Routine:            WST_INIT_MODES

  Function:
      This routine initializes structures and variables associated
  with WSTERM's various modes.

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

wst_init_modes()
{
    int attr;

    wst_paging = ON;                 /* display EOP after screenful */
    wst_freeze = OFF;                /* allow scrolling */
    wst_f_audit = OFF;               /* file audit off */
    wst_p_audit = OFF;               /* line printer audit off */
    wst_edit_mode = OFF;             /* disable line edit mode */
    break_flag = FALSE;              /* no break hit */
    wst_status = WST_UNKNOWN_MODE;   /* mode to be determined */
    clr_index = 0;                   /* not currently in escape sequence */
    cursor_type = CURSOR_UNDERSCORE; /* assume underscore cursor */

    wst_fansi_flag = FALSE;          /* assume FANSI-CONSOLE not used */

    init_fconsole();       /* set scroll region and wst_fansi_flag */
                           /*   if device driver is FANSI-CONSOLE  */

    printf(ED);            /* (EraseDisplay) clear screen and home cursor */
    getattr(&attr);        /* get character attributes */
    wst_screens_init(' ',attr);  /* initialize the screen variables */
    init_wst_scroll(attr);   /* initialize structure for scrolling display */
    p_aud_init();
    f_aud_init();
    init_histbuff();
    init_killbuff();
    save_printer_timeout();
    set_printer_timeout(1);
}



/*
**********************************************************************

  Routine:            GETATTR 

  Function:
      This routine gets the current screen attributes. The screen 
  attributes read can then be used to determine what color and 
  intensity is to be used for subsequent displaying. 

  Parameters:
     (output)         attr - pointer to the integer variable for 
                          passing back the current attributes 

  Returns:            NONE 

**********************************************************************/

getattr(attr)
int *attr;
{
    union REGS reg, outreg;

    cursor_move(CURSOR_HOME_ROW,CURSOR_HOME_COL);    /* home cursor */
    reg.h.ah = RD_SCREEN;           /* read character and attributes */
    reg.h.bh = get_active_page();   /* from current active page */
    int86(BIOS_VIDEO,&reg,&outreg); /* call BIOS to get character attributes */
    *attr = (int)outreg.h.ah;    /* set attribute parameter with attributes */
}



/*
**********************************************************************

  Routine:            INIT_FCONSOLE

  Function:
      This routine determines if FANSI-CONSOLE is being used as the 
  screen driver. If so, the global flag "wst_fansi_flag" is set and 
  an escape sequence is sent to initialize the first 24 lines of the 
  screen as the scrolling region. 

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

init_fconsole()
{
    int fd;

    /* if device driver for FANSI-CONSOLE exists */
    if ((fd = open("fcon",0)) >= 0) {
        close(fd);           /* we don't need file descriptor any more */

        wst_fansi_flag = TRUE;  /* set to indicate fansi-console installed */

        /* print sequence to set the scroll region from lines 1 to 24 */
        put_screen_str(FCON_SET_SCROLL_24);
    }
}



/*
**********************************************************************

  Routine:            RESET_SCROLL 

  Function:
      This routine checks to see if the global flag "wst_fansi_flag" 
  has been set and if so, will send an escape sequence to the screen 
  driver to reset the scrolling region. 

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

reset_scroll()
{
    /* if fansi console installed */
    if (wst_fansi_flag)
        /* print the escape sequence to set the scroll
           region to the default (the entire screen)
        */
        put_screen_str(FCON_RESET_SCROLL_STR);
}


/* End of WSTINIT */

 



		    wstkbscr.c                      04/24/89  1040.7rew 04/24/89  1032.5      188730



/* ********************************************
   *                                          *
   * Copyright, (C) Honeywell Bull Inc., 1987 *
   *                                          *
   ******************************************** */

/* HISTORY COMMENTS:
  1) change(87-05-04,Wallman), approve(87-05-04,MCR7586),
     audit(87-07-16,Flegel), install(87-08-07,MR12.1-1072):
     First release.
  2) change(87-09-02,Wallman), approve(87-09-02,MCR7586),
     audit(87-07-16,Flegel), install(87-09-10,MR12.1-1103):
     PBF to improve robustness of string handling by avoiding all str*
     functions.
  3) change(88-02-24,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Removed debugging code and unused variables; code re-formatting.
  4) change(88-04-11,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Added mapping of ^2 key to ALT-0, DEL key to ASCII del and
     ^BREAK (if break flag is set) to ALT-B.
  5) change(88-05-18,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Deleted parameter hide_sw in calls to replay().
  6) change(88-07-25,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Documentation additions only. Added header comments to all routines.
  7) change(88-08-09,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Fix references to include files; "wstdefs.h" was split into
     "wstdefs.h" and "wsttype.h" to avoid declaration clash; also,
     various constants defined to descriptive names.
  8) change(88-08-30,Lee), approve(88-09-12,MCR7986), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Removed non-edit async mode and references to non-edit async mode
     line editing routines.
  9) change(89-01-18,Lee), approve(89-01-02,MCR8043), audit(89-03-14,Flegel),
     install(89-04-24,MR12.3-1033):
     Separated input and output parameters to int86() to avoid confusion
     when parameters are used.
                                                   END HISTORY COMMENTS */

/* WSTKBSCR - keyboard/screen manager for WSTERM */

/* This module holds functions needed to handle keyboard input and to manage
   the screen display. */

#include    <stdio.h>
#include    <dos.h>
#include    <ws.h>
#include    <ws_mcb.h>
#include    <wsmincap.h>
#include    "wstdefs.h"
#include    "wsttype.h"
#include    "wstglob.h"


/**** PUBLIC FUNCTIONS ******************************************************/

/*
**********************************************************************

  Routine:            EXTRACT_MSG 

  Function:
      This routine extracts sync mode messages from kb.klin. Sync 
  mode messages are delimited by break characters, screen line length 
  overflow, and read count exhaust. 

  Parameters:
     (input)          no_block - specifies to send zero length 
                          messages 
     (input)          tro_sw - timer run out switch 
     (input)          txmt_sw - specifies to transmit the message 
     (input)          hide_sw - switch to suppress echoing 

  Returns:            NONE 

**********************************************************************/

extract_msg (no_block, tro_sw, txmt_sw, hide_sw)
int no_block,   /* Send 0-length messages */
tro_sw,         /* Timer run out switch */
txmt_sw,        /* Transmit the message */
hide_sw;        /* Switch to suppress echoing */

{   
    int curc,       /* Local column value */
        echo;       /* Local echo control */

    register int    cndx;        /* Working index */

    /* Scan the keyboard buffer. We will hit one of:
       1) a break character (msgs were backed up)
       2) end of kb.klin (a timer runout has occurred)
       3) read_count exhaust
       4) screen.maxcol overflow */

    echo = kb.echo;
    curc = screen.curcol;
    for (cndx = kb.endx;  cndx < strlen (kb.klin) && (read_count > 0)
        && ((echo && curc <= screen.maxcol) || ~echo);  cndx++) { 
        read_count--;           /* Decrement the read count */

        /* If WSTERM is echoing, count and echo all printing characters */

        if (echo && ~hide_sw && isprint (kb.klin [cndx])) { 
            curc++;
            putscr (&kb.klin [cndx], 1);
        }

        /* If the klin character is a break character or a control
           character, we're at the linelength limit, or the read
           count has exhausted, end the read, send that much, force
           echoing OFF, and ltrim the data sent from kb.klin */

        if (stpchr (brk_table, kb.klin [cndx]) || iscntrl (kb.klin [cndx]) ||
            (echo && curc == screen.maxcol) || read_count == 0) { 
            term_read = ON;     /* Terminate the read */

            send_msg (kb.klin, ++cndx);
            strcpy (kb.klin, &kb.klin [cndx]);
            kb.cndx = strlen (kb.klin);
            cndx = kb.cndx;
            kb.endx = 0;
            echo = OFF;         /* Force echoing OFF */
            read_active = OFF;
        }
    }               /* End of kb.klin scan loop */

    /* If we fall out of the kb.klin scan loop with anything left we
       have reached the end of kb.klin */

    if (strlen (kb.klin) > 0) {

        /* Send the leftovers if not echoing, otherwise, update the last echoed
           character index (kb.endx) */

        if (txmt_sw && ~kb.echo && read_active) { 
            send_msg (kb.klin, strlen (kb.klin));
            kb.cndx = 0;
            kb.endx = 0;
            setmem (kb.klin, sizeof (kb.klin), NUL);
        }
        else if (kb.echo && ~hide_sw)
            kb.endx = kb.cndx;
    }

    screen.curcol = curc;

}               /* End of extract_msg */



/*
**********************************************************************

  Routine:            NEXT_TAB 

  Function:
      This routine computes the distance (in columns) to the next tab 
  column. 

  Parameters:
     (input)          ccol - specifies the current screen column 

  Returns:            the number of columns to the next tab column 

**********************************************************************/

next_tab (ccol)
int ccol;       /* Current column */

{ 
    int space;

    /* assume that the tabs are set every 10 columns; */
    /* this calculation may have to work for negative */
    /* values. */

    space = TAB_SIZE * ((ccol + TAB_SIZE) / TAB_SIZE) - ccol;
    return (space);
}               /* End of next_tab */



/*
**********************************************************************

  Routine:            PROCESS_KBRD_CHAR 

  Function:
      This routine handles keyboard input for non-edit mode and sync 
  mode. 

  Parameters:
     (input)          hide_sw - switch to suppress echoing 

  Returns:            NONE 

**********************************************************************/

process_kbrd_char (hide_sw)
int hide_sw;        /* Switch to suppress echoing */

{
    read_keyboard (BLOCK);

    /* Processing an octal escape? */

    if (octsw > 0) {

        /* Is this a meaningful octal digit? */

        if (isdigit (kb.chr [0]) && kb.chr [0] < '8' && octsw < 3) { 
            octval = 8 * octval + (int) kb.chr [0] - 060;
            octsw++;

            return;
        }
        else {  /* Not part of \nnn */
            sprintf (octstr, "%c%03o", LNC, octval);
            sprintf (kb.dstr, "%c", kb.chr [0]);

            put_kchr (hide_sw);
            octsw = 0;
        }

        return;
    }               /* End of octal processing */

    /* if control char or ALT key or function key */

    if (iscntrl (kb.chr [0]) || (kb.key_status & ALT) || kb.fkey) { 
        process_ctl_char (hide_sw);
        return;
    }

    if (~mowse_active) {     /* Glass TTY mode? */

        /* Send any leftover typeahead */

        if (kb.cndx > 0) { 
            puttdata (FG_TERMINAL_DATA, kb.klin, kb.cndx);
            kb.cndx = 0;
        }

        if (kb.echo && ~hide_sw) {

            putscr (kb.dstr, 1);
        }
        puttdata (FG_TERMINAL_DATA, kb.chr, 1);
    }               /* End of glass TTY mode */

    /* Otherwise, we are in packet mode */

    else {
        /* Transmit sync mode message for control and break characters */

        if (sync && (iscntrl (kb.chr [0]) || stpchr (brk_table, kb.chr [0]))) {

            put_kchr (hide_sw);
            if (read_active)
                extract_msg (~NO_BLOCK, ~TRO,
                    TXMT_MSG, hide_sw);
            return;
        }

        /* we're in sync mode */

        sprintf (kb.dstr, "%c", kb.chr [0]);
        put_kchr (hide_sw);

    }               /* End of packet mode */
}               /* End of process_kbrd_char */



/*
**********************************************************************

  Routine:            READ_KEYBOARD 

  Function:
      This routine reads the keyboard for key presses. If a key is 
  read, it is kept and maintained in the global structure 'kb'. The 
  caller may specify that the routine waits if no keyboard input or 
  returns immediately instead. 

  Parameters:
     (input)          block_sw - if TRUE, routine will wait if no 
                          keyboard key was pressed, otherwise routine 
                          returns immediately 

  Returns:            OFF if no key in the key queue 
                      ON if a key was fetched from the key queue 

**********************************************************************/

read_keyboard (block_sw)
int block_sw;       /* Block-for-input switch */

/*  If block_sw is ON, return the key code of the first available
    keystroke, waiting if there isn't one waiting the DOS key queue.
    The key code is (scan code || character code).

    If block_sw is OFF, return OFF if the DOS key queue is empty;
    otherwise, return the key code if the first queued keystroke.
*/

{   
    int flags,      /* CPU flags */
    key_q_sw;
    union regs_struct regs, outregs;
    int ch;

    /* check if break key has been hit */
    if (break_flag) {

        /* if block switch is off, just return key hit status */
        if (~block_sw)
            return(ON);

        /* handle the break key by mapping it to ALT-B for BREAK
           processing */
        kb.key_status = ALT;
        kb.key_ndx = B_KEY_CODE;
        kb.chr [0] = NUL;
        kb.chr [1] = NUL;
        kb.fkey = OFF;
        break_flag = 0;
        return(ON);
    }

    setmem (&regs, sizeof (regs), 0);

    /* Get key queue status */

    regs.hreg.ah = BIOS_KB_STATUS;
    flags = int86 (BIOS_KB, &regs, &outregs) & LOW_8_BITS;
    key_q_sw = -((flags & Z_FLAG_MASK) == 0);    /* ZF = no character */

    /* Get key shift status */

    regs.hreg.ah = BIOS_KB_SHIFTS;
    int86 (BIOS_KB, &regs, &outregs);
    if (kb.key_status == -1)
        kb.key_status = outregs.hreg.al;

    /* Return changes if we're not asked to block */

    if (~block_sw) {

        return (key_q_sw);
    }

    /* Get keystroke from DOS */

    regs.hreg.ah = BIOS_KB_READ;
    int86 (BIOS_KB, &regs, &outregs);
    kb.key_ndx = outregs.hreg.ah;
    kb.chr [0] = (char) outregs.hreg.al;
    kb.chr [1] = NUL;
    kb.fkey = OFF;

    /* encode keyboard character into unique code */
    if (outregs.hreg.al)
        ch = outregs.hreg.al;
    else
        ch = outregs.hreg.ah + ASCII_EXTEND_CODE;

    /* if ^2 (same as ^@) key hit, map it ALT-0 to send a NUL */
    if (ch == CTRL_2) {
        kb.key_status = ALT;
        kb.key_ndx = zero_KEY_CODE;
        kb.chr [0] = NUL;
        kb.chr [1] = NUL;
        kb.fkey = OFF;
        return(ON);
    }

    /* if DEL key hit, map it onto ASCII DEL */
    else if (ch == DEL_KEY) {
        kb.key_status = 0;
        kb.key_ndx = 0;
        kb.chr [0] = DEL;
        kb.chr [1] = NUL;
        kb.fkey = OFF;
        return(ON);
    }

    /* Refetch shift status in case it changed during the wait for the character */

    regs.hreg.ah = BIOS_KB_SHIFTS;
    int86 (BIOS_KB, &regs, &outregs);
    kb.key_status = outregs.hreg.al;


    /* Is this a function key? */

    if (kb.key_ndx >= F1_KEY_CODE && kb.key_ndx < F1_KEY_CODE + 10) { 
        kb.fkey = ON;
        strcpy (kb.chr, &F1_10 [kb.key_ndx - F1_KEY_CODE - 1][4]);
    }

    if (kb.key_ndx >= F11_KEY_CODE && kb.key_ndx < F11_KEY_CODE + 2) { 
        kb.fkey = ON;
        strcpy (kb.chr, &F11_12 [kb.key_ndx - F11_KEY_CODE - 1][4]);
    }

    return (ON);
}               /* End of read_keyboard */



/*
**********************************************************************

  Routine:            SEND_MSG 

  Function:
      This routine sends a control message to the host. 

  Parameters:
     (input)          msg_str - specifies the message buffer 
                          containing the message to send 
     (input)          msg_len - specifies the number of bytes in the 
                          message buffer to send 

  Returns:            NONE 

**********************************************************************/

send_msg (msg_str, msg_len)
int     msg_len;        /* Number of bytes to send */
char    *msg_str;       /* The byte string */

{   
    struct snd_msg_struct snd_msg;

    setmem (&snd_msg, sizeof (snd_msg), 0);

    if (~kb.echo) {          /* RNE */
        if (term_read) { 
            snd_msg.hdr.id [0] = 'E';
            snd_msg.hdr.id [1] = 'N';
            snd_msg.hdr.id [2] = 'I';
            term_read = OFF;
            read_active = OFF;
            kb.echo = OFF;
        }
        else { 
            snd_msg.hdr.id [0] = 'U';
            snd_msg.hdr.id [1] = 'I';
            snd_msg.hdr.id [2] = 'C';
        }
    }
    else {  /* RWE */
        if (term_read) { 
            snd_msg.hdr.id [0] = 'E';
            snd_msg.hdr.id [1] = 'E';
            snd_msg.hdr.id [2] = 'I';
            term_read = OFF;
            read_active = OFF;
            kb.echo = OFF;
        }
        else { 
            snd_msg.hdr.id [0] = 'E';
            snd_msg.hdr.id [1] = 'I';
            snd_msg.hdr.id [2] = 'C';
        }
    }

    byteshift (msg_len, &snd_msg.hdr.msb_size, &snd_msg.hdr.lsb_size);
    snd_msg.data [0] = NUL;     /* Erase target string */
    strncpy (snd_msg.data, msg_str, msg_len);

    puttdata (FG_CONTROL_MESSAGE, &snd_msg, msg_len + 5);
}               /* End of send_msg */



/**** LOCAL FUNCTIONS *******************************************************/

/*
**********************************************************************

  Routine:            PROCESS_CTL_CHAR 

  Function:
      This routine handles control, ALT and function keys in non-edit 
  mode (and sync) mode. 

  Parameters:
     (input)          hide_sw - if TRUE, echoing is suppressed 

  Returns:            NONE 

**********************************************************************/

process_ctl_char (hide_sw)
int hide_sw;        /* Switch to suppress echoing */

{
    /* Check for local escapes */

    if (kb.key_status & ALT) {

        local_esc (kb.key_ndx);
        return;
    }

    /* For glass TTY mode, just send the 'character' */

    if (~mowse_active) { 
        puttdata (FG_TERMINAL_DATA, kb.chr, strlen (kb.chr));

    }  /* For sync mode, they are break characters */

    else if (sync) { 
        catstr (&kb.klin [kb.cndx], kb.chr, strlen (kb.chr),
             "kb.klin", sizeof (kb.klin));
        kb.cndx += strlen (kb.chr);
        kb.klin [kb.cndx] = NUL;

        if (read_active) { 
            term_read = ON;
            extract_msg (~NO_BLOCK, ~TRO, TXMT_MSG,
                 hide_sw);
        }
    }
}               /* End of process_ctl_char */



/*
**********************************************************************

  Routine:            PUT_KCHR 

  Function:
      When a key or an octal value (specified by entering \ followed 
  by octal digits) is entered, it is stored for examination before 
  further processing takes place. This routine takes the stored value 
  and places it into the global buffer containing the input line 
  (kb.klin). The routine is called when not in edit mode.

  Parameters:
     (input)          hide_sw - if TRUE, specifies echoing is to be 
                          suppressed 

  Returns:            NONE 

**********************************************************************/

put_kchr (hide_sw)
int hide_sw;        /* Switch to suppress echoing */

{   

    /* Is there a pending octal escape */

    if (octsw > 0) { 
        if (kb.cndx == strlen (kb.klin)) {   /* Tack octval on the end */
            kb.klin [kb.cndx] = (char) octval;
            kb.pos [kb.cndx] = ds.ccol;
            kb.klin [++kb.cndx] = NUL;
        }
        else  /* Replace buffered character */
            kb.klin [kb.cndx] = (char) octval;
    }

    if (kb.cndx == strlen (kb.klin)) {      /* Tack kb.chr on the end */
        kb.klin [kb.cndx] = kb.chr [0];
        kb.pos [kb.cndx] = ds.ccol + 4 * (octsw > 0);
        kb.klin [kb.cndx + 1] = NUL;
    }
    else 
        kb.klin [kb.cndx] = kb.chr [0]; /* Replace buffered character */

    if (~sync) { 
        if (put_kstr (hide_sw)) {       /* Nonzero if kb.dstr wont fit */
            kb.klin [kb.cndx] = NUL;
            return;
        }
    }

    kb.cndx++;          /* Advance buffer index */
}               /* End of put_kchr */



/*
**********************************************************************

  Routine:            PUT_KSTR 

  Function:
      This routine displays the keyboard character string in the 
  global variable kb.dstr. 

  Parameters:
     (input)          hide_sw - if TRUE, specifies that echoing is to 
                          be suppressed 

  Returns:            NONE 

**********************************************************************/

put_kstr (hide_sw)
int hide_sw;        /* Switch to suppress echoing */

{   
    int err_flg;        /* Error flag */

    err_flg = OFF;

    /* Replacing a character */

    if (ds.ccol < strlen (ds.dlin) && ~hide_sw && kb.endx == kb.cndx) { 
        if (replay (strlen (kb.dstr)))
            err_flg = ON;
    }

    /* Appending a character */

    else {

        /* Wrap line if last column */

        if (ds.ccol == screen.maxcol) { 
            if (wrap_line (ds.lndx, ds.ccol))
                err_flg = ON;       /* Error if line wont fit */
            else 
                ds.lndx++;
        }

        /* If kb.dstr overflows */

        if (strlen (ds.dlin) + strlen (kb.dstr) > screen.maxcol &&
            ~err_flg) { 
            if (replay (strlen (kb.dstr)))
                err_flg = ON;
        }
        else if (~err_flg)       /* Doesn't overflow */ { 
            if (octsw > 0) { 
                catstr (ds.dlin, octstr, 4, "ds.dlin",
                     sizeof (ds.dlin));
                ds.ccol += strlen (octstr);
                if (kb.echo && ~hide_sw)
                    putscr (octstr, 4);
            }

            if (kb.echo && ~hide_sw) { 
                if (ds.ccol < strlen (ds.dlin)) { 
                    putscr (&ds.dlin [ds.ccol],
                         strlen (&ds.dlin [ds.ccol]));

                    ds.ccol = strlen (ds.dlin);
                }
                else { 
                    catstr (ds.dlin, kb.dstr,
                         strlen (kb.dstr), "ds.dlin", sizeof (ds.dlin));
                    ds.spill [ds.lndx] = 0;
                    ds.ccol += strlen (kb.dstr);
                    putscr (kb.dstr, strlen (kb.dstr));

                }
            }
        }
    }

    kb.endx++;

    return (err_flg);
}               /* End of put_kstr */



/*
**********************************************************************

  Routine:            WRAP_LINE 

  Function:
      This routine wraps a keyboard display line. 

  Parameters:
     (input)          lin - specifies the current line 
     (input)          col - specifies the current column 

  Returns:            NONE 

**********************************************************************/

wrap_line (lin, col)
int lin,        /* Current line */
col;        /* Current column */

{

    /* Copy ds.dlin to ds.map */

    strcpy (&ds.map [lin][0], ds.dlin);

    /* Is the display map full? */

    if (lin == DS_LCT - 1) { 
        putscr (SCP, strlen (SCP));
        cursor_move (MINI_LIN, 0);
        printf ("%s%s", "Input line cannot be processed because it ",
                    "exceeds screen size. (any key)");

        /* Wait for a character */

        while (read_keyboard (~BLOCK))
            ;

        cursor_move (MINI_LIN, 0);
        putscr (EL, strlen (EL));
        putscr (RCP, strlen (RCP));

        cursor_move (screen.curlin + lin, col);
        putscr (EL, strlen (EL));
        return (ON);
    }

    scroll ();
    ds.ccol = 0;
    ds.splct [lin + 1] = 0;
    setmem (ds.dlin, sizeof (ds.dlin), NUL);
    if (lin + 1 > ds.lct)
        ds.lct++;

    return (OFF);
}               /* End of wrap_line */


  



		    wstkill.c                       04/24/89  1040.7rew 04/24/89  1032.7      134055



/* ********************************************
   *                                          *
   * Copyright, (C) Honeywell Bull Inc., 1988 *
   *                                          *
   ******************************************** */

/* HISTORY COMMENTS:
  1) change(88-08-04,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Created.
  2) change(88-08-09,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Fix references to include files; "wstdefs.h" was split into
     "wstdefs.h" and "wsttype.h" to avoid declaration clash; also,
     various constants defined to descriptive names.
  3) change(89-01-18,Lee), approve(89-01-02,MCR8043), audit(89-03-14,Flegel),
     install(89-04-24,MR12.3-1033):
     phx21233 - Modified line input manipulations to update the character
     display length flags as well to control echoing of echoed and non-echoed
     input.
                                                   END HISTORY COMMENTS */

#include <dos.h>
#include "wstdefs.h"
#include "wstglob.h"
#include "wstkill.h"

/*
**********************************************************************

  Routine:            YANK 

  Function:
      This routine yanks the last item that was saved to the kill 
  buffer and inserts the item into the edit mode line buffer. The 
  display is updated. 

  Parameters:
     (input/output)   line - specifies the structure containing the 
                          line being edited and information about the 
                          line in edit mode 

  Returns:            NONE 

  Note 1 - If an error occurs (e.g. there is not enough room in the 
      line to contain the item being yanked), a beep is sounded and 
      no processing takes place. 
**********************************************************************/

yank(line)
EDIT_LINE *line;
{
    int line_chars_free;
    int i, j;
    int hi, lo;
    int cnt;
    int previous;

    /* determine amount of free space in line being edited */
    line_chars_free = MAX_LINE_SIZE - line->length;

    /* check and handle for nothing in kill buffer */
    if (kill_info.chars_free == KILL_BUFF_SIZE ||
        (kill_info.current == kill_info.tail && !kill_info.head_of_killbuff)) {
        beep();
        return;
    }

    /* index to previous item in kill buffer */
    previous = (kill_info.current + KILL_BUFF_SIZE - kill_info.current_size) %
        KILL_BUFF_SIZE;

    i = previous;

    /* determine total size of this previous item */
    lo = kill_info.kb[i];
    i = (i+1)%KILL_BUFF_SIZE;
    hi = kill_info.kb[i];
    i = (i+1)%KILL_BUFF_SIZE;

    cnt = (hi * MAX_7_BIT_VAL) + lo;

    /* subtract item size bytes to get number of data bytes */
    cnt -= TOTAL_SIZE_SPEC_BYTES;

    /* check and handle insufficient space in line to insert item */
    if (line_chars_free < cnt) {
        beep();
        return;
    }

    /* create gap for inserting yank item */
    for (j = line->length; j >= line->index; j--) {
        line->line[j+cnt] = line->line[j];
        line->size[j+cnt] = line->size[j];    /* phx21233 R.L. - update display length flags */
    }

    line->length += cnt;
    kill_info.yank_index = line->index;
    kill_info.yank_size = cnt;    /* reset on save or RETURN */

    /* copy item into gap */
    for (j = 0; j < cnt; j++) {
        line->line[line->index+j] = kill_info.kb[i];
        line->size[line->index+j] = (kb.echo) ? TRUE : FALSE; /* phx21233 R.L. updated echo status */
        i = (i+1)%KILL_BUFF_SIZE;
    }

    /* update the display and cursor */
    redisplay(line,line->index,&(line->max_row),&(line->max_col));
    cursor_right(line,kill_info.yank_size);
}



/*
**********************************************************************

  Routine:            YANK_PREVIOUS 

  Function:
      This routine allows each item in the kill buffer to be yanked 
  in reversed chronological order, each time the routine is called. 
  The routine "yank()" must have been called initially to yank the 
  most recently killed item in order for previous items to be yanked. 
  When the previous item is yanked, it replaces the item that was 
  yanked immediately before by deleting that item first before 
  inserting the newly yanked item. The display and cursor is updated 
  with each yank. 

  Parameters:
     (input/output)   line - specifies the structure containing the 
                          line being edited and information about the 
                          line in edit mode 

  Returns:            NONE 

  Note 1 - If an error occurs (e.g. there is no room in the line 
      being edited to contain the item yanked), the routine will 
      sound a beep and no further processing takes place. 
**********************************************************************/

yank_previous(line)
EDIT_LINE *line;
{
    int i, j;
    int hi, lo;
    int cnt;
    int previous;
    int diff;

    /* check that a yank was previously made */
    if (kill_info.yank_size < 1) {
        beep();
        return;
    }

    /* check that cursor has not moved since last yank */
    if (line->index != kill_info.yank_index+kill_info.yank_size) {
        beep();
        return;
    }

    /* check and handle for nothing in the kill buffer */
    if (kill_info.chars_free == KILL_BUFF_SIZE ||
        (kill_info.current == kill_info.tail && !kill_info.head_of_killbuff)) {
        beep();
        return;
    }

    /* get index to previous item in the kill buffer */
    previous = (kill_info.current + KILL_BUFF_SIZE -
        kill_info.current_size) % KILL_BUFF_SIZE;

    /* check and handle reaching last item of kill buffer */
    if (previous == kill_info.tail)
        previous = kill_info.head;

    /* index of current item now indexes to previous item */
    kill_info.current = previous;

    /* update size of current item with size of previous item */
    if (previous != kill_info.tail) {

        /* get size of previous item */
        previous = (previous + KILL_BUFF_SIZE - N_SIZE_SPEC_BYTES) % KILL_BUFF_SIZE;
        lo = kill_info.kb[previous];
        previous = (previous+1) % KILL_BUFF_SIZE;
        hi = kill_info.kb[previous];
        kill_info.current_size = (hi * MAX_7_BIT_VAL)+lo;
    }

    /* current does not index to first item of kill buffer */
    kill_info.head_of_killbuff = FALSE;

    /* index to previous item */
    previous = (kill_info.current + KILL_BUFF_SIZE -
        kill_info.current_size) % KILL_BUFF_SIZE;

    /* move cursor to beginning of previously yanked item */
    cursor_left(line,kill_info.yank_size);

    i = previous;

    /* get size of item to yank */
    lo = kill_info.kb[i];
    i = (i+1)%KILL_BUFF_SIZE;
    hi = kill_info.kb[i];
    i = (i+1)%KILL_BUFF_SIZE;

    cnt = (hi * MAX_7_BIT_VAL) + lo;
    kill_info.current_size = cnt;

    cnt -= TOTAL_SIZE_SPEC_BYTES;

    /* compare size of items to be yanked and previously yanked to  */
    /* determine whether to expand or shrink the line being edited  */
    if (cnt < kill_info.yank_size) {

        /* determine amount to shrink the line */
        diff = kill_info.yank_size - cnt;

        /* shrink over the previous yanked item */
        for (j = kill_info.yank_index+cnt; j < line->length-diff; j++) {
            line->line[j] = line->line[j+diff];
            line->size[j] = line->size[j+diff];    /* phx21233 R.L. - update display length flags */
        }

        /* update line length to reflect shrinkage */
        line->length -= diff;
    }

    else if (kill_info.yank_size < cnt) {

        /* determine amount to expand */
        diff = cnt - kill_info.yank_size;

        /* check and handle not enough room to contain yanked item */
        if (line->length + diff >= MAX_LINE_SIZE) {
            beep();
            return;
        }

        /* create gap at previously yanked item */
        for (j = line->length; j >= kill_info.yank_index; j--) {
            line->line[j+diff] = line->line[j];
            line->size[j+diff] = line->size[j];    /* phx21233 R.L. - update display length */
        }

        /* update the line length to reflect gap inserted */
        line->length += diff;
    }

    kill_info.yank_index = line->index;
    kill_info.yank_size = cnt;    /* reset on save or RETURN */

    /* copy the item to be yanked over the previously yanked item */
    for (j = 0; j < cnt; j++) {
        line->line[line->index+j] = kill_info.kb[i];
        line->size[line->index+j] = (kb.echo) ? TRUE : FALSE;  /* phx21233 R.L. - update display length */
        i = (i+1)%KILL_BUFF_SIZE;
    }

    /* update the screen and cursor */
    redisplay(line,line->index,&(line->max_row),&(line->max_col));
    cursor_right(line,kill_info.yank_size);

    /* update flag to indicate current item is not first item in    */
    /* kill buffer                                                  */
    kill_info.head_of_killbuff = FALSE;
}



/*
**********************************************************************

  Routine:            SAVE_TO_KILLBUFF 

  Function:
      This routine saves an item (one or more characters) to the kill 
  buffer for subsequent retrieval via the yank() and yank_previous() 
  routines. The kill buffer is of fixed sized and when an item being 
  saved is larger than the space available in the kill buffer, then 
  room is created by freeing up previously stored items (from the 
  least recently saved to the most recently saved) until enough room 
  has been created. 

  Parameters:
     (input)          str - specifies the buffer containing the item 
                          to save 
     (input)          item_size - specifies the number of characters 
                          from the specified buffer to save 

  Returns:            NONE 

**********************************************************************/

save_to_killbuff(str,item_size)
char *str;
int item_size;
{
    int i, j;
    int lo_byte;
    int hi_byte;
    int first_chunk;
    int buffer_empty;

    /* check for item too big to fit into killbuffer; this should */
    /* not normally happen since the size of largest item is an */
    /* input line that is completely full, and the size of the line */
    /* buffer is currently less than the size of the kill buffer */
    if (item_size+TOTAL_SIZE_SPEC_BYTES > KILL_BUFF_SIZE)

        /* truncate size of item so save so that it fits and continue */
        item_size = KILL_BUFF_SIZE - TOTAL_SIZE_SPEC_BYTES;


    /* delete items from tail until enough room */
    while (kill_info.chars_free < item_size+TOTAL_SIZE_SPEC_BYTES) {

        i = (kill_info.tail + kill_info.tail_item_size) % KILL_BUFF_SIZE;

        /* if insertion will overwrite all existing items */
        if (i == kill_info.head && kill_info.chars_free == NONE) {

            /* reinitialize everything */
            init_killbuff();
            break;
        }

        /* determine size of least recently saved item */
        kill_info.tail = i;
        lo_byte = kill_info.kb[i];
        i = (i+1)%KILL_BUFF_SIZE;
        hi_byte = kill_info.kb[i];

        /* delete least recently saved item from kill buffer */
        kill_info.chars_free += kill_info.tail_item_size;
        kill_info.tail_item_size = (hi_byte * MAX_7_BIT_VAL) + lo_byte;
    }

    /* set flag to determine whether kill buffer is now empty */
    if (kill_info.head == kill_info.tail && kill_info.chars_free == KILL_BUFF_SIZE)
        buffer_empty = TRUE;
    else
        buffer_empty = FALSE;

    /* determine space taken up in kill buffer for new item */
    kill_info.head_item_size = item_size+TOTAL_SIZE_SPEC_BYTES;
    kill_info.chars_free -= kill_info.head_item_size;

    /* size of item is to be stored in first two and last two       */
    /* bytes of item in kill buffer; determine the values of the    */
    /* size bytes                                                   */
    lo_byte = kill_info.head_item_size % MAX_7_BIT_VAL;
    hi_byte = kill_info.head_item_size / MAX_7_BIT_VAL;

    /* store into first two bytes of item */
    i = kill_info.head;
    kill_info.kb[i] = lo_byte;
    i = (i+1)%KILL_BUFF_SIZE;
    kill_info.kb[i] = hi_byte;
    i = (i+1)%KILL_BUFF_SIZE;

    /* copy across end of buffer to beginning of buffer? */
    if (i+item_size > KILL_BUFF_SIZE) {

        /* determine amount to copy up to end of buffer */
        first_chunk = KILL_BUFF_SIZE - i;

        /* determine amount to copy starting from beginning of */
        /* buffer */
        item_size -= first_chunk;

        /* copy item to kill buffer */
        for (j = 0; j < first_chunk; j++)
            kill_info.kb[i++] = str[j];
        for (i = 0; i < item_size; i++)
            kill_info.kb[i] = str[j++];

    }

    /* no buffer wrap around, do straight copy */
    else {
        for (j = 0; j < item_size; j++)
            kill_info.kb[i++] = str[j];
    }

    /* last two bytes of item holds size of item in kill buffer */
    i = i % KILL_BUFF_SIZE;
    kill_info.kb[i] = lo_byte;
    i = (i+1) % KILL_BUFF_SIZE;
    kill_info.kb[i] = hi_byte;
    i = (i+1) % KILL_BUFF_SIZE;

    /* if buffer was empty, make tail and head the same */
    if (buffer_empty) {
        kill_info.tail = kill_info.head;
        kill_info.tail_item_size = kill_info.head_item_size;
    }

    /* head index points to next location in kill buffer to add */
    /* next item */
    kill_info.head = i;

    /* set current item index to most currently saved item index */
    kill_info.current = kill_info.head;

    /* current item size to currently saved item size */
    kill_info.current_size = kill_info.head_item_size;

    /* index 'current' is now same as index 'head' */
    kill_info.head_of_killbuff = TRUE;

    /* reset values used for yanking */
    kill_info.yank_index = ZERO_INDEX_VALUE;
    kill_info.yank_size = ZERO_BYTES;

}



/*
**********************************************************************

  Routine:            INIT_KILLBUFF 

  Function:
      This routine initializes the kill buffer to indicate an empty 
  kill buffer. 

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

init_killbuff()
{

    /* all item indices set to 0 (beginning of kill buffer) and     */
    /* all item sizes set to 0 (no items)                           */

    kill_info.head = ZERO_INDEX_VALUE;
    kill_info.head_item_size = ZERO_BYTES;
    kill_info.tail = ZERO_INDEX_VALUE;
    kill_info.tail_item_size = ZERO_BYTES;
    kill_info.current = ZERO_INDEX_VALUE;
    kill_info.current_size = ZERO_BYTES;
    kill_info.chars_free = KILL_BUFF_SIZE;

    /* 'current' is the same as 'head' */
    kill_info.head_of_killbuff = TRUE;

    /* no items previously yanked */
    kill_info.yank_index = ZERO_INDEX_VALUE;
    kill_info.yank_size = ZERO_BYTES;
}

 



		    wstscrn.c                       04/24/89  1040.7rew 04/24/89  1031.8      201663



/* ********************************************
   *                                          *
   * Copyright, (C) Honeywell Bull Inc., 1988 *
   *                                          *
   ******************************************** */

/* HISTORY COMMENTS:
  1) change(88-04-29,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Created.
  2) change(88-07-25,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Documentation additions only. Added header comments to all routines.
  3) change(88-08-09,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Fix references to include files; "wstdefs.h" was split into
     "wstdefs.h" and "wsttype.h" to avoid declaration clash; also,
     various constants defined to descriptive names.
  4) change(89-01-30,Lee), approve(89-01-02,MCR8043), audit(89-03-14,Flegel),
     install(89-04-24,MR12.3-1033):
     Separated input and output arguments to int86() to avoid confusion
     when parameters are used.
                                                   END HISTORY COMMENTS */

/* WSTSCRN - This module contains routines for manipulating WSTERM's
   various screens. The copy of what should be contained on the screen
   is maintained in screen buffers which may be "swapped" to the screen.
*/

#include <dos.h>
#include <ctype.h>
#include "wstdefs.h"
#include "wstglob.h"

/*
**********************************************************************

  Routine:            WST_SCREEN_CLEAR 

  Function:
      This routine blank fills the contents of a specified screen 
  buffer and initializes its cursor coordinates to the home position. 

  Parameters:
     (output)         scr - pointer to the screen buffer to clear 

  Returns:            NONE 

**********************************************************************/

wst_screen_clear(scr)
SCREEN *scr;    /* pointer to screen buffer */
{
    int i;

    /* home cursor position */
    scr->cursor_row = CURSOR_HOME_ROW;
    scr->cursor_col = CURSOR_HOME_COL;

    /* clear the screen by writing blanks to entire screen buffer */
    for (i = 0; i < SCREEN_BUFFER_BYTES;) {
        scr->screen[i++] = ' ';
        scr->screen[i++] = scr->attr;
    }
}



/*
**********************************************************************

  Routine:            WST_SCREEN_PRINTLINE 

  Function:
      This routine writes a line of text to the screen buffer at the 
  screen buffer's current row coordinate. The screen buffer's row 
  coordinate variable is then incremented. 

  Parameters:
     (output)         scr - pointer to the screen buffer to write the 
                          string to 
     (input)          str - the character string to write 

  Returns:            NONE 

**********************************************************************/

wst_screen_printline(scr,str)
SCREEN *scr;    /* pointer to screen buffer */
char *str;      /* string to write to screen buffer */
{
    register int col;
    register int offset;

    /* write the string at the cursor line starting at column 0 */
    col = 0;

    /* index into appropriate location into screen buffer */
    /* (multiply by 2 to account for character and attribute bytes) */
    offset = scr->cursor_row * SCREEN_COLS * 2;

    /* put each character to the screen buffer until end of string */
    /* or until end of line */
    for (col = 0; *str && col < SCREEN_COLS; col++) {
        scr->screen[offset++] = *str++;
        offset++;
    }

    /* increment the cursor line */
    scr->cursor_row++;
}



/*
**********************************************************************

  Routine:            PUT_WST_SCREEN 

  Function:
      This routine displays a character, updating the position of the 
  physical cursor in the cursor position variables of the specified 
  screen buffer. Boundary checks are made to ensure that the cursor 
  stays within the defined screen boundary. 

  Parameters:
     (output)         scr - specifies the screen buffer whose cursor 
                          coordinate variables are to be updated 
     (input)          ch - specifies the character to display 

  Returns:            NONE 

**********************************************************************/

put_wst_screen(scr,ch)
SCREEN *scr;   /* pointer to screen buffer */
int ch;        /* character to */
{

    /* save current cursor position */
    cursor_pos(&scr->cursor_row,&scr->cursor_col);

    /* overwriting status line? */
    if (scr->cursor_row > MAX_SCREEN_LINE) {

        /* scroll the display */
        wst_scroll();

        /* "scroll" cursor as well */
        scr->cursor_row = MAX_SCREEN_LINE;
        cursor_move(scr->cursor_row,scr->cursor_col);
    }

    /* display the character */
    putch(ch);

    /* get cursor position */
    cursor_pos(&scr->cursor_row,&scr->cursor_col);

    /* on status line? */
    if (scr->cursor_row > MAX_SCREEN_LINE) {

        /* scroll display up */
        wst_scroll();

        /* "scroll" cursor up */
        scr->cursor_row = MAX_SCREEN_LINE;
        cursor_move(scr->cursor_row,scr->cursor_col);
    }    
}



/*
**********************************************************************

  Routine:            WST_SCREENS_INIT 

  Function:
      This routine initializes wsterm's screen buffers (foreground, 
  background and temporary) when WSTERM starts up. 

  Parameters:
     (input)          ch - specifies the character to initialize the 
                          contents of the screen buffer with 
     (input)          attr - specifies the attribute to initialize 
                          the contents of the screen buffer with 

  Returns:            NONE 

  Note 1 - Only the attribute and cursor position fields are 
      initialized for the temporary screen buffer as the screen 
      contents should always be initialized before it is used. 
**********************************************************************/

wst_screens_init(ch,attr)
int ch;   /* character to fill the screens with on initialization */
int attr; /* attribute to fill the screens with on initialization */
{
    int i;

    /* set the attribute to be used for a particular screen */
    wst_fg_screen.attr = attr;
    wst_bg_screen.attr = attr;
    wst_tmp_screen.attr = attr;
    wst_help_screen.attr = attr;

    /* home the cursor positions */
    wst_fg_screen.cursor_row = CURSOR_HOME_ROW;
    wst_fg_screen.cursor_col = CURSOR_HOME_COL;

    wst_bg_screen.cursor_row = CURSOR_HOME_ROW;
    wst_bg_screen.cursor_col = CURSOR_HOME_COL;

    wst_tmp_screen.cursor_row = CURSOR_HOME_ROW;
    wst_tmp_screen.cursor_col = CURSOR_HOME_COL;

    wst_help_screen.cursor_row = CURSOR_HOME_ROW;
    wst_help_screen.cursor_col = CURSOR_HOME_COL;

    /* initialize the contents of the screens; */
    /* temporary and help screen is not initialized, it should be */
    /* explicitly initialized each time it is used */
    for (i = 0; i < SCREEN_BUFFER_BYTES;) {
        wst_fg_screen.screen[i] = ch;
        wst_bg_screen.screen[i++] = ch;
        wst_fg_screen.screen[i] = attr;
        wst_bg_screen.screen[i++] = attr;
    }
}



/*
**********************************************************************

  Routine:            SAVE_WST_SCREEN 

  Function:
      This routine saves the contents of the screen and the position 
  of the cursor to a screen buffer structure. 

  Parameters:
     (output)         scr - pointer to the screen buffer structure to 
                          save the screen to 

  Returns:            NONE 

  Note 1 - Only the first 24 lines are saved as the 25th line is the 
      status line 
**********************************************************************/

save_wst_screen(scr)
SCREEN *scr;   /* pointer to the screen buffer */
{
    cursor_pos(&scr->cursor_row,&scr->cursor_col);
    save_screen(scr->screen);
}



/*
**********************************************************************

  Routine:            RESTORE_WST_SCREEN 

  Function:
      This routine restores the contents of the screen and cursor 
  position which was previously saved in a screen buffer structure. 

  Parameters:
     (input)          scr - specifies the screen buffer structure to 
                          restore the screen from 

  Returns:            NONE 

  Note 1 - Only the first 24 lines of the screen are restored as the 
      25th line is the status line 
**********************************************************************/

restore_wst_screen(scr)
SCREEN *scr;
{
    restore_screen(scr->screen);
    cursor_move(scr->cursor_row,scr->cursor_col);
}



/*
**********************************************************************

  Routine:            CURSOR_MOVE 

  Function:
      This routine moves the physical cursor on the screen to a 
  specified screen coordinate. 

  Parameters:
     (input)          row - specifies the row to move to (0 = top of 
                          screen) 
     (input)          col - specifies the column to move to (0 = left 
                          most column) 

  Returns:            NONE 

**********************************************************************/

cursor_move(row,col)
int row;
int col;
{
    union REGS reg, outreg;

    reg.h.ah = VIDEO_CURSOR_MOVE_FUNC;   /* VIDEO cursor set */
    reg.h.dh = row;                /* coordinates to move to */
    reg.h.dl = col;
    reg.h.bh = get_active_page();  /* in current active page */
    int86(BIOS_VIDEO,&reg,&outreg);   /* call BIOS routine to do actual move */
}


/*
**********************************************************************

  Routine:            CURSOR_POS 

  Function:
      This routine reads the coordinates of the physical cursor on 
  the screen. 

  Parameters:
     (output)         row - pointer to the integer for passing back 
                          the row coordinate of the cursor 
     (output)         col - pointer to the integer for passing back 
                          the column coordinate of the cursor 

  Returns:            NONE 

**********************************************************************/

cursor_pos(row,col)
int *row;
int *col;
{
    union REGS reg, outreg;

    reg.h.ah = VIDEO_CURSOR_READ_FUNC;   /* VIDEO cursor read */
    reg.h.bh = get_active_page();   /* from current active page */
    int86(BIOS_VIDEO,&reg,&outreg);    /* call BIOS to get coordinates */
    *row = outreg.h.dh;
    *col = outreg.h.dl;
}



/*
**********************************************************************

  Routine:            WAIT_FOR_KEY 

  Function:
      This routine will get a key, waiting blocked if necessary. 

  Parameters:         NONE 

  Returns:            an ASCII code if an ASCII keyboard character 
                          was pressed 
                      an encoded value greater than 255 if a function 
                          or ALT key was pressed 

**********************************************************************/

wait_for_key()
{
    union REGS reg, outreg;
    int code;

    /* break key before this routine got called? */
    if (break_flag) {
        break_flag = FALSE;
        return(BREAK_KEY);
    }

    /* read the keyboard */
    reg.h.ah = BIOS_KB_READ;
    int86(BIOS_KB,&reg,&outreg);

    /* break key hit ? */
    if (break_flag) {
        break_flag = FALSE;
        return(BREAK_KEY);
    }

    /* non zero indicates regular ASCII character */
    if (outreg.h.al)
        return((int)outreg.h.al);

    /* otherwise extended ASCII code, generate unique extension code */
    code = ASCII_EXTEND_CODE + outreg.h.ah;
    return(code);
}




/*
**********************************************************************

  Routine:            CHECKKEY 

  Function:
      This routine checks to see if the a keyboard key has already 
  been pressed. 

  Parameters:         NONE 

  Returns:            an ASCII code if an ASCII keyboard character 
                          was pressed 
                      an encoded value greater than 255 if a function 
                          or ALT key was pressed 
                      -1 if no key was pressed 

**********************************************************************/

checkkey()
{
    union REGS reg, outreg;
    int cpu_flags;

    if (break_flag)    /* break key was hit */
        return(BREAK_KEY);

    reg.h.ah = BIOS_KB_STATUS;   /* call BIOS routine to see if key was hit */
    cpu_flags = int86(BIOS_KB,&reg,&outreg);

    /* check if key was hit */
    if (cpu_flags & Z_FLAG_MASK)
        return(-1);

    /* regular ASCII character? */
    if (outreg.h.al)
        return((int)outreg.h.al);

    /* encode as an extended ASCII value */
    return (ASCII_EXTEND_CODE + outreg.h.ah);
}



/*
**********************************************************************

  Routine:            ENABLE_CTL_C_CHECK 

  Function:
      This routine turns on CTRL-C checking and saves the original 
  CTRL-C checking status (either enabled or disabled) in the global 
  variable 'orig_break_status'. 

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

enable_ctl_c_check()
{
    union REGS reg, outreg;

    reg.h.ah = DOS_CTRL_C_FUNCTION;    /* function to get/set ctrl-c checking */

    /* exchange current CTRL-C checking state (enabled or disabled)
       with ENABLED state
    */
    reg.h.al = DOS_CTRL_C_EXCHANGE;    /* exchange states */
    reg.h.dl = DOS_CTRL_C_ENABLE;      /* checking enabled after exchange */

    int86(DOS_INT,&reg,&outreg);   /* call DOS interrupt to set ctrl-c checking */
    orig_break_status = outreg.h.dl;  /* save original ctrl-c checking status */
}



/*
**********************************************************************

  Routine:            RESTORE_CTL_C_CHECK 

  Function:
      This routine restores CTRL-C checking to the state (enabled or 
  disabled) previously saved in the global variable 
  'orig_break_status'. 

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

restore_ctl_c_check()
{
    union REGS reg, outreg;

    /* if originally ON, then no need to turn OFF ctl-c checking */
    if (orig_break_status) return;

    /* turn off ctl-c checking */
    reg.h.ah = DOS_CTRL_C_FUNCTION; /* function to get/set ctrl-c checking */
    reg.h.al = DOS_CTRL_C_SET;      /* switch to set ctrl-c checking */
    reg.h.dl = DOS_CTRL_C_DISABLE;  /* indicate ctrl-c checking turned off */
    int86(DOS_INT,&reg,&outreg);    /* call BIOS to turn ctrl-c checking off */
}



/*
**********************************************************************

  Routine:            PUT_TO_SCREEN 

  Function:
      This routine displays a character to the screen with boundary 
  checking. If the character goes beyond the defined screen size, the 
  cursor is forced back inside the screen area. In particular, this 
  ensures that no character, be it part of a long string or escape 
  sequence, will be placed outside the defined screen area. 

  Parameters:
     (input)          ch - specifies the character to display; the 
                          character to passed to the screen driver 

  Returns:            NONE 

**********************************************************************/

put_to_screen(ch)
int ch;
{
    union REGS reg, outreg;

    /* save current cursor coordinates; assume in foreground */
    cursor_pos(&wst_fg_screen.cursor_row,&wst_fg_screen.cursor_col);

    /* cursor already out of bounds? */
    if (wst_fg_screen.cursor_row > MAX_SCREEN_LINE) {

        /* "scroll" cursor up */
        wst_fg_screen.cursor_row = MAX_SCREEN_LINE;
        cursor_move(wst_fg_screen.cursor_row,wst_fg_screen.cursor_col);
    }    

    /* display the character */
    reg.h.al = ch;
    int86(0x29,&reg,&outreg);

    /* check again */
    cursor_pos(&wst_fg_screen.cursor_row,&wst_fg_screen.cursor_col);

    if (wst_fg_screen.cursor_row > MAX_SCREEN_LINE) {

        /* "scroll" cursor up */
        wst_fg_screen.cursor_row = MAX_SCREEN_LINE;
        cursor_move(wst_fg_screen.cursor_row,wst_fg_screen.cursor_col);
    }    
}



/*
**********************************************************************

  Routine:            WST_GETLINE 

  Function:
      This routine will get a line of input from the keyboard. The 
  line is terminated when the user hits <CARRIAGE RETURN>. This 
  routine is used instead of gets() to prevent ^C from breaking out 
  of the program. 

  Parameters:
     (output)         scr - pointer to the screen buffer to use for 
                          saving cursor position information; while 
                          in background screen, background screen 
                          buffer is used; if in foreground screen, 
                          foreground screen buffer should be used 
     (output)         str - specifies the string for passing back the 
                          line entered 

  Returns:            NONE 

**********************************************************************/

wst_getline(scr,str,stat_line)
SCREEN *scr;
char *str;   /* string to pass back the value entered */
char *stat_line;  /* status line message being displayed */
{
    int ch;
    int i;   /* index to where data is to be placed in string */

    i = 0;

    /* loop until <RETURN> hit */
    while ((ch = getkey(BLOCK)) != RETURN_KEY) {

        /* check BACKSPACE key */
        if (ch == BACKSPACE) {

            /* only if something exists in the string */
            if (i > ZERO_INDEX_VALUE) {
                /* decrement index */
                i--;

                /* rubout the character displayed */
                put_wst_screen(scr,BACKSPACE);
                put_wst_screen(scr,' ');
                put_wst_screen(scr,BACKSPACE);
            }
        }

        /* invoke background help */
        else if (ch == ALT_H) {
            help(BG_HELP);
            status_line(stat_line);
        }

        /* if is a printable character and line length of 127 not exceeded */
        else if (i < 127 && ch < ASCII_DEL && isprint(ch)) {

            /* add character to string */
            str[i] = ch;
            i++;

            /* display the character */
            put_wst_screen(scr,ch);
        }

        else
            beep();
    }

    /* echo the linefeed at end of line */
    put_wst_screen(scr,'\n');

    /* terminate the string */
    str[i] = NUL_TERMINATOR;
}



/*
**********************************************************************

  Routine:            INIT_WST_SCROLL

  Function:
      This function initializes a global structure "scroll_regs"
  which is used for scrolling the working area (first 24 lines)
  of the screen.

  Parameters:         NONE

  Returns:            NONE

**********************************************************************/

init_wst_scroll(attr)
int attr;
{
    /* scroll display up */
    scroll_regs.h.ah = VIDEO_SCROLL_UP_FUNC;
    scroll_regs.h.al = DEFAULT_LINES_TO_SCROLL;
    scroll_regs.h.ch = CURSOR_HOME_ROW;
    scroll_regs.h.cl = CURSOR_HOME_COL;
    scroll_regs.h.dh = SCREEN_LINES-1;
    scroll_regs.h.dl = SCREEN_COLS-1;
    scroll_regs.h.bh = attr;
}



/*
**********************************************************************

  Routine:            WST_SCROLL

  Function:
      This function scrolls the first 24 lines of the screen up a
  row, filling the 24th row with blanks.

  Parameters:         NONE

  Returns:            NONE

**********************************************************************/

wst_scroll()
{
    union REGS out;

    /* scroll display up */
    int86(BIOS_VIDEO,&scroll_regs,&out);
}



/*
**********************************************************************

  Routine:            PUT_SCREEN_STR 

  Function:
      This routine write a string directly to the screen driver. 

  Parameters:
     (input)          str - pointer to the string to write 

  Returns:            NONE 

**********************************************************************/

put_screen_str(str)
char *str;
{
    while (*str) putch(*str++);
}



/*
**********************************************************************

  Routine:            UPPERCASE

  Function:
      This routine returns the uppercased ASCII value of a character
  if that character is a lowercased letter. This function is used
  instead of the normal ctype.h toupper() because the character may
  be an extended ASCII value, i.e. the value of the character is not
  restricted to be in the range of 0 to 127.

  Parameters:
     (input)          ch - the character to convert to uppercase

  Returns:            the value of 'ch' if 'ch' is not a lowercase
                          letter;
                      otherwise the uppercase value of 'ch'

**********************************************************************/

uppercase(ch)
int ch;
{
    if (ch < 'a' || ch > 'z') return(ch);
    return(ch - ('a' - 'A'));
}



/*
**********************************************************************

  Routine:            WST_RESET

  Function:
      This function handles the reset escape sequence "ESC c" which
  causes the colors, scrolling region and other screen attributes to
  be reset. This routine restores the attributes needed by WSTERM
  after the reset and updates variables which are affected by the
  reset.

  Parameters:         NONE

  Returns:            NONE 

**********************************************************************/

wst_reset()
{
    int attr;

    /* update attributes of screen */
    getattr(&attr);
    wst_fg_screen.attr = attr;
    wst_bg_screen.attr = attr;
    wst_tmp_screen.attr = attr;
    wst_help_screen.attr = attr;
    scroll_regs.h.bh = attr;

    /* restore status line and WSTERM version */
    update_status();
    clear_screen ();
    cursor_move (CURSOR_HOME_ROW, 60);
    putscr("WSTERM Vers ",12);
    putscr(version,strlen(version));
    cursor_move (CURSOR_HOME_ROW,CURSOR_HOME_COL);        

    /* tell edit mode that screen has been cleared/reset */
    if (edlin.length > 0)
        erase_edit_line(&edlin);
    edlin.orig_row = edlin.cur_row = edlin.max_row = CURSOR_HOME_ROW;
    edlin.orig_col = edlin.cur_col = edlin.cur_row = CURSOR_HOME_COL;

}

 



		    wstutil.c                       04/24/89  1040.7rew 04/24/89  1032.4      324054



/* ********************************************
   *                                          *
   * Copyright, (C) Honeywell Bull Inc., 1987 *
   *                                          *
   ******************************************** */


/* HISTORY COMMENTS:
  1) change(87-05-04,Wallman), approve(87-05-04,MCR7586),
     audit(87-08-10,Flegel), install(87-08-07,MR12.1-1072):
     First release.
  2) change(87-08-14,Wallman), approve(87-08-14,PBF7586),
     audit(87-08-17,Flegel), install(87-09-10,MR12.1-1103):
     PBF increasing length of msg_line to 256 to fix stringsize condition.
  3) change(87-09-02,Wallman), approve(87-09-02,PBF7586),
     audit(87-08-17,Flegel), install(87-09-10,MR12.1-1103):
     PBF to improve robustness of string handling by avoiding all str*
     functions.
  4) change(87-09-17,Wallman), approve(87-09-17,PBF7586),
     audit(87-09-17,LJAdams), install(87-09-18,MR12.1-1109):
     Added support for Cursor Horizontal Absolute ANSI control sequence.
  5) change(88-02-24,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Removed debugging code and unused variables,
     re-formatting.
  6) change(88-04-11,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Added routine to flush keyboard input after processing BREAK
     function. Replaces a "while read_keyboard()" statement which
     did not work properly.
  7) change(88-04-20,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Added support for help screen in local_esc().
  8) change(88-04-22,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Added support for status line; output to screen is filtered to
     trap some invalid escape sequences and to trap sequences which
     corrupts the status line.
  9) change(88-05-18,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Deleted hide_sw reference to function replay().
 10) change(88-05-26,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Handling of ALT-S, ALT-O, ALT-F and ALT-P.
 11) change(88-07-20,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Modified to make edit mode default after atm.
 12) change(88-07-25,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Documentation additions only. Added header comments to all routines.
 13) change(88-08-09,Lee), approve(88-05-16,MCR7897), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Fix references to include files; "wstdefs.h" was split into
     "wstdefs.h" and "wsttype.h" to avoid declaration clash; also,
     various constants defined to descriptive names.
 14) change(88-08-30,Lee), approve(88-09-12,MCR7986), audit(88-09-19,Flegel),
     install(88-10-12,MR12.2-1160):
     Removed non-edit async mode and references to non-edit async mode
     line editing routines.
 15) change(89-01-30,Lee), approve(89-01-02,MCR8043), audit(89-03-14,Flegel),
     install(89-04-24,MR12.3-1033):
     phx21233 - Updated kb.echo when toggling between edit and non-edit mode
     while MOWSE is not attached. Updated end of page handling to allow
     variable page size.
                                                   END HISTORY COMMENTS */

/* WSTUTIL - WSTERM utility routines */

/* This module holds functions used by more than one WSTERM module */

#include  <stdio.h>
#include  <dos.h>
#include  <ws.h>
#include  <cat.h>
#include  <wsmincap.h>
#include  "wstdefs.h"
#include  "wsttype.h"
#include  "wstglob.h"

/*
**********************************************************************

  Routine:            BYTESHIFT 

  Function:
      When loading integer values, different machines will load 
  either the high or the low byte first. Multics always wants the 
  data loaded in the low byte. This routine will shift the bits if 
  needed regardless of machine type. 

  Parameters:
     (input)          number - the integer value to load 
     (output)         high - specifies the contents of the high byte 
     (output)         low - specifies the contents of the low byte 

  Returns:            NONE 

**********************************************************************/

byteshift (number, high, low)
int   number;
byte  *high,
      *low;

{ 
    if (number < MAX_8_BIT_VALUE) { 
        *high = 0;
        *low  = number;
    }
    else { 
        *high = number / MAX_8_BIT_VALUE;
        *low  = number % MAX_8_BIT_VALUE;
    }
}                                       /* End of byteshift */



/*
**********************************************************************

  Routine:            CATSTR 

  Function:
      This routine catenates strings with stringsize checking. 

  Parameters:
     (input/output)   target - target string 
     (input)          add_on - add-on string 
     (input)          target_name - target string name 
     (input)          add_on_size - character count of 'add_on' 
     (input)          target_size - target string size 

  Returns:            NONE 

  Note 1 - This routine will abort WSTERM with an error message if a 
      string size overflow is encountered!!! 
**********************************************************************/

catstr (target, add_on, add_on_size, target_name, target_size)
char    *target,            /* Target string */
        *add_on,            /* Add-on string */
        target_name [];     /* Target string name */
int     add_on_size,        /* Character count of 'add_on' */
        target_size;        /* Target string size */
{
    register int old_length;

    old_length = strlen(target);

    if (old_length + add_on_size > target_size - 1) { 

        put_screen_str ("Program error: A string size overflow has been detected in ");
        put_screen_str (target_name);

        exit (1);
    }

    movmem (add_on, &target [strlen (target)], add_on_size);
    target [ old_length + add_on_size] = NUL_TERMINATOR;
    return;
}                                       /* End of catstr */



/*
**********************************************************************

  Routine:            CLEAR_SCREEN 

  Function:
      This routine clears the data area of the screen (the first 24 
  lines) and initializes the global screen information variables 
  accordingly. The status line area (25th line) is left untouched. 

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

clear_screen ()

{ 
    clear_window();

    screen.curcol = CURSOR_HOME_COL;
    screen.curlin = CURSOR_HOME_ROW;
    screen.EOP_ct = 0;
    ds.ccol = 0;
    ds.lct = 0;
    ds.splct [0] = NUL;
}                                       /* End of clear_screen */



/*
**********************************************************************

  Routine:            EMIT_MSG 

  Function:
      This routine displays a host or local message on the screen. 
  The message may contain ANSI escape sequences. It calls the routine 
  EMIT_MSG_2 to do the real work since the message is parsed and 
  accumulated while checking for ANSI escape sequences so it must not 
  let the message become too large for EMIT_MSG_2 to handle. 

  Parameters:
     (input)          msg - specifies the buffer containing the 
                          message to display 
     (input)          msgl - specifies the number of characters from 
                          the message buffer to display 
     (input)          pstr_sw - switch to specify if the message is a 
                          prompt string 

  Returns:            NONE 

**********************************************************************/

emit_msg(msg,msgl,pstr_sw)
char msg[];
int msgl, pstr_sw;
{
    char *msg_ptr;

    msg_ptr = msg;

    /* display message in chunks up to 20 bytes in size */
    while (msgl > 20) {
        emit_msg_2(msg_ptr, 20, pstr_sw);
        msg_ptr += 20;
        msgl -= 20;
    }
    emit_msg_2(msg_ptr,msgl,pstr_sw);

    /* clear prompt string after displaying entire prompt string */
    if (screen.curcol < 1 || pstr_sw) { 
        ds.pstrl = 0;
        setmem (ds.pstr, sizeof (ds.pstr), NUL);
        kb.pos [0] = NUL;
    }
}



/*
**********************************************************************

  Routine:            EMIT_MSG_2

  Function:
      This routine displays a host or local message on the screen. 
  The message may contain ANSI escape sequences. 

  Parameters:
     (input)          msg - specifies the buffer containing the 
                          message to display 
     (input)          msgl - specifies the number of characters from 
                          the message buffer to display 
     (input)          pstr_sw - switch to specify if the message is a 
                          prompt string 

  Returns:            NONE 

**********************************************************************/

emit_msg_2 (msg, msgl, pstr_sw)
char    msg [];             /* The message */
int     msgl,               /* Message length */
        pstr_sw;            /* Prompt string */

{         
    int curc, curl,         /* For tracking cursor position */
        ipstr,              /* klin index for start of pstr */
        newc, newl,         /* For tracking cursor position */
        tab_width;          /* SPs needed for tab expansion */
    register int    i;               /* Working index */
    char    msg_line [256],     /* For message display */
            tab_space [12];

    /* We must parse display message for ANSI control sequences in order that
       their side effects are handled properly.

       Presumption:
       Display messages contain ONLY alphamerics & ANSI control sequences */

    ipstr = 0;
    setmem (msg_line, sizeof (msg_line), NUL);

    curc = screen.curcol;
    curl = screen.curlin;

    /* Scan the message */

    for (i = 0; i < msgl; i++) {           /* Begin message parse loop */

        if (checkkey() == ALT_B)
            return;

        switch (msg [i]) {
            case 'A':                         /* CUU - cursor up */
                catstr (msg_line, &msg [i], 1, "msg_line-3",
                              sizeof (msg_line));

                if (ds.do_ctl) { 
                    curl -= max (newl, 1);
                    ds.do_ctl = OFF;
                }
                else
                    curc++;
                break;

            case 'B':                         /* CUD - cursor down */
                catstr (msg_line, &msg [i], 1, "msg_line-3",
                              sizeof (msg_line));

                if (ds.do_ctl) { 
                    curl += max (newl, 1);
                    ds.do_ctl = OFF;
                }
                else
                    curc++;
                break;

            case BEL:                         /* ASCII BEL */
                catstr (msg_line, &msg [i], 1, "msg_line",
                              sizeof (msg_line));
                break;

            case BSP:                         /* ASCII BS */
                if (curc > 0) { 
                    catstr (msg_line, &msg [i], 1,
                         "msg_line", sizeof (msg_line));
                    curc = max (curc - 1, 0);
                }
                break;

            case 'C':                         /* CUF - cursor forward */
                catstr (msg_line, &msg [i], 1, "msg_line-3",
                              sizeof (msg_line));

                if (ds.do_ctl) { 
                    curl += max (newl, 1);
                    ds.do_ctl = OFF;
                }
                else
                    curc++;
                break;

            case CR:                          /* ASCII CR */
                if (strlen (msg_line) > 0) { 
                    catstr (msg_line, &msg [i], 1,
                         "msg_line", sizeof (msg_line));

                    putscr (msg_line, strlen (msg_line));
                    setmem (msg_line, sizeof (msg_line), NUL);
                }

                cursor_move (curl, 0);  /* Go to left margin */
                curc = 0;

                ds.pstrl = 0;
                setmem (ds.pstr, sizeof (ds.pstr), NUL);
                ipstr = i + 1;                /* Next char starts a prompt string */
                break;

            case 'D':                         /* CUB - cursor backward */
                catstr (msg_line, &msg [i], 1, "msg_line-3",
                              sizeof (msg_line));

                if (ds.do_ctl) { 
                    curc -= max (newl, 1);
                    ds.do_ctl = OFF;
                }
                else
                    curc++;
                break;

            case ESC:                         /* Starting display control */
                if (strlen (msg_line) > 0) {

                    putscr (msg_line, strlen (msg_line));
                    setmem (msg_line, sizeof (msg_line), NUL);
                }

                catstr (msg_line, &msg [i], 1, "msg_line-2",
                              sizeof (msg_line));
                newc = 0;                       /* Reset accumulators */
                newl = 0;
                ds.do_ctl = ON;                 /* Now parsing a display control */
                break;

            case 'G':
                catstr (msg_line, &msg [i], 1, "msg_line-3",
                              sizeof (msg_line));

                if (ds.do_ctl) {        /* ANSI CHA - record value & restart */
                    curc = max (newc - 1, 0);
                    kb.pos [0] = curc;
                    ds.do_col = OFF;
                    ds.do_ctl = OFF;
                    ds.pstrl = 0;
                    setmem (ds.pstr, sizeof (ds.pstr), NUL);
                    ipstr = i + 1;        /* Next char starts a prompt string */

                }
                else
                    curc++;
                break;

            case 'H':
                catstr (msg_line, &msg [i], 1, "msg_line-3",
                              sizeof (msg_line));

                if (ds.do_ctl) {         /* ANSI CUP - record values & restart */
                    curl = max (newl - 1, 0);
                    curc = max (newc - 1, 0);
                    kb.pos [0] = curc;
                    ds.do_col = OFF;
                    ds.do_ctl = OFF;
                    ds.pstrl = 0;
                    setmem (ds.pstr, sizeof (ds.pstr), NUL);
                    ipstr = i + 1;         /* Next char starts a prompt string */

                }
                else
                    curc++;
                break;

            case HT:                          /* ASCII HT */
                tab_width = next_tab (curc);
                curc += tab_width;
                catstr (msg_line, strncpy (tab_space,
                    spaces, tab_width), tab_width, "msg_line-4", sizeof (msg_line));
                break;

            case 'J':
                catstr (msg_line, &msg [i], 1, "msg_line-5",
                              sizeof (msg_line));

                if (ds.do_ctl) {                 /* ANSI ED - start over */
                    curl = 0;
                    curc = 0;
                    kb.pos [0] = 0;
                    ds.do_col = OFF;
                    ds.do_ctl = OFF;
                    bk_msg_showing = OFF;
                    fg_msg_showing = OFF;
                }
                else
                    curc++;
                break;

            case NL:                          /* ASCII LF */
                if (strlen (msg_line) > 0) {

                    putscr (msg_line, strlen (msg_line));
                    setmem (msg_line, sizeof (msg_line), NUL);
                }

                scroll ();
                curl = screen.curlin;

                if (local_action == 'b')
                    return;

                curc = 0;
                ds.pstrl = 0;
                setmem (ds.pstr, sizeof (ds.pstr), NUL);
                ipstr = i + 1;
                break;

            case ';':
                catstr (msg_line, &msg [i], 1, "msg_line-6",
                      sizeof (msg_line));

                if (ds.do_ctl)                  /* ANSI field separator */
                    ds.do_col = ON;
                else
                    curc++;
                break;

            case '[':
                catstr (msg_line, &msg [i], 1, "msg_line-7",
                              sizeof (msg_line));

                if (ds.do_ctl)
                    ;                 /* ANSI field opener */
                else
                    curc++;
                break;

            default:                          /* Anything else */

                /**** NOTE: Cases for char/line insert/delete may be needed */

                if (ds.do_ctl) { 
                    catstr (msg_line, &msg [i], 1,
                         "msg_line-8", sizeof (msg_line));

                    if (isdigit (msg [i])) { 
                        if (ds.do_col)
                            newc = 10 * newc + (int) msg [i] -
                                060;
                        else 
                            newl = 10 * newl + (int) msg [i] -
                                060;
                    }
                    else { /* Nothing else matters */
                        ds.do_col = OFF;
                        ds.do_ctl = OFF;
                    }
                }
                else if (isprint (msg [i])) { 
                    catstr (msg_line, &msg [i], 1,
                         "msg_line-9",  sizeof (msg_line));
                    curc++;
                }
                break;
        }                                   /* End of switch cases */

        /* Do the EOL processing */

        if (screen.maxcol > 0 && curc == screen.maxcol) {   /* phx21233 RL - skip if line length 0 */
            /* In packet mode; just wrap the line */

            if (mowse_active) { 
                if (~sync) {

                putscr (msg_line,
                         strlen (msg_line));
                    setmem (msg_line, sizeof (msg_line),
                         NUL);

                    scroll ();
                    curl = screen.curlin;

                    if (local_action == 'b')
                        return;

                    setmem (msg_line, sizeof (msg_line),
                         NUL);
                    catstr (msg_line,
                         "\\c", 2, "wrap flag", 
                        sizeof (msg_line));
                    curc = 2;
                    ipstr = i;
                }                             /* End of ~sync code */
            }                               /* End of mowse_active code */ 


            /* This is used so that the cursor never goes
               beyond screen.maxcol */

            else {
                catstr (msg_line, bs_str,
                     1, "msg_line",  sizeof (msg_line));
                curc--;
            }
        }                                 /* End of maxcol code */
    }                                     /* End of msg parse loop */

    /* Display any remaining message text */

    if (strlen (msg_line) > 0) { 
        putscr (msg_line, strlen (msg_line));
        setmem (msg_line, sizeof (msg_line), NUL);
    }

    /* If the message doesn't have a trailing NL and isn't the prompt string,
       it may be (at least part of) a prompt string. */

    if (curc > 0 && ~pstr_sw) { 
        i -= ipstr;

        if (ds.pstrl + i < MAX_SCREEN_COL) {         /* Only if the shoe fits ... */
            catstr (ds.pstr, &msg [ipstr], i, "ds.pstr",
                 sizeof (ds.pstr));
            ds.pstrl += i;
            kb.pos [0] = curc;
        }

    }

    screen.curlin = curl;
    screen.curcol = curc;

}                                       /* End of emit_msg */



/*
**********************************************************************

  Routine:            LOCAL_ESC 

  Function:
      This routine handles local escape functions requested when the 
  user hits certain ALT keys. 

  Parameters:
     (input)          scan_code - specifies the scan code for the 
                          particular ALT key entered; it determines 
                          what local escape function is being 
                          requested 

  Returns:            NONE 

**********************************************************************/

local_esc (scan_code)
int scan_code;
{
    register int    i;                  /* Working index */

    /* Move the action character to static so everybody knows what it is */

    local_action = tolower (kb.chr [0]);

    switch (scan_code) {

    case Q_KEY_CODE:                    /* Exit wsterm */

        if (read_active) {              /* Terminate any active read */
            term_read = ON;
            send_msg (nul_str, 0);
        }

        local_action = QUIT;            /* Force the defined QUIT */
        break;

    case S_KEY_CODE:
        wst_freeze = !wst_freeze;   /* toggle flag which control scrolling */
        update_status();            /* update change on status line */
        if (wst_freeze) {
            wait_for_key();
            wst_freeze = FALSE;
            update_status();
        }
        break;

    /* toggle edit mode */
    case E_KEY_CODE:
        if (mowse_active)
            status_err_msg("Cannot toggle edit in packet mode. <any key>-resume");

        else if (wst_edit_mode) {
            if (edlin.length > 0)
                status_err_msg("Line not sent, enter or kill line first. <any key>-resume");

            else {
                wst_edit_mode = FALSE;
                /* set the default to be NOT in edit mode */
                glass_edit_mode = FALSE;
                kb.echo = FALSE;    /* phx21233 R.L. update echo flag for glass tty edit mode */
            }
        }
        else if (mowse_active && kb.cndx > 0)
            status_err_msg("Line not sent, enter or kill line first. <any key>-resume");

        else {
            wst_edit_mode = ON;
            /* set the default to be in edit mode */
            glass_edit_mode = TRUE;
            kb.echo = TRUE;    /* phx21233 R.L. update echo flag for glass tty edit mode */
        }
        update_status();
        break;


    case O_KEY_CODE:
        wst_paging = !wst_paging;   /* toggle flag for displaying EOPs */
        update_status();            /* update change on status line */
        break;

    case F_KEY_CODE:
        wst_f_audit = !wst_f_audit;  /* toggle flag for file audit */
        if (wst_f_audit) {
            if (begin_file_audit() < 0)
                wst_f_audit = OFF;
        }
        else
            end_file_audit();
        update_status();             /* update change on status line */
        break;

    case P_KEY_CODE:
        wst_p_audit = !wst_p_audit;  /* toggle flag for printer audit */
        if (wst_p_audit) {
            if (begin_printer_audit() < 0)
                wst_p_audit = OFF;
        }
        else
            end_printer_audit();
        update_status();             /* update change on status line */
        break;

    case M_KEY_CODE:                    /* Display minibuffer */

        display_bkmsg ();
        break;

    case B_KEY_CODE:                    /* Line break */

        /* Wipe out all input typeahead */

        kb.cndx = 0;
        kb.endx = 0;
        kb.klin [0] = NUL;

        if (wst_edit_mode && !sync) {
            cursor_eol(&edlin);
            screen.curlin = edlin.cur_row;
            screen.curcol = edlin.cur_col;
        }

        edlin.index = 0;
        edlin.length = 0;

        flush_dos_keys();

        if (mowse_active) {
            put_to_screen(CR);
            put_to_screen(LF);
            screen.curlin = wst_fg_screen.cursor_row;
            screen.curcol = wst_fg_screen.cursor_col;
            ds.ccol = 0;
            ds.lct = 0;
            ds.lndx = 0;
            setmem(ds.dlin,sizeof(ds.dlin),NUL);
            ds.pstrl = 0;
            ds.pstr[0] = 0;
            ds.splct[0] = 0;
            screen.EOP_ct = 0;
        }

        puttdata (FG_BREAK, NUL, 0);
        break_sent = mowse_active;
        break;

    case C_KEY_CODE:                    /* Clear screen */

        clear_screen ();
        cursor_move (CURSOR_HOME_ROW, 60);
        putscr("WSTERM Vers ",12);
        putscr(version,strlen(version));
        cursor_move (CURSOR_HOME_ROW,CURSOR_HOME_COL);        

        if (ds.pstrl > 0)
            emit_msg (ds.pstr, ds.pstrl, PSTR);
        else if (wst_edit_mode) {
            edlin.orig_row = edlin.cur_row = edlin.max_row = CURSOR_HOME_ROW;
            edlin.orig_col = edlin.cur_col = edlin.cur_row = CURSOR_HOME_COL;
            redraw_edit_line(&edlin);
        }

        break;

    case zero_KEY_CODE:                 /* Send NUL (set mark) */
    case 129:

        if (mowse_active)
            send_msg (nul_str, 1);
        else 
            puttdata (FG_TERMINAL_DATA, nul_str, 1);
        break;

    case D_KEY_CODE:                    /* Display message */

        if (~fg_msg_showing) { 
            status_err_msg("No foreground messages. <any key>-resume");
            update_status();
        }
        else { 
            if (wst_edit_mode || (mowse_active && ~sync)) { 
                /* redraw for edit mode */
                erase_edit_line(&edlin);
                emit_msg(fg_msg.text,fg_msg_len,~PSTR);
                fg_msg_len = 0;
                signal_fg(OFF);
                fg_msg_showing = OFF;
                cursor_pos(&edlin.cur_row,&edlin.cur_col);
                edlin.orig_row = edlin.cur_row;
                edlin.orig_col = edlin.cur_col;
                redraw_edit_line(&edlin);
            }
        }
        break;

    case H_KEY_CODE:    /* invoke the help screen */
        help(GENERAL_HELP);
        update_status();  /* restore the status line before returning */
        break;

    case V_KEY_CODE:  /* invoke history screen */
        if (wst_edit_mode) {
            history_screen(&wst_fg_screen);
            update_status();
        }
        else {
            status_err_msg("History functions available only in edit mode. <any key>-resume");
            update_status();
        }
        break;

    default:                            /* Anything else is an error */
        status_err_msg("Unrecognized WSTERM request, enter ALT-H for help.  <any key>-resume");
        update_status();
        break;
    }
}                                       /* End of local_esc */



/*
**********************************************************************

  Routine:            PUTSCR 

  Function:
      This routine writes a string to the screen driver. Undesirable 
  escape sequences are filtered out. The ANSI clear screen "ESC [ 2 
  J" and clear to end of page "ESC [ J" sequences are intercepted to 
  prevent the 25th line from being cleared. Instead, appropriate 
  routines are called to clear all but the 25th line and to clear up 
  to but not including the 25th line. Clearing the 25th line (the 
  status line) causes flickering each time the screen is cleared. 

  Parameters:
     (input)          str - specifies the buffer containing the 
                          message to display 
     (input)          strl - specifies the number of characters from 
                          the message buffer to display 

  Returns:            NONE 

**********************************************************************/

putscr(str,strl)
char *str;
int strl;
{
    int ch;
    int i;

    /* process each character */
    for (i = 0; i < strl; i++) {

        if (checkkey() == ALT_S) {
            wait_for_key();
            wst_freeze = !wst_freeze; /* toggle flag which control scrolling */
            update_status();            /* update change on status line */
        }

        if (wst_freeze) {
            wait_for_key();
            wst_freeze = FALSE;
            update_status();
        }
            
        ch = *str++;

/* algorithm: increment index each time the character received
    matches the next character in the escape sequence until the
    entire escape sequence is received. Once the entire sequence
    is recognized, handle it. */

        /* matching first character of escape sequence? */
        if (clr_index == 0) {
            /* first character an escape char? */
            if (ch == ESC)
                /* yes, match next character in sequence */
                clr_index++;
            /* not escape character, just display the character */
            else
                put_to_screen(ch);
        }

        /* check if second character of sequence */
        else if (clr_index == 1) {

            /* match second char in sequence ? */
            if (ch == '[')
                clr_index++;

            /* check if still part of valid escape sequence */
            else if (is_esc[ch]) {
                clr_index = 0;
                put_to_screen(ESC);
                put_to_screen(ch);

                /* if reset sequence ESC c, recover for WSTERM */
                if (ch == 'c')
                    wst_reset();
            }
            /* not the sequence we are looking for, flush */
            else {
                clr_index = 0;
                put_to_screen(ch);
            }
        }

        /* check if third character of sequence */
        else if (clr_index == 2) {

            /* last char in "ESC [ J" sequence? */
            if (ch == 'J') {
                clear_eow();
                clr_index = 0;
            }

            /* the '2' in "ESC [ 2 J" sequence? */
            else if (ch == '2')
                clr_index++;

            /* not a recognized sequence, flush */
            else {
                put_to_screen(ESC);
                put_to_screen('[');
                put_to_screen(ch);
                clr_index = 0;
            }
        }

        /* the 'J' in "ESC [ 2 J" sequence */
        else if (clr_index == 3) {
            if (ch == 'J') {
                clear_window();
                clr_index = 0;
            }

            /* not recognized, flush */
            else {
                put_to_screen(ESC);
                put_to_screen('[');
                put_to_screen('2');
                put_to_screen(ch);
                clr_index = 0;
            }
        }

        /* not recognized, flush */
        else {
            clr_index = 0;
            put_to_screen(ch);
        }
    }
}



/*
**********************************************************************

  Routine:            CLEAR_EOW 

  Function:
      This routine is used to handle the ANSI escape sequence "ESC [ 
  J" to clear the screen from the cursor position to the end of the 
  screen. This routine simulates clearing to the end of the screen 
  but does not damage the 25th line (the status line). 

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

clear_eow()
{
    union REGS reg, outreg;
    int row, col;

    cursor_pos(&row,&col);
    if (row < 24) {

        put_screen_str(EL);  /* display Erase Line escape sequence */

        if (row+1 < SCREEN_LINES) {

            reg.h.ah = VIDEO_SCROLL_UP_FUNC;
            reg.h.al = 0;   /* lines to scroll; 0 means clear scroll region */
            reg.h.ch = row+1;  /* start on next line */
            reg.h.cl = 0;      /* left most column */
            reg.h.dh = SCREEN_LINES-1;    /* to end of screen */
            reg.h.dl = SCREEN_COLS-1;     /* to last column */
            reg.h.bh = wst_fg_screen.attr;
            int86(BIOS_VIDEO,&reg,&outreg);

        }
    }
    cursor_move(row,col);
}



/*
**********************************************************************

  Routine:            CLEAR_WINDOW 

  Function:
      This routine is called to clear the screen and to initialize 
  the global screen information variables accordingly. The contents 
  of the 25th line (status line) remains untouched. 

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

clear_window()
{
    union REGS reg, outreg;

    reg.h.ah = VIDEO_SCROLL_UP_FUNC;
    reg.h.al = 0;  /* line to scroll, 0 means clear scroll region */
    reg.x.cx = 0;  /* home row and column coordinates */
    reg.h.dh = SCREEN_LINES-1;   /* end of screen row and column coordinates */
    reg.h.dl = SCREEN_COLS-1;
    reg.h.bh = wst_fg_screen.attr;

    int86(BIOS_VIDEO,&reg,&outreg);
    cursor_move(CURSOR_HOME_ROW,CURSOR_HOME_COL);
    screen.curcol = CURSOR_HOME_COL;
    screen.curlin = CURSOR_HOME_ROW;
}



/*
**********************************************************************

  Routine:            SCROLL 

  Function:
      This function manages the advancement of the display down the 
  screen. 

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

scroll ()

{         
    union regs_struct regs, outregs;

    /* Clear local action character */

    /*  action = NUL;*/

    /* If we're at the bottom of the main screen area, scroll up one line */

    if (screen.curlin >= MAX_SCREEN_LINE) {
        wst_scroll();

        regs.hreg.ah = SET_CURSOR_POS;      /* Position cursor at blank line */
        regs.hreg.bh = get_active_page();   /* in current active page */
        regs.xreg.dx = LINE24_COL0;
        int86 (BIOS_VIDEO, &regs, &outregs);

    }

    /* Otherwise, emit NL and count a screen line */
    else {
        putscr (nl, 2);
        screen.curlin++;
        screen.curcol = 0;

    }

    if (mowse_active && wst_paging)           /* Count an EOP line, too */
        screen.EOP_ct++;
    ds.pstrl = 0;
    setmem (ds.pstr, sizeof (ds.pstr), NUL);

    /* If mowse is attached, do local EOP processing */

    if (mowse_active) { 
        if (screen.EOP_ct == screen.maxlin && screen.maxlin > 0) {
            putscr ("EOP", 3);

            /* Wait for a character from the keyboard */
            screen.EOP_ct = 0;
            while (checkkey() < 0);
            if (checkkey() == ALT_B || checkkey() == BREAK_KEY)
                return;
            getkey(BLOCK);
            put_to_screen(CR);
            put_to_screen(LF);
        }
    }
}                                       /* End of scroll */



/*
**********************************************************************

  Routine:            FLUSH_DOS_KEYS 

  Function:
      This routine discards any keys pending in DOS's keyboard 
  buffer. 

  Parameters:         NONE 

  Returns:            NONE 

**********************************************************************/

flush_dos_keys()
{
    union REGS r, outr;

    r.h.ah = BIOS_KB_STATUS;

    /* while key in keyboard buffer, get the key from keyboard
       buffer */
    while (!(int86(BIOS_KB,&r,&outr) & Z_FLAG_MASK)) {
        r.h.ah = BIOS_KB_READ;
        int86(BIOS_KB,&r,&outr);
        r.h.ah = BIOS_KB_STATUS;
    }
}



/*
**********************************************************************

  Routine:            STATUS_ERR_MSG 

  Function:
      This routine displays an error message on the status line and 
  waits for any key hit to resume. 

  Parameters:
     (input)          msg - the null-terminated string containing the 
                          error message to display 

  Returns:            NONE 

**********************************************************************/

status_err_msg(msg)
char *msg;
{
    int row, col;

    cursor_pos(&row,&col);
    cursor_move(HIDE_CURSOR_ROW,HIDE_CURSOR_COL);
    status_line(msg);
    wait_for_key();
    cursor_move(row,col);
}


/* End of WSTUTIL */





		    bull_copyright_notice.txt       08/30/05  1008.4r   08/30/05  1007.3    00020025

                                          -----------------------------------------------------------


Historical Background

This edition of the Multics software materials and documentation is provided and donated
to Massachusetts Institute of Technology by Group Bull including Bull HN Information Systems Inc. 
as a contribution to computer science knowledge.  
This donation is made also to give evidence of the common contributions of Massachusetts Institute of Technology,
Bell Laboratories, General Electric, Honeywell Information Systems Inc., Honeywell Bull Inc., Groupe Bull
and Bull HN Information Systems Inc. to the development of this operating system. 
Multics development was initiated by Massachusetts Institute of Technology Project MAC (1963-1970),
renamed the MIT Laboratory for Computer Science and Artificial Intelligence in the mid 1970s, under the leadership
of Professor Fernando Jose Corbato.Users consider that Multics provided the best software architecture for 
managing computer hardware properly and for executing programs. Many subsequent operating systems
incorporated Multics principles.
Multics was distributed in 1975 to 2000 by Group Bull in Europe , and in the U.S. by Bull HN Information Systems Inc., 
as successor in interest by change in name only to Honeywell Bull Inc. and Honeywell Information Systems Inc. .

                                          -----------------------------------------------------------

Permission to use, copy, modify, and distribute these programs and their documentation for any purpose and without
fee is hereby granted,provided that the below copyright notice and historical background appear in all copies
and that both the copyright notice and historical background and this permission notice appear in supporting
documentation, and that the names of MIT, HIS, Bull or Bull HN not be used in advertising or publicity pertaining
to distribution of the programs without specific prior written permission.
    Copyright 1972 by Massachusetts Institute of Technology and Honeywell Information Systems Inc.
    Copyright 2006 by Bull HN Information Systems Inc.
    Copyright 2006 by Bull SAS
    All Rights Reserved
