#! /bin/sh
# Make a new directory for the rn sources, cd to it, and run kits 1 thru 10 
# through sh.  When all 10 kits have been run, read README.

echo "This is rn kit 5 (of 10).  If kit 5 is complete, the line"
echo '"'"End of kit 5 (of 10)"'" will echo at the end.'
echo ""
export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
echo Extracting term.c
cat >term.c <<'!STUFFY!FUNK!'
/* $Id: term.c,v 4.4 1991/09/09 20:27:37 sob Exp sob $
 *
 * $Log: term.c,v $
 * Revision 4.4  1991/09/09  20:27:37  sob
 * release 4.4
 *
 *
 * 
 */
/* This software is Copyright 1991 by Stan Barber. 
 *
 * Permission is hereby granted to copy, reproduce, redistribute or otherwise
 * use this software as long as: there is no monetary profit gained
 * specifically from the use or reproduction of this software, it is not
 * sold, rented, traded or otherwise marketed, and this copyright notice is
 * included prominently in any copy made. 
 *
 * The author make no claims as to the fitness or correctness of this software
 * for any use whatsoever, and it is provided as is. Any use of this software
 * is at the user's own risk. 
 */

#include "EXTERN.h"
#include "common.h"
#include "util.h"
#include "final.h"
#include "help.h"
#include "cheat.h"
#include "intrp.h"
#include "INTERN.h"
#include "term.h"

char ERASECH;		/* rubout character */
char KILLCH;		/* line delete character */
char tcarea[TCSIZE];	/* area for "compiled" termcap strings */


/* guarantee capability pointer != Nullch */
/* (I believe terminfo will ignore the &tmpaddr argument.) */

#define Tgetstr(key) ((tmpstr = tgetstr(key,&tmpaddr)) ? tmpstr : nullstr)

#ifdef PUSHBACK
struct keymap {
    char km_type[128];
    union km_union {
	struct keymap *km_km;
	char *km_str;
    } km_ptr[128];
};

#define KM_NOTHIN 0
#define KM_STRING 1
#define KM_KEYMAP 2
#define KM_BOGUS 3

#define KM_TMASK 3
#define KM_GSHIFT 4
#define KM_GMASK 7

typedef struct keymap KEYMAP;

KEYMAP *topmap INIT(Null(KEYMAP*));

void mac_init();
KEYMAP *newkeymap();
void show_keymap();
void pushstring();
#endif

void line_col_calcs();

/* terminal initialization */

void
term_init()
{
    savetty();				/* remember current tty state */

#ifdef TERMIO
    ospeed = _tty.c_cflag & CBAUD;	/* for tputs() */
    ERASECH = _tty.c_cc[VERASE];	/* for finish_command() */
    KILLCH = _tty.c_cc[VKILL];		/* for finish_command() */
    if (GT = ((_tty.c_oflag & TABDLY) != TAB3))
	/* we have tabs, so that's OK */;
    else
	_tty.c_oflag &= ~TAB3;	/* turn off kernel tabbing -- done in rn */
#else
    ospeed = _tty.sg_ospeed;		/* for tputs() */
    ERASECH = _tty.sg_erase;		/* for finish_command() */
    KILLCH = _tty.sg_kill;		/* for finish_command() */
    if (GT = ((_tty.sg_flags & XTABS) != XTABS))
	/* we have tabs, so that's OK */;
    else
	_tty.sg_flags &= ~XTABS;
#endif

    /* The following could be a table but I can't be sure that there isn't */
    /* some degree of sparsity out there in the world. */

    switch (ospeed) {			/* 1 second of padding */
#ifdef BEXTA
        case BEXTA:  just_a_sec = 1920; break;
#else
#ifdef B19200
        case B19200: just_a_sec = 1920; break;
#endif
#endif
        case B9600:  just_a_sec =  960; break;
        case B4800:  just_a_sec =  480; break;
        case B2400:  just_a_sec =  240; break;
        case B1800:  just_a_sec =  180; break;
        case B1200:  just_a_sec =  120; break;
        case B600:   just_a_sec =   60; break;
	case B300:   just_a_sec =   30; break;
	/* do I really have to type the rest of this??? */
        case B200:   just_a_sec =   20; break;
        case B150:   just_a_sec =   15; break;
        case B134:   just_a_sec =   13; break;
        case B110:   just_a_sec =   11; break;
        case B75:    just_a_sec =    8; break;
        case B50:    just_a_sec =    5; break;
        default:     just_a_sec =  960; break;
					/* if we are running detached I */
    }					/*  don't want to know about it! */
}

/* set terminal characteristics */

void
term_set(tcbuf)
char *tcbuf;		/* temp area for "uncompiled" termcap entry */
{
    char *tmpaddr;			/* must not be register */
    register char *tmpstr;
    char *tgetstr();
    char *s;
    int status;
#ifdef TIOCGWINSZ
    struct winsize winsize;
#endif

#ifdef PENDING
#if ! defined (FIONREAD) && ! defined (RDCHK)
    /* do no delay reads on something that always gets closed on exit */

    devtty = open("/dev/tty",0);
    if (devtty < 0) {
	printf(cantopen,"/dev/tty") FLUSH;
	finalize(1);
    }
    fcntl(devtty,F_SETFL,O_NDELAY);
#endif
#endif
    
    /* get all that good termcap stuff */

#ifdef HAVETERMLIB
    status = tgetent(tcbuf,getenv("TERM"));	/* get termcap entry */
    if (status < 1) {
#ifdef VERBOSE
	printf("No termcap %s found.\n", status ? "file" : "entry") FLUSH;
#else
	fputs("Termcap botch\n",stdout) FLUSH;
#endif
	finalize(1);
    }
    tmpaddr = tcarea;			/* set up strange tgetstr pointer */
    s = Tgetstr("pc");			/* get pad character */
    PC = *s;				/* get it where tputs wants it */
    if (!tgetflag("bs")) {		/* is backspace not used? */
	BC = Tgetstr("bc");		/* find out what is */
	if (BC == nullstr) 		/* terminfo grok's 'bs' but not 'bc' */
	    BC = Tgetstr("le");
    } else
	BC = "\b";			/* make a backspace handy */
    UP = Tgetstr("up");			/* move up a line */
    if (!*UP)				/* no UP string? */
	marking = 0;			/* disable any marking */
    if (muck_up_clear)			/* this is for weird HPs */
	CL = "\n\n\n\n";
    else
	CL = Tgetstr("cl");		/* get clear string */
    CE = Tgetstr("ce");			/* clear to end of line string */
    TI = Tgetstr("ti");			/* initialize display */
    TE = Tgetstr("te");			/* reset display */
#ifdef CLEAREOL
    HO = Tgetstr("ho");			/* home cursor if no CM */
    CM = Tgetstr("cm");			/* cursor motion */
    if (*CM || *HO)
	can_home = TRUE;
    CD = Tgetstr("cd");			/* clear to end of display */
    if (!*CE || !*CD || !can_home)	/* can we CE, CD, and home? */
	can_home_clear = FALSE;		/*  no, so disable use of clear eol */
    if (!*CE) CE = CD;
#endif /* CLEAREOL */
    SO = Tgetstr("so");			/* begin standout */
    SE = Tgetstr("se");			/* end standout */
    if ((SG = tgetnum("sg"))<0)
	SG = 0;				/* blanks left by SG, SE */
    US = Tgetstr("us");			/* start underline */
    UE = Tgetstr("ue");			/* end underline */
    if ((UG = tgetnum("ug"))<0)
	UG = 0;				/* blanks left by US, UE */
    if (*US)
	UC = nullstr;			/* UC must not be NULL */
    else
	UC = Tgetstr("uc");		/* underline a character */
    if (!*US && !*UC) {			/* no underline mode? */
	US = SO;			/* substitute standout mode */
	UE = SE;
	UG = SG;
    }
    LINES = tgetnum("li");		/* lines per page */
    COLS = tgetnum("co");		/* columns on page */

#ifdef TIOCGWINSZ
    { struct winsize ws;
	if (ioctl(0, TIOCGWINSZ, &ws) >= 0 && ws.ws_row > 0 && ws.ws_col > 0) {
	    LINES = ws.ws_row;
	    COLS = ws.ws_col;
	}
    }
#endif
	
    AM = tgetflag("am");		/* terminal wraps automatically? */
    XN = tgetflag("xn");		/* then eats next newline? */
    VB = Tgetstr("vb");
    if (!*VB)
	VB = "\007";
    CR = Tgetstr("cr");
    if (!*CR) {
	if (tgetflag("nc") && *UP) {
	    CR = safemalloc((MEM_SIZE)strlen(UP)+2);
	    sprintf(CR,"%s\r",UP);
	}
	else
	    CR = "\r";
    }
#ifdef TIOCGWINSZ
	if (ioctl(1, TIOCGWINSZ, &winsize)>=0) {
		if (winsize.ws_row>0) LINES=winsize.ws_row;
		if (winsize.ws_col>0) COLS=winsize.ws_col;
	}
#endif
#else
    ??????				/* Roll your own... */
#endif
    termlib_init();
    line_col_calcs();
    noecho();				/* turn off echo */
    crmode();				/* enter cbreak mode */

#ifdef PUSHBACK
    mac_init(tcbuf);
#endif
}

#ifdef PUSHBACK
void
mac_init(tcbuf)
char *tcbuf;
{
    char tmpbuf[1024];

    tmpfp = fopen(filexp(getval("RNMACRO",RNMACRO)),"r");
    if (tmpfp != Nullfp) {
	while (fgets(tcbuf,1024,tmpfp) != Nullch) {
	    mac_line(tcbuf,tmpbuf,(sizeof tmpbuf));
	}
	fclose(tmpfp);
    }
}

