Article 2704 of comp.sources.unix:
Path: nntpd.lkg.dec.com!crl.dec.com!crl.dec.com!bloom-beacon.mit.edu!news.kei.com!news.mathworks.com!newsfeed.internetmci.com!in1.uu.net!news1.digital.com!vixie!vixie!not-for-mail
From: davison@borland.com (Wayne Davison)
Newsgroups: comp.sources.unix
Subject: v29i046: trn-3.6 - threaded newsreader based on RN, V3.6, Part09/14
Date: 29 Oct 1995 01:32:58 -0800
Organization: Vixie Enterprises
Lines: 3801
Sender: vixie@vix.com
Approved: vixie@gw.home.vix.com
Message-ID: <46vhoa$t50@gw.home.vix.com>
References: <1.814959141.29825@gw.home.vix.com>
NNTP-Posting-Host: gw.home.vix.com

Submitted-By: davison@borland.com (Wayne Davison)
Posting-Number: Volume 29, Issue 46
Archive-Name: trn-3.6/part09

#!/bin/sh
# This is `part09' (part 9 of a multipart archive).
# Do not concatenate these parts, unpack them in order with `/bin/sh'.
# File `trn-3.6/rthread.c' is being continued...
#
touch -am 1231235999 $$.touch >/dev/null 2>&1
if test ! -f 1231235999 && test -f $$.touch; then
  shar_touch=touch
else
  shar_touch=:
  echo
  echo 'WARNING: not restoring timestamps.  Consider getting and'
  echo "installing GNU \`touch', distributed in GNU File Utilities..."
  echo
fi
rm -f 1231235999 $$.touch
#
if test ! -r _sharseq.tmp; then
  echo 'Please unpack part 1 first!'
  exit 1
fi
shar_sequence=`cat _sharseq.tmp`
if test "$shar_sequence" != 9; then
  echo "Please unpack part $shar_sequence next!"
  exit 1
fi
if test ! -f _sharnew.tmp; then
  echo 'x - still skipping trn-3.6/rthread.c'
else
  echo 'x - continuing file trn-3.6/rthread.c'
  sed 's/^X//' << 'SHAR_EOF' >> 'trn-3.6/rthread.c' &&
