1: /*************************************************************************
   2:  * This program is copyright (C) 1985, 1986 by Jonathan Payne.  It is    *
   3:  * provided to you without charge for use only on a licensed Unix        *
   4:  * system.  You may copy JOVE provided that this notice is included with *
   5:  * the copy.  You may not sell copies of this program or versions        *
   6:  * modified for use on microcomputer systems, unless the copies are      *
   7:  * included with a Unix system distribution and the source is provided.  *
   8:  *************************************************************************/
   9: 
  10: /* Recovers JOVE files after a system/editor crash.
  11:    Usage: recover [-d directory] [-syscrash]
  12:    The -syscrash option is specified in /etc/rc and what it does it
  13:    move all the jove tmp files from TMP_DIR to REC_DIR.
  14: 
  15:    The -d option lets you specify the directory to search for tmp files when
  16:    the default isn't the right one.
  17: 
  18:    Look in Makefile to change the default directories. */
  19: 
  20: #include <stdio.h>  /* Do stdio first so it doesn't override OUR
  21: 			   definitions. */
  22: #undef EOF
  23: #undef BUFSIZ
  24: #undef putchar
  25: 
  26: #include "jove.h"
  27: #include "temp.h"
  28: #include "rec.h"
  29: #include <signal.h>
  30: #include <sys/file.h>
  31: #include <sys/stat.h>
  32: #include <sys/dir.h>
  33: 
  34: #ifndef L_SET
  35: #	define L_SET  0
  36: #	define L_INCR 1
  37: #endif
  38: 
  39: char    blk_buf[BUFSIZ];
  40: int nleft;
  41: FILE    *ptrs_fp;
  42: int data_fd;
  43: struct rec_head Header;
  44: char    datafile[40],
  45:     pntrfile[40];
  46: long    Nchars,
  47:     Nlines;
  48: char    tty[] = "/dev/tty";
  49: int UserID,
  50:     Verbose = 0;
  51: 
  52: struct file_pair {
  53:     char    *file_data,
  54:         *file_rec;
  55: #define INSPECTED   01
  56:     int file_flags;
  57:     struct file_pair    *file_next;
  58: } *First = 0,
  59:   *Last = 0;
  60: 
  61: struct rec_entry    *buflist[100] = {0};
  62: 
  63: #ifndef BSD4_2
  64: 
  65: typedef struct {
  66:     int d_fd;       /* File descriptor for this directory */
  67: } DIR;
  68: 
  69: DIR *
  70: opendir(dir)
  71: char    *dir;
  72: {
  73:     DIR *dp = (DIR *) malloc(sizeof *dp);
  74: 
  75:     if ((dp->d_fd = open(dir, 0)) == -1)
  76:         return NULL;
  77:     return dp;
  78: }
  79: 
  80: closedir(dp)
  81: DIR *dp;
  82: {
  83:     (void) close(dp->d_fd);
  84:     free(dp);
  85: }
  86: 
  87: struct direct *
  88: readdir(dp)
  89: DIR *dp;
  90: {
  91:     static struct direct    dir;
  92: 
  93:     do
  94:         if (read(dp->d_fd, &dir, sizeof dir) != sizeof dir)
  95:             return NULL;
  96:     while (dir.d_ino == 0);
  97: 
  98:     return &dir;
  99: }
 100: 
 101: #endif BSD4_2
 102: 
 103: /* Get a line at `tl' in the tmp file into `buf' which should be LBSIZE
 104:    long. */
 105: 
 106: char *
 107: getline(tl, buf)
 108: disk_line   tl;
 109: char    *buf;
 110: {
 111:     register char   *bp,
 112:             *lp;
 113:     register int    nl;
 114: 
 115:     lp = buf;
 116:     bp = getblock(tl);
 117:     nl = nleft;
 118:     tl &= ~OFFMSK;
 119: 
 120:     while (*lp++ = *bp++) {
 121:         if (--nl == 0) {
 122:             /* += INCRMT moves tl to the next block in
 123: 			   the tmp file. */
 124:             bp = getblock(tl += INCRMT);
 125:             nl = nleft;
 126:         }
 127:     }
 128: }
 129: 
 130: char *
 131: getblock(atl)
 132: disk_line   atl;
 133: {
 134:     int bno,
 135:         off;
 136:     static int  curblock = -1;
 137: 
 138:     bno = (atl >> OFFBTS) & BLKMSK;
 139:     off = (atl << SHFT) & LBTMSK;
 140:     nleft = BUFSIZ - off;
 141: 
 142:     if (bno != curblock) {
 143:         lseek(data_fd, (long) bno * BUFSIZ, L_SET);
 144:         read(data_fd, blk_buf, BUFSIZ);
 145:         curblock = bno;
 146:     }
 147:     return blk_buf + off;
 148: }
 149: 
 150: char *
 151: copystr(s)
 152: char    *s;
 153: {
 154:     char    *str;
 155: 
 156:     str = malloc(strlen(s) + 1);
 157:     strcpy(str, s);
 158: 
 159:     return str;
 160: }
 161: 
 162: /* Scandir returns the number of entries or -1 if the directory cannoot
 163:    be opened or malloc fails. */
 164: 
 165: scandir(dir, nmptr, qualify, sorter)
 166: char    *dir;
 167: struct direct   ***nmptr;
 168: int (*qualify)();
 169: struct direct   *(*sorter)();
 170: {
 171:     DIR *dirp;
 172:     struct direct   *entry,
 173:             **ourarray;
 174:     int nalloc = 10,
 175:         nentries = 0;
 176: 
 177:     if ((dirp = opendir(dir)) == NULL)
 178:         return -1;
 179:     ourarray = (struct direct **) malloc(nalloc * sizeof (struct direct *));
 180:     while ((entry = readdir(dirp)) != NULL) {
 181:         if (qualify != 0 && (*qualify)(entry) == 0)
 182:             continue;
 183:         if (nentries == nalloc) {
 184:             ourarray = (struct direct **) realloc(ourarray, (nalloc += 10) * sizeof (struct direct));
 185:             if (ourarray == NULL)
 186:                 return -1;
 187:         }
 188:         ourarray[nentries] = (struct direct *) malloc(sizeof *entry);
 189:         *ourarray[nentries] = *entry;
 190:         nentries++;
 191:     }
 192:     closedir(dirp);
 193:     if (nentries != nalloc)
 194:         ourarray = (struct direct **) realloc(ourarray,
 195:                     (nentries * sizeof (struct direct)));
 196:     if (sorter != 0)
 197:         qsort(ourarray, nentries, sizeof (struct direct **), sorter);
 198:     *nmptr = ourarray;
 199: 
 200:     return nentries;
 201: }
 202: 
 203: alphacomp(a, b)
 204: struct direct   **a,
 205:         **b;
 206: {
 207:     return strcmp((*a)->d_name, (*b)->d_name);
 208: }
 209: 
 210: char    *CurDir;
 211: 
 212: /* Scan the DIRNAME directory for jove tmp files, and make a linked list
 213:    out of them. */
 214: 
 215: get_files(dirname)
 216: char    *dirname;
 217: {
 218:     int add_name();
 219:     struct direct   **nmptr;
 220: 
 221:     CurDir = dirname;
 222:     scandir(dirname, &nmptr, add_name, (int (*)())0);
 223: }
 224: 
 225: add_name(dp)
 226: struct direct   *dp;
 227: {
 228:     char    dfile[128],
 229:         rfile[128];
 230:     struct file_pair    *fp;
 231:     struct rec_head     header;
 232:     int fd;
 233: 
 234:     if (strncmp(dp->d_name, REC_BASE, strlen(REC_BASE)) != 0)
 235:         return 0;
 236:     /* If we get here, we found a "recover" tmp file, so now
 237: 	   we look for the corresponding "data" tmp file.  First,
 238: 	   though, we check to see whether there is anything in
 239: 	   the "recover" file.  If it's 0 length, there's no point
 240: 	   in saving its name. */
 241:     (void) sprintf(rfile, "%s/%s", CurDir, dp->d_name);
 242:     (void) sprintf(dfile, "%s/jove%s", CurDir, dp->d_name + strlen(REC_BASE));
 243:     if ((fd = open(rfile, 0)) != -1) {
 244:         if ((read(fd, (char *) &header, sizeof header) != sizeof header)) {
 245:             close(fd);
 246:                 return 0;
 247:         } else
 248:             close(fd);
 249:     }
 250:     if (access(dfile, 0) != 0) {
 251:         fprintf(stderr, "recover: can't find the data file for %s/%s\n", TMP_DIR, dp->d_name);
 252:         fprintf(stderr, "so deleting...\n");
 253:         (void) unlink(rfile);
 254:         (void) unlink(dfile);
 255:         return 0;
 256:     }
 257:     /* If we get here, we've found both files, so we put them
 258: 	   in the list. */
 259:     fp = (struct file_pair *) malloc (sizeof *fp);
 260:     if ((char *) fp == 0) {
 261:         fprintf(stderr, "recover: cannot malloc for file_pair.\n");
 262:         exit(-1);
 263:     }
 264:     fp->file_data = copystr(dfile);
 265:     fp->file_rec = copystr(rfile);
 266:     fp->file_flags = 0;
 267:     fp->file_next = First;
 268:     First = fp;
 269: 
 270:     return 1;
 271: }
 272: 
 273: options()
 274: {
 275:     printf("Options are:\n");
 276:     printf("	?		list options.\n");
 277:     printf("	get		get a buffer to a file.\n");
 278:     printf("	list		list known buffers.\n");
 279:     printf("	print		print a buffer to terminal.\n");
 280:     printf("	quit		quit and delete jove tmp files.\n");
 281:     printf("	restore		restore all buffers.\n");
 282: }
 283: 
 284: /* Returns a legitimate buffer # */
 285: 
 286: struct rec_entry **
 287: getsrc()
 288: {
 289:     char    name[128];
 290:     int number;
 291: 
 292:     for (;;) {
 293:         tellme("Which buffer ('?' for list)? ", name);
 294:         if (name[0] == '?')
 295:             list();
 296:         else if (name[0] == '\0')
 297:             return 0;
 298:         else if ((number = atoi(name)) > 0 && number <= Header.Nbuffers)
 299:             return &buflist[number];
 300:         else {
 301:             int i;
 302: 
 303:             for (i = 1; i <= Header.Nbuffers; i++)
 304:                 if (strcmp(buflist[i]->r_bname, name) == 0)
 305:                     return &buflist[i];
 306:             printf("%s: unknown buffer.\n", name);
 307:         }
 308:     }
 309: }
 310: 
 311: /* Get a destination file name. */
 312: 
 313: static char *
 314: getdest()
 315: {
 316:     static char filebuf[256];
 317: 
 318:     tellme("Output file: ", filebuf);
 319:     if (filebuf[0] == '\0')
 320:         return 0;
 321:     return filebuf;
 322: }
 323: 
 324: #include "ctype.h"
 325: 
 326: char *
 327: readword(buf)
 328: char    *buf;
 329: {
 330:     int c;
 331:     char    *bp = buf;
 332: 
 333:     while (index(" \t\n", c = getchar()))
 334:         ;
 335: 
 336:     do {
 337:         if (index(" \t\n", c))
 338:             break;
 339:         *bp++ = c;
 340:     } while ((c = getchar()) != EOF);
 341:     *bp = 0;
 342: 
 343:     return buf;
 344: }
 345: 
 346: tellme(quest, answer)
 347: char    *quest,
 348:     *answer;
 349: {
 350:     if (stdin->_cnt <= 0) {
 351:         printf("%s", quest);
 352:         fflush(stdout);
 353:     }
 354:     readword(answer);
 355: }
 356: 
 357: /* Print the specified file to strandard output. */
 358: 
 359: jmp_buf int_env;
 360: 
 361: catch()
 362: {
 363:     longjmp(int_env, 1);
 364: }
 365: 
 366: restore()
 367: {
 368:     register int    i;
 369:     char    tofile[100],
 370:         answer[30];
 371:     int nrecovered = 0;
 372: 
 373:     for (i = 1; i <= Header.Nbuffers; i++) {
 374:         (void) sprintf(tofile, "#%s", buflist[i]->r_bname);
 375: tryagain:
 376:         printf("Restoring %s to %s, okay?", buflist[i]->r_bname,
 377:                              tofile);
 378:         tellme(" ", answer);
 379:         switch (answer[0]) {
 380:         case 'y':
 381:             break;
 382: 
 383:         case 'n':
 384:             continue;
 385: 
 386:         default:
 387:             tellme("What file should I use instead? ", tofile);
 388:             goto tryagain;
 389:         }
 390:         get(&buflist[i], tofile);
 391:         nrecovered++;
 392:     }
 393:     printf("Recovered %d buffers.\n", nrecovered);
 394: }
 395: 
 396: get(src, dest)
 397: struct rec_entry    **src;
 398: char    *dest;
 399: {
 400:     FILE    *outfile;
 401: 
 402:     if (src == 0 || dest == 0)
 403:         return;
 404:     (void) signal(SIGINT, catch);
 405:     if (setjmp(int_env) == 0) {
 406:         if ((outfile = fopen(dest, "w")) == NULL) {
 407:             printf("recover: cannot create %s.\n", dest);
 408:             return;
 409:         }
 410:         seekto(src - buflist);
 411:         if (dest != tty)
 412:             printf("\"%s\"", dest);
 413:         dump_file(outfile);
 414:     } else
 415:         printf("\nAborted!\n");
 416:     fclose(outfile);
 417:     if (dest != tty)
 418:         printf(" %ld lines, %ld characters.\n", Nlines, Nchars);
 419:     (void) signal(SIGINT, SIG_DFL);
 420: }
 421: 
 422: char **
 423: scanvec(args, str)
 424: register char   **args,
 425:         *str;
 426: {
 427:     while (*args) {
 428:         if (strcmp(*args, str) == 0)
 429:             return args;
 430:         args++;
 431:     }
 432:     return 0;
 433: }
 434: 
 435: read_rec(recptr)
 436: struct rec_entry    *recptr;
 437: {
 438:     if (fread((char *) recptr, sizeof *recptr, 1, ptrs_fp) != 1)
 439:         fprintf(stderr, "recover: cannot read record.\n");
 440: }
 441: 
 442: seekto(which)
 443: {
 444:     struct rec_entry    rec;
 445: 
 446:     fseek(ptrs_fp, (long) (sizeof Header), L_SET);
 447: 
 448:     while (which-- > 1) {
 449:         read_rec(&rec);
 450:         if (fseek(ptrs_fp, (long) rec.r_nlines * sizeof (disk_line),
 451:             L_INCR) == -1)
 452:             printf("recover: improper fseek!\n");
 453:     }
 454: }
 455: 
 456: makblist()
 457: {
 458:     int i;
 459: 
 460:     for (i = 1; i <= Header.Nbuffers; i++) {
 461:         seekto(i);
 462:         if (buflist[i] == 0)
 463:             buflist[i] = (struct rec_entry *) malloc (sizeof (struct rec_entry));
 464:         read_rec(buflist[i]);
 465:     }
 466:     if (buflist[i]) {
 467:         free((char *) buflist[i]);
 468:         buflist[i] = 0;
 469:     }
 470: }
 471: 
 472: disk_line
 473: getaddr(fp)
 474: register FILE   *fp;
 475: {
 476:     register int    nchars = sizeof (disk_line);
 477:     disk_line   addr;
 478:     register char   *cp = (char *) &addr;
 479: 
 480:     while (--nchars >= 0)
 481:         *cp++ = getc(fp);
 482: 
 483:     return addr;
 484: }
 485: 
 486: dump_file(out)
 487: FILE    *out;
 488: {
 489:     struct rec_entry    record;
 490:     register int    nlines;
 491:     register disk_line  daddr;
 492:     char    buf[BUFSIZ];
 493: 
 494:     read_rec(&record);
 495:     nlines = record.r_nlines;
 496:     Nchars = Nlines = 0L;
 497:     while (--nlines >= 0) {
 498:         daddr = getaddr(ptrs_fp);
 499:         getline(daddr, buf);
 500:         Nlines++;
 501:         Nchars += 1 + strlen(buf);
 502:         fputs(buf, out);
 503:         if (nlines > 0)
 504:             fputc('\n', out);
 505:     }
 506:     if (out != stdout)
 507:         fclose(out);
 508: }
 509: 
 510: /* List all the buffers. */
 511: 
 512: list()
 513: {
 514:     int i;
 515: 
 516:     for (i = 1; i <= Header.Nbuffers; i++)
 517:         printf("%d) buffer %s  \"%s\" (%d lines)\n", i,
 518:             buflist[i]->r_bname,
 519:             buflist[i]->r_fname,
 520:             buflist[i]->r_nlines);
 521: }
 522: 
 523: doit(fp)
 524: struct file_pair    *fp;
 525: {
 526:     char    answer[30];
 527:     char    *datafile = fp->file_data,
 528:         *pntrfile = fp->file_rec;
 529: 
 530:     ptrs_fp = fopen(pntrfile, "r");
 531:     if (ptrs_fp == NULL) {
 532:         if (Verbose)
 533:             fprintf(stderr, "recover: cannot read rec file (%s).\n", pntrfile);
 534:         return 0;
 535:     }
 536:     fread((char *) &Header, sizeof Header, 1, ptrs_fp);
 537:     if (Header.Uid != UserID)
 538:         return 0;
 539: 
 540:     /* Don't ask about JOVE's that are still running ... */
 541: #ifdef KILL0
 542:     if (kill(Header.Pid, 0) == 0)
 543:         return 0;
 544: #else
 545: #ifdef LSRHS
 546:     if (pexist(Header.Pid))
 547:         return 0;
 548: #endif LSRHS
 549: #endif KILL0
 550: 
 551:     if (Header.Nbuffers == 0) {
 552:         printf("There are no modified buffers in %s; should I delete the tmp file?", pntrfile);
 553:         ask_del(" ", fp);
 554:         return 1;
 555:     }
 556: 
 557:     if (Header.Nbuffers < 0) {
 558:         fprintf(stderr, "recover: %s doesn't look like a jove file.\n", pntrfile);
 559:         ask_del("Should I delete it? ", fp);
 560:         return 1;   /* We'll, we sort of found something. */
 561:     }
 562:     printf("Found %d buffer%s last updated: %s",
 563:         Header.Nbuffers,
 564:         Header.Nbuffers != 1 ? "s" : "",
 565:         ctime(&Header.UpdTime));
 566:     data_fd = open(datafile, 0);
 567:     if (data_fd == -1) {
 568:         fprintf(stderr, "recover: but I can't read the data file (%s).\n", datafile);
 569:         ask_del("Should I delete the tmp files? ", fp);
 570:         return 1;
 571:     }
 572:     makblist();
 573: 
 574:     for (;;) {
 575:         tellme("(Type '?' for options): ", answer);
 576:         switch (answer[0]) {
 577:         case '\0':
 578:             continue;
 579: 
 580:         case '?':
 581:             options();
 582:             break;
 583: 
 584:         case 'l':
 585:             list();
 586:             break;
 587: 
 588:         case 'p':
 589:             get(getsrc(), tty);
 590:             break;
 591: 
 592:         case 'q':
 593:             ask_del("Shall I delete the tmp files? ", fp);
 594:             return 1;
 595: 
 596:         case 'g':
 597:             {   /* So it asks for src first. */
 598:                 char    *dest;
 599:                 struct rec_entry    **src;
 600: 
 601:                 if ((src = getsrc()) == 0)
 602:                     break;
 603:                 dest = getdest();
 604:             get(src, dest);
 605:             break;
 606:             }
 607: 
 608:         case 'r':
 609:             restore();
 610:             break;
 611: 
 612:         default:
 613:             printf("I don't know how to \"%s\"!\n", answer);
 614:             break;
 615:         }
 616:     }
 617: }
 618: 
 619: ask_del(prompt, fp)
 620: char    *prompt;
 621: struct file_pair    *fp;
 622: {
 623:     char    yorn[20];
 624: 
 625:     tellme(prompt, yorn);
 626:     if (yorn[0] == 'y')
 627:         del_files(fp);
 628: }
 629: 
 630: del_files(fp)
 631: struct file_pair    *fp;
 632: {
 633:     (void) unlink(fp->file_data);
 634:     (void) unlink(fp->file_rec);
 635: }
 636: 
 637: savetmps()
 638: {
 639:     struct file_pair    *fp;
 640:     int status,
 641:         pid;
 642: 
 643:     if (strcmp(TMP_DIR, REC_DIR) == 0)
 644:         return;     /* Files are moved to the same place. */
 645:     get_files(TMP_DIR);
 646:     for (fp = First; fp != 0; fp = fp->file_next) {
 647:         switch (pid = fork()) {
 648:         case -1:
 649:             fprintf(stderr, "recover: can't fork\n!");
 650:             exit(-1);
 651: 
 652:         case 0:
 653:             execl("/bin/cp", "cp", fp->file_data, fp->file_rec, REC_DIR, 0);
 654:             fprintf(stderr, "recover: cannot execl /bin/cp.\n");
 655:             exit(-1);
 656: 
 657:         default:
 658:             while (wait(&status) != pid)
 659:                 ;
 660:             if (status != 0)
 661:                 fprintf(stderr, "recover: non-zero status (%d) returned from copy.\n", status);
 662:         }
 663:     }
 664: }
 665: 
 666: lookup(dir)
 667: char    *dir;
 668: {
 669:     struct file_pair    *fp;
 670:     struct rec_head     header;
 671:     char    yorn[20];
 672:     int nfound = 0,
 673:         this_one;
 674: 
 675:     get_files(dir);
 676:     for (fp = First; fp != 0; fp = fp->file_next) {
 677:         nfound += doit(fp);
 678:         if (ptrs_fp)
 679:             (void) fclose(ptrs_fp);
 680:         if (data_fd > 0)
 681:             (void) close(data_fd);
 682:     }
 683:     return nfound;
 684: }
 685: 
 686: main(argc, argv)
 687: int argc;
 688: char    *argv[];
 689: {
 690:     int nfound;
 691:     char    **argvp;
 692: 
 693:     UserID = getuid();
 694: 
 695:     if (scanvec(argv, "-help")) {
 696:         printf("recover: usage: recover [-d directory] [-syscrash]\n");
 697:         printf("Use \"recover\" after JOVE has died for some\n");
 698:         printf("unknown reason.\n\n");
 699:         printf("Use \"recover -syscrash\" when the system is in the process\n");
 700:         printf("of rebooting.  This is done automatically at reboot time\n");
 701:         printf("and so most of you don't have to worry about that.\n\n");
 702:         printf("Use \"recover -d directory\" when the tmp files are store\n");
 703:         printf("in DIRECTORY instead of the default one (%s).\n", TMP_DIR);
 704:         exit(0);
 705:     }
 706:     if (scanvec(argv, "-v"))
 707:         Verbose++;
 708:     if (scanvec(argv, "-syscrash")) {
 709:         printf("Recovering jove files ... ");
 710:         savetmps();
 711:         printf("Done.\n");
 712:         exit(0);
 713:     }
 714:     if (argvp = scanvec(argv, "-uid"))
 715:         UserID = atoi(argvp[1]);
 716:     if (argvp = scanvec(argv, "-d"))
 717:         nfound = lookup(argvp[1]);
 718:     else {
 719:         if ((nfound = lookup(REC_DIR)) ||
 720:             (nfound = lookup(TMP_DIR)))
 721:             ;
 722:     }
 723:     if (nfound == 0)
 724:         printf("There's nothing to recover.\n");
 725: }

