/* @(#)ost.c 17.1.1.1 (ES0-DMD) 01/25/02 17:35:27 */ /*=========================================================================== 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 ost .AUTHOR Guido Russo [ST-ECF], Francois Ochsenbein [ESO-IPG] .LANGUAGE C .KEYWORDS Terminal i/o .ENVIRONMENT VAX / VMS Version .COMMENTS Adapted from Toolpack TIE WINDOWS. .VERSION 1.0 30-Jan-1986: Creation .VERSION 1.1 19-Jun-1986: Cosmetic changes (F. Ochsenbein). Redefined I/O functions as #define's. Traced system errors. Modified the Terminator Mask as a short expression. .VERSION 1.2 01-Jul-1986: Since QIO is used for output and QIOW for input, 2 DIFFERENT i/o status blocks are required for read and write operations !!! .VERSION 1.3 14-Aug-1986: The baud rate is also returned. .VERSION 1.4 10-Oct-1986: A new function, xv_close, does the required wait until all text is displayed. .VERSION 1.5 11-Jun-1987: Cosmetic modifications .VERSION 1.6 16-Jun-1987: Adapted for Ibm-PC, G. Russo, M. Albrecht. .VERSION 1.7 22-Jun-1987: Adapted for UNIX .VERSION 1.8 19-Jan-1988: Transformed to os routine ostinfo, ostopen, ostclose, ostread, ostwrite. A time-out is ALWAYS used. ostin returns the number of bytes in type-ahead buffer. .VERSION 2.0 09-Mar-1988: Added interrupt catching, to be sure that the terminal is correcly reset. .VERSION 2.1 28-Oct-1988: No ^C catching in VMS version. .VERSION 2.2 18-May-1989: Added vt300_series terminal type to ostinfo. When terminal is unknown, the string "unknown" is returned. M. Albrecht [ESIS] .VERSION 2.3 24-Jul-1989: ostint returns previously defined interrupt function .VERSION 2.4 03-Aug-1990: ostint works also if terminal was not opened. .VERSION 2.5 08-Sep-1990: allow long output .VERSION 2.6 17-Oct-1990: Removed GNU-nonunderstandable code... .VERSION 2.65 06-Nov-1990: Added ostwinch (Window Change) ----------------------------------------------------------------------------*/ #define DEBUG 0 #include #include /* Classical macros */ #include /* Terminal Definitions */ #include #include #ifdef EOF #undef EOF #endif typedef int (*FUNCTION)(); /* Pointer to Function */ #ifndef SIG_ERR #define SIG_ERR (FUNCTION)-1 #endif int oststop(); static int (*f_int)() = NULL_FCT(int); /* Interrupt function */ static char buf_name[24]; # include # include # include # include # include # define dsc$w_length len # define dsc$a_pointer s # include # define ENTER() oserror = 0, vmserror = SS$_NORMAL # define EXIT(x) FIN: if (!(vmserror&1)) \ if (oserror == 0) oserror = EIO;\ return (oserror ? -1 : x); # define CALL$(f) if (!((vmserror = f)&1)) FINISH; # define func_ssm IO$_SENSEMODE # define func_sen IO$_SENSEMODE|IO$M_TYPEAHDCNT # define func_out IO$_WRITELBLK|IO$M_NOFORMAT # define func_cin IO$_READLBLK|IO$M_NOFILTR|IO$M_NOECHO|IO$M_TIMED int SYS$WAITFR(); static int tt_chan = 0; /* Channel number */ static int tt_efn_r = 0; /* Event flag read */ static int tt_efn_w = 0; /* Event flag write */ static int mask[2] = {0,0}; /* Short Mask, no terminator char */ static unsigned short iosb_r[4]= {0}; /* I/O status block for read */ static unsigned short iosb_w[4]= {SS$_NORMAL, 0, 0, 0}; /* I/O status block for write */ static unsigned short io_sm[4] = {0}; static char tt_des_s[] = "TT:"; static struct dsc$descriptor_s tt_des = { sizeof(tt_des_s)-1, DSC$K_DTYPE_T, DSC$K_CLASS_S, tt_des_s }; #define FINISH goto FIN MID_EXTERN int oserror; MID_EXTERN char *oserrmsg; MID_EXTERN int vmserror; /* VMS-specific error code */ /*========================================================================== * VMS-specific internal routines *==========================================================================*/ static int assign() /*+++++ .PURPOSE Assign channel to terminal + event flags .RETURNS 0 (sucess) / -1 (failure), oserror explains .REMARKS If no terminal attached, returns -1. --------------*/ { ENTER(); if (tt_chan == 0) { CALL$(LIB$GET_EF(&tt_efn_r)); /* Get an event flag for read */ CALL$(SYS$CLREF(tt_efn_r)); /* ... and clear it */ CALL$(LIB$GET_EF(&tt_efn_w)); /* Get an event flag for write */ CALL$(SYS$CLREF(tt_efn_w)); /* ... and clear it */ CALL$(SYS$ASSIGN(&tt_des,&tt_chan,0,0)); /* Assign a channel to TT */ } EXIT(0); } /*========================================================================== * ostinfo *==========================================================================*/ int ostinfo (tstat) /*+++++ .PURPOSE Get info about the terminal in termstatus structure (see osterm.h), i.e. terminal name, number of lines, of columns, baud rate, and interrupt control characters. .RETURNS 0 (sucess) / -1 (failure), oserror explains .REMARKS If no terminal attached, returns -1. --------------*/ struct termstatus *tstat; /* OUT: Terminal description */ { register int i; register char *p, *q; ENTER(); tstat->lines = 0; tstat->columns = 0; if (assign() < 0) FINISH; CALL$(SYS$QIOW(tt_efn_r,tt_chan,func_ssm,iosb_r,0,0, io_sm,sizeof(io_sm),0,0,0,0)); /* Get device characteristics */ tstat->lines = io_sm[3] >> 8; /* Screen length */ tstat->columns = io_sm[1]; /* Width of screen */ /* Get the baud rate --- However, some rounding is sufficient */ switch(iosb_r[1] & 0xFF) { case TT$C_BAUD_150: case TT$C_BAUD_134: i = 150; break; case TT$C_BAUD_110: i = 110; break; case TT$C_BAUD_50: i = 50 ; break; case TT$C_BAUD_75: i = 75 ; break; case TT$C_BAUD_300: i = 300; break; case TT$C_BAUD_600: i = 600; break; default: case TT$C_BAUD_1200: case TT$C_BAUD_1800: i = 1200; break; case TT$C_BAUD_2000: i = 2000; break; case TT$C_BAUD_2400: i = 2400; break; case TT$C_BAUD_3600: i = 3600; break; case TT$C_BAUD_4800: i = 4800; break; case TT$C_BAUD_7200: i = 7200; break; case TT$C_BAUD_9600: i = 9600; break; case TT$C_BAUD_19200: i = 19200; break; } /* Set terminal type according to physical device */ switch(io_sm[0] >> 8) /* VMS-supplied terminal type */ { case TT$_VT52: case TT$_VT55: p = "vt52"; /* VT52 class */ break; case TT$_VT100: case TT$_VT101: case TT$_VT105: case TT$_VT125: p = "vt100"; /* VT100 class */ break; case TT$_VT102: case TT$_VT131: case TT$_VT132: p = "vt102"; /* VT102 class */ break; case TT$_VT200_SERIES: p = "vt200"; /* VT200 class */ break; case TT$_VT300_SERIES: p = "vt300"; /* VT300 class */ break; case TT$_LA12: case TT$_LA34: case TT$_LA36: case TT$_LA38: case TT$_LA120: case TT$_LA100: p = "ht"; /* Hardcopy */ break; default: p = "unknown"; /* unknown */ break; } tstat->cc_INT = Control_('C'); tstat->cc_QUIT = Control_('Y'); tstat->baud_rate = i; /* Copy terminal name to buffer */ i = strlen(p); if (i > sizeof(buf_name)-1) i = sizeof(buf_name)-1; for (q = buf_name; --i >= 0; ) *(q++) = *(p++); *q = EOS; tstat->termname = buf_name; EXIT(0); } /*========================================================================== * ostopen *==========================================================================*/ int ostopen () /*+++++++++++++ .PURPOSE Initialize the terminal. .RETURNS 0 (sucess) / -1 (failure), oserror explains .REMARKS If no terminal attached, returns -1. --------------*/ { ENTER(); if (assign() < 0) FINISH; CALL$(SYS$QIOW(tt_efn_r,tt_chan,func_ssm,iosb_r,0,0, io_sm,sizeof(io_sm),0,0,0,0)); /* Get device characteristics */ #if 0 /* Don't catch ^C */ CALL$(SYS$QIOW(tt_efn_w,tt_chan,IO$_SETMODE|IO$M_CTRLCAST,iosb_w,0,0, f_int,SIGINT,0,0,0,0)); /* Enable Control C */ #endif EXIT(0); } /*========================================================================== * ostclose *==========================================================================*/ int ostclose () /*+++++++ .PURPOSE Close the terminal (reset it to normal) .RETURNS 0 / -1 on failure ----------*/ { register int l; ENTER(); l = 0; #if DEBUG puts("\n....Closed Terminal"); #endif EXIT(l); } /*========================================================================== * oststop *==========================================================================*/ int oststop (s) /*++++++++++++ .PURPOSE Terminate program in case of interrput .RETURNS To OS ----------------------------------------------------------------------------*/ int s; /* IN: Signal identification */ { ENTER(); ostclose(); SYS$EXIT(SS$_NORMAL); EXIT(0); } /*========================================================================== * ostset *==========================================================================*/ int ostset (tstat) /*++++ .PURPOSE Set Terminal. .RETURNS 0 / -1 .REMARKS Only interrupt / quit controls are reset. ----------------------------------------------------------------------------*/ struct termstatus *tstat; /* IN: Status structure with controls\ to modify */ { ENTER(); EXIT(0); } /*========================================================================== * ostraw *==========================================================================*/ int ostraw (op) /*++++ .PURPOSE Set Terminal to raw (op = 1), to Normal (0) .RETURNS 0 / -1 .REMARKS Does nothing... ---------------------------------*/ int op; /* IN: 0 to reset to standard, 1 to reset to raw */ { ENTER(); EXIT(0); } /*========================================================================== * ostint *==========================================================================*/ FUNCTION ostint (f) /*++++ .PURPOSE Define a function for interrupt .RETURNS Previous function ----------------------------------------------------------------------------*/ FUNCTION f; /* IN: Function to call in case of Interrupt */ { FUNCTION old_f; ENTER(); old_f = f_int; f_int = f; if (!tt_chan) assign(); CALL$(SYS$QIOW(tt_efn_w,tt_chan,IO$_SETMODE|IO$M_CTRLCAST, iosb_w,0,0,0,0,0,0,0,0)); /* Disable Control C */ CALL$(SYS$QIOW(tt_efn_w,tt_chan,IO$_SETMODE|IO$M_CTRLCAST, iosb_w,0,0,f_int,SIGINT,0,0,0,0)); /* Enable Control C */ CALL$(SYS$QIOW(tt_efn_w,tt_chan,IO$_SETMODE|IO$M_CTRLCAST, iosb_w,0,0,SYS$WAITFR,tt_efn_w,0,0,0,0)); /* Called before */ FIN: return(old_f); } FUNCTION ostwinch (f) /*++++ .PURPOSE Define a function for Window Change .RETURNS Previous function ----------------------------------------------------------------------------*/ FUNCTION f; /* IN: Function to call in case of Window Change */ { FUNCTION old_f; ENTER(); old_f = SIG_ERR; oserror = -1, oserrmsg = "WINCH not available"; return(old_f); } /*========================================================================== * ostin *==========================================================================*/ int ostin() /*+++ .PURPOSE Retrieve the number of characters waiting for input (type-ahead buffer) .RETURNS Number of bytes waiting in type-ahead buffer / -1 for error. .REMARKS No actual read is performed. --------*/ { register int l; ENTER(); /* Call system routine to get number of characters * in type-ahead buffer */ CALL$(SYS$QIOW(tt_efn_r,tt_chan,func_sen,iosb_r,0,0, io_sm,sizeof(io_sm),0,0,0,0)); l = io_sm[0]; EXIT(l); } /*========================================================================== * ostread *==========================================================================*/ int ostread(string, length, timeout) /*+++ .PURPOSE Input from the terminal (a timeout is REQUIRED!). A null timeout performs the reading of what is in the type-ahead buffer only. \begin{TeX} This routine must perform binary input --- \ie the input is not echoed or edited, and the program receives the user's input without having to wait for a RETURN / newline / etc. If the user has not typed anything within the maximum time passed (in seconds) it should return with the value zero. It is desirable (but not strictly necessary) that the "wait" be cut short if input is received after the routine call but before the expiry of the time period --- if this is not the case then the calling routines may simply be a bit slow. \end{TeX} .RETURNS Number of bytes read / -1 (End of File or Failure) -----------------------------------------------------------------------*/ char *string; /* OUT: string read */ int length; /* IN: size of string */ int timeout; /* IN: Timeout time in seconds */ { register int l, time; static long int num_char; ENTER(); if (length <=0) /* Impossible to get 0 char */ { oserror = EINVAL; FINISH; } /* Test timeout */ time = (timeout < 0 ? 0 : timeout); /* Call system routine to get number of characters * in type-ahead buffer */ CALL$(SYS$QIOW(tt_efn_r,tt_chan,func_sen,iosb_r,0,0, io_sm,sizeof(io_sm),0,0,0,0)); /* if buffer empty, input 1 character */ l = (io_sm[0] ? io_sm[0] : 1 ); l = MIN(l, length); /* read as many as the buffer */ /* Call system routine to actually perform read * from the type-ahead buffer */ CALL$(SYS$QIOW(tt_efn_r,tt_chan,func_cin,iosb_r,0,0,string,l, time,mask,0,0)); /* Check for successfull completion. * Note that timeout is not an error, * and number of read bytes need not to be identical with request. */ l = iosb_r[1]; /* actual number of char read */ switch(iosb_r[0]) { case SS$_NORMAL: case SS$_TIMEOUT: /* successful completion */ vmserror = SS$_NORMAL; default: break; /* Report system error */ } EXIT(l); } /*========================================================================== * ostwrite *==========================================================================*/ int ostwrite (string, length) /*+++ .PURPOSE Physical output of a string to the terminal. .RETURNS Number of bytes written / -1 (failure, oserror explains) -----------------------------------------------------------------------------*/ char *string; /* IN: string to be written */ int length; /* IN: length of string */ { register int l; register char *p, *pe; ENTER(); for (p = string, pe = p + length; p < pe; p += l) { l = pe - p; if (l > 512) l = 512; /* Limit */ CALL$(SYS$QIOW(tt_efn_w,tt_chan,func_out,iosb_w,0,0, p,l,0,0,0,0)); } EXIT(l); }