void
mac_line(line,tmpbuf,tbsize)
char *line;
char *tmpbuf;
int tbsize;
{
    register char *s, *m;
    register KEYMAP *curmap;
    register int ch;
    register int garbage = 0;
    static char override[] = "\nkeymap overrides string\n";

    if (topmap == Null(KEYMAP*))
	topmap = newkeymap();
    if (*line == '#' || *line == '\n')
	return;
    if (line[ch = strlen(line)-1] == '\n')
	line[ch] = '\0';
    m = dointerp(tmpbuf,tbsize,line," \t");
    if (!*m)
	return;
    while (*m == ' ' || *m == '\t') m++;
    for (s=tmpbuf,curmap=topmap; *s; s++) {
	ch = *s & 0177;
	if (s[1] == '+' && isdigit(s[2])) {
	    s += 2;
	    garbage = (*s & KM_GMASK) << KM_GSHIFT;
	}
	else
	    garbage = 0;
	if (s[1]) {
	    if ((curmap->km_type[ch] & KM_TMASK) == KM_STRING) {
		fputs(override,stdout) FLUSH;
		free(curmap->km_ptr[ch].km_str);
		curmap->km_ptr[ch].km_str = Nullch;
	    }
	    curmap->km_type[ch] = KM_KEYMAP + garbage;
	    if (curmap->km_ptr[ch].km_km == Null(KEYMAP*))
		curmap->km_ptr[ch].km_km = newkeymap();
	    curmap = curmap->km_ptr[ch].km_km;
	}
	else {
	    if ((curmap->km_type[ch] & KM_TMASK) == KM_KEYMAP)
		fputs(override,stdout) FLUSH;
	    else {
		curmap->km_type[ch] = KM_STRING + garbage;
		curmap->km_ptr[ch].km_str = savestr(m);
	    }
	}
    }
}

KEYMAP*
newkeymap()
{
    register int i;
    register KEYMAP *map;

#ifndef lint
    map = (KEYMAP*)safemalloc(sizeof(KEYMAP));
#else
    map = Null(KEYMAP*);
#endif /* lint */
    for (i=127; i>=0; --i) {
	map->km_ptr[i].km_km = Null(KEYMAP*);
	map->km_type[i] = KM_NOTHIN;
    }
    return map;
}

void
show_macros()
{
    char prebuf[64];

    if (topmap != Null(KEYMAP*)) {
	print_lines("Macros:\n",STANDOUT);
	*prebuf = '\0';
	show_keymap(topmap,prebuf);
    }
    else {
	print_lines("No macros defined.\n", NOMARKING);
    }
}

void
show_keymap(curmap,prefix)
register KEYMAP *curmap;
char *prefix;
{
    register int i;
    register char *next = prefix + strlen(prefix);
    register int kt;

    for (i=0; i<128; i++) {
	if (kt = curmap->km_type[i]) {
	    if (i < ' ')
		sprintf(next,"^%c",i+64);
	    else if (i == ' ')
		strcpy(next,"\\040");
	    else if (i == 127)
		strcpy(next,"^?");
	    else
		sprintf(next,"%c",i);
	    if ((kt >> KM_GSHIFT) & KM_GMASK) {
		sprintf(cmd_buf,"+%d", (kt >> KM_GSHIFT) & KM_GMASK);
		strcat(next,cmd_buf);
	    }
	    switch (kt & KM_TMASK) {
	    case KM_NOTHIN:
		sprintf(cmd_buf,"%s	%c\n",prefix,i);
		print_lines(cmd_buf,NOMARKING);
		break;
	    case KM_KEYMAP:
		show_keymap(curmap->km_ptr[(char)i].km_km, prefix);
		break;
	    case KM_STRING:
		sprintf(cmd_buf,"%s	%s\n",prefix,curmap->km_ptr[i].km_str);
		print_lines(cmd_buf,NOMARKING);
		break;
	    case KM_BOGUS:
		sprintf(cmd_buf,"%s	BOGUS\n",prefix);
		print_lines(cmd_buf,STANDOUT);
		break;
	    }
	}
    }
}

#endif

/* routine to pass to tputs */

char
putchr(ch)
register char ch;
{
    putchar(ch);
#ifdef lint
    ch = Null(char);
    ch = ch;
#endif
    return((char) 0);
}

/* input the 2nd and succeeding characters of a multi-character command */
/* returns TRUE if command finished, FALSE if they rubbed out first character */

bool
finish_command(donewline)
int donewline;
{
    register char *s;
    register bool quoteone = FALSE;

    s = buf;
    if (s[1] != FINISHCMD)		/* someone faking up a command? */
	return TRUE;
    do {
      top:
	if (*(unsigned char *)s < ' ') {
	    putchar('^');
	    putchar(*s | 64);
	}
	else if (*s == '\177') {
	    putchar('^');
	    putchar('?');
	}
	else
	    putchar(*s);		/* echo previous character */
	s++;
re_read:
	fflush(stdout);
	getcmd(s);
	if (quoteone) {
	    quoteone = FALSE;
	    continue;
	}
	if (errno || *s == Ctl('l')) {
	    *s = Ctl('r');		/* force rewrite on CONT */
	}
	if (*s == '\033') {		/* substitution desired? */
#ifdef ESCSUBS
	    char tmpbuf[4], *cpybuf;

	    tmpbuf[0] = '%';
	    read_tty(&tmpbuf[1],1);
#ifdef RAWONLY
	    tmpbuf[1] &= 0177;
#endif
	    tmpbuf[2] = '\0';
	    if (tmpbuf[1] == 'h') {
		(void) help_subs();
		*s = '\0';
		reprint();
		goto re_read;
	    }
	    else if (tmpbuf[1] == '\033') {
		*s = '\0';
		cpybuf = savestr(buf);
		interp(buf, (sizeof buf), cpybuf);
		free(cpybuf);
		s = buf + strlen(buf);
		reprint();
		goto re_read;
	    }
	    else {
		interp(s,(sizeof buf) - (s-buf),tmpbuf);
		fputs(s,stdout);
		s += strlen(s);
	    }
	    goto re_read;
#else
	    notincl("^[");
	    *s = '\0';
	    reprint();
	    goto re_read;
#endif
	}
	else if (*s == ERASECH) {	/* they want to rubout a char? */
	    rubout();
	    s--;			/* discount the char rubbed out */
	    if (*(unsigned char *)s < ' ' || *s == '\177')
		rubout();
	    if (s == buf) {		/* entire string gone? */
		fflush(stdout);		/* return to single char command mode */
		return FALSE;
	    }
	    else
		goto re_read;
	}
	else if (*s == KILLCH) {	/* wipe out the whole line? */
	    while (s-- != buf) {	/* emulate that many ERASEs */
		rubout();
		if (*(unsigned char *)s < ' ' || *s == '\177')
		    rubout();
	    }
	    fflush(stdout);
	    return FALSE;		/* return to single char mode */
	}
#ifdef WORDERASE
	else if (*s == Ctl('w')) {	/* wipe out one word? */
	    *s-- = ' ';
	    while (!isspace(*s) || isspace(s[1])) {
		rubout();
		if (s-- == buf) {
		    fflush(stdout);
		    return FALSE;	/* return to single char mode */
		}
		if (*(unsigned char *)s < ' ' || *s == '\177')
		    rubout();
	    }
	    s++;
	    goto re_read;
	}
#endif
	else if (*s == Ctl('r')) {
	    *s = '\0';
	    reprint();
	    goto re_read;
	}
	else if (*s == Ctl('v')) {
	    putchar('^');
	    backspace();
	    fflush(stdout);
	    getcmd(s);
	    goto top;
	}
	else if (*s == '\\') {
	    quoteone = TRUE;
	}
#ifdef cray
    } while (*s != '\r');		/* till a newline (not echoed) */
#else
    } while (*s != '\n');		/* till a newline (not echoed) */
#endif
    *s = '\0';				/* terminate the string nicely */
    if (donewline)
	putchar('\n') FLUSH;
    return TRUE;			/* say we succeeded */
}

/* discard any characters typed ahead */

void
eat_typeahead()
{
#ifdef PUSHBACK
    if (!typeahead && nextin==nextout)	/* cancel only keyboard stuff */
#else
    if (!typeahead)
#endif
    {
#ifdef PENDING
	while (input_pending())
	    read_tty(buf,sizeof(buf));
#else /* this is probably v7 */
#ifdef TERMIO
	ioctl(_tty_ch,TCSETAW,&_tty);
#else
	ioctl(_tty_ch,TIOCSETP,&_tty);
#endif
#endif
    }
}

void
settle_down()
{
    dingaling();
    fflush(stdout);
/*    sleep(1); */
#ifdef PUSHBACK
    nextout = nextin;			/* empty circlebuf */
#endif
    eat_typeahead();
}

#ifdef PUSHBACK
/* read a character from the terminal, with multi-character pushback */

int
read_tty(addr,size)
char *addr;
int size;
{
    if (nextout != nextin) {
	*addr = circlebuf[nextout++];
	nextout %= PUSHSIZE;
	return 1;
    }
    else {
	size = read(0,addr,size);
#ifdef RAWONLY
	*addr &= 0177;
#endif
	return size;
    }
}

#ifdef PENDING
#if ! defined (FIONREAD) && ! defined (RDCHK)
int
circfill()
{
    register int Howmany;

    errno = 0;
    Howmany = read(devtty,circlebuf+nextin,1);

    if (Howmany < 0 && (errno == EAGAIN || errno == EINTR))
	Howmany = 0;
    if (Howmany) {
	nextin += Howmany;
	nextin %= PUSHSIZE;
    }
    return Howmany;
}
#endif /* PENDING */
#endif /* FIONREAD */

void
pushchar(c)
char c;
{
    nextout--;
    if (nextout < 0)
	nextout = PUSHSIZE - 1;
    if (nextout == nextin) {
	fputs("\npushback buffer overflow\n",stdout) FLUSH;
	sig_catcher(0);
    }
    circlebuf[nextout] = c;
}

#else /* PUSHBACK */
#ifndef read_tty
/* read a character from the terminal, with hacks for O_NDELAY reads */

