v23i072: TRN, version of RN that follows conversation threads, Part13/14

Rich Salz rsalz at bbn.com
Tue Dec 4 07:28:23 AEST 1990


Submitted-by: Wayne Davison <davison at dri.com>
Posting-number: Volume 23, Issue 72
Archive-name: trn/part13

---- Cut Here and unpack ----
#!/bin/sh
# this is part 13 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file rthreads.c continued
#
CurArch=13
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
     exit 1; fi
( read Scheck
  if test "$Scheck" != $CurArch
  then echo "Please unpack part $Scheck next!"
       exit 1;
  else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file rthreads.c"
sed 's/^X//' << 'SHAR_EOF' >> rthreads.c
X	printf( "\n\nRead failed for thread data -- continuing unthreaded.\n" );
X	fclose( fp_in );
X	bzero( &total, sizeof (TOTAL) );
X	return 0;
X    }
X    lp_bmap( &total.first, 4 );
X    wp_bmap( &total.root, 5 );
X
X    if( !read_item( &author_cnts, (MEM_SIZE)total.author * sizeof (WORD) )
X     || !read_item( &strings, (MEM_SIZE)total.string1 ) 
X     || !read_item( &subject_cnts, (MEM_SIZE)total.subject * sizeof (WORD) )
X     || !read_item( &p_roots, (MEM_SIZE)total.root * sizeof (PACKED_ROOT) )
X     || !read_item( &p_articles, (MEM_SIZE)total.article * sizeof (PACKED_ARTICLE) ) ) {
X	printf( "\n\nRead failed for thread data -- continuing unthreaded.\n" );
X	fclose( fp_in );
X	unuse_data( 0 );
X	return 0;
X    }
X    fclose( fp_in );
X
X    if( !word_same || !long_same ) {
X	wp_bmap( author_cnts, total.author );
X	wp_bmap( subject_cnts, total.subject );
X	for( i = 0; i < total.root; i++ ) {
X	    lp_bmap( &p_roots[i].root_num, 1 );
X	    wp_bmap( &p_roots[i].articles, 3 );
X	}
X	for( i = 0; i < total.article; i++ ) {
X	    lp_bmap( &p_articles[i].num, 2 );
X	    wp_bmap( &p_articles[i].subject, 8 );
X	}
X    }
X
X#ifndef lint
X    author_ptrs = (char **)safemalloc( total.author * sizeof (char **) );
X    subject_ptrs = (char **)safemalloc( total.subject * sizeof (char **) );
X    root_subjects = (WORD *)safemalloc( total.root * sizeof (WORD) );
X    root_article_cnts = (WORD *)safemalloc( total.root * sizeof (WORD) );
X#endif
X    selected_roots = safemalloc( total.root * sizeof (char) );
X
X    bzero( root_article_cnts, total.root * sizeof (WORD) );
X    bzero( selected_roots, total.root * sizeof (char) );
X
X    for( i = 0, ptr = strings; i < total.author; i++ ) {
X	author_ptrs[i] = ptr;
X	ptr += strlen( ptr ) + 1;
X    }
X
X    for( i = 0, j = 0; i < total.root; i++ ) {
X	root_subjects[i] = j;
X	k = p_roots[i].subject_cnt;
X	while( k-- ) {
X	    root_article_cnts[i] += subject_cnts[j];
X	    subject_ptrs[j++] = ptr;
X	    ptr += strlen( ptr ) + 1;
X	}
X	if( saved_selections ) {
X	    for( k = 0; k < selected_root_cnt; k++ ) {
X		if( p_roots[i].root_num == saved_selections[k] ) {
X		    selected_roots[i] = 1;
X		}
X	    }
X	}
X    }
X    count_roots( !saved_selections );
X    Free( &saved_selections );
X    select_page = 0;
X    return 1;
X}
X
X/* A short-hand for reading a chunk of the file into a malloced array.
X*/
Xstatic int
Xread_item( dest, len )
Xchar **dest;
XMEM_SIZE len;
X{
X    int ret;
X
X    *dest = safemalloc( len );
X    ret = fread( *dest, 1, (int)len, fp_in );
X    if( ret != len ) {
X	free( *dest );
X	*dest = Nullch;
X	return 0;
X    }
X    return 1;
X}
X
X/* Free some memory if it hasn't already been freed.
X*/
Xstatic void
XFree( pp )
Xchar **pp;
X{
X    if( *pp ) {
X	free( *pp );
X	*pp = Nullch;
X    }
X}
X
X/* Discard the thread data that we received through the use_data() call.
X** If "save_selections" is non-zero, we'll try to remember which roots
X** are currently selected long enough for the use_data() call to re-use
X** them.  Only do this when you are going to re-open the same data file
X** immediately with use_data() (presumably because the data has been
X** updated while we were using it).
X*/
Xvoid
Xunuse_data( save_selections )
Xbool save_selections;
X{
X    int i, j;
X
X    if( save_selections ) {
X#ifndef lint
X	saved_selections
X	  = (ART_NUM *)safemalloc( selected_root_cnt * sizeof (ART_NUM) );
X#endif
X	for( i = 0, j = 0; i < total.root; i++ ) {
X	    if( selected_roots[i] && root_article_cnts[i] ) {
X		saved_selections[j++] = p_roots[i].root_num;
X	    }
X	}
X    } else {
X	selected_root_cnt = selected_count = 0;
X    }
X    Free( &p_roots );
X    Free( &root_subjects );
X    Free( &author_cnts );
X    Free( &subject_cnts );
X    Free( &author_ptrs );
X    Free( &subject_ptrs );
X    Free( &root_article_cnts );
X    Free( &selected_roots );
X    Free( &p_articles );
X    Free( &strings );
X
X    p_art = curr_p_art = Nullart;
X    init_tree();		/* free any tree lines */
X
X    bzero( &total, sizeof (TOTAL) );
X}
X
X/* Transform each WORD's byte-ordering in a buffer of the designated length.
X*/
Xstatic void
Xwp_bmap( buf, len )
XWORD *buf;
Xint len;
X{
X    union {
X	BYTE b[sizeof (WORD)];
X	WORD w;
X    } in, out;
X    register int i;
X
X    if( word_same ) {
X	return;
X    }
X    while( len-- ) {
X	in.w = *buf;
X	for( i = 0; i < sizeof (WORD); i++ ) {
X	    out.b[my_bmap.w[i]] = in.b[mt_bmap.w[i]];
X	}
X	*buf++ = out.w;
X    }
X}
X
X/* Transform each LONG's byte-ordering in a buffer of the designated length.
X*/
Xstatic void
Xlp_bmap( buf, len )
XLONG *buf;
Xint len;
X{
X    union {
X	BYTE b[sizeof (LONG)];
X	LONG l;
X    } in, out;
X    register int i;
X
X    if( long_same ) {
X	return;
X    }
X    while( len-- ) {
X	in.l = *buf;
X	for( i = 0; i < sizeof (LONG); i++ ) {
X	    out.b[my_bmap.l[i]] = in.b[mt_bmap.l[i]];
X	}
X	*buf++ = out.l;
X    }
X}
X
X#endif /* USETHREADS */
SHAR_EOF
echo "File rthreads.c is complete"
chmod 0660 rthreads.c || echo "restore of rthreads.c fails"
echo "x - extracting rthreads.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > rthreads.h &&
X/* $Header: rthreads.h,v 4.3.3.1 90/06/20 22:56:01 davison Trn $
X**
X** $Log:	rthreads.h,v $
X** Revision 4.3.3.1  90/06/20  22:56:01  davison
X** Initial Trn Release
X** 
X*/
X
X#include "threads.h"
X
XEXT TOTAL total;
X
XEXT PACKED_ROOT *p_roots INIT(0);
XEXT WORD *root_subjects INIT(0);
XEXT WORD *author_cnts INIT(0);
XEXT WORD *subject_cnts INIT(0);
XEXT char **author_ptrs INIT(0);
XEXT char **subject_ptrs INIT(0);
XEXT PACKED_ARTICLE *p_articles INIT(0);
XEXT WORD *root_article_cnts INIT(0);
XEXT char *selected_roots INIT(0);
XEXT ART_NUM *saved_selections INIT(0);
XEXT bool unread_selector INIT(0);
X
XEXT PACKED_ARTICLE *p_art INIT(0);
XEXT PACKED_ARTICLE *curr_p_art INIT(0);
XEXT PACKED_ARTICLE *recent_p_art INIT(0);
X
XEXT int selected_root_cnt INIT(0);
XEXT ART_NUM selected_count INIT(0);
XEXT int unthreaded INIT(0);
XEXT int select_page;
XEXT bool scan_all_roots;
X
XEXT bool word_same, long_same;
XEXT BMAP my_bmap, mt_bmap;
X
Xvoid thread_init(), mybytemap();
Xchar *thread_name(), *safemalloc();
Xint use_data();
Xvoid unuse_data();
Xvoid find_article(), init_tree(), entire_tree();
Xint tree_puts(), finish_tree();
Xvoid first_art(), follow_thread(), next_root(), prev_root();
Xchar select_thread();
Xint count_roots(), count_one_root();
XPACKED_ARTICLE *upper_limit();
X
X#define Nullart Null(PACKED_ARTICLE*)
SHAR_EOF
chmod 0660 rthreads.h || echo "restore of rthreads.h fails"
echo "x - extracting search.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > search.c &&
X/* $Header: search.c,v 4.3.2.2 90/03/22 23:05:31 sob Exp $
X *
X * $Log:	search.c,v $
X * Revision 4.3.2.2  90/03/22  23:05:31  sob
X * Fixes provided by Wayne Davison <drivax!davison>
X * 
X * Revision 4.3.2.1  90/03/17  17:46:29  sob
X * Added changes to insure that null search strings won't result in core dumps
X * on non-VAX computers.
X * 
X * Revision 4.3  85/05/01  11:50:16  lwall
X * Baseline for release with 4.3bsd.
X * 
X */
X
X/* string search routines */
X 
X/*		Copyright (c) 1981,1980 James Gosling		*/
X 
X/* Modified Aug. 12, 1981 by Tom London to include regular expressions
X   as in ed.  RE stuff hacked over by jag to correct a few major problems,
X   mainly dealing with searching within the buffer rather than copying
X   each line to a separate array.  Newlines can now appear in RE's */
X
X/* Ripped to shreds and glued back together to make a search package,
X * July 6, 1984, by Larry Wall. (If it doesn't work, it's probably my fault.)
X * Changes include:
X *	Buffer, window, and mlisp stuff gone.
X *	Translation tables reduced to 1 table.
X *	Expression buffer is now dynamically allocated.
X *	Character classes now implemented with a bitmap.
X */
X
X#include "EXTERN.h"
X#include "common.h"
X#include "util.h"
X#include "INTERN.h"
X#include "search.h"
X
X#ifndef BITSPERBYTE
X#define BITSPERBYTE 8
X#endif
X
X#define BMAPSIZ (127 / BITSPERBYTE + 1)
X
X/* meta characters in the "compiled" form of a regular expression */
X#define	CBRA	2		/* \( -- begin bracket */
X#define	CCHR	4		/* a vanilla character */
X#define	CDOT	6		/* . -- match anything except a newline */
X#define	CCL	8		/* [...] -- character class */
X#define	NCCL	10		/* [^...] -- negated character class */
X#define	CDOL	12		/* $ -- matches the end of a line */
X#define	CEND	14		/* The end of the pattern */
X#define	CKET	16		/* \) -- close bracket */
X#define	CBACK	18		/* \N -- backreference to the Nth bracketed
X				   string */
X#define CIRC	20		/* ^ matches the beginning of a line */
X
X#define WORD	32		/* matches word character \w */
X#define NWORD	34		/* matches non-word characer \W */
X#define WBOUND	36		/* matches word boundary \b */
X#define NWBOUND	38		/* matches non-(word boundary) \B */
X 
X#define	STAR	01		/* * -- Kleene star, repeats the previous
X				   REas many times as possible; the value
X				   ORs with the other operator types */
X 
X#define ASCSIZ 0200
Xtypedef char	TRANSTABLE[ASCSIZ];
X
Xstatic	TRANSTABLE trans = {
X0000,0001,0002,0003,0004,0005,0006,0007,
X0010,0011,0012,0013,0014,0015,0016,0017,
X0020,0021,0022,0023,0024,0025,0026,0027,
X0030,0031,0032,0033,0034,0035,0036,0037,
X0040,0041,0042,0043,0044,0045,0046,0047,
X0050,0051,0052,0053,0054,0055,0056,0057,
X0060,0061,0062,0063,0064,0065,0066,0067,
X0070,0071,0072,0073,0074,0075,0076,0077,
X0100,0101,0102,0103,0104,0105,0106,0107,
X0110,0111,0112,0113,0114,0115,0116,0117,
X0120,0121,0122,0123,0124,0125,0126,0127,
X0130,0131,0132,0133,0134,0135,0136,0137,
X0140,0141,0142,0143,0144,0145,0146,0147,
X0150,0151,0152,0153,0154,0155,0156,0157,
X0160,0161,0162,0163,0164,0165,0166,0167,
X0170,0171,0172,0173,0174,0175,0176,0177,
X};
Xstatic bool folding = FALSE;
X
Xstatic int err;
Xstatic char *FirstCharacter;
X
Xvoid
Xsearch_init()
X{
X#ifdef UNDEF
X    register int    i;
X    
X    for (i = 0; i < ASCSIZ; i++)
X	trans[i] = i;
X#else
X    ;
X#endif
X}
X
Xvoid
Xinit_compex(compex)
Xregister COMPEX *compex;
X{
X    /* the following must start off zeroed */
X
X    compex->eblen = 0;
X    compex->brastr = Nullch;
X}
X
Xvoid
Xfree_compex(compex)
Xregister COMPEX *compex;
X{
X    if (compex->eblen) {
X	free(compex->expbuf);
X	compex->eblen = 0;
X    }
X    if (compex->brastr) {
X	free(compex->brastr);
X	compex->brastr = Nullch;
X    }
X}
X
Xstatic char *gbr_str = Nullch;
Xstatic int gbr_siz = 0;
X
Xchar *
Xgetbracket(compex,n)
Xregister COMPEX *compex;
Xint n;
X{
X    int length = compex->braelist[n] - compex->braslist[n];
X
X    if (!compex->nbra || n > compex->nbra || !compex->braelist[n] || length<0)
X	return nullstr;
X    growstr(&gbr_str, &gbr_siz, length+1);
X    safecpy(gbr_str, compex->braslist[n], length+1);
X    return gbr_str;
X}
X
Xvoid
Xcase_fold(which)
Xint which;
X{
X    register int i;
X
X    if (which != folding) {
X	if (which) {
X	    for (i = 'A'; i <= 'Z'; i++)
X		trans[i] = tolower(i);
X	}
X	else {
X	    for (i = 'A'; i <= 'Z'; i++)
X		trans[i] = i;
X	}
X	folding = which;
X    }
X}
X
X/* Compile the given regular expression into a [secret] internal format */
X
Xchar *
Xcompile (compex, strp, RE, fold)
Xregister COMPEX *compex;
Xregister char   *strp;
Xint RE;
Xint fold;
X{
X    register int c;
X    register char  *ep;
X    char   *lastep;
X    char    bracket[NBRA],
X	   *bracketp;
X    char **alt = compex->alternatives;
X    char *retmes = "Badly formed search string";
X 
X    case_fold(compex->do_folding = fold);
X    if (!compex->eblen) {
X	compex->expbuf = safemalloc(84);
X	compex->eblen = 80;
X    }
X    ep = compex->expbuf;		/* point at expression buffer */
X    *alt++ = ep;			/* first alternative starts here */
X    bracketp = bracket;			/* first bracket goes here */
X    if (*strp == 0) {			/* nothing to compile? */
X	if (*ep == 0)			/* nothing there yet? */
X	    return "Null search string";
X	return Nullch;			/* just keep old expression */
X    }
X    compex->nbra = 0;			/* no brackets yet */
X    lastep = 0;
X    for (;;) {
X	if (ep - compex->expbuf >= compex->eblen)
X	    grow_eb(compex);
X	c = *strp++;			/* fetch next char of pattern */
X	if (c == 0) {			/* end of pattern? */
X	    if (bracketp != bracket) {	/* balanced brackets? */
X#ifdef VERBOSE
X		retmes = "Unbalanced parens";
X#endif
X		goto cerror;
X	    }
X	    *ep++ = CEND;		/* terminate expression */
X	    *alt++ = 0;			/* terminal alternative list */
X	    /*
X	    compex->eblen = ep - compex->expbuf + 1;
X	    compex->expbuf = saferealloc(compex->expbuf,compex->eblen+4); */
X	    return Nullch;		/* return success */
X	}
X	if (c != '*')
X	    lastep = ep;
X	if (!RE) {			/* just a normal search string? */
X	    *ep++ = CCHR;		/* everything is a normal char */
X	    *ep++ = c;
X	}
X	else				/* it is a regular expression */
X	    switch (c) {
X 
X		case '\\':		/* meta something */
X		    switch (c = *strp++) {
X		    case '(':
X			if (compex->nbra >= NBRA) {
X#ifdef VERBOSE
X			    retmes = "Too many parens";
X#endif
X			    goto cerror;
X			}
X			*bracketp++ = ++compex->nbra;
X			*ep++ = CBRA;
X			*ep++ = compex->nbra;
X			break;
X		    case '|':
X			if (bracketp>bracket) {
X#ifdef VERBOSE
X			    retmes = "No \\| in parens";	/* Alas! */
X#endif
X			    goto cerror;
X			}
X			*ep++ = CEND;
X			*alt++ = ep;
X			break;
X		    case ')':
X			if (bracketp <= bracket) {
X#ifdef VERBOSE
X			    retmes = "Unmatched right paren";
X#endif
X			    goto cerror;
X			}
X			*ep++ = CKET;
X			*ep++ = *--bracketp;
X			break;
X		    case 'w':
X			*ep++ = WORD;
X			break;
X		    case 'W':
X			*ep++ = NWORD;
X			break;
X		    case 'b':
X			*ep++ = WBOUND;
X			break;
X		    case 'B':
X			*ep++ = NWBOUND;
X			break;
X		    case '0': case '1': case '2': case '3': case '4':
X		    case '5': case '6': case '7': case '8': case '9':
X			*ep++ = CBACK;
X			*ep++ = c - '0';
X			break;
X		    default:
X			*ep++ = CCHR;
X			if (c == '\0')
X			    goto cerror;
X			*ep++ = c;
X			break;
X		    }
X		    break;
X		case '.':
X		    *ep++ = CDOT;
X		    continue;
X 
X		case '*':
X		    if (lastep == 0 || *lastep == CBRA || *lastep == CKET
X			|| *lastep == CIRC
X			|| (*lastep&STAR)|| *lastep>NWORD)
X			goto defchar;
X		    *lastep |= STAR;
X		    continue;
X 
X		case '^':
X		    if (ep != compex->expbuf && ep[-1] != CEND)
X			goto defchar;
X		    *ep++ = CIRC;
X		    continue;
X 
X		case '$':
X		    if (*strp != 0 && (*strp != '\\' || strp[1] != '|'))
X			goto defchar;
X		    *ep++ = CDOL;
X		    continue;
X 
X		case '[': {		/* character class */
X		    register int i;
X		    
X		    if (ep - compex->expbuf >= compex->eblen - BMAPSIZ)
X			grow_eb(compex);	/* reserve bitmap */
X		    for (i = BMAPSIZ; i; --i)
X			ep[i] = 0;
X		    
X		    if ((c = *strp++) == '^') {
X			c = *strp++;
X			*ep++ = NCCL;	/* negated */
X		    }
X		    else
X			*ep++ = CCL;	/* normal */
X		    
X		    i = 0;		/* remember oldchar */
X		    do {
X			if (c == '\0') {
X#ifdef VERBOSE
X			    retmes = "Missing ]";
X#endif
X			    goto cerror;
X			}
X			if (*strp == '-' && *(++strp))
X			    i = *strp++;
X			else
X			    i = c;
X			while (c <= i) {
X			    ep[c / BITSPERBYTE] |= 1 << (c % BITSPERBYTE);
X			    if (fold && isalpha(c))
X				ep[(c ^ 32) / BITSPERBYTE] |=
X				    1 << ((c ^ 32) % BITSPERBYTE);
X					/* set the other bit too */
X			    c++;
X			}
X		    } while ((c = *strp++) != ']');
X		    ep += BMAPSIZ;
X		    continue;
X		}
X 
X	    defchar:
X		default:
X		    *ep++ = CCHR;
X		    *ep++ = c;
X	    }
X    }
Xcerror:
X    compex->expbuf[0] = 0;
X    compex->nbra = 0;
X    return retmes;
X}
X
Xvoid
Xgrow_eb(compex)
Xregister COMPEX *compex;
X{
X    compex->eblen += 80;
X    compex->expbuf = saferealloc(compex->expbuf, (MEM_SIZE)compex->eblen + 4);
X}
X
Xchar *
Xexecute (compex, addr)
Xregister COMPEX *compex;
Xchar *addr;
X{
X    register char *p1 = addr;
X    register char *trt = trans;
X    register int c;
X 
X    if (addr == Nullch || compex->expbuf == Nullch)
X	return Nullch;
X    if (compex->nbra) {			/* any brackets? */
X	for (c = 0; c <= compex->nbra; c++)
X	    compex->braslist[c] = compex->braelist[c] = Nullch;
X	if (compex->brastr)
X	    free(compex->brastr);
X	compex->brastr = savestr(p1);	/* in case p1 is not static */
X	p1 = compex->brastr;		/* ! */
X    }
X    case_fold(compex->do_folding);	/* make sure table is correct */
X    FirstCharacter = p1;		/* for ^ tests */
X    if (compex->expbuf[0] == CCHR && !compex->alternatives[1]) {
X	c = trt[compex->expbuf[1]];	/* fast check for first character */
X	do {
X	    if (trt[*p1] == c && advance (compex, p1, compex->expbuf))
X		return p1;
X	    p1++;
X	} while (*p1 && !err);
X	return Nullch;
X    }
X    else {			/* regular algorithm */
X	do {
X	    register char **alt = compex->alternatives;
X	    while (*alt) {
X		if (advance (compex, p1, *alt++))
X		    return p1;
X	    }
X	    p1++;
X	} while (*p1 && !err);
X	return Nullch;
X    }
X}
X 
X/* advance the match of the regular expression starting at ep along the
X   string lp, simulates an NDFSA */
Xbool
Xadvance (compex, lp, ep)
Xregister COMPEX *compex;
Xregister char *ep;
Xregister char *lp;
X{
X    register char *curlp;
X    register char *trt = trans;
X    register int i;
X 
X    while ((*ep & STAR) || *lp || *ep == CIRC || *ep == CKET)
X	switch (*ep++) {
X 
X	    case CCHR:
X		if (trt[*ep++] != trt[*lp]) return FALSE;
X		lp++;
X		continue;
X 
X	    case CDOT:
X		if (*lp == '\n') return FALSE;
X		lp++;
X		continue;
X 
X	    case CDOL:
X		if (!*lp || *lp == '\n')
X		    continue;
X		return FALSE;
X 
X	    case CIRC:
X		if (lp == FirstCharacter || lp[-1]=='\n')
X		    continue;
X		return FALSE;
X 
X	    case WORD:
X		if (isalnum(*lp)) {
X		    lp++;
X		    continue;
X		}
X		return FALSE;
X 
X	    case NWORD:
X		if (!isalnum(*lp)) {
X		    lp++;
X		    continue;
X		}
X		return FALSE;
X 
X	    case WBOUND:
X		if ((lp == FirstCharacter || !isalnum(lp[-1])) !=
X			(!*lp || !isalnum(*lp)) )
X		    continue;
X		return FALSE;
X 
X	    case NWBOUND:
X		if ((lp == FirstCharacter || !isalnum(lp[-1])) ==
X			(!*lp || !isalnum(*lp)))
X		    continue;
X		return FALSE;
X 
X	    case CEND:
X		return TRUE;
X 
X	    case CCL:
X		if (cclass (ep, *lp, 1)) {
X		    ep += BMAPSIZ;
X		    lp++;
X		    continue;
X		}
X		return FALSE;
X 
X	    case NCCL:
X		if (cclass (ep, *lp, 0)) {
X		    ep += BMAPSIZ;
X		    lp++;
X		    continue;
X		}
X		return FALSE;
X 
X	    case CBRA:
X		compex->braslist[*ep++] = lp;
X		continue;
X 
X	    case CKET:
X		i = *ep++;
X		compex->braelist[i] = lp;
X		compex->braelist[0] = lp;
X		compex->braslist[0] = compex->braslist[i];
X		continue;
X 
X	    case CBACK:
X		if (compex->braelist[i = *ep++] == 0) {
X		    fputs("bad braces\n",stdout) FLUSH;
X		    err = TRUE;
X		    return FALSE;
X		}
X		if (backref (compex, i, lp)) {
X		    lp += compex->braelist[i] - compex->braslist[i];
X		    continue;
X		}
X		return FALSE;
X 
X	    case CBACK | STAR:
X		if (compex->braelist[i = *ep++] == 0) {
X		    fputs("bad braces\n",stdout) FLUSH;
X		    err = TRUE;
X		    return FALSE;
X		}
X		curlp = lp;
X		while (backref (compex, i, lp)) {
X		    lp += compex->braelist[i] - compex->braslist[i];
X		}
X		while (lp >= curlp) {
X		    if (advance (compex, lp, ep))
X			return TRUE;
X		    lp -= compex->braelist[i] - compex->braslist[i];
X		}
X		continue;
X 
X	    case CDOT | STAR:
X		curlp = lp;
X		while (*lp++ && lp[-1] != '\n');
X		goto star;
X 
X	    case WORD | STAR:
X		curlp = lp;
X		while (*lp++ && isalnum(lp[-1]));
X		goto star;
X 
X	    case NWORD | STAR:
X		curlp = lp;
X		while (*lp++ && !isalnum(lp[-1]));
X		goto star;
X 
X	    case CCHR | STAR:
X		curlp = lp;
X		while (*lp++ && trt[lp[-1]] == trt[*ep]);
X		ep++;
X		goto star;
X 
X	    case CCL | STAR:
X	    case NCCL | STAR:
X		curlp = lp;
X		while (*lp++ && cclass (ep, lp[-1], ep[-1] == (CCL | STAR)));
X		ep += BMAPSIZ;
X		goto star;
X 
X	star:
X		do {
X		    lp--;
X		    if (advance (compex, lp, ep))
X			return TRUE;
X		} while (lp > curlp);
X		return FALSE;
X 
X	    default:
X		fputs("Badly compiled pattern\n",stdout) FLUSH;
X		err = TRUE;
X		return -1;
X	}
X	if (*ep == CEND || *ep == CDOL) {
X	    return TRUE;
X    }
X    return FALSE;
X}
X 
Xbool
Xbackref (compex, i, lp)
Xregister COMPEX *compex;
Xregister int i;
Xregister char *lp;
X{
X    register char *bp;
X 
X    bp = compex->braslist[i];
X    while (*lp && *bp == *lp) {
X	bp++;
X	lp++;
X	if (bp >= compex->braelist[i])
X	    return TRUE;
X    }
X    return FALSE;
X}
X
Xbool
Xcclass (set, c, af)
Xregister char  *set;
Xregister int c;
X{
X    c &= 0177;
X#if BITSPERBYTE == 8
X    if (set[c >> 3] & 1 << (c & 7))
X#else
X    if (set[c / BITSPERBYTE] & 1 << (c % BITSPERBYTE))
X#endif
X	return af;
X    return !af;
X}
SHAR_EOF
chmod 0660 search.c || echo "restore of search.c fails"
echo "x - extracting search.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > search.h &&
X/* $Header: search.h,v 4.3 85/05/01 11:50:46 lwall Exp $
X *
X * $Log:	search.h,v $
X * Revision 4.3  85/05/01  11:50:46  lwall
X * Baseline for release with 4.3bsd.
X * 
X */
X
X#ifndef NBRA
X#define	NBRA	10		/* the maximum number of meta-brackets in an
X				   RE -- \( \) */
X#define NALTS	10		/* the maximum number of \|'s */
X 
Xtypedef struct {	
X    char *expbuf;		/* The compiled search string */
X    int eblen;			/* Length of above buffer */
X    char *alternatives[NALTS];	/* The list of \| seperated alternatives */
X    char *braslist[NBRA];	/* RE meta-bracket start list */
X    char *braelist[NBRA];	/* RE meta-bracket end list */
X    char *brastr;		/* saved match string after execute() */
X    char nbra;			/* The number of meta-brackets int the most
X				   recenlty compiled RE */
X    bool do_folding;		/* fold upper and lower case? */
X} COMPEX;
X
Xvoid	search_init();
Xvoid	init_compex();
Xvoid	free_compex();
Xchar	*getbracket();
Xvoid	case_fold();
Xchar	*compile(); 
Xvoid	grow_eb();
Xchar	*execute(); 
Xbool	advance();
Xbool	backref(); 
Xbool	cclass(); 
X#endif
SHAR_EOF
chmod 0660 search.h || echo "restore of search.h fails"
echo "x - extracting sw.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > sw.c &&
X/* $Header: sw.c,v 4.3.3.1 90/06/20 22:40:11 davison Trn $
X *
X * $Log:	sw.c,v $
X * Revision 4.3.3.1  90/06/20  22:40:11  davison
X * Initial Trn Release
X * 
X * Revision 4.3.2.3  90/05/08  22:06:00  sob
X * Added quick startup (-q) flag.
X * 
X * Revision 4.3.2.2  90/03/22  23:05:34  sob
X * Fixes provided by Wayne Davison <drivax!davison>
X * 
X * Revision 4.3.2.1  89/12/09  00:52:40  sob
X * Now handles SIGWINCH correctly.
X * 
X * Revision 4.3.1.2  85/05/21  13:36:23  lwall
X * Sped up "rn -c" by not doing unnecessary initialization.
X * 
X * Revision 4.3.1.1  85/05/10  11:40:38  lwall
X * Branch for patches.
X * 
X * Revision 4.3  85/05/01  11:50:54  lwall
X * Baseline for release with 4.3bsd.
X * 
X */
X
X#include "EXTERN.h"
X#include "common.h"
X#include "util.h"
X#include "head.h"
X#include "only.h"
X#include "term.h"
X#include "ng.h"
X#include "intrp.h"
X#include "INTERN.h"
X#include "sw.h"
X
Xvoid
Xsw_init(argc,argv,tcbufptr)
Xint argc;
Xchar *argv[];
Xchar **tcbufptr;
X{
X    register int i;
X
X    if (argc >= 2 && strEQ(argv[1],"-c"))
X	checkflag=TRUE;			/* so we can optimize for -c */
X    interp(*tcbufptr,1024,GLOBINIT);
X    sw_file(tcbufptr,FALSE);
X    safecpy(*tcbufptr,getenv("RNINIT"),1024);
X    if (**tcbufptr) {
X	if (**tcbufptr == '/') {
X	    sw_file(tcbufptr,TRUE);
X	}
X	else
X	    sw_list(*tcbufptr);
X    }
X
X    for (i = 1; i < argc; i++)
X	decode_switch(argv[i]);
X}
X
Xvoid
Xsw_file(tcbufptr,bleat)
Xchar **tcbufptr;
Xbool bleat;
X{
X    int initfd = open(*tcbufptr,0);
X	
X    if (initfd >= 0) {
X	fstat(initfd,&filestat);
X	if (filestat.st_size > 1024)
X	    *tcbufptr = saferealloc(*tcbufptr,(MEM_SIZE)filestat.st_size);
X	if (filestat.st_size) {
X	    read(initfd,*tcbufptr,(int)filestat.st_size);
X	    (*tcbufptr)[filestat.st_size-1] = '\0';
X				/* wipe out last newline */
X	    sw_list(*tcbufptr);
X	}
X	else
X	    **tcbufptr = '\0';
X	close(initfd);
X    }
X    else {
X	if (bleat)
X	    printf(cantopen,*tcbufptr) FLUSH;
X	**tcbufptr = '\0';
X    }
X}
X
X/* decode a list of space separated switches */
X
Xvoid
Xsw_list(swlist)
Xchar *swlist;
X{
X    char *tmplist = safemalloc((MEM_SIZE) strlen(swlist) + 2);
X					/* semi-automatic string */
X    register char *p, inquote = 0;
X
X    strcpy(tmplist,swlist);
X    for (p=tmplist; isspace(*p); p++) ;	/* skip any initial spaces */
X    while (*p) {			/* "String, or nothing" */
X	if (!inquote && isspace(*p)) {	/* word delimiter? */
X	    *p++ = '\0';		/* chop here */
X	    while (isspace(*p))		/* these will be ignored later */
X		p++;
X	}
X	else if (inquote == *p) {
X	    strcpy(p,p+1);		/* delete trailing quote */
X	    inquote = 0;		/* no longer quoting */
X	}
X	else if (!inquote && *p == '"' || *p == '\'') {
X					/* OK, I know when I am not wanted */
X	    inquote = *p;		/* remember single or double */
X	    strcpy(p,p+1);		/* delete the quote */
X	}				/* (crude, but effective) */
X	else if (*p == '\\') {		/* quoted something? */
X	    if (p[1] == '\n')		/* newline? */
X		strcpy(p,p+2);		/* "I didn't see anything" */
X	    else {
X		strcpy(p,p+1);		/* delete the backwhack */
X		p++;			/* leave the whatever alone */
X	    }
X	}
X	else
X	    p++;			/* normal char, leave it alone */
X    }
X    *++p = '\0';			/* put an extra null on the end */
X    if (inquote)
X	printf("Unmatched %c in switch\n",inquote) FLUSH;
X    for (p = tmplist; *p; /* p += strlen(p)+1 */ ) {
X	decode_switch(p);
X	while (*p++) ;			/* point at null + 1 */
X    }
X    free(tmplist);			/* this oughta be in Ada */
X}
X
X/* decode a single switch */
X
Xvoid
Xdecode_switch(s)
Xregister char *s;
X{
X    while (isspace(*s))			/* ignore leading spaces */
X	s++;
X#ifdef DEBUGGING
X    if (debug)
X	printf("Switch: %s\n",s) FLUSH;
X#endif
X    if (*s != '-' && *s != '+') {	/* newsgroup pattern */
X	setngtodo(s);
X    }
X    else {				/* normal switch */
X	bool upordown = *s == '-' ? TRUE : FALSE;
X	char tmpbuf[LBUFLEN];
X
X	s++;
X	switch (*s) {
X#ifdef TERMMOD
X	case '=': {
X	    char *beg = s+1;
X
X	    while (*s && *s != '-' && *s != '+') s++;
X	    cpytill(tmpbuf,beg,*s);
X	    if (upordown ? strEQ(getenv("TERM"),tmpbuf)
X	    		 : strNE(getenv("TERM"),tmpbuf) ) {
X		decode_switch(s);
X	    }
X	    break;
X	}
X#endif
X#ifdef BAUDMOD
X	case '0': case '1': case '2': case '3': case '4':
X	case '5': case '6': case '7': case '8': case '9':
X	    if (upordown ? (just_a_sec*10 <= atoi(s))
X	    		 : (just_a_sec*10 >= atoi(s)) ) {
X		while (isdigit(*s)) s++;
X		decode_switch(s);
X	    }
X	    break;
X#endif
X	case '/':
X	    if (checkflag)
X		break;
X#ifdef SETENV
X	    setenv("SAVEDIR",  upordown ? "%p/%c" : "%p" );
X	    setenv("SAVENAME", upordown ? "%a"    : "%^C");
X#else
X	    notincl("-/");
X#endif
X	    break;
X	case 'c':
X	    checkflag = upordown;
X	    break;
X	case 'C':
X	    s++;
X	    if (*s == '=') s++;
X	    docheckwhen = atoi(s);
X	    break;
X	case 'd': {
X	    if (checkflag)
X		break;
X	    s++;
X	    if (*s == '=') s++;
X	    if (cwd) {
X		chdir(cwd);
X		free(cwd);
X	    }
X	    cwd = savestr(s);
X	    break;
X	}
X#ifdef DEBUGGING
X	case 'D':
X	    s++;
X	    if (*s == '=') s++;
X	    if (*s)
X		if (upordown)
X		    debug |= atoi(s);
X		else
X		    debug &= ~atoi(s);
X	    else
X		if (upordown)
X		    debug |= 1;
X		else
X		    debug = 0;
X	    break;
X#endif
X	case 'e':
X	    erase_screen = upordown;
X	    break;
X	case 'E':
X#ifdef SETENV
X	    s++;
X	    if (*s == '=')
X		s++;
X	    strcpy(tmpbuf,s);
X	    s = index(tmpbuf,'=');
X	    if (s) {
X		*s++ = '\0';
X		setenv(tmpbuf,s);
X	    }
X	    else
X		setenv(tmpbuf,nullstr);
X#else
X	    notincl("-E");
X#endif
X	    break;
X	case 'F':
X	    s++;
X	    indstr = savestr(s);
X	    break;
X#ifdef INNERSEARCH
X	case 'g':
X	    gline = atoi(s+1)-1;
X	    break;
X#endif
X	case 'H':
X	case 'h': {
X	    register int len, i;
X	    char *t;
X	    int flag = (*s == 'h' ? HT_HIDE : HT_MAGIC);
X	    
X	    if (checkflag)
X		break;
X	    s++;
X	    len = strlen(s);
X	    for (t=s; *t; t++)
X		if (isupper(*t))
X		   *t = tolower(*t);
X	    for (i=HEAD_FIRST; i<HEAD_LAST; i++)
X		if (!len || strnEQ(s,htype[i].ht_name,len))
X		    if (upordown)
X			htype[i].ht_flags |= flag;
X		    else
X			htype[i].ht_flags &= ~flag;
X	    break;
X	}
X	case 'i':
X	    s++;
X	    if (*s == '=') s++;
X	    initlines = atoi(s);
X	    initlines_specified = TRUE;
X	    break;
X	case 'l':
X	    muck_up_clear = upordown;
X	    break;
X	case 'L':
X#ifdef CLEAREOL
X	    can_home_clear = upordown;
X#else
X	    notincl("-L");
X#endif
X	    break;
X	case 'M':
X	    mbox_always = upordown;
X	    break;
X	case 'm':
X	    s++;
X	    if (*s == '=') s++;
X	    if (!upordown)
X		marking = NOMARKING;
X	    else if (*s == 'u')
X		marking = UNDERLINE;
X	    else {
X		marking = STANDOUT;
X	    }
X	    break;
X	case 'N':
X	    norm_always = upordown;
X	    break;
X#ifdef VERBOSE
X	case 'n':
X	    fputs("This isn't readnews.  Don't use -n.\n\n",stdout) FLUSH;
X	    break;
X#endif
X	case 'r':
X	    findlast = upordown;
X	    break;
X	case 's':
X	    s++;
X	    if (*s == '=') s++;
X	    if (*s) {
X		countdown = atoi(s);
X		suppress_cn = FALSE;
X	    }
X	    else {
X		if (!upordown)
X		    countdown = 5;
X		suppress_cn = upordown;
X	    }
X	    break;
X	case 'S':
X#ifdef ARTSEARCH
X	    s++;
X	    if (*s == '=') s++;
X	    if (*s)
X		scanon = atoi(s);
X	    else
X		scanon = upordown*3;
X#else
X	    notincl("-S");
X#endif
X	    break;
X	case 't':
X#ifdef VERBOSE
X#ifdef TERSE
X	    verbose = !upordown;
X#else
X	    notincl("+t");
X#endif
X#else
X	    notincl("+t");
X#endif
X	    break;
X	case 'T':
X	    typeahead = upordown;
X	    break;
X	case 'v':
X#ifdef VERIFY
X	    verify = upordown;
X#else
X	    notincl("-v");
X#endif
X	    break;
X	case 'x':
X#ifdef USETHREADS
X	    s++;
X	    if (*s == '=') s++;
X	    if (*s <= '9' && *s >= '0') {
X		if ((max_tree_lines = atoi(s)) > 11)
X		    max_tree_lines = 11;
X		do {
X		    s++;
X		} while (*s <= '9' && *s >= '0');
X	    } else
X		max_tree_lines = upordown*6;
X	    if (*s)
X		strncpy(select_order, s, 3);
X	    if (mode == 'i')
X		use_threads = upordown;
X	    else if (use_threads != upordown)
X		printf("You must exit and restart to turn threaded operation %s.\n\n",
X		    upordown ? "on" : "off");
X#else
X	    notincl("-x");
X#endif
X	    break;
X	case 'X':
X#ifdef USETHREADS
X	    s++;
X	    if (*s == '=') s++;
X	    if (*s <= '9' && *s >= '0') {
X		select_on = atoi(s);
X		do {
X		    s++;
X		} while (*s <= '9' && *s >= '0');
X	    } else
X		select_on = upordown;
X	    if (*s)
X		end_select = *s++;
X	    if (*s)
X		page_select = *s;
X#else
X	    notincl("-X");
X#endif
X	    break;
X	/*
X	 * People want a way to avoid checking for new newsgroups on startup.
X	 */
X	case 'q':
X		quickstart = upordown;
X		break;
X	default:
X#ifdef VERBOSE
X	    IF(verbose)
X		printf("\nIgnoring unrecognized switch: -%c\n", *s) FLUSH;
X	    ELSE
X#endif
X#ifdef TERSE
X		printf("\nIgnoring -%c\n", *s) FLUSH;
X#endif
X	    break;
X	}
X    }
X}
X
X/* print current switch values */
X
Xvoid
Xpr_switches()
X{
X    static char mp[2] = {'+','-'};
X    register int i;
X    
X    fputs("\nCurrent switch settings:\n",stdout);
X    printf("%c/ ", mp[strEQ(getval("SAVEDIR",SAVEDIR),"%p/%c")]);
X    printf("%cc ", mp[checkflag]);
X    printf("-C%d ", docheckwhen);
X    printf("-d%s ", cwd);
X#ifdef DEBUGGING
X    if (debug)
X	printf("-D%d ", debug);
X#endif
X    printf("%ce ", mp[erase_screen]);
X    printf("-F\"%s\" ", indstr);
X#ifdef INNERSEARCH
X    printf("-g%d", gline);
X#endif
X    putchar('\n');
X#ifdef VERBOSE
X    if (verbose) {
X	for (i=HEAD_FIRST; i<HEAD_LAST; i++)
X	    printf("%ch%s%c",
X		mp[htype[i].ht_flags & HT_HIDE], htype[i].ht_name,
X		(! (i % 5) ? '\n' : ' ') );
X    }
X#endif
X    printf("-i%d ", initlines);
X    printf("%cl ", mp[muck_up_clear]);
X#ifdef CLEAREOL
X    printf("%cL ", mp[can_home_clear]);
X#endif /* CLEAREOL */
X    if (marking)
X	printf("-m%c ",marking==UNDERLINE?'u':'s');
X    else
X	printf("+m ");
X    printf("%cM ", mp[mbox_always]);
X    printf("%cN ", mp[norm_always]);
X    printf("%cr ", mp[findlast]);
X    if (countdown)
X	printf("-s%d ", countdown);
X    else
X	printf("%cs ", mp[suppress_cn]);
X#ifdef ARTSEARCH
X    if (scanon)
X	printf("-S%d ",scanon);
X    else
X	printf("+S ");
X#endif
X#ifdef VERBOSE
X#ifdef TERSE
X    printf("%ct ", mp[!verbose]);
X#endif
X#endif
X    printf("%cT ", mp[typeahead]);
X#ifdef VERIFY
X    printf("%cv ", mp[verify]);
X#endif
X#ifdef USETHREADS
X    if (use_threads)
X	printf("-x%d%s ",max_tree_lines,select_order);
X    else
X	printf("+x ");
X    if (select_on)
X	printf("-X%d%c%c ",select_on,end_select,page_select);
X    else
X	printf("+X ");
X#endif
X    fputs("\n\n",stdout) FLUSH;
X#ifdef ONLY
X    if (maxngtodo) {
X#ifdef VERBOSE
X	IF(verbose)
X	    fputs("Current restriction:",stdout);
X	ELSE
X#endif
X#ifdef TERSE
X	    fputs("Only:",stdout);
X#endif
X	for (i=0; i<maxngtodo; i++)
X	    printf(" %s",ngtodo[i]);
X	fputs("\n\n",stdout) FLUSH;
X    }
X#ifdef VERBOSE
X    else if (verbose)
X	fputs("No restriction.\n\n",stdout) FLUSH;
X#endif
X#endif
X}
X
Xvoid
Xcwd_check()
X{
X    char tmpbuf[LBUFLEN];
X
X    if (!cwd)
X	cwd = savestr(filexp("~/News"));
X    strcpy(tmpbuf,cwd);
X    if (chdir(cwd)) {
X	safecpy(tmpbuf,filexp(cwd),sizeof tmpbuf);
X	if (makedir(tmpbuf,MD_DIR) < 0 || chdir(tmpbuf) < 0) {
X	    interp(cmd_buf, (sizeof cmd_buf), "%~/News");
X	    if (makedir(cmd_buf,MD_DIR) < 0)
X		strcpy(tmpbuf,homedir);
X	    else
X		strcpy(tmpbuf,cmd_buf);
X	    chdir(tmpbuf);
X#ifdef VERBOSE
X	    IF(verbose)
X		printf("\
XCannot make directory %s--\n\
X	articles will be saved to %s\n\
X\n\
X",cwd,tmpbuf) FLUSH;
X	    ELSE
X#endif
X#ifdef TERSE
X		printf("\
XCan't make %s--\n\
X	using %s\n\
X\n\
X",cwd,tmpbuf) FLUSH;
X#endif
X	}
X    }
X    free(cwd);
X    getwd(tmpbuf);
X    if (eaccess(tmpbuf,2)) {
X#ifdef VERBOSE
X	IF(verbose)
X	    printf("\
XCurrent directory %s is not writeable--\n\
X	articles will be saved to home directory\n\n\
X",tmpbuf) FLUSH;
X	ELSE
X#endif
X#ifdef TERSE
X	    printf("%s not writeable--using ~\n\n",tmpbuf) FLUSH;
X#endif
X	strcpy(tmpbuf,homedir);
X    }
X    cwd = savestr(tmpbuf);
X}
SHAR_EOF
chmod 0660 sw.c || echo "restore of sw.c fails"
echo "x - extracting sw.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > sw.h &&
X/* $Header: sw.h,v 4.3 85/05/01 11:51:07 lwall Exp $
X *
X * $Log:	sw.h,v $
X * Revision 4.3  85/05/01  11:51:07  lwall
X * Baseline for release with 4.3bsd.
X * 
X */
X
X#ifdef INNERSEARCH
XEXT int gline INIT(0);
X#endif
X
Xvoid    sw_init();
Xvoid    sw_file();
Xvoid    sw_list();
Xvoid	decode_switch();
Xvoid	pr_switches();
Xvoid	cwd_check();
SHAR_EOF
chmod 0660 sw.h || echo "restore of sw.h fails"
echo "x - extracting term.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > term.c &&
X/* $Header: term.c,v 4.3.3.1 90/07/28 18:09:09 davison Trn $
X *
X * $Log:	term.c,v $
X * Revision 4.3.3.1  90/07/28  18:09:09  davison
X * Initial Trn Release
X * 
X * Revision 4.3.2.7  90/04/21  16:54:29  sob
X * Installed patches provided by SCO for SCO Xenix
X * 
X * Revision 4.3.2.6  90/04/13  23:48:17  sob
X * Modifications provided by Gene Hackney for 3b2.
X * 
X * Revision 4.3.2.5  90/04/06  20:35:08  sob
X * Added fixes for SCO Xenix sent by ronald at robobar.co.uk.
X * 
X * Revision 4.3.2.4  90/03/22  23:05:38  sob
X * Fixes provided by Wayne Davison <drivax!davison>
X * 
X * Revision 4.3.2.3  89/11/28  01:51:58  sob
X * Now handles SIGWINCH correctly.
X * 
X * Revision 4.3.2.2  89/11/27  01:31:34  sob
X * Altered NNTP code per ideas suggested by Bela Lubkin
X * <filbo at gorn.santa-cruz.ca.us>
X * 
X * Revision 4.3.2.1  89/11/06  01:02:12  sob
X * Added RRN support from NNTP 1.5
X * 
X * Revision 4.3.1.3  85/09/10  11:05:23  lwall
X * Improved %m in in_char().
X * 
X * Revision 4.3.1.2  85/05/16  16:45:35  lwall
X * Forced \r to \n on input.
X * Fix for terminfo braindamage regarding bc emulation.
X * 
X * Revision 4.3.1.1  85/05/10  11:41:03  lwall
X * Branch for patches.
X * 
X * Revision 4.3  85/05/01  11:51:10  lwall
X * Baseline for release with 4.3bsd.
X * 
X */
X
X#include "EXTERN.h"
X#include "common.h"
X#include "util.h"
X#include "final.h"
X#include "help.h"
X#include "cheat.h"
X#include "intrp.h"
X#include "INTERN.h"
X#include "term.h"
X
X#ifdef SYS_PTEM
X#include <sys/stream.h>
X#include <sys/ptem.h>
X#endif
X
Xchar ERASECH;		/* rubout character */
Xchar KILLCH;		/* line delete character */
Xchar tcarea[TCSIZE];	/* area for "compiled" termcap strings */
X
X#ifdef USETHREADS
Xint upcost;
X#endif
X
X/* guarantee capability pointer != Nullch */
X/* (I believe terminfo will ignore the &tmpaddr argument.) */
X
X#define Tgetstr(key) ((tmpstr = tgetstr(key,&tmpaddr)) ? tmpstr : nullstr)
X
X#ifdef PUSHBACK
Xstruct keymap {
X    char km_type[128];
X    union km_union {
X	struct keymap *km_km;
X	char *km_str;
X    } km_ptr[128];
X};
X
X#define KM_NOTHIN 0
X#define KM_STRING 1
X#define KM_KEYMAP 2
X#define KM_BOGUS 3
X
X#define KM_TMASK 3
X#define KM_GSHIFT 4
X#define KM_GMASK 7
X
Xtypedef struct keymap KEYMAP;
X
XKEYMAP *topmap INIT(Null(KEYMAP*));
X
Xvoid mac_init();
XKEYMAP *newkeymap();
Xvoid show_keymap();
Xvoid pushstring();
X#endif
X
Xvoid line_col_calcs();
X
X/* terminal initialization */
X
Xvoid
Xterm_init()
X{
X    savetty();				/* remember current tty state */
X
X#ifdef TERMIO
X    ospeed = _tty.c_cflag & CBAUD;	/* for tputs() */
X    ERASECH = _tty.c_cc[VERASE];	/* for finish_command() */
X    KILLCH = _tty.c_cc[VKILL];		/* for finish_command() */
X#else
X    ospeed = _tty.sg_ospeed;		/* for tputs() */
X    ERASECH = _tty.sg_erase;		/* for finish_command() */
X    KILLCH = _tty.sg_kill;		/* for finish_command() */
X#endif
X
X    /* The following could be a table but I can't be sure that there isn't */
X    /* some degree of sparsity out there in the world. */
X
X    switch (ospeed) {			/* 1 second of padding */
X#ifdef BEXTA
X        case BEXTA:  just_a_sec = 1920; break;
X#else
X#ifdef B19200
X        case B19200: just_a_sec = 1920; break;
X#endif
X#endif
X        case B9600:  just_a_sec =  960; break;
X        case B4800:  just_a_sec =  480; break;
X        case B2400:  just_a_sec =  240; break;
X        case B1800:  just_a_sec =  180; break;
X        case B1200:  just_a_sec =  120; break;
X        case B600:   just_a_sec =   60; break;
X	case B300:   just_a_sec =   30; break;
X	/* do I really have to type the rest of this??? */
X        case B200:   just_a_sec =   20; break;
X        case B150:   just_a_sec =   15; break;
X        case B134:   just_a_sec =   13; break;
X        case B110:   just_a_sec =   11; break;
X        case B75:    just_a_sec =    8; break;
X        case B50:    just_a_sec =    5; break;
X        default:     just_a_sec =  960; break;
X					/* if we are running detached I */
X    }					/*  don't want to know about it! */
X}
X
X/* set terminal characteristics */
X
Xvoid
Xterm_set(tcbuf)
Xchar *tcbuf;		/* temp area for "uncompiled" termcap entry */
X{
X    char *tmpaddr;			/* must not be register */
X    register char *tmpstr;
X    char *tgetstr();
X    char *s;
X    int status;
X#ifdef TIOCGWINSZ
X#ifdef u3b2
Xstruct winsize {
X	unsigned short ws_row;       /* rows, in characters*/
X	unsigned short ws_col;       /* columns, in character */
X	unsigned short ws_xpixel;    /* horizontal size, pixels */
X	unsigned short ws_ypixel;    /* vertical size, pixels */
X};
X#endif
X    struct winsize winsize;
X#endif
X
X#ifdef PENDING
X#if ! defined (FIONREAD) && ! defined (RDCHK)
X    /* do no delay reads on something that always gets closed on exit */
X
X    devtty = open("/dev/tty",0);
X    if (devtty < 0) {
X	printf(cantopen,"/dev/tty") FLUSH;
X	finalize(1);
X    }
X    fcntl(devtty,F_SETFL,O_NDELAY);
X#endif
X#endif
X    
X    /* get all that good termcap stuff */
X
X#ifdef HAVETERMLIB
X    status = tgetent(tcbuf,getenv("TERM"));	/* get termcap entry */
X    if (status < 1) {
X#ifdef VERBOSE
X	printf("No termcap %s found.\n", status ? "file" : "entry") FLUSH;
X#else
X	fputs("Termcap botch\n",stdout) FLUSH;
X#endif
X	finalize(1);
X    }
X    tmpaddr = tcarea;			/* set up strange tgetstr pointer */
X    s = Tgetstr("pc");			/* get pad character */
X    PC = *s;				/* get it where tputs wants it */
X    if (!tgetflag("bs")) {		/* is backspace not used? */
X	BC = Tgetstr("bc");		/* find out what is */
X	if (BC == nullstr) 		/* terminfo grok's 'bs' but not 'bc' */
X	    BC = Tgetstr("le");
X    } else
X	BC = "\b";			/* make a backspace handy */
X    UP = Tgetstr("up");			/* move up a line */
X    if (!*UP)				/* no UP string? */
X	marking = 0;			/* disable any marking */
X    if (muck_up_clear)			/* this is for weird HPs */
X	CL = "\n\n\n\n";
X    else
X	CL = Tgetstr("cl");		/* get clear string */
X    CE = Tgetstr("ce");			/* clear to end of line string */
X#if defined(CLEAREOL) || defined(USETHREADS)
X    HO = Tgetstr("ho");			/* home cursor if no CM */
X    CM = Tgetstr("cm");			/* cursor motion */
X    if (*CM || *HO)
X	can_home = TRUE;
X#endif
X#ifdef CLEAREOL
X    CD = Tgetstr("cd");			/* clear to end of display */
X    if (!*CE || !*CD || !can_home)	/* can we CE, CD, and home? */
X	can_home_clear = FALSE;		/*  no, so disable use of clear eol */
X#endif /* CLEAREOL */
X#ifdef USETHREADS
X    upcost = strlen(UP);
X#endif
X    SO = Tgetstr("so");			/* begin standout */
X    SE = Tgetstr("se");			/* end standout */
X    if ((SG = tgetnum("sg"))<0)
X	SG = 0;				/* blanks left by SG, SE */
X    US = Tgetstr("us");			/* start underline */
X    UE = Tgetstr("ue");			/* end underline */
X    if ((UG = tgetnum("ug"))<0)
X	UG = 0;				/* blanks left by US, UE */
X    if (*US)
X	UC = nullstr;			/* UC must not be NULL */
X    else
X	UC = Tgetstr("uc");		/* underline a character */
X    if (!*US && !*UC) {			/* no underline mode? */
X	US = SO;			/* substitute standout mode */
X	UE = SE;
X	UG = SG;
X    }
X    LINES = tgetnum("li");		/* lines per page */
X    COLS = tgetnum("co");		/* columns on page */
X
X#ifdef TIOCGWINSZ
X    { struct winsize ws;
X	if (ioctl(0, TIOCGWINSZ, &ws) >= 0 && ws.ws_row > 0 && ws.ws_col > 0) {
X	    LINES = ws.ws_row;
X	    COLS = ws.ws_col;
X	}
X    }
X#endif
X	
X    AM = tgetflag("am");		/* terminal wraps automatically? */
X    XN = tgetflag("xn");		/* then eats next newline? */
X    VB = Tgetstr("vb");
X    if (!*VB)
X	VB = "\007";
X    CR = Tgetstr("cr");
X    if (!*CR) {
X	if (tgetflag("nc") && *UP) {
X	    CR = safemalloc((MEM_SIZE)strlen(UP)+2);
X	    sprintf(CR,"%s\r",UP);
X	}
X	else
X	    CR = "\r";
X    }
X#ifdef TIOCGWINSZ
X	if (ioctl(1, TIOCGWINSZ, &winsize)>=0) {
X		if (winsize.ws_row>0) LINES=winsize.ws_row;
X		if (winsize.ws_col>0) COLS=winsize.ws_col;
X	}
X#endif
X#else
X    ??????				/* Roll your own... */
X#endif
X    line_col_calcs();
X    noecho();				/* turn off echo */
X    crmode();				/* enter cbreak mode */
X
X#ifdef PUSHBACK
X    mac_init(tcbuf);
X#endif
X}
X
X#ifdef PUSHBACK
Xvoid
Xmac_init(tcbuf)
Xchar *tcbuf;
X{
X    char tmpbuf[1024];
X
X    tmpfp = fopen(filexp(getval("RNMACRO",RNMACRO)),"r");
X    if (tmpfp != Nullfp) {
X	while (fgets(tcbuf,1024,tmpfp) != Nullch) {
X	    mac_line(tcbuf,tmpbuf,(sizeof tmpbuf));
X	}
X	fclose(tmpfp);
X    }
X}
X
Xvoid
Xmac_line(line,tmpbuf,tbsize)
Xchar *line;
Xchar *tmpbuf;
Xint tbsize;
X{
X    register char *s, *m;
X    register KEYMAP *curmap;
X    register int ch;
X    register int garbage = 0;
X    static char override[] = "\nkeymap overrides string\n";
X
X    if (topmap == Null(KEYMAP*))
X	topmap = newkeymap();
X    if (*line == '#' || *line == '\n')
X	return;
X    if (line[ch = strlen(line)-1] == '\n')
X	line[ch] = '\0';
X    m = dointerp(tmpbuf,tbsize,line," \t");
X    if (!*m)
X	return;
X    while (*m == ' ' || *m == '\t') m++;
X    for (s=tmpbuf,curmap=topmap; *s; s++) {
X	ch = *s & 0177;
X	if (s[1] == '+' && isdigit(s[2])) {
X	    s += 2;
X	    garbage = (*s & KM_GMASK) << KM_GSHIFT;
X	}
X	else
X	    garbage = 0;
X	if (s[1]) {
X	    if ((curmap->km_type[ch] & KM_TMASK) == KM_STRING) {
X		fputs(override,stdout) FLUSH;
X		free(curmap->km_ptr[ch].km_str);
X		curmap->km_ptr[ch].km_str = Nullch;
X	    }
X	    curmap->km_type[ch] = KM_KEYMAP + garbage;
X	    if (curmap->km_ptr[ch].km_km == Null(KEYMAP*))
X		curmap->km_ptr[ch].km_km = newkeymap();
X	    curmap = curmap->km_ptr[ch].km_km;
X	}
X	else {
X	    if ((curmap->km_type[ch] & KM_TMASK) == KM_KEYMAP)
X		fputs(override,stdout) FLUSH;
X	    else {
X		curmap->km_type[ch] = KM_STRING + garbage;
X		curmap->km_ptr[ch].km_str = savestr(m);
X	    }
X	}
X    }
X}
X
XKEYMAP*
Xnewkeymap()
X{
X    register int i;
X    register KEYMAP *map;
X
X#ifndef lint
X    map = (KEYMAP*)safemalloc(sizeof(KEYMAP));
X#else
X    map = Null(KEYMAP*);
X#endif /* lint */
X    for (i=127; i>=0; --i) {
X	map->km_ptr[i].km_km = Null(KEYMAP*);
X	map->km_type[i] = KM_NOTHIN;
X    }
X    return map;
X}
X
Xvoid
Xshow_macros()
X{
X    char prebuf[64];
X
X    if (topmap != Null(KEYMAP*)) {
X	print_lines("Macros:\n",STANDOUT);
X	*prebuf = '\0';
X	show_keymap(topmap,prebuf);
X    }
X    else {
X	print_lines("No macros defined.\n", NOMARKING);
X    }
X}
X
Xvoid
Xshow_keymap(curmap,prefix)
Xregister KEYMAP *curmap;
Xchar *prefix;
X{
X    register int i;
X    register char *next = prefix + strlen(prefix);
X    register int kt;
X
X    for (i=0; i<128; i++) {
X	if (kt = curmap->km_type[i]) {
X	    if (i < ' ')
X		sprintf(next,"^%c",i+64);
X	    else if (i == ' ')
X		strcpy(next,"\\040");
X	    else if (i == 127)
X		strcpy(next,"^?");
X	    else
X		sprintf(next,"%c",i);
X	    if ((kt >> KM_GSHIFT) & KM_GMASK) {
X		sprintf(cmd_buf,"+%d", (kt >> KM_GSHIFT) & KM_GMASK);
X		strcat(next,cmd_buf);
X	    }
X	    switch (kt & KM_TMASK) {
X	    case KM_NOTHIN:
X		sprintf(cmd_buf,"%s	%c\n",prefix,i);
X		print_lines(cmd_buf,NOMARKING);
X		break;
X	    case KM_KEYMAP:
X		show_keymap(curmap->km_ptr[(char)i].km_km, prefix);
X		break;
X	    case KM_STRING:
X		sprintf(cmd_buf,"%s	%s\n",prefix,curmap->km_ptr[i].km_str);
X		print_lines(cmd_buf,NOMARKING);
X		break;
X	    case KM_BOGUS:
X		sprintf(cmd_buf,"%s	BOGUS\n",prefix);
X		print_lines(cmd_buf,STANDOUT);
X		break;
X	    }
X	}
X    }
X}
X
X#endif
X
X/* routine to pass to tputs */
X
Xchar
Xputchr(ch)
Xregister char ch;
X{
X    putchar(ch);
X#ifdef lint
X    ch = Null(char);
X    ch = ch;
X#endif
X    return((char) 0);
X}
X
X/* input the 2nd and succeeding characters of a multi-character command */
X/* returns TRUE if command finished, FALSE if they rubbed out first character */
X
Xbool
Xfinish_command(donewline)
Xint donewline;
X{
X    register char *s;
X    register bool quoteone = FALSE;
X
X    s = buf;
X    if (s[1] != FINISHCMD)		/* someone faking up a command? */
X	return TRUE;
X    do {
X      top:
X	if ((unsigned char)*s < ' ') {
X	    putchar('^');
X	    putchar(*s | 64);
X	}
X	else if (*s == '\177') {
X	    putchar('^');
X	    putchar('?');
X	}
X	else
X	    putchar(*s);		/* echo previous character */
X	s++;
Xre_read:
X	fflush(stdout);
X	getcmd(s);
X	if (quoteone) {
X	    quoteone = FALSE;
X	    continue;
X	}
X	if (errno || *s == Ctl('l')) {
X	    *s = Ctl('r');		/* force rewrite on CONT */
X	}
X	if (*s == '\033') {		/* substitution desired? */
X#ifdef ESCSUBS
X	    char tmpbuf[4], *cpybuf;
X
X	    tmpbuf[0] = '%';
X	    read_tty(&tmpbuf[1],1);
X#ifdef RAWONLY
X	    tmpbuf[1] &= 0177;
X#endif
X	    tmpbuf[2] = '\0';
X	    if (tmpbuf[1] == 'h') {
X		(void) help_subs();
X		*s = '\0';
X		reprint();
X		goto re_read;
X	    }
X	    else if (tmpbuf[1] == '\033') {
X		*s = '\0';
X		cpybuf = savestr(buf);
X		interp(buf, (sizeof buf), cpybuf);
X		free(cpybuf);
X		s = buf + strlen(buf);
X		reprint();
X		goto re_read;
X	    }
X	    else {
X		interp(s,(sizeof buf) - (s-buf),tmpbuf);
X		fputs(s,stdout);
X		s += strlen(s);
X	    }
X	    goto re_read;
X#else
X	    notincl("^[");
X	    *s = '\0';
X	    reprint();
X	    goto re_read;
X#endif
X	}
X	else if (*s == ERASECH) {	/* they want to rubout a char? */
X	    rubout();
X	    s--;			/* discount the char rubbed out */
X	    if ((unsigned char)*s < ' ' || *s == '\177')
X		rubout();
X	    if (s == buf) {		/* entire string gone? */
X		fflush(stdout);		/* return to single char command mode */
X		return FALSE;
X	    }
X	    else
X		goto re_read;
X	}
X	else if (*s == KILLCH) {	/* wipe out the whole line? */
X	    while (s-- != buf) {	/* emulate that many ERASEs */
X		rubout();
X		if ((unsigned char)*s < ' ' || *s == '\177')
X		    rubout();
X	    }
X	    fflush(stdout);
X	    return FALSE;		/* return to single char mode */
X	}
X#ifdef WORDERASE
X	else if (*s == Ctl('w')) {	/* wipe out one word? */
X	    *s-- = ' ';
X	    while (!isspace(*s) || isspace(s[1])) {
X		rubout();
X		if (s-- == buf) {
X		    fflush(stdout);
X		    return FALSE;	/* return to single char mode */
X		}
X		if ((unsigned char)*s < ' ' || *s == '\177')
X		    rubout();
X	    }
X	    s++;
X	    goto re_read;
X	}
X#endif
X	else if (*s == Ctl('r')) {
X	    *s = '\0';
X	    reprint();
X	    goto re_read;
X	}
X	else if (*s == Ctl('v')) {
X	    putchar('^');
X	    backspace();
X	    fflush(stdout);
X	    getcmd(s);
X	    goto top;
X	}
X	else if (*s == '\\') {
X	    quoteone = TRUE;
X	}
X    } while (*s != '\n');		/* till a newline (not echoed) */
X    *s = '\0';				/* terminate the string nicely */
X    if (donewline)
X	putchar('\n') FLUSH;
X    return TRUE;			/* say we succeeded */
X}
X
X/* discard any characters typed ahead */
X
Xvoid
Xeat_typeahead()
X{
X#ifdef PUSHBACK
X    if (!typeahead && nextin==nextout)	/* cancel only keyboard stuff */
X#else
X    if (!typeahead)
X#endif
X    {
X#ifdef PENDING
X	while (input_pending())
X	    read_tty(buf,sizeof(buf));
X#else /* this is probably v7 */
X	ioctl(_tty_ch,TIOCSETP,&_tty);
X#endif
X    }
X}
X
Xvoid
Xsettle_down()
X{
X    dingaling();
X    fflush(stdout);
X    sleep(1);
X#ifdef PUSHBACK
X    nextout = nextin;			/* empty circlebuf */
X#endif
X    eat_typeahead();
X}
X
X#ifdef PUSHBACK
X/* read a character from the terminal, with multi-character pushback */
X
Xint
Xread_tty(addr,size)
Xchar *addr;
Xint size;
X{
X    if (nextout != nextin) {
X	*addr = circlebuf[nextout++];
X	nextout %= PUSHSIZE;
X	return 1;
X    }
X    else {
X	size = read(0,addr,size);
X#ifdef RAWONLY
X	*addr &= 0177;
X#endif
X	return size;
X    }
X}
X
X#ifdef PENDING
X#if ! defined (FIONREAD) && ! defined (RDCHK)
Xint
Xcircfill()
X{
X    register int Howmany = read(devtty,circlebuf+nextin,1);
X
X    if (Howmany) {
X	nextin += Howmany;
X	nextin %= PUSHSIZE;
X    }
X    return Howmany;
X}
X#endif /* PENDING */
X#endif /* FIONREAD */
X
Xvoid
Xpushchar(c)
Xchar c;
X{
X    nextout--;
X    if (nextout < 0)
X	nextout = PUSHSIZE - 1;
X    if (nextout == nextin) {
X	fputs("\npushback buffer overflow\n",stdout) FLUSH;
X	sig_catcher(0);
X    }
X    circlebuf[nextout] = c;
X}
X
X#else /* PUSHBACK */
X#ifndef read_tty
X/* read a character from the terminal, with hacks for O_NDELAY reads */
X
Xint
Xread_tty(addr,size)
Xchar *addr;
Xint size;
X{
X    if (is_input) {
X	*addr = pending_ch;
X	is_input = FALSE;
X	return 1;
X    }
X    else {
X	size = read(0,addr,size);
X#ifdef RAWONLY
X	*addr &= 0177;
X#endif
X	return size;
X    }
X}
X#endif /* read_tty */
X#endif /* PUSHBACK */
X
X/* print an underlined string, one way or another */
X
Xvoid
Xunderprint(s)
Xregister char *s;
X{
X    assert(UC);
X    if (*UC) {		/* char by char underline? */
X	while (*s) {
X	    if ((unsigned char)*s < ' ') {
X		putchar('^');
X		backspace();/* back up over it */
X		underchar();/* and do the underline */
X		putchar(*s+64);
X		backspace();/* back up over it */
X		underchar();/* and do the underline */
X	    }
X	    else {
X		putchar(*s);
X		backspace();/* back up over it */
X		underchar();/* and do the underline */
X	    }
X	    s++;
X	}
X    }
X    else {		/* start and stop underline */
X	underline();	/* start underlining */
X	while (*s) {
X	    if ((unsigned char)*s < ' ') {
X		putchar('^');
X		putchar(*s+64);
X	    }
X	    else
X		putchar(*s);
X	    s++;
X	}
X	un_underline();	/* stop underlining */
X    }
X}
X
X/* keep screen from flashing strangely on magic cookie terminals */
X
X#ifdef NOFIREWORKS
Xvoid
Xno_sofire()
X{
X    if (*UP && *SE) {		/* should we disable fireworks? */
X	putchar('\n');
X	un_standout();
X	up_line();
X	carriage_return();
X    }
X}
X
Xvoid
Xno_ulfire()
X{
X    if (*UP && *US) {		/* should we disable fireworks? */
X	putchar('\n');
X	un_underline();
X	up_line();
X	carriage_return();
X    }
X}
X#endif
X
X/* get a character into a buffer */
X
Xvoid
Xgetcmd(whatbuf)
Xregister char *whatbuf;
X{
X#ifdef PUSHBACK
X    register KEYMAP *curmap;
X    register int i;
X    bool no_macros; 
X    int times = 0;			/* loop detector */
X    char scrchar;
X
Xtryagain:
X    curmap = topmap;
X    no_macros = (whatbuf != buf && nextin == nextout); 
X#endif
X    for (;;) {
X	int_count = 0;
X	errno = 0;
X	if (read_tty(whatbuf,1) < 0)
X	    if (!errno)
X	        errno = EINTR;
X	    else {
X	    perror(readerr);
X	    sig_catcher(0);
X	}
X#ifdef PUSHBACK
X	if (*whatbuf & 0200 || no_macros) {
X	    *whatbuf &= 0177;
X	    goto got_canonical;
X	}
X	if (curmap == Null(KEYMAP*))
X	    goto got_canonical;
X	for (i = (curmap->km_type[*whatbuf] >> KM_GSHIFT) & KM_GMASK; i; --i){
X	    read_tty(&scrchar,1);
X	}
X	switch (curmap->km_type[*whatbuf] & KM_TMASK) {
X	case KM_NOTHIN:			/* no entry? */
X	    if (curmap == topmap)	/* unmapped canonical */
X		goto got_canonical;
X	    settle_down();
X	    goto tryagain;
X	case KM_KEYMAP:			/* another keymap? */
X	    curmap = curmap->km_ptr[*whatbuf].km_km;
X	    assert(curmap != Null(KEYMAP*));
X	    break;
X	case KM_STRING:			/* a string? */
X	    pushstring(curmap->km_ptr[*whatbuf].km_str);
X	    if (++times > 20) {		/* loop? */
X		fputs("\nmacro loop?\n",stdout);
X		settle_down();
X	    }
X	    no_macros = FALSE;
X	    goto tryagain;
X	}
X#else
X#ifdef RAWONLY
X	*whatbuf &= 0177;
X#endif
X	break;
X#endif
X    }
X
Xgot_canonical:
X#ifndef TERMIO
X    if (*whatbuf == '\r')
X	*whatbuf = '\n';
X#endif
X    if (whatbuf == buf)
X	whatbuf[1] = FINISHCMD;		/* tell finish_command to work */
X}
X
X#ifdef PUSHBACK
Xvoid
Xpushstring(str)
Xchar *str;
X{
X    register int i;
X    char tmpbuf[PUSHSIZE];
X    register char *s = tmpbuf;
X
X    assert(str != Nullch);
X    interp(s,PUSHSIZE,str);
X    for (i = strlen(s)-1; i >= 0; --i) {
X	s[i] ^= 0200; 
X	pushchar(s[i]);
X    }
X}
X#endif
X
Xint
Xget_anything()
X{
X    char tmpbuf[2];
X
Xreask_anything:
X    unflush_output();			/* disable any ^O in effect */
X    standout();
X#ifdef VERBOSE
X    IF(verbose)
X	fputs("[Type space to continue] ",stdout);
X    ELSE
X#endif
X#ifdef TERSE
X	fputs("[MORE] ",stdout);
X#endif
X    un_standout();
X    fflush(stdout);
X    eat_typeahead();
X    if (int_count) {
X	return -1;
X    }
X    collect_subjects();			/* loads subject cache until */
X					/* input is pending */
X    getcmd(tmpbuf);
X    if (errno || *tmpbuf == '\f') {
X	putchar('\n') FLUSH;		/* if return from stop signal */
X	goto reask_anything;		/* give them a prompt again */
X    }
X    if (*tmpbuf == 'h') {
X#ifdef VERBOSE
X	IF(verbose)
X	    fputs("\nType q to quit or space to continue.\n",stdout) FLUSH;
X	ELSE
X#endif
X#ifdef TERSE
X	    fputs("\nq to quit, space to continue.\n",stdout) FLUSH;
X#endif
X	goto reask_anything;
X    }
X    else if (*tmpbuf != ' ' && *tmpbuf != '\n') {
X	carriage_return();
X	erase_eol();	/* erase the prompt */
X	carriage_return();
X	return *tmpbuf == 'q' ? -1 : *tmpbuf;
X    }
X    if (*tmpbuf == '\n') {
X	page_line = LINES - 1;
X	carriage_return();
X	erase_eol();
X	carriage_return();
X    }
X    else {
X	page_line = 1;
X	if (erase_screen)		/* -e? */
X	    clear();			/* clear screen */
X	else {
X	    carriage_return();
X	    erase_eol();		/* erase the prompt */
X	    carriage_return();
X	}
X    }
X    return 0;
X}
X
X#ifdef USETHREADS
Xint
Xpause_getcmd()
X{
X    unflush_output();			/* disable any ^O in effect */
X    standout();
X#ifdef VERBOSE
X    IF(verbose)
X	fputs("[Type space or a command] ",stdout);
X    ELSE
X#endif
X#ifdef TERSE
X	fputs("[CMD] ",stdout);
X#endif
X    un_standout();
X    fflush(stdout);
X    eat_typeahead();
X    if (int_count) {
X	return -1;
X    }
X    getcmd(buf);
X    if (errno || *buf == '\f') {
X	return 0;			/* if return from stop signal */
X    }
X    else if (*buf != ' ') {
X	carriage_return();
X	erase_eol();	/* erase the prompt */
X	carriage_return();
X	return *buf;
X    }
X    return 0;
X}
X#endif
X
Xvoid
Xin_char(prompt, newmode)
Xchar *prompt;
Xchar newmode;
X{
X    char oldmode = mode;
X
Xreask_in_char:
X    unflush_output();			/* disable any ^O in effect */
X    fputs(prompt,stdout);
X    fflush(stdout);
X    eat_typeahead();
X    mode = newmode;
X    getcmd(buf);
X    if (errno || *buf == '\f') {
X	putchar('\n') FLUSH;		/* if return from stop signal */
X	goto reask_in_char;		/* give them a prompt again */
X    }
X    mode = oldmode;
X}
X
Xint
Xprint_lines(what_to_print,hilite)
Xchar *what_to_print;
Xint hilite;
X{
X    register char *s;
X    register int i;
X
X    if (page_line < 0)			/* they do not want to see this? */
X	return -1;
X    for (s=what_to_print; *s; ) {
X	if (page_line >= LINES || int_count) {
X	    if (i = -1, int_count || (i = get_anything())) {
X		page_line = -1;		/* disable further print_lines */
X		return i;
X	    }
X	}
X	page_line++;
X	if (hilite == STANDOUT) {
X#ifdef NOFIREWORKS
X	    if (erase_screen)
X		no_sofire();
X#endif
X	    standout();
X	}
X	else if (hilite == UNDERLINE) {
X#ifdef NOFIREWORKS
X	    if (erase_screen)
X		no_ulfire();
X#endif
X	    underline();
X	}
X	for (i=0; i<COLS; i++) {
X	    if (!*s)
X		break;
X	    if ((unsigned char)*s >= ' ')
X		putchar(*s);
X	    else if (*s == '\t') {
X		putchar(*s);
X		i = ((i+8) & ~7) - 1; 
X	    }
X	    else if (*s == '\n') {
X		i = 32000;
X	    }
X	    else {
X		i++;
X		putchar('^');
X		putchar(*s + 64);
X	    }
X	    s++;
X	}
X	if (i) {
X	    if (hilite == STANDOUT)
X		un_standout();
X	    else if (hilite == UNDERLINE)
X		un_underline();
X	    if (AM && i == COLS)
X		fflush(stdout);
X	    else
X		putchar('\n') FLUSH;
X	}
X    }
X    return 0;
X}
X
Xvoid
Xpage_init()
X{
X    page_line = 1;
X    if (erase_screen)
X	clear();
X    else
X	putchar('\n') FLUSH;
X}
X
Xvoid
Xpad(num)
Xint num;
X{
X    register int i;
X
X    for (i = num; i; --i)
X	putchar(PC);
X    fflush(stdout);
X}
X
X/* echo the command just typed */
X
X#ifdef VERIFY
Xvoid
Xprintcmd()
X{
X    if (verify && buf[1] == FINISHCMD) {
X	if ((unsigned char)*buf < ' ') {
X	    putchar('^');
X	    putchar(*buf | 64);
X	    backspace();
X	    backspace();
X	}
X	else {
X	    putchar(*buf);
X	    backspace();
X	}
X	fflush(stdout);
X    }
X}
X#endif
X
Xvoid
Xrubout()
X{
X    backspace();			/* do the old backspace, */
X    putchar(' ');			/*   space, */
X    backspace();			/*     backspace trick */
X}
X
Xvoid
Xreprint()
X{
X    register char *s;
X
X    fputs("^R\n",stdout) FLUSH;
X    for (s = buf; *s; s++) {
X	if ((unsigned char)*s < ' ') {
SHAR_EOF
echo "End of part 13"
echo "File term.c is continued in part 14"
echo "14" > s2_seq_.tmp
exit 0

exit 0 # Just in case...
-- 
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.



More information about the Comp.sources.unix mailing list