/* @(#)tvput.c 17.1.1.1 (ES0-DMD) 01/25/02 17:36:57 */ /*=========================================================================== 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 tvput.c .AUTHOR Francois Ochsenbein [ESO-IPG] .LANGUAGE C .KEYWORDS Terminal Independant i/o Package. .ENVIRONMENT TermWindows .COMMENTS This module groups output and graphic char treatement. \begin{TeX} Used Capabilities: $$\begin{tabular}{|lp{37em}|} \hline {\tt se=} & Exit Stand-out mode \\ {\tt so=} & Start Stand-out mode \\ {\tt us=} & Start Underline mode \\ {\tt Va=} & Set keyboard to ASCII \\ {\tt Vg=} & Set keyboard to graphic mode \\ {\tt Vn=} & Set normal Video Attributes \\ {\tt VB=} & Set Bold Video Attributes \\ {\tt Vu=} & Set Underline Video Attributes \\ {\tt Vb=} & Set blink Video Attributes \\ {\tt Vr=} & Set reverse Video Attributes \\ \hline \end{tabular}$$ \end{TeX} .VERSION 1.0 07-Jul-1986: Creation .VERSION 1.1 12-Aug-1986: Added tv_wa, writing a string with attributes. .VERSION 1.2 13-Oct-1986 Some terminals (e.g. HP) need to resend the attribute on each new line. This feature incorporated with ChangedLine flag in standout part of TERM structure. .VERSION 2.0 03-Dec-1986 New terminal-independant with output buffering version. .VERSION 2.1 11-Jun-1987 Version '2' of TermWindows. Defaut input char is Control_Z. Interfaces to xv routines in a seperate module. Batch mode allowed. .VERSION 2.2 23-Jun-1987 Implementation for UNIX and Minimal Version. .VERSION 3.0 20-Mar-1988 Version '3' of TermWindows. ----------------------------------------------------------------------------*/ #define DEBUG 0 /* For debugging */ #define PM_LEVEL LEVEL_TV #define TW_MACROS 0 /* Don't use TermWindows Macros */ #define TW_import 0 #define TW_STRUCT 0 /* Do not use window Structures */ #include MID_EXTERN TERM *terms ; static char special; MID_STATIC char gtr = 1; #define SEND(p) tv_send(p,1) #if DEBUG # define TERMTEST if(!terms->version) tv_gopen();\ tv_ed(terms) #else # define TERMTEST if(!terms->version) tv_gopen() #endif #define ENTER_TV(x) int state_buffer; \ ENTER(x); TERMTEST; \ state_buffer = tv_buffer(1); #define EXIT_TV(f) FIN: \ tv_buffer(state_buffer); \ EXIT(f) /* Macros just to improve readibility */ #define curl (terms->pos[0]) #define curc (terms->pos[1]) #define diml (terms->dim[0]) #define dimc (terms->dim[1]) #define BUFS (terms->bufs) #define Attr (terms->attr) #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 #define IssueCorner(x) { special = CornerChar(x); \ tv_wg(&special, 1); } /* MONITOR (ZTPUT); */ /* CG. status defined locally */ /*========================================================================== * isgr0 *==========================================================================*/ static int isgr0(c) /*+++ .PURPOSE Test non-graphic mode .RETURNS 0 (FALSE) / 1 (TRUE) .REMARKS Not traced --------*/ char c; /* IN: char to test */ { return((c == '+') || (c == '-') || (c == '|') || (c == '~')); } /*===========================================================================*/ static int strupper ( str ) /*+++++++++ .PURPOSE Converts (in place) a string to upper case .RETURNS Length of string --------*/ char *str; /* MOD: starting address */ { register char *p; for (p = str; *p; p++) *p = toupper(*p); return(p-str); } /*========================================================================== * tv_attr *==========================================================================*/ int tv_attr(val) /*+++++++++ .PURPOSE Set attributes for the next output to screen (using tv_write, tv_put or tv_puts) .RETURNS OK / NOK .REMARKS Attributes are defined as numbers to be OR'ed in TERMINAL.H The cursor position remains unchanged. To revert to the normal attributes, use tv_attr with a value of 0. ----------------*/ int val; /* IN: Desired screen attributes */ { char *p; int new, st, k; ENTER_TV("tv_attr"); TRACE_ED_I("Asked attributes: ", val); st = OK; new = val &(_BLINK_|_UNDERSCORE_|_BOLD_|_REVERSE_|_GRAPHICS_); new ^= terms->attr_init; /* Useful only if attr_init is not null */ if (terms->standout & ChangedLine) /* Current Attributes assumed to * have changed. Reissue. */ { terms->standout &= ~ChangedLine; tv_attr((int)terms->attr_init | (new & _GRAPHICS_)); } if(Attr == new) FINISH; /* No change */ k = terms->standout & 7; /* k > 1 means `no or special standout' */ if ((new & _GRAPHICS_) != (Attr & _GRAPHICS_)) { if (new & _GRAPHICS_) p = TTattr[Vg]; else p = TTattr[Va]; if (p) if ( (st = SEND(p)) != OK) FINISH; } /* If only graphics changed, exit now */ if ((new & (~_GRAPHICS_)) == (Attr & (~_GRAPHICS_))) { Attr = new; FINISH; } /* Set first terminal to No Attributes ... */ if (Attr &(~_GRAPHICS_)) { p = TTattr[Vn]; if (p) if_not(st = SEND(p)) FINISH; } Attr = new; /* ... if no other attribute is asked for, exit */ if ((Attr & (~_GRAPHICS_)) == 0) FINISH; /* ... and send successively the asked attributes * However, if no attributes exist at all, not necessary * to search for non-existent capabilities.... */ if(k > 1) FINISH; /* A loop is used for attributes */ for (k=1, new = 1; k <= _REVERSE_; k++, new <<= 1) { if (Attr & new) if_not(st = SEND(TTattr[k])) FINISH; } EXIT_TV(st); } /*========================================================================== * tv_bell *==========================================================================*/ int tv_bell() /* .PURPOSE Ring the terminal bell. .RETURNS OK .REMARKS Use `bl' capability --- or ASCII char `07' if such a capability is not present. -----------------------------------------------------------------------*/ { register char *p; int status; MID_RSTATIC char ascii_bell = '\07'; ENTER_TV("tv_bell"); status = OK; p = SearchCap("bl"); if (!p) p = SearchCap("vb"); if (!p) status = tv_out(&ascii_bell,1); else status = SEND(p); FINISH; EXIT_TV(status); } /*====================================================================== * tv_box *======================================================================*/ int tv_box(topl,topc,boxl,boxc) /*+++ .PURPOSE Draw a box, and position the cursor at top left corner. .RETURNS OK / NOK (impossible) .REMARKS Value of 0 for box dimensions assume all usable space. The cursor does not move if the box cannot be drawn. Negative values for box dimensions mean right / down adjustments. ---*/ int topl; /* IN: Line of upper-left corner (<0 if counted\ from bottom) */ int topc; /* IN: Column of upper-left corner (<0 if counted from right) */ int boxl; /* IN: Line width of box (0 = whole space) */ int boxc; /* IN: Column width of box (0 = whole space) */ { int status; int lh, lv, old_attr; short int b0[2], bd[2]; /* Final position & dimension of box */ ENTER_TV("tv_box"); #if DEBUG TRACE_ED_I("Top line=",topl); TRACE_ED_I("Top col.=",topc); TRACE_ED_I("Ext line=",boxl); TRACE_ED_I("Ext col.=",boxc); #endif b0[0] = topl; b0[1] = topc; bd[0] = boxl; bd[1] = boxc; /* Adjust box dimensions */ status = tv_rb(b0, bd, terms->dim); if (status != OK) FINISH; #if DEBUG TRACE_ED_I("Kept Top line=",topl); TRACE_ED_I("Kept Top col.=",topc); TRACE_ED_I("Kept Ext line=",boxl); TRACE_ED_I("Kept Ext col.=",boxc); #endif old_attr = Attr; tv_attr(old_attr | _GRAPHICS_); /* All in Graphics Mode */ lh = bd[1] - 2; lv = bd[0] -2 ; /* First, write the upperleft corner */ tv_goto(b0[0],b0[1]); IssueCorner(_UPLEFT_); /* Write now first horizontal line */ tv_rule(_RIGHT_,lh); /* Write upperight corner */ IssueCorner(_UPRIGHT_); /* Vertical lines */ tv_goto(b0[0]+1, b0[1] + bd[1] -1); tv_rule(_DOWN_,lv); IssueCorner(_DOWNRIGHT_); tv_goto(b0[0]+1, b0[1]); tv_rule(_DOWN_,lv); IssueCorner(_DOWNLEFT_); /* Bottom horizontal line */ tv_rule(_RIGHT_,lh); /* Reset attributes, and go to top left corner */ tv_attr(old_attr); tv_goto(b0[0]+1, b0[1]+1); EXIT_TV(status); } /*====================================================================== * tv_graph *======================================================================*/ int tv_graph(k) /*+++ .PURPOSE Switch Translate or Not the Graphic Characters. .RETURNS Previous state 0 (False) / 1 (True) .REMARKS ---*/ int k; /* IN: Status FALSE / TRUE */ { register int s; s = gtr; gtr = k; return(s); } /*====================================================================== * tv_gtr *======================================================================*/ static int tv_gtr(str, len) /*+++ .PURPOSE Translate the terminal-independant graphic chars into terminal-dependant graphic characters .RETURNS OK / NOK (there is at leat 1 non-graphic char) .REMARKS *** For Internal Use *** ---*/ char *str; /* MOD: String to translate */ int len; /* IN: Length of str */ { int status; char *p; int i, k; ENTER("tv_gtr"); status = OK; if (gtr) { for (p= str, i=len; --i>=0; p++) { k = *p - 'a'; if ( (k < 0) || ( k >= ITEMS(terms->gchars)) ) k = _RUBBISH_; *p = terms->gchars[k]; if (isgr0(*p)) status = NOK; } } EXIT(status); } /*========================================================================== * tv_line *==========================================================================*/ int tv_line(str, len) /*+++++++++++++++++ .PURPOSE Write a string made of normal characters to the terminal, on a single line. .RETURNS OK / NOK .REMARKS The line is truncated if the right margin would be passed. If the cursor was at the end of the line, issue a new line first. If the terminal is hardcopy and stand-out mode is on, underline. ----------------*/ char *str; /* IN: String to display on the terminal */ int len; /* IN: Length of String */ { int status; register int l, col; register char *p; ENTER_TV("tv_line"); #if DEBUG tv_ed(terms); #endif status = OK; if (len <= 0) FINISH; /* No output */ if(curc >= dimc) tv_nl(); col = curc; p = str; /* Send attributes if necessary */ if (terms->standout & ChangedLine) { l = terms->attr; terms->attr = terms->attr_init; tv_attr(l); } /* Truncate length if necessary */ l = dimc - curc; l = MIN ( l, len); if(Attr) { switch(terms->standout & 7) { case 2: /* Write first the underline, if stand-out mode * --- but not if only Graphics */ if (Attr & (~_GRAPHICS_)) { oscfill(BUFS,l,'_'); status = tv_out(BUFS,l); curc += l; tv_goto(curl,col); /* Go again to required column*/ } default: if (Attr & _GRAPHICS_) /* Translate graphic chars */ { p = BUFS; oscopy(p, str, l); if (tv_gtr(p, l) != OK) /* Note: if some non- */ { while (--l >= 0) /* graph. chars */ { if (isgr0(*p)) tv_attr((int)Attr & ~_GRAPHICS_); else tv_attr((int)Attr | _GRAPHICS_); tv_out(p, 1), p++, curc++; } tv_attr((int)Attr | _GRAPHICS_); FINISH; } } status = tv_out(p, l); break; case 3: /* Change Case - * but not if Graphics! */ p = BUFS; oscopy(p, str, l); if (Attr & _GRAPHICS_) tv_gtr(p, l); else strupper(p); status = tv_out(p, l); break; } } else status = tv_out(p, l); curc += l; EXIT_TV(status); } /*========================================================================== * tv_puts *==========================================================================*/ int tv_puts(str) /*+++++++++ .PURPOSE Write an EOS-terminated string to the terminal, followed by a newline. .RETURNS OK / NOK .REMARKS Control characters are automatically treated. -----------*/ char *str; /* IN: EOS-terminated string to send to the terminal */ { register int s; /* Status */ ENTER_TV("tv_puts"); s = tv_write(str,strlen(str), 1); if (s == OK) s = tv_nl(); FINISH; EXIT_TV(s); } /*====================================================================== * tv_rule *======================================================================*/ int tv_rule(direction, len) /*+++ .PURPOSE Writes a rule, horizontal or vertical .RETURNS OK / NOK .REMARKS Uses the graphic character if it exists. .REMARKS On return, the cursor is just after (at the left, right, up or down depending on the direction) the last issued character ---*/ int direction; /* IN: The direction(_UP_, _LEFT_, etc) of the rule */ int len; /* IN: Rule length, in characters */ { int i, l, dir, old_attr; int status; ENTER_TV("tv_rule"); status = OK; old_attr = Attr; dir = direction; l = len; if (len < 0) /* Change direction */ { dir = 1^direction; l = -len; } l = MIN(l, dimc-curc); /* Not too many ! */ if (l == 0) FINISH; i = dir >> 1; /* Direction horiz./vertical */ if (i > 1) /* Bad direction... */ { status = NOK; ERR_ED_I("Bad rule orientation: ", direction); FINISH; } special = RuleChar(i); /* Get the rule char */ tv_attr(old_attr | _GRAPHICS_); /* Now, issue as many rule characters as required */ while(--l>=0) /* Write char + BS */ { status = tv_line(&special, 1); /* Note, cursor moves right */ if (status != OK) break; if (dir != _RIGHT_) { tv_mvc(_LEFT_,1); tv_mvc(dir,1); } } tv_attr(old_attr); EXIT_TV(status); } /*========================================================================== * tv_write *==========================================================================*/ int tv_write(str, len, opt) /*++++++++++++ .PURPOSE Write a string to the terminal, taking into account control chars or replacing them with "rubbish" characters. .RETURNS OK / NOK .REMARKS If option is non-zero, the \n (newline), \b (backskpace), \r (carriage-return), \f (form-feed) \t (tab) and `Delete' control characters are automatically treated. Other control chars (or all if option is zero) are issued as "rubbish". ---------------*/ char *str; /* IN: String to display on the terminal */ int len; /* IN: Length of String */ int opt; /* IN: 0 to treat control chars, 1 otherwise */ { char *p; int i, l, old_attr; int status; char control_char; MID_RSTATIC char rubbish_char = RubbishChar(); ENTER_TV("tv_write"); status = OK; if (len <= 0) FINISH; /* No output */ TRACE_STR2(str, len); /* Scan the string until a control char is found */ for (p = str, l = len, i = 0; l > 0; p += i, l -= i) { if(curc >= dimc) tv_nl(); i = oscscan(p, l, _CNTRL_, main_ascii); i = MIN(i, dimc - curc); /* Not more than one line */ /* Send the line */ if (i) /* Normal Characters */ { if (!(status = tv_line(p, i))) FINISH; continue; } /* A control char was found ---- Process these chars */ control_char = *p; if (opt == 0) /* Don't process, i.e. replace by something * leading to `default' in following switch */ control_char = EOS; switch(control_char) { case '\n' : /* Start a new line */ tv_nl(); break; case '\r' : /* go to beginning of line */ tv_goto(curl,0); break; case '\f' : /* Clear screen */ tv_clear(_WHOLE_); break; case '\b' : /* backspace */ tv_mvc(_LEFT_,1); break; case DEL : /* delete: bs, then clear cursor */ tv_mvc(_LEFT_,1); tv_cc(1); break; case '\t' : /* Tabs are assumed to be 7,15,etc */ if(curc >= dimc) tv_nl(); /* Output the tab */ if ( (status = tv_line(p, 1)) != OK) FINISH; curc++; while (curc&7) curc++; /* Adjust the cursor position */ break; default : /* Any other control, issue RUBBISH */ old_attr = Attr; tv_attr(old_attr | _GRAPHICS_); status = tv_line(&rubbish_char, 1); tv_attr(old_attr); if (status != OK) FINISH; break; } i = 1; } EXIT_TV (status); } /*========================================================================== * tv_wa *==========================================================================*/ int tv_wa(str, len) /*+++++++++++ .PURPOSE Write a string made of (attribute + char) to the terminal. .RETURNS OK / NOK .REMARKS All control characters are translated to rubbish. ------------*/ ACHAR *str; /* IN: String to display on the terminal */ int len; /* IN: Length of String */ { ACHAR *p; int i, l; char *pc; ACHAR a; char wbuf[81]; int status; ENTER_TV("tv_wa"); status = OK; if (len <= 0) FINISH; /* No output */ TRACE_STR2((char *)str, sizeof(ACHAR)*len); for (p = str, l = len, i = 0; l > 0; l -= i) { a = *p & 0xff00; tv_attr((int)(a >> 8)); for (pc = wbuf, i = MIN(sizeof(wbuf), l); (--i >= 0) && ((*p & 0xff00) == a); p++, pc++) *pc = *p & HIGH; i = pc - wbuf; /* String Length */ if_not(status = tv_write(wbuf,i, 0)) FINISH; } EXIT_TV(status); } /*========================================================================== * tv_wg *==========================================================================*/ int tv_wg(str, len) /*++++++++ .PURPOSE Write graphic characters. .RETURNS OK / NOK .REMARKS All bad chars are translated into rubbish -----------------------------------------------------------------------*/ char *str; /* IN: String to display on the terminal */ int len; /* IN: Length of String */ { int old_attr; int status; ENTER_TV("tv_wg"); TRACE_ED_STR2("Output graphics: ", str, len); old_attr = Attr; tv_attr(old_attr | _GRAPHICS_); status = tv_write(str, len, 0); tv_attr(old_attr); FINISH; EXIT_TV(status); } /*========================================================================== * tv_wsend *==========================================================================*/ int tv_wsend(str,len) /* .PURPOSE Directly passes a string to OS-dependant routines .RETURNS OK / NOK .REMARKS The cursor is assumed not to move ... -----------------------------------------------------------------------*/ char *str; /* IN: String to display on the terminal */ int len; /* IN: Length of String */ { register int s; /* Status */ ENTER_TV("tv_wsend"); s = tv_out(str,len); FINISH; EXIT_TV(s); }