Defined functions

add_name defined in line 225; used 2 times
alphacomp defined in line 203; never used
ask_del defined in line 619; used 4 times
catch defined in line 361; used 1 times
closedir defined in line 80; used 1 times
copystr defined in line 150; used 2 times
del_files defined in line 630; used 1 times
doit defined in line 523; used 1 times
dump_file defined in line 486; used 1 times
get defined in line 396; used 3 times
get_files defined in line 215; used 2 times
getaddr defined in line 472; used 1 times
getblock defined in line 130; used 4 times
getdest defined in line 313; used 1 times
getline defined in line 106; used 5 times
getsrc defined in line 286; used 2 times
list defined in line 512; used 2 times
lookup defined in line 666; used 3 times
main defined in line 686; never used
makblist defined in line 456; used 1 times
opendir defined in line 69; used 1 times
options defined in line 273; used 1 times
read_rec defined in line 435; used 3 times
readdir defined in line 87; used 1 times
readword defined in line 326; used 1 times
restore defined in line 366; used 1 times
savetmps defined in line 637; used 1 times
scandir defined in line 165; used 1 times
scanvec defined in line 422; used 5 times
seekto defined in line 442; used 2 times
tellme defined in line 346; used 6 times

Defined variables

CurDir defined in line 210; used 3 times
First defined in line 58; used 4 times
Header defined in line 43; used 16 times
Nchars defined in line 46; used 3 times
Nlines defined in line 47; used 3 times
UserID defined in line 49; used 3 times
Verbose defined in line 50; used 2 times
blk_buf defined in line 39; used 2 times
buflist defined in line 61; used 16 times
data_fd defined in line 42; used 6 times
datafile defined in line 44; used 3 times
int_env defined in line 359; used 2 times
nleft defined in line 40; used 3 times
pntrfile defined in line 45; used 5 times
tty defined in line 48; used 3 times

Defined struct's

file_pair defined in line 52; used 16 times

Defined macros

INSPECTED defined in line 55; never used
L_INCR defined in line 36; used 1 times
L_SET defined in line 35; used 3 times
Last modified: 1986-03-28
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2345
Valid CSS Valid XHTML 1.0 Strict