int
read_tty(addr,size)
char *addr;
int size;
{
    if (is_input) {
	*addr = pending_ch;
	is_input = FALSE;
	return 1;
    }
    else {
	size = read(0,addr,size);
#ifdef RAWONLY
	*addr &= 0177;
#endif
	return size;
    }
}
#endif /* read_tty */
#endif /* PUSHBACK */

/* print an underlined string, one way or another */

void
underprint(s)
register char *s;
{
    assert(UC);
    if (*UC) {		/* char by char underline? */
	while (*s) {
	    if (*(unsigned char *)s < ' ') {
		putchar('^');
		backspace();/* back up over it */
		underchar();/* and do the underline */
		putchar(*s+64);
		backspace();/* back up over it */
		underchar();/* and do the underline */
	    }
	    else {
		putchar(*s);
		backspace();/* back up over it */
		underchar();/* and do the underline */
	    }
	    s++;
	}
    }
    else {		/* start and stop underline */
	underline();	/* start underlining */
	while (*s) {
	    if (*(unsigned char *)s < ' ') {
		putchar('^');
		putchar(*s+64);
	    }
	    else
		putchar(*s);
	    s++;
	}
	un_underline();	/* stop underlining */
    }
}

/* keep screen from flashing strangely on magic cookie terminals */

#ifdef NOFIREWORKS
void
no_sofire()
{
    if (*UP && *SE) {		/* should we disable fireworks? */
	putchar('\n');
	un_standout();
	up_line();
	carriage_return();
    }
}

void
no_ulfire()
{
    if (*UP && *US) {		/* should we disable fireworks? */
	putchar('\n');
	un_underline();
	up_line();
	carriage_return();
    }
}
#endif

/* get a character into a buffer */

void
getcmd(whatbuf)
register char *whatbuf;
{
#ifdef PUSHBACK
    register KEYMAP *curmap;
    register int i;
    bool no_macros; 
    int times = 0;			/* loop detector */
    char scrchar;

tryagain:
    curmap = topmap;
    no_macros = (whatbuf != buf && nextin == nextout); 
#endif
    for (;;) {
	int_count = 0;
	errno = 0;
	if (read_tty(whatbuf,1) < 0){
	    if (!errno)
	        errno = EINTR;
	    if (errno == EINTR)
		return;
	    perror(readerr);
	    sig_catcher(0);
	}
#ifdef PUSHBACK
	if (*whatbuf & 0200 || no_macros) {
	    *whatbuf &= 0177;
	    goto got_canonical;
	}
	if (curmap == Null(KEYMAP*))
	    goto got_canonical;
	for (i = (curmap->km_type[*whatbuf] >> KM_GSHIFT) & KM_GMASK; i; --i){
	    read_tty(&scrchar,1);
	}
	switch (curmap->km_type[*whatbuf] & KM_TMASK) {
	case KM_NOTHIN:			/* no entry? */
	    if (curmap == topmap)	/* unmapped canonical */
		goto got_canonical;
	    settle_down();
	    goto tryagain;
	case KM_KEYMAP:			/* another keymap? */
	    curmap = curmap->km_ptr[*whatbuf].km_km;
	    assert(curmap != Null(KEYMAP*));
	    break;
	case KM_STRING:			/* a string? */
	    pushstring(curmap->km_ptr[*whatbuf].km_str);
	    if (++times > 20) {		/* loop? */
		fputs("\nmacro loop?\n",stdout);
		settle_down();
	    }
	    no_macros = FALSE;
	    goto tryagain;
	}
#else
#ifdef RAWONLY
	*whatbuf &= 0177;
#endif
	break;
#endif
    }

got_canonical:
#ifndef TERMIO
    if (*whatbuf == '\r')
	*whatbuf = '\n';
#endif
    if (whatbuf == buf)
	whatbuf[1] = FINISHCMD;		/* tell finish_command to work */
}

#ifdef PUSHBACK
void
pushstring(str)
char *str;
{
    register int i;
    char tmpbuf[PUSHSIZE];
    register char *s = tmpbuf;

    assert(str != Nullch);
    interp(s,PUSHSIZE,str);
    for (i = strlen(s)-1; i >= 0; --i) {
	s[i] ^= 0200; 
	pushchar(s[i]);
    }
}
#endif

int
get_anything()
{
    char tmpbuf[2];

reask_anything:
    unflush_output();			/* disable any ^O in effect */
    standout();
#ifdef VERBOSE
    IF(verbose)
	fputs("[Type space to continue] ",stdout);
    ELSE
#endif
#ifdef TERSE
	fputs("[MORE] ",stdout);
#endif
    un_standout();
    fflush(stdout);
    eat_typeahead();
    if (int_count) {
	return -1;
    }
    collect_subjects();			/* loads subject cache until */
					/* input is pending */
    getcmd(tmpbuf);
    if (errno || *tmpbuf == '\f') {
	putchar('\n') FLUSH;		/* if return from stop signal */
	goto reask_anything;		/* give them a prompt again */
    }
    if (*tmpbuf == 'h') {
#ifdef VERBOSE
	IF(verbose)
	    fputs("\nType q to quit or space to continue.\n",stdout) FLUSH;
	ELSE
#endif
#ifdef TERSE
	    fputs("\nq to quit, space to continue.\n",stdout) FLUSH;
#endif
	goto reask_anything;
    }
    else if (*tmpbuf != ' ' && *tmpbuf != '\n') {
	carriage_return();
	erase_eol();	/* erase the prompt */
	carriage_return();
	return *tmpbuf == 'q' ? -1 : *tmpbuf;
    }
    if (*tmpbuf == '\n') {
	page_line = LINES - 1;
	carriage_return();
	erase_eol();
	carriage_return();
    }
    else {
	page_line = 1;
	if (erase_screen)		/* -e? */
	    clear();			/* clear screen */
	else {
	    carriage_return();
	    erase_eol();		/* erase the prompt */
	    carriage_return();
	}
    }
    return 0;
}

void
in_char(prompt, newmode)
char *prompt;
char newmode;
{
    char oldmode = mode;

reask_in_char:
    unflush_output();			/* disable any ^O in effect */
    fputs(prompt,stdout);
    fflush(stdout);
    eat_typeahead();
    mode = newmode;
    getcmd(buf);
    if (errno || *buf == '\f') {
	putchar('\n') FLUSH;		/* if return from stop signal */
	goto reask_in_char;		/* give them a prompt again */
    }
    mode = oldmode;
}

int
print_lines(what_to_print,hilite)
char *what_to_print;
int hilite;
{
    register char *s;
    register int i;

    if (page_line < 0)			/* they do not want to see this? */
	return -1;
    for (s=what_to_print; *s; ) {
	if (page_line >= LINES || int_count) {
	    if (i = -1, int_count || (i = get_anything())) {
		page_line = -1;		/* disable further print_lines */
		return i;
	    }
	}
	page_line++;
	if (hilite == STANDOUT) {
#ifdef NOFIREWORKS
	    if (erase_screen)
		no_sofire();
#endif
	    standout();
	}
	else if (hilite == UNDERLINE) {
#ifdef NOFIREWORKS
	    if (erase_screen)
		no_ulfire();
#endif
	    underline();
	}
	for (i=0; i<COLS; i++) {
	    if (!*s)
		break;
	    if (*(unsigned char *)s >= ' ')
		putchar(*s);
	    else if (*s == '\t') {
		putchar(*s);
		i = ((i+8) & ~7) - 1; 
	    }
	    else if (*s == '\n') {
		i = 32000;
	    }
	    else {
		i++;
		putchar('^');
		putchar(*s + 64);
	    }
	    s++;
	}
	if (i) {
	    if (hilite == STANDOUT)
		un_standout();
	    else if (hilite == UNDERLINE)
		un_underline();
	    if (AM && i == COLS)
		fflush(stdout);
	    else
		putchar('\n') FLUSH;
	}
    }
    return 0;
}

void
page_init()
{
    page_line = 1;
    if (erase_screen)
	clear();
    else
	putchar('\n') FLUSH;
}

void
pad(num)
int num;
{
    register int i;

    for (i = num; i; --i)
	putchar(PC);
    fflush(stdout);
}

/* echo the command just typed */

#ifdef VERIFY
void
printcmd()
{
    if (verify && buf[1] == FINISHCMD) {
	if (*(unsigned char *)buf < ' ') {
	    putchar('^');
	    putchar(*buf | 64);
	    backspace();
	    backspace();
	}
	else {
	    putchar(*buf);
	    backspace();
	}
	fflush(stdout);
    }
}
#endif

void
rubout()
{
    backspace();			/* do the old backspace, */
    putchar(' ');			/*   space, */
    backspace();			/*     backspace trick */
}

void
reprint()
{
    register char *s;

    fputs("^R\n",stdout) FLUSH;
    for (s = buf; *s; s++) {
	if (*(unsigned char *)s < ' ') {
	    putchar('^');
	    putchar(*s | 64);
	}
	else
	    putchar(*s);
    }
}

#ifdef CLEAREOL
void
home_cursor()
{
    char *tgoto();

    if (!*HO) {			/* no home sequence? */
	if (!*CM) {		/* no cursor motion either? */
	    fputs ("\n\n\n", stdout);
	    return;		/* forget it. */
	}
	tputs (tgoto (CM, 0, 0), 1, putchr);	/* go to home via CM */
	return;
    }
    else {			/* we have home sequence */
	tputs (HO, 1, putchr);	/* home via HO */
    }
}
#endif

void
line_col_calcs()
{
     if (LINES > 0) {			/* is this a crt? */
	  if ((!initlines) || (!initlines_specified))
	       /* no -i or unreasonable value for initlines */
	       if (ospeed >= B9600) 	/* whole page at >= 9600 baud */
		    initlines = LINES;
	       else if (ospeed >= B4800)/* 16 lines at 4800 */
		    initlines = 16;
	       else			/* otherwise just header */
		    initlines = 8;
     }
     else {				/* not a crt */
	  LINES = 30000;		/* so don't page */
	  CL = "\n\n";			/* put a couple of lines between */
	  if ((!initlines) || (!initlines_specified))
	       /* make initlines reasonable */
	       initlines = 8;
     }
     if (COLS <= 0)
	  COLS = 80;
}


