home *** CD-ROM | disk | FTP | other *** search
-
- static char rcsid[] = "@(#)$Id: curses.c,v 4.1.1.3 90/07/12 20:18:02 syd Exp $";
-
- /*******************************************************************************
- * The Elm Mail System - $Revision: 4.1.1.3 $ $State: Exp $
- *
- * Copyright (c) 1986, 1987 Dave Taylor
- * Copyright (c) 1988, 1989, 1990 USENET Community Trust
- *******************************************************************************
- * Bug reports, patches, comments, suggestions should be sent to:
- *
- * Syd Weinstein, Elm Coordinator
- * elm@DSI.COM dsinc!elm
- *
- *******************************************************************************
- * $Log: curses.c,v $
- * Revision 4.1.1.3 90/07/12 20:18:02 syd
- * Be sure that output characters are not negative integers.
- * From: tct!chip@uunet.UU.NET (Chip Salzenberg)
- *
- * Revision 4.1.1.2 90/06/26 20:09:09 syd
- * Add 8 bit support via ascii_ctype
- * From: Robert Claeson <prc@erbe.se>
- *
- * Revision 4.1.1.1 90/06/05 21:05:22 syd
- * Fixes where src/curses.c attempts to set the screen size via the ioctl
- * TIOCGWINSIZ if it exsists. It should only use the row or col size as
- * returned from the ioctl if they are not 0.
- * From: muller%sdcc10@ucsd.edu (Keith Muller)
- *
- * Revision 4.1 90/04/28 22:42:39 syd
- * checkin of Elm 2.3 as of Release PL0
- *
- *
- ******************************************************************************/
-
- /** This library gives programs the ability to easily access the
- termcap information and write screen oriented and raw input
- programs. The routines can be called as needed, except that
- to use the cursor / screen routines there must be a call to
- InitScreen() first. The 'Raw' input routine can be used
- independently, however.
-
- **/
-
- /** NOTE THE ADDITION OF: the #ifndef ELM stuff around routines that
- we don't use. This is for code size and compile time speed...
- **/
-
- #include "headers.h"
-
- #ifdef TERMIOS
- # include <termios.h>
- # if __convex__
- # include <sys/ioctl.h> /* non-standard, for TIOCGWINSZ */
- # endif
- #else
- # ifdef TERMIO
- # include <termio.h>
- # else
- # include <sgtty.h>
- # endif
- #endif
-
- #include <ctype.h>
-
- #ifdef PTEM
- # include <sys/types.h>
- # include <sys/stream.h>
- # include <sys/ptem.h>
- #endif
-
- #ifdef BSD
- #undef tolower
- #endif
-
- #define TTYIN 0
-
- #ifdef SHORTNAMES
- # define _clearinverse _clrinv
- # define _cleartoeoln _clrtoeoln
- # define _cleartoeos _clr2eos
- # define _transmit_off xmit_off
- # define _transmit_on xmit_on
- #endif
-
- #ifdef TERMIOS
- struct termios _raw_tty,
- _original_tty;
- #define ttgetattr(fd,where) tcgetattr((fd),(where))
- #define ttsetattr(fd,where) tcsetattr((fd),TCSADRAIN,(where))
- #else /*TERMIOS*/
- # ifdef TERMIO
- struct termio _raw_tty,
- _original_tty;
- #define ttgetattr(fd,where) ioctl((fd),TCGETA,(where))
- #define ttsetattr(fd,where) ioctl((fd),TCSETAW,(where))
- # else
- struct sgttyb _raw_tty,
- _original_tty;
- #define ttgetattr(fd,where) ioctl((fd),TIOCGETP,(where))
- #define ttsetattr(fd,where) ioctl((fd),TIOCSETP,(where))
- # endif /*TERMIO*/
- #endif /*TERMIOS*/
-
- static int _inraw = 0; /* are we IN rawmode? */
-
- #define DEFAULT_LINES_ON_TERMINAL 24
- #define DEFAULT_COLUMNS_ON_TERMINAL 80
-
- static int _memory_locked = 0; /* are we IN memlock?? */
- static int _line = -1, /* initialize to "trash" */
- _col = -1;
-
- static int _intransmit; /* are we transmitting keys? */
-
- static
- char *_clearscreen, *_moveto, *_up, *_down, *_right, *_left,
- *_setbold, *_clearbold, *_setunderline, *_clearunderline,
- *_sethalfbright, *_clearhalfbright, *_setinverse, *_clearinverse,
- *_cleartoeoln, *_cleartoeos, *_transmit_on, *_transmit_off,
- *_set_memlock, *_clear_memlock, *_initscreen, *_exitscreen;
-
- static int _lines, _columns, _automargin, _eatnewlineglitch, initialized;
- int tabspacing;
-
- static char _terminal[1024]; /* Storage for terminal entry */
- static char _capabilities[1024]; /* String for cursor motion */
-
- static char *ptr = _capabilities; /* for buffering */
-
- int outchar(); /* char output for tputs */
- char *tgetstr(), /* Get termcap capability */
- *tgoto(); /* and the goto stuff */
-
- InitScreen()
- {
- /* Set up all this fun stuff: returns zero if all okay, or;
- -1 indicating no terminal name associated with this shell,
- -2..-n No termcap for this terminal type known
- */
-
- int tgetent(), /* get termcap entry */
- err;
- char termname[40];
- char *strcpy(), *getenv();
-
- if (getenv("TERM") == NULL)
- strcpy(termname, "ansi");
- else
- strcpy(termname, getenv("TERM"));
-
- if ((err = tgetent(_terminal, termname)) != 1)
- return(err-2);
-
- _line = 0; /* where are we right now?? */
- _col = 0; /* assume zero, zero... */
-
- /* load in all those pesky values */
- _initscreen = tgetstr("ti", &ptr);
- _exitscreen = tgetstr("te", &ptr);
- _clearscreen = tgetstr("cl", &ptr);
- _moveto = tgetstr("cm", &ptr);
- _up = tgetstr("up", &ptr);
- _down = tgetstr("do", &ptr);
- _right = tgetstr("nd", &ptr);
- _left = tgetstr("bs", &ptr);
- _setbold = tgetstr("so", &ptr);
- _clearbold = tgetstr("se", &ptr);
- _setunderline = tgetstr("us", &ptr);
- _clearunderline = tgetstr("ue", &ptr);
- _setinverse = tgetstr("so", &ptr);
- _clearinverse = tgetstr("se", &ptr);
- _sethalfbright = tgetstr("hs", &ptr);
- _clearhalfbright = tgetstr("he", &ptr);
- _cleartoeoln = tgetstr("ce", &ptr);
- _cleartoeos = tgetstr("cd", &ptr);
- _lines = tgetnum("li");
- _columns = tgetnum("co");
- tabspacing = ((tabspacing=tgetnum("it"))==-1 ? 8 : tabspacing);
- _automargin = tgetflag("am");
- _eatnewlineglitch = tgetflag("xn");
- _transmit_on = tgetstr("ks", &ptr);
- _transmit_off = tgetstr("ke", &ptr);
- _set_memlock = tgetstr("ml", &ptr);
- _clear_memlock = tgetstr("mu", &ptr);
-
-
- if (!_left) {
- _left = "\b";
- }
-
- tputs(_initscreen, 1, outchar);
- fflush(stdout);
- initialized = 1;
-
- return(0);
- }
-
- ExitScreen()
- {
- if ( initialized )
- {
- tputs(_exitscreen, 1, outchar);
- fflush(stdout);
- }
- }
-
- char *return_value_of(termcap_label)
- char *termcap_label;
- {
- /** This will return the string kept by termcap for the
- specified capability. Modified to ensure that if
- tgetstr returns a pointer to a transient address
- that we won't bomb out with a later segmentation
- fault (thanks to Dave@Infopro for this one!)
-
- Tweaked to remove padding sequences.
- **/
-
- static char escape_sequence[20];
- register int i=0,j=0;
- char buffer[20];
- char *myptr, *tgetstr(); /* Get termcap capability */
-
- if (strlen(termcap_label) < 2)
- return(NULL);
-
- if (termcap_label[0] == 's' && termcap_label[1] == 'o')
- {
- if (_setinverse)
- strcpy(escape_sequence, _setinverse);
- else
- return( (char *) NULL );
- }
- else if (termcap_label[0] == 's' && termcap_label[1] == 'e')
- {
- if (_clearinverse)
- strcpy(escape_sequence, _clearinverse);
- else
- return( (char *) NULL );
- }
- else if ((myptr = tgetstr(termcap_label, &ptr)) == NULL)
- return( (char *) NULL );
- else
- strcpy(escape_sequence, myptr);
-
- if (chloc(escape_sequence, '$') != -1) {
- while (escape_sequence[i] != '\0') {
- while (escape_sequence[i] != '$' && escape_sequence[i] != '\0')
- buffer[j++] = escape_sequence[i++];
- if (escape_sequence[i] == '$') {
- while (escape_sequence[i] != '>') i++;
- i++;
- }
- }
- buffer[j] = '\0';
- strcpy(escape_sequence, buffer);
- }
-
- return( (char *) escape_sequence);
- }
-
- transmit_functions(newstate)
- int newstate;
- {
- /** turn function key transmission to ON | OFF **/
-
- if (newstate != _intransmit) {
- _intransmit = ! _intransmit;
- if (newstate == ON)
- tputs(_transmit_on, 1, outchar);
- else
- tputs(_transmit_off, 1, outchar);
- fflush(stdout); /* clear the output buffer */
- }
- }
-
- /****** now into the 'meat' of the routines...the cursor stuff ******/
-
- ScreenSize(lines, columns)
- int *lines, *columns;
- {
- /** returns the number of lines and columns on the display. **/
-
- #ifdef OS2
- _ScreenSize(&_lines, &_columns);
- #endif
- #ifdef TIOCGWINSZ
- struct winsize w;
-
- if (ioctl(1,TIOCGWINSZ,&w) != -1) {
- if (w.ws_row > 0)
- _lines = w.ws_row;
- if (w.ws_col > 0)
- _columns = w.ws_col;
- }
- #endif
-
- if (_lines == 0) _lines = DEFAULT_LINES_ON_TERMINAL;
- if (_columns == 0) _columns = DEFAULT_COLUMNS_ON_TERMINAL;
-
- *lines = _lines - 1; /* assume index from zero */
- *columns = _columns;
- }
-
- SetXYLocation(x,y)
- int x,y;
- {
- /* declare where the cursor is on the screen - useful after using
- * a function that moves cursor in predictable fasion but doesn't
- * set the static x and y variables used in this source file -
- * e.g. getpass().
- */
-
- _line = x;
- _col = y;
- }
-
- GetXYLocation(x,y)
- int *x,*y;
- {
- /* return the current cursor location on the screen */
-
- *x = _line;
- *y = _col;
- }
-
- ClearScreen()
- {
- /* clear the screen: returns -1 if not capable */
-
- _line = 0; /* clear leaves us at top... */
- _col = 0;
-
- if (!_clearscreen)
- return(-1);
-
- tputs(_clearscreen, 1, outchar);
- fflush(stdout); /* clear the output buffer */
- return(0);
- }
-
- static
- CursorUp(n)
- int n;
- {
- /** move the cursor up 'n' lines **/
- /** Calling function must check that _up is not null before calling **/
-
- _line = (_line-n > 0? _line - n: 0); /* up 'n' lines... */
-
- while (n-- > 0)
- tputs(_up, 1, outchar);
-
- fflush(stdout);
- return(0);
- }
-
-
- static
- CursorDown(n)
- int n;
- {
- /** move the cursor down 'n' lines **/
- /** Caller must check that _down is not null before calling **/
-
- _line = (_line+n <= LINES? _line + n: LINES); /* down 'n' lines... */
-
- while (n-- > 0)
- tputs(_down, 1, outchar);
-
- fflush(stdout);
- return(0);
- }
-
-
- static
- CursorLeft(n)
- int n;
- {
- /** move the cursor 'n' characters to the left **/
- /** Caller must check that _left is not null before calling **/
-
- _col = (_col - n> 0? _col - n: 0); /* left 'n' chars... */
-
- while (n-- > 0)
- tputs(_left, 1, outchar);
-
- fflush(stdout);
- return(0);
- }
-
-
- static
- CursorRight(n)
- int n;
- {
- /** move the cursor 'n' characters to the right (nondestructive) **/
- /** Caller must check that _right is not null before calling **/
-
- _col = (_col+n < COLUMNS? _col + n: COLUMNS); /* right 'n' chars... */
-
- while (n-- > 0)
- tputs(_right, 1, outchar);
-
- fflush(stdout);
- return(0);
- }
-
- static
- moveabsolute(col, row)
- {
-
- char *stuff, *tgoto();
-
- stuff = tgoto(_moveto, col, row);
- tputs(stuff, 1, outchar);
- fflush(stdout);
- }
-
- MoveCursor(row, col)
- int row, col;
- {
- /** move cursor to the specified row column on the screen.
- 0,0 is the top left! **/
-
- int scrollafter = 0;
-
- /* we don't want to change "rows" or we'll mangle scrolling... */
-
- if (col < 0)
- col = 0;
- if (col >= COLUMNS)
- col = COLUMNS - 1;
- if (row < 0)
- row = 0;
- if (row > LINES) {
- if (col == 0)
- scrollafter = row - LINES;
- row = LINES;
- }
-
- if (!_moveto)
- return(-1);
-
- if (row == _line) {
- if (col == _col)
- return(0); /* already there! */
-
- else if (abs(col - _col) < 5) { /* within 5 spaces... */
- if (col > _col && _right)
- CursorRight(col - _col);
- else if (col < _col && _left)
- CursorLeft(_col - col);
- else
- moveabsolute(col, row);
- }
- else /* move along to the new x,y loc */
- moveabsolute(col, row);
- }
- else if (_line == row-1 && col == 0) {
- if (_col != 0)
- putchar('\r');
- putchar('\n');
- fflush(stdout);
- }
- else if (col == _col && abs(row - _line) < 5) {
- if (row < _line && _up)
- CursorUp(_line - row);
- else if (row > _line && _down)
- CursorDown(row - _line);
- else
- moveabsolute(col, row);
- }
- else
- moveabsolute(col, row);
-
- _line = row; /* to ensure we're really there... */
- _col = col;
-
- if (scrollafter) {
- putchar('\r');
- while (scrollafter--)
- putchar('\n');
- }
-
- return(0);
- }
-
- CarriageReturn()
- {
- /** move the cursor to the beginning of the current line **/
- Writechar('\r');
- }
-
- NewLine()
- {
- /** move the cursor to the beginning of the next line **/
-
- Writechar('\r');
- Writechar('\n');
- }
-
- StartBold()
- {
- /** start boldface/standout mode **/
-
- if (!_setbold)
- return(-1);
-
- tputs(_setbold, 1, outchar);
- fflush(stdout);
- return(0);
- }
-
-
- EndBold()
- {
- /** compliment of startbold **/
-
- if (!_clearbold)
- return(-1);
-
- tputs(_clearbold, 1, outchar);
- fflush(stdout);
- return(0);
- }
-
- #ifndef ELM
-
- StartUnderline()
- {
- /** start underline mode **/
-
- if (!_setunderline)
- return(-1);
-
- tputs(_setunderline, 1, outchar);
- fflush(stdout);
- return(0);
- }
-
-
- EndUnderline()
- {
- /** the compliment of start underline mode **/
-
- if (!_clearunderline)
- return(-1);
-
- tputs(_clearunderline, 1, outchar);
- fflush(stdout);
- return(0);
- }
-
-
- StartHalfbright()
- {
- /** start half intensity mode **/
-
- if (!_sethalfbright)
- return(-1);
-
- tputs(_sethalfbright, 1, outchar);
- fflush(stdout);
- return(0);
- }
-
- EndHalfbright()
- {
- /** compliment of starthalfbright **/
-
- if (!_clearhalfbright)
- return(-1);
-
- tputs(_clearhalfbright, 1, outchar);
- fflush(stdout);
- return(0);
- }
-
- StartInverse()
- {
- /** set inverse video mode **/
-
- if (!_setinverse)
- return(-1);
-
- tputs(_setinverse, 1, outchar);
- fflush(stdout);
- return(0);
- }
-
-
- EndInverse()
- {
- /** compliment of startinverse **/
-
- if (!_clearinverse)
- return(-1);
-
- tputs(_clearinverse, 1, outchar);
- fflush(stdout);
- return(0);
- }
-
- int
- HasMemlock()
- {
- /** returns TRUE iff memory locking is available (a terminal
- feature that allows a specified portion of the screen to
- be "locked" & not cleared/scrolled... **/
-
- return ( _set_memlock && _clear_memlock );
- }
-
- static int _old_LINES;
-
- int
- StartMemlock()
- {
- /** mark the current line as the "last" line of the portion to
- be memory locked (always relative to the top line of the
- screen) Note that this will alter LINES so that it knows
- the top is locked. This means that (plus) the program
- will scroll nicely but (minus) End memlock MUST be called
- whenever we leave the locked-memory part of the program! **/
-
- if (! _set_memlock)
- return(-1);
-
- if (! _memory_locked) {
-
- _old_LINES = LINES;
- LINES -= _line; /* we can't use this for scrolling */
-
- tputs(_set_memlock, 1, outchar);
- fflush(stdout);
- _memory_locked = TRUE;
- }
-
- return(0);
- }
-
- int
- EndMemlock()
- {
- /** Clear the locked memory condition... **/
-
- if (! _set_memlock)
- return(-1);
-
- if (_memory_locked) {
- LINES = _old_LINES; /* back to old setting */
-
- tputs(_clear_memlock, 1, outchar);
- fflush(stdout);
- _memory_locked = FALSE;
- }
- return(0);
- }
-
- #endif /* ndef ELM */
-
- Writechar(ch)
- register int ch;
- {
- /** write a character to the current screen location. **/
-
- static int wrappedlastchar = 0;
- int justwrapped, nt;
-
- ch &= 0xFF;
- justwrapped = 0;
-
- /* if return, just go to left column. */
- if(ch == '\r') {
- if (wrappedlastchar)
- justwrapped = 1; /* preserve wrap flag */
- else {
- putchar('\r');
- _col = 0;
- }
- }
-
- /* if newline and terminal just did a newline without our asking,
- * do nothing, else output a newline and increment the line count */
- else if (ch == '\n') {
- if (!wrappedlastchar) {
- putchar('\n');
- if (_line < LINES)
- ++_line;
- }
- }
-
- /* if backspace, move back one space if not already in column 0 */
- else if (ch == BACKSPACE) {
- if(_col != 0) {
- putchar('\b');
- _col--;
- } /* else BACKSPACE does nothing */
- }
-
- /* if bell, ring the bell but don't advance the column */
- else if (ch == '\007') {
- putchar(ch);
- }
-
- /* if a tab, output it */
- else if (ch == '\t') {
- putchar(ch);
- if((nt=next_tab(_col+1)) > prev_tab(COLUMNS))
- _col = COLUMNS-1;
- else
- _col = nt-1;
- }
-
- else {
- /* if some kind of non-printable character change to a '?' */
- #ifdef ASCII_CTYPE
- if(!isascii(ch) || !isprint(ch))
- #else
- if(!isprint(ch))
- #endif
- ch = '?';
-
- /* if we only have one column left, simulate automargins if
- * the terminal doesn't have them */
- if (_col == COLUMNS - 1) {
- putchar(ch);
- if (!_automargin || _eatnewlineglitch) {
- putchar('\r');
- putchar('\n');
- }
- if (_line < LINES)
- ++_line;
- _col = 0;
- justwrapped = 1;
- }
-
- /* if we are here this means we have no interference from the
- * right margin - just output the character and increment the
- * column position. */
- else {
- putchar(ch);
- _col++;
- }
- }
-
- wrappedlastchar = justwrapped;
-
- return(0);
- }
-
- /*VARARGS2*/
-
- Write_to_screen(line, argcount, arg1, arg2, arg3)
- char *line;
- int argcount;
- char *arg1, *arg2, *arg3;
- {
- /** This routine writes to the screen at the current location.
- when done, it increments lines & columns accordingly by
- looking for "\n" sequences... **/
-
- switch (argcount) {
- case 0 :
- PutLine0(_line, _col, line);
- break;
- case 1 :
- PutLine1(_line, _col, line, arg1);
- break;
- case 2 :
- PutLine2(_line, _col, line, arg1, arg2);
- break;
- case 3 :
- PutLine3(_line, _col, line, arg1, arg2, arg3);
- break;
- }
- }
-
- PutLine0(x, y, line)
- int x,y;
- register char *line;
- {
- /** Write a zero argument line at location x,y **/
-
- MoveCursor(x,y);
- while(*line)
- Writechar(*line++);
- fflush(stdout);
- }
-
- /*VARARGS2*/
- PutLine1(x,y, line, arg1)
- int x,y;
- char *line;
- char *arg1;
- {
- /** write line at location x,y - one argument... **/
-
- char buffer[VERY_LONG_STRING];
-
- sprintf(buffer, line, arg1);
-
- PutLine0(x, y, buffer);
- fflush(stdout);
- }
-
- /*VARARGS2*/
- PutLine2(x,y, line, arg1, arg2)
- int x,y;
- char *line;
- char *arg1, *arg2;
- {
- /** write line at location x,y - one argument... **/
-
- char buffer[VERY_LONG_STRING];
-
- sprintf(buffer, line, arg1, arg2);
-
- PutLine0(x, y, buffer);
- fflush(stdout);
- }
-
- /*VARARGS2*/
- PutLine3(x,y, line, arg1, arg2, arg3)
- int x,y;
- char *line;
- char *arg1, *arg2, *arg3;
- {
- /** write line at location x,y - one argument... **/
-
- char buffer[VERY_LONG_STRING];
-
- sprintf(buffer, line, arg1, arg2, arg3);
-
- PutLine0(x, y, buffer);
- fflush(stdout);
- }
-
- CleartoEOLN()
- {
- /** clear to end of line **/
-
- if (!_cleartoeoln)
- return(-1);
-
- tputs(_cleartoeoln, 1, outchar);
- fflush(stdout); /* clear the output buffer */
- return(0);
- }
-
- CleartoEOS()
- {
- /** clear to end of screen **/
-
- if (!_cleartoeos)
- #ifdef OS2
- {
- int i;
- printf("\033[s\033[K");
- for ( i = _line + 1; i < _lines; i++ )
- printf("\033[%d;1H\033[K", i + 1);
- printf("\033[u");
- fflush(stdout);
- }
- #else
- return(-1);
- #endif
-
- tputs(_cleartoeos, 1, outchar);
- fflush(stdout); /* clear the output buffer */
- return(0);
- }
-
-
- RawState()
- {
- /** returns either 1 or 0, for ON or OFF **/
-
- return( _inraw );
- }
-
- Raw(state)
- int state;
- {
- /** state is either ON or OFF, as indicated by call **/
-
- if (state == OFF && _inraw) {
- (void) ttsetattr(TTYIN,&_original_tty);
- _inraw = 0;
- #ifdef OS2
- setmode(1, O_TEXT);
- #endif
- }
- else if (state == ON && ! _inraw) {
-
- (void) ttgetattr(TTYIN, &_original_tty);
- (void) ttgetattr(TTYIN, &_raw_tty); /** again! **/
-
- #if !defined(TERMIO) && !defined(TERMIOS)
- _raw_tty.sg_flags &= ~(ECHO); /* echo off */
- _raw_tty.sg_flags |= CBREAK; /* raw on */
- #else
- _raw_tty.c_lflag &= ~(ICANON | ECHO); /* noecho raw mode */
-
- _raw_tty.c_cc[VMIN] = '\01'; /* minimum # of chars to queue */
- _raw_tty.c_cc[VTIME] = '\0'; /* minimum time to wait for input */
-
- #endif
- (void) ttsetattr(TTYIN, &_raw_tty);
- _inraw = 1;
- #ifdef OS2
- setmode(1, O_BINARY);
- #endif
- }
- }
-
- #ifdef OS2
- char cbuffer[1024];
- int cbufsize;
-
- tflush()
- {
- if ( cbufsize ) {
- write(1, cbuffer, cbufsize);
- cbufsize = 0;
- }
- }
- #endif
-
- int
- ReadCh()
- {
- /** read a character with Raw mode set! **/
-
- register int result;
- char ch;
- #ifdef OS2
- tflush();
- return readkey();
- #else
- result = read(0, &ch, 1);
- return((result <= 0 ) ? EOF : ch);
- #endif
- }
-
- outchar(c)
- char c;
- {
- /** output the given character. From tputs... **/
- /** Note: this CANNOT be a macro! **/
-
- #ifdef OS2
- cbuffer[cbufsize++] = c;
-
- if ( cbufsize == sizeof(cbuffer) )
- tflush();
- #else
- putc(c, stdout);
- #endif
- }
-
-