[comp.sources.unix] v19i084: Cnews production release, Part07/19

rsalz@uunet.uu.net (Rich Salz) (06/27/89)

Submitted-by: utzoo!henry
Posting-number: Volume 19, Issue 84
Archive-name: cnews2/part07

: ---CUT HERE---
echo 'contrib/rn.mod/better.way':
sed 's/^X//' >'contrib/rn.mod/better.way' <<'!'
XDate:  9 Jun 1989 1852-EDT (Friday)
XFrom: csri.toronto.edu!moraes
XReceived: by neat.ai.toronto.edu id 11723; Fri, 9 Jun 89 18:52:43 EDT
XReply-To: moraes@csri.toronto.edu
XX-Mailer: Mail User's Shell (6.3 6/25/88)
XTo:	henry@utzoo, geoff@utstat.toronto.edu
XSubject: rn fixes
XCc:	moraes@csri.toronto.edu
XMessage-Id: <89Jun9.185243edt.11723@neat.ai.toronto.edu>
X
XThese are the rn fixes to make it use the new active.times file to
Xstop the startup problems when new newsgroups are created.
X
XIt seems fast, and reliable - also completely backward compatible, as
Xfar as I can tell. Note that a new newsreader will now not be asked
Xabout all the newsgroups - they can pick the ones they want later.
X
X	- moraes
X
X# To unbundle, sh this file
Xecho README.rn 1>&2
Xsed 's/^-//' >README.rn <<'!'
XThe rn.mod file is a set of speedups for rn, which make use of a new file
Xwhich C news can generate, called $NEWSCTL/active.times. This file contains
Xthe creation times of the newsgroups, and solves the problem of rn stat'ing
Xevery newsgroup spool directory to figure out if it is a new newsgroup or
Xnot.
X
XThe changes to addng.c prevent rn stating all ~700 directories under
X-/usr/spool/news every time the active file changes (this is known as "the rn
Xhuddle").  This reduced start up time after touching active from 108 seconds
Xelapsed on a Sun 3 to 5 seconds.
X
XThe theory behind the 700 stats in the newgroup huddle is apparently that if
Xrn stats group/1, and it exists, then group must be a newly-created group.
XWith rapid expiry, group/1 won't be around for long in most groups, causing
Xrn to miss some new groups, and in "valuable" groups with long expiry times,
Xgroup/1 will be around for a very long time, making rn spuriously think that
Xthe old groups are new.
X
XTo get this to work - apply the diffs to rn. You may need some hand patching
X-- our version of rn has been hacked to apply various local fixes and some U
Xof Waterloo fixes. (The base U of Waterloo rn contains two other handy
Xchanges:  a -q which disables the interrogation when the active file
Xchanges, and a third answer during the interrogation: "q" means "I don't
Xcare, just show me some news, right now".)
X
XThe main changes are to addng.c, and init.c, to use the new procedure
Xchecknewgroups() for detecting new groups, instead of the earlier heuristic.
X
XCreate a active.times file from your active file using the act.to.times
Xscript in the C News distribution. (C News 'newgroup' will keep it uptodate)
X
XTry it.
X!
Xecho rn.mod 1>&2
Xsed 's/^-//' >rn.mod <<'!'
X-*** /tmp/,RCSt1a11034	Fri Jun  9 18:36:21 1989
X---- addng.c	Fri Jun  9 18:33:55 1989
X-***************
X-*** 39,44 ****
X---- 39,50 ----
X-  
X-  #ifdef FINDNEWNG
X-  /* generate a list of new newsgroups from active file */
X-+ /*
X-+  * The arguments are redundant - they used to be used in a heuristic to
X-+  * determine new newsgroups. With C News active.times file, this is
X-+  * unnecessary, since we use the faster, more reliable checknewgroups()
X-+  * procedure.
X-+  */
X-  
X-  bool
X-  newlist(munged,checkinlist)
X-***************
X-*** 71,86 ****
X-  		fprintf(tmpfp,"%s\n",buf);
X-  					/* then remember said newsgroup */
X-  	    }
X-- #ifdef FASTNEW
X-- 	    else {			/* not really a new group */
X-- 		if (!munged) {		/* did we assume not munged? */
X-- 		    fclose(tmpfp);	/* then go back, knowing that */
X-- 		    UNLINK(tmpname);
X-- 		    free(tmpname);
X-- 		    return TRUE;	/* active file was indeed munged */
X-- 		}
X-- 	    }
X-- #endif
X-  	}
X-  #ifdef DEBUGGING
X-  	else
X---- 77,82 ----
X-***************
X-*** 106,127 ****
X-      return FALSE;			/* do not call us again */
X-  }
X-  
X-! /* return creation time of newsgroup */
X-  
X-  long
X-  birthof(ngnam,ngsize)
X-  char *ngnam;
X-  ART_NUM ngsize;
X-  {
X--     long time();
X-- 
X--     /*
X--      * This used to try and stat article 1 to find the newsgroup creating
X--      * time. Almost never finds article 1, since it will always long gone.
X--      * Nuke the stat() and speed up startup immensely.
X--      */
X--     /* not there, assume something good */
X--     return (ngsize ? 0L : time(Null(long *)));
X-  }
X-  
X-  bool
X---- 102,229 ----
X-      return FALSE;			/* do not call us again */
X-  }
X-  
X-! /*
X-!  * gets the group time, from the second field, simultaneously null terminating
X-!  * after the first field in buf.
X-!  */
X-! static long
X-! getgrptime(buf)
X-! char *buf;
X-! {
X-! 	char *s;
X-! 	
X-! 	s = index(buf, ' ');
X-! 	if (s == Nullch || *(s+1) == '\0')
X-! 		return 0L;
X-! 	*s++ = '\0';
X-! 	return(atol(s));
X-! }
X-  
X-+ /*
X-+  * Use the groups file (ACTIVE.times, typically /usr/lib/news/active.times) to
X-+  * see if there are any new newsgroups
X-+  */
X-+ checknewgroups()
X-+ {
X-+     FILE *fp;
X-+     long grptime;
X-+     long ngrptime;
X-+     long pos;
X-+     long npos;
X-+     char *s;
X-+     char *grpfile;
X-+     char tmpbuf[LBUFLEN];
X-+ #define GROUPEXT ".times"
X-+ 
X-+     grpfile = safemalloc(strlen(filexp(ACTIVE)) + sizeof(GROUPEXT));
X-+     strcpy(grpfile, filexp(ACTIVE));
X-+     strcat(grpfile, GROUPEXT);
X-+     
X-+     fp = fopen(grpfile, "r");
X-+     if (fp == (FILE *) NULL) {
X-+ 	printf(cantopen, grpfile) FLUSH;
X-+     	return;
X-+     }
X-+ 
X-+     pos = npos = lastpos;
X-+     grptime = lastgrptime;
X-+     if (lastnewgroup != Nullch)
X-+ 	strcpy(tmpbuf, lastnewgroup);
X-+     /*
X-+      * In the general case, this 'if()' will be false, unless someone has
X-+      * messed up the groups file, or this is the first time this person is
X-+      * reading news
X-+      */
X-+     if (lastnewgroup == Nullch || fseek(fp, lastpos, 0) == -1 ||
X-+         fgets(buf, LBUFLEN, fp) == NULL ||
X-+ 	!strnEQ(buf, lastnewgroup, strlen(lastnewgroup))) {
X-+ 		/* We need to check the file from the start - use time */
X-+ 		if (fseek(fp, 0L, 0) == -1) {
X-+ 			printf(cantseek, grpfile) FLUSH;
X-+ 			fclose(fp);
X-+ 			free(grpfile);
X-+ 			return;
X-+ 		}
X-+ 		pos = npos = 0L;
X-+ 		while (fgets(buf, LBUFLEN, fp) != Nullch) {
X-+ 			buf[strlen(buf)-1] = '\0';
X-+ 			ngrptime = getgrptime(buf);
X-+ 			if (ngrptime > lastgrptime)
X-+ 				break;
X-+ 			if (ngrptime == 0L)
X-+ 				continue;
X-+ 			grptime = ngrptime;
X-+ 			strcpy(tmpbuf, buf);
X-+ 			pos = npos;
X-+ 			npos = ftell(fp);
X-+ 		}
X-+ 		if (fseek(fp, pos, 0) == -1) {
X-+ 			printf(cantseek, grpfile) FLUSH;
X-+ 			fclose(fp);
X-+ 			free(grpfile);
X-+ 			return;
X-+ 		}
X-+ 		npos = pos;
X-+     }
X-+     /*
X-+      * At this point, the file pointer is positioned at the start of the first
X-+      * new group. This is the value of pos. Now start asking about new groups.
X-+      */
X-+     while (fgets(buf, LBUFLEN, fp) != Nullch) {
X-+ 	buf[strlen(buf)-1] = '\0';
X-+ 	ngrptime = getgrptime(buf);
X-+ 	if (ngrptime == 0L)
X-+ 		continue;
X-+ 	grptime = ngrptime;
X-+ 	strcpy(tmpbuf, buf);
X-+ 	pos = npos;
X-+ 	if (grptime > lastgrptime && find_ng(buf) == nextrcline)
X-+ 		/* not in .newsrc and newer that last new newsgroup */
X-+ 		get_ng(buf, TRUE);
X-+ 	npos = ftell(fp);
X-+     }
X-+     lastpos = pos;
X-+     lastgrptime = grptime;
X-+     if (lastnewgroup != Nullch)
X-+     	free(lastnewgroup);
X-+     lastnewgroup = savestr(tmpbuf);
X-+     fclose(fp);
X-+     free(grpfile);
X-+ }
X-+ 
X-+ 	
X-+ 
X-+ /*
X-+  * return creation time of newsgroup - procedure made redundant by C News
X-+  * active.times and checknewgroups()
X-+  */
X-+ 
X-+ /*ARGSUSED*/
X-  long
X-  birthof(ngnam,ngsize)
X-  char *ngnam;
X-  ART_NUM ngsize;
X-  {
X-  }
X-  
X-  bool
X-*** /tmp/,RCSt1a11034	Fri Jun  9 18:36:24 1989
X---- common.h	Fri Jun  9 18:30:10 1989
X-***************
X-*** 1,9 ****
X-! /* $Header: /ai/car/src/rn/RCS/common.h,v 4.6 89/06/09 18:29:44 moraes Exp $
X-   * 
X-   * $Log:	common.h,v $
X--  * Revision 4.6  89/06/09  18:29:44  moraes
X--  * *** empty log message ***
X--  * 
X-   * Revision 4.5  89/06/05  21:59:37  moraes
X-   * enabled -q option permanantly. New speed mods make it unnecessary for
X-   * most people, but some people just want to see general/gradnews/ut.*
X---- 1,6 ----
X-! /* $Header: /ai/car/src/rn/RCS/common.h,v 4.5 89/06/05 21:59:37 moraes Exp $
X-   * 
X-   * $Log:	common.h,v $
X-   * Revision 4.5  89/06/05  21:59:37  moraes
X-   * enabled -q option permanantly. New speed mods make it unnecessary for
X-   * most people, but some people just want to see general/gradnews/ut.*
X-***************
X-*** 292,299 ****
X-  			/* (Note: both VERBOSE and TERSE can be defined; -t
X-  			 * sets terse mode.  One or the other MUST be defined.
X-  			 */
X-- #define QUICK		/* -q option - Don't ask about new newsgroups */
X-- 
X-  #ifndef pdp11
X-  #   define CACHESUBJ	/* cache subject lines in memory */
X-  			/* without this ^N still works but runs really slow */
X---- 289,294 ----
X-*** /tmp/,RCSt1a11034	Fri Jun  9 18:36:25 1989
X---- init.c	Fri Jun  9 18:30:10 1989
X-***************
X-*** 1,4 ****
X-! /* $Header: /ai/car/src/rn/RCS/init.c,v 1.2 88/07/14 18:15:22 ken Exp $
X-   *
X-   * $Log:	init.c,v $
X-   * Revision 1.2  88/07/14  18:15:22  ken
X---- 1,4 ----
X-! /* $Header: init.c,v 1.2 88/07/14 18:15:22 ken Exp $
X-   *
X-   * $Log:	init.c,v $
X-   * Revision 1.2  88/07/14  18:15:22  ken
X-***************
X-*** 166,185 ****
X-  
X-  #ifdef FINDNEWNG
X-      fstat(actfp->_file,&filestat);	/* did active file grow? */
X-- #ifdef QUICK
X-      /* maintain the old active file size, to avoid "new newsgroup" blather */
X-      if (quick)
X-  	filestat.st_size = lastactsiz;
X-- #endif
X-      if (filestat.st_size != lastactsiz) {
X-  	long actsiz = filestat.st_size;	/* remember new size */
X-  	NG_NUM oldnext = nextrcline;	/* remember # lines in newsrc */
X-- #ifdef FASTNEW
X-- 	bool munged = writesoft || !lastactsiz;
X-- 					/* bad soft ptrs -> edited active */
X-- #else
X-- 	bool munged = TRUE;		/* just assume .newsrc munged */
X-- #endif
X-  
X-  #ifdef VERBOSE
X-  	IF(verbose)
X---- 166,177 ----
X-***************
X-*** 190,208 ****
X-  #ifdef TERSE
X-  	    fputs("\nNew newsgroups:\n",stdout) FLUSH;
X-  #endif
X-! #ifdef FASTNEW
X-! 	if (!munged) {			/* maybe just do tail of file? */
X-! 	    fseek(actfp,lastactsiz-1,0);
X-! 	    fgets(buf,LBUFLEN,actfp);
X-! 	    munged = (*buf != '\n');
X-! 	    if (!munged)
X-! 		munged = newlist(munged,FALSE);
X-! 	}
X-! #endif
X-! 	if (munged) {			/* must we scan entire file? */
X-! 	    fseek(actfp,0L,0);		/* rewind active file */
X-! 	    newlist(munged,FALSE);      /* sure hope they use hashing... */
X-! 	}
X-  	lastactsiz = actsiz;		/* remember for .rnlast */
X-  	if (nextrcline != oldnext) {	/* did we add any new groups? */
X-  	    foundany = TRUE;		/* let main() know */
X---- 182,188 ----
X-  #ifdef TERSE
X-  	    fputs("\nNew newsgroups:\n",stdout) FLUSH;
X-  #endif
X-! 	checknewgroups();
X-  	lastactsiz = actsiz;		/* remember for .rnlast */
X-  	if (nextrcline != oldnext) {	/* did we add any new groups? */
X-  	    foundany = TRUE;		/* let main() know */
X-*** /tmp/,RCSt1a11034	Fri Jun  9 18:36:26 1989
X---- last.c	Fri Jun  9 17:06:01 1989
X-***************
X-*** 1,9 ****
X-! /* $Header: /ai/car/src/rn/RCS/last.c,v 1.1 89/06/09 03:52:49 moraes Exp $
X-   *
X-   * $Log:	last.c,v $
X--  * Revision 1.1  89/06/09  03:52:49  moraes
X--  * Initial revision
X--  * 
X-   * Revision 4.3  85/05/01  11:42:16  lwall
X-   * Baseline for release with 4.3bsd.
X-   * 
X---- 1,6 ----
X-! /* $Header: last.c,v 4.3 85/05/01 11:42:16 lwall Exp $
X-   *
X-   * $Log:	last.c,v $
X-   * Revision 4.3  85/05/01  11:42:16  lwall
X-   * Baseline for release with 4.3bsd.
X-   * 
X-***************
X-*** 26,37 ****
X-      lastname = savestr(filexp(LASTNAME));
X-      if ((tmpfp = fopen(lastname,"r")) != Nullfp) {
X-  	fgets(tcbuf,1024,tmpfp);
X-! 	tcbuf[strlen(tcbuf)-1] = '\0';
X-  	lastngname = savestr(tcbuf);
X-  	fgets(tcbuf,1024,tmpfp);
X-  	lasttime = atol(tcbuf);
X-  	fgets(tcbuf,1024,tmpfp);
X-  	lastactsiz = atol(tcbuf);
X-  	fclose(tmpfp);
X-      }
X-      else {
X---- 23,52 ----
X-      lastname = savestr(filexp(LASTNAME));
X-      if ((tmpfp = fopen(lastname,"r")) != Nullfp) {
X-  	fgets(tcbuf,1024,tmpfp);
X-! 	tcbuf[strlen(tcbuf) - 1] = '\0';
X-  	lastngname = savestr(tcbuf);
X-  	fgets(tcbuf,1024,tmpfp);
X-  	lasttime = atol(tcbuf);
X-  	fgets(tcbuf,1024,tmpfp);
X-  	lastactsiz = atol(tcbuf);
X-+ 	/*
X-+ 	 * The first time when new rn is used by a user who was using the old
X-+ 	 * rn, the lastgrptime is taken to be 'now', so the user is not
X-+ 	 * hassled with hundreds of newsgroups
X-+ 	 */
X-+ 	if (fgets(tcbuf, 1024,tmpfp) != (char *) NULL)
X-+ 		lastgrptime = atol(tcbuf);
X-+ 	else 
X-+ 		lastgrptime = time(0);
X-+ 	if (fgets(tcbuf, 1024, tmpfp) != (char *) NULL) {
X-+ 		tcbuf[strlen(tcbuf) - 1] = '\0';
X-+ 		lastnewgroup = savestr(tcbuf);
X-+ 	} else
X-+ 		lastnewgroup = NULL;
X-+ 	if (fgets(tcbuf, 1024, tmpfp) != (char *) NULL)
X-+ 		lastpos = atol(tcbuf);
X-+ 	else
X-+ 		lastpos = 0;
X-  	fclose(tmpfp);
X-      }
X-      else {
X-***************
X-*** 38,43 ****
X---- 53,67 ----
X-  	lastngname = nullstr;
X-  	lasttime = 0;
X-  	lastactsiz = 0;
X-+ 	/*
X-+ 	 * The default for the new reader is not to show hundreds of new
X-+ 	 * newsgroups. The system admin should use newsetup to provide a
X-+ 	 * proper starting subset - the user can select new newsgroups by
X-+ 	 * hand. Much faster
X-+ 	 */
X-+ 	lastgrptime = time(0);
X-+ 	lastnewgroup = Nullch;
X-+ 	lastpos = 0;
X-      }
X-  }
X-  
X-***************
X-*** 47,54 ****
X-  writelast()
X-  {
X-      if ((tmpfp = fopen(lastname,"w")) != Nullfp) {
X-! 	fprintf(tmpfp,"%s\n%ld\n%ld\n",
X-! 	    (ngname==Nullch?nullstr:ngname),(long)lasttime,(long)lastactsiz);
X-  	fclose(tmpfp);
X-      }
X-      else
X---- 71,81 ----
X-  writelast()
X-  {
X-      if ((tmpfp = fopen(lastname,"w")) != Nullfp) {
X-! 	fprintf(tmpfp,"%s\n%ld\n%ld\n%ld\n%s\n%ld\n",
X-! 	    (ngname==Nullch?nullstr:ngname),(long)lasttime,(long)lastactsiz,
X-! 	    lastgrptime, 
X-! 	    ((lastnewgroup == (char *) NULL) ? nullstr:lastnewgroup),
X-! 	    lastpos);
X-  	fclose(tmpfp);
X-      }
X-      else
X-*** /tmp/,RCSt1a11034	Fri Jun  9 18:36:27 1989
X---- last.h	Fri Jun  9 05:32:16 1989
X-***************
X-*** 12,17 ****
X---- 12,20 ----
X-  EXT char *lastngname INIT(Nullch);	/* last newsgroup read, from .rnlast file */
X-  EXT long lasttime INIT(0);	/* time last rn was started up */
X-  EXT long lastactsiz INIT(0);	/* size of active file when rn last started up */
X-+ EXT long lastgrptime INIT(0);	/* time the groups file was last changed */
X-+ EXT char *lastnewgroup INIT(Nullch);	/* last new newsgroup */
X-+ EXT long lastpos INIT(0);	/* pos. of last new newsgroup in groups file */
X-  
X-  void	last_init();
X-  void    writelast();
XNo differences encountered
X!
X
X
!
echo 'expire/Makefile':
sed 's/^X//' >'expire/Makefile' <<'!'
XPROF = 
XCOPTS = -O
XCFLAGS = $(COPTS) -I../include $(PROF)
XLINTFLAGS = -I../include
XJUNKLINT = 'possible pointer align'
XLDFLAGS = $(CFLAGS)
XDBM = -ldbm
XLIBS= ../libcnews.a
XTHEM = expire histdups histinfo histslash mkdbm mkhistory \
X	superkludge upact doexpire mkadir
XDTR = README Makefile dircheck doexpire expire.c histdups histinfo.c \
X	histslash.c lowest.c mkdbm.c mkhistory pgood superkludge tgood upact \
X	mkadir
X# =()<NEWSARTS = @<NEWSARTS>@>()=
XNEWSARTS = /usr/spool/news
X# =()<NEWSBIN = @<NEWSBIN>@>()=
XNEWSBIN = /usr/lib/newsbin
X# =()<NEWSCTL = @<NEWSCTL>@>()=
XNEWSCTL = /usr/lib/news
X# workaround for System V make bug
XSHELL = /bin/sh
X
Xall:	$(THEM)
X
Xbininstall:	$(THEM) explist.proto
X	-if test ! -d $(NEWSBIN)/expire ; then mkdir $(NEWSBIN)/expire; fi
X	chmod +x $(THEM)
X	cp $(THEM) $(NEWSBIN)/expire
X
Xnewsinstall:	explist.proto
X	-if test ! -r $(NEWSCTL)/explist ; then cp explist.proto $(NEWSCTL)/explist ; fi
X
Xcmp:	$(THEM)
X	-for f in $(THEM) ; do cmp $$f $(NEWSBIN)/expire/$$f ; done
X
Xexpire: expire.o $(LIBS)
X	$(CC) $(LDFLAGS) expire.o $(LIBS) $(DBM) -o $@
X
Xhistinfo: histinfo.o $(LIBS)
X	$(CC) $(LDFLAGS) histinfo.o $(LIBS) -o $@
X
Xlowest:	lowest.o $(LIBS)
X	$(CC) $(LDFLAGS) lowest.o $(LIBS) -o $@
X
Xhistslash:	histslash.o $(LIBS)
X	$(CC) $(LDFLAGS) histslash.o $(LIBS) -o $@
X
Xmkdbm:	mkdbm.o $(LIBS)
X	$(CC) $(LDFLAGS) mkdbm.o $(LIBS) $(DBM) -o $@
X
Xlint:	expire.c
X	lint -ha $(LINTFLAGS) expire.c 2>&1 | egrep -v $(JUNKLINT) | tee $@
X
Xexplist.proto:
X	echo "# hold onto history lines 14 days, nobody gets >90 days" >$@
X	echo "/expired/			x	14	-" >>$@
X	echo "/bounds/			x	0-1-90	-" >>$@
X	echo >>$@
X	echo "# override later defaults for some groups of note" >>$@
X	echo "sci.space.shuttle,rec.birds	x	7	@" >>$@
X	echo >>$@
X	echo "# big non-tech groups held long enough for a long weekend" >>$@
X	echo "sci,rec,talk,soc,misc,alt	u	4	-" >>$@
X	echo >>$@
X	echo "# real noise gets thrown away fast" >>$@
X	echo "news.groups			x	2	-" >>$@
X	echo "junk,tor.news.stats		x	2	-" >>$@
X	echo >>$@
X	echo "# throw away some technical stuff not worth archiving" >>$@
X	echo "comp.os.vms,comp.mail.maps	x	7	-" >>$@
X	echo >>$@
X	echo "# default:  7 days and archive" >>$@
X	echo "all				x	7	@" >>$@
X
X# setup for regression test
Xsetup:
X	rm -f explist history active active.after history.proto
X	rm -rf arts arch arch2 arch3 nbin
X	>history.pag
X	>history.dir
X	echo "/expired/	x	0.08	-" >>explist
X	echo '/bounds/	x	0.01-0.1-0.11	-' >>explist
X	echo "bar,!bar.ugh	x	0.05	`pwd`/arch2" >>explist
X	echo 'mod	m	0.1	@' >>explist
X	echo 'mod	u	0.05	-' >>explist
X	echo 'urp	x	0.01-0.05-0.1	-' >>explist
X	echo "bletch	x	0.1	=`pwd`/arch3/bletch" >>explist
X	echo 'all	x	0.1	@' >>explist
X	mkdir nbin nbin/expire
X	for f in $(THEM) ; do ln $$f nbin/expire/$$f ; done
X	echo 'ln $$* >/dev/null 2>/dev/null' >nbin/newslock
X	echo 'echo 10' >nbin/spacefor
X	chmod +x nbin/* nbin/expire/*
X	mkdir arts arts/foo arts/bar arts/bar/ugh arts/urp arch arch2
X	mkdir arts/mod arts/mod/mod arts/mod/unmod arch3 arch3/bletch
X	mkdir arts/bletch
X	echo 'foo 00099 00000 y' >>active
X	echo 'foo 00099 00001 y' >>active.after
X	echo 'bar 00099 00000 m' >>active
X	echo 'bar 00099 00099 m' >>active.after
X	echo 'bar.ugh 00099 00000 m' >>active
X	echo 'bar.ugh 00099 00099 m' >>active.after
X	echo 'urp 00099 00000 n' >>active
X	echo 'urp 00099 00007 n' >>active.after
X	echo 'mod.mod 00013 00000 m' >>active
X	echo 'mod.mod 00013 00013 m' >>active.after
X	echo 'mod.unmod 00016 00000 y' >>active
X	echo 'mod.unmod 00016 00016 y' >>active.after
X	echo 'bletch 00099 00000 y' >>active
X	echo 'bletch 00099 00099 y' >>active.after
X	echo '<wont1>	9999~-	foo/1' >>history.proto
X	echo :foo/1: >arts/foo/1
X	echo 'Message-ID: <wont1>' >>arts/foo/1
X	echo '<will2>	1000~-	foo/2' >>history.proto
X	echo foo/2 >arts/foo/2
X	echo '<will3>	1000~100	foo/3' >>history.proto
X	echo foo/3 >arts/foo/3
X	echo '<two4>	100	bar/4' >>history.proto
X	echo :bar/4: >arts/bar/4
X	echo 'Subject: yes' >>arts/bar/4
X	echo '<will5>	100~	bar.ugh/5' >>history.proto
X	echo :bar/ugh/5: >arts/bar/ugh/5
X	echo >>arts/bar/ugh/5
X	echo 'Subject: no' >>arts/bar/ugh/5
X	echo '<gone6>	100~-	urp/6' >>history.proto
X	echo urp/6 >arts/urp/6
X	echo '<wont7>	9999~9999~xx~a	urp/7' >>history.proto
X	echo :urp/7: >arts/urp/7
X	echo 'Message-ID: <wont7>' >>arts/urp/7
X	echo 'Expires: 9999' >>arts/urp/7
X	echo '<gone8>	100~20000	urp/8' >>history.proto
X	echo urp/8 >arts/urp/8
X	echo '<gone9>	100~-	urp/9' >>history.proto
X	echo '<wont10>	1000~20000	foo/10' >>history.proto
X	echo :foo/10: >arts/foo/10
X	echo 'Message-ID: <wont10>' >>arts/foo/10
X	echo 'Expires: 20000' >>arts/foo/10
X	echo 'Supersedes: <wont1>' >>arts/foo/10
X	echo >>arts/foo/10
X	echo '<will11>	100~20000	foo/11' >>history.proto
X	echo foo/11 >arts/foo/11
X	echo '<will12>	100~-	mod.mod/12' >>history.proto
X	echo mod/mod/12 >arts/mod/mod/12
X	echo '<wont13>	2000	mod.mod/13' >>history.proto
X	echo :mod/mod/13: >arts/mod/mod/13
X	echo 'Message-ID: <wont13>' >>arts/mod/mod/13
X	echo '<gone14>	100~-	mod.unmod/14' >>history.proto
X	echo mod/unmod/14 >arts/mod/unmod/14
X	echo '<gone15>	2000	mod.unmod/15' >>history.proto
X	echo mod/unmod/15 >arts/mod/unmod/15
X	echo '<wont16>	9999~-	mod.unmod/16' >>history.proto
X	echo :mod/unmod/16: >arts/mod/unmod/16
X	echo 'Message-ID: <wont16>' >>arts/mod/unmod/16
X	echo '<three17>	100~-	bletch/17' >>history.proto
X	echo bletch/17 >arts/bletch/17
X	egrep wont history.proto >history.after
X	echo '<gone96>	5000~-	/' >>history.proto
X	echo '<gone96>	5000~-' >>history.after
X	echo '<gone97>	5000~-' >>history.proto
X	echo '<gone97>	5000~-' >>history.after
X	echo '<gone98>	5000~-	urp/98' >>history.proto
X	echo '<gone98>	5000~-' >>history.after
X	echo urp/98 >arts/urp/98
X	echo '<multi99>	5000~-	bar/99, bar.ugh/99  foo/99 urp/99' >>history.proto
X	echo '<multi99>	5000~-	bar.ugh/99 foo/99' >>history.after
X	echo :foo/99:bar/99:bar/ugh/99:urp/99: >arts/foo/99
X	echo 'Message-ID: <multi99>' >>arts/foo/99
X	ln arts/foo/99 arts/bar/99
X	ln arts/foo/99 arts/bar/ugh/99
X	ln arts/foo/99 arts/urp/99
X	cp history.proto history
X
X# regression test machinery
XD = NEWSARTS=`pwd`/arts NEWSCTL=`pwd` NEWSBIN=`pwd`/nbin
XRUN = $(D) ./expire -a `pwd`/arch -n 10000
XFIXMIDFIELD = 's/	[0-9]*~*/	~/;s/~	/~-	/;s/~xx~a//'
XFIXPATHS = "s;`pwd`;P;g"
Xgoodt:	expire setup	# do NOT run this unless you know what you're doing
X	$(RUN) -t explist 2>&1 | sed $(FIXPATHS) >tgood
X	chmod -w tgood
Xgoodp:	expire setup	# do NOT run this unless you know what you're doing
X	$(RUN) -p explist >pgood 2>&1
X	chmod -w pgood
Xdoit:	expire		# for debugging
X	echo "$(RUN) -t explist" >$@
X	chmod +x $@
X
X# the regression test proper
Xr:	$(THEM) dircheck setup tgood pgood
X	chmod +x dircheck $(THEM)
X	$(RUN) -c explist
X	: "okay, it's sane"
X	$(RUN) -t explist >test.out 2>&1
X	sed $(FIXPATHS) test.out | cmp - tgood
X	: "okay, it seems to know what it's doing -- now, can it do it?"
X	$(RUN) -p explist >test.out 2>test.stderr
X	test ! -s test.stderr
X	cmp test.out pgood
X	test ! -f history.n
X	cmp history.proto history.o
X	egrep wont history.proto | ./dircheck arts
X	egrep 'will|two|gone|three' history.proto | ./dircheck -n arts
X	egrep will history.proto | ./dircheck arch
X	egrep 'wont|two|gone|three' history.proto | ./dircheck -n arch
X	egrep two history.proto | ./dircheck arch2
X	egrep 'will|wont|gone|three' history.proto | ./dircheck -n arch2
X	egrep three history.proto | ./dircheck arch3
X	egrep 'will|wont|gone|two' history.proto | ./dircheck -n arch3
X	test -f arts/foo/99
X	test -f arts/bar/ugh/99
X	test -f arch2/bar/99
X	test ! -f arts/urp/99
X	cmp history history.after
X	: "that's it for expire, on to upact"
X	$(D) ./upact
X	cmp active active.after
X	: "and for upact, on to mkhistory"
X	awk -F'	' 'NF > 2' history | sed $(FIXMIDFIELD) | sort >history.after
X	rm -f history.pag history.dir
X	$(D) ./mkhistory
X	sort history | sed $(FIXMIDFIELD) | cmp - history.after
X	test -r history.pag
X	test -r history.dir
X	: "and that's mkhistory done, finally try superkludge"
X	test -r arts/foo/1
X	test -r arts/foo/10
X	$(D) ./superkludge foo
X	test ! -r arts/foo/1
X	test -r arts/foo/10
X	: "success!"
X
Xtidy:
X	rm -f junk history history.pag history.dir history.o active
X	rm -f history.n* mon.out history.proto history.after test.out doit
X	rm -f active.old active.new explist lint active.after test.stderr
X	rm -rf arts arch arch2 arch3 nbin
X
Xclean:	tidy
X	rm -f *.o expire histslash mkdbm histinfo lowest explist.proto
X	rm -f dtr
X
Xspotless:	clean	# don't run this unless you know what you're doing
X	rm -f pgood tgood
X
Xdtr:	$(DTR)
X	makedtr $(DTR) >$@
!
echo 'expire/README':
sed 's/^X//' >'expire/README' <<'!'
XC News expire
X
XUnlike the old alpha C News expire, this one will accept B News history
Xfiles... although that slows it down, and this hasn't been tested well.
XBeware that the date in the middle field of the history line must be
Xreadable to getdate(3), and rumor hath it that late B 2.11 dates are not.
XTalk about stupid...  We don't care enough to do anything about this.
XRebuilding your history file in C News format is preferable anyway.
X
XIt WON'T accept the old experimental C News four-field history files;
Xwe recommend
X
X	awk -F'	' '{ print $1 "	" $2 "~" $3 "	" $4 }'
X
X(those are tabs in the quotes after the -F and the empty-looking quotes
Xin the awk program) as a conversion aid.
X
X"make r" will compile everything and run a complex set of regression tests,
Xchecking the results automatically.  If nothing screams, there is a high
Xprobability that expire, upact, mkhistory, and superkludge are working.
X
Xdircheck checks the results of expire regression testing.
Xhistdups, histinfo, histslash, and mkdbm are parts of mkhistory.
Xlowest is an optimized version of part of upact -- it's faster, but it's
X	also the only thing in C News that needs to know how to read
X	directories, which is a portability hassle, so it's not the default.
Xpgood and tgood are regression-test output-should-look-like-this files.
Xmkadir is what expire invokes to create archiving subdirectories.
!
echo 'expire/mkadir':
sed 's/^X//' >'expire/mkadir' <<'!'
X#! /bin/sh
X# make directories for expire archiving
X# $1 is overall archive dir, remaining args are successively deeper
X# subdirectories under $1 (e.g. comp comp/lang comp/lang/c) (which may
X# or may not already exist -- expire doesn't know or care).  Note, last
X# argument therefore is slashed newsgroup name.
X
Xcase $# in
X0|1)	echo "Usage: $0 archdir subdir ..." >&2 ; exit 2 ;;
Xesac
X
Xcd $1
Xshift
X
Xfor d
Xdo
X	if test ! -d "$d"
X	then
X		mkdir "$d" >/dev/null 2>/dev/null
X	fi
Xdone
!
echo done


-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.