/* @(#)tvinit.c 17.1.1.1 (ES0-DMD) 01/25/02 17:36:56 */ /*=========================================================================== Copyright (C) 1995 European Southern Observatory (ESO) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Massachusetss Ave, Cambridge, MA 02139, USA. Corresponding concerning ESO-MIDAS should be addressed as follows: Internet e-mail: midas@eso.org Postal address: European Southern Observatory Data Management Division Karl-Schwarzschild-Strasse 2 D 85748 Garching bei Muenchen GERMANY ===========================================================================*/ /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .TYPE Module .IDENTIFICATION tvinit.c .AUTHOR Francois Ochsenbein [ESO-IPG] .LANGUAGE C .KEYWORDS Terminal Independant i/o Package .ENVIRONMENT TermWindows .COMMENTS This module provides functions to open/close the terminal. PhysiCal output makes use of ost. *** NOTE *** This version includes the OS-dependant fi_date routine *** \begin{TeX} Used Capabilities: $$\begin{tabular}{|lp{30em}|}\hline {\tt .M=} & Switch on automatic margin \\ {\tt .m=} & Switch off automatic margin \\ {\tt am} & Terminal has automatic margins \\ {\tt co\#} & Number of columns on the screen \\ {\tt is=} & Initialization sequence \\ {\tt ti=} & Initialization sequence for special modes \\ {\tt te=} & Undo what's done by {\tt ti} \\ {\tt ks=} & Start keypad mode \\ {\tt ke=} & Exit keypad mode \\ {\tt li\#} & Number of lines on the screen \\ {\tt rs=} & Reset terminal sequence \\ {\tt se=} & Exit Stand-out mode (normal attributes) \\ {\tt Va=} & Set keyboard to ASCII \\ {\tt Vn=} & Set normal Video attributes \\ {\tt up=} & Move Cursor up \\ {\tt do=} & Move Cursor down \\ {\tt bc=} & Move Cursor left \\ {\tt nd=} & Move Cursor right \\ {\tt nl=} & Write a newline \\ {\tt cm=} & Cursor absolute positionning \\ \hline \end{tabular}$$ The default TERMCAP file the logical {\tt TERMCAPFILE} (or some other definition in {\tt stdef:terminal.h}). However, the login directory is searched for an existing (binary) copy of terminal capabilities, named from terminal name with extension {\tt .tty}.\\[0.5ex] {\bf Notes}: \begin{enumerate} \item if the terminal has automatic margins (the cursor moves to the beginning of the next line when the right margin is reached), the number of columns is decremented to avoid wrapping problems. \item if no terminal is available (\eg in batch mode), what should appear on the terminal is simply directed to stdout. \end{enumerate} \end{TeX} .VERSION 1.0 07-Jul-1986: Creation .VERSION 1.1 02-Sep-1986: The default directory is searched for a binary copy of terminal capabilities. The TERMCAPFILE is only used if such a binary copy does not exist. .VERSION 1.2 26-Sep-1986: At initialisation, set scrolling region to whole screen. .VERSION 1.3 10-Oct-1986: At closing, use of newly defined tt_close function. .VERSION 2.0 03-Dec-1986: New terminal-independant version. Buffering capabilities. .VERSION 2.1 12-Jun-1987: Possibility of Batch Mode. Modified bug in ztinit. Version '2' of TermCap: check if Termcapfile was not modified. .VERSION 2.2 23-Jun-1987: Minimal implementation in Version 2, with UNIX compatibility. This minimal implementation has the restrictions: \begin{TeX} \begin{itemize} \item no batch mode \item a binary copy of the termcapabilities for the specific terminal exist: no need to parse the TermCapFile and to encode the capabilities. \item no batch possibility \item no insert/delete/scrolling \end{itemize} \end{TeX} .VERSION 2.3 02-Dec-1987 Use of external function while waiting for input .VERSION 3.0 15-Mar-1988 Adapted on top of OS routines. Version 3 which allows definition of control characters. .VERSION 3.1 21-Feb-1989 Added tv_setcc .VERSION 3.2 28-Mar-1989 Added DEFAULT_TERMINAL = ansi .VERSION 3.3 17-May-1989 Check minimal capabilities .VERSION 3.4 19-Jun-1989 Allow :nl=\n capability .VERSION 3.5 29-Jun-1989 Check correctly the version... .VERSION 3.6 25-Jul-1989 Reset Automatic Margins at Close... .VERSION 3.7 23-Aug-1989 `ti' cap is required for SunView... Also added (for Unix) a lookup in Local /etc/termcap .VERSION 3.8 28-May-1990 Allow hard terminals... .VERSION 3.9 27-Aug-1990 Leave Int = ^C as default in Unix .VERSION 3.91 07-Sep-1990 Let write a message if a problem occurs... .VERSION 3.92 09-Oct-1990 Allow file output (Unix background) .VERSION 3.93 03-Dec-1990 tv_setsc allows the change of Control Char Set .VERSION 3.94 26-Feb-1991 Was calling tv_open recursively in batch... Also added socket option in tv_setsc .VERSION 4.0 28-Jan-1994 Create the binary copy in MID_WORK vs HOME. CG. -------------------------------------------------------*/ #define DEBUG 0 /* For debugging only */ #define PM_LEVEL LEVEL_TV #define Closing_Wait 500 /* ms to wait at Closing */ #define DEFAULT_TERMINAL "ansi" #define TW_MACROS 0 /* Don't use TermWindows Macros */ #define TW_import 0 #define TW_STRUCT 0 /* Do not use window Structures */ #include /* OS Terminal Definitions */ #include #ifndef NULL #define NULL NULL_PTR(char) #endif #define EXT_TTY ".tty" #if MID_OS_MSDOS /* --- For Ibm-PC (M. Albrecht) */ MID_STATIC char *DIR_TTY = "\\"; /* Default Directory */ # define DIR_TTY_TRAILER "" #else #if MID_OS_VMS MID_STATIC char *DIR_TTY = "SYS$LOGIN:"; # define DIR_TTY_TRAILER "" #else /* UNIX */ MID_STATIC char *DIR_TTY = NULL; /* Default Directory */ # define DIR_TTY_TRAILER "/" # define local_termcapfile "/etc/termcap" #endif #endif MID_STATIC TERM sterm = { /* The Terminal Definition */ 1, /* No Terminal */ 0 /* The version id */ }; static struct termstatus tst; MID_GLOBAL TERM *terms = &sterm; /* The terminal structure common to TV routines */ static short int old_pos[2]; MID_STATIC char ccdef[4][33] = { /* Control Characters */ { TW_cc_NONE, TW_cc_MODE, TW_cc_HOME, TW_cc_INT, /* User */ TW_cc_DOWN, TW_cc_EOL, TW_cc_REFR, TW_cc_NONE, /* ^D ^E ^F ^G */ TW_cc_HELP, TW_cc_NW, TW_cc_RET , TW_cc_HELP, /* ^H ^I ^J ^K */ TW_cc_LEFT, TW_cc_RET, TW_cc_NW, TW_cc_NONE, /* ^L ^M ^N ^O */ TW_cc_NONE, TW_cc_NONE, TW_cc_RIGHT,TW_cc_NONE, /* ^P ^Q ^R ^S */ TW_cc_NONE, TW_cc_UP, TW_cc_DELE, TW_cc_DELW, /* ^T ^U ^V ^W */ TW_cc_DELL, TW_cc_QUIT, TW_cc_EOF, TW_cc_NONE, /* ^X ^Y ^Z ^[ */ TW_cc_RAW, TW_cc_NONE, TW_cc_MODE, TW_cc_NONE, /* ^\ ^] ^^ ^_ */ TW_cc_DELC}, /* Delete */ { TW_cc_NONE, TW_cc_MODE, TW_cc_UP, TW_cc_INT, /* VMS */ TW_cc_LEFT, TW_cc_EOL, TW_cc_RIGHT,TW_cc_HELP, /* ^D ^E ^F ^G */ TW_cc_HOME, TW_cc_NW, TW_cc_RET , TW_cc_HELP, /* ^H ^I ^J ^K */ TW_cc_NONE, TW_cc_RET, TW_cc_DOWN, TW_cc_NONE, /* ^L ^M ^N ^O */ TW_cc_NONE, TW_cc_NONE, TW_cc_REFR, TW_cc_NONE, /* ^P ^Q ^R ^S */ TW_cc_NONE, TW_cc_DELL, TW_cc_DELE, TW_cc_DELW, /* ^T ^U ^V ^W */ TW_cc_NONE, TW_cc_QUIT, TW_cc_EOF, TW_cc_NONE, /* ^X ^Y ^Z ^[ */ TW_cc_RAW, TW_cc_NONE, TW_cc_MODE, TW_cc_NONE, /* ^\ ^] ^^ ^_ */ TW_cc_DELC}, /* Delete */ { TW_cc_NONE, TW_cc_MODE, TW_cc_LEFT, TW_cc_INT, /* Unix */ TW_cc_EOF, TW_cc_EOL, TW_cc_RIGHT,TW_cc_NONE, /* ^D ^E ^F ^G */ TW_cc_DELC, TW_cc_NW, TW_cc_RET, TW_cc_HELP, /* ^H ^I ^J ^K */ TW_cc_HOME, TW_cc_RET, TW_cc_DOWN, TW_cc_NONE, /* ^L ^M ^N ^O */ TW_cc_UP, TW_cc_NONE, TW_cc_REFR, TW_cc_NONE, /* ^P ^Q ^R ^S */ TW_cc_NONE, TW_cc_DELL, TW_cc_RAW, TW_cc_DELW, /* ^T ^U ^V ^W */ TW_cc_DELE, TW_cc_NONE, TW_cc_NONE, TW_cc_NONE, /* ^X ^Y ^Z ^[ */ TW_cc_QUIT, TW_cc_NONE, TW_cc_MODE, TW_cc_NONE, /* ^\ ^] ^^ ^_ */ TW_cc_DELC}, /* Delete */ { TW_cc_NONE, TW_cc_NONE, TW_cc_NONE, TW_cc_NONE, /* Socket */ TW_cc_EOF, TW_cc_EOL, TW_cc_REFR, TW_cc_NONE, /* ^D ^E ^F ^G */ TW_cc_HELP, TW_cc_NONE, TW_cc_RET , TW_cc_HELP, /* ^H ^I ^J ^K */ TW_cc_RET, TW_cc_RET, TW_cc_NONE, TW_cc_NONE, /* ^L ^M ^N ^O */ TW_cc_NONE, TW_cc_NONE, TW_cc_NONE, TW_cc_NONE, /* ^P ^Q ^R ^S */ TW_cc_NONE, TW_cc_NONE, TW_cc_RAW, TW_cc_NONE, /* ^T ^U ^V ^W */ TW_cc_NONE, TW_cc_NONE, TW_cc_EOF, TW_cc_NONE, /* ^X ^Y ^Z ^[ */ TW_cc_NONE, TW_cc_NONE, TW_cc_MODE, TW_cc_NONE, /* ^\ ^] ^^ ^_ */ TW_cc_DELC}, /* Delete */ }; /* Macros just to improve readibility */ #define SEND(p) tv_send(p,1) #define curl (terms->pos[0]) #define curc (terms->pos[1]) #define diml (terms->dim[0]) #define dimc (terms->dim[1]) #define oldl old_pos[0] #define oldc old_pos[1] #define KEYPAD (terms->flags & TERM_KPAD) #define TTattr terms->tt_attr #define Vn 0 #define VB 1 #define Vu 2 #define Vb 3 #define Vr 4 #define Vg 5 #define Va 6 /* MONITOR(TVINIT); */ /* CG. static is defined locally */ /*========================================================================== * tv_setcc *==========================================================================*/ int tv_setcc(c, action) /*+++++++ .PURPOSE Define the meaning of Control Characters for TermWindow Usage. .RETURNS Actual action of cc (differs if could not be changed) .REMARKS If cc is alphabetic, it's converted to control character. ----------*/ int c; /* IN: The control character */ int action; /* IN: Action TW_cc_xxx as defined in twdef.h */ { register char *p; register int k; static char cc; ENTER("+tv_setcc"); p = NULL_PTR(char); cc = (iscntrl(c) ? c : Control_(c)); k = (cc < 32 ? cc : 32); /* Position in terms->tc */ switch(action) { case TW_cc_INT: p = &(tst.cc_INT); break; case TW_cc_QUIT: p = &(tst.cc_QUIT); break; default: if ((action < 0) || (action > TW_cc_max)) FINISH; } /* Check it's not an escape sequence */ if (terms->specials & MASK(k)) FINISH; if (p) /* Must reset terminal... */ { if (ostinfo(&tst)) FINISH; /* Be sure interrupt chars are right */ if (*p == cc) { terms->tc[k] = action; FINISH;} /* No change */ *p = cc; /* Change it .. */ ostset(&tst); /* Change terminal ... */ ostinfo(&tst); /* Verify it's done */ if (*p != cc) terms->standout |= ChangedControl, terms->tc[(*p < 32 ? *p : 32)] = action; } if (terms->tc[k] != action) terms->standout |= ChangedControl; terms->tc[k] = action; FIN: k = terms->tc[k]; EXIT(k); } int tv_setsc(option) /*+++++++ .PURPOSE Define the meaning of Control Characters for TermWindow Usage. .RETURNS Previous definitions .REMARKS ----------*/ int option; /* IN: TW_cc_NONE (no control mapping) / TW_cc_VMS / \ TW_cc_UNIX / TW_cc_SET */ { int old_option, i, k; char cc; ENTER("+tv_setsc"); old_option = (terms->flags & TERM_NOMAP ? TW_cc_NONE : TW_cc_SET); k = -1; switch(option) { case TW_cc_NONE: terms->flags |= TERM_NOMAP; break; case TW_cc_SET: terms->flags &= ~TERM_NOMAP; break; case -1: k = TW_cc_default; break; case TW_cc_USER: k = 0; break; case TW_cc_VMS: case TW_cc_UNIX: k = option; break; case TW_cc_SOCKET: k = option-1; break; } if (k >= 0) { for (i = 32, cc = DEL; i >= 0; cc = --i) tv_setcc(cc, ccdef[k][i]); terms->flags &= ~TERM_NOMAP; } EXIT(old_option); } /*========================================================================== * tv_getcc *==========================================================================*/ int tv_getcc(action) /*+++++++ .PURPOSE Retrieve the Control Character corresponding to a TermWindow Action. .RETURNS The Control Character corresponding to the action (-1 for None) .REMARKS If several control characters are mapped to an action, the first encountered is returned. ----------*/ int action; /* IN: Action TW_cc_xxx as defined in twdef.h */ { int i; for (i = 0; i < sizeof(terms->tc); i++) if (terms->tc[i] == action) break; if (i == sizeof(terms->tc) - 1) i = DEL; else if (i >= sizeof(terms->tc)) i = -1; return(i); } /*========================================================================== * tv_aload *==========================================================================*/ static int tv_aload() /*+++ .PURPOSE Load attributes and graphic chars in the TERM structure from TERMCAPabilities. .RETURNS OK .REMARKS Some termcap files use `me' `mb' `md' `mr' for exit mode, blink, bold, reverse respectively. ----------*/ { register char *p, *pso; register int i; int k; MID_RSTATIC char gcap[] = "GvGhG0G1G2G3G4GuGdGlGrGg"; MID_RSTATIC char video[] = "VnmeVBmdVuusVbmbVrmr";/* Video attr. */ /* If TTattr not yet loaded, do it now * Note that no Stand-Out mode implies Overstrike or ChangeCase */ if(terms->standout&7) return(OK); /* Already done */ k = 1; /* Last 3 bits of terms->standout */ /* Load the defaults graphic characters */ terms->gchars[_VERTICAL_] = '|'; terms->gchars[_HORIZONTAL_] = '-'; for (i = ITEMS(terms->gchars); --i>=2; ) terms->gchars[i] = '+'; terms->gchars[_RUBBISH_] = '~'; pso = SearchCap("so"); /* Default stand-out mode */ p = SearchCap("Vg"); /* Graphic */ /* Some Termcap files use "as" */ if (!p) p = SearchCap("as"); TTattr[Vg] = p; /* Load now the graphic chars */ for (i=0; i < ITEMS(terms->gchars); i++) { p = SearchCap(&gcap[i*2]); if (p) terms->gchars[i] = *(p+4); } TRACE_ED_STR2("Graphic chars: ", terms->gchars, sizeof(terms->gchars)); p = SearchCap("Va"); /* ASCII */ /* Some Termcap files use "ae" */ if (!p) p = SearchCap("ae"); TTattr[Va] = p; /* Load now Video Attributes */ for (i = 0; i < sizeof(video)/4; i++) { p = SearchCap(&video[i*4]); /* V. */ if (!p) p = SearchCap(&video[i*4+2]); /* m. */ if (!p) p = pso; TTattr[i] = p; TRACE_ED_STR2("TTattr is: ", TTattr[i], 12); } p = TTattr[Vn]; /* Normal */ if ( (!p) || (p == pso) ) p = SearchCap("se"); TTattr[Vn] = p; if (!p) /* No existing attribute */ k = (SearchCap("os") ? 2: /* Use Overstrike */ 3); /* Use Case Change */ terms->standout |= k; return(OK); } /*========================================================================== * tv_close *==========================================================================*/ int tv_close () /*+++ .PURPOSE Close the opened terminal .RETURNS OK .REMARKS To be called at the end of program using tv_... functions. ---*/ { register char *p; ENTER("tv_close"); if(!terms->version) FINISH; /* Was not opened ! */ if (terms->term_type) FINISH; /* Is NOT a terminal! */ tv_where(old_pos); /* Reset the scrolling */ tv_attr(terms->attr_init); tv_sr0(); tv_goto(oldl,oldc); /* Go to newline if cursor not positioned at the left margin */ if (curc) tv_nl(); /* Reset Automatic Margins */ if (SearchCap("am")) { p = SearchCap(".M"); if (p) SEND(p); } /* Clear the lower part of the screen */ if(!(terms->term_type & TERM_hard)) tv_clear(_DOWN_); /* Reset the original attributes */ tv_attr(terms->attr_init); /* Reset the terminal to init --- use `rs' capability */ SendCap("te"); /* Undo ti */ SendCap("rs"); /* Reset */ #if MID_OS_VMS tv_wms(Closing_Wait); /* Wait a bit ... */ #endif ostclose(); FIN: terms->version = 0; EXIT(OK); } /*========================================================================== * tv_gterm *==========================================================================*/ char *tv_gterm() /*+++ .PURPOSE Retrieve terminal name .RETURNS Pointer to terminal name / NULL if not opened .REMARKS ---*/ { tv_open(NULL_PTR(char), NULL_PTR(char), -1); /* Default Open */ return(terms->term_name); } /*========================================================================== * tv_kpad *==========================================================================*/ static int tv_kpad (k) /*+++ .PURPOSE Enable or disables the keypad. .RETURNS OK if possible, NOK if not possible .REMARKS ---*/ int k; /* IN: non-zero to enable, zero to disable */ { register char *p; register int s; ENTER("tv_kpad"); s = OK; if(k) /* Trying to enable ... */ { if (KEYPAD) FINISH; p = SearchCap("ks"); if (p) terms->flags |= TERM_KPAD; } else /* Trying to disable .. */ { if (!KEYPAD) FINISH; p = SearchCap("ke"); terms->flags &= (~TERM_KPAD); } if (!p) s = NOK; else SEND(p); FIN: EXIT(s); } /*========================================================================== * tv_init *==========================================================================*/ int tv_reset() /*+++ .PURPOSE Reset the Terminal: Get new number of lines/cols. .RETURNS OK / NOK .REMARKS ---*/ { short cur_pos[2]; cur_pos[0] = terms->pos[0]; cur_pos[1] = terms->pos[1]; if (ostinfo(&tst)) return(NOK); /* Get Characteristics */ if (tst.lines <= 0) return(NOK); /* Bad lines count */ if (tst.columns > 0) terms->dim[1] = terms->dim_init[1] = tst.columns; if ((tst.lines > 0) && (tst.lines != terms->dim_init[0])) { terms->dim[0] = terms->dim_init[0] = tst.lines; tv_sr0(); /* Reset scrolling region */ } tv_goto (cur_pos[0], cur_pos[1]); return(OK); } static int resize () /*+++ .PURPOSE Function called when window resized. .RETURNS OK / NOK ----*/ { ostwinch(resize); /* Reset function for next Window Resize */ return(tv_reset()); } static int tv_init (opt) /*+++ .PURPOSE Initializes the terminal (number of lines, col, etc) .RETURNS OK / NOK .REMARKS List of capabilities is assumed to be loaded in the Minimal Version. If the terminal has automatic margin (am), number of columns is decremented. ---*/ int opt; /* IN: Option for control characters */ { register char *p; register int i; MID_RSTATIC char motions[] = "updobcndnlcm" ; /* Cursor seq. */ MID_RSTATIC char swidth[] = "lico" ; /* Screen dim. */ MID_RSTATIC char no_cap[] = ""; ENTER("tv_init"); terms->baud = MAX(tst.baud_rate, 20000); terms->attr_init = 0; terms->attr = 0; terms->dim_init[0] = tst.lines; /* Default number of lines */ terms->dim_init[1] = tst.columns; /* Default number of columns */ terms->pos[0] = tst.lines-1; /* Default position */ terms->pos[1] = 0; /* Default position */ terms->scregion[0] = 0; /* Default top scrolling region */ terms->scregion[1] = 0; /* Default top scrolling region */ terms->flags = 0; /* No flag */ terms->pad_char = 0; /* Default padding character */ terms->standout = 0; /* Unloaded attribute sequences */ terms->ir = 0; /* Read buffer */ terms->irtop = 0; /* Read buffer */ terms->iw = 0; /* Write buffer */ terms->last_char = 0; terms->last_type = 0; /* Number of lines / columns */ for (i = 0; i < 2; i++) { if (terms->dim_init[i]) continue; p = SearchCap(&swidth[i*2]); if (p) terms->dim_init[i] = atoi(p+4); } /* Padding char, if known */ p = SearchCap("pc"); if (p) terms->pad_char = *(p+4); /* Set the control characters */ if (terms->term_type == 0) { if (ostopen() < 0) opt = TW_cc_SOCKET, ERROR(osmsg()); tv_setsc(opt); } /* Determine basic motions sequences */ for (i = 0; i < ITEMS(terms->tt_ptr); i++) { p = SearchCap(&motions[i*2]); if_not(p) p = no_cap; terms->tt_ptr[i] = p; } /* Check the NewLine: can't be only \n */ p = terms->tt_ptr[_NEWLINE_]; if ( (*p == '\01') && (*(p+4) == '\n')) terms->tt_ptr[_NEWLINE_] = "\02nl=\r\n"; if (*terms->tt_ptr[_LEFT_] == 0) /* No left motion, try bs */ if_not (SearchCap("bs")) terms->tt_ptr[_LEFT_] = SearchCap("_H"); #if (TW_LEVEL == 0) /* Test all cursor movements exist */ for (i = 0; i < ITEMS(terms->tt_ptr); i++) { if(*(terms->tt_ptr[i]) == 0) { ERR_ED_STR2("Missing Capability: ", terms->tt_ptr[i]+1, 2); EXIT(NOK); } } #else /* If no up capability, set terminal to `hard' */ if(*(terms->tt_ptr[_UP_]) == 0) terms->flags |= TERM_hard; #endif /* Clear Capability */ p = SearchCap("cl"); if (!p) p = SearchCap("ff"); terms->tt_clear = p; /* Get Graphic Chars and Change Attribute sequences */ tv_aload(); /* Send init sequence if necessary */ p = SearchCap("is"); if (p) SEND(p); else /* Some TERMCAP files have i1, i2, i3 cap's */ { SendCap("i1"); SendCap("i2"); SendCap("i3"); } SendCap("ti"); /* Special Initialisation */ /* Look for automatic margins. If possible to disable, do it. */ if (SearchCap("am")) { p = SearchCap(".m"); if (p) SEND(p), (terms->flags) |= TERM_am; else (terms->dim_init[1])--; } terms->dim[0] = terms->dim_init[0]; terms->dim[1] = terms->dim_init[1]; /* Set the default attributes and char set */ SEND(terms->tt_attr[Vn]); SEND(terms->tt_attr[Va]); /* Enable keypad mode */ tv_kpad(1); /* Set the scrolling region to whole screen ... (superseedes init) */ tv_sr0(); EXIT(OK); } /*========================================================================== * tv_open *==========================================================================*/ int tv_open (device, term_file, option) /*+++++ .PURPOSE Open a specified device, reading specifications in the term_file (list of TERMCAPabilities) terminal descriptions. .RETURNS OK / NOK .REMARKS In Minimal Implementation, Binary file MUST exist, and No batch possibilities. The option allows a choice of control characters, as TW_cc_VMS, TW_cc_UNIX or TW_cc_USER. The control characters to use may be set BEFORE calling tv_open. \begin{TeX} The actions of the Control Characters are defined as follows: $$\begin{tabular}{|l|ccc|l|} \hline Mnemonic & User & VMS & UNIX & Action \\ \hline {\tt TW\_cc\_INT} & \^{}C & \^{}C & {\em Del.} & Interrupt \\ {\tt TW\_cc\_QUIT} & \^{}Y & \^{}Y & \^{}\b & Quit (Stop) \\ {\tt TW\_cc\_RET} & \^{}M & \^{}M & \^{}M & Return Key \\ {\tt TW\_cc\_EOF} & \^{}Z & \^{}Z & \^{}D & End of File character \\ {\tt TW\_cc\_RAW} & \^{}\b & \^{}\b & \^{}V & No interpretation of next character \\ {\tt TW\_cc\_MODE} & \^{}A & \^{}A & \^{}A & Switch Insert / Replace Modes \\ {\tt TW\_cc\_REFRESH} & \^{}F & \^{}R & \^{}R & Refresh Screen \\ {\tt TW\_cc\_HELP} & \^{}H & \^{}G & \^{}K & Help Window \\ {\tt TW\_cc\_UP} & \^{}U & \^{}B & \^{}P & Move Up \\ {\tt TW\_cc\_DOWN} & \^{}D & \^{}N & \^{}N & Move Down \\ {\tt TW\_cc\_LEFT} & \^{}L & \^{}D & \^{}B & Move Left (Backwards) \\ {\tt TW\_cc\_RIGHT} & \^{}R & \^{}F & \^{}F & Move Right (Forwards) \\ {\tt TW\_cc\_HOME} & \^{}B & \^{}H & \^{}L & Move to Left Margin \\ {\tt TW\_cc\_EOL} & \^{}E & \^{}E & \^{}E & Move to End of Line \\ {\tt TW\_cc\_NW} & \^{}I & \^{}I & \^{}I & Move to Next Word \\ {\tt TW\_cc\_DELC} & {\em Del.} & {\em Del.}& \^{}H & Delete character at left of cursor \\ {\tt TW\_cc\_DELW} & \^{}W & \^{}W & \^{}W & Delete Word at Left of cursor\\ {\tt TW\_cc\_DELE} & \^{}J & \^{}J & \^{}X & Delete to End of Line \\ {\tt TW\_cc\_DELL} & \^{}X & \^{}X & \^{}U & Delete Complete Line \\ \hline \end{tabular}$$ \end{TeX} -----*/ char *device; /* IN: The type of device; NULL gets from environment */ char *term_file;/* IN: The Binary file; from device by default */ int option; /* IN: Option for control characters */ { register char *p, *p1, *p2; static int bfile; #if (TW_LEVEL > 0) /* Full Implementation */ TERM *term2; long int t; int status; MID_STATIC char binput = 0; MID_STATIC char *termcapfile = NULL; #endif ENTER("tv_open"); if (sterm.version == TW_VERSION) EXIT(OK); /* Already done */ #if (TW_LEVEL > 0) /* Full Implementation */ /* Define first the TermCap filename, using defaults, * and retrieve date of creation in case of modifs */ termcapfile = (term_file ? term_file : TERMCAPFILE); if (!termcapfile) termcapfile = oshenv("TERMCAP",NULL_PTR(char)); if (!termcapfile) #if MID_OS_MSDOS termcapfile = "\\termcap.dat"; #else { ERROR("TERMCAPFILE not defined"); goto BAD; } #endif t = osfdate(termcapfile); #endif /* Get first Terminal Status. * Note that, if no terminal is associated with the process * (eg batch run, indicated by a bad return code * in ostinfo), stdin/stdout are assumed */ if (ostinfo(&tst) < 0) /* No terminal... */ terms->term_type = 1, /* Indicates NOT a terminal */ ERROR(osmsg()); else terms->term_type = 0; /* Indicates a true terminal */ terms->version = TW_VERSION; /* Corrected 26-Feb-1991 */ terms->term_name = tst.termname; p = (device ? device : terms->term_name); /* Terminal name */ /* if (!(*p)) p = terms->term_name; */ if (!p) p = DEFAULT_TERMINAL; /* if (!(*p)) p = DEFAULT_TERMINAL; */ TRACE_ED_STRING("Terminal id: ", p); /* Copy terminal name and termcapfile to a new buffer */ if (!DIR_TTY) DIR_TTY = oshenv("MID_WORK", (char *)0); if (!DIR_TTY) DIR_TTY = oshenv("HOME", (char *)0); terms->term_name = MEM_GET(char, 2*strlen(p) + strlen(DIR_TTY) + 1 + strlen(termcapfile) + sizeof(DIR_TTY_TRAILER) + sizeof(EXT_TTY)); for (p2 = terms->term_name, p1 = p; *p1; p1++, p2++) #if MID_OS_VMS /* Convert to lower case for VAX... */ *p2 = tolower(*p1); #else *p2 = *p1; #endif *p2 = EOS; terms->save_file = ++p2; /* Transform device name to file name */ for (p1 = DIR_TTY; *p1; p1++, p2++) *p2 = *p1; for (p1 = DIR_TTY_TRAILER; *p1; p1++, p2++) *p2 = *p1; for (p1 = p; *p1; p1++) #if MID_OS_VMS /* VMS doesn't like hyphens in filenames... */ if (isalnum(*p1)) #endif *(p2++) = *p1; for (p1 = EXT_TTY; *p1; p1++, p2++) *p2 = *p1; *p2 = EOS; p1 = termcapfile, termcapfile = ++p2; for (; *p1; p1++, p2++) *p2 = *p1; *p2 = EOS; #if (TW_LEVEL > 0) /* ------------- F U L L Implementation ----- */ /* Look if a binary file with loaded capabilities * already exists; but don't use it if its date * is earlier than revision date of TermCap file! * *** Note that, if TermCap file doesn't exist, * the check will always be OK. */ bfile = 0; if (osfdate(terms->save_file) > t) bfile = osdopen(terms->save_file, READ); binput = (bfile > 0); if (binput) { term2 = MEM_GET(TERM,1); *term2 = *terms; /* Save */ status = osdread(bfile, (char *)terms, sizeof(TERM)); TRACE_ED_STR2("Read TERM: ", (char *)terms, sizeof(TERM)); if ( (status != sizeof(TERM)) || (terms->version != TW_VERSION) ) { binput = 0; *terms = *term2; MEM_FREE(term2); } } if (binput) { terms->save_file = term2->save_file; terms->term_name = term2->term_name; MEM_FREE(term2); terms->caplist = MEM_GET(char,terms->size); status = osdread(bfile, terms->caplist, terms->size); TRACE_ED_STR2("Read capl: ", terms->caplist, status); if (status != terms->size) binput = 0; } if (bfile>0) osdclose(bfile); /* If no binary input, acquire the terminal * capabilities directly from TermCapFile */ if (!binput) { eh_class(_WARNING_); /* Next message is a Warning */ ERR_ED_STRING("Obsolete version (recreated): ", terms->save_file); ERR_CLEAR(); bfile = osdopen(terms->save_file, WRITE); status = tu_load(termcapfile, terms->term_name, terms); #ifdef local_termcapfile if (status != OK) status = tu_load(local_termcapfile, terms->term_name, terms); #endif if (status != OK) { if (GetLog() > 2) /* There is a Log File. Issue also the message to the terminal, to let the user be aware of the problem... */ { p = ERR_LOC(); /* Retrieve Error ... */ ostwrite("**** ", 5); /* and display */ ostwrite(p, strlen(p)); /* and display */ ostwrite("\r\n", 2); ospwait(4); /* Just wait, to give some time to read the so important above message ... */ } goto BAD; } /* Copy structure to the binary file */ terms->size = terms->captop; /* Limit the size */ TRACE_ED_STR2("Writ TERM: ", (char *)terms, sizeof(TERM)); osdwrite(bfile, (char *)terms, sizeof(TERM)); TRACE_ED_STR2("Writ capl: ", terms->caplist, terms->size); osdwrite(bfile, terms->caplist, terms->size); osdclose(bfile); } #else /* ---------- Minimal Implementation -------- */ /* Load the binary file with loaded capabilities */ p2 = (term_file ? term_file : terms->save_file); bfile = osdopen(p2, READ); if (bfile <= 0) { ERR_ED_STRING("Can't find ", p2); goto BAD; } p1 = terms->term_name; /* Save */ status = osdread(bfile, terms, sizeof(TERM)); if ( (status != sizeof(TERM)) || (terms->version != TW_VERSION) ) { ERR_ED_STRING("Bad Version of ", p2); goto BAD; } terms->term_name = p1; /* Reset addresses */ terms->save_file = p1 + strlen(p1) + 1; /* Read the CapList */ if (!(terms->caplist = MEM_GET(char,terms->size))) goto BAD; if (osdread(bfile, terms->caplist, terms->size) != terms->size) { ERR_ED_STRING("Bad ", p2); goto BAD; } osdclose(bfile); #endif terms->buf_size = TVBUF; if (!(terms->bufr = MEM_GET(char, 3*TVBUF))) goto BAD; terms->bufw = terms->bufr + terms->buf_size; terms->bufs = terms->bufw + terms->buf_size; /* Initialize the terminal */ if (tv_init(option) != OK) goto BAD; ostwinch(resize); /* Set function for Window Resize */ status = OK; FINISH; BAD: status = NOK, ostclose(); FIN: EXIT(status); } /*========================================================================== * tv_stop *==========================================================================*/ int tv_stop (stop) /*+++ .PURPOSE Stop (stop!=0) or Start (stop==0) the terminal .RETURNS The previous state, i.e. 0 if terminal was active, not-zero if terminal was already stopped. (always 0 in Minimal Implementation) .REMARKS What is in the buffer is NOT sent to the terminal (immediate stop) ---*/ int stop; /* IN: 0 to start, 1 to stop */ { #if (TW_LEVEL == 0) return(0); #else register int returned; ENTER("tv_stop"); returned = (terms->flags) & (TERM_NOWRITE); if(stop) terms->flags |= TERM_NOWRITE; else terms->flags &= ~(TERM_NOWRITE); EXIT(returned); #endif } /*========================================================================== * tv_wait *==========================================================================*/ int tv_wait (ms) /*+++ .PURPOSE Set a waiting time (ms) after each output to screen. .RETURNS The previous waiting time (always 0 in Minimal Implementation) .REMARKS Useful to have an idea about the speed of a program as seen from a remote terminal... The waiting time is limited to 30000 (0.5 mn). ---*/ int ms; /* IN: milliseconds to wait */ { #if (TW_LEVEL == 0) return(0); #else register int old_ms; ENTER("+tv_wait"); if (terms) old_ms = terms->msw, terms->msw = (ms < 30000 ? ms : 30000); else old_ms = 0; EXIT(old_ms); #endif } /*========================================================================== * tv_dim *==========================================================================*/ int tv_dim(coo) /*+++++++++++ .PURPOSE Returns the current screen dimensions .RETURNS OK .REMARKS The position is adjusted within the screen limits. Not traced. ------------*/ short int coo[2]; /* OUT: screen dimensions: line (0=top), col (0=left) */ { tv_open(NULL_PTR(char), NULL_PTR(char), -1); /* Default Open */ coo[0] = terms->dim[0]; coo[1] = terms->dim[1]; return(OK); } #if 0 /*========================================================================== * tv_width *==========================================================================*/ int tv_width (width) /*+++ .PURPOSE Set the width (number of columns) to a specified value .RETURNS OK (was done, new dimension loaded), NOK (not possible, always in Minimal Implementation) .REMARKS Only enlarge or reduce width. Enlarge is `.S' with width `.W#', reduce is `.s' with width `.w#' * Note that, in case of output to a file, the width may always be changed! ---*/ int width; /* IN: New column width */ { #if (TW_LEVEL < 2) return(NOK); #else register char *p, *pw; ENTER("tv_width"); TRACE_ED_I("Present Width: ",terms->dim[1]); TRACE_ED_I("Asked Width: ",width); if ( (width == terms->dim[1]) || (terms->term_type) ) { terms->dim[1] = width; EXIT(OK); } status = OK; if (width > terms->dim[1]) p = ".S", pw = ".W"; /* Enlarge */ else p = ".s", pw = ".w"; /* Reduce */ p = SearchCap(p), pw = SearchCap(pw); if ((p) && (pw)) SEND(p), terms->dim[1] = atoi(pw+4); else status = NOK; EXIT(status); #endif } #endif /*========================================================================== * Internal Routines *==========================================================================*/ #if DEBUG /*========================================================================== * tv_ed *==========================================================================*/ int tv_ed () /*+++ .PURPOSE Edit the terminal characteristics on the log file. .RETURNS OK .REMARKS Only used for debugging. ---*/ { register char *p, *pw; MID_STATIC char msg[80] = ""; sprintf(msg,"....Device %s[%d] of dim. [%d,%d] -- Cursor at [%d,%d]", terms->term_name, terms->term_type, terms->dim[0], terms->dim[1], terms->pos[0], terms->pos[1]); LOG(msg); sprintf(msg,".... attr=%X, flags=%X", terms->attr, terms->flags); LOG(msg); return(OK); } #endif