X    return TRUE;
X}
X
XSUBJECT *
Xnext_subj(sp, subj_mask)
Xregister SUBJECT *sp;
Xint subj_mask;
X{
X    if (!sp)
X	sp = first_subject;
X    else if (sel_mode == SM_THREAD) {
X	ARTICLE *ap = sp->thread;
X	do {
X	    sp = sp->next;
X	} while (sp && sp->thread == ap);
X    }
X    else
X	sp = sp->next;
X
X    while (sp && (sp->flags & subj_mask) != subj_mask) {
X	sp = sp->next;
X    }
X    return sp;
X}
X
XSUBJECT *
Xprev_subj(sp, subj_mask)
Xregister SUBJECT *sp;
Xint subj_mask;
X{
X    if (!sp)
X	sp = last_subject;
X    else if (sel_mode == SM_THREAD) {
X	ARTICLE *ap = sp->thread;
X	do {
X	    sp = sp->prev;
X	} while (sp && sp->thread == ap);
X    }
X    else
X	sp = sp->prev;
X
X    while (sp && (sp->flags & subj_mask) != subj_mask) {
X	sp = sp->prev;
X    }
X    return sp;
X}
X
X/* Select a single article.
X*/
Xvoid
Xselect_article(ap, auto_flags)
Xregister ARTICLE *ap;
Xint auto_flags;
X{
X    int desired_flags = (sel_rereading? AF_READ : 0);
X#ifdef VERBOSE
X    bool echo;
X
X    if (auto_flags & AUTO_ECHO) {
X	echo = TRUE;
X	auto_flags &= ~AUTO_ECHO;
X    } else
X	echo = FALSE;
X#else
X    auto_flags &= ~AUTO_ECHO;
X#endif
X    if (auto_flags & (AUTO_SELECT|AUTO_SELECTALL))
X	localkf_changes = 2;
X    if ((ap->flags & (AF_MISSING|AF_READ)) == desired_flags) {
X	if (!(ap->flags & sel_mask)) {
X	    selected_count++;
X#ifdef VERBOSE
X	    if (echo) {
X		IF(verbose)
X		    fputs("\tSelected",stdout);
X	    }
X#endif
X	}
X	ap->flags = (ap->flags & ~AF_DEL) | sel_mask;
X	ap->autofl |= auto_flags;
X    } else
X	ap->autofl |= auto_flags;
X    if (ap->subj) {
X	if (!(ap->subj->flags & sel_mask))
X	    selected_subj_cnt++;
X	ap->subj->flags = (ap->subj->flags&~SF_DEL) | sel_mask | SF_VISIT;
X    }
X    selected_only = (selected_only || selected_count != 0);
X}
X
X/* Select this article's subject.
X*/
Xvoid
Xselect_arts_subject(ap, auto_flags)
Xregister ARTICLE *ap;
Xint auto_flags;
X{
X    if (ap->subj && ap->subj->articles)
X	select_subject(ap->subj, auto_flags);
X    else
X	select_article(ap, auto_flags);
X}
X
X/* Select all the articles in a subject.
X*/
Xvoid
Xselect_subject(subj, auto_flags)
XSUBJECT *subj;
Xint auto_flags;
X{
X    register ARTICLE *ap;
X    int desired_flags = (sel_rereading? AF_READ : 0);
X    int old_count = selected_count;
X
X    if (auto_flags & (AUTO_SELECT|AUTO_SELECTALL))
X	localkf_changes = 2;
X    for (ap = subj->articles; ap; ap = ap->subj_next) {
X	if ((ap->flags & (AF_MISSING|AF_READ|sel_mask)) == desired_flags) {
X	    ap->flags |= sel_mask;
X	    ap->autofl |= auto_flags;
X	    selected_count++;
X	} else
X	    ap->autofl |= auto_flags;
X    }
X    if (selected_count > old_count) {
X	if (!(subj->flags & sel_mask))
X	    selected_subj_cnt++;
X	subj->flags = (subj->flags & ~SF_DEL)
X		    | sel_mask | SF_VISIT | SF_WASSELECTED;
X	selected_only = TRUE;
X    } else
X	subj->flags |= SF_WASSELECTED;
X}
X
X/* Select this article's thread.
X*/
Xvoid
Xselect_arts_thread(ap, auto_flags)
Xregister ARTICLE *ap;
Xint auto_flags;
X{
X    if (ap->subj && ap->subj->thread)
X	select_thread(ap->subj->thread, auto_flags);
X    else
X	select_arts_subject(ap, auto_flags);
X}
X
X/* Select all the articles in a thread.
X*/
Xvoid
Xselect_thread(thread, auto_flags)
Xregister ARTICLE *thread;
Xint auto_flags;
X{
X    register SUBJECT *sp;
X
X    sp = thread->subj;
X    do {
X	select_subject(sp, auto_flags);
X	sp = sp->thread_link;
X    } while (sp != thread->subj);
X}
X
X/* Select the subthread attached to this article.
X*/
Xvoid
Xselect_subthread(ap, auto_flags)
Xregister ARTICLE *ap;
Xint auto_flags;
X{
X    register ARTICLE *limit;
X    SUBJECT *subj;
X    int desired_flags = (sel_rereading? AF_READ : 0);
X    int old_count = selected_count;
X
X    if (!ap)
X	return;
X    subj = ap->subj;
X    for (limit = ap; limit; limit = limit->parent) {
X	if (limit->sibling) {
X	    limit = limit->sibling;
X	    break;
X	}
X    }
X
X    if (auto_flags & (AUTO_SELECT|AUTO_SELECTALL))
X	localkf_changes = 2;
X    for (; ap != limit; ap = bump_art(ap)) {
X	if ((ap->flags & (AF_MISSING|AF_READ|sel_mask)) == desired_flags) {
X	    ap->flags |= sel_mask;
X	    ap->autofl |= auto_flags;
X	    selected_count++;
X	} else
X	    ap->autofl |= auto_flags;
X    }
X    if (subj && selected_count > old_count) {
X	if (!(subj->flags & sel_mask))
X	    selected_subj_cnt++;
X	subj->flags = (subj->flags & ~SF_DEL) | sel_mask | SF_VISIT;
X	selected_only = TRUE;
X    }
X}
X
X/* Deselect a single article.
X*/
Xvoid
Xdeselect_article(ap)
Xregister ARTICLE *ap;
X{
X    if (ap->flags & sel_mask) {
X	ap->flags &= ~sel_mask;
X	if (!selected_count--)
X	    selected_count = 0;
X#ifdef VERBOSE
X	if (mode != 't') {
X	    IF(verbose)
X		fputs("\tDeselected",stdout);
X	}
X#endif
X    }
X    if (sel_rereading && sel_mode == SM_ARTICLE)
X	ap->flags |= AF_DEL;
X}
X
X/* Deselect this article's subject.
X*/
Xvoid
Xdeselect_arts_subject(ap)
Xregister ARTICLE *ap;
X{
X    if (ap->subj && ap->subj->articles)
X	deselect_subject(ap->subj);
X    else
X	deselect_article(ap);
X}
X
X/* Deselect all the articles in a subject.
X*/
Xvoid
Xdeselect_subject(subj)
XSUBJECT *subj;
X{
X    register ARTICLE *ap;
X
X    for (ap = subj->articles; ap; ap = ap->subj_next) {
X	if (ap->flags & sel_mask) {
X	    ap->flags &= ~sel_mask;
X	    if (!selected_count--)
X		selected_count = 0;
X	}
X    }
X    if (subj->flags & sel_mask) {
X	subj->flags &= ~sel_mask;
X	selected_subj_cnt--;
X    }
X    subj->flags &= ~(SF_VISIT | SF_WASSELECTED);
X    if (sel_rereading)
X	subj->flags |= SF_DEL;
X    else
X	subj->flags &= ~SF_DEL;
X}
X
X/* Deselect this article's thread.
X*/
Xvoid
Xdeselect_arts_thread(ap)
Xregister ARTICLE *ap;
X{
X    if (ap->subj && ap->subj->thread)
X	deselect_thread(ap->subj->thread);
X    else
X	deselect_arts_subject(ap);
X}
X
X/* Deselect all the articles in a thread.
X*/
Xvoid
Xdeselect_thread(thread)
Xregister ARTICLE *thread;
X{
X    register SUBJECT *sp;
X
X    sp = thread->subj;
X    do {
X	deselect_subject(sp);
X	sp = sp->thread_link;
X    } while (sp != thread->subj);
X}
X
X/* Deselect everything.
X*/
Xvoid
Xdeselect_all()
X{
X    register SUBJECT *sp;
X
X    for (sp = first_subject; sp; sp = sp->next)
X	deselect_subject(sp);
X    selected_count = selected_subj_cnt = 0;
X    sel_page_sp = 0;
X    sel_page_app = 0;
X    sel_last_ap = 0;
X    sel_last_sp = 0;
X    selected_only = FALSE;
X}
X
X/* Kill all unread articles attached to this article's subject.
X*/
Xvoid
Xkill_arts_subject(ap, auto_flags)
Xregister ARTICLE *ap;
Xint auto_flags;
X{
X    if (ap->subj && ap->subj->articles)
X	kill_subject(ap->subj, auto_flags);
X    else {
X	set_read(ap);
X	ap->autofl |= AUTO_KILLALL;
X    }
X}
X
X/* Kill all unread articles attached to the given subject.
X*/
Xvoid
Xkill_subject(subj, auto_flags)
XSUBJECT *subj;
Xint auto_flags;
X{
X    register ARTICLE *ap;
X    register int killmask = ((auto_flags&KF_ALL)? AF_READ:(AF_READ|sel_mask));
X
X    if (auto_flags & KF_KILLFILE) {
X	localkf_changes = 2;
X	auto_flags = AUTO_KILLALL;
X    } else
X	auto_flags = 0;
X    for (ap = subj->articles; ap; ap = ap->subj_next) {
X	if (!(ap->flags & killmask))
X	    set_read(ap);
X	ap->autofl |= auto_flags;
X    }
X    subj->flags &= ~(SF_VISIT | SF_WASSELECTED);
X}
X
X/* Kill all unread articles attached to this article's thread.
X*/
Xvoid
Xkill_arts_thread(ap, auto_flags)
Xregister ARTICLE *ap;
Xint auto_flags;
X{
X    if (ap->subj && ap->subj->thread)
X	kill_thread(ap->subj->thread, auto_flags);
X    else
X	kill_arts_subject(ap, auto_flags);
X}
X
X/* Kill all unread articles attached to the given thread.
X*/
Xvoid
Xkill_thread(thread, auto_flags)
Xregister ARTICLE *thread;
Xint auto_flags;
X{
X    register SUBJECT *sp;
X
X    sp = thread->subj;
X    do {
X	kill_subject(sp, auto_flags);
X	sp = sp->thread_link;
X    } while (sp != thread->subj);
X}
X
X/* Kill the subthread attached to this article.
X*/
Xvoid
Xkill_subthread(ap, auto_flags)
Xregister ARTICLE *ap;
Xint auto_flags;
X{
X    register ARTICLE *limit;
X
X    if (!ap)
X	return;
X    for (limit = ap; limit; limit = limit->parent) {
X	if (limit->sibling) {
X	    limit = limit->sibling;
X	    break;
X	}
X    }
X
X    if (auto_flags & KF_KILLFILE) {
X	localkf_changes = 2;
X	auto_flags = AUTO_KILL;
X    } else
X	auto_flags = 0;
X    for (; ap != limit; ap = bump_art(ap)) {
X	if (!(ap->flags & (AF_READ|AF_MISSING)))
X	    set_read(ap);
X	ap->autofl |= auto_flags;
X    }
X}
X
X/* Unkill all the articles attached to the given subject.
X*/
Xvoid
Xunkill_subject(subj)
XSUBJECT *subj;
X{
X    register ARTICLE *ap;
X
X    for (ap = subj->articles; ap; ap = ap->subj_next) {
X	if (sel_rereading) {
X	    if ((ap->flags & (AF_DELSEL|AF_MISSING)) == AF_DELSEL) {
X		if (ap->flags & AF_READ)
X		    toread[ng]++;
X		ap->flags = (ap->flags & ~(AF_DELSEL|AF_READ)) | AF_SEL;
X	    } else
X		ap->flags &= ~(AF_DEL|AF_DELSEL);
X	} else {
X	    if ((ap->flags & (AF_READ|AF_MISSING)) == AF_READ)
X		onemore(ap);
X	    if (selected_only && !(ap->flags & (AF_SEL|AF_READ))) {
X		ap->flags = (ap->flags & ~AF_DEL) | AF_SEL;
X		selected_count++;
X	    }
X	}
X    }
X    if (!sel_rereading && selected_only && !(subj->flags & SF_SEL)) {
X	subj->flags |= SF_SEL | SF_VISIT | SF_WASSELECTED;
X	selected_subj_cnt++;
X    }
X    subj->flags &= ~(SF_DEL|SF_DELSEL);
X}
X
X/* Unkill all the articles attached to the given thread.
X*/
Xvoid
Xunkill_thread(thread)
Xregister ARTICLE *thread;
X{
X    register SUBJECT *sp;
X
X    sp = thread->subj;
X    do {
X	unkill_subject(sp);
X	sp = sp->thread_link;
X    } while (sp != thread->subj);
X}
X
X/* Unkill the subthread attached to this article.
X*/
Xvoid
Xunkill_subthread(ap)
Xregister ARTICLE *ap;
X{
X    register ARTICLE *limit;
X    register SUBJECT *sp;
X
X    if (!ap)
X	return;
X    for (limit = ap; limit; limit = limit->parent) {
X	if (limit->sibling) {
X	    limit = limit->sibling;
X	    break;
X	}
X    }
X
X    sp = ap->subj;
X    for (; ap != limit; ap = bump_art(ap)) {
X	if ((ap->flags & (AF_READ|AF_MISSING)) == AF_READ)
X	    onemore(ap);
X	if (selected_only && !(ap->flags & AF_SEL)) {
X	    ap->flags |= AF_SEL;
X	    selected_count++;
X	}
X    }
X    if (!(sp->flags & sel_mask))
X	selected_subj_cnt++;
X    sp->flags = (sp->flags & ~SF_DEL) | SF_SEL | SF_VISIT;
X    selected_only = (selected_only || selected_count != 0);
X}
X
X/* Clear the auto flags in all unread articles attached to the given subject.
X*/
Xvoid
Xclear_subject(subj)
XSUBJECT *subj;
X{
X    register ARTICLE *ap;
X
X    for (ap = subj->articles; ap; ap = ap->subj_next) {
X	ap->autofl = 0;
X    }
X    localkf_changes = 2;
X}
X
X/* Clear the auto flags in all unread articles attached to the given thread.
X*/
Xvoid
Xclear_thread(thread)
Xregister ARTICLE *thread;
X{
X    register SUBJECT *sp;
X
X    sp = thread->subj;
X    do {
X	clear_subject(sp);
X	sp = sp->thread_link;
X    } while (sp != thread->subj);
X}
X
X/* Clear the auto flags in the subthread attached to this article.
X*/
Xvoid
Xclear_subthread(ap)
Xregister ARTICLE *ap;
X{
X    register ARTICLE *limit;
X
X    if (!ap)
X	return;
X    for (limit = ap; limit; limit = limit->parent) {
X	if (limit->sibling) {
X	    limit = limit->sibling;
X	    break;
X	}
X    }
X
X    for (; ap != limit; ap = bump_art(ap)) {
X	ap->autofl = 0;
X    }
X    localkf_changes = 2;
X}
X
XARTICLE *
Xsubj_art(sp)
XSUBJECT *sp;
X{
X    register ARTICLE *ap = Nullart;
X    int art_mask = (selected_only? AF_SEL : 0);
X    bool TG_save = ThreadedGroup;
X
X    ThreadedGroup = (sel_mode == SM_THREAD);
X    ap = first_art(sp);
X    while (ap && (ap->flags & (art_mask|AF_READ)) != art_mask)
X	ap = next_art(ap);
X    if (!ap) {
X	reread = TRUE;
X	ap = first_art(sp);
X	if (art_mask) {
X	    while (ap && !(ap->flags & AF_SEL))
X		ap = next_art(ap);
X	    if (!ap)
X		ap = first_art(sp);
X	}
X    }
X    ThreadedGroup = TG_save;
X    return ap;
X}
X
X/* Find the next thread (first if art > lastart).  If articles are selected,
X** only choose from threads with selected articles.
X*/
Xvoid
Xvisit_next_thread()
X{
X    register SUBJECT *sp;
X    register ARTICLE *ap = artp;
X
X    sp = (ap? ap->subj : Nullsubj);
X    while ((sp = next_subj(sp, SF_VISIT)) != Nullsubj) {
X	if ((ap = subj_art(sp)) != Nullart) {
X	    art = article_num(ap);
X	    artp = ap;
X	    return;
X	}
X	reread = FALSE;
X    }
X    artp = Nullart;
X    art = lastart+1;
X    forcelast = TRUE;
X}
X
X/* Find previous thread (or last if artp == NULL).  If articles are selected,
X** only choose from threads with selected articles.
X*/
Xvoid
Xvisit_prev_thread()
X{
X    register SUBJECT *sp;
X    register ARTICLE *ap = artp;
X
X    sp = (ap? ap->subj : Nullsubj);
X    while ((sp = prev_subj(sp, SF_VISIT)) != Nullsubj) {
X	if ((ap = subj_art(sp)) != Nullart) {
X	    art = article_num(ap);
X	    artp = ap;
X	    return;
X	}
X	reread = FALSE;
X    }
X    artp = Nullart;
X    art = lastart+1;
X    forcelast = TRUE;
X}
X
X/* Find artp's parent or oldest ancestor.  Returns FALSE if no such
X** article.  Sets art and artp otherwise.
X*/
Xbool
Xfind_parent(keep_going)
Xbool_int keep_going;
X{
X    register ARTICLE *ap = artp;
X
X    if (!ap->parent)
X	return FALSE;
X
X    do {
X	ap = ap->parent;
X    } while (keep_going && ap->parent);
X
X    if (((artp = ap)->flags & AF_TMPMEM) == AF_TMPMEM)
X	art = 0;
X    else
X	art = article_num(ap);
X    return TRUE;
X}
X
X/* Find artp's first child or youngest decendent.  Returns FALSE if no
X** such article.  Sets art and artp otherwise.
X*/
Xbool
Xfind_leaf(keep_going)
Xbool_int keep_going;
X{
X    register ARTICLE *ap = artp;
X
X    if (!ap->child1)
X	return FALSE;
X
X    do {
X	ap = ap->child1;
X    } while (keep_going && ap->child1);
X
X    if (((artp = ap)->flags & AF_TMPMEM) == AF_TMPMEM)
X	art = 0;
X    else
X	art = article_num(ap);
X    return TRUE;
X}
X
Xstatic ARTICLE *first_sib(), *last_sib();
X
X/* Find the next "sibling" of artp, including cousins that are the
X** same distance down the thread as we are.  Returns FALSE if no such
X** article.  Sets art and artp otherwise.
X*/
Xbool
Xfind_next_sib()
X{
X    ARTICLE *ta, *tb;
X    int ascent;
X
X    ascent = 0;
X    ta = artp;
X    for (;;) {
X	while (ta->sibling) {
X	    ta = ta->sibling;
X	    if (tb = first_sib(ta, ascent)) {
X		if (((artp = tb)->flags & AF_TMPMEM) == AF_TMPMEM)
X		    art = 0;
X		else
X		    art = article_num(tb);
X		return TRUE;
X	    }
X	}
X	if (!(ta = ta->parent))
X	    break;
X	ascent++;
X    }
X    return FALSE;
X}
X
X/* A recursive routine to find the first node at the proper depth.  This
X** article is at depth 0.
X*/
Xstatic ARTICLE *
Xfirst_sib(ta, depth)
XARTICLE *ta;
Xint depth;
X{
X    ARTICLE *tb;
X
X    if (!depth)
X	return ta;
X
X    for (;;) {
X	if (ta->child1 && (tb = first_sib(ta->child1, depth-1)))
X	    return tb;
X
X	if (!ta->sibling)
X	    return Nullart;
X
X	ta = ta->sibling;
X    }
X}
X
X/* Find the previous "sibling" of artp, including cousins that are
X** the same distance down the thread as we are.  Returns FALSE if no
X** such article.  Sets art and artp otherwise.
X*/
Xbool
Xfind_prev_sib()
X{
X    ARTICLE *ta, *tb;
X    int ascent;
X
X    ascent = 0;
X    ta = artp;
X    for (;;) {
X	tb = ta;
X	if (ta->parent)
X	    ta = ta->parent->child1;
X	else
X	    ta = ta->subj->thread;
X	if (tb = last_sib(ta, ascent, tb)) {
X	    if (((artp = tb)->flags & AF_TMPMEM) == AF_TMPMEM)
X		art = 0;
X	    else
X		art = article_num(tb);
X	    return TRUE;
X	}
X	if (!(ta = ta->parent))
X	    break;
X	ascent++;
X    }
X    return FALSE;
X}
X
X/* A recursive routine to find the last node at the proper depth.  This
X** article is at depth 0.
X*/
Xstatic ARTICLE *
Xlast_sib(ta, depth, limit)
XARTICLE *ta;
Xint depth;
XARTICLE *limit;
X{
X    ARTICLE *tb, *tc;
X
X    if (ta == limit)
X	return Nullart;
X
X    if (ta->sibling) {
X	tc = ta->sibling;
X	if (tc != limit && (tb = last_sib(tc,depth,limit)))
X	    return tb;
X    }
X    if (!depth)
X	return ta;
X    if (ta->child1)
X	return last_sib(ta->child1, depth-1, limit);
X    return Nullart;
X}
X
X/* Get each subject's article count; count total articles and selected
X** articles (use sel_rereading to determine whether to count read or
X** unread articles); deselect any subjects we find that are empty if
X** CS_UNSELECT or CS_UNSEL_STORE is specified.  If mode is CS_RESELECT
X** is specified, the selections from the last CS_UNSEL_STORE are
X** reselected.
X*/
Xvoid
Xcount_subjects(cmode)
Xint cmode;
X{
X    register int count, sel_count;
X    register ARTICLE *ap;
X    register SUBJECT *sp;
X    int desired_flags = (sel_rereading? AF_READ : 0);
X    time_t subjdate;
X
X    article_count = selected_count = selected_subj_cnt = 0;
X    if (last_cached >= lastart)
X	firstart = lastart+1;
X
X    if (cmode != CS_RETAIN)
X	for (sp = first_subject; sp; sp = sp->next)
X	    sp->flags &= ~SF_VISIT;
X    for (sp = first_subject; sp; sp = sp->next) {
X	subjdate = 0;
X	count = sel_count = 0;
X	for (ap = sp->articles; ap; ap = ap->subj_next) {
X	    if ((ap->flags & (AF_MISSING|AF_READ)) == desired_flags) {
X		count++;
X		if (ap->flags & sel_mask)
X		    sel_count++;
X		if (!subjdate)
X		    subjdate = ap->date;
X		if (article_num(ap) < firstart)
X		    firstart = article_num(ap);
X	    }
X	}
X	if (cmode == CS_UNSEL_STORE) {
X	    if (sp->flags & SF_SEL)
X		sp->flags |= SF_OLDSEL;
X	    else
X		sp->flags &= ~SF_OLDSEL;
X	} else if (cmode == CS_RESELECT) {
X	    if (sp->flags & SF_OLDSEL)
X		sp->flags |= SF_SEL;
X	    else
X		sp->flags &= ~SF_SEL;
X	}
X	sp->misc = count;
X	if (subjdate)
X	    sp->date = subjdate;
X	else if (!sp->date && sp->articles)
X	    sp->date = sp->articles->date;
X	article_count += count;
X	if (sel_count) {
X	    sp->flags = (sp->flags & ~(SF_SEL|SF_DEL)) | sel_mask;
X	    selected_count += sel_count;
X	    selected_subj_cnt++;
X	} else if (cmode >= CS_UNSELECT)
X	    sp->flags &= ~sel_mask;
X	else if (sp->flags & sel_mask) {
X	    sp->flags &= ~SF_DEL;
X	    selected_subj_cnt++;
X	}
X	if (count && (!selected_only || (sp->flags & sel_mask))) {
X	    sp->flags |= SF_VISIT;
X	}
X    }
X    if (cmode != CS_RETAIN && !article_count && !selected_only) {
X	for (sp = first_subject; sp; sp = sp->next)
X	    sp->flags |= SF_VISIT;
X    }
X}
X
Xint
Xsubjorder_subject(spp1, spp2)
Xregister SUBJECT **spp1;
Xregister SUBJECT **spp2;
X{
X    return strcasecmp((*spp1)->str+4, (*spp2)->str+4) * sel_direction;
X}
X
Xint
Xsubjorder_date(spp1, spp2)
Xregister SUBJECT **spp1;
Xregister SUBJECT **spp2;
X{
X    return (int)((*spp1)->date - (*spp2)->date) * sel_direction;
X}
X
Xint
Xsubjorder_count(spp1, spp2)
Xregister SUBJECT **spp1;
Xregister SUBJECT **spp2;
X{
X    int eq;
X    if ((eq = (int)((*spp1)->misc - (*spp2)->misc)) != 0)
X	return eq * sel_direction;
X    return (int)((*spp1)->date - (*spp2)->date);
X}
X
Xint
Xthreadorder_subject(spp1, spp2)
XSUBJECT **spp1;
XSUBJECT **spp2;
X{
X    register ARTICLE *t1 = (*spp1)->thread;
X    register ARTICLE *t2 = (*spp2)->thread;
X    if (t1 != t2 && t1 && t2)
X	return strcasecmp(t1->subj->str+4, t2->subj->str+4) * sel_direction;
X    return (int)((*spp1)->date - (*spp2)->date);
X}
X
Xint
Xthreadorder_date(spp1, spp2)
XSUBJECT **spp1;
XSUBJECT **spp2;
X{
X    register ARTICLE *t1 = (*spp1)->thread;
X    register ARTICLE *t2 = (*spp2)->thread;
X    if (t1 != t2 && t1 && t2) {
X	register SUBJECT *sp1, *sp2;
X	int eq;
X	if (!(sp1 = t1->subj)->misc)
X	    for (sp1=sp1->thread_link; sp1 != t1->subj; sp1=sp1->thread_link)
X		if (sp1->misc)
X		    break;
X	if (!(sp2 = t2->subj)->misc)
X	    for (sp2=sp2->thread_link; sp2 != t2->subj; sp2=sp2->thread_link)
X		if (sp2->misc)
X		    break;
X	if (!(eq = (int)(sp1->date - sp2->date)))
X	    return strcasecmp(sp1->str+4, sp2->str+4);
X	return eq * sel_direction;
X    }
X    return (int)((*spp1)->date - (*spp2)->date);
X}
X
Xint
Xthreadorder_count(spp1, spp2)
XSUBJECT **spp1;
XSUBJECT **spp2;
X{
X    register int size1 = (*spp1)->misc;
X    register int size2 = (*spp2)->misc;
X    if ((*spp1)->thread != (*spp2)->thread) {
X	register SUBJECT *sp;
X	for (sp = (*spp1)->thread_link; sp != *spp1; sp = sp->thread_link)
X	    size1 += sp->misc;
X	for (sp = (*spp2)->thread_link; sp != *spp2; sp = sp->thread_link)
X	    size2 += sp->misc;
X    }
X    if (size1 != size2)
X	return (size1 - size2) * sel_direction;
X    return threadorder_date(spp1, spp2);
X}
X
X/* Sort the subjects according to the chosen order.
X*/
Xvoid
Xsort_subjects()
X{
X    register SUBJECT *sp;
X    register int i;
X    SUBJECT **lp, **subj_list;
X    int (*sort_procedure)();
X
X    /* If we don't have at least two subjects, we're done! */
X    if (!first_subject || !first_subject->next)
X	return;
X
X    switch (sel_sort) {
X    case SS_DATE:
X    default:
X	sort_procedure = (sel_mode == SM_THREAD?
X			  threadorder_date : subjorder_date);
X	break;
X    case SS_SUBJECT:
X	sort_procedure = (sel_mode == SM_THREAD?
X			  threadorder_subject : subjorder_subject);
X	break;
X    case SS_COUNT:
X	sort_procedure = (sel_mode == SM_THREAD?
X			  threadorder_count : subjorder_count);
X	break;
X    }
X
X    subj_list = (SUBJECT**)safemalloc(subject_count * sizeof (SUBJECT*));
X    for (lp = subj_list, sp = first_subject; sp; sp = sp->next)
X	*lp++ = sp;
X    assert(lp - subj_list == subject_count);
X
X    qsort(subj_list, subject_count, sizeof (SUBJECT*), sort_procedure);
X
X    first_subject = sp = subj_list[0];
X    sp->prev = Nullsubj;
X    for (i = subject_count, lp = subj_list; --i; lp++) {
X	lp[0]->next = lp[1];
X	lp[1]->prev = lp[0];
X	if (sel_mode == SM_THREAD) {
X	    if (lp[0]->thread && lp[0]->thread == lp[1]->thread)
X		lp[0]->thread_link = lp[1];
X	    else {
X		lp[0]->thread_link = sp;
X		sp = lp[1];
X	    }
X	}
X    }
X    last_subject = lp[0];
X    last_subject->next = Nullsubj;
X    if (sel_mode == SM_THREAD)
X	last_subject->thread_link = sp;
X    free((char*)subj_list);
X}
X
Xint
Xartorder_date(art1, art2)
Xregister ARTICLE **art1;
Xregister ARTICLE **art2;
X{
X    return (int)((*art1)->date - (*art2)->date) * sel_direction;
X}
X
Xint
Xartorder_subject(art1, art2)
Xregister ARTICLE **art1;
Xregister ARTICLE **art2;
X{
X    if ((*art1)->subj == (*art2)->subj)
X	return (int)((*art1)->date - (*art2)->date);
X    return strcasecmp((*art1)->subj->str + 4, (*art2)->subj->str + 4)
X	* sel_direction;
X}
X
Xint
Xartorder_author(art1, art2)
Xregister ARTICLE **art1;
Xregister ARTICLE **art2;
X{
X    int eq;
X    if ((eq = strcasecmp((*art1)->from, (*art2)->from)) != 0)
X	return eq * sel_direction;
X    return (int)((*art1)->date - (*art2)->date);
X}
X
Xint
Xartorder_number(art1, art2)
Xregister ARTICLE **art1;
Xregister ARTICLE **art2;
X{
X    return (int)(article_num(*art1) - article_num(*art2)) * sel_direction;
X}
X
Xint
Xartorder_groups(art1, art2)
Xregister ARTICLE **art1;
Xregister ARTICLE **art2;
X{
X    if ((*art1)->subj == (*art2)->subj)
X	return (int)((*art1)->date - (*art2)->date);
X    return (int)((*art1)->subj->date - (*art2)->subj->date) * sel_direction;
X}
X
X/* Sort the articles according to the chosen order.
X*/
Xvoid
Xsort_articles()
X{
X    int (*sort_procedure)();
X
X    build_artptrs();
X
X    /* If we don't have at least two articles, we're done! */
X    if (artptr_list_size < 2)
X	return;
X
X    switch (sel_sort) {
X    case SS_DATE:
X    default:
X	sort_procedure = artorder_date;
X	break;
X    case SS_SUBJECT:
X	sort_procedure = artorder_subject;
X	break;
X    case SS_AUTHOR:
X	sort_procedure = artorder_author;
X	break;
X    case SS_NUMBER:
X	sort_procedure = artorder_number;
X	break;
X    case SS_GROUPS:
X	sort_procedure = artorder_groups;
X	break;
X    }
X    sel_page_app = 0;
X    qsort(artptr_list, artptr_list_size, sizeof (ARTICLE*), sort_procedure);
X}
X
Xstatic void
Xbuild_artptrs()
X{
X    ARTICLE **app, *ap;
X    ART_NUM count = article_count;
X    int desired_flags = (sel_rereading? AF_READ : 0);
X
X    if (!artptr_list || artptr_list_size != count) {
X	artptr_list = (ARTICLE**)saferealloc((char*)artptr_list,
X		(MEM_SIZE)count * sizeof (ARTICLE*));
X	artptr_list_size = count;
X    }
X    for (app = artptr_list, ap = article_list; count; ap++) {
X	if ((ap->flags & (AF_MISSING|AF_READ)) == desired_flags) {
X	    *app++ = ap;
X	    count--;
X	}
X    }
X}
SHAR_EOF
  echo 'File trn-3.6/rthread.c is complete' &&
  $shar_touch -am 1110023094 'trn-3.6/rthread.c' &&
  chmod 0644 'trn-3.6/rthread.c' ||
  echo 'restore of trn-3.6/rthread.c failed'
  shar_count="`wc -c < 'trn-3.6/rthread.c'`"
  test 33742 -eq "$shar_count" ||
    echo "trn-3.6/rthread.c: original size 33742, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= trn-3.6/rthread.h ==============
