File:  [Coherent Logic Development] / freem / src / service.c
Revision 1.12: download - view: text, annotated - select for diffs
Mon Mar 24 04:05:36 2025 UTC (8 days, 20 hours ago) by snw
Branches: MAIN
CVS tags: v0-62-3, HEAD
Replace crlf with frm_crlf to avoid symbol conflict with readline on OS/2

/*
 *   $Id: service.c,v 1.12 2025/03/24 04:05:36 snw Exp $
 *    terminal and sequential I/O handling,
 *    file and global locking
 *
 *  
 *   Author: Serena Willis <snw@coherent-logic.com>
 *    Copyright (C) 1998 MUG Deutschland
 *    Copyright (C) 2020, 2025 Coherent Logic Development LLC
 *
 *
 *   This file is part of FreeM.
 *
 *   FreeM is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Affero Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   FreeM is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU Affero Public License for more details.
 *
 *   You should have received a copy of the GNU Affero Public License
 *   along with FreeM.  If not, see <https://www.gnu.org/licenses/>.
 *
 *   $Log: service.c,v $
 *   Revision 1.12  2025/03/24 04:05:36  snw
 *   Replace crlf with frm_crlf to avoid symbol conflict with readline on OS/2
 *
 *   Revision 1.11  2025/03/24 02:00:30  snw
 *   Work around some OS/2 incompatibilities in service.c
 *
 *   Revision 1.10  2025/03/24 01:55:46  snw
 *   Work around some OS/2 incompatibilities in service.c
 *
 *   Revision 1.9  2025/03/24 01:54:09  snw
 *   Work around some OS/2 incompatibilities in set_break and set_zbreak
 *
 *   Revision 1.8  2025/03/24 01:52:30  snw
 *   Work around some OS/2 incompatibilities in set_break and set_zbreak
 *
 *   Revision 1.7  2025/03/09 19:50:47  snw
 *   Second phase of REUSE compliance and header reformat
 *
 *
 * SPDX-FileCopyrightText:  (C) 2025 Coherent Logic Development LLC
 * SPDX-License-Identifier: AGPL-3.0-or-later
 **/

#include <errno.h>
#include <sys/types.h>

#if !defined(__OpenBSD__) && !defined(__FreeBSD__)
# include <sys/timeb.h>
#endif

#include <sys/ioctl.h>
#include <unistd.h>
#include <stdlib.h>

#ifdef AMIGA68K
#include <sys/fcntl.h>
#endif

#define MAXZAS NESTLEVLS
#include "mpsdef.h"

#include <time.h>

#ifdef USE_SYS_TIME_H
#include <sys/time.h>
#endif

#include "events.h"

long int tell ();
void ris (struct vtstyp *scr);

#ifdef SCO
int scosgr (short att, short bwflag);
#endif

/* system services */
#if !defined(__APPLE__) && !defined(__gnu_hurd__) && !defined(EMSCRIPTEN)
# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__AMIGA)
#  include <termios.h>
#  if !defined(__AMIGA)
#   define TCGETA TIOCGETA
#   define TCSETA TIOCSETA
#  endif
#  define termio termios
# else
#  if !defined(MSDOS)
#    include <termio.h>
#  endif
#  if defined(__OS2__)
#    include <termios.h>
#    define termio termios
#  endif
# endif
#else
# include <termios.h>
#endif

#include <fcntl.h>

/* search 'string' for occurence of 'pattrn'
 * return: 0='not found' nbr='pattern begins at nbr' */
long int find (char *string, char *pattrn)
{
    short i;
    short j;
    register int k;
    register int l;

    i = 0;

    while (pattrn[i] != EOL) i++;				/* $l of 2nd arg */

    if (i == 1) {
        
        l = pattrn[0];
        k = 0;
        
        while (string[k] != EOL) {

            if (string[k++] == l) return k;

        }
        
        return 0L;
    
    }
    
    j = stlen (string);
    
    for (k = 0; k < j; k++) {
        
        l = 0;


l10:

        if (string[k + l] != pattrn[l]) continue;
        if (++l < i) goto l10;
    
        return ++k;

    }

    return 0L;
}					/* end of find() */

/* called by exclusive KILL to search 'exceptions' for occurence of 'variable'
 * return: 1='not found, can be killed' 0='cannot be killed' */
short int kill_ok (char *exceptions, char *variable)
{
    short i;
    short j;
    register int k;
    register int l;

    j = stlen (exceptions);
    i = stlen (variable);

    for (k = 0; k < j; k++) {
        
        for (l = 0; l < i; l++) {
            
            if (exceptions[k + l] != variable[l]) {
            
                if (exceptions[k + l] == SP && variable[l] == DELIM) return FALSE;
    
                goto outerspace;
            
            }

        }
        
        return FALSE;


outerspace:;        /* the semicolon apparently needs to be here in this case. */
                    /* break time. */

    }

    return TRUE;
}					/* end of kill_ok */

/* write this format */
void write_f (char *intext)
{
    char outtext[256];		/* output string */
    short l;
    int i;
    char final;
    int csi;

    csi = FALSE;
    l = stlen (intext);
    
    if (l < 2) return;				/* not recognized */
    
    for (i = 0; i < l; i++) {

        if (intext[i] == DELIM) break;
    
    }


    intext[i] = EOL;

    /* CUB - Cursor Backward        */
    if (!stcmp (intext, "CUB\201")) {
        
        csi = TRUE;
        final = 'D';
        
        goto end;

    }

    /* CUD - Cursor Down            */
    if (!stcmp (intext, "CUD\201")) {
        
        csi = TRUE;
        final = 'B';
        
        goto end;

    }

    /* CUF - Cursor Forward         */
    if (!stcmp (intext, "CUF\201")) {
    
        csi = TRUE;
        final = 'C';
    
        goto end;
    
    }

    /* CUP - Cursor Position        */
    /* HVP - Horizontal and vertical Position */
    if (!stcmp (intext, "CUP\201") || !stcmp (intext, "HVP\201")) {
    
        csi = TRUE;
        final = 'H';

        goto end;

    }

    /* CUU - Cursor Up              */
    if (!stcmp (intext, "CUU\201")) {
    
        csi = TRUE;
        final = 'A';
    
        goto end;

    }

    /* DCH - Delete Character */
    if (!stcmp (intext, "DCH\201")) {
        
        csi = TRUE;
        final = 'P';
    
        goto end;

    }

    /* ICH - Insert Character */
    if (!stcmp (intext, "ICH\201")) {
    
        csi = TRUE;
        final = '@';
        
        goto end;
    
    }
    
    /* DL  - Delete Line */
    if (!stcmp (intext, "DL\201")) {
    
        csi = TRUE;
        final = 'M';
        
        goto end;

    }

    /* IL  - Insert Line */
    if (!stcmp (intext, "IL\201")) {
    
        csi = TRUE;
        final = 'L';

        goto end;

    }

    /* SU  - Scroll Up = pan down */
    if (!stcmp (intext, "SU\201")) {
        
        csi = TRUE;
        final = 'S';
        
        goto end;
    
    }
    
    /* SD  - Scroll Down = pan up */
    if (!stcmp (intext, "SD\201")) {
        
        csi = TRUE;
        final = 'T';

        goto end;

    }

    /* DA  - Device Attributes      */
    if (!stcmp (intext, "DA\201")) {
        
        csi = TRUE;
        final = 'c';

        goto end;

    }

    /* DSR - Device Status Report   */
    if (!stcmp (intext, "DSR\201")) {
    
        csi = TRUE;
        final = 'n';

        goto end;

    }

    /* ED  - Erase Display          */
    if (!stcmp (intext, "ED\201")) {
        
        csi = TRUE;
        final = 'J';
        
        goto end;

    }

    /* EL  - Erase Line             */
    if (!stcmp (intext, "EL\201")) {
        
        csi = TRUE;
        final = 'K';

        goto end;

    }

    /* ECH - Erase Character */
    if (!stcmp (intext, "ECH\201")) {
    
        csi = TRUE;
        final = 'X';
    
        goto end;
    
    }
    
    /* HTS - Horizontal Tabulation Set */
    if (!stcmp (intext, "HTS\201")) {
        
        final = 'H';
        
        goto end;

    }

    /* IND - Index                  */
    if (!stcmp (intext, "IND\201")) {
        
        final = 'D';
        
        goto end;

    }

    /* NEL - NExt Line              */
    if (!stcmp (intext, "NEL\201")) {
    
        final = 'E';
    
        goto end;
    
    }
    
    if (!stcmp (intext, "SSA\201")) {
    
        final = 'F';
        
        goto end;

    }

    if (!stcmp (intext, "ESA\201")) {
    
        final = 'G';
    
        goto end;

    }

    if (!stcmp (intext, "HTJ\201")) {
    
        final = 'I';
    
        goto end;

    }

    if (!stcmp (intext, "VTS\201")) {
        
        final = 'J';
    
        goto end;

    }

    if (!stcmp (intext, "PLD\201")) {
        
        final = 'K';
        
        goto end;

    }

    if (!stcmp (intext, "PLU\201")) {
    
        final = 'L';
    
        goto end;
    
    }
    
    /* RI  - Reverse Index          */
    if (!stcmp (intext, "RI\201")) {
    
        final = 'M';
    
        goto end;

    }

    /* SS2 - Single Shift G2 */
    if (!stcmp (intext, "SS2\201")) {
    
        final = 'N';
        
        goto end;
    
    }
    
    /* SS3 - Single Shift G3 */
    if (!stcmp (intext, "SS3\201")) {
    
        final = 'O';
        
        goto end;
    
    }
    
    /* DCS - Device Control String introducer */
    if (!stcmp (intext, "DCS\201")) {
        
        final = 'P';
        
        goto end;

    }

    if (!stcmp (intext, "PU1\201")) {
        
        final = 'Q';
    
        goto end;
    
    }
    
    if (!stcmp (intext, "PU2\201")) {
        
        final = 'R';
    
        goto end;

    }

    if (!stcmp (intext, "STS\201")) {
    
        final = 'S';
    
        goto end;

    }

    if (!stcmp (intext, "CCH\201")) {
    
        final = 'T';
    
        goto end;

    }

    if (!stcmp (intext, "MW\201")) {
    
        final = 'U';
    
        goto end;

    }

    if (!stcmp (intext, "SPA\201")) {
        
        final = 'V';
    
        goto end;
    
    }
    
    if (!stcmp (intext, "EPA\201")) {
    
        final = 'W';
    
        goto end;
    
    }
    
    /* CSI - Command String Introducer */
    if (!stcmp (intext, "CSI\201")) {
    
        final = '[';
        
        goto end;

    }

    /* ST - device control String Terminator */
    if (!stcmp (intext, "ST\201")) {
    
        final = '\\';
    
        goto end;

    }

    if (!stcmp (intext, "OSC\201")) {
    
        final = ']';
    
        goto end;

    }

    if (!stcmp (intext, "PM\201")) {
        
        final = '^';
        
        goto end;

    }

    if (!stcmp (intext, "APC\201")) {
        
        final = '_';

        goto end;

    }

    /* RIS - Reset to Initial State */
    if (!stcmp (intext, "RIS\201")) {
    
        final = 'c';
        
        goto end;

    }

    /* RM  - Reset Mode             */
    if (!stcmp (intext, "RM\201")) {
    
        csi = TRUE;
        final = 'l';
    
        goto end;
    
    }
    
    /* SGR - Select Graphic Rendition */
    if (!stcmp (intext, "SGR\201")) {
        
        csi = TRUE;
        final = 'm';
    
        goto end;
    
    }
    
    /* SM  - Set Mode               */
    if (!stcmp (intext, "SM\201")) {
        
        csi = TRUE;
        final = 'h';

        goto end;

    }

    /* TBC - Tabulation Clear       */
    if (!stcmp (intext, "TBC\201")) {
    
        csi = TRUE;
        final = 'g';
    
        goto end;
    
    }
    
    if (!stcmp (intext, "NUL\201")) {
    
        final = NUL;
        
        goto controls;
    
    }

    if (!stcmp (intext, "SOH\201")) {
    
        final = SOH;
    
        goto controls;
    
    }
    
    if (!stcmp (intext, "STX\201")) {
        
        final = STX;
        
        goto controls;

    }

    if (!stcmp (intext, "ETX\201")) {
    
        final = ETX;
        
        goto controls;
    
    }
    
    if (!stcmp (intext, "EOT\201")) {
    
        final = EOT;
        
        goto controls;

    }

    if (!stcmp (intext, "ENQ\201")) {
        
        final = ENQ;
        
        goto controls;

    }

    if (!stcmp (intext, "ACK\201")) {
        
        final = ACK;
    
        goto controls;

    }
    
    if (!stcmp (intext, "BEL\201")) {
    
        final = BEL;
    
        goto controls;
    
    }
    
    if (!stcmp (intext, "BS\201")) {
    
        final = BS;
    
        goto controls;
    
    }
    
    if (!stcmp (intext, "HT\201")) {
        
        final = TAB;
    
        goto controls;
    
    }
    
    if (!stcmp (intext, "LF\201")) {
        
        final = LF;
        
        goto controls;
    
    }
    
    if (!stcmp (intext, "VT\201")) {
    
        final = VT;
    
        goto controls;
    
    }
    
    if (!stcmp (intext, "FF\201")) {
    
        final = FF;
    
        goto controls;
    
    }
    
    if (!stcmp (intext, "CR\201")) {
    
        final = CR;
    
        goto controls;

    }
    
    if (!stcmp (intext, "SO\201")) {
    
        final = SO;
    
        goto controls;
    
    }
    
    if (!stcmp (intext, "SI\201")) {
        
        final = SI;
    
        goto controls;
    
    }
    
    if (!stcmp (intext, "DLE\201")) {
        
        final = DLE;
    
        goto controls;
    
    }
    
    if (!stcmp (intext, "DC1\201")) {
    
        final = DC1;
    
        goto controls;
    
    }
    
    if (!stcmp (intext, "DC2\201")) {
        
        final = DC2;
    
        goto controls;
    
    }
    
    if (!stcmp (intext, "DC3\201")) {
        
        final = DC3;
    
        goto controls;
    
    }
    
    if (!stcmp (intext, "DC4\201")) {
        
        final = DC4;
        
        goto controls;
    
    }
    
    if (!stcmp (intext, "NAK\201")) {
        
        final = NAK;
    
        goto controls;
    
    }
    
    if (!stcmp (intext, "SYN\201")) {
        
        final = SYN;
    
        goto controls;
    
    }
    
    if (!stcmp (intext, "ETB\201")) {
    
        final = ETB;
    
        goto controls;
    
    }
    
    if (!stcmp (intext, "CAN\201")) {

        final = CAN;
    
        goto controls;

    }
    
    if (!stcmp (intext, "EM\201")) {
    
        final = EM;
        
        goto controls;
    
    }
    
    if (!stcmp (intext, "SUB\201")) {
    
        final = SUB;
        
        goto controls;
    
    }
    
    if (!stcmp (intext, "ESC\201")) {
    
        final = ESC;
    
        goto controls;
    
    }
    
    if (!stcmp (intext, "FS\201")) {
    
        final = FS;
    
        goto controls;
    
    }
    
    if (!stcmp (intext, "GS\201")) {
    
        final = GS;

        goto controls;

    }

    
    if (!stcmp (intext, "RS\201")) {
    
        final = RS;
    
        goto controls;
    
    }
    
    if (!stcmp (intext, "US\201")) {
    
        final = US;
        
        goto controls;
    
    }
    
    if (!stcmp (intext, "DEL\201")) {
        
        final = DEL;
    
        goto controls;
    
    }
    
    /* DECKPAM Keypad Application Mode */
    if (!stcmp (intext, "DECKPAM\201")) {
        
        final = '=';
    
        goto end;
    
    }
    
    /* DECKPNM Keypad Numeric Mode  */
    if (!stcmp (intext, "DECKPNM\201")) {
    
        final = '>';
    
        goto end;
    
    }
    
    /* DECLL Load LEDs              */
    if (!stcmp (intext, "DECLL\201")) {
        
        csi = TRUE;
        final = 'q';

        goto end;
    
    }

    /* DECRC Restore Cursor         */
    if (!stcmp (intext, "DECRC\201")) {
        
        final = '8';
        
        goto end;
    
    }
    
    /* DECSC Save Cursor            */
    if (!stcmp (intext, "DECSC\201")) {
        
        final = '7';
    
        goto end;
    
    }
    
    /* DECSTBM Set Top & Bottom Margins */
    if (!stcmp (intext, "TBM\201") ||
        
        !stcmp (intext, "DECSTBM\201")) {
    
        csi = TRUE;
        final = 'r';
    
        goto end;
    
    }

    /* ZAS Alternate Screen */
    if (!stcmp (intext, "ZAS\201")) {

        csi = TRUE;
        final = '~';

        goto end;
    
    }
    
    return;				/* code not recognized */

    controls:
    outtext[0] = final;
    outtext[1] = EOL;
    
    write_m (outtext);
    
    return;

end:

    outtext[0] = ESC;

    if (csi++) outtext[1] = '[';

    while (++i < l) {
    
        if ((outtext[csi] = intext[i]) == DELIM) outtext[csi] = ';';
    
        csi++;
    
    }
    
    outtext[csi++] = final;
    outtext[csi] = EOL;
    
    write_m (outtext);
    
    return;
}					/* end of write_f() */

