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

Defined functions

add_name defined in line 234; used 2 times
alphacomp defined in line 212; never used
ask_del defined in line 621; used 4 times
catch defined in line 370; used 1 times
closedir defined in line 82; used 1 times
copystr defined in line 159; used 2 times
del_files defined in line 632; used 1 times
doit defined in line 529; used 1 times
dump_file defined in line 493; used 1 times
get defined in line 405; used 3 times
get_files defined in line 224; used 2 times
getaddr defined in line 479; used 1 times
getblock defined in line 139; used 3 times
getdest defined in line 322; used 1 times
getsrc defined in line 295; used 2 times
list defined in line 518; used 3 times
lookup defined in line 671; used 2 times
main defined in line 693; never used
makblist defined in line 462; used 1 times
opendir defined in line 71; used 1 times
options defined in line 282; used 1 times
read_rec defined in line 443; used 1 times
readdir defined in line 89; used 1 times
readword defined in line 335; used 1 times
restore defined in line 375; used 1 times
savetmps defined in line 640; never used
scandir defined in line 174; used 1 times
scanvec defined in line 430; used 4 times
seekto defined in line 450; used 1 times
tellme defined in line 355; used 6 times

Defined variables

CurDir defined in line 219; used 3 times
Directory defined in line 52; used 2 times
First defined in line 60; used 4 times
Header defined in line 44; used 17 times
Nchars defined in line 47; used 3 times
Nlines defined in line 48; used 3 times
UserID defined in line 50; used 3 times
Verbose defined in line 51; used 2 times
blk_buf defined in line 40; used 2 times
buflist defined in line 63; used 18 times
data_fd defined in line 43; used 6 times
datafile defined in line 45; used 3 times
int_env defined in line 368; used 2 times
nleft defined in line 41; used 3 times
pntrfile defined in line 46; used 5 times
tty defined in line 49; used 3 times

Defined struct's

file_pair defined in line 54; used 16 times

Defined macros

INSPECTED defined in line 57; never used
L_INCR defined in line 37; never used
L_SET defined in line 36; used 4 times
STDIO defined in line 25; never used
Last modified: 1988-03-15
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4546
Valid CSS Valid XHTML 1.0 Strict