#ifdef SIGWINCH
SIGRET
winch_catcher()
{
     /* Reset signal in case of System V dain bramage */
     sigset(SIGWINCH, winch_catcher);

     /* Come here if window size change signal received */
#ifdef TIOCGWINSZ
     { struct winsize ws;
       if (ioctl(0, TIOCGWINSZ, &ws) >= 0 && ws.ws_row > 0 && ws.ws_col > 0) {
	 LINES = ws.ws_row;
	 COLS = ws.ws_col;
	 line_col_calcs();
       }
     }
#else
     /* Well, if SIGWINCH is defined, but TIOCGWINSZ isn't, there's    */
     /* almost certainly something wrong.  Figure it out for yourself, */
     /* because I don't know now to deal :-)                           */
#endif
}
#endif
void
termlib_init()
{
#ifdef HAVETERMLIB
	if (TI && *TI)
		tputs (TI,1,putchr);
#endif
	return;
}
void
termlib_reset()
{
#ifdef HAVETERMLIB
	if (TE && *TE)
		tputs (TE,1,putchr);
#endif
	return;
}
!STUFFY!FUNK!
echo Extracting art.c
cat >art.c <<'!STUFFY!FUNK!'
/* $Id: art.c,v 4.4 1991/09/09 20:18:23 sob Exp sob $
 *
 *
 * 
 */
/* This software is Copyright 1991 by Stan Barber. 
 *
 * Permission is hereby granted to copy, reproduce, redistribute or otherwise
 * use this software as long as: there is no monetary profit gained
 * specifically from the use or reproduction of this software, it is not
 * sold, rented, traded or otherwise marketed, and this copyright notice is
 * included prominently in any copy made. 
 *
 * The author make no claims as to the fitness or correctness of this software
 * for any use whatsoever, and it is provided as is. Any use of this software
 * is at the user's own risk. 
 */

#include "EXTERN.h"
#include "common.h"
#include "rn.h"
#include "ngstuff.h"
#include "ngdata.h"
#include "head.h"
#include "cheat.h"
#include "help.h"
#include "search.h"
#include "artio.h"
#include "ng.h"
#include "bits.h"
#include "final.h"
#include "artstate.h"
#include "rcstuff.h"
#include "term.h"
#include "sw.h"
#include "util.h"
#include "backpage.h"
#include "intrp.h"
#include "INTERN.h"
#include "art.h"

/* page_switch() return values */

#define PS_NORM 0
#define PS_ASK 1
#define PS_RAISE 2
#define PS_TOEND 3

bool special = FALSE;		/* is next page special length? */
int slines = 0;			/* how long to make page when special */
ART_LINE highlight = -1;	/* next line to be highlighted */
char *restart = Nullch;		/* if nonzero, the place where last */
				/* line left off on line split */
char *blinebeg;			/* where in buffer current line began */
ART_POS alinebeg;		/* where in file current line began */

#ifdef INNERSEARCH
ART_POS innersearch = 0;	/* artpos of end of line we found */
				/* for 'g' command */
ART_LINE isrchline = 0;			/* last line to display */
bool hide_everything = FALSE;
				/* if set, do not write page now, */
				/* but refresh when done with page */
COMPEX gcompex;				/* in article search pattern */
#endif

bool firstpage;			/* is this the 1st page of article? */

char art_buf[LBUFLEN];		/* place for article lines */

void
art_init()
{
    ;
}