/* Output on HOME device */
void writeHOME (char *text)			
{

#if !defined(__OS2__)    
    struct winsize terminal_window;
#endif    
    static char initflag = TRUE;	/* initialisation flag */
    static char esc = 0;		/* esc processing flag */
    static char dcs = 0;		/* device control processing flag */

    static short args[ARGS_IN_ESC];
    static short argcnt = 0;
    static short noargs = TRUE;
    static char tmp[512];
    static short foreground = TRUE;	/* foreground flag */
    static struct vtstyp *vts;

    /* external struct vtstyp *screen;         active screen */
    static struct vtstyp *altscr;	/* background screen */
    static struct vtstyp *zases[MAXZAS];
    static int zaslevel = 0;

    /* SGR and CSI=cF have ***different*** color codes */
    #ifdef COLOR
    static char coltrans[8] =
    {0, 4, 2, 6, 1, 5, 3, 7};

    #endif /* COLOR */


    short   tmpx;
    register int ch;
    register int j;
    register int i;
    short   k;

    /* we assume the HOME device is an ASCII machine according
    * to ANSI X3.4, X3.64 etc with 24 lines and 80 columns
    * so we look not only at controls as the MUMPS X11.1-1984
    * demands, but as well at esc sequences and device control
    * strings.
    * 
    * In addition we assume, that the terminal cannot handle
    * tab_clear (CSI 3g) nor tab_set (ESC H) so these functions
    * are emulated here. For most terminals that might
    * not be neccesary. With 'PROC_TAB' we may switch versions.
    * 
    * We support the VT100 on PC-"Terminals"
    * where there is no TBM so we have to emulate
    * scoll up /down with LF,RI and autowrap. SGR is somewhat
    * crazy on the PC and there is a lot of code to fix that.
    * The PC completely ignores SGRs it does not fully recognize.
    * E.g. SGR(7,4) will not work while SGR(4,7) at least inverts
    * the display.
    * CSI 10 p (invert INVERS at active position) 
    * is being emulated too.
    * We emulate the terminal software so we have always an image
    * of the screen in memory. That enables us to have features like
    * CSI 0 ~  (private sequence: change screen)
    * CSI 1 ~  (private sequence: output to foreground screen)
    * CSI 2 ~  (private sequence: output to background screen)
    * CSI 3 ~  (private sequence: save foreground to background)
    * CSI 4 ~  (private sequence: screen restore)
    * and the 'hardcopy function'
    */
    if (initflag) {

#if !defined(__OS2__)        
        /* TODO: why are we casting to void here? */
        (void) ioctl(STDOUT_FILENO, TIOCGWINSZ, &terminal_window);
        
        n_lines = terminal_window.ws_row;
        n_columns = terminal_window.ws_col;
#else
        n_lines = 25;
        n_columns = 80;
#endif
        
        screen = (struct vtstyp *) calloc (1, sizeof (struct vtstyp));

        ris (screen);
        altscr = (struct vtstyp *) calloc (1, sizeof (struct vtstyp));

        ris (altscr);
        initflag = FALSE;

    }

    opnfile[HOME] = stdout;
    tmpx = 0;
    j = 0;
    
    while ((ch = text[j++]) != EOL) {
        
        if (ch == NUL) continue;
    
        if (tmpx > 480) {
        
            tmp[tmpx] = EOL;
            tmpx = 0;
        
            if (foreground) m_output (tmp);

        }


        if (RightMargin && xpos[HOME] > RightMargin && esc == 0) {

            --j;
            
            tmp[tmpx++] = CR;
            xpos[HOME] = 0;
            ch = LF;

        }

        /* what in the name of good and holy is this macro abuse nonsense? */

#ifdef PROC_TAB
        if (ch != TAB) tmp[tmpx++] = ch;
#else
        tmp[tmpx++] = ch;
#endif /* PROC_TAB */
        

        if (UNSIGN (ch) >= SP && ch != DEL) {	/* printable characters */
            
            if (esc == 0) {		/* no esc/dcs in progress; wrap-around */

                (*screen).screenx[(unsigned int) (*screen).sclines[ypos[HOME]]][xpos[HOME]] = ch;
            
                if ((*screen).savarg == FALSE) {
            

#ifdef COLOR
                    (*screen).screenc[(unsigned int) (*screen).sclines[ypos[HOME]]][xpos[HOME]] = (*screen).col;
#endif /* COLOR */

                    (*screen).screena[(unsigned int) (*screen).sclines[ypos[HOME]]][xpos[HOME]] = (*screen).att;

                }

                if (dcs == 0 && ++xpos[HOME] >= n_columns) {
                
                    xpos[HOME] = 0;
                
                    if ((*screen).rollflag) goto pLF;
                
                    ypos[HOME] = (*screen).sc_lo;

                }

                continue;

            }

            if (esc == 1) {		/* esc_sequence in progress */

                if (ch == '[') {	/* CSI command string starts */
                    esc = 2;
                    continue;
                } 
                else if (ch == 'H') {	/* HTS set tab at $X */
                    (*screen).tabs[xpos[HOME]] = 1;
                } 
                else if (ch == 'M') {	/* RI cursor up *//* upper margin of scroll area: scroll down */
                
                    if (ypos[HOME] == (*screen).sc_up) {
                        
                        k = (*screen).sclines[(*screen).sc_lo];
                        
                        for (i = (*screen).sc_lo; i > (*screen).sc_up; i--) (*screen).sclines[i] = (*screen).sclines[i - 1];
                
                        (*screen).sclines[(*screen).sc_up] = k;
                
                        for (i = 0; i < n_columns; i++) {
                        
                            (*screen).screenx[k][i] = SP;
                            (*screen).screena[k][i] = (*screen).att;


#ifdef COLOR
                            (*screen).screenc[k][i] = (*screen).col;
#endif /* COLOR */

                        }
                        
                        if (foreground) {
                
                            tmp[tmpx - 2] = EOL;
                            m_output (tmp);
                            
                            tmpx = 0;
                            part_ref (screen, (*screen).sc_up, (*screen).sc_lo);

                        }
                    }

                    if (ypos[HOME] != 0 && ypos[HOME] != (*screen).sc_up) ypos[HOME]--;
                    
                    tmp[tmpx++] = ESC;
                    tmp[tmpx++] = '[';
                    
                    if (ypos[HOME] > 8) tmp[tmpx++] = (1 + ypos[HOME]) / 10 + '0';
                    
                    tmp[tmpx++] = (1 + ypos[HOME]) % 10 + '0';
                    
                    if (xpos[HOME] > 0) { 

                        tmp[tmpx++] = ';';
                        
                        if (xpos[HOME] > 8) tmp[tmpx++] = (1 + xpos[HOME]) / 10 + '0';
                        
                        tmp[tmpx++] = (1 + xpos[HOME]) % 10 + '0';
                    
                    }
                    
                    tmp[tmpx++] = 'H';

                } 
                else if (ch == 'E') {	/* NEL new line */

                    /* RI */
                
                    xpos[HOME] = 0;
                    esc = 0;
                    
                    goto pLF;

                } 
                else if (ch == 'Q') {	/* DCS Device control string */
                    dcs = 1;
                } 
                else if (ch == '\\') {	/* ST String terminator (DCS) */
                    dcs = 0;
                } 
                else if (ch == '7') {	/* DEC CS Cursor Save */
                    
                    (*screen).csx[(*screen).cs] = xpos[HOME];
                    (*screen).csy[(*screen).cs] = ypos[HOME];
                    
                    if (++((*screen).cs) >= CSLEN) (*screen).cs = CSLEN - 1;

                } 
                else if (ch == '8') {	/* DEC CRST Cursor Restore */
                    
                    if (--((*screen).cs) <= 0) (*screen).cs = 0;
                    
                    xpos[HOME] = (*screen).csx[(*screen).cs];
                    ypos[HOME] = (*screen).csy[(*screen).cs];
                    
                    /* make sure cursor is at desired position */
                    tmp[tmpx++] = ESC;
                    tmp[tmpx++] = '[';
                    
                    if (ypos[HOME] > 8) tmp[tmpx++] = (1 + ypos[HOME]) / 10 + '0';

                    tmp[tmpx++] = (1 + ypos[HOME]) % 10 + '0';
                    
                    if (xpos[HOME] > 0) {

                        tmp[tmpx++] = ';';
                        
                        if (xpos[HOME] > 8) tmp[tmpx++] = (1 + xpos[HOME]) / 10 + '0';
                        
                        tmp[tmpx++] = (1 + xpos[HOME]) % 10 + '0';

                    }

                    tmp[tmpx++] = 'H';

                } 
                else if (ch == 'c') {	/* RIS Reset to initial state */
                    
                    esc = 0;
                    dcs = 0;
                    foreground = TRUE;
                    xpos[HOME] = 0;
                    ypos[HOME] = 0;
                    
                    ris (screen);

                } 
                else if (ch == '(' || ch == ')') {
                    continue;
                }
                
                esc = 0;

                continue;

            }				/* end if (esc==1) */

            /* command string (esc [) in progress */
            /* numeric arguments ? */
            if (ch >= '0' && ch <= '9') {

                noargs = FALSE;
                args[argcnt] = args[argcnt] * 10 + ch - '0';
                
                continue;

            }

            if (ch == ';') {
                
                args[++argcnt] = 0;
                
                continue;

            }

            if (ch == '=') {
                esc = 3;
                continue;
            }				/* color sequence */

            if (esc == 3) {

                esc = 0;


#ifdef COLOR
                if (ch == 'F') {	/* foreground color */

                    (*screen).col = (((*screen).col & ~017) | (args[0] & 017));
                
                    tmp[tmpx++] = ESC;	/* reverse background */
                    tmp[tmpx++] = '[';
                    tmp[tmpx++] = '=';

                    if (args[0] > 9) tmp[tmpx++] = '0' + (args[0] / 10);

                    tmp[tmpx++] = '0' + (args[0] % 10);
                    tmp[tmpx++] = 'I';

                    continue;

                }

                if (ch == 'G') {	/* background color */

                    (*screen).col = (((*screen).col & 017) | (args[0] * 16));
                
                    tmp[tmpx++] = ESC;	/* reverse forground */
                    tmp[tmpx++] = '[';
                    tmp[tmpx++] = '=';
                
                    if (args[0] > 9) tmp[tmpx++] = '0' + (args[0] / 10);

                    tmp[tmpx++] = '0' + (args[0] % 10);
                    tmp[tmpx++] = 'H';
                    
                    continue;

                }
#endif /* COLOR */


                continue;

            } /* if (esc == 3) */

            if (ch < '@') continue;

            /* check final characters */
            if (ch == 'A') {		/* CUU cursor up */
                
                do {
                    
                    if (--ypos[HOME] < 0) ypos[HOME] = 0;
                
                }
                while (--args[0] > 0);

            } 
            else if (ch == 'B') {	/* CUD cursor down */
                
                do {
                
                    if (++ypos[HOME] >= (n_lines - 1)) ypos[HOME] = (n_lines - 1);
                
                }
                while (--args[0] > 0);

            } 
            else if (ch == 'C') {	/* CUF cursor right */
                
                do {
                    
                    if (++xpos[HOME] >= n_columns) xpos[HOME] = (n_columns - 1);

                }
                while (--args[0] > 0);

            } 
            else if (ch == 'D') {	/* CUB cursor left */

                do {

                    if (--xpos[HOME] < 0) xpos[HOME] = 0;

                }
                while (--args[0] > 0) ;

            } 
            else if (ch == 'H') {	/* CUP cursor position */

                i = --args[0];
            
                if (i < 0) i = 0;
                if (i <= n_lines) ypos[HOME] = i;

                i = --args[1];
                
                if (i < 0) i = 0;
                if (i < n_columns) xpos[HOME] = i;

            } 
            else if (ch == 'K') {	/* EL erase line */
            
                int k;

                i = 0;
                k = n_columns;

                if (args[0] == 0) i = xpos[HOME];
                if (args[0] == 1) k = xpos[HOME] + 1;

                while (i < k) {

                    (*screen).screenx[(unsigned int) (*screen).sclines[ypos[HOME]]][i] = SP;
                    (*screen).screena[(unsigned int) (*screen).sclines[ypos[HOME]]][i] = 0;	/* not 'att' */


#ifdef COLOR
                    (*screen).screenc[(unsigned int) (*screen).sclines[ypos[HOME]]][i] = (*screen).col;
#endif /* COLOR */

                    i++;

                }
            } 
            else   /* TODO: this bogosity must go away. */


ED:     
                if (ch == 'J') {		/* ED erase display */

                    register int k;

#ifdef COLOR
                    unsigned char color;
#endif /* COLOR  (COLOR is forced on in mpsdef.h or mpsdef0.h) */

                    i = 0;
                    k = n_columns;
                    
                    if (args[0] == 0) i = xpos[HOME];
                    if (args[0] == 1) k = xpos[HOME] + 1;
                

#ifdef COLOR
                    color = (*screen).col;
#endif /* COLOR */

                    while (i < k) {		/* clear current line */

                        /* TODO: revisit this commented-out section. Was part of the
                         *       original support for terminals larger than 80x25.
                         *       Possibly responsible for screen state corruption?
                         *
                         *       Ref: issue #95
                         *       https://gitlab.coherent-logic.com/jpw/freem/-/issues/95
                         */
                        /*
                        (*screen).screenx[(unsigned int) (*screen).sclines[ypos[HOME]]][i] = SP;
                        (*screen).screena[(unsigned int) (*screen).sclines[ypos[HOME]]][i] = 0;*/

                        (*screen).screenx[ypos[HOME]][i] = SP;
                        (*screen).screena[ypos[HOME]][i] = 0;	/* not 'att' */
                    
#ifdef COLOR
                        (*screen).screenc[ypos[HOME]][i] = color;
#endif /* COLOR */

                        i++;
                
                    }

                    /* clear rest of screen */
                    if (args[0] != 1) {
                        
                        for (k = ypos[HOME] + 1; k < n_lines; k++) {
                            
                            for (i = 0; i < n_columns; i++) {
                                
                                /* TODO: revisit; see above */
                                /* (*screen).screenx[(unsigned int) (*screen).sclines[k]][i] = SP; */
                                (*screen).screenx[k][i] = SP;
                                (*screen).screena[k][i] = 0;


#ifdef COLOR
                                (*screen).screenc[k][i] = color;
#endif /* COLOR */

                            }

                        }

                    }

                    /* clear beginning of screen */
                    if (args[0] != 0) {	
                        
                        for (k = 0; k < ypos[HOME]; k++) {
                        
                            for (i = 0; i < n_columns; i++) {
                        
                                (*screen).screenx[k][i] = SP;
                                (*screen).screena[k][i] = 0;

                    
#ifdef COLOR
                                (*screen).screenc[k][i] = color;
#endif /* COLOR */

                            }

                        }

                    }


#ifdef SCO
                    if (foreground) {

                        if ((*screen).lin24) tmp[tmpx - 1] = CAN;
                        
                        tmp[tmpx] = EOL;
                        m_output (tmp);
                        
                        tmpx = 0;
                        part_ref (screen, 0, n_lines - 1);

                    }                
#endif /* SCO */

                }
            /* end ED */        
            else if (ch == 'p') {	/* private */
                
                if (args[0] == 10) {	
                    
                    /* invert 'inverse' at */
                    /* current cursor pos. */ 
                    
                    (*screen).screena[(unsigned int) (*screen).sclines[ypos[HOME]]][xpos[HOME]] ^= 0100;

#ifdef SCO

                    /* now we're in the meat of the really bizarre SCO UNIX terminal I/O stuff.
                       most of this will need to be reworked. */

                    if (foreground) {
                        
                        k = (*screen).screena[(unsigned int) (*screen).sclines[ypos[HOME]]][xpos[HOME]];
                        
                        if (((*screen).att & 01) != (k & 01)) tmp[tmpx++] = (k & 01) ? SO : SI;
                        
                        k = scosgr (k, (*screen).bw);
                        
                        tmp[tmpx++] = ESC;
                        tmp[tmpx++] = '[';
                        
                        if ((*screen).bw) tmp[tmpx++] = '7';
                        
                        tmp[tmpx++] = 'm';
                        tmp[tmpx++] = ESC;
                        tmp[tmpx++] = '[';
                        
                        if (k & 02) {
                            tmp[tmpx++] = '1';
                            tmp[tmpx++] = ';';
                        }		/* SCO !!! Yeah, SCO. What of it? Such a useful comment... */
                        
                        if (k & 04) {
                            tmp[tmpx++] = '3';
                            tmp[tmpx++] = ';';
                        }

                        if (k & 010) {
                            tmp[tmpx++] = '4';
                            tmp[tmpx++] = ';';
                        }

                        if (k & 020) {
                            tmp[tmpx++] = '5';
                            tmp[tmpx++] = ';';
                        }

                        if (k & 040) {
                            tmp[tmpx++] = '6';
                            tmp[tmpx++] = ';';
                        }

                        if (k & 0100) {
                            tmp[tmpx++] = '7';
                            tmp[tmpx++] = ';';
                        }
                        
                        if (k & 0200) {
                            tmp[tmpx++] = '8';
                            tmp[tmpx++] = ';';
                        }

                        if (tmp[tmpx - 1] == ';') tmpx--;
                        
                        tmp[tmpx++] = 'm';
                        tmp[tmpx++] = (*screen).screenx[(unsigned int) (*screen).sclines[ypos[HOME]]][xpos[HOME]];
                        tmp[tmpx++] = ESC;
                        tmp[tmpx++] = '[';
                        k = ypos[HOME] + 1;
                        
                        if (k > 9) tmp[tmpx++] = k / 10 + '0';
                        
                        tmp[tmpx++] = k % 10 + '0';
                        
                        if (xpos[HOME]) {
                            
                            tmp[tmpx++] = ';';
                            k = xpos[HOME] + 1;
                        
                            if (k > 9) tmp[tmpx++] = k / 10 + '0';
                            
                            tmp[tmpx++] = k % 10 + '0';
                        
                        }
                        
                        tmp[tmpx++] = 'H';
                        
                        if (k != screen->att) {
                            
                            k = scosgr ((*screen).att, (*screen).bw);
                            
                            tmp[tmpx++] = (k & 01) ? SO : SI;
                            tmp[tmpx++] = ESC;
                            tmp[tmpx++] = '[';
                            tmp[tmpx++] = '0';
                            
                            if (k & 02) {
                                tmp[tmpx++] = ';';
                                tmp[tmpx++] = '1';
                            }		/* SCO !!! Again... what about it? */
                            
                            if (k & 04) {
                                tmp[tmpx++] = ';';
                                tmp[tmpx++] = '3';
                            }

                            if (k & 010) {
                                tmp[tmpx++] = ';';
                                tmp[tmpx++] = '4';
                            }

                            if (k & 020) {
                                tmp[tmpx++] = ';';
                                tmp[tmpx++] = '5';
                            }

                            if (k & 040) {
                                tmp[tmpx++] = ';';
                                tmp[tmpx++] = '6';
                            }

                            if (k & 0100) {
                                tmp[tmpx++] = ';';
                                tmp[tmpx++] = '7';
                            }

                            if (k & 0200) {
                                tmp[tmpx++] = ';';
                                tmp[tmpx++] = '8';
                            }
                            
                            tmp[tmpx++] = 'm';
                        
                        }
                    
                    }
#endif /* SCO */

                }
            } 
            else if (ch == 'r') {	/* TBM Top_Bottom Margin */

                register int k;

                if (noargs || ((*screen).sc_up = (--args[0])) <= 0) (*screen).sc_up = 0;
                
                /* TODO: Revisit. This still appears to be hardcoded to the old fixed terminal size.
                 *       Ref issue #95
                 */
                if (!argcnt || (((*screen).sc_lo = (--args[1])) > 24) || ((*screen).sc_lo == 23 && (*screen).lin24 == TRUE)) {
                    (*screen).sc_lo = (*screen).lin24 ? 23 : 24;
                }
                
                /* restore old cursor position */
                tmp[tmpx++] = ESC;
                tmp[tmpx++] = '[';
                k = ypos[HOME] + 1;

                if (k > 9) tmp[tmpx++] = k / 10 + '0';
                
                tmp[tmpx++] = k % 10 + '0';
                
                if (xpos[HOME]) {

                    tmp[tmpx++] = ';';
                    k = xpos[HOME] + 1;
                    
                    if (k > 9) tmp[tmpx++] = k / 10 + '0';
                    
                    tmp[tmpx++] = k % 10 + '0';
                
                }
                
                tmp[tmpx++] = 'H';

            } 
            else if (ch == 's') {	/* CS Cursor Save */

                (*screen).csx[(*screen).cs] = xpos[HOME];
                (*screen).csy[(*screen).cs] = ypos[HOME];
                (*screen).cssgr[(*screen).cs] = (*screen).att;
        

#ifdef COLOR
                (*screen).cscol[(*screen).cs] = (*screen).col;
#endif /* COLOR */

                if (++((*screen).cs) >= CSLEN) (*screen).cs = CSLEN - 1;

            } 
            else if (ch == 'u') {	

                /* CRST Cursor Unsave (if no args) */
                /* those bloody bastards made 'CSI u' and CSI 0 u' */
                /* different. flag 'noargs' distinguishes          */

                /* bloody bastards, eh? this whole module is a bloody bastard,
                 * so I seriously have no idea what the hell you're complaining
                 * about, Mr. ha-Ashkenaz.
                 */

                if (noargs) {


#ifdef COLOR
                int     color;
#endif /* COLOR */

                if (--((*screen).cs) <= 0) (*screen).cs = 0;
                
                xpos[HOME] = (*screen).csx[(*screen).cs];
                ypos[HOME] = (*screen).csy[(*screen).cs];
                
                (*screen).att = (*screen).cssgr[(*screen).cs];
                

#ifdef COLOR
                (*screen).col = (*screen).cscol[(*screen).cs];
                color = (*screen).col;
#endif /* COLOR */

                /* make sure cursor is at desired position */
                tmp[tmpx++] = ESC;
                tmp[tmpx++] = '[';

                if (ypos[HOME] > 8) tmp[tmpx++] = (1 + ypos[HOME]) / 10 + '0';
                
                tmp[tmpx++] = (1 + ypos[HOME]) % 10 + '0';
                
                if (xpos[HOME] > 0) { 

                    tmp[tmpx++] = ';';
                
                    if (xpos[HOME] > 8) tmp[tmpx++] = (1 + xpos[HOME]) / 10 + '0';

                    tmp[tmpx++] = (1 + xpos[HOME]) % 10 + '0';

                }

                tmp[tmpx++] = 'H';
                

#ifdef COLOR
            
                /* make sure cursor has right color */
                tmp[tmpx++] = ESC;	/* background color */
                tmp[tmpx++] = '[';
                tmp[tmpx++] = '=';
                
                if (color / 16 > 9) tmp[tmpx++] = '0' + (color / 16 / 10);
                
                tmp[tmpx++] = '0' + (color / 16 % 10);
                tmp[tmpx++] = 'G';
                tmp[tmpx++] = ESC;	/* reverse foreground col */
                tmp[tmpx++] = '[';
                tmp[tmpx++] = '=';
                
                if (color / 16 > 9) tmp[tmpx++] = '0' + (color / 16 / 10);
                
                tmp[tmpx++] = '0' + (color / 16 % 10);
                tmp[tmpx++] = 'H';
                tmp[tmpx++] = ESC;	/* foreground color */
                tmp[tmpx++] = '[';
                tmp[tmpx++] = '=';
                
                if (color % 16 > 9) tmp[tmpx++] = '0' + (color % 16 / 10);
                
                tmp[tmpx++] = '0' + (color % 16 % 10);
                tmp[tmpx++] = 'F';
                tmp[tmpx++] = ESC;	/* reverse background col */
                tmp[tmpx++] = '[';
                tmp[tmpx++] = '=';
                
                if (color % 16 > 9) tmp[tmpx++] = '0' + (color % 16 / 10);

                tmp[tmpx++] = '0' + (color % 16 % 10);
                tmp[tmpx++] = 'I';
#endif /* COLOR */

                } 
                else if (args[0] == 0) {

                    (*screen).lin24 = FALSE;
                    
                    if ((*screen).sc_lo == 23) (*screen).sc_lo = 24;

                } 
                else if (args[0] == 1) {
                
                    (*screen).lin24 = TRUE;
                    
                    if ((*screen).sc_lo == 24) (*screen).sc_lo = 23;

                } 
                else if (args[0] == 8) {
                    (*screen).rollflag = FALSE;
                }
                else if (args[0] == 9) {
                    (*screen).rollflag = TRUE;
                }            
#ifdef SCO
                else if (args[0] == 20) {

                    (*screen).bw = FALSE;
                    
                    if (foreground) {
                        
                        tmp[tmpx] = EOL;                    
                        m_output (tmp);
                    
                        tmpx = 0;                
                        part_ref (screen, 0, n_lines - 1);
                    
                    }

                } 
                else if (args[0] == 21) {
                    
                    (*screen).bw = TRUE;
                    
                    if (foreground) {
                    
                        tmp[tmpx] = EOL;
                        m_output (tmp);

                        tmpx = 0;
                        part_ref (screen, 0, n_lines - 1);

                    }

                }
#endif /* SCO */

            } 
            else if (ch == 'X') {	/* ECH Erase Character */

                if ((k = args[0]) < 1) k = 1;
                if ((k + xpos[HOME]) > n_columns) k = n_columns - xpos[HOME];

                i = xpos[HOME];
                k = i + k;
                
                while (i < k) {

                    (*screen).screenx[(unsigned int) (*screen).sclines[ypos[HOME]]][i] = SP;
                    (*screen).screena[(unsigned int) (*screen).sclines[ypos[HOME]]][i] = 0;	/* not 'att' */


#ifdef COLOR
                    (*screen).screenc[(unsigned int) (*screen).sclines[ypos[HOME]]][i] = (*screen).col;
#endif /* COLOR */

                    i++;
    
                }
    
            } else if (ch == 'g') {	/* TBC Tabulation clear */

                if (args[0] == 3) {	
                    /* clear all */
                    for (i = 0; i < n_columns; (*screen).tabs[i++] = 0) ;
                } 
                else if (args[0] == 0) {	
                    /* clear one */
                    (*screen).tabs[xpos[HOME]] = 0;
                }
            

#ifdef SCO
                while (tmpx >= 0) if (tmp[--tmpx] == ESC) break;
                
                tmp[tmpx] = NUL;
                ch = NUL;            
#endif /* SCO */

            } 
            else if (ch == 'm') {	/* SGR Select Graphic Rendition */
            
                (*screen).att &= 01;	/* clear att */
            

#ifdef SCO
                while (tmpx > 0 && tmp[--tmpx] != ESC);

                ch = CAN;
#endif /* SCO */

                i = argcnt;

                while (i >= 0) {

                    if (((*screen).savarg = (args[i] == 50))) continue;


#ifdef SCO			/* process save SGR(1) in position of SGR(2) */
                    if (args[i] == 1) args[i] = 2;
#endif /* SCO */

#ifdef COLOR
                    if (args[i] > 29 && args[i] < 38) {		/* foregr.color */
                        (*screen).col = ((*screen).col & ~017) | coltrans[args[i] - 30];
                    }

                    if (args[i] > 39 && args[i] < 48) {		/* backgr.color */
                        (*screen).col = (((*screen).col & 017) | (coltrans[args[i] - 40] * 16));
                    }

#endif /* COLOR */
                
                    if (args[i] > 1 && args[i] < 9) (*screen).att |= (1 << (args[i] - 1));
                    if (args[i] == 0) (*screen).att &= 01;	/* clear att */
                    
                    i--;

                }

#ifdef SCO
                tmp[tmpx++] = ESC;
                tmp[tmpx++] = '[';
                if ((*screen).bw) tmp[tmpx++] = '7';

                tmp[tmpx++] = 'm';


#ifdef COLOR
                tmp[tmpx++] = ESC;
                tmp[tmpx++] = '[';
                tmp[tmpx++] = '=';
                if ((*screen).col / 16 > 9) tmp[tmpx++] = '0' + ((*screen).col / 16 / 10);

                tmp[tmpx++] = '0' + ((*screen).col / 16 % 10);
                tmp[tmpx++] = 'G';
                tmp[tmpx++] = ESC;
                tmp[tmpx++] = '[';
                tmp[tmpx++] = '=';
                if ((*screen).col / 16 > 9) tmp[tmpx++] = '0' + ((*screen).col / 16 / 10);
                
                tmp[tmpx++] = '0' + ((*screen).col / 16 % 10);
                tmp[tmpx++] = 'H';
                tmp[tmpx++] = ESC;
                tmp[tmpx++] = '[';
                tmp[tmpx++] = '=';
                if ((*screen).col % 16 > 9) tmp[tmpx++] = '0' + ((*screen).col % 16 / 10);
                
                tmp[tmpx++] = '0' + ((*screen).col % 16 % 10);
                tmp[tmpx++] = 'F';
                tmp[tmpx++] = ESC;
                tmp[tmpx++] = '[';
                tmp[tmpx++] = '=';
                if ((*screen).col % 16 > 9) tmp[tmpx++] = '0' + ((*screen).col % 16 / 10);
                
                tmp[tmpx++] = '0' + ((*screen).col % 16 % 10);
                tmp[tmpx++] = 'I';
#endif /* COLOR */

                if ((*screen).att & ~01) {

                    int j;

                    j = scosgr ((*screen).att & ~01, (*screen).bw);
                    
                    tmp[tmpx++] = ESC;
                    tmp[tmpx++] = '[';
                    
                    if (j & 02) {
                        tmp[tmpx++] = '1';
                        tmp[tmpx++] = ';';
                    }

                    if (j & 04) {
                        tmp[tmpx++] = '3';
                        tmp[tmpx++] = ';';
                    }

                    if (j & 010) {
                        tmp[tmpx++] = '4';
                        tmp[tmpx++] = ';';
                    }

                    if (j & 020) {
                        tmp[tmpx++] = '5';
                        tmp[tmpx++] = ';';
                    }

                    if (j & 040) {
                        tmp[tmpx++] = '6';
                        tmp[tmpx++] = ';';
                    }
            
                    if (j & 0100) {
                        tmp[tmpx++] = '7';
                        tmp[tmpx++] = ';';
                    }

                    if (j & 0200) {
                        tmp[tmpx++] = '8';
                        tmp[tmpx++] = ';';
                    }

                    if (tmp[tmpx - 1] == ';') tmpx--;

                    tmp[tmpx++] = 'm';

                }
#endif /* SCO */

            } 
            else if (ch == 'P') {	/* DCH Delete Character */
                int j;

                if ((j = args[0]) == 0) j = 1;
                
                k = (*screen).sclines[ypos[HOME]];
                
                for (i = xpos[HOME]; i < (n_columns - j); i++) {

                    (*screen).screenx[k][i] = (*screen).screenx[k][i + j];
                    (*screen).screena[k][i] = (*screen).screena[k][i + j];
            

#ifdef COLOR
                    (*screen).screenc[k][i] = (*screen).screenc[k][i + j];
#endif /* COLOR */

                }

                for (; i < n_columns; i++) {

                    (*screen).screenx[k][i] = SP;
                    (*screen).screena[k][i] = (*screen).att;
            

#ifdef COLOR
                    (*screen).screenc[k][i] = (*screen).col;
#endif /* COLOR */

                }


            } else if (ch == '@') {	/* ICH Insert Character */
                int j;

                if ((j = args[0]) == 0) j = 1;
                
                k = (*screen).sclines[ypos[HOME]];
                
                for (i = (n_columns - 1); i >= (xpos[HOME] + j); i--) {
                
                    (*screen).screenx[k][i] = (*screen).screenx[k][i - j];
                    (*screen).screena[k][i] = (*screen).screena[k][i - j];
            

#ifdef COLOR
                    (*screen).screenc[k][i] = (*screen).screenc[k][i - j];
#endif /* COLOR */

                }

                for (; i >= xpos[HOME]; i--) {

                    (*screen).screenx[k][i] = SP;
                    (*screen).screena[k][i] = (*screen).att;
                

#ifdef COLOR
                    (*screen).screenc[k][i] = (*screen).col;
#endif /* COLOR */

                }

            } else if (ch == 'M') {	/* DL Delete Line */
                int j = args[0];

                do {

                    k = (*screen).sclines[ypos[HOME]];
                    
                    for (i = ypos[HOME]; i < (*screen).sc_lo; i++) (*screen).sclines[i] = (*screen).sclines[i + 1];
                    
                    (*screen).sclines[i] = k;
                    
                    for (i = 0; i < n_columns; i++) {
                        
                        (*screen).screenx[k][i] = SP;
                        (*screen).screena[k][i] = (*screen).att;


#ifdef COLOR
                        (*screen).screenc[k][i] = (*screen).col;
#endif /* COLOR */

                    }

                } while (--j > 0);

                xpos[HOME] = 0;
            

#ifdef SCO
                if (foreground) {

                    tmp[tmpx - 1] = CAN;	/* do not send DL */
                    tmp[tmpx] = EOL;                
                    m_output (tmp);

                    tmpx = 0;
                    part_ref (screen, (*screen).sc_up, n_lines - 1);

                }

#endif /* SCO */

            } 
            else if (ch == 'L') {	/* IL Insert Line */
                int     j = args[0];

                do {
                    k = (*screen).sclines[(*screen).sc_lo];
                    
                    for (i = (*screen).sc_lo; i > ypos[HOME]; i--) {
                        (*screen).sclines[i] = (*screen).sclines[i - 1];
                    }
                    
                    (*screen).sclines[ypos[HOME]] = k;
                    
                    for (i = 0; i < n_columns; i++) {

                        (*screen).screenx[k][i] = SP;
                        (*screen).screena[k][i] = (*screen).att;
                    

#ifdef COLOR
                        (*screen).screenc[k][i] = (*screen).col;
#endif /* COLOR */

                    }
                } while (--j > 0);
                
                xpos[HOME] = 0;


#ifdef SCO
                if (foreground) {

                    tmp[tmpx - 1] = CAN;	/* do not send IL */
                    tmp[tmpx] = EOL;
                    m_output (tmp);
                    
                    tmpx = 0;
                    part_ref (screen, (*screen).sc_up, n_lines - 1);

                }
#endif /* SCO */

            } 
            else if (ch == 'S') {	/* SU Scroll up   */
            int j = args[0];

            do {

                k = (*screen).sclines[(*screen).sc_up];
                
                for (i = (*screen).sc_up; i < (*screen).sc_lo; i++) {
                    (*screen).sclines[i] = (*screen).sclines[i + 1];
                }
                
                (*screen).sclines[i] = k;
                
                for (i = 0; i < n_columns; i++) {
                    
                    (*screen).screenx[k][i] = SP;
                    (*screen).screena[k][i] = (*screen).att;


#ifdef COLOR
                    (*screen).screenc[k][i] = (*screen).col;
#endif /* COLOR */

                }

            } while (--j > 0);


#ifdef SCO
            if (foreground) {

                tmp[tmpx - 1] = 'A';	/* do not send SU */
                tmp[tmpx] = EOL;
                m_output (tmp);
                
                tmpx = 0;
                part_ref (screen, (*screen).sc_up, n_lines - 1);

            }
#endif /* SCO */
        
            } 
            else if (ch == 'T') {	/* SD Scroll down */
                
                int j = args[0];

                do {

                    k = (*screen).sclines[(*screen).sc_lo];
                    
                    for (i = (*screen).sc_lo; i > (*screen).sc_up; i--) {
                        (*screen).sclines[i] = (*screen).sclines[i - 1];
                    }
                    
                    (*screen).sclines[i] = k;

                    for (i = 0; i < n_columns; i++) {
                        
                        (*screen).screenx[k][i] = SP;
                        (*screen).screena[k][i] = (*screen).att;


#ifdef COLOR
                        (*screen).screenc[k][i] = (*screen).col;
#endif /* COLOR */

                    }

                } while (--j > 0);

            
#ifdef SCO

                if (foreground) {

                    tmp[tmpx - 1] = 'A';	/* do not send SD */
                    tmp[tmpx] = EOL;
                    m_output (tmp);
                    
                    tmpx = 0;
                    part_ref (screen, (*screen).sc_up, n_lines - 1);

                }

#endif /* SCO */
        
            } else if (ch == 'Z') {	/* CBT Cursor backward tab */

                if ((i = xpos[HOME] - 1) < 1) i = 1;

                do {
                    
                    while ((*screen).tabs[--i] == 0) {

                        if (i < 0) {
                            i++;
                            break;
                        }

                    }

                    if (i == 0) break;

                } while (args[0]-- > 0);
                
                xpos[HOME] = i;


#ifdef PROC_TAB
                tmp[tmpx++] = CR;
                
                if ((xpos[HOME] = i) != 0) {
                
                    tmp[tmpx++] = ESC;
                    tmp[tmpx++] = '[';
                
                    if (i > 9) tmp[tmpx++] = i / 10 + '0';
                
                    tmp[tmpx++] = i % 10 + '0';
                    tmp[tmpx++] = 'C';

                }

#endif /* PROC_TAB */

            }

            if (ch != '~') goto zasend;
            
            /* ZAS Alternate Screen stuff */
            /* the following is better programmed with     */
            /* 'switch' but some compilers do not have     */
            /* enough power to swallow the implied stack   */
            /* depth                                       */
            /* switch (args[0]) */
            
            i = args[0];
            
            if (i == 1) goto zas1;
            if (i == 2) goto zas2;
            if (i == 3) goto zas3;
            if (i == 4) goto zas4;
            if (i == 5) goto zas5;
            if (i != 0) goto zas6;

            /* zas0: exchange foreground/background */
            tmp[tmpx] = EOL;
            tmpx = 0;
            
            if (foreground) m_output (tmp);
            
            /* exchange parameters of screen */
            (*screen).Xpos = xpos[HOME];
            (*screen).Ypos = ypos[HOME];
            
            vts = screen;
            screen = altscr;
            altscr = vts;
            
            xpos[HOME] = (*screen).Xpos;
            ypos[HOME] = (*screen).Ypos;


zas4:			/* refresh foreground */

            tmpx = 0;
            
            if (foreground) part_ref (screen, 0, n_lines - 1);
            
            goto zasend;
        

zas1:			/* foreground screen */

            if (foreground) goto zasend;

            foreground = TRUE;
        
        
pPRIVATE:       /* exchange parameters of screen */

            (*screen).Xpos = xpos[HOME];
            (*screen).Ypos = ypos[HOME];
            
            vts = screen;
            screen = altscr;
            altscr = vts;
            
            xpos[HOME] = (*screen).Xpos;
            ypos[HOME] = (*screen).Ypos;
            
            tmpx = 0;
            
            goto zasend;
        

zas2:			/* background screen */

            if (foreground == FALSE) goto zasend;
            
            tmp[tmpx] = EOL;
            m_output (tmp);
            
            foreground = FALSE;
            
            goto pPRIVATE;
            

zas3:			/* save foreground to back */
        
            stcpy0 ((char *) altscr, (const char *) screen, sizeof (struct vtstyp));

            goto zasend;
        

zas5:			/* push screen */

            if (zaslevel >= MAXZAS) goto zasend;
            
            vts = (struct vtstyp *) calloc (1, sizeof (struct vtstyp));
            zases[zaslevel++] = vts;

            (*screen).Xpos = xpos[HOME];
            (*screen).Ypos = ypos[HOME];
            
            stcpy0 ((char *) vts, (const char *) screen, sizeof (struct vtstyp));

            goto zasend;


zas6:			/* pop  screen */
        
            if (--zaslevel < 0) {
                zaslevel = 0;
                goto zasend;
            }

            vts = zases[zaslevel];
        

#ifdef SCO
            i = (*screen).bw;		/* do not pop bw state */
#endif /* SCO */

            stcpy0 ((char *) screen, (const char *) vts, sizeof (struct vtstyp));


#ifdef SCO
            (*screen).bw = i;
#endif /* SCO */

            xpos[HOME] = (*screen).Xpos;
            ypos[HOME] = (*screen).Ypos;

            free (vts);

            goto zas4;
            /* end zas6 */


zasend:         /* stuf we do when we're finished doing other zassy things */
        
            argcnt = 0;
            noargs = TRUE;
            esc = 0;
            
            continue;

        }				/* end 'printable' characters */
    
        if ((esc = (ch == ESC))) {

            for (ch = 0; ch < ARGS_IN_ESC; args[ch++] = 0);

            argcnt = 0;
            noargs = TRUE;

            continue;

        }

        if (ch == LF) {
    

pLF:

            if ((ypos[HOME] <= (*screen).sc_up) || (ypos[HOME] > (*screen).sc_lo)) {

                if (++ypos[HOME] >= (n_lines - 1)) {
                    ypos[HOME] = (n_lines - 1);
                }

                if (ch == LF) tmpx--;
                
                tmp[tmpx++] = ESC;
                tmp[tmpx++] = '[';
                
                if (ypos[HOME] > 8) tmp[tmpx++] = (1 + ypos[HOME]) / 10 + '0';
                
                tmp[tmpx++] = (1 + ypos[HOME]) % 10 + '0';
                
                if (xpos[HOME] > 0) { 

                    tmp[tmpx++] = ';';
                
                    if (xpos[HOME] > 8) tmp[tmpx++] = (1 + xpos[HOME]) / 10 + '0';

                    tmp[tmpx++] = (1 + xpos[HOME]) % 10 + '0';

                }

                tmp[tmpx++] = 'H';

            }    
            else if (ypos[HOME] < (*screen).sc_lo) {
                
                /* within scroll area */
                if (++ypos[HOME] >= (n_lines - 1)) {
                    ypos[HOME] = (n_lines - 1);
                }

            }
            else {
                
                /* lower margin of scroll area: scroll up */
                xpos[HOME] = 0;


#ifdef SCO
                if ((ch != LF) && (!(*screen).lin24) && (ypos[HOME] == (*screen).sc_lo) && (ypos[HOME] == n_lines - 1)) {
                    continue;
                }
#endif /* SCO */

                /* TODO: find out what 'rollflag' is */
                /*                        if ((*screen).rollflag==FALSE) continue; */
                k = (*screen).sclines[(*screen).sc_up];

                for (i = (*screen).sc_up; i < (*screen).sc_lo; i++) {
                    (*screen).sclines[i] = (*screen).sclines[i + 1];
                }

                (*screen).sclines[(*screen).sc_lo] = k;
                
                for (i = 0; i < n_columns; i++) {

                    (*screen).screenx[k][i] = SP;
                    (*screen).screena[k][i] = (*screen).att;
            
#ifdef COLOR
                    (*screen).screenc[k][i] = (*screen).col;
#endif /* COLOR */

                }


#ifdef SCO
                tmp[tmpx] = EOL;
                tmpx = 0;
                
                if (foreground) {
                    m_output (tmp);
                    part_ref (screen, (*screen).sc_up, (*screen).sc_lo);
            }
#endif /* SCO */

            }

            continue;

        } /* if (ch == LF) */

        if (ch == CR) {
            xpos[HOME] = 0;
            continue;
        }

        if (ch == BS) {
            
            if (--xpos[HOME] < 0) xpos[HOME] = 0;

            continue;

        }

        /* FORM FEED: clear screen */
        if (ch == FF) {

            xpos[HOME] = 0;
            ypos[HOME] = 0;
            
            ch = 'J';
            
            tmp[tmpx - 1] = ESC;
            tmp[tmpx++] = '[';
            tmp[tmpx++] = 'H';
            tmp[tmpx++] = ESC;
            tmp[tmpx++] = '[';
            tmp[tmpx++] = ch;
            
            args[0] = 0;
            noargs = TRUE;
            argcnt = 0;
            
            goto ED;

        }

        if (ch == TAB) {

            k = xpos[HOME];
            
            if ((i = k + 1) >= n_columns) i = (n_columns - 1);
            
            while ((*screen).tabs[i] == 0) {

                if (i >= n_columns) {
                    i = (n_columns - 1);
                    break;
                }
                
                i++;

            }


#ifdef PROC_TAB
            if (i != k) {
                
                tmp[tmpx++] = CR;
            
                if ((xpos[HOME] = i) != 0) {
            
                    tmp[tmpx++] = ESC;
                    tmp[tmpx++] = '[';
            
                    if (i > 9) tmp[tmpx++] = i / 10 + '0';
            
                    tmp[tmpx++] = i % 10 + '0';
                    tmp[tmpx++] = 'C';
            
                }
            
            }
#endif /* PROC_TAB */

            continue;
        }
        
        /* SI Shift In */
        if (ch == SI) (*screen).att &= ~01;	/* clear SO-Bit */
        
        /* SO Shift Out */
        if (ch == SO) (*screen).att |= 01;	/* set SO-Bit */

        if (ch == CAN) {		/* CANcel ESC_esquence */
            esc = argcnt = noargs = 0;
            continue;
        }

    }					/* end while */
        
    tmp[tmpx] = EOL;
    
    if (foreground) m_output (tmp);

    return;

}					/* end writeHOME() */


