rn version 4.3 (kit 4 of 9)
sources-request at genrad.UUCP
sources-request at genrad.UUCP
Sat May 11 07:00:09 AEST 1985
From: lwall at sdcrdcf.UUCP (Larry Wall)
---------------- cut here ---------------
#! /bin/sh
# Make a new directory for the rn sources, cd to it, and run kits 1 thru 9
# through sh. When all 9 kits have been run, read README.
echo "This is rn kit 4 (of 9). If kit 4 is complete, the line"
echo '"'"End of kit 4 (of 9)"'" will echo at the end.'
echo ""
export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
echo Extracting ng.c
cat >ng.c <<'!STUFFY!FUNK!'
/* $Header: ng.c,v 4.3 85/05/01 11:43:43 lwall Exp $
*
* $Log: ng.c,v $
* Revision 4.3 85/05/01 11:43:43 lwall
* Baseline for release with 4.3bsd.
*
*/
#include "EXTERN.h"
#include "common.h"
#include "rn.h"
#include "term.h"
#include "final.h"
#include "util.h"
#include "artsrch.h"
#include "cheat.h"
#include "help.h"
#include "kfile.h"
#include "rcstuff.h"
#include "head.h"
#include "artstate.h"
#include "bits.h"
#include "art.h"
#include "artio.h"
#include "ngstuff.h"
#include "intrp.h"
#include "respond.h"
#include "ngdata.h"
#include "backpage.h"
#include "rcln.h"
#include "last.h"
#include "INTERN.h"
#include "ng.h"
#include "artstate.h" /* somebody has to do it */
/* art_switch() return values */
#define AS_NORM 0
#define AS_INP 1
#define AS_ASK 2
#define AS_CLEAN 3
ART_NUM recent_art = 0; /* previous article # for '-' command */
ART_NUM curr_art = 0; /* current article # */
int exit_code = NG_NORM;
void
ng_init()
{
#ifdef KILLFILES
open_kfile(KF_GLOBAL);
#endif
}
/* do newsgroup on line ng with name ngname */
/* assumes that we are chdir'ed to SPOOL, and assures that that is
* still true upon return, but chdirs to SPOOL/ngname in between
*
* If you can understand this routine, you understand most of the program.
* The basic structure is:
* for each desired article
* for each desired page
* for each line on page
* if we need another line from file
* get it
* if it's a header line
* do special things
* for each column on page
* put out a character
* end loop
* end loop
* end loop
* end loop
*
* (Actually, the pager is in another routine.)
*
* The chief problem is deciding what is meant by "desired". Most of
* the messiness of this routine is due to the fact that people want
* to do unstructured things all the time. I have used a few judicious
* goto's where I thought it improved readability. The rest of the messiness
* arises from trying to be both space and time efficient. Have fun.
*/
int
do_newsgroup(start_command)
char *start_command; /* command to fake up first */
{
char oldmode = mode;
register long i; /* scratch */
int skipstate; /* how many unavailable articles */
/* have we skipped already? */
char *whatnext = "%sWhat next? [%s]";
#ifdef ARTSEARCH
srchahead = (scanon && ((ART_NUM)toread[ng]) >= scanon ? -1 : 0);
/* did they say -S? */
#endif
mode = 'a';
recent_art = curr_art = 0;
exit_code = NG_NORM;
if (eaccess(ngdir,5)) { /* directory read protected? */
if (eaccess(ngdir,0)) {
#ifdef VERBOSE
IF(verbose)
printf("\nNewsgroup %s does not have a spool directory!\n",
ngname) FLUSH;
ELSE
#endif
#ifdef TERSE
printf("\nNo spool for %s!\n",ngname) FLUSH;
#endif
#ifdef CATCHUP
catch_up(ng);
#endif
toread[ng] = TR_NONE;
}
else {
#ifdef VERBOSE
IF(verbose)
printf("\nNewsgroup %s is not currently accessible.\n",
ngname) FLUSH;
ELSE
#endif
#ifdef TERSE
printf("\n%s not readable.\n",ngname) FLUSH;
#endif
toread[ng] = TR_NONE; /* make this newsgroup invisible */
/* (temporarily) */
}
mode = oldmode;
return -1;
}
/* chdir to newsgroup subdirectory */
if (chdir(ngdir)) {
printf(nocd,ngdir) FLUSH;
mode = oldmode;
return -1;
}
#ifdef CACHESUBJ
subj_list = Null(char **); /* no subject list till needed */
#endif
/* initialize control bitmap */
if (initctl()) {
mode = oldmode;
return -1;
}
/* FROM HERE ON, RETURN THRU CLEANUP OR WE ARE SCREWED */
in_ng = TRUE; /* tell the world we are here */
forcelast = TRUE; /* if 0 unread, do not bomb out */
art=firstart;
/* remember what newsgroup we were in for sake of posterity */
writelast();
/* do they want a special top line? */
firstline = getval("FIRSTLINE",Nullch);
/* see if there are any special searches to do */
#ifdef KILLFILES
open_kfile(KF_LOCAL);
#ifdef VERBOSE
IF(verbose)
kill_unwanted(firstart,"Looking for articles to kill...\n\n",TRUE);
ELSE
#endif
#ifdef TERSE
kill_unwanted(firstart,"Killing...\n\n",TRUE);
#endif
#endif
/* now read each unread article */
rc_changed = doing_ng = TRUE; /* enter the twilight zone */
skipstate = 0; /* we have not skipped anything (yet) */
checkcount = 0; /* do not checkpoint for a while */
do_fseek = FALSE; /* start 1st article at top */
if (art > lastart)
art=firstart; /* init the for loop below */
for (; art<=lastart+1; ) { /* for each article */
/* do we need to "grow" the newsgroup? */
if (art > lastart || forcegrow)
grow_ctl();
check_first(art); /* make sure firstart is still 1st */
if (start_command) { /* fake up an initial command? */
prompt = whatnext;
strcpy(buf,start_command);
free(start_command);
start_command = Nullch;
art = lastart+1;
goto article_level;
}
if (art>lastart) { /* are we off the end still? */
ART_NUM ucount = 0; /* count of unread articles left */
for (i=firstart; i<=lastart; i++)
if (!(ctl_read(i)))
ucount++; /* count the unread articles */
#ifdef DEBUGGING
/*NOSTRICT*/
if (debug && ((ART_NUM)toread[ng]) != ucount)
printf("(toread=%ld sb %ld)",(long)toread[ng],(long)ucount)
FLUSH;
#endif
/*NOSTRICT*/
toread[ng] = (ART_UNREAD)ucount; /* this is perhaps pointless */
art = lastart + 1; /* keep bitmap references sane */
if (art != curr_art) {
recent_art = curr_art;
/* remember last article # (for '-') */
curr_art = art; /* remember this article # */
}
if (erase_screen)
clear(); /* clear the screen */
else
fputs("\n\n",stdout) FLUSH;
#ifdef VERBOSE
IF(verbose)
printf("End of newsgroup %s.",ngname);
/* print pseudo-article */
ELSE
#endif
#ifdef TERSE
printf("End of %s",ngname);
#endif
if (ucount) {
printf(" (%ld article%s still unread)",
(long)ucount,ucount==1?nullstr:"s");
}
else {
if (!forcelast)
goto cleanup; /* actually exit newsgroup */
}
prompt = whatnext;
#ifdef ARTSEARCH
srchahead = 0; /* no more subject search mode */
#endif
fputs("\n\n",stdout) FLUSH;
skipstate = 0; /* back to none skipped */
}
else if (!reread && was_read(art)) {
/* has this article been read? */
art++; /* then skip it */
continue;
}
else if
(!reread && !was_read(art)
&& artopen(art) == Nullfp) { /* never read it, & cannot find it? */
if (errno != ENOENT) { /* has it not been deleted? */
#ifdef VERBOSE
IF(verbose)
printf("\n(Article %ld exists but is unreadable.)\n",
(long)art) FLUSH;
ELSE
#endif
#ifdef TERSE
printf("\n(%ld unreadable.)\n",(long)art) FLUSH;
#endif
skipstate = 0;
sleep(2);
}
switch(skipstate++) {
case 0:
clear();
#ifdef VERBOSE
IF(verbose)
fputs("Skipping unavailable article",stdout);
ELSE
#endif
#ifdef TERSE
fputs("Skipping",stdout);
#endif
for (i = just_a_sec/3; i; --i)
putchar(PC);
fflush(stdout);
sleep(1);
break;
case 1:
fputs("..",stdout);
fflush(stdout);
break;
default:
putchar('.');
fflush(stdout);
#define READDIR
#ifdef READDIR
{ /* fast skip patch */
ART_NUM newart;
if (! (newart=getngmin(".",art)))
newart = lastart+1;
for (i=art; i<newart; i++)
oneless(i);
art = newart - 1;
}
#endif
break;
}
oneless(art); /* mark deleted as read */
art++; /* try next article */
continue;
}
else { /* we have a real live article */
skipstate = 0; /* back to none skipped */
if (art != curr_art) {
recent_art = curr_art;
/* remember last article # (for '-') */
curr_art = art; /* remember this article # */
}
if (!do_fseek) { /* starting at top of article? */
artline = 0; /* start at the beginning */
topline = -1; /* and remember top line of screen */
/* (line # within article file) */
}
clear(); /* clear screen */
artopen(art); /* make sure article file is open */
if (artfp == Nullfp) { /* could not find article? */
printf("Article %ld of %s is not available.\n\n",
(long)art,ngname) FLUSH;
prompt = whatnext;
#ifdef ARTSEARCH
srchahead = 0;
#endif
}
else { /* found it, so print it */
switch (do_article()) {
case DA_CLEAN: /* quit newsgroup */
goto cleanup;
case DA_TOEND: /* do not mark as read */
goto reask_article;
case DA_RAISE: /* reparse command at end of art */
goto article_level;
case DA_NORM: /* normal end of article */
break;
}
}
mark_as_read(art); /* mark current article as read */
reread = FALSE;
do_hiding = TRUE;
#ifdef ROTATION
rotate = FALSE;
#endif
}
/* if these gotos bother you, think of this as a little state machine */
reask_article:
#ifdef MAILCALL
setmail();
#endif
setdfltcmd();
#ifdef CLEAREOL
if (erase_screen && can_home_clear) /* PWP was here */
clear_rest();
#endif CLEAREOL
unflush_output(); /* disable any ^O in effect */
standout(); /* enter standout mode */
printf(prompt,mailcall,dfltcmd);/* print prompt, whatever it is */
un_standout(); /* leave standout mode */
putchar(' ');
fflush(stdout);
reinp_article:
eat_typeahead();
#ifdef PENDING
look_ahead(); /* see what we can do in advance */
if (!input_pending())
collect_subjects(); /* loads subject cache until */
/* input is pending */
#endif
getcmd(buf);
if (errno || *buf == '\f') {
if (LINES < 100 && !int_count)
*buf = '\f'; /* on CONT fake up refresh */
else {
putchar('\n') FLUSH; /* but only on a crt */
goto reask_article;
}
}
article_level:
/* parse and process article level command */
switch (art_switch()) {
case AS_INP: /* multichar command rubbed out */
goto reinp_article;
case AS_ASK: /* reprompt "End of article..." */
goto reask_article;
case AS_CLEAN: /* exit newsgroup */
goto cleanup;
case AS_NORM: /* display article art */
break;
}
} /* end of article selection loop */
/* shut down newsgroup */
cleanup:
#ifdef KILLFILES
kill_unwanted(firstart,"\nCleaning up...\n\n",FALSE);
/* do cleanup from KILL file, if any */
#endif
in_ng = FALSE; /* leave newsgroup state */
if (artfp != Nullfp) { /* article still open? */
fclose(artfp); /* close it */
artfp = Nullfp; /* and tell the world */
openart = 0;
}
putchar('\n') FLUSH;
yankback(); /* do a Y command */
restore_ng(); /* reconstitute .newsrc line */
doing_ng = FALSE; /* tell sig_catcher to cool it */
free(ctlarea); /* return the control area */
#ifdef CACHESUBJ
if (subj_list) {
for (i=OFFSET(lastart); i>=0; --i)
if (subj_list[i])
free(subj_list[i]);
#ifndef lint
free((char*)subj_list);
#endif lint
}
#endif
write_rc(); /* and update .newsrc */
rc_changed = FALSE; /* tell sig_catcher it is ok */
if (chdir(spool)) {
printf(nocd,spool) FLUSH;
sig_catcher(0);
}
#ifdef KILLFILES
if (localkfp) {
fclose(localkfp);
localkfp = Nullfp;
}
#endif
mode = oldmode;
return exit_code;
} /* Whew! */
/* decide what to do at the end of an article */
int
art_switch()
{
register ART_NUM i;
setdef(buf,dfltcmd);
#ifdef VERIFY
printcmd();
#endif
switch (*buf) {
case 'p': /* find previous unread article */
do {
if (art <= firstart)
break;
art--;
} while (was_read(art) || artopen(art) == Nullfp);
#ifdef ARTSEARCH
srchahead = 0;
#endif
return AS_NORM;
case 'P': /* goto previous article */
if (art > absfirst)
art--;
else {
#ifdef VERBOSE
IF(verbose)
fputs("\n\
There are no articles prior to this one.\n\
",stdout) FLUSH;
ELSE
#endif
#ifdef TERSE
fputs("\nNo previous articles\n",stdout) FLUSH;
#endif
return AS_ASK;
}
reread = TRUE;
#ifdef ARTSEARCH
srchahead = 0;
#endif
return AS_NORM;
case '-':
if (recent_art) {
art = recent_art;
reread = TRUE;
#ifdef ARTSEARCH
srchahead = -(srchahead != 0);
#endif
return AS_NORM;
}
else {
exit_code = NG_MINUS;
return AS_CLEAN;
}
case 'n': /* find next unread article? */
if (art > lastart) {
if (toread[ng])
art = firstart;
else
return AS_CLEAN;
}
#ifdef ARTSEARCH
else if (scanon && srchahead) {
*buf = Ctl('n');
goto normal_search;
}
#endif
else
art++;
#ifdef ARTSEARCH
srchahead = 0;
#endif
return AS_NORM;
case 'N': /* goto next article */
if (art > lastart)
art = absfirst;
else
art++;
if (art <= lastart)
reread = TRUE;
#ifdef ARTSEARCH
srchahead = 0;
#endif
return AS_NORM;
case '$':
art = lastart+1;
forcelast = TRUE;
#ifdef ARTSEARCH
srchahead = 0;
#endif
return AS_NORM;
case '1': case '2': case '3': /* goto specified article */
case '4': case '5': case '6': /* or do something with a range */
case '7': case '8': case '9': case '.':
forcelast = TRUE;
switch (numnum()) {
case NN_INP:
return AS_INP;
case NN_ASK:
return AS_ASK;
case NN_REREAD:
reread = TRUE;
#ifdef ARTSEARCH
if (srchahead)
srchahead = -1;
#endif
break;
case NN_NORM:
if (was_read(art)) {
art = firstart;
pad(just_a_sec/3);
}
else
return AS_ASK;
break;
}
return AS_NORM;
case Ctl('k'):
edit_kfile();
return AS_ASK;
case 'K':
case 'k':
case Ctl('n'): case Ctl('p'):
case '/': case '?':
#ifdef ARTSEARCH
normal_search:
{ /* search for article by pattern */
char cmd = *buf;
reread = TRUE; /* assume this */
switch (art_search(buf, (sizeof buf), TRUE)) {
case SRCH_ERROR:
return AS_ASK;
case SRCH_ABORT:
return AS_INP;
case SRCH_INTR:
#ifdef VERBOSE
IF(verbose)
printf("\n(Interrupted at article %ld)\n",(long)art) FLUSH;
ELSE
#endif
#ifdef TERSE
printf("\n(Intr at %ld)\n",(long)art) FLUSH;
#endif
art = curr_art;
/* restore to current article */
return AS_ASK;
case SRCH_DONE:
fputs("done\n",stdout) FLUSH;
pad(just_a_sec/3); /* 1/3 second */
if (srchahead)
art = firstart;
else
art = curr_art;
reread = FALSE;
return AS_NORM;
case SRCH_SUBJDONE:
#ifdef UNDEF
fputs("\n\n\n\nSubject not found.\n",stdout) FLUSH;
pad(just_a_sec/3); /* 1/3 second */
#endif
art = firstart;
reread = FALSE;
return AS_NORM;
case SRCH_NOTFOUND:
fputs("\n\n\n\nNot found.\n",stdout) FLUSH;
art = curr_art; /* restore to current article */
return AS_ASK;
case SRCH_FOUND:
if (cmd == Ctl('n') || cmd == Ctl('p'))
oldsubject = TRUE;
break;
}
return AS_NORM;
}
#else
buf[1] = '\0';
notincl(buf);
return AS_ASK;
#endif
case 'u': /* unsubscribe from this newsgroup? */
rcchar[ng] = NEGCHAR;
return AS_CLEAN;
case 'M':
#ifdef DELAYMARK
if (art <= lastart) {
delay_unmark(art);
printf("\nArticle %ld will return.\n",(long)art) FLUSH;
}
#else
notincl("M");
#endif
return AS_ASK;
case 'm':
if (art <= lastart) {
unmark_as_read(art);
printf("\nArticle %ld marked as still unread.\n",(long)art) FLUSH;
}
return AS_ASK;
case 'c': /* catch up */
reask_catchup:
#ifdef VERBOSE
IF(verbose)
in_char("\nDo you really want to mark everything as read? [yn] ");
ELSE
#endif
#ifdef TERSE
in_char("\nReally? [ynh] ");
#endif
putchar('\n') FLUSH;
setdef(buf,"y");
#ifdef VERIFY
printcmd();
#endif
if (*buf == 'h') {
#ifdef VERBOSE
IF(verbose)
fputs("\
Type y or SP to mark all articles as read.\n\
Type n to leave articles marked as they are.\n\
Type u to mark everything read and unsubsubscribe.\n\
",stdout) FLUSH;
ELSE
#endif
#ifdef TERSE
fputs("\
y or SP to mark all read.\n\
n to forget it.\n\
u to mark all and unsubscribe.\n\
",stdout) FLUSH;
#endif
goto reask_catchup;
}
else if (*buf == 'n' || *buf == 'q') {
return AS_ASK;
}
else if (*buf != 'y' && *buf != 'u') {
fputs(hforhelp,stdout) FLUSH;
settle_down();
goto reask_catchup;
}
for (i = firstart; i <= lastart; i++) {
ctl_set(i); /* mark as read */
}
#ifdef DELAYMARK
if (dmfp)
yankback();
#endif
if (*buf == 'u') {
rcchar[ng] = NEGCHAR;
return AS_CLEAN;
}
art = lastart+1;
forcelast = FALSE;
return AS_NORM;
case 'Q':
exit_code = NG_ASK;
/* FALL THROUGH */
case 'q': /* go back up to newsgroup level? */
return AS_CLEAN;
case 'j':
putchar('\n') FLUSH;
if (art <= lastart)
mark_as_read(art);
return AS_ASK;
case 'h': { /* help? */
int cmd;
if ((cmd = help_art()) > 0)
pushchar(cmd);
return AS_ASK;
}
case '&':
if (switcheroo()) /* get rest of command */
return AS_INP; /* if rubbed out, try something else */
return AS_ASK;
case '#':
#ifdef VERBOSE
IF(verbose)
printf("\nThe last article is %ld.\n",(long)lastart) FLUSH;
ELSE
#endif
#ifdef TERSE
printf("\n%ld\n",(long)lastart) FLUSH;
#endif
return AS_ASK;
case '=': {
char tmpbuf[256];
ART_NUM oldart = art;
int cmd;
char *subjline = getval("SUBJLINE",Nullch);
#ifndef CACHESUBJ
char *s;
#endif
page_init();
#ifdef CACHESUBJ
if (!subj_list)
fetchsubj(art,TRUE,FALSE);
#endif
for (i=firstart; i<=lastart && !int_count; i++) {
#ifdef CACHESUBJ
if (!was_read(i) &&
(subj_list[OFFSET(i)] != Nullch || fetchsubj(i,FALSE,FALSE)) &&
*subj_list[OFFSET(i)] ) {
sprintf(tmpbuf,"%5ld ", i);
if (subjline) {
art = i;
interp(tmpbuf + 6, (sizeof tmpbuf) - 6, subjline);
}
else
safecpy(tmpbuf + 6, subj_list[OFFSET(i)],
(sizeof tmpbuf) - 6);
if (cmd = print_lines(tmpbuf,NOMARKING)) {
if (cmd > 0)
pushchar(cmd);
break;
}
}
#else
if (!was_read(i) && (s = fetchsubj(i,FALSE,FALSE)) && *s) {
sprintf(tmpbuf,"%5ld ", i);
if (subjline) { /* probably fetches it again! */
art = i;
interp(tmpbuf + 6, (sizeof tmpbuf) - 6, subjline);
}
else
safecpy(tmpbuf + 6, s, (sizeof tmpbuf) - 6);
if (cmd = print_lines(tmpbuf,NOMARKING)) {
if (cmd > 0)
pushchar(cmd);
break;
}
}
#endif
}
int_count = 0;
art = oldart;
return AS_ASK;
}
case '^':
art = firstart;
#ifdef ARTSEARCH
srchahead = 0;
#endif
return AS_NORM;
#if defined(CACHESUBJ) && defined(DEBUGGING)
case 'D':
printf("\nFirst article: %ld\n",(long)firstart) FLUSH;
if (!subj_list)
fetchsubj(art,TRUE,FALSE);
if (subj_list != Null(char **)) {
for (i=1; i<=lastart && !int_count; i++) {
if (subj_list[OFFSET(i)])
printf("%5ld %c %s\n",
i, (was_read(i)?'y':'n'), subj_list[OFFSET(i)]) FLUSH;
}
}
int_count = 0;
return AS_ASK;
#endif
case 'v':
if (art <= lastart) {
reread = TRUE;
do_hiding = FALSE;
}
return AS_NORM;
#ifdef ROTATION
case Ctl('x'):
#endif
case Ctl('r'):
#ifdef ROTATION
rotate = (*buf==Ctl('x'));
#endif
if (art <= lastart)
reread = TRUE;
return AS_NORM;
#ifdef ROTATION
case 'X':
rotate = !rotate;
/* FALL THROUGH */
#else
case Ctl('x'):
case 'x':
case 'X':
notincl("x");
return AS_ASK;
#endif
case 'l': case Ctl('l'): /* refresh screen */
if (art <= lastart) {
reread = TRUE;
clear();
do_fseek = TRUE;
artline = topline;
if (artline < 0)
artline = 0;
}
return AS_NORM;
case 'b': case Ctl('b'): /* back up a page */
if (art <= lastart) {
ART_LINE target;
reread = TRUE;
clear();
do_fseek = TRUE;
target = topline - (LINES - 2);
artline = topline;
do {
artline--;
} while (artline >= 0 && artline > target &&
vrdary(artline-1) >= 0);
topline = artline;
if (artline < 0)
artline = 0;
}
return AS_NORM;
case '!': /* shell escape */
if (escapade())
return AS_INP;
return AS_ASK;
case 'C': {
cancel_article();
return AS_ASK;
}
case 'R':
case 'r': { /* reply? */
reply();
return AS_ASK;
}
case 'F':
case 'f': { /* followup command */
followup();
forcegrow = TRUE; /* recalculate lastart */
return AS_ASK;
}
case '|':
case 'w': case 'W':
case 's': case 'S': /* save command */
if (save_article() == SAVE_ABORT)
return AS_INP;
return AS_ASK;
#ifdef DELAYMARK
case 'Y': /* yank back M articles */
yankback();
art = firstart; /* from the beginning */
return AS_NORM; /* pretend nothing happened */
#endif
#ifdef STRICTCR
case '\n':
fputs(badcr,stdout) FLUSH;
return AS_ASK;
#endif
default:
printf("\n%s",hforhelp) FLUSH;
settle_down();
return AS_ASK;
}
}
#ifdef MAILCALL
/* see if there is any mail */
void
setmail()
{
if (! (mailcount++)) {
char *mailfile = filexp(getval("MAILFILE",MAILFILE));
if (stat(mailfile,&filestat) < 0 || !filestat.st_size
|| filestat.st_atime > filestat.st_mtime)
mailcall = nullstr;
else
mailcall = "(Mail) ";
}
mailcount %= 10; /* check every 10 articles */
}
#endif
void
setdfltcmd()
{
if (toread[ng]) {
#ifdef ARTSEARCH
if (srchahead)
dfltcmd = "^Nnpq";
else
#endif
dfltcmd = "npq";
}
else {
if (art > lastart)
dfltcmd = "qnp";
else
dfltcmd = "npq";
}
}
!STUFFY!FUNK!
echo Extracting art.c
cat >art.c <<'!STUFFY!FUNK!'
/* $Header: art.c,v 4.3 85/05/01 11:34:51 lwall Exp $
*
* $Log: art.c,v $
* Revision 4.3 85/05/01 11:34:51 lwall
* Baseline for release with 4.3bsd.
*
*/
#include "EXTERN.h"
#include "common.h"
#include "rn.h"
#include "ngstuff.h"
#include "head.h"
#include "cheat.h"
#include "help.h"
#include "search.h"
#include "artio.h"
#include "ng.h"
#include "bits.h"
#include "final.h"
#include "artstate.h"
#include "rcstuff.h"
#include "term.h"
#include "sw.h"
#include "util.h"
#include "backpage.h"
#include "intrp.h"
#include "INTERN.h"
#include "art.h"
/* page_switch() return values */
#define PS_NORM 0
#define PS_ASK 1
#define PS_RAISE 2
#define PS_TOEND 3
bool special = FALSE; /* is next page special length? */
int slines = 0; /* how long to make page when special */
ART_LINE highlight = -1; /* next line to be highlighted */
char *restart = Nullch; /* if nonzero, the place where last */
/* line left off on line split */
char *blinebeg; /* where in buffer current line began */
ART_POS alinebeg; /* where in file current line began */
#ifdef INNERSEARCH
ART_POS innersearch = 0; /* artpos of end of line we found */
/* for 'g' command */
ART_LINE isrchline = 0; /* last line to display */
bool hide_everything = FALSE;
/* if set, do not write page now, */
/* but refresh when done with page */
COMPEX gcompex; /* in article search pattern */
#endif
bool firstpage; /* is this the 1st page of article? */
void
art_init()
{
;
}
int
do_article()
{
register char *s;
ART_POS artsize; /* size in bytes of article */
char art_buf[LBUFLEN]; /* place for article lines */
bool hide_this_line = FALSE; /* hidden header line? */
ART_LINE linenum; /* line # on page, 1 origin */
#ifdef ULSMARTS
bool under_lining = FALSE;
/* are we underlining a word? */
#endif
register char *bufptr = art_buf;
/* pointer to input buffer */
register int outpos; /* column position of output */
static char prompt_buf[64]; /* place to hold prompt */
bool notesfiles = FALSE; /* might there be notesfiles junk? */
char oldmode = mode;
#ifdef INNERSEARCH
register int outputok;
#endif
if (fstat(artfp->_file,&filestat))
/* get article file stats */
return DA_CLEAN;
artsize = filestat.st_size;
/* from that get article size */
sprintf(prompt_buf,
"%%sEnd of article %ld (of %ld)--what next? [%%s]",
(long)art,(long)lastart); /* format prompt string */
prompt = prompt_buf;
int_count = 0; /* interrupt count is 0 */
firstpage = (topline < 0);
for (;;) { /* for each page */
assert(art == openart);
if (do_fseek) {
#ifdef ASYNC_PARSE
parse_maybe(art); /* make sure header is ours */
#endif
artpos = vrdary(artline);
if (artpos < 0)
artpos = -artpos; /* labs(), anyone? */
fseek(artfp,artpos,0);
if (artpos < htype[PAST_HEADER].ht_minpos)
in_header = SOME_LINE;
do_fseek = FALSE;
restart = Nullch;
}
if (firstpage) {
if (firstline) {
interp(art_buf, (sizeof art_buf), firstline);
#ifdef CLEAREOL
maybe_eol(); /* PWP */
#endif CLEAREOL
fputs(art_buf,stdout) FLUSH;
artopen(art); /* rewind article in case interp */
/* forced a header parse */
}
else {
ART_NUM i;
#ifdef CLEAREOL
maybe_eol(); /* PWP */
#endif CLEAREOL
printf("Article %ld",(long)art);
i = (((ART_NUM)toread[ng]) - 1 + was_read(art));
#ifdef DELAYMARK
if (i || dmcount) {
printf(" (%ld more",(long)i);
if (dmcount)
printf(" + %ld Marked to return)",(long)dmcount);
putchar(')');
}
#else
if (i)
printf(" (%ld more)",(long)i);
#endif
if (htype[NGS_LINE].ht_flags & HT_HIDE)
printf(" in %s", ngname);
fputs(":\n",stdout) FLUSH;
}
start_header(art);
forcelast = FALSE; /* we will have our day in court */
restart = Nullch;
artline = 0; /* start counting lines */
artpos = 0;
vwtary(artline,artpos); /* remember pos in file */
}
for (linenum=(firstpage?2:1);
in_header || (
#ifdef INNERSEARCH
innersearch ? innermore() :
#endif
linenum<(firstpage?initlines:(special?slines:LINES)) );
linenum++) { /* for each line on page */
if (int_count) { /* exit via interrupt? */
putchar('\n') FLUSH; /* get to left margin */
int_count = 0; /* reset interrupt count */
return DA_NORM; /* skip out of loops */
}
if (restart) { /* did not finish last line? */
bufptr = restart; /* then start again here */
restart = Nullch; /* and reset the flag */
}
else { /* not a restart */
if (fgets(art_buf,LBUFLEN,artfp)==Nullch) {
/* if all done */
return DA_NORM; /* skip out of loops */
}
bufptr = art_buf; /* so start at beginning */
art_buf[LBUFLEN-1] = '\0';
/* make sure string ends */
}
blinebeg = bufptr; /* remember where we began */
alinebeg = artpos; /* both in buffer and file */
if (in_header && bufptr == art_buf)
hide_this_line =
parseline(art_buf,do_hiding,hide_this_line);
else if (notesfiles && do_hiding &&
bufptr == art_buf && *art_buf == '#' &&
isupper(art_buf[1]) && art_buf[2] == ':' ) {
fgets(art_buf,sizeof(art_buf),artfp);
if (index(art_buf,'!') != Nullch)
fgets(art_buf,sizeof(art_buf),artfp);
htype[PAST_HEADER].ht_minpos = ftell(artfp);
/* exclude notesfiles droppings */
hide_this_line = TRUE; /* and do not print either */
notesfiles = FALSE;
}
if (in_header && htype[in_header].ht_flags & HT_MAGIC) {
if (in_header == NGS_LINE) {
hide_this_line = (index(art_buf,',') == Nullch && do_hiding);
}
else if (in_header == EXPIR_LINE) {
if (!(htype[EXPIR_LINE].ht_flags & HT_HIDE))
hide_this_line = (strlen(art_buf) < 10 && do_hiding);
}
}
if (in_header == SUBJ_LINE &&
htype[SUBJ_LINE].ht_flags & HT_MAGIC) {
/* is this the subject? */
int length;
length = strlen(art_buf)-1;
artline++;
art_buf[length] = '\0'; /* wipe out newline */
#ifdef NOFIREWORKS
no_ulfire();
#endif
notesfiles =
(instr(&art_buf[length-10]," - (nf") != Nullch);
if (oldsubject) {
length += 7;
fputs("(SAME) ",stdout);
oldsubject = FALSE;
}
if (length+UG > COLS) { /* rarely true */
linenum++;
vwtary(artline,vrdary(artline-1)+COLS);
artline++;
}
s = art_buf + 8;
*s++ = '\0'; /* make into 2 strings */
#ifdef CLEAREOL
maybe_eol(); /* PWP */
#endif CLEAREOL
fputs(art_buf,stdout) FLUSH;
/* print up through : */
if (!UG)
putchar(' ');
underprint(s); /* print subject underlined */
putchar('\n') FLUSH; /* and finish the line */
}
else if (hide_this_line) { /* do not print line? */
linenum--; /* compensate for linenum++ */
if (!in_header)
hide_this_line = FALSE;
}
else { /* just a normal line */
if (highlight==artline) { /* this line to be highlit? */
if (marking == STANDOUT) {
#ifdef NOFIREWORKS
if (erase_screen)
no_sofire();
#endif
standout();
}
else {
#ifdef NOFIREWORKS
if (erase_screen)
no_ulfire();
#endif
underline();
}
if (*bufptr == '\n')
putchar(' ');
}
#ifdef INNERSEARCH
outputok = !hide_everything;
/* get it into register, hopefully */
#endif
#ifdef CLEAREOL
#ifdef INNERSEARCH
if (outputok)
#endif
maybe_eol(); /* PWP */
#endif CLEAREOL
for (outpos = 0; outpos < COLS; ) {
/* while line has room */
if (*bufptr >= ' ') { /* normal char? */
#ifdef ULSMARTS
if (*bufptr == '_') {
if (bufptr[1] == '\b') {
if (!under_lining && highlight!=artline
#ifdef INNERSEARCH
&& outputok
#endif
) {
under_lining++;
if (UG) {
if (bufptr != buf &&
bufptr[-1] == ' ') {
outpos--;
backspace();
}
}
underline();
}
bufptr += 2;
}
}
else {
if (under_lining) {
under_lining = 0;
un_underline();
if (UG) {
if (*bufptr == ' ')
goto skip_put;
outpos++;
}
}
}
#endif
#ifdef INNERSEARCH
if (outputok)
#endif
{
#ifdef ROTATION
if (rotate && !in_header
&& isalpha(*bufptr)) {
if ((*bufptr & 31) <= 13)
putchar(*bufptr+13);
else
putchar(*bufptr-13);
}
else
#endif
putchar(*bufptr);
}
if (*UC && ((highlight==artline && marking == 1)
#ifdef ULSMARTS
|| under_lining
#endif
)) {
backspace();
underchar();
}
skip_put:
bufptr++;
outpos++;
}
else if (*bufptr == '\n' || !*bufptr) {
/* newline? */
#ifdef ULSMARTS
if (under_lining) {
under_lining = 0;
un_underline();
}
#endif
#ifdef DEBUGGING
if (debug & DEB_INNERSRCH && outpos < COLS - 6) {
standout();
printf("%4d",artline);
un_standout();
}
#endif
#ifdef INNERSEARCH
if (outputok)
#endif
putchar('\n') FLUSH;
restart = 0;
outpos = 1000; /* signal normal \n */
}
else if (*bufptr == '\t') { /* tab? */
#ifdef INNERSEARCH
if (outputok)
#endif
putchar(*bufptr);
bufptr++;
outpos += 8 - outpos % 8;
}
else if (*bufptr == '\f') { /* form feed? */
#ifdef INNERSEARCH
if (outputok)
#endif
fputs("^L",stdout);
if (bufptr == blinebeg && highlight != artline)
linenum = 32700;
/* how is that for a magic number? */
bufptr++;
outpos += 2;
}
else { /* other control char */
#ifdef INNERSEARCH
if (outputok)
#endif
{
putchar('^');
if (highlight == artline && *UC && marking == 1) {
backspace();
underchar();
putchar(*bufptr+64);
backspace();
underchar();
}
else
putchar(*bufptr+64);
}
bufptr++;
outpos += 2;
}
} /* end of column loop */
if (outpos < 1000) {/* did line overflow? */
restart = bufptr;
/* restart here next time */
if (AM) { /* automatic margins on tty? */
if (!XN && *bufptr == '\n')
/* need we simulate XN? */
restart = 0;
/* skip the newline */
}
else { /* cursor just hangs there */
#ifdef INNERSEARCH
if (outputok)
#endif
putchar('\n') FLUSH;
/* so move it down ourselves */
if (*bufptr == '\n')
restart = 0;
/* simulate XN if need be */
}
#ifdef CLEAREOL
/* #ifdef INNERSEARCH
if (outputok)
#endif
maybe_eol(); */ /* PWP *//* comment this out for now
until I am sure it is
needed*/
#endif CLEAREOL
}
/* handle normal end of output line formalities */
if (highlight == artline) {
/* were we highlighting line? */
if (marking == STANDOUT)
un_standout();
else
un_underline();
highlight = -1; /* no more we are */
}
artline++; /* count the line just printed */
if (artline - LINES + 1 > topline)
/* did we just scroll top line off? */
topline = artline - LINES + 1;
/* then recompute top line # */
}
/* determine actual position in file */
if (restart) /* stranded somewhere in the buffer? */
artpos += restart - blinebeg;
/* just calculate position */
else /* no, ftell will do */
artpos = ftell(artfp);
/* so do ftell */
vwtary(artline,artpos); /* remember pos in file */
} /* end of line loop */
#ifdef INNERSEARCH
innersearch = 0;
if (hide_everything) {
hide_everything = FALSE;
*buf = Ctl('l');
goto fake_command;
}
#endif
if (linenum >= 32700)/* did last line have formfeed? */
vwtary(artline-1,-vrdary(artline-1));
/* remember by negating pos in file */
special = FALSE; /* end of page, so reset page length */
firstpage = FALSE; /* and say it is not 1st time thru */
/* extra loop bombout */
if (artpos == artsize) /* did we just now reach EOF? */
return DA_NORM; /* avoid --MORE--(100%) */
/* not done with this article, so pretend we are a pager */
reask_pager:
unflush_output(); /* disable any ^O in effect */
standout(); /* enter standout mode */
printf("--MORE--(%ld%%)",(long)(artpos*100/artsize));
un_standout(); /* leave standout mode */
fflush(stdout);
/* reinp_pager: /* unused, commented for lint */
eat_typeahead();
#ifdef DEBUGGING
if (debug & DEB_CHECKPOINTING) {
printf("(%d %d %d)",checkcount,linenum,artline);
fflush(stdout);
}
#endif
if (checkcount >= docheckwhen &&
linenum == LINES &&
(artline > 40 || checkcount >= docheckwhen+10) ) {
/* while he is reading a whole page */
/* in an article he is interested in */
checkcount = 0;
checkpoint_rc(); /* update .newsrc */
}
collect_subjects(); /* loads subject cache until */
/* input is pending */
mode = 'p';
getcmd(buf);
if (errno) {
if (LINES < 100 && !int_count)
*buf = '\f';/* on CONT fake up refresh */
else {
*buf = 'q'; /* on INTR or paper just quit */
}
}
carriage_return();
#ifndef CLEAREOL
erase_eol(); /* and erase the prompt */
#else
if (erase_screen && can_home_clear) /* PWP was here */
clear_rest();
else
erase_eol(); /* and erase the prompt */
#endif CLEAREOL
fflush(stdout);
fake_command: /* used by innersearch */
/* parse and process pager command */
switch (page_switch()) {
case PS_ASK: /* reprompt "--MORE--..." */
goto reask_pager;
case PS_RAISE: /* reparse on article level */
mode = oldmode;
return DA_RAISE;
case PS_TOEND: /* fast pager loop exit */
mode = oldmode;
return DA_TOEND;
case PS_NORM: /* display more article */
break;
}
} /* end of page loop */
}
/* process pager commands */
int
page_switch()
{
register char *s;
switch (*buf) {
case 'd':
case Ctl('d'): /* half page */
special = TRUE;
slines = LINES / 2 + 1;
if (marking && *blinebeg != '\f') {
up_line();
highlight = --artline;
restart = blinebeg;
artpos = alinebeg;
}
return PS_NORM;
case '!': /* shell escape */
escapade();
return PS_ASK;
#ifdef INNERSEARCH
case Ctl('i'):
gline = 3;
sprintf(cmd_buf,"^[^%c]",*blinebeg);
compile(&gcompex,cmd_buf,TRUE,TRUE);
goto caseG;
case Ctl('g'):
gline = 3;
compile(&gcompex,"^Subject:",TRUE,TRUE);
goto caseG;
case 'g': /* in-article search */
if (!finish_command(FALSE))/* get rest of command */
return PS_ASK;
s = buf+1;
if (isspace(*s))
s++;
if ((s = compile(&gcompex,s,TRUE,TRUE)) != Nullch) {
/* compile regular expression */
printf("\n%s\n",s) FLUSH;
return PS_ASK;
}
carriage_return();
erase_eol(); /* erase the prompt */
/* FALL THROUGH */
caseG:
case 'G': {
/* ART_LINE lines_to_skip = 0; */
ART_POS start_where;
if (gline < 0 || gline > LINES-2)
gline = LINES-2;
#ifdef DEBUGGING
if (debug & DEB_INNERSRCH)
printf("Start here? %d >=? %d\n",topline + gline + 1,artline)
FLUSH;
#endif
if (*buf == Ctl('i') || topline+gline+1 >= artline)
start_where = artpos;
/* in case we had a line wrap */
else {
start_where = vrdary(topline+gline+1);
if (start_where < 0)
start_where = -start_where;
}
if (start_where < htype[PAST_HEADER].ht_minpos)
start_where = htype[PAST_HEADER].ht_minpos;
fseek(artfp,(long)start_where,0);
innersearch = 0; /* assume not found */
while (fgets(buf, sizeof buf, artfp) != Nullch) {
/* lines_to_skip++; NOT USED NOW */
#ifdef DEBUGGING
if (debug & DEB_INNERSRCH)
printf("Test %s",buf) FLUSH;
#endif
if (execute(&gcompex,buf) != Nullch) {
innersearch = ftell(artfp);
break;
}
}
if (!innersearch) {
fseek(artfp,artpos,0);
fputs("(Not found)",stdout) FLUSH;
return PS_ASK;
}
#ifdef DEBUGGING
if (debug & DEB_INNERSRCH)
printf("On page? %ld <=? %ld\n",(long)innersearch,(long)artpos)
FLUSH;
#endif
if (innersearch <= artpos) { /* already on page? */
if (innersearch < artpos) {
artline = topline+1;
while (vrdary(artline) < innersearch)
artline++;
}
highlight = artline - 1;
#ifdef DEBUGGING
if (debug & DEB_INNERSRCH)
printf("@ %d\n",highlight) FLUSH;
#endif
topline = highlight - gline;
if (topline < -1)
topline = -1;
*buf = '\f'; /* fake up a refresh */
innersearch = 0;
return page_switch();
}
else { /* who knows how many lines it is? */
do_fseek = TRUE;
hide_everything = TRUE;
}
return PS_NORM;
}
#else
case 'g': case 'G': case Ctl('g'):
notincl("g");
return PS_ASK;
#endif
case '\n': /* one line */
special = TRUE;
slines = 2;
return PS_NORM;
#ifdef ROTATION
case 'X':
rotate = !rotate;
/* FALL THROUGH */
#endif
case 'l':
case '\f': /* refresh screen */
#ifdef DEBUGGING
if (debug & DEB_INNERSRCH) {
printf("Topline = %d",topline) FLUSH;
gets(buf);
}
#endif
clear();
do_fseek = TRUE;
artline = topline;
if (artline < 0)
artline = 0;
firstpage = (topline < 0);
return PS_NORM;
case 'b':
case '\b': /* I like backspace for this -- PWP */
/* Leaving it undocumented in case */
/* I want to steal the key--LAW */
case Ctl('b'): { /* back up a page */
ART_LINE target;
#ifndef CLEAREOL
clear();
#else
if (can_home_clear) /* if we can home do it -- PWP */
home_cursor();
else
clear();
#endif CLEAREOL
do_fseek = TRUE; /* reposition article file */
target = topline - (LINES - 2);
artline = topline;
do {
artline--;
} while (artline >= 0 && artline > target &&
vrdary(artline-1) >= 0);
topline = artline;
/* remember top line of screen */
/* (line # within article file) */
if (artline < 0)
artline = 0;
firstpage = (topline < 0);
return PS_NORM;
}
case 'h': { /* help */
int cmd;
if ((cmd = help_page()) > 0)
pushchar(cmd);
return PS_ASK;
}
case '\177':
case '\0': /* treat del,break as 'n' */
*buf = 'n';
/* FALL THROUGH */
case 'k': case 'K':
case 'n': case 'N': case Ctl('n'):
case 's': case 'S':
case 'u':
case 'w': case 'W':
case '|':
mark_as_read(art); /* mark article as read */
/* FALL THROUGH */
case '#':
case '$':
case '&':
case '-':
case '.':
case '/':
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
case '=':
case '?':
case 'c': case 'C':
case 'f': case 'F':
case 'j':
case Ctl('k'):
case 'm': case 'M':
case 'p': case 'P': case Ctl('p'):
case 'Q':
case 'r': case 'R': case Ctl('r'):
case 'v':
case 'Y':
#ifndef ROTATION
case 'x': case 'X':
#endif
case Ctl('x'):
case '^':
#ifdef ROTATION
rotate = FALSE;
#endif
reread = FALSE;
do_hiding = TRUE;
if (index("nNpP",*buf) == Nullch &&
index("wWsS!&|/?123456789.",*buf) != Nullch) {
setdfltcmd();
standout(); /* enter standout mode */
printf(prompt,mailcall,dfltcmd);
/* print prompt, whatever it is */
un_standout(); /* leave standout mode */
putchar(' ');
fflush(stdout);
}
return PS_RAISE; /* and pretend we were at end */
#ifdef ROTATION
case 'x':
rotate = TRUE;
/* FALL THROUGH */
#endif
case 'y':
case Ctl('v'): /* I like emacs -- PWP */
/* Leaving it undocumented in case */
/* I want to steal the key--LAW */
case ' ': /* continue current article */
if (erase_screen) { /* -e? */
#ifndef CLEAREOL
clear(); /* clear screen */
#else
if (can_home_clear) /* if we can home do it -- PWP */
home_cursor();
else
clear(); /* else clear screen */
#endif CLEAREOL
if (*blinebeg != '\f') {
restart = blinebeg;
artline--; /* restart this line */
artpos = alinebeg;
if (marking) /* and mark repeated line */
highlight = artline;
}
topline = artline;
/* and remember top line of screen */
/* (line # within article file) */
}
else if (marking && *blinebeg != '\f') {
/* are we marking repeats? */
up_line(); /* go up one line */
highlight = --artline;/* and get ready to highlight */
restart = blinebeg; /* the old line */
artpos = alinebeg;
}
return PS_NORM;
case 'q': /* quit this article? */
do_hiding = TRUE;
return PS_TOEND;
default:
fputs(hforhelp,stdout) FLUSH;
settle_down();
return PS_ASK;
}
}
#ifdef INNERSEARCH
bool
innermore()
{
if (artpos < innersearch) { /* not even on page yet? */
#ifdef DEBUGGING
if (debug & DEB_INNERSRCH)
printf("Not on page %ld < %ld\n",(long)artpos,(long)innersearch)
FLUSH;
#endif
return TRUE;
}
if (artpos == innersearch) { /* just got onto page? */
isrchline = artline; /* remember first line after */
highlight = artline - 1;
#ifdef DEBUGGING
if (debug & DEB_INNERSRCH)
printf("There it is %ld = %ld, %d @ %d\n",(long)artpos,
(long)innersearch,hide_everything,highlight) FLUSH;
#endif
if (hide_everything) { /* forced refresh? */
topline = highlight - gline;
if (topline < -1)
topline = -1;
return FALSE; /* let refresh do it all */
}
}
#ifdef DEBUGGING
if (debug & DEB_INNERSRCH)
printf("Not far enough? %d <? %d + %d\n",artline,isrchline,gline)
FLUSH;
#endif
if (artline < isrchline + gline) {
return TRUE;
}
return FALSE;
}
#endif
!STUFFY!FUNK!
echo Extracting search.c
cat >search.c <<'!STUFFY!FUNK!'
/* $Header: search.c,v 4.3 85/05/01 11:50:16 lwall Exp $
*
* $Log: search.c,v $
* Revision 4.3 85/05/01 11:50:16 lwall
* Baseline for release with 4.3bsd.
*
*/
/* string search routines */
/* Copyright (c) 1981,1980 James Gosling */
/* Modified Aug. 12, 1981 by Tom London to include regular expressions
as in ed. RE stuff hacked over by jag to correct a few major problems,
mainly dealing with searching within the buffer rather than copying
each line to a separate array. Newlines can now appear in RE's */
/* Ripped to shreds and glued back together to make a search package,
* July 6, 1984, by Larry Wall. (If it doesn't work, it's probably my fault.)
* Changes include:
* Buffer, window, and mlisp stuff gone.
* Translation tables reduced to 1 table.
* Expression buffer is now dynamically allocated.
* Character classes now implemented with a bitmap.
*/
#include "EXTERN.h"
#include "common.h"
#include "util.h"
#include "INTERN.h"
#include "search.h"
#ifndef BITSPERBYTE
#define BITSPERBYTE 8
#endif
#define BMAPSIZ (127 / BITSPERBYTE + 1)
/* meta characters in the "compiled" form of a regular expression */
#define CBRA 2 /* \( -- begin bracket */
#define CCHR 4 /* a vanilla character */
#define CDOT 6 /* . -- match anything except a newline */
#define CCL 8 /* [...] -- character class */
#define NCCL 10 /* [^...] -- negated character class */
#define CDOL 12 /* $ -- matches the end of a line */
#define CEND 14 /* The end of the pattern */
#define CKET 16 /* \) -- close bracket */
#define CBACK 18 /* \N -- backreference to the Nth bracketed
string */
#define CIRC 20 /* ^ matches the beginning of a line */
#define WORD 32 /* matches word character \w */
#define NWORD 34 /* matches non-word characer \W */
#define WBOUND 36 /* matches word boundary \b */
#define NWBOUND 38 /* matches non-(word boundary) \B */
#define STAR 01 /* * -- Kleene star, repeats the previous
REas many times as possible; the value
ORs with the other operator types */
#define ASCSIZ 0200
typedef char TRANSTABLE[ASCSIZ];
static TRANSTABLE trans = {
0000,0001,0002,0003,0004,0005,0006,0007,
0010,0011,0012,0013,0014,0015,0016,0017,
0020,0021,0022,0023,0024,0025,0026,0027,
0030,0031,0032,0033,0034,0035,0036,0037,
0040,0041,0042,0043,0044,0045,0046,0047,
0050,0051,0052,0053,0054,0055,0056,0057,
0060,0061,0062,0063,0064,0065,0066,0067,
0070,0071,0072,0073,0074,0075,0076,0077,
0100,0101,0102,0103,0104,0105,0106,0107,
0110,0111,0112,0113,0114,0115,0116,0117,
0120,0121,0122,0123,0124,0125,0126,0127,
0130,0131,0132,0133,0134,0135,0136,0137,
0140,0141,0142,0143,0144,0145,0146,0147,
0150,0151,0152,0153,0154,0155,0156,0157,
0160,0161,0162,0163,0164,0165,0166,0167,
0170,0171,0172,0173,0174,0175,0176,0177,
};
static bool folding = FALSE;
static int err;
static char *FirstCharacter;
void
search_init()
{
#ifdef UNDEF
register int i;
for (i = 0; i < ASCSIZ; i++)
trans[i] = i;
#else
;
#endif
}
void
init_compex(compex)
register COMPEX *compex;
{
/* the following must start off zeroed */
compex->eblen = 0;
compex->brastr = Nullch;
}
void
free_compex(compex)
register COMPEX *compex;
{
if (compex->eblen) {
free(compex->expbuf);
compex->eblen = 0;
}
if (compex->brastr) {
free(compex->brastr);
compex->brastr = Nullch;
}
}
static char *gbr_str = Nullch;
static int gbr_siz = 0;
char *
getbracket(compex,n)
register COMPEX *compex;
int n;
{
int length = compex->braelist[n] - compex->braslist[n];
if (!compex->nbra || n > compex->nbra || !compex->braelist[n] || length<0)
return nullstr;
growstr(&gbr_str, &gbr_siz, length+1);
safecpy(gbr_str, compex->braslist[n], length+1);
return gbr_str;
}
void
case_fold(which)
int which;
{
register int i;
if (which != folding) {
if (which) {
for (i = 'A'; i <= 'Z'; i++)
trans[i] = tolower(i);
}
else {
for (i = 'A'; i <= 'Z'; i++)
trans[i] = i;
}
folding = which;
}
}
/* Compile the given regular expression into a [secret] internal format */
char *
compile (compex, strp, RE, fold)
register COMPEX *compex;
register char *strp;
int RE;
int fold;
{
register int c;
register char *ep;
char *lastep;
char bracket[NBRA],
*bracketp;
char **alt = compex->alternatives;
char *retmes = "Badly formed search string";
case_fold(compex->do_folding = fold);
if (!compex->eblen) {
compex->expbuf = safemalloc(84);
compex->eblen = 80;
}
ep = compex->expbuf; /* point at expression buffer */
*alt++ = ep; /* first alternative starts here */
bracketp = bracket; /* first bracket goes here */
if (*strp == 0) { /* nothing to compile? */
if (*ep == 0) /* nothing there yet? */
return "Null search string";
return Nullch; /* just keep old expression */
}
compex->nbra = 0; /* no brackets yet */
lastep = 0;
for (;;) {
if (ep - compex->expbuf >= compex->eblen)
grow_eb(compex);
c = *strp++; /* fetch next char of pattern */
if (c == 0) { /* end of pattern? */
if (bracketp != bracket) { /* balanced brackets? */
#ifdef VERBOSE
retmes = "Unbalanced parens";
#endif
goto cerror;
}
*ep++ = CEND; /* terminate expression */
*alt++ = 0; /* terminal alternative list */
/*
compex->eblen = ep - compex->expbuf + 1;
compex->expbuf = saferealloc(compex->expbuf,compex->eblen+4); */
return Nullch; /* return success */
}
if (c != '*')
lastep = ep;
if (!RE) { /* just a normal search string? */
*ep++ = CCHR; /* everything is a normal char */
*ep++ = c;
}
else /* it is a regular expression */
switch (c) {
case '\\': /* meta something */
switch (c = *strp++) {
case '(':
if (compex->nbra >= NBRA) {
#ifdef VERBOSE
retmes = "Too many parens";
#endif
goto cerror;
}
*bracketp++ = ++compex->nbra;
*ep++ = CBRA;
*ep++ = compex->nbra;
break;
case '|':
if (bracketp>bracket) {
#ifdef VERBOSE
retmes = "No \\| in parens"; /* Alas! */
#endif
goto cerror;
}
*ep++ = CEND;
*alt++ = ep;
break;
case ')':
if (bracketp <= bracket) {
#ifdef VERBOSE
retmes = "Unmatched right paren";
#endif
goto cerror;
}
*ep++ = CKET;
*ep++ = *--bracketp;
break;
case 'w':
*ep++ = WORD;
break;
case 'W':
*ep++ = NWORD;
break;
case 'b':
*ep++ = WBOUND;
break;
case 'B':
*ep++ = NWBOUND;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
*ep++ = CBACK;
*ep++ = c - '0';
break;
default:
*ep++ = CCHR;
if (c == '\0')
goto cerror;
*ep++ = c;
break;
}
break;
case '.':
*ep++ = CDOT;
continue;
case '*':
if (lastep == 0 || *lastep == CBRA || *lastep == CKET
|| *lastep == CIRC
|| (*lastep&STAR)|| *lastep>NWORD)
goto defchar;
*lastep |= STAR;
continue;
case '^':
if (ep != compex->expbuf && ep[-1] != CEND)
goto defchar;
*ep++ = CIRC;
continue;
case '$':
if (*strp != 0 && (*strp != '\\' || strp[1] != '|'))
goto defchar;
*ep++ = CDOL;
continue;
case '[': { /* character class */
register int i;
if (ep - compex->expbuf >= compex->eblen - BMAPSIZ)
grow_eb(compex); /* reserve bitmap */
for (i = BMAPSIZ; i; --i)
ep[i] = 0;
if ((c = *strp++) == '^') {
c = *strp++;
*ep++ = NCCL; /* negated */
}
else
*ep++ = CCL; /* normal */
i = 0; /* remember oldchar */
do {
if (c == '\0') {
#ifdef VERBOSE
retmes = "Missing ]";
#endif
goto cerror;
}
if (*strp == '-' && *(++strp))
i = *strp++;
else
i = c;
while (c <= i) {
ep[c / BITSPERBYTE] |= 1 << (c % BITSPERBYTE);
if (fold && isalpha(c))
ep[(c ^ 32) / BITSPERBYTE] |=
1 << ((c ^ 32) % BITSPERBYTE);
/* set the other bit too */
c++;
}
} while ((c = *strp++) != ']');
ep += BMAPSIZ;
continue;
}
defchar:
default:
*ep++ = CCHR;
*ep++ = c;
}
}
cerror:
compex->expbuf[0] = 0;
compex->nbra = 0;
return retmes;
}
void
grow_eb(compex)
register COMPEX *compex;
{
compex->eblen += 80;
compex->expbuf = saferealloc(compex->expbuf, (MEM_SIZE)compex->eblen + 4);
}
char *
execute (compex, addr)
register COMPEX *compex;
char *addr;
{
register char *p1 = addr;
register char *trt = trans;
register int c;
if (addr == Nullch)
return Nullch;
if (compex->nbra) { /* any brackets? */
for (c = 0; c <= compex->nbra; c++)
compex->braslist[c] = compex->braelist[c] = Nullch;
if (compex->brastr)
free(compex->brastr);
compex->brastr = savestr(p1); /* in case p1 is not static */
p1 = compex->brastr; /* ! */
}
case_fold(compex->do_folding); /* make sure table is correct */
FirstCharacter = p1; /* for ^ tests */
if (compex->expbuf[0] == CCHR && !compex->alternatives[1]) {
c = trt[compex->expbuf[1]]; /* fast check for first character */
do {
if (trt[*p1] == c && advance (compex, p1, compex->expbuf))
return p1;
p1++;
} while (*p1 && !err);
return Nullch;
}
else { /* regular algorithm */
do {
register char **alt = compex->alternatives;
while (*alt) {
if (advance (compex, p1, *alt++))
return p1;
}
p1++;
} while (*p1 && !err);
return Nullch;
}
}
/* advance the match of the regular expression starting at ep along the
string lp, simulates an NDFSA */
bool
advance (compex, lp, ep)
register COMPEX *compex;
register char *ep;
register char *lp;
{
register char *curlp;
register char *trt = trans;
register int i;
while ((*ep & STAR) || *lp || *ep == CIRC || *ep == CKET)
switch (*ep++) {
case CCHR:
if (trt[*ep++] != trt[*lp]) return FALSE;
lp++;
continue;
case CDOT:
if (*lp == '\n') return FALSE;
lp++;
continue;
case CDOL:
if (!*lp || *lp == '\n')
continue;
return FALSE;
case CIRC:
if (lp == FirstCharacter || lp[-1]=='\n')
continue;
return FALSE;
case WORD:
if (isalnum(*lp)) {
lp++;
continue;
}
return FALSE;
case NWORD:
if (!isalnum(*lp)) {
lp++;
continue;
}
return FALSE;
case WBOUND:
if ((lp == FirstCharacter || !isalnum(lp[-1])) !=
(!*lp || !isalnum(*lp)) )
continue;
return FALSE;
case NWBOUND:
if ((lp == FirstCharacter || !isalnum(lp[-1])) ==
(!*lp || !isalnum(*lp)))
continue;
return FALSE;
case CEND:
return TRUE;
case CCL:
if (cclass (ep, *lp, 1)) {
ep += BMAPSIZ;
lp++;
continue;
}
return FALSE;
case NCCL:
if (cclass (ep, *lp, 0)) {
ep += BMAPSIZ;
lp++;
continue;
}
return FALSE;
case CBRA:
compex->braslist[*ep++] = lp;
continue;
case CKET:
i = *ep++;
compex->braelist[i] = lp;
compex->braelist[0] = lp;
compex->braslist[0] = compex->braslist[i];
continue;
case CBACK:
if (compex->braelist[i = *ep++] == 0) {
fputs("bad braces\n",stdout) FLUSH;
err = TRUE;
return FALSE;
}
if (backref (compex, i, lp)) {
lp += compex->braelist[i] - compex->braslist[i];
continue;
}
return FALSE;
case CBACK | STAR:
if (compex->braelist[i = *ep++] == 0) {
fputs("bad braces\n",stdout) FLUSH;
err = TRUE;
return FALSE;
}
curlp = lp;
while (backref (compex, i, lp)) {
lp += compex->braelist[i] - compex->braslist[i];
}
while (lp >= curlp) {
if (advance (compex, lp, ep))
return TRUE;
lp -= compex->braelist[i] - compex->braslist[i];
}
continue;
case CDOT | STAR:
curlp = lp;
while (*lp++ && lp[-1] != '\n');
goto star;
case WORD | STAR:
curlp = lp;
while (*lp++ && isalnum(lp[-1]));
goto star;
case NWORD | STAR:
curlp = lp;
while (*lp++ && !isalnum(lp[-1]));
goto star;
case CCHR | STAR:
curlp = lp;
while (*lp++ && trt[lp[-1]] == trt[*ep]);
ep++;
goto star;
case CCL | STAR:
case NCCL | STAR:
curlp = lp;
while (*lp++ && cclass (ep, lp[-1], ep[-1] == (CCL | STAR)));
ep += BMAPSIZ;
goto star;
star:
do {
lp--;
if (advance (compex, lp, ep))
return TRUE;
} while (lp > curlp);
return FALSE;
default:
fputs("Badly compiled pattern\n",stdout) FLUSH;
err = TRUE;
return -1;
}
if (*ep == CEND || *ep == CDOL) {
return TRUE;
}
return FALSE;
}
bool
backref (compex, i, lp)
register COMPEX *compex;
register int i;
register char *lp;
{
register char *bp;
bp = compex->braslist[i];
while (*lp && *bp == *lp) {
bp++;
lp++;
if (bp >= compex->braelist[i])
return TRUE;
}
return FALSE;
}
bool
cclass (set, c, af)
register char *set;
register int c;
{
c &= 0177;
#if BITSPERBYTE == 8
if (set[c >> 3] & 1 << (c & 7))
#else
if (set[c / BITSPERBYTE] & 1 << (c % BITSPERBYTE))
#endif
return af;
return !af;
}
!STUFFY!FUNK!
echo Extracting ngstuff.c
cat >ngstuff.c <<'!STUFFY!FUNK!'
/* $Header: ngstuff.c,v 4.3 85/05/01 11:45:03 lwall Exp $
*
* $Log: ngstuff.c,v $
* Revision 4.3 85/05/01 11:45:03 lwall
* Baseline for release with 4.3bsd.
*
*/
#include "EXTERN.h"
#include "common.h"
#include "term.h"
#include "util.h"
#include "ng.h"
#include "bits.h"
#include "intrp.h"
#include "cheat.h"
#include "head.h"
#include "final.h"
#include "sw.h"
#include "INTERN.h"
#include "ngstuff.h"
void
ngstuff_init()
{
;
}
/* do a shell escape */
int
escapade()
{
register char *s;
bool interactive = (buf[1] == FINISHCMD);
bool docd;
char whereiam[256];
if (!finish_command(interactive)) /* get remainder of command */
return -1;
s = buf+1;
docd = *s != '!';
if (!docd) {
s++;
}
else {
getwd(whereiam);
if (chdir(cwd)) {
printf(nocd,cwd) FLUSH;
sig_catcher(0);
}
}
while (*s == ' ') s++;
/* skip leading spaces */
interp(cmd_buf, (sizeof cmd_buf), s);/* interpret any % escapes */
resetty(); /* make sure tty is friendly */
doshell(Nullch,cmd_buf); /* invoke the shell */
noecho(); /* and make terminal */
crmode(); /* unfriendly again */
if (docd) {
if (chdir(whereiam)) {
printf(nocd,whereiam) FLUSH;
sig_catcher(0);
}
}
#ifdef MAILCALL;
mailcount = 0; /* force recheck */
#endif
return 0;
}
/* process & command */
int
switcheroo()
{
if (!finish_command(TRUE)) /* get rest of command */
return -1; /* if rubbed out, try something else */
if (!buf[1])
pr_switches();
#ifdef PUSHBACK
else if (buf[1] == '&') {
if (!buf[2]) {
page_init();
show_macros();
}
else {
char tmpbuf[LBUFLEN];
register char *s;
for (s=buf+2; isspace(*s); s++);
mac_line(s,tmpbuf,(sizeof tmpbuf));
}
}
#endif
else {
bool docd = (instr(buf,"-d") != Nullch);
char whereami[256];
if (docd)
getwd(whereami);
sw_list(buf+1);
if (docd) {
cwd_check();
if (chdir(whereami)) { /* -d does chdirs */
printf(nocd,whereami) FLUSH;
sig_catcher(0);
}
}
}
return 0;
}
/* process range commands */
int
numnum()
{
ART_NUM min, max;
char *cmdlst = Nullch;
register char *s, *c;
ART_NUM oldart = art;
char tmpbuf[LBUFLEN];
bool justone = TRUE; /* assume only one article */
if (!finish_command(TRUE)) /* get rest of command */
return NN_INP;
if (lastart < 1) {
fputs("\nNo articles\n",stdout) FLUSH;
return NN_ASK;
}
#ifdef ARTSRCH
if (srchahead)
srchahead = -1;
#endif
for (s=buf; *s && (isdigit(*s) || index(" ,-.$",*s)); s++)
if (!isdigit(*s))
justone = FALSE;
if (*s) {
cmdlst = savestr(s);
justone = FALSE;
}
else if (!justone)
cmdlst = savestr("m");
*s++ = ',';
*s = '\0';
safecpy(tmpbuf,buf,LBUFLEN);
for (s = tmpbuf; c = index(s,','); s = ++c) {
*c = '\0';
if (*s == '.')
min = oldart;
else
min = atol(s);
if (min<absfirst) { /* make sure it is reasonable */
min = absfirst;
printf("(First article is %ld)\n",(long)absfirst) FLUSH;
pad(just_a_sec/3);
}
if ((s=index(s,'-')) != Nullch) {
s++;
if (*s == '$')
max = lastart;
else if (*s == '.')
max = oldart;
else
max = atol(s);
}
else
max = min;
if (max>lastart) {
max = lastart;
if (min > max)
min = max;
printf("(Last article is %ld)\n",(long)lastart) FLUSH;
pad(just_a_sec/3);
}
if (max < min) {
fputs("\nBad range\n",stdout) FLUSH;
if (cmdlst)
free(cmdlst);
return NN_ASK;
}
if (justone) {
art = min;
return NN_REREAD;
}
check_first(min);
for (art=min; art<=max; art++) {
if (perform(cmdlst,TRUE)) {
#ifdef VERBOSE
IF(verbose)
printf("\n(Interrupted at article %ld)\n",(long)art)
FLUSH;
ELSE
#endif
#ifdef TERSE
printf("\n(Intr at %ld)\n",(long)art) FLUSH;
#endif
if (cmdlst)
free(cmdlst);
return NN_ASK;
}
}
}
art = oldart;
if (cmdlst)
free(cmdlst);
return NN_NORM;
}
int
perform(cmdlst,toplevel)
register char *cmdlst;
int toplevel;
{
register int ch;
if (toplevel) {
printf("%-6ld",art);
fflush(stdout);
}
for (; ch = *cmdlst; cmdlst++) {
if (isspace(ch) || ch == ':')
continue;
if (ch == 'j') {
mark_as_read(art);
#ifdef VERBOSE
IF(verbose)
fputs("\tJunked",stdout);
#endif
}
else if (ch == 'm') {
unmark_as_read(art);
#ifdef VERBOSE
IF(verbose)
fputs("\tMarked unread",stdout);
#endif
}
else if (ch == 'M') {
#ifdef DELAYMARK
delay_unmark(art);
#ifdef VERBOSE
IF(verbose)
fputs("\tWill return",stdout);
#endif
#else
notincl("M");
return -1;
#endif
}
else if (ch == '=') {
printf("\t%s",fetchsubj(art,FALSE,FALSE));
#ifdef VERBOSE
IF(verbose)
;
ELSE
#endif
putchar('\n') FLUSH; /* ghad! */
}
else if (ch == 'C') {
#ifdef ASYNC_PARSE
printf("\t%sancelled",(cancel_article() ? "Not c" : "C"));
#else
notincl("C");
return -1;
#endif
}
else if (ch == '%') {
#ifdef ASYNC_PARSE
char tmpbuf[512];
cmdlst = dointerp(tmpbuf, (sizeof tmpbuf), cmdlst,":");
if (*cmdlst != ':')
--cmdlst;
if (perform(tmpbuf,FALSE))
return -1;
#else
notincl("%");
return -1;
#endif
}
else if (index("!&sSwW|",ch)) {
cmdlst = cpytill(buf,cmdlst,':') - 1;
/* we now have the command in buf */
if (ch == '!') {
escapade();
#ifdef VERBOSE
IF(verbose)
fputs("\tShell escaped",stdout);
#endif
}
else if (ch == '&') {
switcheroo();
#ifdef VERBOSE
IF(verbose)
fputs("\tSwitched",stdout);
#endif
}
else {
putchar('\t');
save_article();
}
}
else {
printf("\t???%s\n",cmdlst);
return -1;
}
#ifdef VERBOSE
fflush(stdout);
#endif
}
if (toplevel) {
#ifdef VERBOSE
IF(verbose)
putchar('\n') FLUSH;
ELSE
#endif
#ifdef TERSE
putchar(' ');
#endif
}
return 0;
}
!STUFFY!FUNK!
echo Extracting makedist
cat >makedist <<'!STUFFY!FUNK!'
#!/bin/sh
# $Header: makedist,v 4.3 85/05/01 11:42:35 lwall Exp $
#
# $Log: makedist,v $
# Revision 4.3 85/05/01 11:42:35 lwall
# Baseline for release with 4.3bsd.
#
rm -f kit*.list
manifake
kitlists
manimake
makekit kit*.list
!STUFFY!FUNK!
echo ""
echo "End of kit 4 (of 9)"
cat /dev/null >kit4isdone
config=true
for iskit in 1 2 3 4 5 6 7 8 9; do
if test -f kit${iskit}isdone; then
echo "You have run kit ${iskit}."
else
echo "You still need to run kit ${iskit}."
config=false
fi
done
case $config in
true)
echo "You have run all your kits. Please read README and then type Configure."
chmod 755 Configure
;;
esac
: I do not append .signature, but someone might mail this.
exit
More information about the Mod.sources
mailing list