/* @(#)twout.c 17.1.1.1 (ES0-DMD) 01/25/02 17:48:07 */ /*=========================================================================== 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 twout.c .AUTHOR Francois Ochsenbein [ESO-IPG] .LANGUAGE C .KEYWORDS Window Management .ENVIRONMENT TermWindows .COMMENTS This module contains routines to perform output on windows. \begin{TeX} \end{TeX} .VERSION 1.0 18-Aug-1986: Creation .VERSION 2.0 03-Dec-1986 New terminal-independant graphic characters with output buffering version. .VERSION 2.1 29-Jun-1987: Extracted from Full Version SM_ZUOUT + .VERSION 2.2 04-Dec-1987: For Usage with Proteus: if a window is Removed and Active, which should normally be incompatible, the window is Refreshed. .VERSION 3.0 20-Mar-1988: Version '3' .VERSION 3.1 12-Dec-1988: SetAttr(_ATTRIBUTE_) takes attribute of Cursor. (but without graphic) .VERSION 3.2 20-Feb-1989: SetAttr returns Previous Attribute .VERSION 3.3 31-Mar-1989: Added tw_wa (Write Achars). Corrected tw_line .VERSION 3.4 16-Jun-1989: Corrected Bug in tw_write (don't limit between markers...) .VERSION 3.5 29-Jun-1989: Added tw_rule, tw_mrule .VERSION 3.6 08-Mar-1990: Modified tw_r (Refresh) .VERSION 3.7 28-May-1990: Allow tw_out for hard terminals .VERSION 3.8 06-Sep-1990: Corrected bug in tw_box (bad box output). Also, corrected tw_attr which was bad when Window = Screen .VERSION 3.9 28-Nov-1990: Keep current attribute in tw_write even when SI / SO (shift in/out) are used. --------------------------*/ #define DEBUG 0 /* For debugging only */ #define PM_LEVEL LEVEL_TW #define TW_import 0 /* Do not use macro window definitions */ #include #include MID_EXTERN WINDOW *Screen; #if DEBUG #define ed_level 3 #define ENTER_DEBUG(x) ENTER(x) #define EXIT_DEBUG(x) EXIT(x) #define DISPLAY(opt) tw_ed(w,opt) #else #define DISPLAY(opt) #define ENTER_DEBUG(x) #define EXIT_DEBUG(x) return(x) #endif static int J; static char hard_term = 0; /* Used by tw_out */ MONITOR(TWOUT); /*========================================================================== * tw_attr *==========================================================================*/ int tw_attr(w, val) /*+++ .PURPOSE Set attributes for the next output to window .RETURNS The previous Attribute. .REMARKS Attributes are defined as numbers to be OR'ed in termdef.h. The cursor position remains unchanged. The _ATTRIBUTE_ definition asks for the attribute of the current cursor position. Note that the asked attributes are XOR'ed with the initial attributes, to ensure that a not-null `val' parameter will result in some `stand-out' mode. ---*/ WINDOW *w; /* MOD: The window concerned */ int val; /* IN: Desired screen attributes */ { register int new_attr, old_attr, line; ENTER_TW("tw_attr"); CheckScreen(w); DISPLAY(0); TRACE_ED_I("Asked attributes: ", val); old_attr = w->attr; if (val == _ATTRIBUTE_) /* Take the attribute of the Cursor */ { J = w->Nj; line = w->pos/J; if (line >= w->Ni) line = w->Ni - 1; new_attr = (*Aij(w, line, w->pos%J))&0xff00 | ' '; new_attr &= ~(_GRAPHICS_<<8); } else new_attr = val & (_GRAPHICS_|_BOLD_|_UNDERSCORE_|_BLINK_|_REVERSE_), new_attr = (new_attr << 8) ^ w->attr_init; if ((w->active) && (Screen->attr != new_attr)) { Screen->attr = new_attr; SetAttr((new_attr) >> 8); } old_attr = (int)(w->attr_init^old_attr)>>8 ; w->attr = new_attr; DISPLAY(0); EXIT_TW(old_attr); } /*====================================================================== * tw_box *======================================================================*/ int tw_box(w,topl,topc,boxl,boxc) /*+++ .PURPOSE Draw a box on a window (with current attribute) and position the cursor at top left corner. .RETURNS OK / NOK (impossible) .REMARKS Value of 0 for box dimensions assume all usable space in the window. The cursor does not move if the box cannot be drawn. ---*/ WINDOW *w; /* MOD: The window concerned */ int topl; /* IN: Line of upper-left corner (<0 for bottom adj.) */ int topc; /* IN: Col. of upper-left corner (<0 for right adj.) */ int boxl; /* IN: Line width of box (0 for complete, <0 for Centered) */ int boxc; /* IN: Col. width of box (0 for complete, <0 for Centered) */ { short int wh[2], wd[2]; /* Final position & dimension of box */ ENTER_TWA("tw_box"); #if DEBUG TRACE_ED_STR2("Window =",w->id, 8); 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 wh[0] = topl; wh[1] = topc; wd[0] = boxl; wd[1] = boxc; /* Adjust box dimensions */ if_not(status = CheckBox(wh, wd, w->dim)) Return; if ((wd[0] < 2) || (wd[1] < 2)) { ERR_ED_STR2("Box requires more space on Window ", w->id, 8); status = NOK; Return; } #if DEBUG TRACE_ED_I("Kept Top line=",wh[0]); TRACE_ED_I("Kept Top col.=",wh[1]); TRACE_ED_I("Kept Ext line=",wd[0]); TRACE_ED_I("Kept Ext col.=",wd[1]); #endif /* Vertical Lines */ tw_goto(w, wh[0], wh[1]), tw_rule(w, _DOWN_, wd[0]); tw_goto(w, wh[0], wh[1] + wd[1]-1), tw_rule(w, _DOWN_, wd[0]); /* Horizontal Lines */ tw_goto(w, wh[0], wh[1]), tw_rule(w, _RIGHT_, wd[1]); tw_goto(w, wh[0] + wd[0]-1, wh[1]), tw_rule(w, _RIGHT_, wd[1]); /* Position Cursor */ tw_goto(w, wh[0]+1, wh[1] + 1); DISPLAY(1); EXIT_TWA(status); } /*====================================================================== * tw_rule *======================================================================*/ static ACHAR modtee(achar, pa) /*+++ .PURPOSE Transforms Tee symbol into correct one. .RETURNS Correct .REMARKS ---*/ ACHAR achar; /* IN: The Tee character */ ACHAR *pa[4]; /* IN: Neighbour characters */ { ACHAR attr, new; int k, i, n, x; static char cc[4] = { CornerChar(_UPLEFT_), CornerChar(_UPRIGHT_), CornerChar(_DOWNLEFT_),CornerChar(_DOWNRIGHT_)}; attr = achar & 0xff00; new = achar & 0x00ff; k = new - TeeChar(0); /* Convert Tee */ for (i = k^2, n = 2; (--n >= 0) && ((int)new >= TeeChar(0)); i ^= 1) { if(isGraphic(*pa[i])) { x = (*pa[i] & 0x00ff); if (x == CornerChar(_CROSS_)) continue; if (x == RuleChar(i>>1)) continue; if (x != TeeChar(i^1)) continue; } if (k > i) x = k, k = i, i = x; x = (k<<1) | (i-2); new = cc[x]; break; } if ((int)new >= TeeChar(0)) /* Still a tee... */ { i = k^1; /* Char to look for */ n = i >> 1; if(isGraphic(*pa[i])) { x = (*pa[i] & 0x00ff); if (x == CornerChar(_CROSS_)) goto _Found; if (x == RuleChar(n)) goto _Found; if (x != TeeChar(i)) goto _Found; } new = RuleChar(1^n); } _Found: return(new | attr); } static ACHAR modcross(achar, pa) /*+++ .PURPOSE Transforms symbol into coorect one. .RETURNS Correct .REMARKS ---*/ ACHAR achar; /* IN: The graphic character */ ACHAR *pa[4]; /* IN: Neighbour characters */ { ACHAR attr, new; int k, i, x; static char allowed_corner[4][2] = { { _UPLEFT_ , _UPRIGHT_ }, /* for UP */ { _DOWNLEFT_, _DOWNRIGHT_}, /* for DOWN */ { _UPLEFT_ , _DOWNLEFT_ }, /* for LEFT */ { _UPRIGHT_ , _DOWNRIGHT_}, /* for RIGHT */ }; attr = achar & 0xff00; new = achar & 0x00ff; if (new != CornerChar(_CROSS_)) return(modtee(achar, pa)); /* Convert Cross */ for (k = 0; (k < 4) && (new == CornerChar(_CROSS_)); k++) { if(isGraphic(*pa[k])) { x = (*pa[k] & 0x00ff); if (x == CornerChar(_CROSS_)) continue; if (x == RuleChar(k>>1)) continue; if (x == CornerChar(allowed_corner[k][0])) continue; if (x == CornerChar(allowed_corner[k][1])) continue; } new = TeeChar(k); break; } if (k <= 1) new = modtee(new, pa); /* Convert Tee */ return(new | attr); } /*==========================================================================*/ int tw_rule(w, direction, len) /*+++ .PURPOSE Writes a rule, horizontal or vertical .RETURNS OK .REMARKS Uses the graphic character if it exists. .REMARKS The cursor moves ONLY if _RIGHT_. ---*/ WINDOW *w; /* MOD: The window concerned */ int direction; /* IN: The direction(_UP_, _LEFT_, etc) of the rule */ int len; /* IN: Rule length, in characters */ { int i, l, lls, x, dpos, dir; short apos[2], incr[2], lim[2]; int status; ACHAR or_attr, special, cross, adda, *pa, *pan[4]; char cc, crule; static ACHAR ab = ' '; ENTER_TWA("tw_rule"); status = OK; /* Keep current window Attributes for Box Drawing */ or_attr = (w->attr & (~HIGH)) | Agraphic; dir = direction; l = len; if (len < 0) /* Change direction */ { dir = 1^direction; l = -len; } lls = l; i = dir >> 1; /* Direction horiz./vertical */ if (i > 1) dir = _RIGHT_, i = 0; /* Default: Horizontal... */ incr[0] = 0, incr[1] = 0, incr[i] = (dir & 1 ? 1 : -1); crule = RuleChar(i); special = crule | or_attr; /* Get the rule char */ cross = CornerChar(_CROSS_) | or_attr; x = w->pos; apos[0] = x / w->dim[1], apos[1] = x % w->dim[1]; dpos = (dir != _RIGHT_ ); /* Cursor Movement at end */ for (; (--l >= 0) && (apos[i] >= 0) && (apos[i] < w->dim[i]); apos[i] += incr[i]) { x = apos[0] * w->dim[1] + apos[1]; pa = Aij(w, apos[0], apos[1]); adda = 0; cc = *pa & 0xff; if (cc == ' ') adda = special; else if (isGraphic(*pa)) adda = (cc == crule ? special : cross); if (adda) tw_fill(w, x, 1, adda); if (dir == _RIGHT_) dpos += 1; } /* Now, reorganize the corners */ x = w->pos; apos[0] = x / w->dim[1], apos[1] = x % w->dim[1]; lim[0] = w->dim[0] - 1; lim[1] = w->dim[1] - 1; for (l = lls; (--l >= 0) && (apos[i] >= 0) && (apos[i] < w->dim[i]); apos[i] += incr[i]) { pa = Aij(w, apos[0], apos[1]); adda = *pa; if(*pa != cross) continue; pan[_UP_] = (apos[0] > 0 ? Aij(w, apos[0]-1, apos[1]) : &ab); pan[_LEFT_] = (apos[1] > 0 ? Aij(w, apos[0], apos[1]-1) : &ab); pan[_DOWN_] = (apos[0] < lim[0] ? Aij(w, apos[0]+1, apos[1]) : &ab); pan[_RIGHT_] = (apos[1] < lim[1] ? Aij(w, apos[0], apos[1]+1) : &ab); adda = modcross(*pa, pan); if (adda != *pa) tw_fill(w, apos[0] * w->dim[1] + apos[1], 1, adda); } w->pos += dpos; if (w->pos >= w->marker[1]) w->pos = w->marker[1] - 1; EXIT_TWA(status); } /*==========================================================================*/ int tw_mrule(w, len) /*+++ .PURPOSE Modifies the rule at current line. .RETURNS OK .REMARKS Useful to terminate a table. On return, cursor on beginning of next line. ---*/ WINDOW *w; /* MOD: The window concerned */ int len; /* IN: Length to look for */ { int i, j, l; short lim[2]; int status; ACHAR adda, *pa, *pan[4]; static ACHAR ab = ' '; ENTER_TWA("tw_mrule"); status = OK; lim[0] = w->dim[0] - 1, lim[1] = w->dim[1] - 1; i = w->pos / w->dim[1]; /* Line to Modify */ j = w->pos % w->dim[1]; /* Col to Modify */ /* Now, reorganize the corners */ for (l = len; (--l >= 0) && (j <= lim[1]); j++, w->pos += 1) { pa = Aij(w, i, j); if_not(isGraphic(*pa)) continue; adda = *pa & 0x00ff; if((int)adda < CornerChar(_CROSS_)) continue; pan[_UP_] = (i > 0 ? Aij(w, i-1, j) : &ab); pan[_LEFT_] = (j > 0 ? Aij(w, i, j-1) : &ab); pan[_DOWN_] = (i < lim[0] ? Aij(w, i+1, j) : &ab); pan[_RIGHT_] = (j < lim[1] ? Aij(w, i, j+1) : &ab); adda = modcross(*pa, pan); if (adda != *pa) tw_fill(w, i * w->dim[1] + j, 1, adda); } w->pos = (i+1)*w->dim[1]; /* Next Line */ if (w->pos >= w->marker[1]) w->pos = w->marker[1] - 1; EXIT_TWA(status); } /*========================================================================== * tw_cline *==========================================================================*/ int tw_cline(w, str, len) /*+++ .PURPOSE Write a string at current location, truncating the text if it is too long to stand on the current line, and adding blanks before / after to have it centered. .RETURNS Length of output string .REMARKS The string is output to the screen if the window is active. Non-printable chars are translated to Rubbish. ---*/ WINDOW *w; /* MOD: Window concerned */ char *str; /* IN: String to output */ int len; /* IN: String length */ { int l, nb, old_pos; ENTER_TWA("+tw_cline"); TRACE_STR2(str,len); old_pos = w->pos; l = w->Nj - w->pos % w->Nj; /* Remaining length in line */ if (l < 1) FINISH; if (len > l) len = l; nb = (l-len)/2; /* Leading blanks */ tw_fill(w, w->pos, nb, w->attr); w->pos += nb; tw_line(w, str, len); nb = (l-len) - nb; /* Trailing blanks */ tw_fill(w, w->pos, nb, w->attr); w->pos += nb; EXIT_TWA(w->pos - old_pos); } /*========================================================================== * tw_line *==========================================================================*/ int tw_line(w, str, len) /*+++ .PURPOSE Write a string at current location, truncating the text if it is too long to stand on the current line. .RETURNS Length of output string .REMARKS The string is output to the screen if the window is active. Non-printable chars are translated to Rubbish. ---*/ WINDOW *w; /* MOD: Window concerned */ char *str; /* IN: String to output */ int len; /* IN: String length */ { register ACHAR *p; int l, i, j; LINE *lm0, *lm1; ACHAR a, new; int chars[2]; ENTER_TWA("+tw_line"); /* First, copy text to window memory */ status = 0; /* Default returned length */ if (len <= 0) FINISH; DISPLAY(0); TRACE_STR2(str,len); J = w->Nj, i = w->pos/J, j = w->pos%J; l = w->Nj - j; /* Remaining length in line */ if (l > len) l = len; if (l < 1) FINISH; status = l; w->flags &= (~Clear); /* Window not more clear ... */ /* Don't forget the Imode possibility ... */ if(w->imode) { tw_chars(w, chars); tw_copw(w, w->pos + l, w, w->pos, chars[1]-l); } w->pos += l; /* Copy the text to memory, with running attribute ... * Take care of control chars! */ a = w->attr & (~HIGH); p = Aij(w, i, j); lm0 = &M0(w, i); lm1 = &M1(w, i); for (; --l >=0; p++, str++) { if (iscntrl(*str)) new = RubbishAchar(); else new = *str; new |= a; if (*p != new) *p = new, *lm0 = MIN(p, *lm0), *lm1 = MAX(p, *lm1); } DISPLAY(0); /* Output to screen if active */ EXIT_TWA(status); } /*========================================================================== * tw_mattr *==========================================================================*/ int tw_mattr(w, len, attr) /*+++ .PURPOSE Modify attribute from current cursor position over specified length to a new attribute. .RETURNS Length of text which was modified. .REMARKS Current attribute does not change; the cursor is moved to the end of the modified text. ---*/ WINDOW *w; /* MOD: Window concerned */ int len; /* IN: Length of text to modify */ int attr; /* IN: New attribute. */ { ACHAR blank; int l, n; ENTER_TWA("tw_mattr"); blank = ((attr & (_BOLD_|_UNDERSCORE_|_BLINK_|_REVERSE_)) << 8) ^ w->attr_init; l = w->pos + len; n = w->dim[0] * w->dim[1]; if (l > n) l = n; l = tw_uattr(w, w->pos, l - w->pos, blank) - w->pos; w->pos += l; EXIT_TWA(l); } /*========================================================================== * tw_mw *==========================================================================*/ int tw_mw(w, hl, hc) /*+++ .PURPOSE Move a window to a new Home Position .RETURNS OK / NOK .METHOD Remove first, then raise it. .REMARKS Operation performed on parent window, if it's a subwindow. ---*/ WINDOW *w; /* MOD: Window concerned */ int hl; /* IN: New home line (<0 for position from bottom) */ int hc; /* IN: New home column (<0 for position from right edge) */ { WINDOW *wp; int k, not_removed; short int h[2]; ENTER_TW("tw_mw"); if_not(w) FINISH; /* Can't move the Screen ! */ h[0] = hl; h[1] = hc; wp = Parent(w); if(wp) /* Move the Parent Window... */ { for (k=0; k<2; k++) if (h[k]>=0) h[k] = MAX(h[k]-w->home[k], 0); } else wp = w; not_removed = wp->flags & Present; if (not_removed) tw_uw(wp, 4, NULL_WINDOW); /* Remove Window */ for (k=0; k<2; k++) { if (h[k] < 0) h[k] = MAX(h[k] + Screen->dim[k], 0); h[k] = MIN(h[k], Screen->dim[k] - wp->dim[k]); wp->home[k] = h[k]; } tw_flags(wp); if (not_removed) tw_r(wp, 1, NULL_WINDOW); /* Raise Window */ EXIT_TW(OK); } /*========================================================================== * tw_out *==========================================================================*/ static int tw_out(i, j, str, len) /*+++ .PURPOSE Ouput to screen, at (absolute) position [i,j], the `string' str; .RETURNS OK / NOK .REMARKS Not user-callable. Optimization of space outputs. ---*/ int i; /* IN: Absolute output line */ int j; /* IN: Absolute output column */ ACHAR *str; /* IN: String to display on the terminal */ int len; /* IN: Length of String */ { ACHAR *p0, *p1; ACHAR a; int l; unsigned char done, right_clear; ENTER_DEBUG("tw_out"); if (len <= 0) FINISH; /* No output */ done = 0; a = Screen->attr_init; p0 = str, p1 = p0 + len; /* Skip leading blanks --- only useful if j=0 ! */ if ((j == 0) && (!hard_term)) { for ( ; (p0 < p1) && (*p0 == a); p0++) ; l = p0 - str; /* Number of leading blanks */ /* Use ClearLine if full line empty */ if ( (p0 == p1) && (l == Screen->Nj) ) { CursorTo(i, 0); ClearLine(); FINISH; } /* Use Clear Left function if more than 5 leading blanks */ if(l>5) { CursorTo(i, l-1), done = 1; ClearLeft(); /* Clear chars at left of cursor (inclusive) */ CursorRight(1); j = l; } else p0 = str; } l = p1 - p0; if (l <= 0) FINISH; /* Line full of blanks */ /* Set Cursor to its correct position */ if_not(done) CursorTo(i,j); right_clear = 0; /* Right part of screen is to be cleared */ /* SetAttr( (*p0)>>8); Made by WriteAchars */ /* Count trailing blanks --- if right adjusted! */ if ((l+j) == Screen->Nj) { while ( (p1 > p0) && (*(--p1) == a) ) right_clear = 1; l = ++p1 - p0; } /* Output text between leading & trailing blanks */ if (l) status = WriteAchars(p0, l); /* Clear right part of Screen */ if (right_clear) ClearRight(); FIN: EXIT_DEBUG(status); } /*========================================================================== * tw_puts *==========================================================================*/ int tw_puts(w, str) /*+++ .PURPOSE Write an EOS-terminated string at current location on specified window, followed by a new line .RETURNS OK / NOK .REMARKS The physical output is only done after inclusion of all text in memory ... if the window is active! ---*/ WINDOW *w; /* MOD: Window concerned */ char *str; /* IN: String to output */ { ENTER_TWA("tw_puts"); /* If Hardware Scrolling is possible, use it */ if (w->hw & Scroll) { w->flags |= state_echo; state_echo = 0; } tw_write(w, str, strlen(str), 1); status = tw_nl(w); EXIT_TWA(status); } /*========================================================================== * tw_r *==========================================================================*/ int tw_r(wx, option, prev) /*+++ .PURPOSE Ouput (refresh) a window with following options: \begin{TeX} \begin{itemize} \item 0: Output only last modifications of a window \item 1: Output whole window \item 2, 3: without reporting the locations of modified chars on Screen \item 4: Remove Window \item 8: Place Window at a specific location \end{itemize} \end{TeX} .RETURNS OK .REMARKS An option of zero only writes modified part of a window; an option of 1 repaint completely the window. Up / Down physical clear not used. Removing a window also deactivates it. ---*/ WINDOW *wx; /* MOD: Window concerned */ int option; /* IN: Option to repaint window */ WINDOW *prev; /* IN: place window just after */ { WINDOW *w, *wl; LINE *lx, *l0, *l1; int long l; int i, opt; char state_clear; ENTER_TW("tw_r"); DISPLAY(0); w = wx; CheckScreen(w); opt = option; hard_term = (Screen->hw & TERM_hard) && ((w->flags & _DISPLAY_) || (opt&1)); if (hard_term) opt |= 16; wl = (opt & 8 ? prev : NULL_WINDOW); /* Move to Parent Window, if it's a subwindow */ if (Parent(w)) tw_upw(w), w = Parent(w); /* Clear Completely the Screen for RefreshScreen */ if ( (w == Screen) && (opt & 1) && (w->hw & Clear) ) ClearScreen(); /* Put Window on Top if Refresh, and * Update Screen Cursor and Attributes */ if (w != Screen) { if (opt & 4) { opt |= 8; /* Will be linked to bottom */ if_not(w->flags & Present) FINISH; /* Already removed */ tw_st(w, Present|Echo, 0); /* Not more present */ } else { tw_st(w, Present, 1); /* if_not(wx->flags & _DISPLAY_) */ tw_uc(w); } if (opt & 1) { opt |= 8; /* A new link will be performed */ if_not (wl) wl = Previous(Screen); } } else if (opt & 4) /* Remove All Windows */ { for (w = Next(Screen); w != Screen; w = Next(w)) tw_st(w, Present|Echo, 0); Screen->pos = 0; /* Cursor at Home */ } if_not(wl) wl = Screen; tw_uw(w, opt, wl); /* Copy window to screen */ state_clear = Screen->clear; if (state_clear) ClearScreen(); for (i=0, lx=ALine(Screen), l0 = Am0(Screen), l1 = Am1(Screen); iNi; i++, lx++, l0++, l1++) { l = *l1 - *l0 + 1; if (l<=0 || l> 512) continue; if (!state_clear) tw_out(i, *l0 - *lx, *l0, l); *l0 = *lx + Screen->Nj; *l1 = NULL_ACHAR; } SetPosition(Screen->pos); SetAttr((Screen->attr) >> 8); EXIT_TW(status); } /*========================================================================== * tw_write *==========================================================================*/ int tw_write(w, str, len, opt) /*+++ .PURPOSE Write a string at current location, interpreting the control characters (opt != 0) or replacing them by rubbish (opt == 0), and wrap text if necessary. .RETURNS Number of characters effectively written before reaching the window bottom. .REMARKS The physical output is only done after inclusion of all text in memory ... if the window is active! Control chars that cannot be interpretated are output as the `Rubbish' character. ---*/ WINDOW *w; /* MOD: Window concerned */ char *str; /* IN: String to output */ int len; /* IN: String length */ int opt; /* IN: non-zero to interpret control chars */ { char *p; int l, i, j, n, old_attr; char *p_end; MID_STATIC char tab[9] = " ";/* Dealing with tabs */ MID_STATIC char control_char = EOS; #define Agraph (_GRAPHICS_ << 8) ENTER_TWA("+tw_write"); /* First, copy to text to window */ if (len <= 0) Return; TRACE_STR2(str,len); DISPLAY(0); J = w->Nj; n = w->dim[0]*w->dim[1]; old_attr = _NORMAL_; /* If Hardware Scrolling is possible, use it */ if (w->hw & Scroll) { w->flags |= state_echo; state_echo = 0; } for ( p = str, p_end = p + len; (p < p_end) && status; p += i) { if (w->pos >= n) { if (w->flags&Scroll) tw_nl(w); else { status = NOK; break; } /* Bottom reached */ } j = w->pos%J; l = MIN(p_end-p, J - j); l = MIN(l, n - w->pos); if (l <= 0) break; /* Search first control char */ i = oscspan(p, l, _PRINT_, main_ascii); tw_line(w, p, i), j += i; if (i == l) continue; /* Only normal characters... */ /* Here only if a control char is encountered */ control_char = *(p++ + i); 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': status = tw_nl(w); break; case '\r': tw_goto(w, w->pos/J, 0); break; case '\f': tw_clear(w, _WHOLE_); break; case '\b': tw_mvc(w, _LEFT_, 1); break; case DEL: tw_dc(w,-1); break; case SI : old_attr = tw_attr(w, _UNDERSCORE_); break; case SO : tw_attr(w, old_attr); break; case '\t': l = 8 - ((j + w->j0) & 7); if (j + l >= J) status = tw_nl(w); else tw_line(w,tab,l); break; case 07: Bell(); break; default : tw_line(w, &control_char, 1); break; } } DISPLAY(0); EXIT_TWA(p-str); } /*========================================================================== * tw_wa *==========================================================================*/ int tw_wa(w, astr, len) /*+++ .PURPOSE Write, at current location, the ACHAR string .RETURNS Number of characters effectively written before reaching the window bottom. .REMARKS Cursor position not modified. ---*/ WINDOW *w; /* MOD: Window concerned */ ACHAR *astr; /* IN: ACHAR string */ int len; /* IN: Number of `characters' */ { int n; ENTER_TWA("tw_wa"); n = w->dim[0]*w->dim[1] - w->pos; n = MIN(len, n); if (n < 0) n = 0; tw_copy(w, w->pos, astr, n); EXIT_TWA(n); } /*========================================================================== * tw_wf *==========================================================================*/ int tw_wf(w, ch, len) /*+++ .PURPOSE Write, at current location, the character ch repeated len times. .RETURNS Number of characters effectively written before reaching the window bottom. .REMARKS Control characters are output as rubbish. ---*/ WINDOW *w; /* MOD: Window concerned */ int ch; /* IN: Fill character */ int len; /* IN: Number of fill characters to issue*/ { ACHAR a; int n; ENTER_TWA("tw_wf"); a = (w->attr & 0xff00) | (ch & 0xff); n = w->dim[0]*w->dim[1]- w->pos; n = MIN(len, n); if (n < 0) n = 0; tw_fill(w, w->pos, n, a); EXIT_TWA(n); } #if 0 /* Useless... */ /*========================================================================== * tw_wt *==========================================================================*/ int tw_wt(w, direction, len) /*+++ .PURPOSE Write a rule (horizontal / vertical) from current position in the specified (_UP_, _DOWN_, _LEFT_, RIGHT_) direction. .RETURNS Number of rule chars effectively written .REMARKS The rule is truncated if margins would be passed. Cursor and Attributes don't move. ---*/ WINDOW *w; /* MOD: Window concerned */ int direction; /* IN: Rule direction */ int len; /* IN: Length of the rule */ { int i, j, J, k, n; int incr; ACHAR special; #define Agraph (_GRAPHICS_ << 8) ENTER_TWA("tw_wt"); /* Test good direction: take RIGHT as default */ J = w->Nj; i = w->pos / J, j = w->pos % J; switch(direction) { default: direction = _RIGHT_; case _RIGHT_: n = J - j; break; case _LEFT_: n = j + 1; break; case _UP_: n = i + 1; break; case _DOWN_: n = w->Ni - i; break; } if (n > len) n = len; if (n <= 0) Return; special = (w->attr & ~HIGH) | Agraphic; if (direction&2) /* Horizontal */ { special |= RuleChar(_HORIZONTAL_); i = w->pos; if_not(direction & 1) i -= (n-1); tw_fill(w, i, special, n); } else /* Vertical */ { special |= RuleChar(_VERTICAL_); i = w->pos; if_not(direction & 1) i -= (n-1)*J; for (j=n; --j>=0; i += J) tw_fill(w, i, special, 1); } EXIT_TWA(n); } #endif