#ifdef SCO

/*att screen attributes byte */
/*bwflag black_on_white flag */
int scosgr (short att, short bwflag)	
{
    
    att = att & ~044;			/* suppress SGR(3) and SGR(6) */
    
    if (att & 0200) return att & 0201;		/* no display */
    if (bwflag) att ^= 0100;			/* toggle inverse */
    if (att & 0100) return att & 0121;		/* inverse, evtl. incl. blink */
    if (att & 032) return att & 033;		/* other valid combinations */
    
    return att;

}					/* end scosgr() */

#endif /* SCO */

/* init Screen params */    
void ris (struct vtstyp *scr)				
{
    short i;
    short l;

    scr->att = 0;

#ifdef COLOR
    scr->col = 7;			/* default color is white on black */
#endif /* COLOR */

    scr->Xpos = 0;
    scr->Ypos = 0;

    for (i = 0; i < CSLEN; i++) {
        scr->csx[i] = 0;
        scr->csy[i] = 0;
    }

    scr->cs = 0;
    scr->sc_up = 0;
    scr->sc_lo = n_lines;
    
    for (i = 0; i <= n_lines; i++) {
        
        scr->sclines[i] = i;
        
        for (l = 0; l < n_columns; l++) {
    
            scr->screenx[i][l] = SP;
            scr->screena[i][l] = 0;

    
#ifdef COLOR
            scr->screenc[i][l] = 7;	/* default color is white on black */
#endif /* COLOR */

        }
    
    }

    /* TABS */
    for (i = 0; i <= n_columns; i++) scr->tabs[i] = 0;    
    for (i = 7; i <= n_columns; i += 8) scr->tabs[i] = 1;

    scr->rollflag = TRUE;		/* Roll or Page mode */
    scr->lin24 = FALSE;			/* 24 lines or 25 lines mode (MUST BE FALSE!!!!) */
    scr->savarg = FALSE;
    
    for (i = 0; i < CSLEN; i++) scr->cssgr[i] = FALSE;		/* save SGR flag */

    return;

}					/* end ris() */