int
do_article()
{
    register char *s;
    ART_POS artsize;			/* size in bytes of article */
    bool hide_this_line = FALSE;	/* hidden header line? */
    ART_LINE linenum;	/* line # on page, 1 origin */
#ifdef ULSMARTS
    bool under_lining = FALSE;
			    /* are we underlining a word? */
#endif
    register char *bufptr = art_buf;
			    /* pointer to input buffer */
    register int outpos;	/* column position of output */
    static char prompt_buf[64];		/* place to hold prompt */
    bool notesfiles = FALSE;		/* might there be notesfiles junk? */
    char oldmode = mode;
    char *ctime();

#ifdef INNERSEARCH
    register int outputok;
#endif

/*  if (fstat(artfp->_file,&filestat)) ... does not work on Apollos */
    if (fstat(fileno(artfp),&filestat))
			    /* get article file stats */
	return DA_CLEAN;
    if ((filestat.st_mode & S_IFMT) != S_IFREG)
	return DA_NORM;
    artsize = filestat.st_size;
			    /* from that get article size */
    sprintf(prompt_buf,
	"%%sEnd of article %ld (of %ld)--what next? [%%s]",
	(long)art,(long)lastart);	/* format prompt string */
    prompt = prompt_buf;
    int_count = 0;		/* interrupt count is 0 */
    firstpage = (topline < 0);
    for (;;) {			/* for each page */
	assert(art == openart);
	if (do_fseek) {
#ifdef ASYNC_PARSE
	    parse_maybe(art);		/* make sure header is ours */
#endif
	    artpos = vrdary(artline);
	    if (artpos < 0)
		artpos = -artpos;	/* labs(), anyone? */
	    if (firstpage)
		artpos = (ART_POS)0;
	    fseek(artfp,artpos,0);
	    if (artpos < htype[PAST_HEADER].ht_minpos)
		in_header = SOME_LINE;
	    do_fseek = FALSE;
	    restart = Nullch;
	}
	linenum = 1;
	if (firstpage) {
	    if (firstline) {
		interp(art_buf, (sizeof art_buf), firstline);
#ifdef CLEAREOL
		maybe_eol();	
#endif /* CLEAREOL */
		fputs(art_buf,stdout) FLUSH;
		linenum++;
		artopen(art);		/* rewind article in case interp */
					/* forced a header parse */
	    } else 
            {
		ART_NUM i;
		   {
#ifdef CLEAREOL
		    maybe_eol();	
#endif /* CLEAREOL */
		    printf("Article %ld",(long)art);
		    i = (ART_NUM)(toread[ng] - 1 + was_read(art));
#ifdef DELAYMARK
		    if ((i > 0) || dmcount) {
			printf(" (%ld more",(long)i);
			if (dmcount)
			    printf(" + %ld Marked to return",(long)dmcount);
			putchar(')');
		    }
#else
		    if (i > 0)
			printf(" (%ld more)",(long)i);
#endif
		    if (htype[NGS_LINE].ht_flags & HT_HIDE)
			printf(" in %s", ngname);
		    fputs(moderated,stdout);
		    fputs(":\n",stdout) FLUSH;
		    linenum++;
		}
	    }
	    start_header(art);
	    forcelast = FALSE;		/* we will have our day in court */
	    restart = Nullch;
	    artline = 0;		/* start counting lines */
	    artpos = 0;
	    vwtary(artline,artpos);	/* remember pos in file */
	}
	for (;				/* linenum already set */
	  in_header || (
#ifdef INNERSEARCH
	  innersearch ? innermore() :
#endif
	  linenum<(firstpage?initlines:(special?slines:LINES)) );
	  linenum++) {		/* for each line on page */
	    if (int_count) {	/* exit via interrupt? */
		putchar('\n') FLUSH;	/* get to left margin */
		int_count = 0;	/* reset interrupt count */
		mode = oldmode;
		special = FALSE;
		return DA_NORM;	/* skip out of loops */
	    }
	    if (restart) {		/* did not finish last line? */
		bufptr = restart;	/* then start again here */
		restart = Nullch;	/* and reset the flag */
	    }
	    else {			/* not a restart */
		if (fgets(art_buf,LBUFLEN,artfp)==Nullch) {
					/* if all done */
		    mode = oldmode;
		    special = FALSE;
		    return DA_NORM;	/* skip out of loops */
		}
		bufptr = art_buf;	/* so start at beginning */
		art_buf[LBUFLEN-1] = '\0';
					/* make sure string ends */
	    }
	    blinebeg = bufptr;	/* remember where we began */
	    alinebeg = artpos;	/* both in buffer and file */
	    if (in_header && bufptr == art_buf) {
		hide_this_line =
		    parseline(art_buf,do_hiding,hide_this_line);
	    } else if (notesfiles && do_hiding &&
	      bufptr == art_buf && *art_buf == '#' &&
	      isupper(art_buf[1]) && art_buf[2] == ':' ) {
		fgets(art_buf,sizeof(art_buf),artfp);
		if (index(art_buf,'!') != Nullch)
		    fgets(art_buf,sizeof(art_buf),artfp);
		htype[PAST_HEADER].ht_minpos = ftell(artfp);
					/* exclude notesfiles droppings */
		hide_this_line = TRUE;	/* and do not print either */
		notesfiles = FALSE;
	    }
#ifdef CUSTOMLINES
	    if (hideline && bufptr == art_buf &&
		  execute(&hide_compex,art_buf) )
		hide_this_line = TRUE;
#endif
	    if (in_header && htype[in_header].ht_flags & HT_MAGIC) {
		if (in_header == NGS_LINE) {
		    hide_this_line = (index(art_buf,',') == Nullch);
		}
		else if (in_header == EXPIR_LINE) {
		    if (!(htype[EXPIR_LINE].ht_flags & HT_HIDE))
		    hide_this_line = (strlen(art_buf) < 10);
		}
		else if (in_header == FROM_LINE) {
		    if (do_hiding && (s = index(art_buf+6,'(')) != Nullch) {
			strcpy(art_buf+6,s+1);
			if((s = rindex(art_buf+6,')')) != Nullch)
			    *s = '\0';
		    }
		}
	    }
	    if (in_header == SUBJ_LINE &&
		htype[SUBJ_LINE].ht_flags & HT_MAGIC) {
			    /* is this the subject? */
		int length;

		length = strlen(art_buf)-1;
		artline++;
		art_buf[length] = '\0';		/* wipe out newline */
#ifdef NOFIREWORKS
		no_ulfire();
#endif
		notesfiles =
		    (instr(&art_buf[length-10]," - (nf", TRUE) != Nullch);
		if (oldsubject) {
		    length += 7;
		    fputs("(SAME) ",stdout);
		    oldsubject = FALSE;
		}
		if (length+UG > COLS) {		/* rarely true */
		    linenum++;
		    vwtary(artline,vrdary(artline-1)+COLS);
		    artline++;
		}
		s = art_buf + 8;
		*s++ = '\0';	/* make into 2 strings */
#ifdef CLEAREOL
		maybe_eol();	
#endif /* CLEAREOL */
		fputs(art_buf,stdout) FLUSH;
				/* print up through : */
		if (!UG)
		    putchar(' ');
		underprint(s);	/* print subject underlined */
		putchar('\n') FLUSH;	/* and finish the line */
	    }
	    else if (hide_this_line && do_hiding) {
					/* do not print line? */
		linenum--;		/* compensate for linenum++ */
		if (!in_header)
		    hide_this_line = FALSE;
	    }
	    else {			/* just a normal line */
		if (highlight==artline) {	/* this line to be highlit? */
		    if (marking == STANDOUT) {
#ifdef NOFIREWORKS
			if (erase_screen)
			    no_sofire();
#endif
			standout();
		    }
		    else {
#ifdef NOFIREWORKS
			if (erase_screen)
			    no_ulfire();
#endif
			underline();
		    }
		    if (*bufptr == '\n')
			putchar(' ');
		}
#ifdef INNERSEARCH
		outputok = !hide_everything;
					/* get it into register, hopefully */
#endif
#ifdef CLEAREOL
#ifdef INNERSEARCH
		if (outputok)
#endif
		maybe_eol();	
#endif /* CLEAREOL */
#ifdef CUSTOMLINES
		if (pagestop && bufptr == art_buf && 
		  execute(&page_compex,art_buf) )
		    linenum = 32700;
#endif
		for (outpos = 0; outpos < COLS; ) {
				    /* while line has room */
		    if (*(unsigned char *)bufptr >= ' ') { /* normal char? */
#ifdef ULSMARTS
			if (*bufptr == '_') {
			    if (bufptr[1] == '\b') {
				if (!under_lining && highlight!=artline
#ifdef INNERSEARCH
				    && outputok
#endif
				    ) {
				    under_lining++;
				    if (UG) {
					if (bufptr != buf &&
					  bufptr[-1] == ' ') {
					    outpos--;
					    backspace();
					}
				    }
				    underline();
				}
				bufptr += 2;
			    }
			}
			else {
			    if (under_lining) {
				under_lining = 0;
				un_underline();
				if (UG) {
				    if (*bufptr == ' ')
					goto skip_put;
				    outpos++;
				}
			    }
			}
#endif
#ifdef INNERSEARCH
			if (outputok)
#endif
			{
#ifdef ROTATION
			    if (rotate && !in_header
			      && isalpha(*bufptr)) {
				if ((*bufptr & 31) <= 13)
				    putchar(*bufptr+13);
				else
				    putchar(*bufptr-13);
			    }
			    else
#endif
				putchar(*bufptr);
			}
			if (*UC && ((highlight==artline && marking == 1)
#ifdef ULSMARTS
			    || under_lining
#endif
			    )) {
			    backspace();
			    underchar();
			}
		    skip_put:
			bufptr++;
			outpos++;
		    }
		    else if (*bufptr == '\n' || !*bufptr) {
						    /* newline? */
#ifdef ULSMARTS
			if (under_lining) {
			    under_lining = 0;
			    un_underline();
			}
#endif
#ifdef DEBUGGING
			if (debug & DEB_INNERSRCH && outpos < COLS - 6) {
			    standout();
			    printf("%4d",artline); 
			    un_standout();
			}
#endif
#ifdef INNERSEARCH
			if (outputok)
#endif
			    putchar('\n') FLUSH;
			restart = 0;
			outpos = 1000;	/* signal normal \n */
		    }
		    else if (*bufptr == '\t') {	/* tab? */
			int incpos =  8 - outpos % 8;
#ifdef INNERSEARCH
			if (outputok)
#endif
			    if (GT)
				putchar(*bufptr);
			    else
				while (incpos--) putchar(' ');
			bufptr++;
			outpos += 8 - outpos % 8;
		    }
		    else if (*bufptr == '\f') {	/* form feed? */
#ifdef INNERSEARCH
			if (outputok)
#endif
			    fputs("^L",stdout);
			if (bufptr == blinebeg && highlight != artline)
			    linenum = 32700;
			    /* how is that for a magic number? */
			bufptr++;
			outpos += 2;
		    }
		    else {		/* other control char */
#ifdef INNERSEARCH
			if (outputok)
#endif
			{
			    putchar('^');
			    if (highlight == artline && *UC && marking == 1) {
				backspace();
				underchar();
				putchar(*bufptr+64);
				backspace();
				underchar();
			    }
			    else
				putchar(*bufptr+64);
			}
			bufptr++;
			outpos += 2;
		    }
		    
		} /* end of column loop */

		if (outpos < 1000) {/* did line overflow? */
		    restart = bufptr;
				    /* restart here next time */
		    if (!AM || XN) {/* no automatic margins on tty? */
#ifdef INNERSEARCH		    /* then move it down ourselves */
			if (outputok)
#endif
			    putchar('\n') FLUSH;
		    }
		    if (*bufptr == '\n')    /* skip the newline */
			restart = 0;
		}

		/* handle normal end of output line formalities */

		if (highlight == artline) {
					/* were we highlighting line? */
		    if (marking == STANDOUT)
			un_standout();
		    else
			un_underline();
		    highlight = -1;	/* no more we are */
		}
		artline++;	/* count the line just printed */
		if (artline - LINES + 1 > topline)
			    /* did we just scroll top line off? */
		    topline = artline - LINES + 1;
			    /* then recompute top line # */
	    }

	    /* determine actual position in file */

	    if (restart)	/* stranded somewhere in the buffer? */
		artpos += restart - blinebeg;
			    /* just calculate position */
	    else		/* no, ftell will do */
		artpos = ftell(artfp);
			    /* so do ftell */
	    vwtary(artline,artpos);	/* remember pos in file */
	} /* end of line loop */

#ifdef INNERSEARCH
	innersearch = 0;
	if (hide_everything) {
	    hide_everything = FALSE;
	    *buf = Ctl('l');
	    goto fake_command;
	}
#endif
	if (linenum >= 32700)/* did last line have formfeed? */
	    vwtary(artline-1,-vrdary(artline-1));
			    /* remember by negating pos in file */

	special = FALSE;	/* end of page, so reset page length */
	firstpage = FALSE;	/* and say it is not 1st time thru */

	/* extra loop bombout */

	if (artpos == artsize) {/* did we just now reach EOF? */
	    mode = oldmode;
	    return DA_NORM;	/* avoid --MORE--(100%) */
	}

/* not done with this article, so pretend we are a pager */

reask_pager:		    
	unflush_output();	/* disable any ^O in effect */
	standout();		/* enter standout mode */
	printf("--MORE--(%ld%%)",(long)(artpos*100/artsize));
	un_standout();	/* leave standout mode */
#ifdef CLEAREOL
 	maybe_eol();
#endif
	fflush(stdout);
/* reinp_pager:     			/* unused, commented for lint */
	eat_typeahead();
#ifdef DEBUGGING
	if (debug & DEB_CHECKPOINTING) {
	    printf("(%d %d %d)",checkcount,linenum,artline);
	    fflush(stdout);
	}
#endif
	if (checkcount >= docheckwhen &&
	  linenum == LINES &&
	  (artline > 40 || checkcount >= docheckwhen+10) ) {
			    /* while he is reading a whole page */
			    /* in an article he is interested in */
	    checkcount = 0;
	    checkpoint_rc();	/* update .newsrc */
	}
	collect_subjects();		/* loads subject cache until */
					/* input is pending */
	mode = 'p';
	getcmd(buf);
	if (errno) {
	    if (LINES < 100 && !int_count)
		*buf = '\f';/* on CONT fake up refresh */
	    else {
		*buf = 'q';	/* on INTR or paper just quit */
	    }
	}
	carriage_return();
#ifndef CLEAREOL
	erase_eol();	/* and erase the prompt */
#else
	if (erase_screen && can_home_clear)	
	    clear_rest();
	else
	    erase_eol();	/* and erase the prompt */
#endif /* CLEAREOL */
	carriage_return();	/* Resets kernel's tab column counter to 0 */
	fflush(stdout);

    fake_command:		/* used by innersearch */

	/* parse and process pager command */

	switch (page_switch()) {
	case PS_ASK:	/* reprompt "--MORE--..." */
	    goto reask_pager;
	case PS_RAISE:	/* reparse on article level */
	    mode = oldmode;
	    return DA_RAISE;
	case PS_TOEND:	/* fast pager loop exit */
	    mode = oldmode;
	    return DA_TOEND;
	case PS_NORM:	/* display more article */
	    break;
	}
    } /* end of page loop */
}

/* process pager commands */

