news 2.10.2 src part 6 (reposting)
Rick Adams
rick at seismo.UUCP
Mon Sep 10 08:10:00 AEST 1984
if test ! -d src
then
mkdir src
echo mkdir src
fi
echo x - src/rfuncs.c
sed 's/^X//' >src/rfuncs.c <<'*-*-END-of-src/rfuncs.c-*-*'
X/*
X * rfuncs - functions for readnews.
X */
X
X#ifndef lint
Xstatic char *SccsId = "@(#)rfuncs.c 2.20 9/3/84";
X#endif !lint
X
X#include "rparams.h"
X
Xlong nngsize; /* The next upcoming value of ngsize. */
Xlong nminartno; /* Smallest article number in this group */
X
Xnextng()
X{
X long curpos;
X#ifdef DEBUG
X fprintf(stderr, "nextng()\n");
X#endif
X curpos = ftell(actfp);
X
Xnext:
X#ifdef DEBUG
X fprintf(stderr, "next:\n");
X#endif
X if (actdirect == BACKWARD) {
X if (back()) {
X fseek(actfp, curpos, 0);
X return 1;
X }
X if (back()) {
X fseek(actfp, curpos, 0);
X return 1;
X }
X }
X if (fgets(afline, BUFLEN, actfp) == NULL)
X return 1;
X if (sscanf(afline, "%s %ld %ld", bfr, &nngsize, &nminartno) < 3) {
X bfr[0] = '\0';
X nngsize = 0;
X nminartno = 0;
X }
X#ifdef DEBUG
X fprintf(stderr, "bfr = '%s'\n", bfr);
X#endif
X
X ngcat(bfr);
X if (!ngmatch(bfr, header.nbuf))
X goto next;
X ngdel(bfr);
X if (xflag)
X readmode = SPEC;
X else
X readmode = NEXT;
X if (selectng(bfr, TRUE))
X goto next;
X return 0;
X}
X
X
Xselectng(name, fastcheck)
Xchar *name;
X{
X register char *ptr, punct = ',';
X register int i;
X register char *p;
X register long cur;
X long next = 0;
X FILE *af;
X long s, sm;
X char buf[100], n[100];
X
X if (*groupdir)
X updaterc();
X last = 1;
X if (strcmp(name, bfr)) {
X af = xfopen(ACTIVE, "r");
X while (fgets(buf, sizeof buf, af) != NULL) {
X if (sscanf(buf, "%s %ld %ld", n, &s, &sm) == 3 &&
X strcmp(n, name) == 0) {
X ngsize = s;
X minartno = sm;
X break;
X }
X }
X fclose(af);
X } else {
X ngsize = nngsize;
X minartno = nminartno;
X }
X#ifdef DEBUG
X fprintf(stderr, "selectng(%s) sets ngsize to %ld, minartno to %ld\n",
X name, ngsize, minartno);
X#endif
X strcpy(groupdir, name);
X if (!xflag) {
X i = findrcline(name);
X if (i >= 0) {
X if (index(rcline[i], '!')) {
X groupdir[0] = 0;
X return 1;
X }
X sprintf(rcbuf, "%s,%ld", rcline[i], ngsize+1);
X }
X else
X sprintf(rcbuf, "ng: %ld", ngsize+1);
X } else
X sprintf(rcbuf, "ng: %ld", ngsize+1);
X#ifdef DEBUG
X fprintf(stderr, "rcbuf set to %s\n", rcbuf);
X#endif DEBUG
X
X /*
X * Fast check for common case: 1-###
X */
X if (fastcheck) {
X p = rcbuf;
X while (*p != ' ')
X p++;
X while (*p == ' ')
X p++;
X if (*p++ == '1' && *p++ == '-') {
X i = 0;
X while (isdigit(*p))
X i = 10 * i + *p++ - '0';
X if (*p == ',' && i >= ngsize) {
X groupdir[0] = 0;
X return 1;
X }
X }
X }
X
X/*
X * The key to understanding this piece of code is that a bit is set iff
X * that article has NOT been read. Thus, we fill in the holes when
X * commas are found (e.g. 1-20,30-35 will result in filling in the 21-29
X * holes), and so we assume the newsrc file is properly ordered, the way
X * we write it out.
X */
X if ((ngsize-minartno) > BITMAPSIZE) {
X sprintf(buf," Bitmap not large enough for newsgroup %s", groupdir);
X xerror(buf);
X }
X
X cur = 0;
X /* Zero out the bitmap */
X p = &bitmap[(ngsize-minartno)/8+1];
X for (ptr = bitmap; ptr <= p;)
X *ptr++ = 0;
X
X /* Decode the .newsrc line indicating what we have read. */
X for (ptr = rcbuf; *ptr && *ptr != ':'; ptr++)
X ;
X while (*ptr) {
X while (!isdigit(*ptr) && *ptr)
X ptr++;
X if (!*ptr)
X break;
X sscanf(ptr, "%ld", &next);
X if (punct == ',') {
X while (++cur < next) {
X set(cur);
X }
X }
X cur = next;
X while (!ispunct(*ptr) && *ptr)
X ptr++;
X punct = *ptr;
X }
X if (rflag)
X bit = ngsize+1;
X else
X bit = minartno -1;
X nextbit();
X ngrp = 1;
X return 0;
X}
X
X#ifdef TMAIL
Xcatchterm()
X{
X unlink(infile);
X unlink(outfile);
X xxit(0);
X}
X
X
X/*
X * The -M (Mail) interface. This code is a reasonably simple model for
X * writing other interfaces. We write out all relavent articles to
X * a temp file, then invoke Mail with an option to have it tell us which
X * articles it read. Finally we count those articles as really read.
X */
XMail()
X{
X register FILE *fp = NULL, *ofp;
X struct hbuf h;
X register char *ptr, *fname;
X int news = 0;
X register int i;
X
X for(i=0;i<NUNREC;i++)
X h.unrec[i] = NULL;
X
X ofp = xfopen(mktemp(outfile), "w");
X if (aflag && *datebuf)
X if ((atime = cgtdate(datebuf)) == -1)
X xerror("Cannot parse date string");
X while (!nextng())
X while (bit <= ngsize) {
X sprintf(filename, "%s/%ld", dirname(groupdir), bit);
X if (access(filename, 4)
X || ((fp = fopen(filename, "r")) == NULL)
X || (hread(&h, fp, TRUE) == NULL)
X || !aselect(&h, FALSE)) {
X#ifdef DEBUG
X fprintf(stderr, "Bad article '%s'\n", filename);
X#endif
X if (fp != NULL) {
X fclose(fp);
X fp = NULL;
X }
X clear(bit);
X nextbit();
X continue;
X }
X fname = ptr = index(h.from, '(');
X if (fname) {
X while (ptr && ptr[-1] == ' ')
X ptr--;
X if (ptr)
X *ptr = 0;
X fname++;
X ptr = fname + strlen(fname) - 1;
X if (*ptr == ')')
X *ptr = 0;
X }
X h.subtime = cgtdate(h.subdate);
X fprintf(ofp, "From %s %s",
X#ifdef INTERNET
X h.from[0] ? h.from :
X#endif
X h.path, ctime(&h.subtime));
X if (fname)
X fprintf(ofp, "Full-Name: %s\n", fname);
X fprintf(ofp, "Newsgroups: %s\n", h.nbuf);
X fprintf(ofp, "Subject: %s\n", h.title);
X fprintf(ofp, "Article-ID: %s/%ld\n\n", groupdir, bit);
X tprint(fp, ofp, TRUE);
X putc('\n', ofp);
X news = TRUE;
X fclose(fp);
X fp = NULL;
X nextbit();
X }
X updaterc();
X fclose(ofp);
X if (!news) {
X fprintf(stderr, "No news.\n");
X unlink(outfile);
X return;
X }
X signal(SIGHUP, catchterm);
X signal(SIGTERM, catchterm);
X sprintf(bfr, "%s -f %s -T %s", TMAIL, outfile, mktemp(infile));
X fwait(fsubr(ushell, bfr, (char *)NULL));
X ofp = xfopen(infile, "r");
X fseek(actfp, 0L, 0);
X while (fgets(afline, BUFLEN, actfp) != NULL) {
X last = 0;
X if (sscanf(afline, "%s %ld", bfr, &nngsize) < 2) {
X bfr[0] = '\0';
X nngsize = 0;
X }
X ngcat(bfr);
X if (!ngmatch(bfr, header.nbuf))
X continue;
X ngdel(bfr);
X *groupdir = 0;
X if (selectng(bfr, TRUE))
X continue;
X fseek(ofp, 0L, 0);
X while (fgets(groupdir, BUFLEN, ofp) != NULL) {
X nstrip(groupdir);
X ptr = index(groupdir, '/');
X *ptr = 0;
X if (strcmp(bfr, groupdir))
X continue;
X sscanf(++ptr, "%ld", &last);
X clear(last);
X }
X if (last) {
X strcpy(groupdir, bfr);
X updaterc();
X }
X }
X unlink(infile);
X unlink(outfile);
X}
X#endif
X
Xupdaterc()
X{
X register long cur = 1, next = 1;
X register int i;
X register char *ptr;
X char oldptr;
X
X sprintf(rcbuf, "%s%c ", groupdir, zapng ? '!' : ':');
X
X zapng = FALSE;
Xagain:
X ptr = &rcbuf[strlen(rcbuf)];
X while (get(next) && next <= ngsize)
X next++;
X cur = next;
X while (!(get(next)) && next <= ngsize)
X next++;
X if (cur == next) {
X next = ngsize + 1;
X goto skip;
X }
X if (cur + 1 == next)
X sprintf(ptr, "%ld,", cur);
X else
X sprintf(ptr, "%ld-%ld,", cur, next - 1);
Xskip:
X if ((long) next > ngsize) {
X if (index(rcbuf, ',') != NULL)
X ngdel(rcbuf);
X else if (index(rcbuf, '!') == NULL)
X return;
X ptr = index(rcbuf, ' ');
X ptr--;
X oldptr = *ptr;
X ptr[0] = ':';
X ptr[1] = '\0';
X i = findrcline(groupdir);
X if (i >= 0) {
X ptr[0] = oldptr;
X ptr[1] = ' ';
X rcline[i] = realloc(rcline[i], (unsigned)(strlen(rcbuf) + 1));
X if (rcline[i] == NULL)
X xerror("Cannot realloc");
X strcpy(rcline[i], rcbuf);
X return;
X }
X if (++line > LINES)
X xerror("Too many newsgroups");
X ptr[0] = oldptr;
X ptr[1] = ' ';
X if ((rcline[line] = malloc((unsigned)(strlen(rcbuf) + 1))) == NULL)
X xerror("Not enough memory");
X strcpy(rcline[line], rcbuf);
X return;
X }
X cur = next;
X goto again;
X}
X
Xnewrc(rcname)
Xchar *rcname;
X{
X register FILE *fp;
X
X if (close(creat(rcname, 0666))) {
X sprintf(bfr, "Cannot create %s", newsrc);
X xerror(bfr);
X }
X
X sprintf(bfr, "%s/users", LIB);
X if ((fp = fopen(bfr, "a")) != NULL) {
X fprintf(fp, "%s\n", username);
X fclose(fp);
X chmod(bfr, 0666);
X }
X}
X
Xnextbit()
X{
X#ifdef DEBUG
X fprintf(stderr,"nextbit() bit = %ld\n", bit);
X#endif DEBUG
X last = bit;
X if (readmode == SPEC || xflag) {
X if (rflag)
X bit--;
X else
X bit++;
X return;
X }
X if (rflag)
X while (--bit, !get(bit) && bit > minartno)
X ;
X else
X while (++bit, !get(bit) && bit <= ngsize)
X ;
X#ifdef DEBUG
X fprintf(stderr,"nextng leaves bit as %ld\n", bit);
X#endif DEBUG
X}
X
Xxxit(status)
Xint status;
X{
X unlink(infile);
X unlink(outfile);
X#ifdef SORTACTIVE
X if (strncmp(ACTIVE,"/tmp/",4) == 0) /* Paranoia */
X unlink(ACTIVE);
X#endif SORTACTIVE
X exit(status);
X}
X
X/*
X * Return TRUE if the user has not ruled out this article.
X */
Xaselect(hp, insist)
Xregister struct hbuf *hp;
Xint insist;
X{
X if (insist)
X return TRUE;
X if (tflag && !titmat(hp, header.title))
X return FALSE;
X if (aflag && cgtdate(hp->recdate) < atime)
X return FALSE;
X if (index(hp->nbuf, ',') && !rightgroup(hp))
X return FALSE;
X if (fflag && isfol(hp))
X return FALSE;
X return TRUE;
X}
X
X/*
X * Code to avoid showing multiple articles for news.
X * Works even if you exit news.
X * Returns nonzero if we should show this article.
X */
Xrightgroup(hp)
Xstruct hbuf *hp;
X{
X char ng[BUFLEN];
X register char *p, *g;
X int i, flag;
X
X strcpy(ng, hp->nbuf);
X ngcat(ng);
X g = ng;
X flag = 1;
X while ((p = index(g, ',')) != NULL) {
X *p++ = '\0';
X while (*p == ' ')
X p++;
X if (strcmp(g, groupdir) == 0)
X return flag;
X if (ngmatch(g, header.nbuf)
X && ((i = findrcline(g)) >= 0
X && index(rcline[i], '!') == NULL))
X flag = 0;
X g = p;
X }
X /* we must be in "junk" or "control" */
X return TRUE;
X}
X
X/*
X * Return TRUE if this article is a followup to something.
X */
Xisfol(hp)
Xregister struct hbuf *hp;
X{
X if (hp->followid[0])
X return TRUE;
X if (strncmp(hp->title, "Re:", 3) == 0)
X return TRUE;
X return FALSE;
X}
X
Xback()
X{
X while (fseek(actfp, -2L, 1) != -1 && ftell(actfp) > 0L) {
X if (getc(actfp) == '\n')
X return 0;
X }
X if (ftell(actfp) == 0L)
X return 0;
X return 1;
X}
X
X/*
X * Trap interrupts.
X */
Xonsig(n)
Xint n;
X{
X signal(n, onsig);
X sigtrap = n;
X if (rcreadok < 2) {
X fprintf(stderr, "Aborted early\n");
X xxit(0);
X }
X}
X
X/*
X * finds the line in your .newsrc file (actually the in-core "rcline"
X * copy of it) and returns the index into the array where it was found.
X * -1 means it didn't find it.
X *
X * We play clever games here to make this faster. It's inherently
X * quadratic - we spend lots of CPU time here because we search through
X * the whole .newsrc for each line. The "prev" variable remembers where
X * the last match was found; we start the search there and loop around
X * to the beginning, in the hopes that the calls will be roughly in order.
X */
Xint
Xfindrcline(name)
Xchar *name;
X{
X register char *p, *ptr;
X register int cur;
X register int i;
X register int top;
X static int prev = 0;
X
X top = line; i = prev;
Xloop:
X for (; i <= top; i++) {
X for (p = name, ptr = rcline[i]; (cur = *p++); ) {
X if (cur != *ptr++)
X goto contin2;
X }
X if (*ptr != ':' && *ptr != '!')
X continue;
X prev = i;
X return i;
Xcontin2:
X ;
X }
X if (i > line && line > prev-1) {
X i = 0;
X top = prev-1;
X goto loop;
X }
X return -1;
X}
X
X#ifdef SORTACTIVE
X/*
X * sortactive - make a local copy of the active file, sorted according
X * to the user's preferences, according to his .newsrc file.
X * Marvin Solomon, University of Wisconsin, 1/2/84
X */
X
Xstruct table_elt {
X long actpos, rcpos;
X};
X
Xstatic int
Xrcsort(a,b)
Xstruct table_elt *a, *b;
X{
X return(a->rcpos - b->rcpos);
X}
X
Xsortactive()
X{
X char newactivename[BUFLEN], aline[BUFLEN], *strcpy(), *p;
X register FILE *nfp, *afp;
X struct table_elt table[LINES];
X int nlines = 0, i;
X long actpos;
X
X /* make a new sorted copy of ACTIVE in the user's home directory */
X strcpy(newactivename, mktemp("/tmp/newsaXXXXXX"));
X nfp = fopen(newactivename, "w");
X if (nfp == NULL) {
X perror(newactivename);
X return;
X }
X
X /* look up all the lines in ACTIVE, finding their positions in .newsrc */
X afp = xfopen(ACTIVE, "r");
X actpos = ftell(afp);
X while (fgets(aline, sizeof aline, afp) != NULL) {
X if (p = index(aline, ' '))
X *p = '\0';
X table[nlines].rcpos = findrcline(aline);
X table[nlines].actpos = actpos;
X nlines++;
X actpos = ftell(afp);
X }
X
X /* sort by position in user's .newsrc file (new groups come up first) */
X qsort((char *)table, nlines, sizeof table[0], rcsort);
X
X /* copy active to newactive, in the new order */
X for (i=0; i<nlines; i++) {
X (void) fseek(afp, table[i].actpos, 0);
X (void) fgets(aline, sizeof aline, afp);
X (void) fprintf(nfp, "%s", aline);
X }
X (void) fclose(afp);
X (void) fclose(nfp);
X
X /* make the rest of readnews think the local active file is the real one */
X free(ACTIVE);
X ACTIVE = AllocCpy(newactivename);
X}
X#endif SORTACTIVE
*-*-END-of-src/rfuncs.c-*-*
echo x - src/rfuncs2.c
sed 's/^X//' >src/rfuncs2.c <<'*-*-END-of-src/rfuncs2.c-*-*'
X/*
X * rfuncs2 - more routines needed by readr.
X */
X
X#ifndef lint
Xstatic char *SccsId = "@(#)rfuncs2.c 1.17 9/3/84";
X#endif !lint
X
X#include "rparams.h"
X
Xstatic char lbuf[BUFLEN*2];
X
XFILE *popen();
X
X/*
X * Match title.
X */
Xtitmat(h, titlist)
Xregister struct hbuf *h;
Xregister char *titlist;
X{
X register char *p;
X
X while (*titlist != '\0') {
X
X for (p = h->title; *p != '\0'; p++)
X if (prefix(p, titlist)) {
X return(TRUE);
X }
X while (*titlist++ != '\0')
X ;
X }
X return(FALSE);
X}
X
X
X/*
X * Save the news item in the user's file.
X * Fri Mar 12 20:04:43 EST 1982: (ittvax!swatt)
X * Allow files with first character as '|' to write article
X * to program across a pipe.
X */
X
X#define PIPECHAR '|'
X
Xsave(file, to)
Xregister char *file, *to;
X{
X register FILE *ufp, *hfp;
X struct hbuf hh;
X int isprogram = 0;
X int isnew = 1;
X register int i;
X
X for(i=0;i<NUNREC;i++)
X hh.unrec[i] = NULL;
X
X if ((hfp = fopen(file, "r")) == NULL) {
X fprintf(stderr, "Can't get article.\n");
X return;
X }
X if (hread(&hh, hfp, TRUE) == NULL) {
X fprintf(stderr, "Article is garbled.\n");
X return;
X }
X ufp = fopen(to, "r");
X if (ufp != NULL) {
X fclose(ufp);
X isnew = 0;
X }
X setgid(gid);
X setuid(uid);
X umask(savmask);
X
X if (*to == PIPECHAR) {
X if ((ufp = popen (&to[1], "w")) == NULL) {
X fprintf(stderr,"Cannot execute %s\n", &to[1]);
X return;
X }
X isprogram++;
X } else if ((ufp = fopen(to, "a")) == NULL) {
X fprintf(stderr,"Cannot append to %s.\n", to);
X return;
X }
X /*
X * V7MAIL code is here to conform to V7 mail format.
X * If you need a different format to be able to
X * use your local mail command (such as four ^A's
X * on the end of articles) substitute it here.
X */
X#ifdef V7MAIL
X hh.subtime = cgtdate(hh.subdate);
X fprintf(ufp, "From %s %s",
X#ifdef INTERNET
X hh.from,
X#else
X hh.path,
X#endif
X ctime(&hh.subtime));
X#endif
X hprint(&hh, ufp, 2);
X#ifdef V7MAIL
X tprint(hfp, ufp, TRUE);
X putc('\n', ufp); /* force blank line at end (ugh) */
X#else
X tprint(hfp, ufp, FALSE);
X#endif
X fclose(hfp);
X if (isprogram)
X pclose (ufp);
X else
X fclose(ufp);
X if (!isprogram)
X printf("%s: %s\n", to, isnew ? "New file" : "Appended");
X}
X
X
X/*
X * Print out the rest of the article.
X */
Xtprint(ifp, ofp, checkfrom)
Xregister FILE *ifp, *ofp;
Xint checkfrom;
X{
X while ((fgets(bfr, sizeof bfr, ifp)) != NULL && !sigtrap) {
X if (checkfrom && strncmp(bfr, "From ", 5) == 0)
X putc('>', ofp);
X fputs(bfr, ofp);
X }
X if (sigtrap)
X qfflush(ofp);
X fflush(ofp);
X fprintf(ofp, (sigtrap ? "\n\n" : "\n"));
X sigtrap = FALSE;
X}
X
X
X/*
X * Print the file header.
X */
Xhprint(hp, ofp, verbose)
Xregister struct hbuf *hp;
Xint verbose;
Xregister FILE *ofp;
X{
X register char *p1, *p2;
X char fname[BUFLEN];
X char *tailpath();
X
X fname[0] = '\0'; /* init name holder */
X
X if (verbose == 2) {
X lhwrite(hp, ofp);
X return;
X }
X
X if (lflag || eflag) {
X char buf1[80], buf2[200];
X char *cp;
X
X strcpy(bfr, groupdir);
X for (cp=bfr; *cp; cp++)
X if (*cp == '/')
X *cp = '.';
X sprintf(buf1, "%s/%ld", bfr, bit);
X sprintf(buf2, "%-20s %s", buf1, hp->title);
X fprintf(ofp, "%.76s\n", buf2);
X return;
X }
X
X p1 = index(hp->from, '('); /* Find the sender's full name. */
X if (p1 == NULL && hp->path[0])
X p1 = index(hp->path, '(');
X if (p1 != NULL) {
X strcpy(fname, p1+1);
X p2 = index(fname, ')');
X if (p2 != NULL)
X *p2 = '\0';
X }
X
X fprintf(ofp, "Subject: %s\n", hp->title);
X if (!hflag && hp->keywords[0])
X fprintf(ofp, "Keywords: %s\n", hp->keywords);
X if (verbose) {
X fprintf(ofp, "From: %s\n", hp->from);
X fprintf(ofp, "Path: %s\n", hp->path);
X if (hp->organization[0])
X fprintf(ofp, "Organization: %s\n", hp->organization);
X }
X else {
X if (p1 != NULL)
X *--p1 = '\0'; /* bump over the '(' */
X#ifdef INTERNET
X /*
X * Prefer Path line if it's in internet format, or if we don't
X * understand internet format here, or if there is no reply-to.
X */
X fprintf(ofp, "From: %s", hp->from);
X#else
X fprintf(ofp, "Path: %s", tailpath(hp));
X#endif
X if (fname[0] || hp->organization[0]) {
X if (fname[0] == '\0') {
X strcpy(fname,hp->from);
X p2 = index(fname,'@');
X if (p2)
X *p2 = '\0';
X }
X fprintf(ofp, " (%s", fname);
X if (hp->organization[0] && !hflag)
X fprintf(ofp, " @ %s", hp->organization);
X fprintf(ofp, ")");
X }
X fprintf(ofp, "\n");
X if (p1 != NULL)
X *p1 = ' ';
X }
X
X ngdel(strcpy(bfr, hp->nbuf));
X if (verbose) {
X fprintf(ofp, "Newsgroups: %s\n", bfr);
X fprintf(ofp, "Date: %s\n", hp->subdate);
X if (hp->sender[0])
X fprintf(ofp, "Sender: %s\n", hp->sender);
X if (hp->replyto[0])
X fprintf(ofp, "Reply-To: %s\n", hp->replyto);
X if (hp->followto[0])
X fprintf(ofp, "Followup-To: %s\n", hp->followto);
X }
X else if (index(bfr, ',') || strcmp(groupdir, "junk") == 0)
X fprintf(ofp, "Newsgroups: %s\n", bfr);
X
X if (pflag || ofp != stdout)
X putc('\n', ofp);
X}
X
X
X/*
X * If ofp != stdout, close it and run the script in coptbuf.
X */
Xcout(ofp)
XFILE *ofp;
X{
X register char *p, *q, *r;
X
X if (ofp == stdout)
X return;
X fclose(ofp);
X p = coptbuf;
X q = lbuf;
X while ((*q = *p++) != '\0')
X if (*q++ == FMETA) {
X q--;
X r = outfile;
X while ((*q++ = *r++) != '\0')
X ;
X q--;
X }
X fwait(fsubr(ushell, lbuf, (char *)NULL));
X unlink(outfile);
X}
X
X
Xcdump(ofp)
Xregister FILE *ofp;
X{
X if (ofp == stdout)
X return;
X fclose(ofp);
X unlink(outfile);
X}
X
X
X/*
X * Quiet 'flush'.
X * Empty (without fflush()) the buffer for stream fp.
X */
X/* ARGSUSED */
Xqfflush(fp)
XFILE *fp;
X{
X /* Alas, stdio does not permit this */
X}
X
X
X/*
X * Count the number of remaining lines in file fp.
X * Do not move the file pointer.
X */
Xlinecnt(fp)
XFILE *fp;
X{
X long curpos;
X register int nlines = 0;
X register int c;
X
X if (fp == NULL)
X return 0;
X curpos = ftell(fp);
X while ((c = getc(fp)) != EOF)
X if (c == '\n')
X nlines++;
X fseek(fp, curpos, 0);
X return nlines;
X}
X
X
X/*
X * Transmit file to system.
X */
Xtransmit(sp, file)
Xregister struct srec *sp;
Xchar *file;
X{
X register FILE *ifp, *ofp;
X register int c;
X struct hbuf hh;
X char TRANS[BUFLEN];
X
X#ifdef DEBUG
X fprintf(stderr, "xmit %s to %s using %s\n", file, sp->s_name, sp->s_xmit);
X#endif
X ifp = xfopen(file, "r");
X for(c=0;c<NUNREC;c++)
X hh.unrec[c] = NULL;
X if (hread(&hh, ifp, TRUE) == NULL)
X return;
X strcpy(TRANS, "/tmp/trXXXXXX");
X ofp = xfopen(mktemp(TRANS), "w");
X if (index(sp->s_flags, 'A') == NULL)
X hwrite(&hh, ofp);
X else
X ohwrite(&hh, ofp);
X while ((c = getc(ifp)) != EOF)
X putc(c, ofp);
X fclose(ifp);
X fclose(ofp);
X if (*sp->s_xmit == '\0' || index(sp->s_flags, 'F') || index(sp->s_flags, 'U'))
X sprintf(bfr, DFTXMIT, sp->s_name, TRANS);
X else
X sprintf(bfr, "(%s) < %s", sp->s_xmit, TRANS);
X#ifdef DEBUG
X fprintf(stderr, "%s\n", bfr);
X#endif
X fwait(fsubr(pshell, bfr, (char *)NULL));
X unlink(TRANS);
X}
X
X
X/*
X * Cancel the article whose header is in hp, by posting a control message
X * to cancel it. The scope of the control message depends on who would
X * really be willing to cancel it. It is sent as far as it will do any good.
X * notauthor is true iff the person posting this article is not the
X * real author of the article being cancelled.
X */
Xcancel(ofp, hp, notauthor)
XFILE *ofp;
Xstruct hbuf *hp;
Xint notauthor;
X{
X int pid;
X
X fflush(ofp);
X pid = fork();
X if (pid < 0) {
X perror("readnews: cancel");
X return 0;
X }
X if (pid > 0)
X return 0;
X if (notauthor)
X sprintf(bfr, "%s/%s -t 'cmsg cancel %s' -n %s -d local < /dev/null",
X LIB, "inews", hp->ident, hp->nbuf);
X else {
X if (hp->distribution[0] == '\0')
X sprintf(bfr, "%s/%s -t 'cmsg cancel %s' -n %s < /dev/null",
X LIB, "inews", hp->ident, hp->nbuf);
X else
X sprintf(bfr, "%s/%s -t 'cmsg cancel %s' -n %s -d %s < /dev/null",
X LIB, "inews", hp->ident, hp->nbuf, hp->distribution);
X }
X execl("/bin/sh", "sh", "-c", bfr, (char *) 0);
X perror(bfr);
X exit(1);
X#ifdef lint
X return 0;
X#endif lint
X}
X
X
Xdash(num, ofp)
Xregister int num;
Xregister FILE *ofp;
X{
X register int i;
X
X for (i = 0; i < num; i++)
X putc('-', ofp);
X putc('\n', ofp);
X}
X
X
Xhelp(ofp)
Xregister FILE *ofp;
X{
X register FILE *fp;
X register int c;
X char temp[BUFLEN];
X
X if (cflag) {
Xoneline:
X fprintf(ofp, "(n)ext re(p)rint (w)rite (q)uit (r)eply\
X (c)ancel -[n] +[n] (f)ollowup (N)ext (U)nsubscribe (v)ersion\n");
X return;
X }
X sprintf(temp, "%s/%s", LIB, "help");
X if ((fp = fopen(temp, "r")) == NULL) {
X fprintf(ofp, "No help file.\n");
X goto oneline;
X }
X while ((c = getc(fp)) != EOF && !sigtrap)
X putc(c, ofp);
X fclose(fp);
X}
X
X
Xpout(ofp)
XFILE *ofp;
X{
X register char *p, *q, *r;
X
X p = PAGER;
X q = lbuf;
X while ((*q = *p++) != '\0')
X if (*q++ == FMETA) {
X q--;
X r = filename;
X while ((*q++ = *r++) != '\0')
X ;
X q--;
X }
X fwait(fsubr(ushell, lbuf, (char *)NULL));
X fprintf(ofp, "\n");
X}
X
X/*
X * Print a very brief version of the date in question.
X */
Xchar *
Xbriefdate(datestr)
Xchar *datestr;
X{
X time_t dt, now;
X char *tmstr;
X char *wkday, *monthdate, *timeofday;
X static char rbuf[20];
X
X dt = cgtdate(datestr);
X tmstr = ctime(&dt);
X
X wkday = tmstr; tmstr[3] = '\0';
X monthdate = tmstr+4; tmstr[10] = '\0';
X timeofday = tmstr+11; tmstr[16] = '\0';
X
X (void) time(&now);
X if (now - dt < 7 * DAYS)
X strcpy(rbuf, wkday);
X else
X strcpy(rbuf, monthdate);
X strcat(rbuf, " ");
X strcat(rbuf, timeofday);
X return rbuf;
X}
X
X/*
X * Return TRUE iff stdout is /dev/null.
X */
Xignoring()
X{
X struct stat ss, ns;
X
X fstat(1, &ss);
X stat("/dev/null", &ns);
X if (ss.st_dev == ns.st_dev && ss.st_rdev == ns.st_rdev)
X return TRUE;
X return FALSE;
X}
*-*-END-of-src/rfuncs2.c-*-*
echo x - src/rmgroup.sh
sed 's/^X//' >src/rmgroup.sh <<'*-*-END-of-src/rmgroup.sh-*-*'
X: '@(#)rmgroup.sh 1.3 8/21/84'
Xfor group
Xdo
X echo "Removing newsgroup $group"
X qgrp="`echo $group | sed 's/\./\\\./g'`"
X if
X grep -s "^$qgrp " LIBDIR/active
X then
X ed - LIBDIR/active << E_O_F
X/^$qgrp /d
Xw
Xq
XE_O_F
X dir=SPOOLDIR/"`echo $group | sed 's/\./\//g'`"
X if
X [ -d "$dir" ]
X then
X rm -r "$dir"
X else
X echo "$0: $dir: no spool directory" 2>&1
X fi
X else
X echo "$0: $group: no such newsgroup" 2>&1
X fi
Xdone
Xexit 0
*-*-END-of-src/rmgroup.sh-*-*
echo x - src/rparams.h
sed 's/^X//' >src/rparams.h <<'*-*-END-of-src/rparams.h-*-*'
X/*
X * rparams.h - parameters for readnews, rfuncs, and readr.
X */
X
X/* @(#)rparams.h 2.14 8/28/84 */
X
X#include "params.h"
X
X/* flags for readnews */
X#define pflag options[0].flag
X#define tflag options[1].flag
X#define aflag options[2].flag
X#define nflag options[3].flag
X#define cflag options[4].flag
X#define lflag options[5].flag
X#define rflag options[6].flag
X#define sflag options[7].flag
X#define xflag options[8].flag
X#define hflag options[9].flag
X#define Mflag options[10].flag
X#define fflag options[11].flag
X#define uflag options[12].flag
X#define eflag options[13].flag
X
X#define NEXT 0
X#define SPEC 1
X
X#define FORWARD 0
X#define BACKWARD 1
X
X#define UNKNOWN 0001 /* possible modes for news program */
X#define MAIL 0004
X#define ANY 0007
X
X#define BITMAPSIZE 2048 /* Must be a power of 2 */
X
Xstruct optable { /* options table. */
X char optlet; /* option character. */
X char filchar; /* if to pickup string, fill character. */
X int flag; /* TRUE if have seen this opt. */
X int newstate; /* STRING if takes arg, else OPTION */
X int oldmode; /* OR of legal input modes. */
X int newmode; /* output mode. */
X char *buf; /* string buffer */
X};
X
X/* external declarations specific to readnews */
Xextern char *infile, *outfile, PAGER[];
Xextern char bitmap[], *temprc, *MAILER;
X
X#ifndef ROOTID
Xextern int ROOTID;
X#endif
X
X#ifdef NOTIFY
Xextern char *TELLME;
X#endif
X
Xextern char filename[],coptbuf[],datebuf[],titlebuf[],afline[];
Xextern char newsrc[],groupdir[],rcbuf[],*rcline[],*argvrc[];
Xextern int mode, ngrp, line, newrc(), readmode;
Xextern long bit, obit, last, ngsize, minartno;
Xextern FILE *rcfp,*actfp;
Xextern time_t atime;
Xextern struct stat statbuf;
Xextern struct optable *optpt, options[];
Xextern int actdirect, rcreadok, zapng;
X
X#ifndef lint
X/* lint gets very mad about i-minartno, this is one way of shutting it up */
X/* macros */
X#define get(i) ((i<minartno)? 0 : (bitmap[(i-minartno) >> 3] & (1 << (i-minartno) % 8)))
X#define set(i) if (i>=minartno) bitmap[(i-minartno) >> 3] |= (1 << (i-minartno) % 8);else
X#define clear(i) if (i>=minartno) bitmap[(i-minartno) >> 3] &= ~(1 << (i-minartno) % 8);else
X#endif !lint
X
X#define FCLOSE(fp) {if (fp != NULL) {fclose(fp);fp = NULL;}}
*-*-END-of-src/rparams.h-*-*
echo x - src/sendbatch.sh
sed 's/^X//' >src/sendbatch.sh <<'*-*-END-of-src/sendbatch.sh-*-*'
X: '@(#)sendbatch.sh 1.3 8/21/84'
Xfor rmt in $*
Xdo
X while test $? -eq 0 -a \( -s BATCHDIR/$rmt -o -s BATCHDIR/$rmt.work \)
X do
X LIBDIR/batch BATCHDIR/$rmt 50000 | \
X if test -s BATCHDIR/$rmt.cmd
X then
X BATCHDIR/$rmt.cmd
X else
X uux - UUXFLAGS $rmt!rnews
X fi
X done
Xdone
*-*-END-of-src/sendbatch.sh-*-*
echo x - src/sendnews.c
sed 's/^X//' >src/sendnews.c <<'*-*-END-of-src/sendnews.c-*-*'
X/*
X * sendnews - send news article by mail.
X */
X
X#ifndef lint
Xstatic char *SccsId = "@(#)sendnews.c 2.8 8/14/84";
X#endif !lint
X
X#include <stdio.h>
X#include <ctype.h>
X#ifndef USG
Xstruct utsname {
X char Sysname[9];
X char nodename[33];
X char release[9];
X char version[9];
X};
X#else
X#include <sys/utsname.h>
X#endif
X
X#define eq(a,b) (strcmp(a,b) == 0)
X#define LNLEN 7 /* strlen("ucbvax!") */
X
Xchar *index();
Xchar buffer[BUFSIZ];
Xint linecount, oflag = 0, aflag = 0, bflag = 0, toflag = 0;
X
XFILE *popen();
Xmain(argc, argv)
Xchar **argv;
X{
X FILE *out;
X char newsgroup[100];
X char sysn[20];
X struct utsname ubuf;
X#ifdef lint
X argc = argc;
X#endif lint
X
X while (**(++argv) == '-') {
X if (*++*argv == 'o')
X oflag++;
X else if (**argv == 'a')
X aflag++;
X else if (**argv == 'b')
X bflag++;
X else if (**argv == 'n')
X strcpy(newsgroup, *(++argv));
X }
X if (aflag && bflag) {
X fprintf(stderr, "'-a' and '-b' options mutually exclusive.\n");
X exit(1);
X }
X
X#ifdef debug
X printf("mail %s\n", *argv);
X sprintf(buffer, "cat");
X#else
X sprintf(buffer, "mail %s", *argv);
X#endif
X out = popen(buffer, "w");
X uname(&ubuf);
X strcpy(sysn, ubuf.nodename);
X strcat(sysn, "!");
X
X /* Standard mail prelude to make the formatters happy */
X fprintf(out, "To: %s\n", *argv);
X fprintf(out, "Subject: network news article\n");
X fprintf(out, "\n");
X
X while (fgets(buffer, sizeof buffer, stdin)) {
X if (*newsgroup && ngline()) {
X if (oflag)
X sprintf(buffer, "%s\n", newsgroup);
X else
X sprintf(buffer, "Newsgroups: %s\n", newsgroup);
X }
X putc('N', out);
X fputs(buffer, out);
X }
X pclose(out);
X exit(0);
X}
X
Xngline()
X{
X if (oflag)
X return linecount == 2;
X if (!toflag && (!strncmp("Newsgroups: ", buffer, 12) ||
X !strncmp("To: ",buffer, 4)))
X return ++toflag;
X return 0;
X}
X
X/*
X * Return the ptr in sp at which the character c appears;
X * NULL if not found
X */
X
Xchar *
Xindex(sp, c)
Xregister char *sp, c;
X{
X do {
X if (*sp == c)
X return(sp);
X } while (*sp++);
X return(NULL);
X}
*-*-END-of-src/sendnews.c-*-*
echo x - src/uname.c
sed 's/^X//' >src/uname.c <<'*-*-END-of-src/uname.c-*-*'
X/*
X * This routine is compatible with the Unix T/S system call uname,
X * which figures out the name of the local system.
X * However, we do it by reading the file /usr/include/whoami.h.
X * This avoids having to recompile uucp for each site and hence
X * avoids having to distribute the source to uucp to people who
X * have only binary licenses.
X */
X
X#ifndef lint
Xstatic char *SccsId = "@(#)uname.c 2.6 8/13/84";
X#endif !lint
X
X#include "params.h"
X
X#ifdef UNAME
X# define DONE
X#endif
X
X#ifdef GHNAME
Xuname(uptr)
Xstruct utsname *uptr;
X{
X gethostname(uptr->nodename, sizeof (uptr->nodename));
X}
X# define DONE
X#endif
X
X#ifndef DONE
X#define HDRFILE "/usr/include/whoami.h"
X
Xuname(uptr)
Xstruct utsname *uptr;
X{
X char buf[BUFSIZ];
X FILE *fd;
X
X fd = fopen(HDRFILE, "r");
X if (fd == NULL) {
X fprintf(stderr, "Cannot open %s\n", HDRFILE);
X exit(1);
X }
X
X for (;;) { /* each line in the file */
X if (fgets(buf, sizeof buf, fd) == NULL) {
X fprintf(stderr, "no sysname in %s\n", HDRFILE);
X fclose(fd);
X exit(2);
X }
X if (sscanf(buf, "#define sysname \"%[^\"]\"", uptr->nodename) == 1) {
X fclose(fd);
X return;
X }
X }
X}
X#endif
*-*-END-of-src/uname.c-*-*
echo x - src/unbatch.c
sed 's/^X//' >src/unbatch.c <<'*-*-END-of-src/unbatch.c-*-*'
X/*
X * unbatchnews: extract news in batched format and process it one article
X * at a time. The format looks like
X * #! rnews 1234
X * article containing 1234 characters
X * #! rnews 4321
X * article containing 4321 characters
X */
X
X#ifndef lint
Xstatic char *SccsId = "@(#)unbatch.c 1.8 9/3/84";
X#endif !lint
X
X# include <stdio.h>
X
Xchar buf[512];
X
Xmain()
X{
X register int c;
X register FILE *pfn;
X register long size;
X char *filename;
X int pid, wpid, exstat;
X char *mktemp(), *gets();
X long atol();
X
X filename = mktemp("/tmp/unbnewsXXXXXX");
X while(gets(buf) != NULL) {
X while (strncmp(buf, "#! rnews ", 9)) {
X fprintf(stderr, "out of sync, skipping %s\n", buf);
X if (gets(buf) == NULL)
X exit(0);
X }
X size = atol(buf+9);
X if(size <= 0)
X break;
X pfn = fopen(filename, "w");
X while(--size >= 0 && (c = getc(stdin)) != EOF)
X putc(c, pfn);
X fclose(pfn);
X
X /*
X * If we got a truncated batch, don't process the
X * last article; it will probably be received again.
X */
X if (size > 0)
X break;
X
X /*
X * rnews < filename
X */
X while ((pid = fork()) == -1) {
X fprintf(stderr, "fork failed, waiting...\r\n");
X sleep(60);
X }
X if (pid == 0) {
X close(0);
X open(filename, 0);
X#ifdef IHCC
X sprintf(buf, "%s/%s/rnews", logdir(HOME), LIBDIR);
X execlp(buf, "rnews", (char *)0);
X#else
X execlp("rnews", "rnews", (char *)0);
X#endif
X perror("rnews");
X exit(1);
X }
X while ((wpid = wait(&exstat)) >= 0 && wpid != pid)
X ;
X }
X unlink(filename);
X}
*-*-END-of-src/unbatch.c-*-*
echo x - src/uurec.c
sed 's/^X//' >src/uurec.c <<'*-*-END-of-src/uurec.c-*-*'
X/*
X * uurec - receive articles via /bin/mail.
X */
X
X#ifndef lint
Xstatic char *SccsId = "@(#)uurec.c 2.7 9/3/84";
X#endif !lint
X
X#include "defs.h"
X
X#include <stdio.h>
X#include <ctype.h>
X
X/*
X * Process a news article which has been shipped via /bin/mail.
X */
X
X#define FROM 01
X#define NLIN 02
X#define BLANK 03
X#define OTHER 04
X
X#define SKIPPING 010
X#define READING 020
X
X#define BFSZ 250
X
X#define EOT '\004'
X
X#define A 01
X#define B 02
X
X#ifdef debug
X# define RNEWS "cat"
X#endif
Xextern char *strcat(), *strcpy();
Xextern char *frombreak();
Xextern FILE *popen();
X
X/* ARGSUSED */
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X char buf[BFSZ], fbuf[BFSZ];
X char bfr[BFSZ], *pbfr = bfr;
X register char *p = NULL;
X register FILE *pipe = stdout;
X register int mode, frmflg, pathcnt, format;
X char *index();
X
X mode = SKIPPING;
X frmflg = FALSE;
X while (fgets(buf, BFSZ, stdin) != NULL) {
X#ifdef debug
X printf("%o\t%s", mode|type(buf), buf);
X#endif
X switch (mode | type(buf)) {
X
X case FROM | SKIPPING:
X if (frmflg)
X p = frombreak(p, buf);
X else
X p = fbuf;
X frmflg = TRUE;
X break;
X
X case FROM | READING:
X if (!frmflg) {
X frmflg = TRUE;
X p = fbuf;
X pclose(pipe);
X }
X p = frombreak(p, buf);
X break;
X
X case NLIN | SKIPPING:
X if ((isupper(buf[1]) && index(buf, ':')) || !strncmp(buf, "From ", 5))
X format = B;
X else
X format = A;
X#ifdef debug
X printf("format = %d\n", format);
X#endif
X mode = READING;
X
X case NLIN | READING:
X if (frmflg) {
X frmflg = FALSE;
X --p;
X while (p >= fbuf && *--p != '!')
X ;
X *++p = '\0';
X pathcnt = 0;
X#ifdef IHCC
X sprintf(pbfr, "%s/%s/%s", logdir(HOME),
X LIBDIR, "rnews");
X#else
X pbfr = RNEWS;
X#endif
X if ((pipe = popen(pbfr, "w")) == NULL) {
X perror("uurec: popen failed");
X exit(1);
X }
X }
X if (format == A) {
X if (++pathcnt == 3)
X fputs(fbuf, pipe);
X fputs(buf+1, pipe);
X } else {
X if (!pathcnt && (!strncmp(buf+1, "From: ", 6) || !strncmp(buf+1, "From ", 5))) {
X pathcnt++;
X fprintf(pipe, "From: %s", fbuf);
X sscanf(buf, "%s %s[^\n]", fbuf, fbuf);
X fprintf(pipe, "%s\n", fbuf);
X } else
X fputs(buf+1, pipe);
X }
X break;
X
X case OTHER | SKIPPING:
X break;
X
X case OTHER | READING:
X pclose(pipe);
X mode = SKIPPING;
X }
X }
X if (pipe)
X pclose(pipe);
X exit(0);
X}
X
Xtype(p)
Xregister char *p;
X{
X while (*p == ' ' || *p == '?')
X ++p;
X
X if (*p == 'N')
X return (NLIN);
X
X if (strncmp(p, ">From ", 6) == 0)
X return (FROM);
X
X if (strncmp(p, "From ", 5) == 0)
X return (FROM);
X
X return(OTHER);
X}
X
X/*
X * Get the system name out of a from line.
X */
Xchar *
Xfrombreak(buf, fbuf)
Xregister char *buf, *fbuf;
X{
X register char *p;
X
X /* break the line into tokens. */
X p = fbuf;
X while (*++p != '\0')
X switch (*p) {
X case '\n':
X case '\t':
X case ' ':
X *p = '\0';
X break;
X case EOT:
X goto garbled;
X default:;
X }
X *++p = EOT;
X *++p = '\0';
X
X for (p=fbuf; *p != EOT || p[1] != '\0'; p += strlen(p)+1) {
X if (strcmp(p, "forwarded") == 0)
X return(buf);
X if (strcmp(p, "remote") == 0) {
X p += strlen(p)+1;
X if (strcmp(p, "from") == 0) {
X p += strlen(p)+1;
X strcpy(buf, p);
X strcat(buf, "!");
X return(buf+strlen(buf));
X }
X }
X }
X garbled:
X strcat(buf, "???!");
X return(buf+4);
X}
*-*-END-of-src/uurec.c-*-*
echo x - src/virtterm.c
sed 's/^X//' >src/virtterm.c <<'*-*-END-of-src/virtterm.c-*-*'
X/*
X * Virtual terminal handler for the HP-2621 terminal.
X * Written by Kenneth Almquist, AGS Computers (HO 4C601, X7105).
X * Modified by Stephen Hemminger, to use TERMCAP (without curses)
X */
Xstatic char *SccsId = "@(#)virtterm.c 1.4 7/17/84";
X
X#include <stdio.h>
X#include <ctype.h>
X
X#define MAXPLEN 24
X#define MAXLLEN 80
X#define BOTLINE (ROWS - 1)
X#define DIRTY 01
X
X/* terminal escape sequences from termcap */
X#define HO _tstr[0] /* home */
X#define CL _tstr[1] /* clear screen */
X#define CD _tstr[2] /* clear to end of screen */
X#define CE _tstr[3] /* clear to end of line */
X#define xUP _tstr[4] /* up one line */
X#define DO _tstr[5] /* down one line */
X#define US _tstr[6] /* underline */
X#define UE _tstr[7] /* underline end */
X#define BT _tstr[8] /* backtab */
X#define xBC _tstr[9] /* backspace */
X#define AL _tstr[10] /* insert line */
X#define DL _tstr[11] /* delete line */
X#define CM _tstr[12] /* cursor move */
X#define CH _tstr[13] /* cursor horizontal move */
X#define CV _tstr[14] /* cursor vertical move */
X#define CS _tstr[15] /* scrolling region */
X#define SF _tstr[16] /* scroll forwards */
X#define SR _tstr[17] /* scroll backwards */
X#define TI _tstr[18] /* start cursor mode */
X#define TE _tstr[19] /* end cursor mode */
X#define TA _tstr[20] /* tab char (if not \t) */
X#define CR _tstr[21] /* carriage return (if not \r) */
X#define xPC _tstr[22] /* for reading pad character */
Xchar PC; /* pad character */
Xchar *BC, *UP; /* external variables for tgoto */
X
Xstatic char sname[] = "hoclcdceupdousuebtbcaldlcmchcvcssfsrtitetacrpc";
Xchar *_tstr[23];
Xint HOlen; /* length of HO string */
X
X
X/* terminal flags */
X#define BS _tflg[0] /* can backspace */
X#define AM _tflg[1] /* has auto margins */
X#define XN _tflg[2] /* no newline after wrap */
X#define RET !_tflg[3] /* has carriage return */
X#define NS _tflg[4] /* has SF (scroll forward) */
X#define PT _tflg[5] /* has tabs */
X#define XT _tflg[6] /* tabs are destructive */
Xint GT = 1; /* tab stops on terminal are set */
X
Xstatic char bname[] = "bsamxnncnsptxt";
Xchar _tflg[7];
X
X
Xextern char *tgoto(), *tgetstr();
Xextern char *getenv(), *strcpy();
X
X#define ULINE 0200
X#define CURSEEN 1
X
X/* Constants accessable by user */
Xint hasscroll; /* scrolling type, 0 == no scrolling */
Xint ROWS; /* number of lines on screen */
Xint COLS; /* width of screen */
X
Xstruct line {
X char len;
X char flags;
X char l[MAXLLEN];
X};
X
Xint _row, _col;
Xint _srow, _scol;
Xstruct line _virt[MAXPLEN], _actual[MAXPLEN];
Xint _uline = 0;
Xint _junked = 1;
Xint _curjunked;
Xint _dir = 1;
Xint _shifttop, _shiftbot;
Xint _shift;
Xint _scratched;
Xint vputc();
X
X
X
X/*
X * Tell refresh to shift lines in region upwards count lines. Count
X * may be negative. The virtual image is not shifted; this may change
X * later. The variable _scratched is set to supress all attempts to
X * shift.
X */
X
Xushift(top, bot, count) {
X if (_scratched)
X return;
X if (_shift != 0 && (_shifttop != top || _shiftbot != bot)) {
X _scratched++;
X return;
X }
X _shifttop = top;
X _shiftbot = bot;
X _shift += count;
X}
X
X
X
X/*
X * generate a beep on the terminal
X */
X
Xbeep() {
X vputc('\7');
X}
X
X/*
X * Move to one line below the bottom of the screen.
X */
X
Xbotscreen() {
X _amove(BOTLINE, 0);
X vputc('\n');
X vflush();
X}
X
X
X
Xmove(row, col) {
X if (row < 0 || row >= ROWS || col < 0 || col >= COLS)
X return;
X _row = row;
X _col = col;
X}
X
X
X
X/*
X * Output string at specified location.
X */
X
Xmvaddstr(row, col, str)
X char *str;
X {
X move(row, col);
X addstr(str);
X}
X
X
Xaddstr(s)
Xchar *s;
X{
X register char *p;
X register struct line *lp;
X register int col = _col;
X
X lp = &_virt[_row];
X if (lp->len < col) {
X p = &lp->l[lp->len];
X while (lp->len < col) {
X *p++ = ' ';
X lp->len++;
X }
X }
X for (p = s; *p != '\0'; p++) {
X if (*p == '\n') {
X lp->len = col;
X lp->flags |= DIRTY;
X col = 0;
X if (++_row >= ROWS)
X _row = 0;
X lp = &_virt[_row];
X }
X else {
X lp->l[col] = *p;
X lp->flags |= DIRTY;
X if (++col >= COLS) {
X lp->len = COLS;
X col = 0;
X if (++_row >= ROWS)
X _row = 0;
X lp = &_virt[_row];
X }
X }
X }
X if (lp->len <= col)
X lp->len = col;
X _col = col;
X}
X
X
X
Xaddch (c) {
X register struct line *lp;
X register char *p;
X
X lp = &_virt[_row];
X if (lp->len < _col) {
X p = &lp->l[lp->len];
X while (lp->len < _col) {
X *p++ = ' ';
X lp->len++;
X }
X }
X lp->l[_col] = c;
X if (lp->len == _col)
X lp->len++;
X if (++_col >= COLS) {
X _col = 0;
X if (++_row >= ROWS)
X _row = 0;
X }
X lp->flags |= DIRTY;
X}
X
X
X
Xclrtoeol() {
X register struct line *lp;
X
X lp = &_virt[_row];
X if (lp->len > _col) {
X lp->len = _col;
X lp->flags |= DIRTY;
X }
X}
X
X
X/*
X * Clear an entire line.
X */
X
Xclrline(row) {
X register struct line *lp;
X
X lp = &_virt[row];
X if (lp->len > 0) {
X lp->len = 0;
X lp->flags |= DIRTY;
X }
X}
X
X
X
Xclear() {
X erase();
X _junked++;
X}
X
X
X
Xerase() {
X register i;
X
X for (i = 0; i < ROWS; i++) {
X _virt[i].len = 0;
X _virt[i].flags |= DIRTY;
X }
X}
X
X
X
Xrefresh() {
X register i;
X int j, len;
X register char *p, *q;
X
X if (checkin())
X return;
X i = 1;
X if (_junked) {
X _sclear();
X _junked = 0;
X } else if (! _scratched) {
X if (_shift > 0) {
X _ushift(_shifttop, _shiftbot, _shift);
X } else if (_shift < 0) {
X i = _dshift(_shifttop, _shiftbot, -_shift);
X } else {
X i = _dir;
X }
X }
X _dir = i;
X _shift = 0;
X if (checkin())
X return;
X _fixlines();
X for (i = _dir > 0 ? 0 : BOTLINE; i >= 0 && i < ROWS; i += _dir) {
X if ((_virt[i].flags & DIRTY) == 0)
X continue;
X _ckclrlin(i); /* decide whether to do a clear line */
X /* probably should consider cd as well */
X len = _virt[i].len;
X if (_actual[i].len < len)
X len = _actual[i].len;
X p = _virt[i].l;
X q = _actual[i].l;
X for (j = 0; j < len; j++) {
X if (*p != *q) {
X _amove(i, j);
X _aputc(*p);
X *q = *p;
X }
X p++, q++;
X }
X len = _virt[i].len;
X if (_actual[i].len > len) {
X _clrtoeol(i, len);
X }
X else {
X for (; j < len; j++) {
X if (*p != ' ') {
X _amove(i, j);
X _aputc(*p);
X }
X *q++ = *p++;
X }
X _actual[i].len = len;
X }
X if (checkin())
X return;
X }
X _dir = 1;
X if (CURSEEN)
X _amove(_row, _col);
X vflush(); /* flush output buffer */
X _scratched = 0;
X}
X
X
X_dshift(top, bot, count) {
X register i;
X
X if (count >= bot - top || hasscroll < 4) { /* must have CS or AL/DL */
X _scratched++;
X return 1;
X }
X for (i = bot - count; _actual[i].len == 0; i--)
X if (i == top)
X return 1;
X for (i = top; i <= bot; i++)
X _virt[i].flags |= DIRTY;
X for (i = bot; i >= top + count; i--)
X _actual[i] = _actual[i - count];
X for (; i >= top; i--)
X _actual[i].len = 0;
X
X if (hasscroll != 5) { /* can we define scrolling region, and scroll back */
X tputs(tgoto(CS, bot, top), 1, vputc);/* define scroll region */
X _curjunked = 1;
X _amove(top, 0);
X for (i = count; --i >= 0;)
X tputs(SR, 1, vputc);/* scroll back */
X tputs(tgoto(CS, BOTLINE, 0), 1, vputc);
X _curjunked = 1;
X } else {
X _amove(bot - count + 1, 0);
X if (CD && bot == BOTLINE)
X tputs(CD, 1, vputc);
X else {
X for (i = count; --i >= 0;)
X tputs(DL, ROWS - _srow, vputc);
X }
X _amove(top, 0);
X for (i = count; --i >= 0;)
X tputs(AL, ROWS - _srow, vputc);
X }
X return -1;
X}
X
X
X_ushift(top, bot, count) {
X register i;
X
X if (count >= bot - top || hasscroll == 0) {
X _scratched++;
X return;
X }
X for (i = top + count; _actual[i].len == 0; i++)
X if (i == bot)
X return;
X if (hasscroll == 1 || hasscroll == 3) {
X /* we cheat and shift the entire screen */
X /* be sure we are shifting more lines into than out of position */
X if ((bot - top + 1) - count <= ROWS - (bot - top + 1))
X return;
X top = 0, bot = BOTLINE;
X }
X for (i = top; i <= bot; i++)
X _virt[i].flags |= DIRTY;
X for (i = top; i <= bot - count; i++)
X _actual[i] = _actual[i + count];
X for (; i <= bot; i++)
X _actual[i].len = 0;
X
X if (hasscroll != 5) {
X if (top != 0 || bot != BOTLINE) {
X tputs(tgoto(CS, bot, top), 0, vputc);
X _curjunked = 1;
X }
X _amove(bot, 0); /* move to bottom */
X for (i = 0; i < count; i++) {
X if (SF) /* scroll forward */
X tputs(SF, 1, vputc);
X else
X vputc('\n');
X }
X if (top != 0 || bot != BOTLINE) {
X tputs(tgoto(CS, BOTLINE, 0), 0, vputc);
X _curjunked = 1;
X }
X } else {
X _amove(top, 0);
X for (i = count; --i >= 0;)
X tputs(DL, ROWS - _srow, vputc);
X if (bot < BOTLINE) {
X _amove(bot - count + 1, 0);
X for (i = count; --i >= 0;)
X tputs(AL, ROWS - _srow, vputc);
X }
X }
X}
X
X
X_sclear() {
X register struct line *lp;
X
X tputs(CL, 0, vputc);
X _srow = _scol = 0;
X for (lp = _actual; lp < &_actual[ROWS]; lp++) {
X lp->len = 0;
X }
X for (lp = _virt; lp < &_virt[ROWS]; lp++) {
X if (lp->len != 0)
X lp->flags |= DIRTY;
X }
X}
X
X
X_clrtoeol(row, col) {
X register struct line *lp = &_actual[row];
X register i;
X
X if (CE && lp->len > col + 1) {
X _amove(row, col);
X tputs(CE, 1, vputc);
X } else {
X for (i = col ; i < lp->len ; i++) {
X if (lp->l[i] != ' ') {
X _amove(row, i);
X _aputc(' ');
X }
X }
X }
X lp->len = col;
X}
X
X
X_fixlines() {
X register struct line *lp;
X register char *p;
X register int i;
X
X for (i = 0; i < ROWS; i++) {
X lp = &_virt[i];
X if (lp->flags & DIRTY) {
X lp = &_virt[i];
X for (p = &lp->l[lp->len]; --p >= lp->l && *p == ' ';);
X lp->len = p + 1 - lp->l;
X if (lp->len == _actual[i].len && strncmp(lp->l, _actual[i].l, lp->len) == 0)
X lp->flags &= ~DIRTY;
X }
X }
X}
X
X
X/*
X * Consider clearing the line before overwriting it.
X * We always clear a line if it has underlined characters in it
X * because these can cause problems. Otherwise decide whether
X * that will decrease the number of characters to change. This
X * routine could probably be simplified with no great loss.
X */
X
X_ckclrlin(i) {
X int eval;
X int len;
X int first;
X register struct line *vp, *ap;
X register int j;
X
X if (!CE)
X return;
X ap = &_actual[i];
X vp = &_virt[i];
X len = ap->len;
X eval = -strlen(CE);
X if (len > vp->len) {
X len = vp->len;
X eval = 0;
X }
X for (j = 0; j < len && vp->l[j] == ap->l[j]; j++);
X if (j == len)
X return;
X first = j;
X while (j < len) {
X if (vp->l[j] == ' ') {
X if (ap->l[j] != ' ') {
X while (++j < len && vp->l[j] == ' ' && ap->l[j] != ' ') {
X eval++;
X }
X if (j == len)
X eval++;
X continue;
X }
X }
X else {
X if (vp->l[j] == ap->l[j]) {
X while (++j < len && vp->l[j] == ap->l[j]) {
X eval--;
X }
X continue;
X }
X }
X j++;
X }
X if (US) {
X for (j = 0 ; j < ap->len ; j++) {
X if (ap->l[j] & ULINE) {
X eval = 999;
X if (first > j)
X first = j;
X break;
X }
X }
X }
X for (j = first; --j >= 0;)
X if (vp->l[j] != ' ')
X break;
X if (j < 0)
X first = 0;
X if (eval > 0) {
X _amove(i, first);
X tputs(CE, 0, vputc);
X _actual[i].len = first;
X }
X}
X
X
X
X/*
X * Move routine
X * first compute direct cursor address string and cost
X * then relative motion string and cost,
X * then home then relative and cost
X * choose smallest and do it.
X *
X * The plod stuff is to build the strings (with padding) then decide
X */
Xstatic char *plodstr; /* current location in relmove string */
X
Xplodput(c) { *plodstr++ = c; }
X
X_amove(row, col) {
X char direct[20];
X char rel[MAXPLEN*10 + MAXLLEN*10]; /* longest move is full screen */
X char ho[MAXPLEN*10 + MAXLLEN*10];
X int cost, newcost;
X register char *movstr;
X
X if (row == _srow && col == _scol && _curjunked == 0)
X return;
X _setul(0);
X
X cost = 999;
X if (CM) {
X plodstr = direct;
X tputs(tgoto(CM, col, row), 0, plodput);
X *plodstr = '\0';
X cost = plodstr - direct;
X movstr = direct;
X }
X if (_curjunked == 0) {
X plodstr = rel;
X if (_vmove(_srow, row) >= 0
X && _hmove(_scol, col, row) >= 0
X && (newcost = plodstr - rel) < cost) {
X *plodstr = '\0';
X cost = newcost;
X movstr = rel;
X }
X }
X if (cost > HOlen) { /* is it worth calculating */
X plodstr = ho;
X tputs(HO, 0, plodput);
X if (_vmove(0, row) >= 0
X && _hmove(0, col, row) >= 0
X && (newcost = plodstr - ho) < cost) {
X *plodstr = '\0';
X cost = newcost;
X movstr = ho;
X }
X }
X
X while (--cost >= 0) {
X vputc(*movstr++);
X }
X _srow = row, _scol = col;
X _curjunked = 0;
X}
X
X
X_vmove(orow, nrow) {
X char direct[128];
X char *saveplod = plodstr;
X
X if (CV) {
X plodstr = direct;
X tputs(tgoto(CV, nrow, nrow), 0, plodput);
X *plodstr = '\0';
X plodstr = saveplod;
X }
X if (orow > nrow) { /* cursor up */
X if (! UP)
X return -1;
X while (orow > nrow) {
X tputs(UP, 1, plodput);
X orow--;
X }
X }
X while (orow < nrow) { /* cursor down */
X if (DO)
X tputs(DO, 1, plodput);
X else
X *plodstr++ = '\n';
X orow++;
X }
X if (CV && plodstr - saveplod >= strlen(direct)) {
X register char *p;
X plodstr = saveplod;
X for (p = direct ; *plodstr = *p++ ; plodstr++);
X }
X return 0;
X}
X
X
X_hmove(ocol, ncol, row) {
X char direct[128];
X char ret[MAXLLEN*10];
X char *saveplod = plodstr;
X char *movstr;
X int cost, newcost;
X
X cost = 999;
X if (CH) {
X plodstr = direct;
X tputs(tgoto(CH, ncol, ncol), 0, plodput);
X cost = plodstr - direct;
X movstr = direct;
X plodstr = saveplod;
X }
X if (RET && ocol > ncol) { /* consider doing carriage return */
X plodstr = ret;
X if (CR)
X tputs(CR, 1, plodput);
X else
X *plodstr++ = '\r';
X if (_relhmove(0, ncol, row) >= 0
X && (newcost = plodstr - ret) < cost) {
X cost = newcost;
X movstr = ret;
X }
X plodstr = saveplod;
X }
X if (_relhmove(ocol, ncol, row) < 0) {
X if (cost == 999)
X return -1;
X goto copy;
X }
X if (plodstr - saveplod > cost) {
Xcopy: plodstr = saveplod;
X while (--cost >= 0)
X *plodstr++ = *movstr++;
X }
X return 0;
X}
X
X
X
X_relhmove(ocol, ncol, row) {
X int tab;
X
X if (ocol < ncol && PT && GT) { /* tab (nondestructive) */
X while ((tab = (ocol + 8) & ~07) <= ncol) {
X if (TA)
X tputs(TA, 1, plodput);
X else
X *plodstr++ = '\t';
X ocol = tab;
X }
X if (tab < COLS && tab - ncol < ncol - ocol) {
X if (TA)
X tputs(TA, 1, plodput);
X else
X *plodstr++ = '\t';
X ocol = tab;
X }
X } else if (BT && GT && ocol > ncol) { /* backwards tab */
X while ((tab = (ocol - 1) &~ 07) >= ncol) {
X if (BS && tab == ocol - 1) {
X if (BC)
X tputs(BC, 1, plodput);
X else
X *plodstr++ = '\b';
X } else
X tputs(BT, 1, plodput);
X ocol = tab;
X }
X if (ncol - tab + 1 < ocol - ncol) {
X tputs(BT, 1, plodput);
X ocol = tab;
X }
X }
X if (ocol > ncol) { /* cursor left */
X if (! BS)
X return -1;
X while (ocol > ncol) {
X if (BC != NULL)
X tputs(BC, 1, plodput);
X else
X *plodstr++ = '\b';
X ocol--;
X }
X }
X if (ocol < ncol) { /* cursor right */
X register struct line *lp = &_actual[row];
X /*
X * This code doesn't move over underlined characters properly,
X * but in practice this doesn't seem to matter.
X */
X while (ocol < ncol) {
X if (ocol < lp->len)
X *plodstr++ = lp->l[ocol];
X else
X *plodstr++ = ' ';
X ocol++;
X }
X }
X return 0;
X}
X
X
X
X_aputc(c) {
X if (AM && _scol == COLS - 1 && _srow == ROWS - 1)
X return;
X _setul(c & ULINE);
X vputc(c & ~ULINE);
X if (++_scol >= COLS) {
X if (! AM) {
X _scol--;
X } else if (XN) {
X _curjunked++;
X } else {
X _scol = 0;
X ++_srow;
X }
X }
X}
X
X
X_setul(on) {
X if (on) {
X if (_uline == 0 && US != NULL) {
X tputs(US, 1, vputc);
X _uline = 1;
X }
X }
X else {
X if (_uline != 0 && UE != NULL) {
X tputs(UE, 1, vputc);
X _uline = 0;
X }
X }
X}
X
X
X/*
X * Initialize termcap strings for later use.
X */
Xinitterm() {
X static char tcbuf[1024]; /* termcap buffer */
X register char *cp;
X
X if ((cp = getenv("TERM")) == NULL)
X xerror("TERM not set in environment");
X
X switch (tgetent(tcbuf, cp)) {
X case 0:
X xerror("Terminal not found in TERMCAP");
X case -1:
X xerror("Can't open /etc/termcap");
X case 1:
X break;
X }
X
X if ((ROWS = tgetnum("li")) == -1
X || (COLS = tgetnum("co")) == -1)
X xerror("Can't get screen size");
X _zap();
X
X if (CL == NULL)
X xerror ("No clear screen defined");
X
X if (HO == NULL && CM == NULL)
X xerror("No home or cursor addressing");
X if (HO)
X HOlen = strlen(HO);
X else
X HOlen = 999;
X
X PC = xPC ? xPC[0] : 0;
X BC = xBC;
X UP = xUP;
X
X if (tgetnum("ug") > 0)
X US = UE = NULL;
X
X if (XT) /* Destructive tab code not included */
X PT = 0; /* to keep things simple */
X
X if (ROWS > MAXPLEN)
X ROWS = MAXPLEN;
X if (COLS > MAXLLEN) {
X COLS = MAXLLEN;
X AM = XN = 1;
X }
X
X /* Select article scrolling algorithm. We prefer scrolling region
X over insert/delete line because it's faster on the HP */
X hasscroll = 0;
X if (!NS) {
X hasscroll = 1;
X if (SR)
X hasscroll = 3;
X if (CS)
X hasscroll++;
X }
X if (AL && DL && hasscroll != 4)
X hasscroll = 5;
X}
X
X
Xrawterm() {
X if (TI != NULL)
X tputs(TI, 0, vputc);
X}
X
X
Xcookedterm() {
X if (TE != NULL)
X tputs(TE, 0, vputc);
X}
X
X
X/* get strings from termcap */
X_zap() {
X static char tstrbuf[1024];
X static char *tp;
X register char *namp, **sp, *bp;
X
X tp = tstrbuf;
X sp = _tstr;
X for (namp = sname; *namp; namp += 2) {
X *sp++ = tgetstr(namp, &tp);
X }
X bp = _tflg;
X for (namp = bname; *namp; namp += 2) {
X *bp++ = tgetflag(namp, &tp);
X }
X}
*-*-END-of-src/virtterm.c-*-*
exit
More information about the Comp.sources.unix
mailing list