/* refresh (foreground) screen partially */
void part_ref (struct vtstyp *scr, short from, short to)		
{
    short k;
    short l;
    short max;
    unsigned char exa;
    unsigned char exc;
    short i;
    unsigned char *linea;
    unsigned char *linex;
    unsigned char *linec;
    unsigned char ch;
    unsigned char tmp[1300];

    /* build up alternate screen */
    /* reset SGR,TBM;white on black,go HOME; 25 Lines */
    stcpy (tmp, "\017\033[m\033[37;40m\033[r\033[H\033[0u\201");    
    m_output (tmp);


#ifndef PROC_TAB
    
    k = 0;
    i = 0;				/* set TABs */
    
    tmp[k++] = ESC;
    tmp[k++] = '[';

    if (from > 8) tmp[k++] = '0' + (from + 1) / 10;
    
    tmp[k++] = '0' + (from + 1) % 10;
    tmp[k++] = 'H';
    
    for (l = 0; l < n_columns; l++) {

        tmp[k++] = SP;
        
        if ((*scr).tabs[l]) {
            
            tmp[k++] = ESC;
            tmp[k++] = 'H';
            
            i = k;

        }

    }

    tmp[i++] = CR;
    tmp[i] = EOL;
    m_output (tmp);
    
#endif /* PROC_TAB */

    k = 0;

    for (i = from; i <= to; i++) {

        tmp[k++] = ESC;			/* CUP(i) */
        tmp[k++] = '[';

        if (i > 8) tmp[k++] = (i + 1) / 10 + '0';
        if (i > 0) tmp[k++] = (i + 1) % 10 + '0';
        
        tmp[k++] = 'H';

        linex = (*scr).screenx[(unsigned int) (*scr).sclines[i]];
        linea = (*scr).screena[(unsigned int) (*scr).sclines[i]];
        
#ifdef COLOR
        linec = (*scr).screenc[(unsigned int) (*scr).sclines[i]];
#endif /* COLOR */

        for (max = n_columns - 1; max > 0; max--) {

            if (linex[max] != SP) break;
            if (linea[max] != linea[max - 1]) break;
            if (linec[max] != linec[max - 1]) break;

        }

        exa = ~linea[0];		/* dummy value to trigger argument codes on 1st char */
        exc = ~linec[0];		/* dummy value to trigger argument codes on 1st char */
        
        for (l = 0; l <= max; l++) {
            
            if (l == (n_columns - 1) && (i == (n_lines))) continue;
            
#ifndef LINUX
#ifdef COLOR
            if (exc != linec[l]) {	/* set color */

                if ((exc / 16) != (linec[l] / 16)) {	/* background color */

                    tmp[k++] = ESC;
                    tmp[k++] = '[';
                    tmp[k++] = '=';
                    tmp[k++] = '0';
            
                    if (linec[l] / 16 > 9) tmp[k++] = '0' + linec[l] / 16 / 10;

                    tmp[k++] = '0' + linec[l] / 16 % 10;
                    tmp[k++] = 'G';
                    tmp[k++] = ESC;	/* background == reverse foreground */
                    tmp[k++] = '[';
                    tmp[k++] = '=';
                    tmp[k++] = '0';
                    
                    if (linec[l] / 16 > 9) tmp[k++] = '0' + linec[l] / 16 / 10;
                    
                    tmp[k++] = '0' + linec[l] / 16 % 10;
                    tmp[k++] = 'H';

                }

                if ((exc % 16) != (linec[l] % 16)) {	/* foreground color */

                    tmp[k++] = ESC;
                    tmp[k++] = '[';
                    tmp[k++] = '=';
                    tmp[k++] = '0';

                    if (linec[l] % 16 > 9) tmp[k++] = '0' + linec[l] % 16 / 10;
                    
                    tmp[k++] = '0' + linec[l] % 16 % 10;
                    tmp[k++] = 'F';
                    tmp[k++] = ESC;	/* foreground == reverse background */
                    tmp[k++] = '[';
                    tmp[k++] = '=';
                    tmp[k++] = '0';
                    
                    if (linec[l] % 16 > 9) tmp[k++] = '0' + linec[l] % 16 / 10;

                    tmp[k++] = '0' + linec[l] % 16 % 10;
                    tmp[k++] = 'I';

                }

                exc = linec[l];

            }

#endif /* COLOR */
#endif /* LINUX */

            if (exa != linea[l]) {	/* set attribute */
                
                short p;
                short xatt;

                p = exa;
                exa = linea[l];
                
                if ((p & 01) != (exa & 01)) tmp[k++] = (exa & 01) ? SO : SI;
                
                if ((p & ~01) != (exa & ~01)) {

                    xatt = exa;
                    

#ifdef SCO
                    xatt = scosgr (xatt, (*scr).bw);
#endif /* SCO */

                    tmp[k++] = ESC;
                    tmp[k++] = '[';


#ifdef SCO
                    if ((*scr).bw) tmp[k++] = '7';
#endif /* SCO */

                    tmp[k++] = 'm';
                    tmp[k++] = ESC;
                    tmp[k++] = '[';

                    if (xatt & 02) {


#ifdef SCO
                        tmp[k++] = '1';
#else
                        tmp[k++] = '2';
#endif /* SCO */

                        tmp[k++] = ';';
                    }

                    if (xatt & 04) {
                        tmp[k++] = '3';
                        tmp[k++] = ';';
                    }

                    if (xatt & 010) {
                        tmp[k++] = '4';
                        tmp[k++] = ';';
                    }
                    
                    if (xatt & 020) {
                        tmp[k++] = '5';
                        tmp[k++] = ';';
                    }
                    
                    if (xatt & 040) {
                        tmp[k++] = '6';
                        tmp[k++] = ';';
                    }

                    if (xatt & 0100) {
                        tmp[k++] = '7';
                        tmp[k++] = ';';
                    }

                    if (xatt & 0200) {
                        tmp[k++] = '8';
                        tmp[k++] = ';';
                    }

                    if (tmp[k - 1] == ';') k--;
                    
                    tmp[k++] = 'm';
                
                }

            }

            tmp[k++] = linex[l];

        }

        if (max + 1 < n_columns) {
            tmp[k++] = ESC;
            tmp[k++] = '[';
            tmp[k++] = 'K';
        }

        tmp[k] = EOL;
        k = mcmnd;
        mcmnd = 'w';
        ch = (*codptr);
        *codptr = ',';
        
        m_output (tmp);
        
        *codptr = ch;
        mcmnd = k;
        
        k = 0;

    }

    /* 'saved' cursor position */
    /* actual cursor position & actual attribute */
    /* 'flush' output */
    k = 0;


#ifndef SCO
    
    tmp[k++] = ESC;			/* restore CursorSave Position */
    tmp[k++] = '[';
    i = (*scr).csy[(*scr).cs] + 1;
    
    if (i > 9) tmp[k++] = '0' + i / 10;
    
    tmp[k++] = '0' + i % 10;
    tmp[k++] = ';';
    
    i = (*scr).csx[(*scr).cs] + 1;
    
    if (i > 9) tmp[k++] = '0' + i / 10;
    
    tmp[k++] = '0' + i % 10;
    tmp[k++] = 'H';
    tmp[k++] = ESC;			/* DEC Cursor SAVE */
    tmp[k++] = '7';
    tmp[k++] = ESC;			/* ANSI (?) Cursor SAVE */
    tmp[k++] = '[';
    tmp[k++] = 's';
    tmp[k++] = ESC;			/* restore 24/25 line mode */
    tmp[k++] = '[';
    tmp[k++] = '0' + (*scr).lin24;
    tmp[k++] = 'u';
    tmp[k++] = ESC;			/* restore Scroll area */
    tmp[k++] = '[';
    
    if (((*scr).sc_up) > 8) tmp[k++] = '0' + ((*scr).sc_up + 1) / 10;
    
    tmp[k++] = '0' + ((*scr).sc_up + 1) % 10;
    tmp[k++] = ';';
    
    if (((*scr).sc_lo) > 8) tmp[k++] = '0' + ((*scr).sc_lo + 1) / 10;
    
    tmp[k++] = '0' + ((*scr).sc_lo + 1) % 10;
    tmp[k++] = 'r';

#endif /* not SCO */

#ifndef LINUX
#ifdef COLOR

    tmp[k++] = ESC;			/* restore foreground color */
    tmp[k++] = '[';
    tmp[k++] = '=';
    
    if (((*scr).col) % 16 > 9) tmp[k++] = '0' + ((*scr).col) % 16 / 10;
    
    tmp[k++] = '0' + ((*scr).col) % 16 % 10;
    tmp[k++] = 'F';
    tmp[k++] = ESC;			/* restore reverse background color */
    tmp[k++] = '[';
    tmp[k++] = '=';
    
    if (((*scr).col) % 16 > 9) tmp[k++] = '0' + ((*scr).col) % 16 / 10;
    
    tmp[k++] = '0' + ((*scr).col) % 16 % 10;
    tmp[k++] = 'I';
    tmp[k++] = ESC;			/* restore background color */
    tmp[k++] = '[';
    tmp[k++] = '=';
    
    if (((*scr).col) / 16 > 9) tmp[k++] = '0' + ((*scr).col) / 16 / 10;
    
    tmp[k++] = '0' + ((*scr).col) / 16 % 10;
    tmp[k++] = 'G';
    tmp[k++] = ESC;			/* restore reverse foreground color */
    tmp[k++] = '[';
    tmp[k++] = '=';
    
    if (((*scr).col) / 16 > 9) tmp[k++] = '0' + ((*scr).col) / 16 / 10;
    
    tmp[k++] = '0' + ((*scr).col) / 16 % 10;
    tmp[k++] = 'H';

#endif /* COLOR */
#endif /* LINUX */

    tmp[k++] = ESC;			/* restore CursorPosition */
    tmp[k++] = '[';

    if (ypos[HOME] > 8) tmp[k++] = '0' + (ypos[HOME] + 1) / 10;
    
    tmp[k++] = '0' + (ypos[HOME] + 1) % 10;
    tmp[k++] = ';';
    
    if (xpos[HOME] > 8) tmp[k++] = '0' + (xpos[HOME] + 1) / 10;
    
    tmp[k++] = '0' + (xpos[HOME] + 1) % 10;
    tmp[k++] = 'H';
    
    i = UNSIGN ((*scr).att);
    
    tmp[k++] = ((i & 01) ? SO : SI);
    tmp[k++] = ESC;			/* restore graphic attributes */
    tmp[k++] = '[';
    

#ifdef SCO
    
    if ((*scr).bw) tmp[k++] = '7';
    
    tmp[k++] = 'm';
    tmp[k++] = ESC;
    tmp[k++] = '[';
    
    i = scosgr (i, (*scr).bw);
    
    if (i & 02) {
        tmp[k++] = '1';
        tmp[k++] = ';';
    }

#else

    if (i & 02) {
        tmp[k++] = '2';
        tmp[k++] = ';';
    }

#endif /* SCO */

    if (i & 04) {
        tmp[k++] = '3';
        tmp[k++] = ';';
    }

    if (i & 010) {
        tmp[k++] = '4';
        tmp[k++] = ';';
    }

    if (i & 020) {
        tmp[k++] = '5';
        tmp[k++] = ';';
    }

    if (i & 040) {
        tmp[k++] = '6';
        tmp[k++] = ';';
    }

    if (i & 0100) {
        tmp[k++] = '7';
        tmp[k++] = ';';
    }

    if (i & 0200) {
        tmp[k++] = '8';
        tmp[k++] = ';';
    }

    if (tmp[k - 1] == ';') k--;
    
    tmp[k++] = 'm';
    tmp[k] = EOL;
    
    k = mcmnd;
    mcmnd = 0;
    
    m_output (tmp);
    
    mcmnd = k;

    return;

}					/* end part_ref() */

