1: /* $Header: bits.c,v 4.3.1.4 86/10/31 15:23:53 lwall Exp $
   2:  *
   3:  * $Log:	bits.c,v $
   4:  * Revision 4.3.1.4  86/10/31  15:23:53  lwall
   5:  * Separated firstart into two variables so KILL on new articles won't
   6:  * accidentally mark articles read.
   7:  *
   8:  * Revision 4.3.1.3  86/09/09  16:01:43  lwall
   9:  * Fixed 'n more articles' bug.
  10:  *
  11:  * Revision 4.3.1.2  86/07/24  14:40:23  lwall
  12:  * Gets host name from path instead of relay-version for news 2.10.3.
  13:  *
  14:  * Revision 4.3.1.1  85/05/10  11:31:41  lwall
  15:  * Branch for patches.
  16:  *
  17:  * Revision 4.3  85/05/01  11:36:15  lwall
  18:  * Baseline for release with 4.3bsd.
  19:  *
  20:  */
  21: 
  22: #include "EXTERN.h"
  23: #include "common.h"
  24: #include "rcstuff.h"
  25: #include "head.h"
  26: #include "util.h"
  27: #include "final.h"
  28: #include "rn.h"
  29: #include "cheat.h"
  30: #include "ng.h"
  31: #include "artio.h"
  32: #include "intrp.h"
  33: #include "ngdata.h"
  34: #include "rcln.h"
  35: #include "kfile.h"
  36: #include "INTERN.h"
  37: #include "bits.h"
  38: 
  39: #ifdef DBM
  40: #    ifdef NULL
  41: #	undef NULL
  42: #    endif NULL
  43: #    include <dbm.h>
  44: #endif DBM
  45: MEM_SIZE ctlsize;           /* size of bitmap in bytes */
  46: 
  47: void
  48: bits_init()
  49: {
  50: #ifdef DELAYMARK
  51:     dmname = savestr(filexp(RNDELNAME));
  52: #else
  53:     ;
  54: #endif
  55: }
  56: 
  57: /* checkpoint the .newsrc */
  58: 
  59: void
  60: checkpoint_rc()
  61: {
  62: #ifdef DEBUGGING
  63:     if (debug & DEB_CHECKPOINTING) {
  64:     fputs("(ckpt)",stdout);
  65:     fflush(stdout);
  66:     }
  67: #endif
  68:     if (doing_ng)
  69:     restore_ng();           /* do not restore M articles */
  70:     if (rc_changed)
  71:     write_rc();
  72: #ifdef DEBUGGING
  73:     if (debug & DEB_CHECKPOINTING) {
  74:     fputs("(done)",stdout);
  75:     fflush(stdout);
  76:     }
  77: #endif
  78: }
  79: 
  80: /* reconstruct the .newsrc line in a human readable form */
  81: 
  82: void
  83: restore_ng()
  84: {
  85:     register char *s, *mybuf = buf;
  86:     register ART_NUM i;
  87:     ART_NUM count=0;
  88:     int safelen = LBUFLEN - 16;
  89: 
  90:     strcpy(buf,rcline[ng]);     /* start with the newsgroup name */
  91:     s = buf + rcnums[ng] - 1;       /* use s for buffer pointer */
  92:     *s++ = rcchar[ng];          /* put the requisite : or !*/
  93:     *s++ = ' ';             /* put the not-so-requisite space */
  94:     for (i=1; i<=lastart; i++) {    /* for each article in newsgroup */
  95:     if (s-mybuf > safelen) {    /* running out of room? */
  96:         safelen *= 2;
  97:         if (mybuf == buf) {     /* currently static? */
  98:         *s = '\0';
  99:         mybuf = safemalloc((MEM_SIZE)safelen + 16);
 100:         strcpy(mybuf,buf);  /* so we must copy it */
 101:         s = mybuf + (s-buf);
 102:                     /* fix the pointer, too */
 103:         }
 104:         else {          /* just grow in place, if possible */
 105:         char *newbuf;
 106: 
 107:         newbuf = saferealloc(mybuf,(MEM_SIZE)safelen + 16);
 108:         s = newbuf + (s-mybuf);
 109:         mybuf = newbuf;
 110:         }
 111:     }
 112:     if (!was_read(i))       /* still unread? */
 113:         count++;            /* then count it */
 114:     else {              /* article was read */
 115:         ART_NUM oldi;
 116: 
 117:         sprintf(s,"%ld",(long)i);   /* put out the min of the range */
 118:         s += strlen(s);     /* keeping house */
 119:         oldi = i;           /* remember this spot */
 120:         do i++; while (i <= lastart && was_read(i));
 121:                     /* find 1st unread article or end */
 122:         i--;            /* backup to last read article */
 123:         if (i > oldi) {     /* range of more than 1? */
 124:         sprintf(s,"-%ld,",(long)i);
 125:                     /* then it out as a range */
 126:         s += strlen(s);     /* and housekeep */
 127:         }
 128:         else
 129:         *s++ = ',';     /* otherwise, just a comma will do */
 130:     }
 131:     }
 132:     if (*(s-1) == ',')          /* is there a final ','? */
 133:     s--;                /* take it back */
 134:     *s++ = '\0';            /* and terminate string */
 135: #ifdef DEBUGGING
 136:     if (debug & DEB_NEWSRC_LINE && !panic) {
 137:     printf("%s: %s\n",rcline[ng],rcline[ng]+rcnums[ng]) FLUSH;
 138:     printf("%s\n",mybuf) FLUSH;
 139:     }
 140: #endif
 141:     free(rcline[ng]);           /* return old rc line */
 142:     if (mybuf == buf) {
 143:     rcline[ng] = safemalloc((MEM_SIZE)(s-buf)+1);
 144:                     /* grab a new rc line */
 145:     strcpy(rcline[ng], buf);    /* and load it */
 146:     }
 147:     else {
 148:     mybuf = saferealloc(mybuf,(MEM_SIZE)(s-mybuf)+1);
 149:                     /* be nice to the heap */
 150:     rcline[ng] = mybuf;
 151:     }
 152:     *(rcline[ng] + rcnums[ng] - 1) = '\0';
 153:     if (rcchar[ng] == NEGCHAR) {    /* did they unsubscribe? */
 154:     printf(unsubto,ngname) FLUSH;
 155:     toread[ng] = TR_UNSUB;      /* make line invisible */
 156:     }
 157:     else
 158:     /*NOSTRICT*/
 159:     toread[ng] = (ART_UNREAD)count;     /* remember how many unread there are */
 160: }
 161: 
 162: /* mark an article unread, keeping track of toread[] */
 163: 
 164: void
 165: onemore(artnum)
 166: ART_NUM artnum;
 167: {
 168: #ifdef DEBUGGING
 169:     if (debug && artnum < firstbit) {
 170:     printf("onemore: %d < %d\n",artnum,firstbit) FLUSH;
 171:     return;
 172:     }
 173: #endif
 174:     if (ctl_read(artnum)) {
 175:     ctl_clear(artnum);
 176:     ++toread[ng];
 177:     }
 178: }
 179: 
 180: /* mark an article read, keeping track of toread[] */
 181: 
 182: void
 183: oneless(artnum)
 184: ART_NUM artnum;
 185: {
 186: #ifdef DEBUGGING
 187:     if (debug && artnum < firstbit) {
 188:     printf("oneless: %d < %d\n",artnum,firstbit) FLUSH;
 189:     return;
 190:     }
 191: #endif
 192:     if (!ctl_read(artnum)) {
 193:     ctl_set(artnum);
 194:     if (toread[ng] > TR_NONE)
 195:         --toread[ng];
 196:     }
 197: }
 198: 
 199: /* mark an article as unread, making sure that firstbit is properly handled */
 200: /* cross-references are left as read in the other newsgroups */
 201: 
 202: void
 203: unmark_as_read(artnum)
 204: ART_NUM artnum;
 205: {
 206:     check_first(artnum);
 207:     onemore(artnum);
 208: #ifdef MCHASE
 209:     if (!parse_maybe(artnum))
 210:     chase_xrefs(artnum,FALSE);
 211: #endif
 212: }
 213: 
 214: #ifdef DELAYMARK
 215: /* temporarily mark article as read.  When newsgroup is exited, articles */
 216: /* will be marked as unread.  Called via M command */
 217: 
 218: void
 219: delay_unmark(artnum)
 220: ART_NUM artnum;
 221: {
 222:     if (dmfp == Nullfp) {
 223:     dmfp = fopen(dmname,"w");
 224:     if (dmfp == Nullfp) {
 225:         printf(cantcreate,dmname) FLUSH;
 226:         sig_catcher(0);
 227:     }
 228:     }
 229:     oneless(artnum);            /* set the correct bit */
 230:     dmcount++;
 231:     fprintf(dmfp,"%ld\n",(long)artnum);
 232: }
 233: #endif
 234: 
 235: /* mark article as read.  If article is cross referenced to other */
 236: /* newsgroups, mark them read there also. */
 237: 
 238: void
 239: mark_as_read(artnum)
 240: ART_NUM artnum;
 241: {
 242:     oneless(artnum);            /* set the correct bit */
 243:     checkcount++;           /* get more worried about crashes */
 244:     chase_xrefs(artnum,TRUE);
 245: }
 246: 
 247: /* make sure we have bits set correctly down to firstbit */
 248: 
 249: void
 250: check_first(min)
 251: ART_NUM min;
 252: {
 253:     register ART_NUM i = firstbit;
 254: 
 255:     if (min < absfirst)
 256:     min = absfirst;
 257:     if (min < i) {
 258:     for (i--; i>=min; i--)
 259:         ctl_set(i);     /* mark as read */
 260:     firstart = firstbit = min;
 261:     }
 262: }
 263: 
 264: /* bring back articles marked with M */
 265: 
 266: #ifdef DELAYMARK
 267: void
 268: yankback()
 269: {
 270:     register ART_NUM anum;
 271: 
 272:     if (dmfp) {         /* delayed unmarks pending? */
 273: #ifdef VERBOSE
 274:     printf("\nReturning %ld Marked article%s...\n",(long)dmcount,
 275:         dmcount == 1 ? nullstr : "s") FLUSH;
 276: #endif
 277:     fclose(dmfp);
 278:     if (dmfp = fopen(dmname,"r")) {
 279:         while (fgets(buf,sizeof buf,dmfp) != Nullch) {
 280:         anum = (ART_NUM)atol(buf);
 281:         /*NOSTRICT*/
 282:         onemore(anum);             /* then unmark them */
 283: #ifdef MCHASE
 284:         chase_xrefs(anum,FALSE);
 285: #endif
 286:         }
 287:         fclose(dmfp);
 288:         dmfp = Nullfp;
 289:         UNLINK(dmname);     /* and be tidy */
 290:     }
 291:     else {
 292:         printf(cantopen,dmname) FLUSH;
 293:         sig_catcher(0);
 294:     }
 295:     }
 296:     dmcount = 0;
 297: }
 298: #endif
 299: 
 300: /* run down xref list and mark as read or unread */
 301: 
 302: int
 303: chase_xrefs(artnum,markread)
 304: ART_NUM artnum;
 305: int markread;
 306: {
 307: #ifdef ASYNC_PARSE
 308:     if (parse_maybe(artnum))        /* make sure we have right header */
 309:     return -1;
 310: #endif
 311: #ifdef DBM
 312:     {
 313:     datum lhs, rhs;
 314:     datum fetch();
 315:     register char *idp;
 316:     char *ident_buf;
 317:     static FILE * hist_file = Nullfp;
 318: #else
 319:     if (
 320: #ifdef DEBUGGING
 321:     debug & DEB_FEED_XREF ||
 322: #endif
 323:     htype[XREF_LINE].ht_minpos >= 0) {
 324:                     /* are there article# xrefs? */
 325: #endif DBM
 326:     char *xref_buf, *curxref;
 327:     register char *xartnum;
 328:     char *rver_buf = Nullch;
 329:     static char *inews_site = Nullch;
 330:     register ART_NUM x;
 331:     char tmpbuf[128];
 332: 
 333: #ifdef DBM
 334:     rver_buf = fetchlines(artnum,NGS_LINE);
 335:                     /* get Newsgroups */
 336:     if (!index(rver_buf,','))   /* if no comma, no Xref! */
 337:         return 0;
 338:     if (hist_file == Nullfp) {  /* Init. file accesses */
 339: #ifdef DEBUGGING
 340:         if (debug)
 341:         printf ("chase_xref: opening files\n");
 342: #endif
 343:         dbminit(filexp(ARTFILE));
 344:         if ((hist_file = fopen (filexp(ARTFILE), "r")) == Nullfp)
 345:         return 0;
 346:     }
 347:     xref_buf = safemalloc((MEM_SIZE)BUFSIZ);
 348:     ident_buf = fetchlines(artnum,MESSID_LINE);
 349:                     /* get Message-ID */
 350: #ifdef DEBUGGING
 351:     if (debug)
 352:         printf ("chase_xref: Message-ID: %s\n", ident_buf);
 353: #endif
 354:     idp = ident_buf;
 355:     while (*++idp)          /* make message-id case insensitive */
 356:         if (isupper(*idp))
 357:             *idp = tolower (*idp);
 358:     lhs.dptr = ident_buf;       /* look up article by id */
 359:     lhs.dsize = strlen(lhs.dptr) + 1;
 360:     rhs = fetch(lhs);       /* fetch the record */
 361:     if (rhs.dptr == NULL)       /* if null, nothing there */
 362:         goto wild_goose;
 363:     fseek (hist_file, *((long *)rhs.dptr), 0);
 364:                     /* datum returned is position in hist file */
 365:     fgets (xref_buf, BUFSIZ, hist_file);
 366: #ifdef DEBUGGING
 367:     if (debug)
 368:         printf ("Xref from history: %s\n", xref_buf);
 369: #endif
 370:     curxref = cpytill(tmpbuf, xref_buf, '\t') + 1;
 371:     curxref = cpytill(tmpbuf, curxref, '\t') + 1;
 372: #ifdef DEBUGGING
 373:     if (debug)
 374:         printf ("chase_xref: curxref: %s\n", curxref);
 375: #endif
 376: #else !DBM
 377: #ifdef DEBUGGING
 378:     if (htype[XREF_LINE].ht_minpos >= 0)
 379: #endif
 380:         xref_buf = fetchlines(artnum,XREF_LINE);
 381:                     /* get xrefs list */
 382: #ifdef DEBUGGING
 383:     else {
 384:         xref_buf = safemalloc((MEM_SIZE)100);
 385:         printf("Give Xref: ") FLUSH;
 386:         gets(xref_buf);
 387:     }
 388: #endif
 389: #ifdef DEBUGGING
 390:     if (debug & DEB_XREF_MARKER)
 391:         printf("Xref: %s\n",xref_buf) FLUSH;
 392: #endif
 393:     curxref = cpytill(tmpbuf,xref_buf,' ') + 1;
 394: 
 395:     /* Make sure site name on Xref matches what inews thinks site is.
 396: 	 * Check first against last inews_site.  If it matches, fine.
 397: 	 * If not, fetch inews_site from current Relay-Version line and
 398: 	 * check again.  This is so that if the new administrator decides
 399: 	 * to change the system name as known to inews, rn will still do
 400: 	 * Xrefs correctly--each article need only match itself to be valid.
 401: 	 */
 402:     if (inews_site == Nullch || strNE(tmpbuf,inews_site)) {
 403:         char *t;
 404: 
 405:         if (inews_site != Nullch)
 406:         free(inews_site);
 407: #ifndef NORELAY
 408:         rver_buf = fetchlines(artnum,RVER_LINE);
 409:         if ((t = instr(rver_buf,"; site ")) == Nullch)
 410: #else NORELAY
 411:           /* In version 2.10.3 of news or afterwards, the Relay-Version
 412:            * and Posting-Version header lines have been removed.  For
 413:            * the code below to work as intended, I have modified it to
 414:            * extract the first component of the Path header line.  This
 415:            * should give the same effect as did the old code with respect
 416:            * to the use of the Relay-Version site name.
 417:            */
 418:           rver_buf = fetchlines(artnum,PATH_LINE);
 419:           if ((t = instr(rver_buf,"!")) == Nullch)
 420: #endif NORELAY
 421:         inews_site = savestr(nullstr);
 422:         else {
 423:         char new_site[128];
 424: 
 425: #ifndef NORELAY
 426:         cpytill(new_site,t + 7,'.');
 427: #else NORELAY
 428:               cpytill(new_site,rver_buf,'!');
 429: #endif NORELAY
 430:         inews_site = savestr(new_site);
 431:         }
 432:         if (strNE(tmpbuf,inews_site)) {
 433: #ifdef DEBUGGING
 434:         if (debug)
 435:             printf("Xref not from %s--ignoring\n",inews_site) FLUSH;
 436: #endif
 437:         goto wild_goose;
 438:         }
 439:     }
 440: #endif DBM
 441:     while (*curxref) {
 442:                     /* for each newsgroup */
 443:         curxref = cpytill(tmpbuf,curxref,' ');
 444: #ifdef DBM
 445:         xartnum = index(tmpbuf,'/');
 446: #else
 447:         xartnum = index(tmpbuf,':');
 448: #endif DBM
 449:         if (!xartnum)       /* probably an old-style Xref */
 450:         break;
 451:         *xartnum++ = '\0';
 452:         if (strNE(tmpbuf,ngname)) {/* not the current newsgroup? */
 453:         x = atol(xartnum);
 454:         if (x)
 455:             if (markread) {
 456:             if (addartnum(x,tmpbuf))
 457:                 goto wild_goose;
 458:             }
 459: #ifdef MCHASE
 460:             else
 461:             subartnum(x,tmpbuf);
 462: #endif
 463:         }
 464:         while (*curxref && isspace(*curxref))
 465:         curxref++;
 466:     }
 467:       wild_goose:
 468:     free(xref_buf);
 469: #ifdef DBM
 470:     free(ident_buf);
 471: #endif DBM
 472:     if (rver_buf != Nullch)
 473:         free(rver_buf);
 474:     }
 475:     return 0;
 476: }
 477: 
 478: int
 479: initctl()
 480: {
 481:     char *mybuf = buf;          /* place to decode rc line */
 482:     register char *s, *c, *h;
 483:     register long i;
 484:     register ART_NUM unread;
 485: 
 486: #ifdef DELAYMARK
 487:     dmcount = 0;
 488: #endif
 489:     if ((lastart = getngsize(ng)) < 0)  /* this cannot happen (laugh here) */
 490:     return -1;
 491: 
 492:     absfirst = getabsfirst(ng,lastart); /* remember first existing article */
 493:     if (!absfirst)          /* no articles at all? */
 494:     absfirst = 1;           /* pretend there is one */
 495: #ifndef lint
 496:     ctlsize = (MEM_SIZE)(OFFSET(lastart)/BITSPERBYTE+20);
 497: #endif lint
 498:     ctlarea = safemalloc(ctlsize);  /* allocate control area */
 499: 
 500:     /* now modify ctlarea to reflect what has already been read */
 501: 
 502:     for (s = rcline[ng] + rcnums[ng]; *s == ' '; s++) ;
 503:                     /* find numbers in rc line */
 504:     i = strlen(s);
 505: #ifndef lint
 506:     if (i >= LBUFLEN-2)         /* bigger than buf? */
 507:     mybuf = safemalloc((MEM_SIZE)(i+2));
 508: #endif lint
 509:     strcpy(mybuf,s);            /* make scratch copy of line */
 510:     mybuf[i++] = ',';           /* put extra comma on the end */
 511:     mybuf[i] = '\0';
 512:     s = mybuf;              /* initialize the for loop below */
 513:     if (strnEQ(s,"1-",2)) {     /* can we save some time here? */
 514:     firstbit = atol(s+2)+1;     /* ignore first range thusly */
 515:     s=index(s,',') + 1;
 516:     }
 517:     else
 518:     firstbit = 1;           /* all the bits are valid for now */
 519:     if (absfirst > firstbit) {      /* do we know already? */
 520:     firstbit = absfirst;        /* no point calling getngmin again */
 521:     }
 522:     else if (artopen(firstbit) == Nullfp) {
 523:                     /* first unread article missing? */
 524:     i = getngmin(".",firstbit); /* see if expire has been busy */
 525:     if (i) {            /* avoid a bunch of extra opens */
 526:         firstbit = i;
 527:     }
 528:     }
 529:     firstart = firstbit;        /* firstart > firstbit in KILL */
 530: #ifdef PENDING
 531: #   ifdef CACHESUBJ
 532:     subj_to_get = firstbit;
 533: #   endif
 534: #endif
 535:     unread = lastart - firstbit + 1;    /* assume this range unread */
 536:     for (i=OFFSET(firstbit)/BITSPERBYTE; i<ctlsize; i++)
 537:     ctlarea[i] = 0;         /* assume unread */
 538: #ifdef DEBUGGING
 539:     if (debug & DEB_CTLAREA_BITMAP) {
 540:     printf("\n%s\n",mybuf) FLUSH;
 541:     for (i=1; i <= lastart; i++)
 542:         if (! was_read(i))
 543:         printf("%ld ",(long)i) FLUSH;
 544:     }
 545: #endif
 546:     for ( ; (c = index(s,',')) != Nullch; s = ++c) {
 547:                     /* for each range */
 548:     ART_NUM min, max;
 549: 
 550:     *c = '\0';          /* do not let index see past comma */
 551:     if ((h = index(s,'-')) != Nullch) { /* is there a -? */
 552:         min = atol(s);
 553:         max = atol(h+1);
 554:         if (min < firstbit)     /* make sure range is in range */
 555:         min = firstbit;
 556:         if (max > lastart)
 557:         max = lastart;
 558:         if (min <= max)     /* non-null range? */
 559:         unread -= max - min + 1;/* adjust unread count */
 560:         for (i=min; i<=max; i++)    /* for all articles in range */
 561:         ctl_set(i);     /* mark them read */
 562:     }
 563:     else if ((i = atol(s)) >= firstbit && i <= lastart) {
 564:                     /* is single number reasonable? */
 565:         ctl_set(i);         /* mark it read */
 566:         unread--;           /* decrement articles to read */
 567:     }
 568: #ifdef DEBUGGING
 569:     if (debug & DEB_CTLAREA_BITMAP) {
 570:         printf("\n%s\n",s) FLUSH;
 571:         for (i=1; i <= lastart; i++)
 572:         if (! was_read(i))
 573:             printf("%ld ",(long)i) FLUSH;
 574:     }
 575: #endif
 576:     }
 577: #ifdef DEBUGGING
 578:     if (debug & DEB_CTLAREA_BITMAP) {
 579:     fputs("\n(hit CR)",stdout) FLUSH;
 580:     gets(cmd_buf);
 581:     }
 582: #endif
 583:     if (mybuf != buf)
 584:     free(mybuf);
 585:     toread[ng] = unread;
 586:     return 0;
 587: }
 588: 
 589: void
 590: grow_ctl()
 591: {
 592:     ART_NUM newlast;
 593:     ART_NUM tmpfirst;
 594:     MEM_SIZE newsize;
 595:     register ART_NUM i;
 596: 
 597:     forcegrow = FALSE;
 598:     newlast = getngsize(ng);
 599:     if (newlast > lastart) {
 600:     ART_NUM tmpart = art;
 601: #ifndef lint
 602:     newsize = (MEM_SIZE)(OFFSET(newlast)/BITSPERBYTE+2);
 603: #else
 604:     newsize = Null(MEM_SIZE);
 605: #endif lint
 606:     if (newsize > ctlsize) {
 607:         newsize += 20;
 608:         ctlarea = saferealloc(ctlarea,newsize);
 609:         ctlsize = newsize;
 610:     }
 611:     toread[ng] += (ART_UNREAD)(newlast-lastart);
 612:     for (i=lastart+1; i<=newlast; i++)
 613:         ctl_clear(i);   /* these articles are unread */
 614: #ifdef CACHESUBJ
 615:     if (subj_list != Null(char**)) {
 616: #ifndef lint
 617:         subj_list = (char**)saferealloc((char*)subj_list,
 618:           (MEM_SIZE)((OFFSET(newlast)+2)*sizeof(char *)) );
 619: #endif lint
 620:         for (i=lastart+1; i<=newlast; i++)
 621:         subj_list[OFFSET(i)] = Nullch;
 622:     }
 623: #endif
 624:     tmpfirst = lastart+1;
 625:     lastart = newlast;
 626: #ifdef KILLFILES
 627: #ifdef VERBOSE
 628:     IF(verbose)
 629:         sprintf(buf,
 630:         "%ld more article%s arrived--looking for more to kill...\n\n",
 631:         (long)(lastart - tmpfirst + 1),
 632:         (lastart > tmpfirst ? "s have" : " has" ) );
 633:     ELSE            /* my, my, how clever we are */
 634: #endif
 635: #ifdef TERSE
 636:         strcpy(buf, "More news--killing...\n\n");
 637: #endif
 638:     kill_unwanted(tmpfirst,buf,TRUE);
 639: #endif
 640:     art = tmpart;
 641:     }
 642: }

Defined functions

bits_init defined in line 47; used 2 times
chase_xrefs defined in line 302; used 4 times
checkpoint_rc defined in line 59; used 3 times
delay_unmark defined in line 218; used 3 times
grow_ctl defined in line 589; used 2 times
initctl defined in line 478; used 2 times
oneless defined in line 182; used 7 times
onemore defined in line 164; used 3 times
restore_ng defined in line 82; used 4 times
unmark_as_read defined in line 202; used 3 times
yankback defined in line 267; used 5 times

Defined variables

ctlsize defined in line 45; used 5 times
Last modified: 1987-03-16
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4535
Valid CSS Valid XHTML 1.0 Strict