if test -f 'trn-3.6/rthread.h' && test X"$1" != X"-c"; then
  echo 'x - skipping trn-3.6/rthread.h (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting trn-3.6/rthread.h (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'trn-3.6/rthread.h' &&
X/* $Id: rthread.h,v 3.0 1992/12/14 00:14:15 davison Trn $
X*/
X/* The authors make no claims as to the fitness or correctness of this software
X * for any use whatsoever, and it is provided as is. Any use of this software
X * is at the user's own risk. 
X */
X
XEXT ART_NUM article_count INIT(0);
XEXT int subject_count INIT(0);
XEXT bool output_chase_phrase;
XEXT char *references;
XEXT bool ov_opened INIT(FALSE);
X
Xvoid thread_init _((void));
Xvoid thread_open _((void));
Xvoid thread_grow _((void));
Xvoid thread_close _((void));
X
Xvoid top_article _((void));
XARTICLE *first_art _((SUBJECT*));
XARTICLE *last_art _((SUBJECT*));
XARTICLE *bump_art _((ARTICLE*));
XARTICLE *next_art _((ARTICLE*));
XARTICLE *prev_art _((ARTICLE*));
Xvoid inc_art _((bool_int,bool_int));
Xvoid dec_art _((bool_int,bool_int));
Xbool next_art_with_subj _((void));
Xbool prev_art_with_subj _((void));
XSUBJECT *next_subj _((SUBJECT*,int));
XSUBJECT *prev_subj _((SUBJECT*,int));
X
Xvoid select_article _((ARTICLE*,int));
Xvoid select_arts_subject _((ARTICLE*,int));
Xvoid select_subject _((SUBJECT*,int));
Xvoid select_arts_thread _((ARTICLE*,int));
Xvoid select_thread _((ARTICLE*,int));
Xvoid select_subthread _((ARTICLE*,int));
Xvoid deselect_article _((ARTICLE*));
Xvoid deselect_arts_subject _((ARTICLE*));
Xvoid deselect_subject _((SUBJECT*));
Xvoid deselect_arts_thread _((ARTICLE*));
Xvoid deselect_thread _((ARTICLE*));
Xvoid deselect_all _((void));
Xvoid kill_arts_subject _((ARTICLE*,int));
Xvoid kill_subject _((SUBJECT*,int));
Xvoid kill_arts_thread _((ARTICLE*,int));
Xvoid kill_thread _((ARTICLE*,int));
Xvoid kill_subthread _((ARTICLE*,int));
Xvoid unkill_subject _((SUBJECT*));
Xvoid unkill_thread _((ARTICLE*));
Xvoid unkill_subthread _((ARTICLE*));
Xvoid clear_subject _((SUBJECT*));
Xvoid clear_thread _((ARTICLE*));
Xvoid clear_subthread _((ARTICLE*));
X
X#define KF_UNSELECTED	0	/* leave selected articles, no KILL file */
X#define KF_ALL		0x0001	/* Affect both selected and unselected */
X#define KF_KILLFILE	0x0002	/* Save the command to the KILL file */
X
XARTICLE *subj_art _((SUBJECT*));
Xvoid visit_next_thread _((void));
Xvoid visit_prev_thread _((void));
X
Xbool find_parent _((bool_int));
Xbool find_leaf _((bool_int));
Xbool find_prev_sib _((void));
Xbool find_next_sib _((void));
X
Xvoid sort_subjects _((void));
Xvoid count_subjects _((int));
X#define CS_RETAIN      0
X#define CS_NORM        1
X#define CS_RESELECT    2
X#define CS_UNSELECT    3
X#define CS_UNSEL_STORE 4
X
Xint subjorder_date _((SUBJECT**, SUBJECT**));
Xint subjorder_str _((SUBJECT**, SUBJECT**));
Xint threadorder_date _((SUBJECT**, SUBJECT**));
Xint threadorder_str _((SUBJECT**, SUBJECT**));
X
Xvoid sort_articles _((void));
X
Xint artorder_date _((ARTICLE**, ARTICLE**));
Xint artorder_str _((ARTICLE**, ARTICLE**));
X
Xtime_t parsedate _((char*));
X
X/* Stuff local to rthread.c. */
X
X#ifdef DOINIT
X
Xstatic void build_artptrs _((void));
X
X#endif
SHAR_EOF
  $shar_touch -am 0429181194 'trn-3.6/rthread.h' &&
  chmod 0644 'trn-3.6/rthread.h' ||
  echo 'restore of trn-3.6/rthread.h failed'
  shar_count="`wc -c < 'trn-3.6/rthread.h'`"
  test 2849 -eq "$shar_count" ||
    echo "trn-3.6/rthread.h: original size 2849, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= trn-3.6/search.c ==============