/* delayed write for higher system throughput */
void m_output (char *text)				
{
    static char buffer[2048];
    static int p = 0;
    char *G;
    int i;
    int ch;

    if (io == HOME) opnfile[io] = stdout;
    
    G = SIflag[io] ? G0O[io] : G1O[io];
    
    i = 0;
    
    while ((ch = text[i++]) != EOL) {

        ch = UNSIGN (ch);
        
        if (ESCflag[io] == FALSE && ch >= NUL && ch < 255) ch = G[ch];
        
        buffer[p++] = ch;
        
        if (ch == SI) {
            SIflag[io] = TRUE;
            G = G0O[io];
        }

        if (ch == SO) {
            SIflag[io] = FALSE;
            G = G1O[io];
        }

        if (ch == ESC) {
            ESCflag[io] = TRUE;
            continue;
        }

        if (ch == '[' && ESCflag[io]) {
            ESCflag[io] = 2;
            continue;
        }

        if (ch >= '@' && ch < DEL) ESCflag[io] = FALSE;
        if (ch != NUL) continue;
        
        fputs (buffer, opnfile[io]);
        
        p = 0;				/* NUL needs special treatment */
        
        fputc (NUL, opnfile[io]);	/* 'cause unix uses it as delim */

    }

    buffer[p] = NUL;
    
    if (mcmnd == 'w' && *codptr == ',' && (p < 1536)) return;

    if (fm_nodelay[io]) {

        if (setjmp (sjbuf)) {
            merr_raise (NOWRITE);
            goto done;
        }

        sig_attach (SIGALRM, &ontimo);
        alarm (3);

    }

    fputs (buffer, opnfile[io]);
    
    p = 0;
    
    if (mcmnd == '*') fputc (EOL, opnfile[io]);	/* special treatment for EOL */
    if (demomode) fputc (d0char, opnfile[io]);
    
    fflush (opnfile[io]);


done:

    alarm (0);			/* reset alarm request */
    
    return;

}					/* end of m_output() */