int
page_switch()
{
    register char *s;
    
    switch (*buf) {
    case 'd':
    case Ctl('d'):	/* half page */
	special = TRUE;
	slines = LINES / 2 + 1;
	if (marking && *blinebeg != '\f'
#ifdef CUSTOMLINES
	  && (!pagestop || blinebeg != art_buf ||
	      !execute(&page_compex,blinebeg))
#endif
	  ) {
	    up_line();
	    highlight = --artline;
	    restart = blinebeg;
	    artpos = alinebeg;
	}
	return PS_NORM;
    case '!':			/* shell escape */
	escapade();
	return PS_ASK;
#ifdef INNERSEARCH
    case Ctl('i'):
	gline = 3;
	sprintf(cmd_buf,"^[^%c]",*blinebeg);
	compile(&gcompex,cmd_buf,TRUE,TRUE);
	goto caseG;
    case Ctl('g'):
	gline = 3;
	compile(&gcompex,"^Subject:",TRUE,TRUE);
	goto caseG;
    case 'g':		/* in-article search */
	if (!finish_command(FALSE))/* get rest of command */
	    return PS_ASK;
	s = buf+1;
	if (isspace(*s))
	    s++;
	if ((s = compile(&gcompex,s,TRUE,TRUE)) != Nullch) {
			    /* compile regular expression */
	    printf("\n%s\n",s) FLUSH;
	    return PS_ASK;
	}
	carriage_return();
	erase_eol();	/* erase the prompt */
	carriage_return();	/* Resets kernel's tab column counter to 0 */
	/* FALL THROUGH */
    caseG:
    case 'G': {
	/* ART_LINE lines_to_skip = 0; */
	ART_POS start_where;

	if (gline < 0 || gline > LINES-2)
	    gline = LINES-2;
#ifdef DEBUGGING
	if (debug & DEB_INNERSRCH)
	    printf("Start here? %d  >=? %d\n",topline + gline + 1,artline)
	      FLUSH;
#endif
	if (*buf == Ctl('i') || topline+gline+1 >= artline)
	    start_where = artpos;
			/* in case we had a line wrap */
	else {
	    start_where = vrdary(topline+gline+1);
	    if (start_where < 0)
		start_where = -start_where;
	}
	if (start_where < htype[PAST_HEADER].ht_minpos)
	    start_where = htype[PAST_HEADER].ht_minpos;
	fseek(artfp,(long)start_where,0);
	innersearch = 0; /* assume not found */
	while (fgets(buf, sizeof buf, artfp) != Nullch) {
	    /* lines_to_skip++; 		NOT USED NOW */
#ifdef DEBUGGING
	    if (debug & DEB_INNERSRCH)
		printf("Test %s",buf) FLUSH;
#endif
	    if (execute(&gcompex,buf) != Nullch) {
		innersearch = ftell(artfp);
		break;
	    }
	}
	if (!innersearch) {
	    fseek(artfp,artpos,0);
	    fputs("(Not found)",stdout) FLUSH;
	    return PS_ASK;
	}
#ifdef DEBUGGING
	if (debug & DEB_INNERSRCH)
	    printf("On page? %ld <=? %ld\n",(long)innersearch,(long)artpos)
	      FLUSH;
#endif
	if (innersearch <= artpos) {	/* already on page? */
	    if (innersearch < artpos) {
		artline = topline+1;
		while (vrdary(artline) < innersearch)
		    artline++;
	    }
	    highlight = artline - 1;
#ifdef DEBUGGING
	    if (debug & DEB_INNERSRCH)
		printf("@ %d\n",highlight) FLUSH;
#endif
	    topline = highlight - gline;
	    if (topline < -1)
		topline = -1;
	    *buf = '\f';		/* fake up a refresh */
	    innersearch = 0;
	    return page_switch();
	}
	else {				/* who knows how many lines it is? */
	    do_fseek = TRUE;
	    hide_everything = TRUE;
	}
	return PS_NORM;
    }
#else
    case 'g': case 'G': case Ctl('g'):
	notincl("g");
	return PS_ASK;
#endif
    case '\n':		/* one line */
	special = TRUE;
	slines = 2;
	return PS_NORM;
#ifdef ROTATION
    case 'X':
	rotate = !rotate;
	/* FALL THROUGH */
#endif
    case 'l':
    case '\f':		/* refresh screen */
#ifdef DEBUGGING
	if (debug & DEB_INNERSRCH) {
	    printf("Topline = %d",topline) FLUSH;
	    gets(buf);
	}
#endif
	clear();
	carriage_return();	/* Resets kernel's tab column counter to 0 */
	do_fseek = TRUE;
	artline = topline;
	if (artline < 0)
	    artline = 0;
	firstpage = (topline < 0);
	return PS_NORM;
    case 'b':
    case '\b':
    case Ctl('b'): {	/* back up a page */
	ART_LINE target;

#ifndef CLEAREOL
	clear();
#else
	if (can_home_clear)	/* if we can home do it */
	    home_cursor();
	else
	    clear();

#endif /* CLEAREOL */
	carriage_return();	/* Resets kernel's tab column counter to 0 */
	do_fseek = TRUE;	/* reposition article file */
	target = topline - (LINES - 2);
	artline = topline;
	if (artline >= 0) do {
	    artline--;
	} while(artline >= 0 && artline > target && vrdary(artline-1) >= 0);
	topline = artline;
			/* remember top line of screen */
			/*  (line # within article file) */
	if (artline < 0)
	    artline = 0;
	firstpage = (topline < 0);
	return PS_NORM;
    }
    case 'h': {		/* help */
	int cmd;

	if ((cmd = help_page()) > 0)
	    pushchar(cmd);
	return PS_ASK;
    }
    case '\177':
    case '\0':		/* treat del,break as 'n' */
	*buf = 'n';
	/* FALL THROUGH */
    case 'k':	case 'K':
    case 'n':	case 'N':	case Ctl('n'):
    case 's':	case 'S':
    case 'e':
    case 'u':
    case 'w':	case 'W':
    case '|':
	mark_as_read();		/* mark article as read */
	/* FALL THROUGH */
    case '#':
    case '$':
    case '&':
    case '-':
    case '.':
    case '/':
    case '1': case '2': case '3': case '4': case '5':
    case '6': case '7': case '8': case '9':
    case '=':
    case '?':
    case 'c':	case 'C':	
#ifdef DEBUGGING
    case 'D':
#endif
    case 'E':
    case 'f':	case 'F':	
    case 'j':
				case Ctl('k'):
    case 'm':	case 'M':	
    case 'p':	case 'P':	case Ctl('p'):	
		case 'Q':
    case 'r':	case 'R':	case Ctl('r'):
    case 'v':
		case 'Y':
#ifndef ROTATION
    case 'x':	case 'X':
#endif
    case Ctl('x'):
    case 'z':
    case '^':

#ifdef ROTATION
	rotate = FALSE;
#endif
	reread = FALSE;
	do_hiding = TRUE;
	if (index("nNpP\016\020",*buf) == Nullch &&
	  index("wWsSe:!&|/?123456789.",*buf) != Nullch) {
	    setdfltcmd();
	    standout();		/* enter standout mode */
	    printf(prompt,mailcall,dfltcmd);
			    /* print prompt, whatever it is */
	    un_standout();	/* leave standout mode */
	    putchar(' ');
	    fflush(stdout);
	}
	return PS_RAISE;	/* and pretend we were at end */
#ifdef ROTATION
    case 'x':
	rotate = TRUE;
	/* FALL THROUGH */
#endif
    case 'y':
    case Ctl('v'):
					/* Leaving it undocumented in case */
					/* I want to steal the key--LAW */
    case ' ':	/* continue current article */
	if (erase_screen) {	/* -e? */
#ifndef CLEAREOL
	    clear();		/* clear screen */
#else
	    if (can_home_clear)	/* if we can home do it */
		home_cursor();
	    else
		clear();	/* else clear screen */

#endif /* CLEAREOL */
	    carriage_return();	/* Resets kernel's tab column counter to 0 */
	    fflush(stdout);

	    if (*blinebeg != '\f'
#ifdef CUSTOMLINES
	      && (!pagestop || blinebeg != art_buf ||
	          !execute(&page_compex,blinebeg))
#endif
	      ) {
		restart = blinebeg;
		artline--;	 /* restart this line */
		artpos = alinebeg;
		if (marking)	/* and mark repeated line */
		    highlight = artline;
	    }
	    topline = artline;
			/* and remember top line of screen */
			/*  (line # within article file) */
	}
	else if (marking && *blinebeg != '\f'
#ifdef CUSTOMLINES
	  && (!pagestop || blinebeg != art_buf ||
	      !execute(&page_compex,blinebeg))
#endif
	  ) {
				/* are we marking repeats? */
	    up_line();		/* go up one line */
	    highlight = --artline;/* and get ready to highlight */
	    restart = blinebeg;	/*   the old line */
	    artpos = alinebeg;
	}
	return PS_NORM;
    case 'q':	/* quit this article? */
	do_hiding = TRUE;
	return PS_TOEND;
    default:
	fputs(hforhelp,stdout) FLUSH;
	settle_down();
	return PS_ASK;
    }
}

#ifdef INNERSEARCH
bool
innermore()
{
    if (artpos < innersearch) {		/* not even on page yet? */
#ifdef DEBUGGING
	if (debug & DEB_INNERSRCH)
	    printf("Not on page %ld < %ld\n",(long)artpos,(long)innersearch)
	      FLUSH;
#endif
	return TRUE;
    }
    if (artpos == innersearch) {	/* just got onto page? */
	isrchline = artline;		/* remember first line after */
	highlight = artline - 1;
#ifdef DEBUGGING
	if (debug & DEB_INNERSRCH)
	    printf("There it is %ld = %ld, %d @ %d\n",(long)artpos,
		(long)innersearch,hide_everything,highlight) FLUSH;
#endif
	if (hide_everything) {		/* forced refresh? */
	    topline = highlight - gline;
	    if (topline < -1)
		topline = -1;
	    return FALSE;		/* let refresh do it all */
	}
    }
#ifdef DEBUGGING
    if (debug & DEB_INNERSRCH)
	printf("Not far enough? %d <? %d + %d\n",artline,isrchline,gline)
	  FLUSH;
#endif
    if (artline < isrchline + gline) {
	return TRUE;
    }
    return FALSE;
}
#endif
!STUFFY!FUNK!
echo Extracting rn.c
cat >rn.c <<'!STUFFY!FUNK!'
/*  rn -- new readnews program
 *
 *  Original Author: lwall@sdcrdcf.UUCP (Larry Wall)
 *  Organization: System Development Corporation, Santa Monica
 *  Current Author/Maintainer: sob@bcm.tmc.edu (Stan Barber)
 *  Organization: Baylor College of Medicine, Houston,Tx
 *
 *  begun:   01/14/83
 *	1.0: 04/08/83
 *      2.0: 09/01/83
 *      RRN/RN: 11/01/89
 *      4.4  07/04/91
 */