if test -f 'trn-3.6/search.c' && test X"$1" != X"-c"; then
  echo 'x - skipping trn-3.6/search.c (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting trn-3.6/search.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'trn-3.6/search.c' &&
X/* $Id: search.c,v 3.0 1992/02/01 03:09:32 davison Trn $
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)
X	return Nullch;
X    if (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 + 4 - compex->expbuf >= compex->eblen)
X	    ep = grow_eb(compex, ep, alt);
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	    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			ep = grow_eb(compex, ep, alt); /* reserve bitmap */
X
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) != ']' && *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
Xchar *
Xgrow_eb(compex, epp, alt)
Xregister COMPEX *compex;
Xchar *epp;
Xchar **alt;
X{
X    register char *oldbuf = compex->expbuf;
X    register char **altlist = compex->alternatives;
X
X    compex->eblen += 80;
X    compex->expbuf = saferealloc(compex->expbuf, (MEM_SIZE)compex->eblen + 4);
X    if (compex->expbuf != oldbuf) {	/* realloc can change expbuf! */
X	epp += compex->expbuf - oldbuf;
X	while (altlist != alt)
X	    *altlist++ += compex->expbuf - oldbuf; 
X    }
X    return epp;
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	if (err) err = 0;
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	if (err) err = 0;
X	return Nullch;
X    }
X   /*NOTREACHED*/
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 || *ep == WBOUND) {
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;
Xint af;
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
  $shar_touch -am 0725103093 'trn-3.6/search.c' &&
  chmod 0644 'trn-3.6/search.c' ||
  echo 'restore of trn-3.6/search.c failed'
  shar_count="`wc -c < 'trn-3.6/search.c'`"
  test 13435 -eq "$shar_count" ||
    echo "trn-3.6/search.c: original size 13435, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= trn-3.6/search.h ==============
if test -f 'trn-3.6/search.h' && test X"$1" != X"-c"; then
  echo 'x - skipping trn-3.6/search.h (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting trn-3.6/search.h (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'trn-3.6/search.h' &&
X/* $Id: search.h,v 3.0 1991/09/09 20:27:37 davison Trn $
X */
X/* This software is Copyright 1991 by Stan Barber. 
X *
X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
X * use this software as long as: there is no monetary profit gained
X * specifically from the use or reproduction of this software, it is not
X * sold, rented, traded or otherwise marketed, and this copyright notice is
X * included prominently in any copy made. 
X *
X * The authors make no claims as to the fitness or correctness of this software
X * for any use whatsoever, and it is provided as is. Any use of this software
X * is at the user's own risk. 
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 _((void));
Xvoid	init_compex _((COMPEX*));
Xvoid	free_compex _((COMPEX*));
Xchar	*getbracket _((COMPEX*,int));
Xvoid	case_fold _((int));
Xchar	*compile _((COMPEX*,char*,int,int)); 
Xchar	*grow_eb _((COMPEX*,char*,char**));
Xchar	*execute _((COMPEX*,char*)); 
Xbool	advance _((COMPEX*,char*,char*));
Xbool	backref _((COMPEX*,int,char*)); 
Xbool	cclass _((char*,int,int));
X#endif
SHAR_EOF
  $shar_touch -am 0711223693 'trn-3.6/search.h' &&
  chmod 0644 'trn-3.6/search.h' ||
  echo 'restore of trn-3.6/search.h failed'
  shar_count="`wc -c < 'trn-3.6/search.h'`"
  test 1711 -eq "$shar_count" ||
    echo "trn-3.6/search.h: original size 1711, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= trn-3.6/Pnews.SH ==============
if test -f 'trn-3.6/Pnews.SH' && test X"$1" != X"-c"; then
  echo 'x - skipping trn-3.6/Pnews.SH (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting trn-3.6/Pnews.SH (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'trn-3.6/Pnews.SH' &&
Xcase $CONFIG in
X    '') . ./config.sh ;;
Xesac
Xecho "Extracting Pnews (with variable substitutions)"
X$spitshell >Pnews <<!GROK!THIS!
X$startsh
X# $Id: Pnews.SH,v 3.0 1992/02/23 21:25:39 davison Trn $
X# 
X# This software is Copyright 1991 by Stan Barber. 
X#
X# Permission is hereby granted to copy, reproduce, redistribute or otherwise
X# use this software as long as: there is no monetary profit gained
X# specifically from the use or reproduction of this software, it is not
X# sold, rented, traded or otherwise marketed, and this copyright notice is
X# included prominently in any copy made. 
X#
X# The author make no claims as to the fitness or correctness of this software
X# for any use whatsoever, and it is provided as is. Any use of this software
X# is at the user's own risk. 
X#
X# syntax: Pnews -h headerfile			or
X#	  Pnews -h headerfile oldarticle	or
X#         Pnews newsgroup title			or just
X#         Pnews
X
Xexport PATH || (echo "OOPS, this isn't sh.  Desperation time.  I will feed myself to sh."; sh \$0; kill \$\$)
X
X# System dependencies
X
Xmailer="\${RNMAILER-${mailer-/bin/mail}}"
X# if you change this to something that does signatures, take out signature code
X
Xcase $d_portable in
Xdefine)
X    # where recordings and distributions are kept
X    lib=\`$filexp $newslib\`
X    # where important rn things are kept
X    rnlib=\`$filexp $privlib\`
X    artcheck=trn-artchk
X    nntplist=nntplist
X    ;;
Xundef)
X    # where recordings and distributions are kept
X    lib="$newslib"
X    # where important rn things are kept
X    rnlib="$privlib"
X    artcheck=$bin/trn-artchk
X    nntplist=$bin/nntplist
X    ;;
Xesac
X
X# your organization name
Xorgname="$orgname"
X# what pager you use--if you have kernal paging use cat
Xpager="\${PAGER-$pager}"
X# how you derive full names, bsd, usg, or other
Xnametype="$nametype"
X# default editor
Xdefeditor="$defeditor"
X# how not to echo with newline
Xn="$n"
Xc="$c"
X
X# You should also look at the distribution warnings below marked !DIST!
X# to make sure any distribution regions you are a member of are included.
X# The following are some prototypical distribution groups.  If you do not
X# use them all set the unused ones to a non-null string such as 'none'.
Xloc="$locdist"
Xorg="$orgdist"
Xmultistate="$multistatedist"
Xcity="$citydist"
Xstate="$statedist"
Xcntry="$cntrydist"
Xcont="$contdist"
X
Xactive=${active-$lib/active}
Xtest=${test-test}
Xsed=${sed-sed}
Xecho=${echo-echo}
Xcat=${cat-cat}
Xegrep=${egrep-egrep}
Xgrep=${grep-grep}
Xtr=${tr-tr}
Xinews=${inewsloc-inews}
Xcp=${cp-cp}
Xsleep=${sleep-sleep}
Xrm=${rm-rm}
Xwho=${who-who}
Xmv=${mv-mv}
X
Xnidump=${nidump}
Xypmatch=${ypmatch}
X
X!GROK!THIS!
Xcase "$d_ignoreorg" in
Xdefine) $spitshell >>Pnews <<'!NO!SUBS!'
Xorgname=${NEWSORG-$orgname}
X!NO!SUBS!
X	;;
X*)	$spitshell >>Pnews <<'!NO!SUBS!'
Xorgname=${NEWSORG-${ORGANIZATION-$orgname}}
X!NO!SUBS!
X	;;
Xesac
X$spitshell >>Pnews <<'!NO!SUBS!'
Xhomedir=${HOME-$LOGDIR}
Xdotdir=${DOTDIR-$homedir}
Xtmpart=$dotdir/.article
Xspeller=$rnlib/Speller
X
Xtmp="${TMPDIR-/tmp}"
Xnewsgroups=${NEWSGROUPS-$lib/newsgroups}
Xactive=${NEWSACTIVE-$active}
Xcase "$active" in
Xnone) active="$tmp/Pnact.$$";;
Xesac
Xnews_sig=${NEWSSIGNATURE-$dotdir/.news_sig}
X
Xcase "$NETSPEED" in
Xfast)
X    if $test ! -f "$newsgroups"; then
X	newsgroups="$tmp/Pnng.$$";
X	rmlist="$newsgroups";
X	cmdlist="$nntplist -o $newsgroups newsgroups ;";
X    fi
X    if $test ! -f "$active"; then
X	active="$tmp/Pnact.$$";
X	rmlist="$rmlist $active";
X	cmdlist="$cmdlist $nntplist -o $active active";
X    fi
X    ;;
Xesac
X
Xif $test -f $dotdir/.pnewsexpert; then
X    expertise=expert
Xelse
X    $cat <<'EOM'
XI see you've never used this version of Pnews before.  I will give you extra
Xhelp this first time through, but then you must remember what you learned.
XIf you don't understand any question, type h and a CR (carriage return) for
Xhelp.
X
XIf you've never posted an article to the net before, it is HIGHLY recommended
Xthat you read the netiquette document found in news.announce.newusers so
Xthat you'll know to avoid the commonest blunders.  To do that, interrupt
XPnews, get to the top-level prompt of [t]rn, and use the command
X"g news.announce.newusers" to go to that group.
X
XEOM
X    expertise=beginner
Xfi
X
Xcase $cntry in
X  can) Stpr=Province ; stpr=province ;;
X  *)   Stpr=State ; stpr=state ;;
Xesac
X
Xcase $multistate in
X  pnw) multistpr="Pacific NorthWest" ;;
X  *)   multistpr="Multi-State Area" ;;
Xesac
X
Xheaderfile=""
Xcase $# in
X0) ;;
X*)  case $1 in
X    -h)
X	headerfile="$2"
X	shift
X	shift
X	case $# in
X	0)
X	    oldart=""
X	    ;;
X	*)
X	    oldart="$1"
X	    shift
X	    ;;
X	esac
X	;;
X    esac
X    ;;
Xesac
X
Xcase $headerfile in
X'')
X    . $rnlib/Pnews.header
X    ;;
X*)
X    $cat < $headerfile  > $tmpart
X    ;;
Xesac
X    rescue="$sleep 1; $cat $tmpart >>${HOME-$LOGDIR}/dead.article ; $rm -f $rmlist ; $echo Article appended to ${HOME-$LOGDIR}/dead.article ; exit"
X    if $test -n "$rmlist" ; then
X	trap "$rm -f $rmlist" 0
X    fi
X    trap "trap : 1; $rescue" 1
X    trap "$rescue" 2
X
X$echo ""
X
X# extract the newsgroups list and distribution
Xhdr_newsgroups=`$sed -n -e '/^Newsgroups:/{' -e 's///' -e 's/,/ /g' -e p -e q -e '}' $tmpart`
Xhdr_distribution=`$sed -n -e '/^Distribution:/{' -e 's///' -e p -e q -e '}' $tmpart`
X
X# check for "poster" magic cookie.  Allow erroneous user@site too.
Xflag=0
Xfor ng in $hdr_newsgroups ; do
X    case "$ng" in
X	poster)	flag=1 ;;
X	*@*) flag=1 ;;
X	*)	;;
X    esac
Xdone
Xcase $flag in
X1)
X    $cat <<'EOM'
X
XThe original author has requested that messages be sent back via mail
Xrather than posting to news.  Do you want to jump out of this and
XEOM
X    $echo $n "mail your reply instead? [yn] $c"
X    read ans
X    case $ans in
X	n*) tweak="$tmp/Pntwk.$$"
X	    $sed '1,/^[	 ]*$/{/^Newsgroups:/d;
X		s/^X-ORIGINAL-NEWSGROUPS:/Newsgroups:/;}' $tmpart >$tweak
X	    $cp $tweak $tmpart
X	    $rm -f $tweak
X	    ;;
X	*)  exit ;;
X    esac
X    $echo " "
X    $echo "The Cc: line should have the poster's requested return address."
X    ;;
Xesac
X  
X# play recorded message
Xif $test -s ${lib}/recording ; then
X     for ng in $hdr_newsgroups ; do
X	_rec1=${lib}/`$sed -n "/^$ng/s/^.*	//p" ${lib}/recording`
X	_tmp=`$echo $ng |$sed "s/\..*//"`
X	_rec2=${lib}/`$cat -s ${lib}/recording|$grep ${_tmp}.all|$sed "s/^.*	//"`
X	if $test -f ${_rec1} ; then
X	    $cat -s ${_rec1}
X	fi
X	if $test -f ${_rec2} ; then
X	    $cat -s ${_rec2}
X	fi
X    done
Xfi
X
X# determine the distribution of this message
Xset X $hdr_distribution
Xshift
Xif $test $# -gt 0 ; then
X    dist=$1.whatever
Xelse
X    set X $hdr_newsgroups
X    shift
X    if $test $# -gt 0 ; then
X	dist=$1.whatever
X    else
X	dist=misc.whatever
X    fi
Xfi
Xcase $dist in
X*.*)
X    ;;
X*)
X    dist=$dist.whatever
X    ;;
Xesac
X
Xcase "$FAST_PNEWS" in
Xy*) ;;
X*)
X# tell them what we think they are doing... !DIST!
Xcase $dist in
Xworld.*|comp.*|news.*|sci.*|rec.*|misc.*|soc.*|talk.*|alt.*|'')
X    $cat <<'EOM'
XThis program posts news to thousands of machines throughout the entire
Xcivilized world.  Your message will cost the net hundreds if not thousands of
Xdollars to send everywhere.  Please be sure you know what you are doing.
X
XEOM
X    ;;
Xvmsnet.*)
X    $echo 'This program posts news to many machines.'
X    ;;
Xbit.*)
X    $echo 'This program posts news to many machines on BITNET.'
X    ;;
Xddn.*)
X    $echo 'This program posts news to many machines throughout the internet.'
X    ;;
X$cont.*)
X    $echo 'This program posts news to many machines throughout the continent.'
X    ;;
X$cntry.*)
X    $echo 'This program posts news to many machines throughout the country.'
X    ;;
X$multistate.*)
X    $echo "This program posts news to many machines throughout the ${multistpr}."
X    ;;
X$state.*)
X    $echo "This program posts news to many machines throughout the ${stpr}."
X    ;;
X$city.*)
X    $echo 'This program posts news to many machines throughout the city.'
X    ;;
X$org.*)
X    $echo 'This program posts news to machines throughout the organization.'
X    ;;
X$loc.*)
X    $echo 'This program posts news to machines throughout the local organization.'
X    ;;
X*.*)
X    $echo 'This program may post news to many machines.'
X    ;;
Xto.*)
X    $echo 'This program may post news to a particular machine.'
X    ;;
X*)
X    $echo 'This program posts news to everyone on the machine.'
X    ;;
Xesac
Xans=""
Xwhile $test "X$ans" = X ; do
X    $echo $n "Are you absolutely sure that you want to do this? [ny] $c"
X    read ans
X    case $ans in
X    y*) ;;
X    f*) ;;
X    h*) $cat <<'EOH'
X
XType n or CR to exit, y to post.
X
XEOH
X	ans="" ;;
X    *) exit ;;
X    esac
Xdone
X;;
Xesac
X
X# run nntplist in the background, if necessary
Xif $test -n "$cmdlist"; then
X    ( eval $cmdlist ) >/dev/null 2>&1 &
Xfi
X
Xcase "$FAST_PNEWS" in
Xy*) file=''
X    $echo "" >> $tmpart
X    state=edit
X    ;;
X*)  file=h;;
Xesac
Xwhile $test "X$file" = Xh ; do
X    $echo ""
X    $echo $n "Prepared file to include [none]: $c"
X    read file
X    case $file in
X    h)
X	$cat <<'EOH'
X
XIf you have already produced the body of your article, type the filename
Xfor it here.  If you just want to proceed directly to the editor, type a
XRETURN.  In any event, you will be allowed to edit as many times as you
Xwant before you send off the article.
XEOH
X	;;
X    '')
X	$echo "" >> $tmpart
X	state=edit
X	;;
X    *)
X	$cat $file >>$tmpart
X	state=check
X	;;
X    esac
Xdone
X
X$echo ""
X
Xif $test -r $news_sig; then
X    $echo "-- " >> $tmpart
X    $sed 4q $news_sig >> $tmpart
Xfi
X
Xwhile : ; do
X    case $state in
X    edit)
X	case $expertise in
X	beginner)
X	    $cat </dev/null >$dotdir/.pnewsexpert
X	    $cat <<'EOMessage'
XA temporary file has been created for you to edit.  Be sure to leave at
Xleast one blank line between the header and the body of your message.
X(And until a certain bug is fixed all over the net, don't start the body of
Xyour message with any indentation, or it may get eaten.)
X
XWithin the header may be fields that you don't understand.  If you don't
Xunderstand a field (or even if you do), you can simply leave it blank, and
Xit will go away when the article is posted.
X
XType return to get the default editor, or type the name of your favorite
Xeditor.
X
XEOMessage
X	    ;;
X	esac
X	case "${VISUAL-${EDITOR-}}" in
X	'')
X	    tmp=h
X	    ;;
X	*)
X	    tmp=''
X	    ;;
X	esac
X	while $test "X$tmp" = Xh ; do
X	    $echo $n "Editor [${VISUAL-${EDITOR-$defeditor}}]: $c"
X	    read tmp
X	    case $tmp in
X	    h)
X		$cat <<'EOH'
X
XType a return to get the default editor, or type the name of the editor you
Xprefer.  The default editor depends on the VISUAL and EDITOR environment
Xvariables.
X
XEOH
X		;;
X	    '')
X		;;
X	    *)
X		VISUAL=$tmp
X		export VISUAL
X		;;
X	    esac
X	done
X	trap : 2
X	${VISUAL-${EDITOR-$defeditor}} $tmpart $oldart
X	trap "$rescue" 2
X	state=check
X	;;
X	
X    check)
X	# wait for possible background nntplist
X	$test -n "$cmdlist" && wait
X
X	# warn about long lines, malformed headers, misspelled newsgroups
X	($artcheck $tmpart 79 $newsgroups $active) 2>/dev/null
X	state=ask
X	;;
X
X    ask)
X	$echo ""
X	$echo $n "Check spelling, Send, Abort, Edit, or List? $c"
X	read ans
X
X	case "$ans" in
X	[aA]*)
X	    state=rescue
X	    ;;
X	[eE]*)
X	    set $ans
X	    case $# in
X	    2)  VISUAL="$2" ;;
X	    esac
X	    state=edit
X	    ;;
X	[lL]*)
X	    $pager $tmpart
X	    state=ask
X	    ;;
X	[cC]*|[sS][pP]*)
X	    $speller $tmpart
X	    state=ask
X	    ;;
X	[sS]*)
X	    state=send
X	    ;;
X	[hH]*)
X	    $cat <<'EOH'
X
XType c to check the article's spelling, s to send the article, a to abort
Xand append the article to dead.article, e to edit the article again, or l
Xto list the article with your pager.
X
XTo invoke an alternate editor, type 'e editor'.
XEOH
X	esac
X	;;
X    
X    send)
X	set X `$sed < $tmpart -n -e '/^Newsgroups: /{' -e p -e q -e '}'`
X	shift
X	case $# in
X	2)
X	    state=cleanup
X	    #posted_to="$2"
X		headerstrip='1,/^[	 ]*$/{/^[A-Z][-A-Za-z0-9]*:[	 ]*$/d;
X			/^X-ORIGINAL-NEWSGROUPS:/d;
X			/^[Cc][Cc]:/d;
X			/^Distribution: world/d;}'
X		if $sed "$headerstrip" $tmpart | $inews -h ; then
X		    : null
X		else
X		    state=ask
X		fi
X		cc=`$sed -n '1,/^[	 ]*$/{/^[Cc][Cc]:[	 ][^	 ]/p;}' $tmpart|
X		 $sed 's/^[Cc][Cc]:[	 ][	 ]*//'`
X		if $test "X$cc" != X ; then
X		    case "$mailer" in
X		    *recmail)	set X ;;
X		    *sendmail)	set X -t ;;
X		    *)		set X `echo $cc | $sed 's/,/ /g'` ;;
X		    esac
X		    shift
X		    (#$echo "X-Also-Posted-To: $posted_to"
X		     case "$mailer" in
X		     *recmail|*sendmail) $echo To: $cc ;;
X		     esac
X		     $sed "$headerstrip" $tmpart
X		     if $test -f $homedir/.signature; then
X			$echo "-- "
X			$cat $homedir/.signature
X		     fi
X		    ) | $mailer $@
X		fi
X	    ;;
X	*)
X	    $echo ""
X	    $echo "Malformed Newsgroups line."
X	    $echo ""
X	    $sleep 1
X	    state=edit
X	    ;;
X	esac
X	;;
X    rescue)
X	if $test -s $tmpart; then
X		$cat $tmpart >> ${HOME-$LOGDIR}/dead.article
X		$echo "Article appended to ${HOME-$LOGDIR}/dead.article"
X		$echo "A copy may be temporarily found in $tmpart"
X	else
X		$echo "Null article discarded."
X	fi
X	exit
X	;;
X    cleanup)
X	case "${AUTHORCOPY-none}" in
X	none)
X	    ;;
X	*)
X	    set X ${USER-${LOGNAME-`$who am i`}} unknown
X	    shift
X	    $rnlib/mbox.saver $tmpart "." "." 0 0 Pnews $AUTHORCOPY "From $1 `LANG= date`"
X	    if $test $? -eq 0 ; then
X		$echo "Article appended to $AUTHORCOPY"
X	    else
X		$echo "Cannot append to $AUTHORCOPY"
X	    fi
X	    ;;
X	esac
X	exit
X	;;
X    esac
Xdone
X!NO!SUBS!
X$eunicefix Pnews
Xchmod 755 Pnews
X$spitshell >Pnews.header <<'!NO!SUBS!'
Xcase $# in
X0)
X    ng=h
X    while $test "X$ng" = Xh ; do
X	$echo ""
X	$echo $n "Newsgroup(s): $c"
X	read ng
X	case $ng in
X	h)
X	    $cat <<'EOH'
X
XType the name of one or more newsgroups to which you wish to post an article.
XIf you want to post to multiple newsgroups, it is better to do them all at
Xonce than to post to each newsgroup individually, which defeats the news
Xreading programs' strategies of eliminating duplicates.
X
XSeparate multiple newsgroup names with commas.
XEOH
X	    ;;
X	esac
X    done
X    ;;
X*)
X    ng=$1
X    shift
X    ;;
Xesac
Xcase $ng in
X*\ *)
X    ng=`$echo "$ng" | $sed 's/[, ] */,/g'`
X    ;;
Xesac
Xcase $ng in
Xddn.*)
X    defdist=inet
X    dist=h
X    ;;
X*.*)
X    defdist=''
X    dist=h
X    ;;
X*)
X    defdist=''
X    dist=''
X    ;;
Xesac
X
Xwhile $test "X$dist" = Xh ; do
X    if $test -f $lib/distributions; then
X	$echo " "
X	$echo "Your local distribution prefixes are:"
X	$cat $lib/distributions
X	$echo " "
X    else
X	$egrep -v '[	 ]none$' <<EOM
X
XYour local distribution prefixes are:
X    Local organization:	$loc
X    Organization:	$org
X    City:		$city
X    $Stpr:  		$state
X    $multistpr:	$multistate
X    Country:		$cntry
X    Continent:		$cont
X    Everywhere:		<null> (not "world")
X
XEOM
X    fi
X    $echo $n "Distribution ($defdist): $c"
X    read dist
X    case $dist in
X    '') dist="$defdist" ;;
X    esac
X    case "$dist" in
X    h)
X	$cat <<'EOH'
X
XThe Distribution line may be used to limit the distribution of an article
Xto some subset of the systems that would receive the article based only on
Xthe Newsgroups line.  For example, if you want to sell your car in talk.auto,
Xand you live in New Jersey, you might want to put "nj" on the Distribution
Xline to avoid advertising in California, which has enough problems of its own.
XThe actual area designators to use depend on where you are, of course.
XEOH
X	;;
X    world*|comp*|news*|sci*|rec*|misc*|soc*|talk*|alt*)
X	dist=''
X	;;
X    ''|$loc|$org|$city|$state|$multistate|$cntry|$cont|$defdist)
X	;;
X    *)  
X	if $test -f $lib/distributions && \
X	  $egrep "^$dist[ 	]" $lib/distributions >$tmpart && \
X	  $test -s $tmpart; then
X	    : null
X	else
X	    $echo "Unrecognized distribution prefix--type h for help, CR to use anyway."
X	    defdist=$dist
X	    dist=h
X	fi
X	;;
X    esac
Xdone
X
Xfollow=""
X
X# LCP 16-Oct-91 Subject line is required.  Make it a little more
X# difficult to omit.  Added "while : ; do", ... "done", and "if"
X# at end of while loop.
Xwhile : ; do
X  case $# in
X  0)
X    title=h
X    while $test "X$title" = Xh ; do
X	$echo ""
X	$echo $n "Title/Subject: $c"
X	read title
X	case $title in
X	h)
X	    $cat <<'EOH'
X
XType the title for your article.  Please make it as informative as possible
X(within reason) so that people who aren't interested won't have to read the
Xarticle to find out they aren't interested.  This includes marking movie
Xspoilers as (spoiler), and rotated jokes as (rot 13).
XEOH
X	;;
X	esac
X    done
X    ;;
X  *)
X    title="$*"
X    # LCP 16-Oct-91 Added "set" and "shift".  Must insure $# is 0
X    # in case the title is all white space and we make another
X    # pass thru this loop.
X    set X
X    shift
X    ;;
X  esac
X  if expr "X$title" : "^X[    ]*$" > /dev/null 2>&1
X  then
X    $cat <<'EOH'
X
XArticles without a "Subject:" line will not be accepted by the News
Xsystem.  Please give a Title/Subject line for your article.
XEOH
X  else
X     break
X  fi
Xdone
X
X
X# now build a file with a header for them to edit
X
Xset X ${USER-${LOGNAME-`$who am i`}}
Xshift
Xlogname=$1
Xcase $logname in
X*!*) logname=`expr "$logname" : '!\(.*\)$'` ;;
Xesac
Xcase ${NAME-$nametype} in
Xbsd)
X	if $test "X$ypmatch" != X; then
X		fullname=`$ypmatch $logname passwd 2>/dev/null | $sed -e "s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^,:;]*\).*"'$'"/\1/"`
X	elif $test "X$nidump" != X; then
X		fullname=`$nidump passwd / | $sed -e "/^$logname:/{s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^,:;]*\).*"'$'"/\1/" -e "q" -e "}" -e "d"`
X	fi
X	if $test "X$fullname" = X; then
X		fullname=`$sed </etc/passwd -e "/^$logname:/{s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^,:;]*\).*"'$'"/\1/" -e "q" -e "}" -e "d"`
X	fi
X    case $fullname in
X    *'&'*) : GACK
X	lname=`$echo $logname | $tr 'a-z' 'A-Z'`
X	lname=`$echo $lname $logname | $sed 's/^\(.\)[^ ]* ./\1/'`
X	fullname=`$echo "$fullname" | $sed "s/&/${lname}/"`
X	;;
X    esac
X    ;;
Xusg)
X    if $test "X$ypmatch" != X; then
X	fullname=`$ypmatch $logname passwd 2>/dev/null | $sed -e "s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^(:]*\).*"'$'"/\1/" -e "s/^.*-//" -e "q"`
X    fi
X    if $test "X$fullname" = X; then
X	fullname=`$sed </etc/passwd -e "/^$logname:/{s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^(:]*\).*"'$'"/\1/" -e "s/^.*-//" -e "q" -e "}" -e "d"`
X    fi
X    ;;
X*)
X    fullname=${NAME-`$cat $dotdir/.fullname`}
X    ;;
Xesac
X
Xcase $orgname in
X/*) orgname=`$cat $orgname` ;;
Xesac
X
X$sed -e '/^Reply-To: $/d' > $tmpart <<EOHeader
XNewsgroups: $ng
XSubject: $title
XSummary: 
XReply-To: $REPLYTO
XFollowup-To: $follow
XDistribution: $dist
XOrganization: $orgname
XKeywords: 
XCc: 
X
XEOHeader
X
X!NO!SUBS!
Xcase "$d_nntp" in
Xdefine) $sed < Pnews.header -e '/^#NORMAL/d' > Pnews.h.new ;;
X*)  $sed < Pnews.header -e '/^#NORMAL/s/^#NORMAL//' > Pnews.h.new ;;
Xesac
X$mv Pnews.h.new Pnews.header
X$eunicefix Pnews.header
SHAR_EOF
  $shar_touch -am 1118220194 'trn-3.6/Pnews.SH' &&
  chmod 0644 'trn-3.6/Pnews.SH' ||
  echo 'restore of trn-3.6/Pnews.SH failed'
  shar_count="`wc -c < 'trn-3.6/Pnews.SH'`"
  test 18275 -eq "$shar_count" ||
    echo "trn-3.6/Pnews.SH: original size 18275, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= trn-3.6/sw.c ==============
if test -f 'trn-3.6/sw.c' && test X"$1" != X"-c"; then
  echo 'x - skipping trn-3.6/sw.c (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting trn-3.6/sw.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'trn-3.6/sw.c' &&
X/* $Id: sw.c,v 3.0 1992/02/01 03:09:32 davison Trn $
X */
X/* This software is Copyright 1991 by Stan Barber. 
X *
X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
X * use this software as long as: there is no monetary profit gained
X * specifically from the use or reproduction of this software, it is not
X * sold, rented, traded or otherwise marketed, and this copyright notice is
X * included prominently in any copy made. 
X *
X * The authors make no claims as to the fitness or correctness of this software
X * for any use whatsoever, and it is provided as is. Any use of this software
X * is at the user's own risk. 
X */
X
X#include "EXTERN.h"
X#include "common.h"
X#include "util.h"
X#include "util2.h"
X#include "cache.h"
X#include "head.h"
X#include "only.h"
X#include "term.h"
X#include "trn.h"
X#include "ng.h"
X#include "ngdata.h"
X#include "artstate.h"
X#include "intrp.h"
X#include "rt-page.h"
X#include "rt-util.h"
X#include "charsubst.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    if (!use_threads || !*safecpy(*tcbufptr,getenv("TRNINIT"),1024))
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_int 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 *s, *p, inquote = 0;
X
X    strcpy(tmplist,swlist);
X    p = tmplist;
X    for (s = p;;) {
X	while (isspace(*s)) s++;	/* skip any initial spaces */
X	if (*s != '#') {
X	    if (s != p)
X		strcpy(p, s);
X	    break;
X	}
X	while (*s && *s++ != '\n') ;	/* skip comments */
X    }
X    while (*p) {			/* "String, or nothing" */
X	if (!inquote && isspace(*p)) {	/* word delimiter? */
X	    *p++ = '\0';		/* chop here */
X	    for (s = p;;) {
X		while (isspace(*s)) s++;
X		if (*s != '#') {
X		    if (s != p)
X			strcpy(p, s);
X		    break;
X		}
X		while (*s && *s++ != '\n') ;
X	    }
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 DEBUG
X    if (debug)
X	printf("Switch: %s\n",s) FLUSH;
X#endif
X    if (*s != '-' && *s != '+') {	/* newsgroup pattern */
X	setngtodo(s);
X	emptyOnly = TRUE;
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	    export("SAVEDIR",  upordown ? "%p/%c" : "%p" );
X	    export("SAVENAME", upordown ? "%a"    : "%^C");
X#else
X	    notincl("-/");
X#endif
X	    break;
X	case 'a':
X	    thread_always = upordown;
X	    break;
X	case 'A':
X	    auto_arrow_macros = upordown;
X	    break;
X	case 'b':
X	    breadth_first = upordown;
X	    break;
X	case 'B':
X	    bkgnd_spinner = upordown;
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 DEBUG
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		export(tmpbuf,s);
X	    }
X	    else
X		export(tmpbuf,nullstr);
X#else
X	    notincl("-E");
X#endif
X	    break;
X	case 'f':
X	    novice_delays = !upordown;
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#ifdef EDIT_DISTANCE
X	case 'G':
X	    fuzzyGet = upordown && (actfp || mode == 'i');
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 'I':
X	    append_unsub = upordown;
X	    break;
X	case 'j':
X	    dont_filter_control = TRUE;
X	    break;
X	case 'J':
X	    s++;
X	    if (*s == '=') s++;
X	    if (isdigit(*s)) {
X		change_join_subject_len(atoi(s));
X		do {
X		    s++;
X		} while (isdigit(*s));
X	    } else
X		change_join_subject_len(upordown? 30 : 0);
X	    break;
X	case 'k':
X	    kill_thru_kludge = upordown;
X	    break;
X	case 'K':
X	    keep_the_group_static = upordown;
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 (isdigit(*s)) {
X		marking_areas = atoi(s);
X		do {
X		    s++;
X		} while (isdigit(*s));
X	    } else
X		marking_areas = HALFPAGE_MARKING;
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 'o':
X	    s++;
X	    if (*s == '=') s++;
X	    if (isdigit(*s)) {
X		olden_days = atoi(s);
X		do {
X		    s++;
X		} while (isdigit(*s));
X	    } else
X		olden_days = upordown;
X	    break;
X	case 'O':
X	    s++;
X	    if (*s == '=') s++;
X	    if (!*s)
X		break;
X	    if (!set_sel_mode(*s)
X	     || (*++s && !set_sel_sort(*s))) {
X#ifdef VERBOSE
X		IF(verbose)
X		    printf("\nIgnoring unrecognized -O option: %c\n", *s) FLUSH;
X		ELSE
X#endif
X#ifdef TERSE
X		    printf("\nIgnoring -O with %c\n", *s) FLUSH;
X#endif
X		break;
X	    }
X	    break;
X	case 'p':
X	    s++;
X	    if (*s == '=') s++;
X	    if (!upordown)
X		auto_select_postings = 0;
X	    else {
X		switch (*s) {
X		case '+':  case '.':  case 'p':
X		    auto_select_postings = *s;
X		    break;
X		default:
X		    auto_select_postings = '.';
X		    break;
X		}
X	    }
X	    break;
X	case 'q':
X	    quickstart = upordown;
X	    break;
X#ifdef CHARSUBST
X        case 'Q':
X	    s++;
X	    if (*s == '=') s++;
X	    if (*s)
X		charsets = savestr(s);
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	    if (!verbose)
X		novice_delays = FALSE;
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 'u':
X	    unbroken_subjects = upordown;
X	    break;
X	case 'U':
X	    unsafe_rc_saves = upordown;
X	    break;
X	case 'v':
X#ifdef VERIFY
X	    verify = upordown;
X#else
X	    notincl("-v");
X#endif
X	    break;
X	case 'V':
X	    trn_version();
X	    putchar('\n');
X	    if (mode == 'i')
X		exit(0);
X	    break;
X	case 'x':
X	    s++;
X	    if (*s == '=') s++;
X	    if (isdigit(*s)) {
X		if ((max_tree_lines = atoi(s)) > 11)
X		    max_tree_lines = 11;
X		do {
X		    s++;
X		} while (isdigit(*s));
X	    } else
X		max_tree_lines = 6;
X	    if (*s)
X		strncpy(select_order, s, 3);
X	    use_threads = upordown;
X	    break;
X	case 'X':
X	    s++;
X	    if (*s == '=') s++;
X	    if (isdigit(*s)) {
X		select_on = atoi(s);
X		do {
X		    s++;
X		} while (isdigit(*s));
X	    } else
X		select_on = upordown;
X	    if (*s)
X		end_select = *s++;
X	    if (*s)
X		page_select = *s;
X	    break;
X	case 'z':
X	    s++;
X	    if (*s == '=') s++;
X	    if (*s)
X		actFetchTime = atoi(s) * 60L;
X	    else
X		actFetchTime = upordown * 5L * 60L;
X	    break;
X	case 'Z':
X	    s++;
X	    if (*s == '=') s++;
X	    if (try_mt > 0)
X		try_mt = 0;
X	    if (try_ov > 0)
X		try_ov = 0;
X	    if (upordown) {
X		while (*s) {
X		    switch (*s++) {
X		    case 'o':
X			if (try_ov == 0)
X			    try_ov = ((mode == 'i' || ov_init())? 1 : -1);
X			break;
X		    case 't':
X			if (try_mt == 0)
X			    try_mt = ((mode == 'i' || mt_init())? 1 : -1);
X			break;
X		    }
X		}
X	    }
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("%ca ", mp[thread_always]);
X    printf("%cA ", mp[auto_arrow_macros]);
X    printf("%cb ", mp[breadth_first]);
X    printf("%cB ", mp[bkgnd_spinner]);
X    printf("%cc ", mp[checkflag]);
X    printf("-C%d ", docheckwhen);
X    printf("-d%s ", cwd);
X#ifdef DEBUG
X    if (debug)
X	printf("-D%d ", debug);
X#endif
X    printf("%ce ", mp[erase_screen]);
X    printf("%cf ", mp[!novice_delays]);
X    printf("-F\"%s\" ", indstr);
X#ifdef INNERSEARCH
X    printf("-g%d ", gline+1);
X#endif
X#ifdef EDIT_DISTANCE
X    printf("%cG", mp[fuzzyGet]);
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	putchar('\n');
X    }
X#endif
X    printf("-i%d ", initlines);
X    printf("%cI ", mp[append_unsub]);
X    printf("%cj ", mp[dont_filter_control]);
X    if (join_subject_len)
X	printf("-J%d ", join_subject_len);
X    else
X	printf("+J ");
X    printf("%ck ", mp[kill_thru_kludge]);
X    printf("%cK ", mp[keep_the_group_static]);
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%d%c ",marking_areas,marking==UNDERLINE?'u':'s');
X    else
X	printf("+m ");
X    printf("%cM ", mp[mbox_always]);
X    printf("%cN ", mp[norm_always]);
X    if (olden_days)
X	printf("-o%d ", olden_days);
X    else
X	printf("+o ");
X    if (auto_select_postings)
X	printf("-p%c ", auto_select_postings);
X    else
X	printf("+p ");
X    printf("%cq ", mp[quickstart]);
X#ifdef CHARSUBST
X    printf("-Q%s ", charsets);
X#endif
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    putchar('\n');
X#ifdef VERBOSE
X#ifdef TERSE
X    printf("%ct ", mp[!verbose]);
X#endif
X#endif
X    printf("%cT ", mp[typeahead]);
X    printf("%cu ", mp[unbroken_subjects]);
X    printf("%cU ", mp[unsafe_rc_saves]);
X#ifdef VERIFY
X    printf("%cv ", mp[verify]);
X#endif
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    if (actFetchTime)
X	printf("-z%ld ",(long)actFetchTime / 60);
X    else
X	printf("+z ");
X    if (try_mt > 0 || try_ov > 0) {
X	printf("-Z");
X	if (try_ov > 0)
X	    putchar('o');
X	if (try_mt > 0)
X	    putchar('t');
X	putchar(' ');
X    } else
X	printf("+Z ");
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
  $shar_touch -am 1118220194 'trn-3.6/sw.c' &&
  chmod 0644 'trn-3.6/sw.c' ||
  echo 'restore of trn-3.6/sw.c failed'
  shar_count="`wc -c < 'trn-3.6/sw.c'`"
  test 15514 -eq "$shar_count" ||
    echo "trn-3.6/sw.c: original size 15514, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= trn-3.6/sw.h ==============
if test -f 'trn-3.6/sw.h' && test X"$1" != X"-c"; then
  echo 'x - skipping trn-3.6/sw.h (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting trn-3.6/sw.h (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'trn-3.6/sw.h' &&
X/* $Id: sw.h,v 3.0 1992/02/01 03:09:32 davison Trn $
X */
X/* This software is Copyright 1991 by Stan Barber. 
X *
X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
X * use this software as long as: there is no monetary profit gained
X * specifically from the use or reproduction of this software, it is not
X * sold, rented, traded or otherwise marketed, and this copyright notice is
X * included prominently in any copy made. 
X *
X * The authors make no claims as to the fitness or correctness of this software
X * for any use whatsoever, and it is provided as is. Any use of this software
X * is at the user's own risk. 
X */
X
X#ifdef INNERSEARCH
XEXT int gline INIT(0);
X#endif
X
Xvoid    sw_init _((int,char**,char**));
Xvoid    sw_file _((char**,bool_int));
Xvoid    sw_list _((char*));
Xvoid	decode_switch _((char*));
Xvoid	pr_switches _((void));
Xvoid	cwd_check _((void));
SHAR_EOF
  $shar_touch -am 0711223693 'trn-3.6/sw.h' &&
  chmod 0644 'trn-3.6/sw.h' ||
  echo 'restore of trn-3.6/sw.h failed'
  shar_count="`wc -c < 'trn-3.6/sw.h'`"
  test 888 -eq "$shar_count" ||
    echo "trn-3.6/sw.h: original size 888, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= trn-3.6/term.c ==============
if test -f 'trn-3.6/term.c' && test X"$1" != X"-c"; then
  echo 'x - skipping trn-3.6/term.c (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting trn-3.6/term.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'trn-3.6/term.c' &&
X/* $Id: term.c,v 3.0 1992/02/01 03:09:32 davison Trn $
X */
X/* This software is Copyright 1991 by Stan Barber. 
X *
X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
X * use this software as long as: there is no monetary profit gained
X * specifically from the use or reproduction of this software, it is not
X * sold, rented, traded or otherwise marketed, and this copyright notice is
X * included prominently in any copy made. 
X *
X * The authors make no claims as to the fitness or correctness of this software
X * for any use whatsoever, and it is provided as is. Any use of this software
X * is at the user's own risk. 
X */
X
X#include "EXTERN.h"
X#include "common.h"
X#include "util.h"
X#include "util2.h"
X#include "final.h"
X#include "help.h"
X#include "cache.h"
X#include "intrp.h"
X#include "INTERN.h"
X#include "term.h"
X
X#ifdef u3b2
X#undef TIOCGWINSZ
X#endif
X
X#undef	USETITE		/* use terminal init/exit seqences (not recommended) */
X#undef	USEKSKE		/* use keypad start/end sequences */
X
Xchar ERASECH;		/* rubout character */
Xchar KILLCH;		/* line delete character */
Xchar tcarea[TCSIZE];	/* area for "compiled" termcap strings */
X
Xint upcost;
X
X/* guarantee capability pointer != Nullch */
X/* (I believe terminfo will ignore the &tmpaddr argument.) */
X
Xchar *tgetstr();
X#define Tgetstr(key) ((tmpstr = tgetstr(key,&tmpaddr)) ? tmpstr : nullstr)
X
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();
X
Xvoid line_col_calcs();
X
X/* terminal initialization */
X
Xvoid
Xterm_init()
X{
X    savetty();				/* remember current tty state */
X
X#ifdef I_TERMIO
X    outspeed = _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    if (GT = ((_tty.c_oflag & TABDLY) != TAB3))
X	/* we have tabs, so that's OK */;
X    else
X	_tty.c_oflag &= ~TAB3;	/* turn off kernel tabbing -- done in rn */
X#else /* !I_TERMIO */
X# ifdef I_TERMIOS
X    outspeed = cfgetospeed(&_tty);	/* for tputs() (output) */
X    ERASECH = _tty.c_cc[VERASE];	/* for finish_command() */
X    KILLCH = _tty.c_cc[VKILL];		/* for finish_command() */
X#if 0
X    _tty.c_oflag &= ~OXTABS;	/* turn off kernel tabbing-done in rn */
X#endif
X# else /* !I_TERMIOS */
X    outspeed = _tty.sg_ospeed;		/* for tputs() */
X    ERASECH = _tty.sg_erase;		/* for finish_command() */
X    KILLCH = _tty.sg_kill;		/* for finish_command() */
X    if (GT = ((_tty.sg_flags & XTABS) != XTABS))
X	/* we have tabs, so that's OK */;
X    else
X	_tty.sg_flags &= ~XTABS;
X# endif /* I_TERMIOS */
X#endif /* I_TERMIO */
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 (outspeed) {			/* 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 *s;
X    int status;
X#ifdef TIOCGWINSZ
X    struct winsize winsize;
X#endif
X
X#ifdef PENDING
X#if ! defined (FIONREAD) && ! defined (HAS_RDCHK)
X    /* do no delay reads on something that always gets closed on exit */
X
X    devtty = fileno(stdin);
X    if (isatty(devtty)) {
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    }
X#endif
X#endif
X    
X    /* get all that good termcap stuff */
X
X#ifdef HAS_TERMLIB
X    s = getenv("TERM");
X    status = tgetent(tcbuf,s? s : "dumb");	/* 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    TI = Tgetstr("ti");			/* initialize display */
X    TE = Tgetstr("te");			/* reset display */
X    KS = Tgetstr("ks");			/* enter `keypad transmit' mode */
X    KE = Tgetstr("ke");			/* exit `keypad transmit' mode */
X    HO = Tgetstr("ho");			/* home cursor */
X    IL = Tgetstr("al");			/* insert (add) line */
X    CM = Tgetstr("cm");			/* cursor motion */
X    if (*CM || *HO)
X	can_home = TRUE;
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    if (!*CE)
X	CE = CD;
X#endif /* CLEAREOL */
X    upcost = strlen(UP);
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 */
SHAR_EOF
  : || echo 'restore of trn-3.6/term.c failed'
fi
echo 'End of archive part 9'
echo 'File trn-3.6/term.c is continued in part 10'
echo 10 > _sharseq.tmp
exit 0