void write_m (char *text)
{
    static char esc = 0;		/* esc processing flag */
    static char tmp[512];
    register int i;
    register int j;
    register int ch;

    if (io == HOME) {
        
        opnfile[HOME] = stdout;
        
        if (frm_filter == FALSE) {
            writeHOME (text);
            return;
        }

    }

    /* 'normal' output for devices other than HOME */
    j = 0;
    i = 0;
    
    while ((ch = text[j++]) != EOL) {
    
        tmp[i++] = ch;
    
        if (ch >= SP) {
    
            if (esc == 0) {
                xpos[io]++;
                continue;
            }
    
            if (ch == '[') {
                esc = 2;
                continue;
            }
    
            if (ch >= '@' || esc == 1) esc = 0;
            
            continue;

        }

        esc = (ch == ESC);
        
        if (ch == LF) {
        
            ypos[io]++;
        
            if (frm_crlf[io]) xpos[io] = 0;
        
            continue;

        }

        if (ch == CR) {
            xpos[io] = 0;
            continue;
        }

        if (ch == BS) {            
            if (--xpos[io] < 0) xpos[io] = 0;
            continue;
        }

        if (ch == FF) {
            
            xpos[io] = 0;
            ypos[io] = 0;
        
            continue;

        }

        if (ch == TAB) {
            xpos[io] += 8 - (xpos[io] % 8);
        }

    }					/* end while */
    
    tmp[i] = EOL;
    
    m_output (tmp);
    
    xpos[io] &= 0377;
    ypos[io] &= 0377;
    
    return;

}					/* end of write_m() */

/* tab to number 'col' column' */
void write_t (short int col)
{
    short int i;
    short int j;
    char tmp[256];			/* Not tied to STRLEN necessarily*/

    if (col <= xpos[io]) return;
    if (col > (sizeof(tmp)-1)) col = (sizeof(tmp)-1);		/* guard against buffer overflow */
    
    j = xpos[io];
    i = 0;
    
    while (j++ < col) tmp[i++] = SP;
    
    tmp[i] = EOL;
    
    write_m (tmp);
    
    return;

}					/* end of write_t() */

void ontimo (void)
{					/* handle timeout (for read) */
    longjmp (sjbuf, 1);
}					/* end of ontimo() */

/*  Try to read up to 'length' characters from current 'io'
 * If 'length' == zero a single character read is performed and 
 * its $ASCII value is returned in 'stuff'.
 * A negative value of 'timeout' means there's no timeout.
 * a zero value looks whether a character has been typed in already
 * a positive value terminates the read after 'timeout' seconds
 * a timeout will set $TEST to TRUE if successfull, FALSE otherwise
 * 
 * timeouts 1 .. 3 are done by polling,
 * higher timeouts request an alarm. that different treatment is
 * necessary, because timeouts may be up to 2 seconds early.
 * polling on higher timeouts would be require too much system resources
 * just for nothing.
 * maximum timeout is 32767 (2**15-1) seconds (about 9 hrs)
 * There are no provisions to handle overflow.
 */