/* This software is Copyright 1991 by Stan Barber. 
 *
 * Permission is hereby granted to copy, reproduce, redistribute or otherwise
 * use this software as long as: there is no monetary profit gained
 * specifically from the use or reproduction of this software, it is not
 * sold, rented, traded or otherwise marketed, and this copyright notice is
 * included prominently in any copy made. 
 *
 * The author make no claims as to the fitness or correctness of this software
 * for any use whatsoever, and it is provided as is. Any use of this software
 * is at the user's own risk. 
 */

static char rnid[] = "@(#)$Id: rn.c,v 4.4 1991/09/09 20:27:37 sob Exp sob $";
static char patchlevel[] = "Pathlevel 0";

/* $Log: rn.c,v $
 * Revision 4.4  1991/09/09  20:27:37  sob
 * release 4.4
 *
 *
 *
 * 
 */

#include "INTERN.h"
#include "common.h"
#include "rn.h"
#ifdef SERVER
#include "server.h"
#endif
#include "EXTERN.h"
#include "rcstuff.h"
#include "term.h"
#include "final.h"
#include "ngdata.h"
#include "util.h"
#include "only.h"
#include "ngsrch.h"
#include "help.h"
#include "last.h"
#include "init.h"
#include "intrp.h"
#include "rcln.h"
#include "sw.h"
#include "addng.h"
#include "ng.h"

void
rn_init()
{
    ;
}

void
main(argc,argv)
int argc;
char *argv[];
{
    bool foundany;
    register char *s;
    bool oh_for_the_good_old_days = FALSE;
    foundany = initialize(argc,argv);

    if (maxngtodo)
	starthere = 0;
    else if (!foundany) {		/* nothing to do? */
#ifdef VERBOSE
	if (verbose)
	    fputs("\
No unread news in subscribed-to newsgroups.  To subscribe to a new\n\
newsgroup use the g<newsgroup> command.\n\
",stdout) FLUSH;
#endif
	starthere = nextrcline;
    }

    /* loop through all unread news */

    {
	char promptbuf[80];
	bool special = FALSE;		/* temporarily allow newsgroup */
					/*   with no unread news? */
	bool retry;			/* cycle back to top of list? */
	NG_NUM recent_ng = 0;
	
	current_ng = 0;
	do {
	    retry = FALSE;
	    if (findlast) {
		findlast = FALSE;
		starthere = 0;
		if (*lastngname) {
		    if ((ng = find_ng(lastngname)) == nextrcline)
			ng = 0;
		    else {
			set_ngname(lastngname);
		    	set_toread(ng);
			if (toread[ng] <= TR_NONE)
			    ng = 0;
		    }
		}
	    }
	    else {
		ng = starthere;
		starthere = 0;
	    }
	    while (ng <= nextrcline) {	/* for each newsgroup */
		mode = 'n';
		if (ng >= nextrcline) {	/* after the last newsgroup? */
		    ng = nextrcline;	/* force it to 1 after */
#ifdef ONLY
		    if (maxngtodo) {
			if (retry)
#ifdef VERBOSE
			    IF(verbose)
				printf("\nRestriction %s%s still in effect.\n",
				    ngtodo[0],
				    maxngtodo > 1 ? ", etc." : nullstr) FLUSH;
			    ELSE
#endif
#ifdef TERSE
				fputs("\n(\"Only\" mode.)\n",stdout) FLUSH;
#endif
			else {
#ifdef VERBOSE
			    IF(verbose)
				fputs("\nNo articles under restriction.",
				  stdout) FLUSH;
			    ELSE
#endif
#ifdef TERSE
				fputs("\nNo \"only\" articles.",stdout) FLUSH;
#endif
			    end_only();	/* release the restriction */
			    retry = TRUE;
			}
		    }
#endif
		    dfltcmd = (retry ? "npq" : "qnp");
#ifdef VERBOSE
		    IF(verbose)
			sprintf(promptbuf,
			    "\n******** End of newsgroups--what next? [%s] ",
			    dfltcmd);
		    ELSE
#endif
#ifdef TERSE
			sprintf(promptbuf,
			    "\n**** End--next? [%s] ", dfltcmd);
#endif
		}
		else {
		    bool shoe_fits;	/* newsgroup matches restriction? */

		    if (toread[ng] >= TR_NONE) {	/* recalc toread? */
			set_ngname(rcline[ng]);
			if (shoe_fits = (special || inlist(ngname)))
			    set_toread(ng);
			if (paranoid) {
			    recent_ng = current_ng;
			    current_ng = ng;
			    cleanup_rc();
					/* this may move newsgroups around */
			    ng = current_ng;
			    set_ngname(rcline[ng]);
			}
		    }
		    if (toread[ng] < (maxngtodo||special ? TR_NONE : TR_ONE) || !shoe_fits) {
					/* unwanted newsgroup? */
			ng++;		/* then skip it */
			continue;
		    }
    reprompt_newsgroup:
		    dfltcmd = "ynq";
#ifdef VERBOSE
		    IF(verbose)
			sprintf(promptbuf,
			    "\n******** %3ld unread article%s in %s--read now? [%s] ",
			    (long)toread[ng], (toread[ng]==TR_ONE ? nullstr : "s"),
			    ngname, dfltcmd);	/* format prompt string */
		    ELSE
#endif
#ifdef TERSE
			sprintf(promptbuf,
			    "\n**** %3ld in %s--read? [%s] ",
			    (long)toread[ng],
			    ngname,dfltcmd);	/* format prompt string */
#endif
		}
		special = FALSE;	/* go back to normal mode */
		if (ng != current_ng) {
		    recent_ng = current_ng;
					/* remember previous newsgroup */
		    current_ng = ng;	/* remember current newsgroup */
		}
    reask_newsgroup:
		unflush_output();	/* disable any ^O in effect */
		fputs(promptbuf,stdout) FLUSH;/* print prompt */
		fflush(stdout);
    reinp_newsgroup:
		eat_typeahead();
		getcmd(buf);
		if (errno || *buf == '\f') {
		    putchar('\n') FLUSH; /* if return from stop signal */
		    goto reask_newsgroup;	/* give them a prompt again */
		}
		setdef(buf,dfltcmd);
#ifdef VERIFY
		printcmd();
#endif
		switch (*buf) {
		case 'p':		/* find previous unread newsgroup */
		    do {
			if (ng <= 0)
			    break;
			ng--;
			if (toread[ng] == TR_NONE)
			    set_toread(ng);
		    } while (toread[ng] <= TR_NONE);
		    break;
		case 'P':		/* goto previous newsgroup */
		    do {
			if (ng <= 0)
			    break;
			ng--;
		    } while (toread[ng] < TR_NONE);
		    special = TRUE;	/* don't skip it if toread==0 */
		    break;
		case '-':
		    ng = recent_ng;	/* recall previous newsgroup */
		    special = TRUE;	/* don't skip it if toread==0 */
		    break;
		case 'q': case 'Q': case 'x':	/* quit? */
		    oh_for_the_good_old_days = (*buf == 'x');
		    putchar('\n') FLUSH;
		    ng = nextrcline+1;	/* satisfy */
		    retry = FALSE;	/*   loop conditions */
		    break;
		case '^':
		    putchar('\n') FLUSH;
		    ng = 0;
		    break;
		case 'n':		/* find next unread newsgroup */
		    if (ng == nextrcline) {
			putchar('\n') FLUSH;
			retry = TRUE;
		    }
		    else if (toread[ng] > TR_NONE)
			retry = TRUE;
		    ng++;
		    break;
		case 'N':		/* goto next newsgroup */
		    ng++;
		    special = TRUE;	/* and don't skip it if toread==0 */
		    break;
		case '1':		/* goto 1st newsgroup */
		    ng = 0;
		    special = TRUE;	/* and don't skip it if toread==0 */
		    break;
		case '$':
		    ng = nextrcline;	/* goto last newsgroup */
		    retry = TRUE;
		    break;
		case 'L':
		    list_newsgroups();
		    goto reask_newsgroup;
		case '/': case '?':	/* scan for newsgroup pattern */
#ifdef NGSEARCH
		    switch (ng_search(buf,TRUE)) {
		    case NGS_ERROR:
			goto reask_newsgroup;
		    case NGS_ABORT:
			goto reinp_newsgroup;
		    case NGS_INTR:
#ifdef VERBOSE
			IF(verbose)
			    fputs("\n(Interrupted)\n",stdout) FLUSH;
			ELSE
#endif
#ifdef TERSE
			    fputs("\n(Intr)\n",stdout) FLUSH;
#endif
			ng = current_ng;
			goto reask_newsgroup;
		    case NGS_FOUND:
			special = TRUE;	/* don't skip it if toread==0 */
			break;
		    case NGS_NOTFOUND:
#ifdef VERBOSE
			IF(verbose)
			    fputs("\n\nNot found--use g to add newsgroups\n",
				stdout) FLUSH;
			ELSE
#endif
#ifdef TERSE
			    fputs("\n\nNot found\n",stdout) FLUSH;
#endif
			goto reask_newsgroup;
		    }
#else
		    notincl("/");
#endif
		    break;
		case 'm':
#ifndef RELOCATE
		    notincl("m");
		    break;
#endif		    
		case 'g':	/* goto named newsgroup */
		    if (!finish_command(FALSE))
					/* if they didn't finish command */
			goto reinp_newsgroup;	/* go try something else */
		    for (s = buf+1; *s == ' '; s++);
					/* skip leading spaces */
#ifdef RELOCATE
		    if (!*s && *buf == 'm' && ngname && ng < nextrcline)
			strcpy(s,ngname);
#endif
		    if (isalpha(*s)) 
			set_ngname(s);
		    else {
			if (isdigit(*s)) {
			    int rcnum;
			    rcnum = atoi(s);
			    if (rcnum < nextrcline)
				set_ngname(rcline[rcnum]);
			    else {
				printf("\nOnly %d groups. Try again.\n",
					nextrcline) FLUSH;
				goto reask_newsgroup;
			    }
			}
			else {
			    printf("\nNo newsgroup entered.\n") FLUSH;
			    goto reask_newsgroup;
			}
		    }
#ifdef RELOCATE
		    if (!get_ng(ngname,*buf=='m'))
						/* try to find newsgroup */
#else
		    if (!get_ng(ngname,FALSE))	/* try to find newsgroup */
#endif
			ng = current_ng;/* if not found, go nowhere */
		    special = TRUE;	/* don't skip it if toread==0 */
		    break;
#ifdef DEBUGGING
		case 'D':
		    printf("\nTries: %d Hits: %d\n",
			softtries,softtries-softmisses) FLUSH;
		    goto reask_newsgroup;
#endif
		case '!':		/* shell escape */
		    if (escapade())	 /* do command */
			goto reinp_newsgroup;
					/* if rubbed out, re input */
		    goto reask_newsgroup;
		case Ctl('k'):		/* edit global KILL file */
		    edit_kfile();
		    goto reask_newsgroup;
		case 'c':		/* catch up */
#ifdef CATCHUP
reask_catchup:
#ifdef VERBOSE
		IF(verbose)
		    in_char("\nDo you really want to mark everything as read? [yn] ", 'C');
		ELSE
#endif
#ifdef TERSE
		    in_char("\nReally? [ynh] ", 'C');
#endif
		    setdef(buf,"y");
#ifdef VERIFY
		    printcmd();
#endif
		    putchar('\n') FLUSH;
		    if (*buf == 'h') {
#ifdef VERBOSE
		    printf("Type y or SP to mark all articles as read.\n");
		    printf("Type n to leave articles marked as they are.\n");
#else
		    printf("y or SP to mark all read.\n");
		    printf("n to forget it.\n");
#endif
			goto reask_catchup;
		    }
		    else if (*buf!=' ' && *buf!='y' && *buf!='n' && *buf!='q') {
			printf(hforhelp);
			settle_down();
			goto reask_catchup;
		    } else if ( (*buf == ' ' || *buf == 'y') && ng<nextrcline )
			catch_up(ng);
		    else
			retry = TRUE;
		    ng++;
#else
		    notincl("c");
#endif
		    break;
		case 'u':		/* unsubscribe */
		    if (ng < nextrcline && toread[ng] >= TR_NONE) {
					/* unsubscribable? */
			printf(unsubto,rcline[ng]) FLUSH;
			rcchar[ng] = NEGCHAR;
					/* unsubscribe to (from?) it */
			toread[ng] = TR_UNSUB;
					/* and make line invisible */
			ng++;		/* do an automatic 'n' */
		    }
		    break;
		case 'h': {		/* help */
		    int cmd;

		    if ((cmd = help_ng()) > 0)
			pushchar(cmd);
		    goto reask_newsgroup;
		}
		case 'a':
#ifndef FINDNEWNG
		    notincl("a");
		    goto reask_newsgroup;
#else
		    /* FALL THROUGH */
#endif
		case 'o':
#ifdef ONLY
		{
#ifdef FINDNEWNG
		    bool doscan = (*buf == 'a');
#endif

		    if (!finish_command(TRUE)) /* get rest of command */
			goto reinp_newsgroup;	/* if rubbed out, try something else */
		    end_only();
		    if (buf[1]) {
			bool minusd = instr(buf+1,"-d", TRUE) != Nullch;

			sw_list(buf+1);
			if (minusd)
			    cwd_check();
			putchar('\n') FLUSH;
#ifdef FINDNEWNG
			if (doscan && maxngtodo)
			    scanactive();
#endif
		    }
		    ng = 0;		/* simulate ^ */
		    retry = FALSE;
		    break;
		}
#else
		    notincl("o");
		    goto reask_newsgroup;
#endif
		case '&':
		    if (switcheroo()) /* get rest of command */
			goto reinp_newsgroup;	/* if rubbed out, try something else */
		    goto reask_newsgroup;
		case 'l': {		/* list other newsgroups */
		    if (!finish_command(TRUE)) /* get rest of command */
			goto reinp_newsgroup;	/* if rubbed out, try something else */
		    for (s = buf+1; *s == ' '; s++);
		    			/* skip leading spaces */
		    sprintf(cmd_buf,"%s '%s'",filexp(NEWSGROUPS),s);
		    resetty();
		    if (doshell(sh,cmd_buf))
#ifdef VERBOSE
			IF(verbose)
			    fputs("    (Error from newsgroups program)\n",
				stdout) FLUSH;
			ELSE
#endif
#ifdef TERSE
			    fputs("(Error)\n",stdout) FLUSH;
#endif
		    noecho();
		    crmode();
		    goto reask_newsgroup;
		}
		case '.': case '=':
		case 'y': case 'Y': /* do normal thing */
		    if (ng >= nextrcline) {
			fputs("\nNot on a newsgroup.",stdout) FLUSH;
			goto reask_newsgroup;
		    }
		    if (*buf == '=')
			s = savestr("=");
		    else if (*buf == '.') {	/* start command? */
			if (!finish_command(FALSE)) /* get rest of command */
			    goto reinp_newsgroup;
			s = savestr(buf+1);
					/* do_newsgroup will free it */
		    }
		    else
			s = Nullch;
		    if (toread[ng])
			retry = TRUE;
		    switch (do_newsgroup(s)) {
		    case NG_ERROR:
		    case NG_NORM:
			ng++;
			break;
		    case NG_ASK:
			goto reprompt_newsgroup;
		    case NG_MINUS:
			ng = recent_ng;	/* recall previous newsgroup */
			special = TRUE;	/* don't skip it if toread==0 */
			break;
		    }
		    break;
#ifdef STRICTCR
		case '\n':
		    fputs(badcr,stdout) FLUSH;
		    goto reask_newsgroup;
#endif
		case 'v':
		    printf("\n%s",rnid);
		    printf("\n%s",patchlevel);
		    printf("\nSend bugs to rrn@lib.tmc.edu (...!uunet!bcm!rrn)\n") FLUSH;
		    goto reask_newsgroup;
		default:
		    printf("\n%s",hforhelp) FLUSH;
		    settle_down();
		    goto reask_newsgroup;
		}
	    }
	} while (retry);
    }

    /* now write .newsrc back out */

    write_rc();

    if (oh_for_the_good_old_days)
	get_old_rc();

    finalize(0);			/* and exit */
}

