/*
* $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>