Newsgroups: news.software.b Subject: C News patch CR.G This is a patch for the C News Cleanup Release. The distribution files on ftp.cs.toronto.edu and zoo.toronto.edu have been updated to match. See the README.changes diff below for what's been done. start of patch CR.G (suggested archive name: patchCR.G) apply with patch -p0 &2 exit 1 fi ! lock -o LOCK $$ || { echo '*** cannot get the lock file' >&2 ; exit 1 ; } status=1 trap 'unlock LOCK ; trap 0 ; exit $status' 0 1 2 15 *** libdbz/makefile.mastercopy Thu Apr 27 21:08:38 1995 --- libdbz/makefile Thu Apr 27 20:53:37 1995 *************** *** 89,95 **** rmdir xx sed '/> 0/d' $(RHIST) >dbase.used test "`cat dbase.used | wc -l`" -eq "`sed -n '2s/ .*//p' dbase.dir`" ; ! : ./rdbz -v dbase cp $(RHIST) dbase2 ./rdbz -E 1000 -0 -p $(RPSIZE) -t ' ' dbase2 cmp $(RHIST) dbase --- 89,95 ---- rmdir xx sed '/> 0/d' $(RHIST) >dbase.used test "`cat dbase.used | wc -l`" -eq "`sed -n '2s/ .*//p' dbase.dir`" ; ! ./rdbz -v dbase cp $(RHIST) dbase2 ./rdbz -E 1000 -0 -p $(RPSIZE) -t ' ' dbase2 cmp $(RHIST) dbase *** libdbz/dbzmain.c.mastercopy Thu Apr 27 21:08:38 1995 --- libdbz/dbzmain.c Wed Apr 26 22:50:52 1995 *************** *** 28,40 **** char *inname = "(no file)"; /* filename for messages etc. */ long lineno; /* line number for messages etc. */ ! char *basename; char *pagname; ! char *dirname; char *str2dup(); FILE *base; int op = 'b'; /* what to do, default build a new table */ int baseinput = 1; /* is the base file also the input? */ char *from = NULL; /* old table to use for dbzagain() */ --- 28,41 ---- char *inname = "(no file)"; /* filename for messages etc. */ long lineno; /* line number for messages etc. */ ! char *base_name; char *pagname; ! char *dir_name; char *str2dup(); FILE *base; int op = 'b'; /* what to do, default build a new table */ + char *badop = "only one of -a -x -c -m -v can be given"; int baseinput = 1; /* is the base file also the input? */ char *from = NULL; /* old table to use for dbzagain() */ *************** *** 70,79 **** --- 71,83 ---- void dofile(); void runs(); void dosweep(); + void verify(); void mkfiles(); void crfile(); void doline(); void process(); + datum dofetch(); + int dostore(); #ifdef HAVERFCIZE extern char *rfc822ize(); *************** *** 96,126 **** progname = argv[0]; ! while ((c = getopt(argc, argv, "axcmt:l:R0E:SqOiX:Yuf:p:eMUC:T:wd")) != EOF) switch (c) { case 'a': /* append to existing table */ if (op != 'b') ! fail("only one of -a -x -c -m can be given", ""); op = 'a'; baseinput = 0; break; case 'x': /* extract from existing table */ if (op != 'b') ! fail("only one of -a -x -c -m can be given", ""); op = 'x'; baseinput = 0; break; case 'c': /* check existing table */ if (op != 'b') ! fail("only one of -a -x -c -m can be given", ""); op = 'c'; break; case 'm': /* extract missing (complement of -x) */ if (op != 'b') ! fail("only one of -a -x -c -m can be given", ""); op = 'm'; baseinput = 0; break; case 't': /* set field separator */ if (strlen(optarg) > (size_t)1) fail("only one field separator allowed", ""); --- 100,135 ---- progname = argv[0]; ! while ((c = getopt(argc, argv, "axcmvt:l:R0E:SqOiX:Yuf:p:eMUC:T:wd")) != EOF) switch (c) { case 'a': /* append to existing table */ if (op != 'b') ! fail(badop, ""); op = 'a'; baseinput = 0; break; case 'x': /* extract from existing table */ if (op != 'b') ! fail(badop, ""); op = 'x'; baseinput = 0; break; case 'c': /* check existing table */ if (op != 'b') ! fail(badop, ""); op = 'c'; break; case 'm': /* extract missing (complement of -x) */ if (op != 'b') ! fail(badop, ""); op = 'm'; baseinput = 0; break; + case 'v': /* verify that this is a dbz file */ + if (op != 'b') + fail(badop, ""); + op = 'v'; + break; case 't': /* set field separator */ if (strlen(optarg) > (size_t)1) fail("only one field separator allowed", ""); *************** *** 206,225 **** } if (errflg || optind >= argc || (optind+1 < argc && baseinput)) { fprintf(stderr, "usage: %s ", progname); ! fprintf(stderr, "[-a] [-x] [-c] database [file] ...\n"); exit(2); } (void) dbzincore(useincore); (void) dbzwritethrough(dowt); ! basename = argv[optind]; ! pagname = str2dup(basename, ".pag"); ! dirname = str2dup(basename, ".dir"); mkfiles(); optind++; if (baseinput) /* implies no further arguments */ ! process(base, basename); else if (optind >= argc) process(stdin, "stdin"); else --- 215,240 ---- } if (errflg || optind >= argc || (optind+1 < argc && baseinput)) { fprintf(stderr, "usage: %s ", progname); ! fprintf(stderr, "[-{axcmv}] database [file] ...\n"); exit(2); } (void) dbzincore(useincore); (void) dbzwritethrough(dowt); ! base_name = argv[optind]; ! pagname = str2dup(base_name, ".pag"); ! dir_name = str2dup(base_name, ".dir"); ! ! if (op == 'v') { ! verify(dir_name); ! /* NOTREACHED */ ! } ! mkfiles(); optind++; if (baseinput) /* implies no further arguments */ ! process(base, base_name); else if (optind >= argc) process(stdin, "stdin"); else *************** *** 233,239 **** if (doruns) runs(pagname); if (sweep) ! dosweep(basename, pagname); if (printx) printf("%ld\n", xxx); exit(0); --- 248,254 ---- if (doruns) runs(pagname); if (sweep) ! dosweep(base_name, pagname); if (printx) printf("%ld\n", xxx); exit(0); *************** *** 240,245 **** --- 255,284 ---- } /* + - verify - just check whether the .dir file looks right or not + */ + void /* does not return */ + verify(dir) + char *dir; + { + FILE *f; + char buf[4]; + size_t n; + + f = fopen(dir, "r"); + if (f == NULL) + exit(1); + n = fread(buf, sizeof(buf), 1, f); + (void) fclose(f); + + if (n != 1 || memcmp(buf, "dbz ", (size_t)4) != 0) + exit(1); + + exit(0); + /* NOTREACHED */ + } + + /* - dofile - open a file and invoke process() */ void *************** *** 266,294 **** mkfiles() { if (op == 'b' && !dbzint) { ! crfile(dirname); crfile(pagname); } ! base = fopen(basename, (op == 'a') ? "a" : "r"); if (base == NULL) ! fail("cannot open `%s'", basename); if (unopen) ! (void) chmod(basename, 0); if (from != NULL) { ! if (dbzagain(basename, from) < 0) ! fail("dbzagain(`%s'...) failed", basename); } else if (op == 'b' && dbzint) { if (!exact) siz = dbzsize(siz); if (tagsize != 0) tag = dbztagmask(tagsize); ! if (dbzfresh(basename, siz, (int)fs, map, tag) < 0) ! fail("dbzfresh(`%s'...) failed", basename); ! } else if (dbminit(basename) < 0) ! fail("dbminit(`%s') failed", basename); if (unopen) ! (void) chmod(basename, 0600); /* hard to restore original */ } /* --- 305,333 ---- mkfiles() { if (op == 'b' && !dbzint) { ! crfile(dir_name); crfile(pagname); } ! base = fopen(base_name, (op == 'a') ? "a" : "r"); if (base == NULL) ! fail("cannot open `%s'", base_name); if (unopen) ! (void) chmod(base_name, 0); if (from != NULL) { ! if (dbzagain(base_name, from) < 0) ! fail("dbzagain(`%s'...) failed", base_name); } else if (op == 'b' && dbzint) { if (!exact) siz = dbzsize(siz); if (tagsize != 0) tag = dbztagmask(tagsize); ! if (dbzfresh(base_name, siz, (int)fs, map, tag) < 0) ! fail("dbzfresh(`%s'...) failed", base_name); ! } else if (dbminit(base_name) < 0) ! fail("dbminit(`%s') failed", base_name); if (unopen) ! (void) chmod(base_name, 0600); /* hard to restore original */ } /* *************** *** 371,393 **** place = ftell(base); llen = strlen(lp); if (fwrite(lp, 1, llen, base) != llen) ! fail("write error in `%s'", basename); /* FALLTHROUGH */ case 'b': if (omitzero && p != NULL && *(p+1) == '0') return; if (unique) { ! value = (dbzint) ? dbzfetch(key) : fetch(key); if (value.dptr != NULL) fail("`%s' already present", lp); } value.dptr = (char *)&place; value.dsize = (int)sizeof(place); ! if (((dbzint) ? dbzstore(key, value) : store(key, value)) < 0) fail("store failed on `%s'", lp); break; case 'c': ! value = (dbzint) ? dbzfetch(key) : fetch(key); shouldfind = (omitzero && p != NULL && *(p+1) == '0') ? 0 : 1; if (!shouldfind && (value.dptr != NULL || value.dsize != 0)) fail("`%s' found, shouldn't be", lp); --- 410,432 ---- place = ftell(base); llen = strlen(lp); if (fwrite(lp, 1, llen, base) != llen) ! fail("write error in `%s'", base_name); /* FALLTHROUGH */ case 'b': if (omitzero && p != NULL && *(p+1) == '0') return; if (unique) { ! value = dofetch(key); if (value.dptr != NULL) fail("`%s' already present", lp); } value.dptr = (char *)&place; value.dsize = (int)sizeof(place); ! if (dostore(key, value) < 0) fail("store failed on `%s'", lp); break; case 'c': ! value = dofetch(key); shouldfind = (omitzero && p != NULL && *(p+1) == '0') ? 0 : 1; if (!shouldfind && (value.dptr != NULL || value.dsize != 0)) fail("`%s' found, shouldn't be", lp); *************** *** 407,413 **** } break; case 'x': ! value = (dbzint) ? dbzfetch(key) : fetch(key); if (value.dptr != NULL && !quick) { (void) memcpy((char *)&place, value.dptr, sizeof(place)); if (fseek(base, place, SEEK_SET) != 0) --- 446,452 ---- } break; case 'x': ! value = dofetch(key); if (value.dptr != NULL && !quick) { (void) memcpy((char *)&place, value.dptr, sizeof(place)); if (fseek(base, place, SEEK_SET) != 0) *************** *** 419,425 **** fputs(lp, stdout); break; case 'm': ! value = (dbzint) ? dbzfetch(key) : fetch(key); if (value.dptr == NULL) { fputs(keytext, stdout); putchar('\n'); --- 458,464 ---- fputs(lp, stdout); break; case 'm': ! value = dofetch(key); if (value.dptr == NULL) { fputs(keytext, stdout); putchar('\n'); *************** *** 529,532 **** --- 568,598 ---- (void) strcpy(p, s1); (void) strcat(p, s2); return(p); + } + + /* + - dofetch - do a fetch or dbzfetch + */ + datum + dofetch(key) + datum key; + { + if (dbzint) + return(dbzfetch(key)); + else + return(fetch(key)); + } + + /* + - dostore - do a store or dbzstore + */ + int + dostore(key, value) + datum key; + datum value; + { + if (dbzint) + return(dbzstore(key, value)); + else + return(store(key, value)); } *** man/readnews.1cn.mastercopy Thu Apr 27 21:08:39 1995 --- man/readnews.1cn Sun Apr 16 22:31:42 1995 *************** *** 4,23 **** .ds b /usr/libexec/news .\" =()<.ds c @@>()= .ds c /etc/news ! .TH READNEWS 1CN "8 July 1993" .BY "C News" .SH NAME readnews \- read news articles .SH SYNOPSIS .B readnews ! .RB [ -n ! newsgroups] ! .RB [ -d ! commands] ! .RB [ -i ] ! .RB [ -clpC ] ! .RB [ -s [ -+? ! .RI [ group ]]] .SH DESCRIPTION .I Readnews without arguments enters command mode, --- 4,41 ---- .ds b /usr/libexec/news .\" =()<.ds c @@>()= .ds c /etc/news ! .\" ! .\" ! .\" ! .TH READNEWS 1CN "16 April 1995" .BY "C News" .SH NAME readnews \- read news articles .SH SYNOPSIS .B readnews ! [ ! .B \-n ! newsgroups ] ! [ ! .B \-d ! commands ] ! [ ! .B \-i ! ] [ ! .B \-c ! ] [ ! .B \-l ! ] [ ! .B \-p ! ] [ ! .B \-C ! ] [ ! .B \-L ! ] [ ! .BR \-A group ! ] [ ! .BR \-D group ! ] .SH DESCRIPTION .I Readnews without arguments enters command mode, *************** *** 35,70 **** Some useful functions are available which don't use command mode. The flags for these are: .TP ! .B -c Check if there is news, and if so print `You have news.'. .TP ! .B -C Check if there is news, and print the groups and number of articles in each group to be read. .TP ! .B -l List the titles of available news articles. .TP ! .B -p Print all articles on standard output, and update .IR newsrc . .TP ! .B -s Print the newsgroup subscription list. .TP ! .BI -s+ " group" Add .I group to the subscription list. .TP ! .BI -s- " group" ! Subtract .I group from the subscription list. - .TP - .B -s? - List currently active newsgroups. .P The remaining flags mostly determine article selection, and may also appear in the --- 53,85 ---- Some useful functions are available which don't use command mode. The flags for these are: .TP ! .B \-c Check if there is news, and if so print `You have news.'. .TP ! .B \-C Check if there is news, and print the groups and number of articles in each group to be read. .TP ! .B \-l List the titles of available news articles. .TP ! .B \-p Print all articles on standard output, and update .IR newsrc . .TP ! .B \-L Print the newsgroup subscription list. .TP ! .BI \-A group Add .I group to the subscription list. .TP ! .BI \-D group ! Delete .I group from the subscription list. .P The remaining flags mostly determine article selection, and may also appear in the *************** *** 75,102 **** file by entering lines prefixed with the word `options', followed by the options arguments. This is most useful with the ! .B -n flag, specifying the usual groups one wishes to subscribe to. .TP ! \fB-n \fInewsgroups\fR Select all articles belonging to .IR newsgroups . ! .I newsgroups is a comma separated list of newsgroup names. The character `!' may be used to exclude certain groups, and the word `all' can be used to match any group. e.g. `-n all,!net.jokes' .TP ! .B -i Ignore .I .newsrc file. It is not read or updated. This allows selection of articles that have already been read. .TP ! \fB-d \fIcommands\fR Disable the .IR commands . ! .I commands is a string of command characters (see the next section); entering any command beginning with any of them will result in an error message. --- 90,117 ---- file by entering lines prefixed with the word `options', followed by the options arguments. This is most useful with the ! .B \-n flag, specifying the usual groups one wishes to subscribe to. .TP ! \fB\-n \fInewsgroups\fR Select all articles belonging to .IR newsgroups . ! .I Newsgroups is a comma separated list of newsgroup names. The character `!' may be used to exclude certain groups, and the word `all' can be used to match any group. e.g. `-n all,!net.jokes' .TP ! .B \-i Ignore .I .newsrc file. It is not read or updated. This allows selection of articles that have already been read. .TP ! \fB\-d \fIcommands\fR Disable the .IR commands . ! .I Commands is a string of command characters (see the next section); entering any command beginning with any of them will result in an error message. *************** *** 129,135 **** This section details the commands available when .I readnews is in command mode (no ! .B -clpsC arguments). The simplest way of using this mode, is to enter RETURN after every prompt. --- 144,150 ---- This section details the commands available when .I readnews is in command mode (no ! .B \-clpsC arguments). The simplest way of using this mode, is to enter RETURN after every prompt. *************** *** 157,163 **** .B . Print the current article. .TP ! .B - Go back to the previous article. This is a toggle, typing it twice returns you to the original article. .TP --- 172,178 ---- .B . Print the current article. .TP ! .B \- Go back to the previous article. This is a toggle, typing it twice returns you to the original article. .TP *************** *** 203,209 **** The .I .newsrc file will be updated provided the flag ! .B -i was not specified. .TP .B x --- 218,224 ---- The .I .newsrc file will be updated provided the flag ! .B \-i was not specified. .TP .B x *************** *** 309,314 **** --- 324,346 ---- when displaying article bodies. This heads off letter bombs at the price of interfering with use of non-ASCII character sets. + .PP + Cleanup of command-line syntax has eliminated the old + .B \-s + option in favor of + .BR \-L , + .BR \-A , + and + .BR \-D . + This is a change for the better, but an incompatible one. + .PP + The + .B \-A + and + .B \-D + options + have a nasty tendency to dump core; + they should be fixed or deleted. .PP This program is about as simple as they come. Almost any seasoned news user will want something more complex. *** readnews/newsrc.c.mastercopy Thu Apr 27 21:08:40 1995 --- readnews/newsrc.c Sun Apr 16 22:09:06 1995 *************** *** 103,110 **** if (!*cp) return; ! argc = 1; ! argv = (char **) myalloc(sizeof(char *)); argv[argc - 1] = cp; while (*cp && (cp = strpbrk(cp, " \t")) != NULL) { while (*cp == ' ' || *cp == '\t') --- 103,111 ---- if (!*cp) return; ! argc = 2; ! argv = (char **) myalloc(2 * sizeof(char *)); ! argv[0] = "options"; argv[argc - 1] = cp; while (*cp && (cp = strpbrk(cp, " \t")) != NULL) { while (*cp == ' ' || *cp == '\t') *************** *** 116,122 **** argv[argc - 1] = cp; } } ! if (options(argc, argv, false)) error("Bad options: %s line %d: %s", rcname, rclineno, s); free((char *) argv); } --- 117,123 ---- argv[argc - 1] = cp; } } ! if (options(argc, argv, false) < 0) error("Bad options: %s line %d: %s", rcname, rclineno, s); free((char *) argv); } *** readnews/readnews.c.mastercopy Thu Apr 27 21:08:40 1995 --- readnews/readnews.c Sun Apr 16 22:26:21 1995 *************** *** 22,28 **** bool Cflag; /* -C verbose -c */ bool sflag; /* -s print newsgroup subscription list */ bool splus; /* -s+ */ - bool slistall; /* -s? */ bool sminus; /* -s- */ char *sarg; /* arg to -s[+-] */ char *nflag; /* -n newsgroups */ --- 22,27 ---- *************** *** 53,61 **** progname = argv[0]; setbuf(stdout, buf); ! if (options(--argc, ++argv, true)) { (void) fprintf(stderr, ! "Usage: readnews [-n newsgroups] [-i] [-clpC] [-s[-+? [group]]]\n"); exit(1); } now = time(&now); --- 52,60 ---- progname = argv[0]; setbuf(stdout, buf); ! if (options(argc, argv, true) < 0) { (void) fprintf(stderr, ! "Usage: readnews [-n newsgroups] [-i] [-clpCL] [-Agroup] [-Dgroup]\n"); exit(1); } now = time(&now); *************** *** 134,219 **** * process options * can be called from readnewsrc() */ options(argc, argv, cline) int argc; char *argv[]; bool cline; { ! register char c; ! ! /* should use getopt(3)... but the -s syntax can't */ ! while (argc > 0) { ! if (argv[0][0] != '-') ! break; ! while (c = *(++(argv[0]))) { ! switch (c) { ! case 'n': ! if (cline) ! nflag = argv[1], n_on_cline = true; ! else { ! if (!n_on_cline) ! nflag = (nflag? ! catstr2(nflag, NGSEPS, argv[1]): ! newstr(argv[1])); ! rcgrps = (rcgrps? ! catstr2(rcgrps, NGSEPS, argv[1]): ! newstr(argv[1])); ! } ! argc--, argv++; ! break; ! case 'd': ! disable = (disable? ! catstr2(disable, "", argv[1]): ! newstr(argv[1])); ! argc--, argv++; ! break; ! case 'i': ! iflag = true; ! continue; ! case 's': ! sflag = true; ! switch (argv[0][1]) { ! case '\0': ! continue; ! case '+': ! splus = true; ! break; ! case '?': ! slistall = true, ++(argv[0]); ! continue; ! case '-': ! sminus = true; ! break; ! default: ! argc = -1; ! break; ! } ! if (argc > 0) { ! sarg = newstr(argv[1]); ! argc--, argv++; ! } ! break; ! case 'p': ! pflag = true; ! continue; ! case 'l': ! lflag = true; ! continue; ! case 'c': ! cflag = true; ! continue; ! case 'C': ! cflag = Cflag = true; ! continue; ! default: ! argc = -1; ! break; } break; } ! argc--, argv++; ! } ! return argc != 0; } /* --- 133,204 ---- * process options * can be called from readnewsrc() */ + int /* < 0 failure, otherwise success */ options(argc, argv, cline) int argc; char *argv[]; bool cline; { ! int c; ! extern int optind; ! extern char *optarg; ! ! optind = 1; /* reset scan, if necessary */ ! while ((c = getopt(argc, argv, "n:d:iLA:D:plcC")) != EOF) ! switch (c) { ! case 'n': ! if (cline) ! nflag = optarg, n_on_cline = true; ! else { ! if (!n_on_cline) ! nflag = (nflag? ! catstr2(nflag, NGSEPS, optarg): ! newstr(optarg)); ! rcgrps = (rcgrps? ! catstr2(rcgrps, NGSEPS, optarg): ! newstr(optarg)); } break; + case 'd': + disable = (disable? + catstr2(disable, "", optarg): + newstr(optarg)); + break; + case 'i': + iflag = true; + break; + case 'L': + sflag = true; + break; + case 'A': + sflag = true; + splus = true; + sarg = optarg; + break; + case 'D': + sflag = true; + sminus = true; + sarg = optarg; + break; + case 'p': + pflag = true; + break; + case 'l': + lflag = true; + break; + case 'c': + cflag = true; + break; + case 'C': + cflag = Cflag = true; + break; + case '?': + default: + return(-1); + break; } ! ! return(0); } /* *************** *** 228,244 **** register char *tmp, *com; register FILE *f; ! if (slistall) { ! (void) printf("Active newsgroups:\n"); ! (void) fflush(stdout); ! /* possibly vestigial code here, old #ifdefs deleted */ ! f = stdout; ! com = 0; /* for lint */ ! com = com; /* for lint */ ! for (ap = alist; ap; ap = ap->a_next) ! (void) fprintf(f, "%s\n", ap->a_name); ! return false; ! } else if (splus || sminus) { if (strpbrk(sarg, BADGRPCHARS)) { (void) printf("%s: Illegal char in newsgroup.\n", sarg); return false; --- 213,219 ---- register char *tmp, *com; register FILE *f; ! if (splus || sminus) { if (strpbrk(sarg, BADGRPCHARS)) { (void) printf("%s: Illegal char in newsgroup.\n", sarg); return false;