/* set current newsgroup */

void
set_ngname(what)
char *what;
{
    int len = strlen(what)+1;

    growstr(&ngname,&ngnlen,len);
    strcpy(ngname,what);
    growstr(&ngdir,&ngdlen,len);
    strcpy(ngdir,getngdir(ngname));
}

static char *myngdir;
static int ngdirlen = 0;

char *
getngdir(ngnam)
char *ngnam;
{
    register char *s;

    growstr(&myngdir,&ngdirlen,strlen(ngnam)+1);
    strcpy(myngdir,ngnam);
    for (s = myngdir; *s; s++)
	if (*s == '.')
	    *s = '/';
    return myngdir;
}
!STUFFY!FUNK!
echo Extracting autosub.c
cat >autosub.c <<'!STUFFY!FUNK!'
/*
 * $Id: autosub.c,v 4.4 1991/09/09 20:18:23 sob Exp sob $
 *
 * $Log: autosub.c,v $
 * Revision 4.4  1991/09/09  20:18:23  sob
 * release 4.4
 *
 *
 *
 */
/* This software is Copyright 1991 by Stan Barber. 
 *
 * Permission is hereby granted to copy, reproduce, redistribute or otherwise
 * use this software as long as: there is no monetary profit gained
 * specifically from the use or reproduction of this software, it is not
 * sold, rented, traded or otherwise marketed, and this copyright notice is
 * included prominently in any copy made. 
 *
 * The author make no claims as to the fitness or correctness of this software
 * for any use whatsoever, and it is provided as is. Any use of this software
 * is at the user's own risk. 
 */

#include "EXTERN.h"
#include "common.h"
#include "ngsrch.h"
#include "search.h"
#include "util.h"
#include "INTERN.h"
#include "autosub.h"

/* Consider the newsgroup specified, and return:	*/
/* : if we should autosubscribe to it			*/
/* ! if we should autounsubscribe to it			*/
/* \0 if we should ask the user.			*/
int
auto_subscribe(ng)
char *ng;
{
    char *s;

    if((s = getval("AUTOSUBSCRIBE", (char *)NULL))
	&& matchlist(s, ng)) return ':';
    if((s = getval("AUTOUNSUBSCRIBE", (char *)NULL))
	&& matchlist(s, ng)) return '!';
    return 0;
}

bool
matchlist(patlist, s)
char *patlist;
char *s;
{
    COMPEX ilcompex;
    char *p;
    char *err;
    bool result;
    bool tmpresult;

    result = FALSE;
    init_compex(&ilcompex);
    while(patlist && *patlist) {

	if(*patlist == '!') {
		patlist++;
		tmpresult = FALSE;
	} else tmpresult = TRUE;

	if(p = index(patlist, ',')) *p = '\0';
        /* compile regular expression */
	err = ng_comp(&ilcompex,patlist,TRUE,TRUE);
	if(p) *p++ = ',';

	if(err != Nullch) {
	    printf("\n%s\n", err) FLUSH;
	    finalize(1);
	}
	
	if (execute(&ilcompex,s) != Nullch)
	    result = tmpresult;
	patlist = p;
    }
    free_compex(&ilcompex);
    return result;
}
!STUFFY!FUNK!
echo ""
echo "End of kit 5 (of 10)"
cat /dev/null >kit5isdone
config=true
for iskit in 1 2 3 4 5 6 7 8 9 10 ; do
    if test -f kit${iskit}isdone; then
	echo "You have run kit ${iskit}."
    else
	echo "You still need to run kit ${iskit}."
	config=false
    fi
done
case $config in
    true)
	echo "You have run all your kits.  Please read README and then type Configure."
	chmod 755 Configure
	;;
esac
: I do not append .signature, but someone might mail this.
exit