void read_m (char *stuff, long read_timeout, short read_timeoutms, short length)
{
    static char previous[2][256] = {{EOL}, {EOL}};				/* all static: longjmp! */
    static short p_toggle = 0;
    static char term_key[256] = {EOL, EOL};
    static short int escptr;
    static short int single;
    static short int timoflag;		/* timeout flag */
    static long int timex;
    static short int timexms;
    static short int i;
    static int ch;
    
#ifdef USE_GETTIMEOFDAY
    static struct timeval timebuffer;
#else
    static struct timeb timebuffer;
#endif

    escptr = 0;
    single = 0;
    timoflag = FALSE;
    
    /* Not necessarily tied to STRLEN */

    if (length > 255) length = 255;
    
    stuff[length] = EOL;
    stuff[0] = EOL;
    
    if (length < 1) single = length = 1;
    
    timex = 0L;
    timexms = 0;

    if (io == HOME) opnfile[HOME] = stdin;

    if (io == HOME && !frm_filter) {
        
        if (NOTYPEAHEAD) fflush (stdin);		/* ignore previous input */
    
        if (read_timeout >= 0) {
    
            test = TRUE;
    
            if (read_timeout > 2 && read_timeout <= 32767) {	/* cave small/large values */
    
                if (setjmp (sjbuf)) {
                    
                    test = FALSE;
                    timoflag = TRUE;

                    goto done;
                
                }

                sig_attach (SIGALRM, &ontimo);
                alarm ((unsigned) read_timeout);

                read_timeout = (-1L);

            } 
            else {
                
                if (read_timeout >= 0) {
                

#ifdef USE_GETTIMEOFDAY
                
                    gettimeofday (&timebuffer, NULL);	/* get current time */
                    
                    read_timeout += timebuffer.tv_sec;	/* target time */
                    read_timeoutms += timebuffer.tv_usec;
                
#else

                    ftime (&timebuffer);	/* get current time */
                    
                    read_timeout += timebuffer.time;		/* target time */
                    read_timeoutms += timebuffer.millitm;
                
#endif

                    if (read_timeoutms > 999) {
                        read_timeoutms -= 1000;
                        read_timeout++;
                    }

                }

            }

        }

        zb[0] = EOL;
        zb[1] = EOL;
        zcc = FALSE;
    
        for (i = 0; i < length; i++) {
            
            if (merr () == INRPT) {
                
                if (--i < 0) i = 0;
                stuff[i] = EOL;

                break;
            }
    
            if (evt_async_enabled && (merr () == ASYNC)) break;
    
            /* TODO: remove old FreeM "journaling" nonsense here */
            if (jour_flag < 0) {

                if ((ch = fgetc (jouraccess)) == EOF) {
                
                    jour_flag = 0;
                
                    fclose (jouraccess);
                
                    jouraccess = NULL;
                
                } 
                else {
                
                    if (ch == SI) {
                        test = FALSE;
                        break;
                    }			/* timeout char */
                
                }
            
            }


            if (jour_flag >= 0) {
            
                if (ug_buf[HOME][0] != EOL) {
                    ch = ug_buf[HOME][0];
                    stcpy (ug_buf[HOME], &ug_buf[HOME][1]);
                } 
                else {
                    if (read_timeout >= 0)
#ifdef SYSFIVE
                    {
                        if (rdchk0 (&ch) == 1) {
                        }
#else
                    {
            
                    if (rdchk (fileno (stdin)) > 0)
                        ch = getc (stdin);
#endif /* SYSFIVE */
                    else {

                        if (read_timeout < 0) {
                        
                            test = FALSE;
                            timoflag = TRUE;
                            stuff[i] = EOL;
                        
                            break;
                        
                        }
#ifdef USE_GETTIMEOFDAY
                        gettimeofday (&timebuffer, NULL);   /* get current time */
                        if ((read_timeout < timebuffer.tv_sec) ||
                        ((read_timeout == timebuffer.tv_sec) &&
                         (read_timeoutms <= timebuffer.tv_usec))) {
#else
                        ftime (&timebuffer);    /* get current time */
                        if ((read_timeout < timebuffer.time) ||
                        ((read_timeout == timebuffer.time) &&
                         (read_timeoutms <= timebuffer.millitm))) {
#endif
                
                            test = FALSE;
                            timoflag = TRUE;
                            stuff[i] = EOL;
                            break;
                        }
                
                        i--;
                        continue;
                    
                    }
                } 
                else {
                    ch = getc (stdin);
                }
            }
        }
    
        if (UNSIGN (ch) == 255) {
            i--;
            continue;
        }				/* illegal char */
        
        if (CONVUPPER) {		/* convert to uppercase ? */
            if (ch >= 'a' && ch <= 'z') ch -= 32;
        }

        /* on CTRL/O suspend execution until next CTRL/O */
        if (ch == SI && CTRLOPROC) {
            
            printf ("\033[8p\033[4u");	/* screen dark, timeout off */
            
            while ((ch = getc (stdin)) != SI);	/* loop until CTRL/O */
        
            printf ("\033[9p\033[5u");	/* screen light, timeout on */
        
            i--;
            continue;
        }

        zb[0] = ch;

        if (single == 0) {

            if (ch == ESC) {
            
                i--;
            
                term_key[0] = ESC;
                escptr = 1;
            
                continue;
            
            }
            
            if (escptr) {

                short j;

                i--;

                term_key[escptr++] = ch;
                term_key[escptr] = EOL;
                
                if (ch == '[' && escptr == 2) continue;	/* CSI */
                
                /* DECs PF1..PF4 and Keypad application */
                if (ch == 'O' && PF1flag && escptr == 2) continue;
                if (escptr > 2 && (ch < '@' || ch >= DEL)) continue;
                
                if (ESCSEQPROC) {
                    stcpy (zb, term_key);            
                    break;
                }

                if (escptr == 2) {

                    if (ch == '9') {	/* to begin of string */

                        while (i >= 0) {

                            if (ECHOON) {

                                if (xpos[HOME] > 0) {
                                    write_m ("\033[D\201");
                                }
                                else {
                                    write_m ("\033M\033[79C\201");
                                }

                            }

                            i--;

                        }

                        escptr = 0;
                        
                        continue;

                    } 
                    else if (ch == ':') {		/* to end of string */

                        while (stuff[i] != EOL && stuff[i + 1] != EOL) {

                            if (ECHOON) {

                                if (xpos[HOME] < (n_columns - 1)) {
                                    write_m ("\033[C\201");
                                }
                                else {
                                    write_m ("\012\015\201");
                                }

                            }
                            
                            i++;

                        }

                        escptr = 0;

                        continue;

                    }

                }

                if (escptr == 3) {

                    if (ch == 'D') {	/* CUB left arrow */

                        if (i >= 0) {
                    
                            if (ECHOON) {

                                if (xpos[HOME] > 0) {
                                    write_m (term_key);
                                }
                                else {
                                    write_m ("\033M\033[79C\201");
                                }

                            }

                            i--;

                        }

                        escptr = 0;

                        continue;

                    }

                    if (stuff[i + 1] == EOL) {
                        escptr = 0;
                        continue;
                    }

                    if (ch == 'C') {	/* CUF right arrow */

                        if (ECHOON) {
                            
                            if (xpos[HOME] < (n_columns - 1)) {
                                write_m (term_key);
                            }
                            else {
                                write_m ("\012\015\201");
                            }

                        }

                        i++;
                        
                        escptr = 0;
                        
                        continue;

                    }

                    if (ch == 'P') {	/* DCH Delete Character */
                        
                        ch = i + 1;
                        
                        if (stuff[ch] != EOL) {
                            while ((stuff[ch] = stuff[ch + 1]) != EOL) ch++;
                        }

                        if (ECHOON) {

                            ch = xpos[HOME] + 1;
                            j = ypos[HOME] + 1;
                            
                            stcpy (term_key, &stuff[i + 1]);
                            stcat (term_key, " \033[\201");
                            intstr (&term_key[stlen (term_key)], j);
                            stcat (term_key, ";\201");
                            intstr (&term_key[stlen (term_key)], ch);
                            stcat (term_key, "H\201");
                            
                            write_m (term_key);

                        }

                        escptr = 0;

                        continue;

                    }

                    if (ch == '@') {	/* ICH Insert Character */
                        
                        ch = i;                    
                        while (stuff[ch++] != EOL);
                        
                        while (ch > i) {
                            stuff[ch] = stuff[ch - 1];
                            ch--;
                        }

                        stuff[i + 1] = SP;
                        
                        if (ECHOON) {

                            ch = xpos[HOME] + 1;
                            j = ypos[HOME] + 1;
                            
                            stcpy (term_key, &stuff[i + 1]);
                            stcat (term_key, "\033[\201");
                            intstr (&term_key[stlen (term_key)], j);
                            stcat (term_key, ";\201");
                            intstr (&term_key[stlen (term_key)], ch);
                            stcat (term_key, "H\201");
                            
                            write_m (term_key);

                        }

                        escptr = 0;
                        
                        continue;

                    }
                }

                /* VT100 Functionkey */
                if (ch == '~' && (escptr == 4 || escptr == 5)) {

                    j = term_key[2] - '0';
                    
                    if (term_key[3] != ch) j = j * 10 + term_key[3] - '0';
                    if (j < 1 || j > 44) j = 0;
                
                }            
                else {
                    /* SCO Functionkey */
                    j = find ("@ABCDFGHIJKLMNOP0_dTVX ;\"#$%&\'<=*+,-./123UWY\201", &term_key[1]);
                }
                
                escptr = 0;
                
                /* key unknown or without a value */
                if (j == 0 || zfunkey[j - 1][0] == EOL)	continue;
                
                /* put key in input buffer, ignore overflow */
                {
                    char    tmp[256];

                    stcpy (tmp, ug_buf[HOME]);
                    stcpy (ug_buf[HOME], zfunkey[--j]);
                    stcat (ug_buf[HOME], tmp);
                }

                continue;
            }

            term_key[0] = ch;
            term_key[1] = EOL;

            if (find (LineTerm, term_key)) break;
        
            if (ch == BS || ch == DEL) {

                if (stuff[i] != EOL) {	/* DEL within string */

                    if (ch == BS && i > 0) {

                        if (ECHOON) {
                        
                            if (xpos[HOME] > 0) {
                                write_m ("\033[D\201");
                            }
                            else {
                                write_m ("\033M\033[79C\201");
                            }
                        
                        }

                        i--;

                    }

                    ch = i;
                    if (stuff[ch] != EOL) {
                        while ((stuff[ch] = stuff[ch + 1]) != EOL) ch++;
                    }

                    if (ECHOON) {

                        int j;

                        ch = xpos[HOME] + 1;
                        j = ypos[HOME] + 1;
                        
                        stcpy (term_key, &stuff[i]);
                        stcat (term_key, " \033[\201");
                        intstr (&term_key[stlen (term_key)], j);
                        stcat (term_key, ";\201");
                        intstr (&term_key[stlen (term_key)], ch);
                        stcat (term_key, "H\201");
                        
                        write_m (term_key);

                    }

                    continue;

                }

                if (i > 0) {

                    if (ECHOON) {

                        if (DELMODE) {

                            if (xpos[HOME] > 0) {
                                write_m ("\010 \010\201");
                            }
                            else {
                                write_m ("\033M\033[79C\033[P\201");
                            }

                        } else {
                            write_m ("\\\201");
                        }

                    }
                    
                    i--;
                    
                    ch = i;
                    
                    while ((stuff[ch] = stuff[ch + 1]) != EOL) ch++;

                }
                else if (DELEMPTY) {

                    /* empty string delete? */
                    stuff[0] = EOL;
                    i = 1;
                    term_key[0] = ch;
                    
                    break;

                }

                i--;

                continue;

            }

            if (ch == NAK || ch == DC2) {	/* CTRL/U deletes all input */

                while (stuff[i] != EOL) {

                    if (ECHOON) {

                        if (xpos[HOME] < (n_columns - 1)) {
                            write_m ("\033[C\201");
                        }
                        else {
                            write_m ("\012\015\201");
                        }
                    
                    }
                    
                    i++;

                }

                while (i > 0) {

                    if (ECHOON) {

                        if (DELMODE) {

                            if (xpos[HOME] > 0) {
                                write_m ("\010 \010\201");
                            }
                            else {
                                write_m ("\033M\033[79C\033[P\201");
                            }

                        } 
                        else {
                            write_m ("\\\201");
                        }

                    }

                    stuff[i--] = EOL;

                }

                stuff[i--] = EOL;
                
                if (ch == NAK) continue;
                
                /* (ch==DC2) *//* CTRL/R Retypes last input */
                
                i = stcpy (stuff, previous[p_toggle]);
                
                stuff[i--] = EOL;
                
                toggle (p_toggle);
                
                if (ECHOON) write_m (stuff);
                
                continue;
            }

            if (ch == STX && (zbreakon || hardcopy)) {
            
                if (zbreakon) zbflag = TRUE;
            
                if (i > 0) {
                    if (ECHOON) write_m ("\010 \010\201");
                }

                i--;

                continue;

            }

            if (ch == BrkKey) {	/* CTRL/C may interrupt */
                
                i--;
                
                if (breakon) {
                    
                    stuff[i] = EOL;
                    merr_raise (INRPT);
        
                    return;
                
                }
        
                continue;
            }

            /* ignore non programmed CTRL/ key ?? */
            if (ch < SP && (ch != TAB || nstx) && NOCTRLS) { /* TAB may be a programmed key */
                i--;
                continue;
            }

        } /* if (single == 0) */

        if (stuff[i] == EOL) stuff[i + 1] = EOL;
        if (ch < 255) ch = (SIflag[io] ? G0I[io] : G1I[io])[UNSIGN (ch)];
        
        stuff[i] = ch;
        
        if (ECHOON) {
        
            term_key[0] = ch;
            term_key[1] = EOL;
        
            write_m (term_key);
        
        }

        } /* ???????????  may need to run through preprocessor to see where the heck this goes */
    } 
    else {				/* $io != HOME */
        int fd;
        int fdstat;

        fd = 0;


#if defined(SYSFIVE) && !defined(__AMIGA) && !defined(MSDOS)

    if (read_timeout >= 0) {

        fd = fileno (opnfile[io]);
        fdstat = fcntl (fd, F_GETFL);
        
        fcntl (fd, F_SETFL, fdstat | O_NDELAY);
    
    }

#endif /* SYSFIVE */

    for (i = 0; i < length; i++) {
        
        if (merr () == INRPT) {
            
            if (--i < 0) i = 0;
    
            stuff[i] = EOL;
        
            break;
        
        }
    
        if (ug_buf[io][0] != EOL) {
            ch = ug_buf[io][0];            
            stcpy (ug_buf[io], &ug_buf[io][1]);
        } 
        else if (read_timeout >= 0) 
        {
            test = TRUE;
    
#ifdef SYSFIVE
    if (fread (&ch, 1, 1, opnfile[io]) < 1)
#else
    if (rdchk (fileno (opnfile[io])) == 0 || ((ch = fgetc (opnfile[io])) == EOF))
#endif /* SYSFIVE */

        {
            if (--read_timeout < 0) {
        
                test = FALSE;
                timoflag = TRUE;
                stuff[i] = EOL;
        
                break;
        
            }
            
            sleep (1);
            
            i--;
            
            continue;

        }

    ch = UNSIGN (ch);
    } 
    else {
        ch = fgetc (opnfile[io]);
    }

    stuff[i] = ch;
    
    if (ch == EOF) {
        /* EOF halts filtered mps */
        if ((io == HOME) && frm_filter) merr_raise (INRPT);
    
        stuff[i] = EOL;
        
        break;
    }

    if (single) break;
    
    if (ch == LF && frm_crlf[io]) {
        i--;
        continue;
    }

    if ((ch == CR) || (ch == LF)) {
        int ch0;

        stuff[i] = EOL;

        /* if input terminates with CR/LF or LF/CR take both    */
        /* as a single termination character. So it is possible */
        /* to get correct input from files written by mumps     */
        /* itself with CR/LF line termination                   */

#if defined(SYSFIVE) && !defined(__AMIGA) && !defined(MSDOS)

        if (fd == 0) {

            fd = fileno (opnfile[io]);
            fdstat = fcntl (fd, F_GETFL);
            
            fcntl (fd, F_SETFL, fdstat | O_NDELAY);

        }

        if (fread (&ch0, 1, 1, opnfile[io]) == 1) {
            ch0 = UNSIGN (ch0);

#else
#if !defined(__AMIGA) && !defined(MSDOS)		   

        if (rdchk (fileno (opnfile[io])) == 1) {
            ch0 = fgetc (opnfile[io]);

#else

#if defined(__AMIGA)	    
	    
        if (rdchk0 (fileno (opnfile[io])) == 1) {
            ch0 = fgetc (opnfile[io]);
#endif
	    
#endif /* __AMIGA */

#if defined(MSDOS)
	if (1) {	    
	    ch0 = fgetc (opnfile[io]);
#endif
	    
#endif /* SYSFIVE */

            if ((ch == CR && ch0 != LF) || (ch == LF && ch0 != CR))
                ungetc (ch0, opnfile[io]);
            }

            break;
        }
        
        if (UNSIGN (stuff[i]) < 255)
            stuff[i] = (SIflag[io] ? G0I[io] : G1I[io])[UNSIGN (stuff[i])];
        }

#if defined(SYSFIVE) && !defined(__AMIGA)
    if (fd) fcntl (fd, F_SETFL, fdstat);
#endif /* SYSFIVE */

    } /* if ((ch == CR) || (ch == LF)) */


done:
    
    alarm (0);			/* reset alarm request */
    
    if (io == HOME && jour_flag > 0) {
        
        char    tmp[256];

        tmp[stcpy (tmp, stuff)] = NUL;        
        fputs (tmp, jouraccess);

        if (timoflag) {
            
            tmp[0] = SI;
            tmp[1] = NUL;		/* CTRL/O as timeout char */
        
            fputs (tmp, jouraccess);
        
        } 
        else if ((i < length) || (stuff[0] == NUL && zb[0] == ESC)) { 
            
            /* save termination char if meaningful */
            tmp[stcpy (tmp, zb)] = NUL;
            fputs (tmp, jouraccess);

        }

    }
    
    if (single) {			/* to ASCII */

        if (timoflag) {
            stuff[0] = '-';
            stuff[1] = '1';
            stuff[2] = EOL;
        } 
        else {
            intstr (stuff, UNSIGN (stuff[0]));
        }

    } 
    else if (io == HOME && stuff[0] != EOL) {
        stcpy (previous[toggle (p_toggle)], stuff);
    }

    return;

}					/* end of read_m() */

#if defined(SYSFIVE)
/* UNIX system V has no 'rdchk' function. We must do it ourselves */

#if !defined(__AMIGA) && !defined(MSDOS)

int rdchk0 (int *data)
{
    static int x;
    static int firsttime = TRUE;
    int retcode;
    char ch;

    if (firsttime) {
        x = fcntl (0, F_GETFL);
        firsttime = FALSE;
    }

    fcntl (0, F_SETFL, x | O_NDELAY);

    retcode = read (0, &ch, 1);

    fcntl (0, F_SETFL, x);

    *data = (retcode > 0) ? ch : NUL;

    return retcode;

}					/* end rdchk0() */

#else

int rdchk0 (int *data) 
{
    /* TODO: flesh out on m68k-amigaos */
    return TRUE;
}    

#endif

/******************************************************************************/
/* under XENIX the system has an intrinsic function 'locking'.                */
/* under UNIX System V it must be done with fcntl.                            */
/* the difference is, that the XENIX locking blocks all other accesses        */
/* whereas UNIX System V gives only protection if all users of a file         */
/* use 'locking'.                                                             */
/* since 'fcntl' is not properly documented, the outcome in any cases of      */
/* errors is uncertain.                                                       */

#ifdef AMIGA68K

int locking (int fd, int action, long count)
{
    /* TODO: flesh out on m68k-amigaos */
    return 0;
}

#else

/* fd = file descriptor of file to be locked */
/* action = action to be performed */
/* count area to be locked */
int locking (int fd, int action, long count)
{

    struct flock lock;

    lock.l_whence = 1;			/* lock from current position */
    lock.l_start = 0;
    lock.l_len = count;
    lock.l_pid = getpid ();

    if (lonelyflag) return 0;			/* no LOCK if single user */
    
    switch (action) {
        

        case 0:				/* LK_UNLK free previously locked area */
        
            lock.l_type = F_UNLCK;
            fcntl (fd, F_SETLK, &lock);
        
            break;
        

        case 1:				/* LK_LOCK lock against others reading and writing my data */
        
            lock.l_type = F_WRLCK;
            fcntl (fd, F_SETLKW, &lock);
        
            break;
        

        case 2:				/* LK_NBLCK lock against others reading and writing my data, don't block */
        
            lock.l_type = F_WRLCK;
            fcntl (fd, F_SETLK, &lock);
        
            break;
        

        case 3:				/* LK_RLCK lock against others writing my data */
        
            lock.l_type = F_RDLCK;
            fcntl (fd, F_SETLKW, &lock);
        
            break;
        

        case 4:				/* LK_NBRLCK lock against others writing my data, don't block */
        
            lock.l_type = F_RDLCK;
            fcntl (fd, F_SETLK, &lock);

            break;

    }
    
    return 0;				/* action properly performed */

}					/* end locking() */

#endif

#ifdef OLDUNIX

/* set io_parameters to mumps/unix conventions */
/*  action: 0 = UNIX; 1 = MUMPS */
void set_io (short action)				
{
    if (lio_mode == action) return;
    
    static char del;
    static char fs;
    struct termio tpara;

    if (frm_filter) return;				/* nothing special if used as filter */
    
    fflush (stdin);
    fflush (stdout);
    fflush (stderr);
    
    ioctl (0, TCGETA, &tpara);		/* get paramters            */
    
    if (action == UNIX) {

	lio_mode = UNIX;
	
        tpara.c_lflag |= (ECHO | ICANON);	/* enable echo/no cbreak mode */
        tpara.c_iflag |= ICRNL;		/* cr-lf mapping */
        tpara.c_oflag |= ONLCR;		/* cr-lf mapping */
        tpara.c_cc[VINTR] = del;	/* interrupt                */
        tpara.c_cc[VQUIT] = fs;		/* quit                     */
        tpara.c_cc[VMIN] = EOT;
        tpara.c_cc[VTIME] = -1;

    } 
    else {				/* action == MUMPS */

	lio_mode = MUMPS;
	
        tpara.c_lflag &= (~(ECHO | ICANON));	/* disable echo/cbreak mode */
        tpara.c_iflag &= ~ICRNL;	/* cr-lf mapping */
        tpara.c_oflag &= ~ONLCR;	/* cr-lf mapping */
        del = tpara.c_cc[VINTR];	/* save previous state of   */
        fs = tpara.c_cc[VQUIT];		/* quit and interrupt       */
        tpara.c_cc[VINTR] = BrkKey;	/* interrupt = CTRL/C       */
        tpara.c_cc[VQUIT] = (zbreakon || hardcopy) ? STX : -1;	/* zbreak/hardcopy */
        tpara.c_cc[VMIN] = 1;
        tpara.c_cc[VTIME] = 1;

    }

    ioctl (0, TCSETA, &tpara);

    return;

}					/* end of set_io() */


/* break_char:           */
/*  -1  = break disabled */
/*  ETX = MUMPS break    */
/*  DEL = UNIX quit      */ 
void set_break (short break_char)
{
#if !defined(__OS2__)
    struct termio arg;

    ioctl (0, TCGETA, &arg);

    arg.c_cc[VINTR] = break_char;	/* interrupt = CTRL/C   */
    
    ioctl (0, TCSETA, &arg);
#endif    
    return;

}					/* end of set_break() */

/* quit_char: */
/* -1  = quit disabled */
/* STX = MUMPS CTRL/B   */
/* DEL = UNIX quit      */
void set_zbreak (short quit_char)
{
#if !defined(__OS2__)    
    struct termio arg;

    ioctl (0, TCGETA, &arg);

    arg.c_cc[VQUIT] = quit_char;
    
    ioctl (0, TCSETA, &arg);
#endif    
    return;

}					/* end of set_zbreak() */

#else

void set_io (short action)				/* set io_parameters to mumps/unix conventions */
{
    static struct termios unixtermio;
    struct termios termios_p;

    if (lio_mode == action) return;    

    if (frm_filter) return;				/* nothing special if used as filter */
    
    if (action == UNIX) {
	lio_mode = UNIX;
	
        tcsetattr (0, TCSADRAIN, &unixtermio);	
    }
    else {				/* action == MUMPS */
	lio_mode = MUMPS;
	
        tcgetattr (0, &unixtermio);	/* get unix paramters */
        tcgetattr (0, &termios_p);	/* get paramters */
    
        termios_p.c_lflag &= (~(ECHO | ICANON));	/* disable echo/cbreak mode */
        termios_p.c_iflag &= ~ICRNL;	/* cr-lf mapping */
        termios_p.c_oflag &= ~ONLCR;	/* cr-lf mapping */
        termios_p.c_cc[VINTR] = BrkKey;	/* interrupt = CTRL/C */
        termios_p.c_cc[VQUIT] = (zbreakon || hardcopy) ? STX : -1;	/* zbreak/hardcopy */
        termios_p.c_cc[VMIN] = 1;
        termios_p.c_cc[VTIME] = 1;
    
        tcsetattr (0, TCSADRAIN, &termios_p);	/* set paramters */
    
    }
    
    return;

}					/* end of set_io() */

void set_break (short break_char)
{

#if !defined(__OS2__)
    struct termios termios_p;

    tcgetattr (0, &termios_p);
    
    termios_p.c_cc[VINTR] = break_char;	/* interrupt = CTRL/C   */
    
    tcsetattr (0, TCSADRAIN, &termios_p);	/* set paramters */
#endif    
    return;

}					/* end of set_break() */

void set_zbreak (short quit_char)
{
#if !defined(__OS2__)
    struct termios termios_p;

    tcgetattr (0, &termios_p);
    
    termios_p.c_cc[VQUIT] = quit_char;
    
    tcsetattr (0, TCSADRAIN, &termios_p);	/* set paramters */
#endif    
    return;

}					/* end of set_zbreak() */

#endif /* OLDUNIX */

#else

/* same for XENIX */
void set_io (short action)				/* set io_parameters to mumps/unix conventions */
{
    static char del;
    static char fs;
    struct sgttyb tt;
    struct tchars tc;

    if (frm_filter) return;				/* nothing special if used as filter */
    
    fflush (stdin);
    fflush (stdout);
    fflush (stderr);
    
    ioctl (0, TIOCGETP, &tt);
    ioctl (0, TIOCGETC, &tc);
    
    if (action == UNIX) {
        
        tt.sg_flags &= ~02;		/* no cbreak mode           */
        tt.sg_flags |= (010 | 020);	/* echo ; CR to LF map      */
        tc.t_quitc = fs;		/* quit                     */
        tc.t_intrc = del;		/* interrupt                */
        
        /* we desperately tried to do it with DEL - but it didn't work */

    } 
    else {				/* action == MUMPS */
        
        tt.sg_flags |= 02;		/* cbreak mode              */
        tt.sg_flags &= (~010 & ~020);	/* 10 no echo; 20 no CR map */
        del = tc.t_intrc;		/* save previous state of   */
        fs = tc.t_quitc;		/* quit and interrupt       */
        tc.t_intrc = BrkKey;		/* interrupt = CTRL/C       */
        tc.t_quitc = (zbreakon || hardcopy) ? STX : -1;		/* zbreak/hardcopy */

    }

    ioctl (0, TIOCSETP, &tt);
    ioctl (0, TIOCSETC, &tc);

}					/* end of set_io() */

void set_break (short break_char)
{
    struct tchars tc;

    ioctl (0, TIOCGETC, &tc);
    
    tc.t_intrc = break_char;
    
    ioctl (0, TIOCSETC, &tc);
    
    return;

}					/* end of set_break */

void set_zbreak (short quit_char)
{
    struct tchars tc;

    
    ioctl (0, TIOCGETC, &tc);
    
    tc.t_quitc = quit_char;
    
    ioctl (0, TIOCSETC, &tc);
    
    return;

}					/* end of set_zbreak */

#endif /* SYSFIVE */


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>