home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume2 / cdiff-v2 / cdiff.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-07  |  31.9 KB  |  1,507 lines

  1. /* Change the following as appropriate */
  2. #undef vms
  3. #undef unix
  4. #undef pdp11
  5. #undef OSK
  6. #undef DEBUG
  7. #define TURBO 1
  8.  
  9. #ifdef TURBO
  10. #include <alloc.h>
  11. #include <errno.h>
  12. #include <process.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16.  
  17. #else
  18. #include <stdio.h>
  19. #include <ctype.h>
  20. #endif
  21.  
  22. #ifdef vms
  23. #include      <ssdef.h>
  24. #include      <stsdef.h>
  25. #define  IO_SUCCESS  (SS$_NORMAL | STS$M_INHIB_MSG)
  26. #define  IO_ERROR  SS$_ABORT
  27. #endif
  28. /*
  29.  * Note: IO_SUCCESS and IO_ERROR are defined in the Decus C stdio.h file
  30.  */
  31. #ifndef  IO_SUCCESS
  32. #define  IO_SUCCESS  0
  33. #endif
  34. #ifndef  IO_ERROR
  35. #define  IO_ERROR  1
  36. #endif
  37.  
  38. #define  EOS      0
  39. #ifdef unix
  40. char temfile[L_tmpnam];
  41. char *tmpnam();
  42. #define  TEMPFILE  (temfile[0]? temfile: (tmpnam(temfile), temfile))
  43. #else
  44. #define  TEMPFILE  "diff.tmp"
  45. #endif
  46. #define  TRUE      1
  47. #define  FALSE      0
  48.  
  49. #ifdef  pdp11
  50. #define  short  int
  51. #endif
  52.  
  53. typedef struct candidate {
  54.   int  b;        /* Line in fileB      */
  55.   int  a;        /* Line in fileA      */
  56.   int  link;        /* Previous candidate      */
  57. } CANDIDATE;
  58.  
  59. typedef struct line {
  60.   unsigned short  hash;      /* Hash value etc.      */
  61.   short      serial;      /* Line number        */
  62. } LINE;
  63.  
  64. LINE  *file[2];        /* Hash/line for total file  */
  65. #define  fileA  file[0]
  66. #define  fileB  file[1]
  67.  
  68. LINE  *sfile[2];        /* Hash/line after prefix  */
  69. #define  sfileA  sfile[0]
  70. #define  sfileB  sfile[1]
  71.  
  72. int  len[2];            /* Actual lines in each file  */
  73. #define  lenA  len[0]
  74. #define  lenB  len[1]
  75.  
  76. int  slen[2];        /* Squished lengths      */
  77. #define  slenA  slen[0]
  78. #define  slenB  slen[1]
  79.  
  80. int  prefix;            /* Identical lines at start  */
  81. int  suffix;            /* Identical lenes at end  */
  82.  
  83. FILE  *infd[2] = { NULL, NULL };  /* Input file identifiers  */
  84. FILE  *tempfd;        /* Temp for input redirection  */
  85.  
  86. extern long  ftell();
  87. extern FILE *fopen();
  88.  
  89. #ifdef TURBO
  90. extern void *malloc();
  91. #else
  92. extern char *malloc();
  93. #endif
  94.  
  95. char    *fgetss();
  96. unsigned short      hash();
  97.  
  98. #ifdef    AMIGA
  99. /* Define these types for Amiga C */
  100. char    *savptr;
  101. int    savsiz;
  102. char    *wrk;
  103. char    *wrk2;
  104. int    cpysiz;
  105. #endif
  106. /*
  107.  * The following vectors overlay the area defined by fileA
  108.  */
  109.  
  110. short      *class;      /* Unsorted line numbers  */
  111. int      *klist;      /* Index of element in clist  */
  112. CANDIDATE  *clist;      /* Storage pool for candidates  */
  113. int      clength = 0;      /* Number of active candidates  */
  114. #define    CSIZE_INC 50    /* How many to allocate each time we have to */
  115. int    csize = CSIZE_INC; /* Current size of storage pool */
  116.  
  117. int      *match;        /* Longest subsequence      */
  118. long      *oldseek;      /* Seek position in file A  */
  119.  
  120. /*
  121.  * The following vectors overlay the area defined by fileB
  122.  */
  123.  
  124. short      *member;      /* Concatenated equiv. classes  */
  125. long      *newseek;      /* Seek position in file B  */
  126. char      *textb;        /* Input from file2 for check  */
  127.  
  128. /*
  129.  * Global variables
  130.  */
  131.  
  132. int      eflag  = FALSE;  /* Edit script requested  */
  133. int      bflag  = FALSE;  /* Blank supress requested  */
  134. int      cflag  = FALSE;  /* Context printout      */
  135. int      iflag  = FALSE;  /* Ignore case requested  */
  136. char      text[257];      /* Input line from file1  */
  137. extern char  *myalloc();      /* Storage allocator      */
  138.  
  139. extern char  *compact();      /* Storage compactor      */
  140.  
  141. #ifdef  DEBUG
  142. #ifndef OSK
  143. #define  TIMING
  144. #endif
  145. #endif
  146. #ifdef  TIMING
  147. extern long  time();
  148. extern char  *$$mend;
  149. long      totaltime;
  150. long      sectiontime;
  151. char      *mstart;
  152. #endif
  153.  
  154. main(argc, argv)
  155. int      argc;
  156. char      **argv;
  157. /*
  158.  * Diff main program
  159.  */
  160. {
  161.   register int  i;
  162.   register char  *ap;
  163.  
  164. #ifdef OSK
  165.   extern int _memmins;
  166.   _memmins = 16 * 1024;            /* tell OSK we will malloc a lot */
  167. #endif
  168. #ifdef  TIMING
  169.   sectiontime = time(&totaltime);
  170. #endif
  171. #ifdef vms
  172.   argc = getredirection(argc,argv);
  173. #endif
  174.   while (argc > 1 && *(ap = argv[1]) == '-' && *++ap != EOS) {
  175.       while (*ap != EOS) {
  176.         switch ((*ap++)) {
  177.         case 'b':
  178.               bflag++;
  179.               break;
  180.  
  181.         case 'c':
  182.           if (*ap > '0' && *ap <= '9') cflag = *ap++ - '0';
  183.           else cflag = 3;
  184.           break;
  185.  
  186.         case 'e':
  187.               eflag++;
  188.               break;
  189.  
  190.         case 'i':
  191.               iflag++;
  192.               break;
  193.  
  194.         default:
  195.               fprintf(stderr,
  196.                   "Warning, bad option '%c'\n",
  197.                   ap[-1]);
  198.               break;
  199.         }
  200.       }
  201.       argc--;
  202.       argv++;
  203.   }
  204.  
  205.   if (argc != 3)
  206.       error("Usage: diff [-options] file1 file2");
  207.   if (cflag && eflag) {
  208.       fprintf(stderr,
  209.         "Warning, -c and -e are incompatible, -c supressed.\n");
  210.       cflag = FALSE;
  211.   }
  212.   argv++;
  213.   for (i = 0; i <= 1; i++) {
  214.       if (argv[i][0] == '-' && argv[i][1] == EOS) {
  215.         infd[i] = stdin;
  216.         if ((tempfd = fopen(TEMPFILE, "w")) == NULL)
  217.             cant(TEMPFILE, "work", 1);
  218.       }
  219.       else {
  220.         infd[i] = fopen(argv[i], "r");
  221.       if (!infd[i]) cant(argv[i], "input", 2);    /* Fatal error */
  222.       }
  223.   }
  224.  
  225.   if (infd[0] == stdin && infd[1] == stdin)
  226.     error("Can't diff two things both on standard input.");
  227.  
  228.   if (infd[0] == NULL && infd[1] == NULL) {
  229.       cant(argv[0], "input", 0);
  230.       cant(argv[1], "input", 1);
  231.   }
  232. #ifdef vms
  233.   else if (infd[1] == NULL)
  234.       opendir(1, &argv[1], infd[0]);
  235.   else if (infd[0] == NULL)
  236.       opendir(0, &argv[0], infd[1]);
  237. #endif
  238.  
  239.  /*
  240.    * Read input, building hash tables.
  241.    */
  242.   input(0);
  243.   input(1);
  244.   squish();
  245. #ifdef  DEBUG
  246.   printf("before sort\n");
  247.   for (i = 1; i <= slenA; i++)
  248.       printf("sfileA[%d] = %6d %06o\n",
  249.         i, sfileA[i].serial, sfileA[i].hash);
  250.   for (i = 1; i <= slenB; i++)
  251.       printf("sfileB[%d] = %6d %06o\n",
  252.         i, sfileB[i].serial, sfileB[i].hash);
  253. #endif
  254.   sort(sfileA, slenA);
  255.   sort(sfileB, slenB);
  256. #ifdef  TIMING
  257.   ptime("input");
  258. #endif
  259. #ifdef  DEBUG
  260.   printf("after sort\n");
  261.   for (i = 1; i <= slenA; i++)
  262.       printf("sfileA[%d] = %6d %06o\n",
  263.         i, sfileA[i].serial, sfileB[i].hash);
  264.   for (i = 1; i <= slenB; i++)
  265.       printf("sfileB[%d] = %6d %06o\n",
  266.         i, sfileB[i].serial, sfileB[i].hash);
  267. #endif
  268.   /*
  269.    * Build equivalence classes.
  270.    */
  271.   member = (short *)fileB;
  272.   equiv();
  273.   member = (short *)compact((char *)member, (slenB + 2) * sizeof (int),
  274.         "squeezing member vector");
  275.   /*
  276.    * Reorder equivalence classes into array class[]
  277.    */
  278.   class = (short *)fileA;
  279.   unsort();
  280.   class = (short *)compact((char *)class, (slenA + 2) * sizeof (int),
  281.         "compacting class vector");
  282. #ifdef  TIMING
  283.   ptime("equiv/unsort");
  284. #endif
  285.   /*
  286.     * Find longest subsequences
  287.    */
  288.   klist = (int *)myalloc((slenA + 2) * sizeof (int), "klist");
  289.   clist = (CANDIDATE *)myalloc(csize * sizeof (CANDIDATE), "clist");
  290.   i = subseq();
  291. #ifndef OSK
  292.   free((char *)member);
  293.   free((char *)class);
  294. #else
  295.   free((char *)member - sizeof(int));
  296.   free((char *)class - sizeof(int));
  297. #endif
  298.   match = (int *)myalloc((lenA + 2) * sizeof (int), "match");
  299.   unravel(klist[i]);
  300. #ifndef OSK
  301.   free((char *)clist);
  302.   free((char *)klist);
  303. #else
  304.   free((char *)clist - sizeof(int));
  305.   free((char *)klist - sizeof(int));
  306. #endif
  307. #ifdef  TIMING
  308.   ptime("subsequence/unravel");
  309. #endif
  310.   /*
  311.    * Check for fortuitous matches and output differences
  312.    */
  313.   oldseek = (long *)myalloc((lenA + 2) * sizeof (* oldseek), "oldseek");
  314.   newseek = (long *)myalloc((lenB + 2) * sizeof (* newseek), "newseek");
  315.   textb = myalloc(sizeof text, "textbuffer");
  316.   if (check(argv[0], argv[1]))
  317.       fprintf(stderr, "Spurious match, output is not optimal\n");
  318. #ifdef  TIMING
  319.   ptime("check");
  320. #endif
  321.   output(argv[0], argv[1]);
  322. #ifdef  TIMING
  323.   ptime("output");
  324.   printf("%ld seconds required\n", sectiontime - totaltime);
  325. #endif
  326.   if (tempfd != NULL) {
  327.       fclose(tempfd);
  328. #ifdef unix
  329.       unlink(TEMPFILE);
  330. #else
  331. #ifdef OSK
  332.     unlink(TEMPFILE);
  333. #else
  334.     remove(TEMPFILE);
  335. #endif
  336. #endif 
  337.   }
  338. }
  339.  
  340.  
  341. input(which)
  342. int      which;        /* 0 or 1 to redefine infd[]  */
  343. /*
  344.  * Read the file, building hash table
  345.  */
  346. {
  347.   register LINE      *lentry;
  348.   register int      linect = 0;
  349.   FILE        *fd;
  350. #define    LSIZE_INC 200    /* # of line entries to alloc at once */
  351.   int    lsize = LSIZE_INC;
  352.  
  353.   lentry = (LINE *)myalloc(sizeof(LINE) * (lsize+3), "line");
  354.   fd = infd[which];
  355.   while (!getline(fd, text)) {
  356.     if (++linect >= lsize) {
  357.         lsize += 200;
  358.         lentry = (LINE *)compact((char *)lentry,
  359.           (lsize + 3) * sizeof(LINE),
  360.           "extending line vector");
  361.     }
  362.       lentry[linect].hash = hash(text);
  363.   }
  364.   /*
  365.    * If input was from stdin ("-" command), finish off the temp file.
  366.    */
  367.   if (fd == stdin) {
  368.       fclose(tempfd);
  369.       tempfd = infd[which] = fopen(TEMPFILE, "r");
  370.   }
  371.   /* If we wanted to be stingy with memory, we could realloc lentry down
  372.    * to its exact size (+3 for some odd reason) here.  No need?  */
  373.   len[which] = linect;
  374.   file[which] = lentry;
  375. }
  376.  
  377. squish()
  378. /*
  379.  * Look for initial and trailing sequences that have identical hash values.
  380.  * Don't bother building them into the candidate vector.
  381.  */
  382. {
  383.   register int  i;
  384.   register LINE  *ap;
  385.   register LINE  *bp;
  386.   int      j;
  387.   int      k;
  388.  
  389.   /*
  390.    * prefix -> first line (from start) that doesn't hash identically
  391.    */
  392.   i = 0; ap = &fileA[1]; bp = &fileB[1];
  393.   while (i < lenA && i < lenB && ap->hash == bp->hash) {
  394.       i++; ap++; bp++;
  395.   }
  396.   prefix = i;
  397.   /*
  398.     * suffix -> first line (from end) that doesn't hash identically
  399.    */
  400.   j = lenA - i;
  401.   k = lenB - i;
  402.   ap = &fileA[lenA];
  403.   bp = &fileB[lenB];
  404.   i = 0;
  405.   while (i < j && i < k && ap->hash == bp->hash) {
  406.       i++; ap--; bp--;
  407.   }
  408.   suffix = i;
  409.   /*
  410.    * Tuck the counts away
  411.    */
  412.   for (k = 0; k <= 1; k++) {
  413.       sfile[k] = file[k] + prefix;
  414.       j = slen[k] = len[k] - prefix - suffix;
  415.  
  416.       for (i = 0, ap = sfile[k]; i <= slen[k]; i++, ap++) {
  417.         ap->serial = i;
  418.       }
  419.   }
  420. }
  421.  
  422. sort(vector, vecsize)
  423. LINE      *vector;      /* What to sort        */
  424. int      vecsize;      /* How many to sort      */
  425. /*
  426.  * Sort hash entries
  427.  */
  428. {
  429.   register int  j;
  430.   register LINE  *aim;
  431.   register LINE  *ai;
  432.   int      mid;  
  433.   int      k;
  434.   LINE      work;
  435.  
  436.   for (j = 1; j <= vecsize; j *= 2);
  437.   mid = (j - 1);
  438.   while ((mid /= 2) != 0) {
  439.       k = vecsize - mid;
  440.       for (j = 1; j <= k; j++) {
  441.         for (ai = &vector[j]; ai > vector; ai -= mid) {
  442.             aim = &ai[mid];
  443.             if (aim < ai)
  444.               break;  /* ?? Why ??      */
  445.             if (aim->hash > ai->hash ||
  446.                   aim->hash == ai->hash &&
  447.                   aim->serial > ai->serial)
  448.               break;
  449.             work.hash = ai->hash;
  450.             ai->hash = aim->hash;
  451.             aim->hash = work.hash;
  452.             work.serial = ai->serial;
  453.             ai->serial = aim->serial;
  454.             aim->serial = work.serial;
  455.         }
  456.       }
  457.   }
  458. }
  459.  
  460. equiv()
  461. /*
  462.  * Build equivalence class vector
  463.  */
  464. {
  465.   register LINE  *ap;
  466. #ifdef TURBO
  467.   union {
  468. #else
  469.   register union {
  470. #endif
  471.       LINE    *bp;
  472.       short    *mp;
  473.   } r;
  474.   register int  j;
  475.   LINE    *atop;
  476.  
  477. #ifdef  DEBUG
  478.   printf("equiv entry\n");
  479.   for (j = 1; j <= slenA; j++)
  480.       printf("sfileA[%d] = %6d %06o\n",
  481.             j, sfileA[j].serial, sfileA[j].hash);
  482.   for (j = 1; j <= slenB; j++)
  483.       printf("sfileB[%d] = %6d %06o\n",
  484.             j, sfileB[j].serial, sfileB[j].hash);
  485. #endif
  486.   j = 1;
  487.   ap = &sfileA[1];
  488.   r.bp = &sfileB[1];
  489.   atop = &sfileA[slenA];
  490.   while (ap <= atop && j <= slenB) {
  491.       if (ap->hash < r.bp->hash) {
  492.         ap->hash = 0;
  493.         ap++;
  494.       }
  495.       else if (ap->hash == r.bp->hash) {
  496.         ap->hash = j;
  497.         ap++;
  498.       }
  499.       else {
  500.         r.bp++;
  501.         j++;
  502.       }
  503.   }
  504.   while (ap <= atop) {
  505.       ap->hash = 0;
  506.       ap++;
  507.   }
  508.   sfileB[slenB + 1].hash = 0;
  509. #ifdef  DEBUG
  510.   printf("equiv exit\n");
  511.   for (j = 1; j <= slenA; j++)
  512.       printf("sfileA[%d] = %6d %06o\n",
  513.             j, sfileA[j].serial, sfileA[j].hash);
  514.   for (j = 1; j <= slenB; j++)
  515.       printf("sfileB[%d] = %6d %06o\n",
  516.             j, sfileB[j].serial, sfileB[j].hash);
  517. #endif
  518.   ap = &sfileB[0];
  519.   atop = &sfileB[slenB];
  520.   r.mp = &member[0];
  521.   while (++ap <= atop) {
  522.       r.mp++;
  523.       *r.mp = -(ap->serial);
  524.       while (ap[1].hash == ap->hash) {
  525.         ap++;
  526.         r.mp++;
  527.         *r.mp = ap->serial;
  528.       }
  529.   }
  530.   r.mp[1] = -1;
  531. #ifdef  DEBUG
  532.   for (j = 0; j <= slenB; j++)
  533.       printf("member[%d] = %d\n", j, member[j]);
  534. #endif
  535. }
  536.  
  537. unsort()
  538. /*
  539.  * Build class vector
  540.  */
  541. {
  542.   register int  *temp;
  543.   register int  *tp;
  544. #if TURBO
  545.   union {
  546. #else
  547.   register union {
  548. #endif
  549.       LINE    *ap;
  550.       short    *cp;
  551.   } u;
  552.   LINE    *evec;
  553.   short    *eclass;
  554. #ifdef  DEBUG
  555.   int      i;
  556. #endif
  557.  
  558.   temp = (int *)myalloc((slenA + 1) * sizeof(int), "unsort scratch");
  559.   u.ap = &sfileA[1];
  560.   evec = &sfileA[slenA];
  561.   while (u.ap <= evec) {
  562. #ifdef  DEBUG
  563.       printf("temp[%2d] := %06o\n", u.ap->serial, u.ap->hash);
  564. #endif
  565.       temp[u.ap->serial] = u.ap->hash;
  566.       u.ap++;
  567.   }
  568.   /*
  569.    * Copy into class vector and free work space
  570.    */
  571.   u.cp = &class[1];
  572.   eclass = &class[slenA];
  573.   tp = &temp[1];
  574.   while (u.cp <= eclass)
  575.       *u.cp++ = *tp++;
  576. #ifndef OSK
  577.   free((char *) temp);
  578. #else
  579.   free((char *)temp - sizeof(int));
  580. #endif
  581. #ifdef  DEBUG
  582.   printf("unsort exit\n");
  583.   for (i = 1; i <= slenA; i++)
  584.       printf("class[%d] = %d %06o\n", i, class[i], class[i]);
  585. #endif
  586. }
  587.  
  588. subseq()
  589. /*
  590.  * Generate maximum common subsequence chain in clist[]
  591.  */
  592. {
  593.   int        a;
  594.   register unsigned      ktop;
  595.   register int      b;
  596.   register int      s;
  597.   unsigned        r;
  598.   int        i;
  599.   int        cand;
  600.  
  601.   klist[0] = newcand(0, 0, -1);
  602.   klist[1] = newcand(slenA + 1, slenB + 1, -1);
  603.   ktop = 1;            /* -> guard entry  */
  604.   for (a = 1; a <= slenA; a++) {
  605.       /*
  606.        * For each non-zero element in fileA ...
  607.        */
  608.       if ((i = class[a]) == 0)
  609.         continue;
  610.       cand = klist[0];      /* No candidate now  */
  611.       r = 0;            /* Current r-candidate  */
  612.       do {
  613. #ifdef  DEBUG
  614.         printf("a = %d, i = %d, b = %d\n", a, i, member[i]);
  615. #endif
  616.         /*
  617.          * Perform the merge algorithm
  618.          */
  619.         if ((b = member[i]) < 0)
  620.             b = -b;
  621. #ifdef  DEBUG
  622.         printf("search(%d, %d, %d) -> %d\n",
  623.               r, ktop, b, search(r, ktop, b));
  624. #endif
  625.         if ((s = search(r, ktop, b)) != 0) {
  626.             if (clist[klist[s]].b > b) {
  627.               klist[r] = cand;
  628.               r = s;
  629.               cand = newcand(a, b, klist[s-1]);
  630. #ifdef  DEBUG
  631.               dumpklist(ktop, "klist[s-1]->b > b");
  632. #endif
  633.             }
  634.             if (s >= ktop) {
  635.               klist[ktop + 1] = klist[ktop];
  636.               ktop++;
  637. #ifdef  DEBUG
  638.               klist[r] = cand;
  639.               dumpklist(ktop, "extend");
  640. #endif
  641.               break;
  642.             }
  643.         }
  644.       } while (member[++i] > 0);
  645.     klist[r] = cand;
  646.   }
  647. #ifdef  DEBUG
  648.   printf("last entry = %d\n", ktop - 1);
  649. #endif
  650.   return(ktop - 1);        /* Last entry found  */
  651. }
  652.  
  653. int
  654. newcand(a, b, pred)
  655. int      a;      /* Line in fileA        */
  656. int      b;      /* Line in fileB        */
  657. int      pred;      /* Link to predecessor, index in cand[]  */
  658. {
  659.   register CANDIDATE  *new;
  660.  
  661.   clength++;
  662.   if (++clength >= csize) {
  663.     csize += CSIZE_INC;
  664.     clist = (CANDIDATE *)compact((char *)clist,
  665.           csize * sizeof (CANDIDATE),
  666.           "extending clist");
  667.   }
  668.   new = &clist[clength - 1];
  669.   new->a = a;
  670.   new->b = b;
  671.   new->link = pred;
  672.   return(clength - 1);
  673. }
  674.  
  675. search(low, high, b)
  676. register unsigned  low;
  677. register unsigned  high;
  678. register int  b;
  679. /*
  680.  * Search klist[low..top] (inclusive) for b.  If klist[low]->b >= b,
  681.  * return zero.  Else return s such that klist[s-1]->b < b and
  682.  * klist[s]->b >= b.  Note that the algorithm presupposes the two
  683.  * preset "fence" elements, (0, 0) and (slenA, slenB).
  684.  */
  685. {
  686.   register int      temp;
  687.   register unsigned      mid;
  688.  
  689.   if (clist[klist[low]].b >= b)
  690.       return(0);
  691.   while ((mid = (low + high) / 2) > low) {
  692.       if ((temp = clist[klist[mid]].b) > b)
  693.         high = mid;
  694.       else if (temp < b)
  695.         low = mid;
  696.       else {
  697.         return(mid);
  698.       }
  699.   }
  700.   return(mid + 1);
  701. }
  702.  
  703.  
  704. unravel(k)
  705. register int  k;
  706. {
  707.   register int      i;
  708.   register CANDIDATE  *cp;
  709.   int        first_trailer;
  710.   int        difference;
  711.  
  712.   first_trailer = lenA - suffix;
  713.   difference = lenB - lenA;
  714. #ifdef  DEBUG
  715.   printf("first trailer = %d, difference = %d\n",
  716.       first_trailer, difference);
  717. #endif
  718.   for (i = 0; i <= lenA; i++) {
  719.       match[i] = (i <= prefix) ? i
  720.         : (i > first_trailer) ? i + difference
  721.         : 0;
  722.   }
  723. #ifdef  DEBUG
  724.   printf("unravel\n");
  725. #endif
  726.   while (k != -1) {
  727.       cp = &clist[k];
  728. #ifdef  DEBUG
  729.       if (k < 0 || k >= clength)
  730.         error("Illegal link -> %d", k);
  731.       printf("match[%d] := %d\n", cp->a + prefix, cp->b + prefix);
  732. #endif
  733.       match[cp->a + prefix] = cp->b + prefix;
  734.       k = cp->link;
  735.   }
  736. }
  737.  
  738.  
  739. /*
  740.  * Check for hash matches (jackpots) and collect random access indices to
  741.  * the two files.
  742.  *
  743.  * It should be possible to avoid doing most of the ftell's by noticing
  744.  * that we are not doing a context diff and noticing that if a line
  745.  * compares equal to the other file, we will not ever need to know its
  746.  * file position.  FIXME.
  747.  */
  748. check(fileAname, fileBname)
  749. char      *fileAname;
  750. char      *fileBname;
  751. {
  752.   register int  a;      /* Current line in file A  */
  753.   register int  b;      /* Current line in file B  */
  754.   int      jackpot;
  755.  
  756. /*
  757.  * The VAX C ftell() returns the address of the CURRENT record, not the
  758.  * next one (as in DECUS C or, effectively, other C's).  Hence, the values
  759.  * are "off by one" in the array.  OFFSET compensates for this.
  760.  */
  761. #ifdef vms
  762. #define OFFSET (-1)
  763. #else
  764. #define OFFSET 0
  765. #endif
  766.  
  767.   b = 1;
  768.   rewind(infd[0]);
  769.   rewind(infd[1]);
  770. /*
  771.  * See above; these would be over-written on VMS anyway.
  772.  */
  773. #ifndef vms
  774.   oldseek[0] = ftell(infd[0]);
  775.   newseek[0] = ftell(infd[1]);
  776. #endif
  777.  
  778.   jackpot = 0;
  779. #ifdef  DEBUG
  780.   printf("match vector\n");
  781.   for (a = 0; a <= lenA; a++)
  782.       printf("match[%d] = %d\n", a, match[a]);
  783. #endif
  784.   for (a = 1; a <= lenA; a++) {
  785.       if (match[a] == 0) {
  786.       /* Unique line in A */
  787.         oldseek[a+OFFSET] = ftell(infd[0]);
  788.         getline(infd[0], text);
  789.         continue;  
  790.       }
  791.       while (b < match[a]) {
  792.       /* Skip over unique lines in B */
  793.         newseek[b+OFFSET] = ftell(infd[1]);
  794.         getline(infd[1], textb);
  795.         b++;
  796.       }
  797.  
  798.     /*
  799.      * Compare the two, supposedly matching, lines.
  800.      * Unless we are going to print these lines, don't bother to
  801.      * remember where they are.  We only print matching lines
  802.      * if a context diff is happening, or if a jackpot occurs.
  803.      */
  804.     if (cflag) {
  805.         oldseek[a+OFFSET] = ftell(infd[0]);
  806.         newseek[b+OFFSET] = ftell(infd[1]);
  807.     }
  808.       getline(infd[0], text);
  809.       getline(infd[1], textb);
  810.       if (!streq(text, textb)) {
  811.         fprintf(stderr,  "Spurious match:\n");
  812.         fprintf(stderr, "line %d in %s, \"%s\"\n",
  813.             a, fileAname, text);
  814.         fprintf(stderr, "line %d in %s, \"%s\"\n",
  815.             b, fileBname, textb);
  816.         match[a] = 0;
  817.         jackpot++;
  818.       }
  819.  
  820.       b++;
  821.   }
  822.   for (; b <= lenB; b++) {
  823.       newseek[b+OFFSET] = ftell(infd[1]);
  824.       getline(infd[1], textb);
  825.   }
  826. /*
  827.  * The logical converse to the code up above, for NON-VMS systems, to
  828.  * store away an fseek() pointer at the beginning of the file.  For VMS,
  829.  * we need one at EOF...
  830.  */
  831. #ifdef vms
  832.   oldseek[lenA] = ftell(infd[0]);
  833.   getline(infd[0],text);        /* Will hit EOF...  */
  834.   newseek[lenB] = ftell(infd[1]);
  835.   getline(infd[1],textb);        /* Will hit EOF...  */
  836. #endif
  837.  
  838.   return(jackpot);
  839. }
  840.  
  841. output(fileAname, fileBname)
  842. char *fileAname, *fileBname;
  843. {
  844.   register int  astart;
  845.   register int  aend = 0;
  846.   int      bstart;
  847.   register int  bend;
  848.  
  849.   rewind(infd[0]);
  850.   rewind(infd[1]);
  851.   match[0] = 0;
  852.   match[lenA+1] = lenB + 1;
  853.   if (!eflag) {
  854.     if (cflag) {
  855.         /*
  856.          * Should include ctime style dates after the file names, but
  857.          * this would be non-trivial on OSK.  Perhaps there should be
  858.          * a special case for stdin.
  859.          */
  860.         printf("*** %s\n--- %s\n", fileAname, fileBname);
  861.     }
  862.       /*
  863.        * Normal printout
  864.        */
  865.       for (astart = 1; astart <= lenA; astart = aend + 1) {
  866.         /*
  867.          * New subsequence, skip over matching stuff
  868.          */
  869.         while (astart <= lenA
  870.               && match[astart] == (match[astart - 1] + 1))
  871.             astart++;
  872.         /*
  873.          * Found a difference, setup range and print it
  874.          */
  875.         bstart = match[astart - 1] + 1;
  876.         aend = astart - 1;
  877.         while (aend < lenA && match[aend + 1] == 0)
  878.             aend++;
  879.         bend = match[aend + 1] - 1;
  880.         match[aend] = bend;
  881.         change(astart, aend, bstart, bend);
  882.       }
  883.   }
  884.   else {
  885.       /*
  886.        * Edit script output -- differences are output "backwards"
  887.        * for the benefit of a line-oriented editor.
  888.        */
  889.       for (aend = lenA; aend >= 1; aend = astart - 1) {
  890.         while (aend >= 1
  891.               && match[aend] == (match[aend + 1] - 1)
  892.               && match[aend] != 0)
  893.             aend--;
  894.         bend = match[aend + 1] - 1;
  895.         astart = aend + 1;
  896.         while (astart > 1 && match[astart - 1] == 0)
  897.             astart--;
  898.         bstart = match[astart - 1] + 1;
  899.         match[astart] = bstart;
  900.         change(astart, aend, bstart, bend);
  901.       }
  902.   }
  903.   if (lenA == 0)
  904.       change(1, 0, 1, lenB);
  905. }
  906.  
  907.  
  908. /*
  909.  * Output a change entry: fileA[astart..aend] changed to fileB[bstart..bend]
  910.  */
  911. change(astart, aend, bstart, bend)
  912. int      astart;
  913. int      aend;
  914. int      bstart;
  915. int      bend;
  916. {
  917.   char c;
  918.   /*
  919.    * This catches a "dummy" last entry
  920.    */
  921.   if (astart > aend && bstart > bend)
  922.       return;
  923.   c = (astart > aend) ? 'a' : (bstart > bend) ? 'd' : 'c';
  924.   if (cflag) fputs("**************\n*** ", stdout);
  925.  
  926.   if (c == 'a' && !cflag)
  927.     range(astart-1, astart-1, 0);    /* Addition: just print one odd # */
  928.   else
  929.     range(astart, aend, 0);        /* Print both, if different */
  930.   if (!cflag) {
  931.     putchar(c);
  932.     if (!eflag) {
  933.     if (c == 'd')
  934.         range(bstart-1, bstart-1, 1); /* Deletion: just print one odd # */
  935.     else
  936.         range(bstart, bend, 1);    /* Print both, if different */
  937.     }
  938.   }
  939.   putchar('\n');
  940.   if (!eflag) {
  941.       fetch(oldseek, astart, aend, lenA, infd[0], 
  942.         cflag ? (c=='d' ? "- " : "! ") : "< ");
  943.     if (cflag) {
  944.       fputs("--- ", stdout);
  945.       range(bstart, bend, 1);
  946.       fputs(" -----\n", stdout);
  947.     } else if (astart <= aend && bstart <= bend)
  948.         printf("---\n");
  949.   }
  950.   fetch(newseek, bstart, bend, lenB, infd[1], 
  951.       cflag ? (c=='a' ? "+ " : "! ") : (eflag ? "" : "> "));
  952.   if (eflag && bstart <= bend)
  953.       printf(".\n");
  954. }
  955.  
  956.  
  957. range(from, to, w)
  958. int      from;
  959. int      to;
  960. int    w;
  961. /*
  962.  * Print a range
  963.  */
  964. {
  965.   if (cflag) {
  966.     if((from -= cflag) <= 0) from = 1;
  967.     if((to += cflag) > len[w]) to = len[w];
  968.   }
  969.   if (to > from) {
  970.     printf("%d,%d", from, to);
  971.   } else if (to < from) {
  972.     printf("%d,%d", to, from);
  973.   } else {
  974.     printf("%d", from);
  975.   }
  976. }
  977.  
  978.  
  979. fetch(seekvec, start, end, trueend, fd, pfx)
  980. long      *seekvec;
  981. register int  start;
  982. register int  end;
  983. int      trueend;
  984. FILE      *fd;
  985. char      *pfx;
  986. /*
  987.  * Print the appropriate text
  988.  */
  989. {
  990.   register int  i;
  991.   register int    first;
  992.   register int    last;
  993.  
  994.   if (cflag) {
  995.     if((first = start - cflag) <= 0) first = 1;
  996.     if((last = end + cflag) > trueend) last = trueend;
  997.   } else {
  998.     first = start;
  999.     last = end;
  1000.   }
  1001.   if (fseek(fd, seekvec[first], 0) != 0) {
  1002.       printf("?Can't read line %d at %08lx (hex) in file%c\n",
  1003.         start, seekvec[first],
  1004.         (fd == infd[0]) ? 'A' : 'B');
  1005.   }
  1006.   else {
  1007.       for (i = first; i <= last; i++) {
  1008.         if (fgetss(text, sizeof text, fd) == NULL) {
  1009.             printf("** Unexpected end of file\n");
  1010.             break;
  1011.         }
  1012. #ifdef DEBUG
  1013.         printf("%5d: %s%s\n", i, pfx, text);
  1014. #else
  1015.         fputs((cflag && (i<start || i>end)) ? "  " : pfx, stdout);
  1016.         fputs(text, stdout);
  1017.       putchar('\n');
  1018. #endif
  1019.       }
  1020.   }  
  1021. }
  1022.  
  1023.  
  1024. /*
  1025.  * Input routine, read one line to buffer[], return TRUE on eof, else FALSE.
  1026.  * The terminating newline is always removed.  If "-b" was given, trailing
  1027.  * whitespace (blanks and tabs) are removed and strings of blanks and
  1028.  * tabs are replaced by a single blank.  Getline() does all hacking for
  1029.  * redirected input files.
  1030.  */
  1031. int
  1032. getline(fd, buffer)
  1033. FILE      *fd;
  1034. char      *buffer;
  1035. {
  1036.   register char  *top;
  1037.   register char  *fromp;
  1038.   register char  c;
  1039.  
  1040.   if (fgetss(buffer, sizeof text, fd) == NULL) {
  1041.       *buffer = EOS;
  1042.       return(TRUE);
  1043.   }
  1044.   if (fd == stdin)
  1045.       fputss(buffer, tempfd);
  1046.   if (bflag || iflag) {
  1047.       top = buffer;
  1048.       fromp = buffer;
  1049.       while ((c = *fromp++) != EOS) {
  1050.         if (bflag && (c == ' ' || c == '\t')) {
  1051.             c = ' ';
  1052.             while (*fromp == ' ' || *fromp == '\t')
  1053.               fromp++;
  1054.         }
  1055.         if (iflag)
  1056.             c = tolower(c);
  1057.         *top++ = c;
  1058.       }
  1059.       if (bflag && top[-1] == ' ')
  1060.         top--;
  1061.       *top = EOS;
  1062.   }
  1063.   return(FALSE);
  1064. }
  1065. static unsigned short crc16a[] = {
  1066.   0000000,  0140301,  0140601,  0000500,
  1067.   0141401,  0001700,  0001200,  0141101,
  1068.   0143001,  0003300,  0003600,  0143501,
  1069.   0002400,  0142701,  0142201,  0002100,  
  1070. };
  1071. static unsigned short crc16b[] = {
  1072.   0000000,  0146001,  0154001,  0012000,
  1073.   0170001,  0036000,  0024000,  0162001,
  1074.   0120001,  0066000,  0074000,  0132001,
  1075.   0050000,  0116001,  0104001,  0043000,
  1076. };
  1077.  
  1078. unsigned short
  1079. hash(buffer)
  1080. char      *buffer;
  1081. /*
  1082.  * Return the CRC16 hash code for the buffer
  1083.  * Algorithm from Stu Wecker (Digital memo 130-959-002-00).
  1084.  */
  1085. {
  1086.   register unsigned short  crc;
  1087.   register char      *tp;
  1088.   register short       temp;
  1089.  
  1090.   crc = 0;
  1091.   for (tp = buffer; *tp != EOS;) {
  1092.       temp = *tp++ ^ crc;  /* XOR crc with new char  */
  1093.       crc = (crc >> 8)
  1094.         ^ crc16a[(temp & 0017)]
  1095.         ^ crc16b[(temp & 0360) >> 4];
  1096.   }
  1097. #ifdef  DEBUG_ALL
  1098.   printf("%06o: %s\n", (crc == 0) ? 1 : crc, buffer);
  1099. #endif
  1100.   return((crc == 0) ? (unsigned short) 1 : crc);
  1101. }      
  1102.  
  1103.  
  1104. #ifdef vms
  1105. opendir(which, arg, okfd)
  1106. int      which;      /* Which file to open (0 or 1)      */
  1107. char      **arg;      /* File name argument, &argv[which]  */
  1108. FILE      *okfd;      /* File name (already open)      */
  1109. {
  1110.   register char      *tp;
  1111.   register int      c;
  1112.   register char      *newname;
  1113.  
  1114.   fgetname(okfd, text);
  1115.   /*
  1116.    * Skip over device name
  1117.    */
  1118.   for (tp = text; (c = *tp) && c != ':'; tp++);
  1119.   if (c)  tp++;
  1120.   else  tp = text;
  1121.   /*
  1122.    * Skip over [UIC] or [PPN] if present
  1123.    */
  1124.   if (*tp == '[' || *tp == '(') {
  1125.       while ((c = *tp++) && c != ']' && c != ')');
  1126.       if (c == 0) {
  1127.         fprintf(stderr, "?Bug: bad file name \"%s\"\n",
  1128.               text);
  1129.         tp--;
  1130.       }
  1131.   }
  1132.   strcpy(text, tp);
  1133.   /*
  1134.    * Don't include version
  1135.    */
  1136.   for (tp = text; (c = *tp) && c != ';'; tp++);
  1137.   *tp = 0;
  1138.   /*
  1139.    * Now, text has the file name, tp - text, its length,
  1140.    * and *arg the (possible) directory name.  Create a new
  1141.    * file name for opening.
  1142.    */
  1143. #ifndef    OSK
  1144.   if ((newname = malloc(tp - text + strlen(*arg) + 1)) == NULL)
  1145.       error("Out of space at start");
  1146. #ifdef    AMIGA
  1147.     savsiz = tp - text + strlen(*arg) + 1;
  1148.     savptr = newname;
  1149. #endif
  1150. #else
  1151.   newname = myalloc(tp - text + strlen(*arg) + 1, "Out of space at start");
  1152. #endif
  1153.   concat(newname, *arg, text, NULL);
  1154.   if ((infd[which] = fopen(newname, "r")) == NULL)
  1155.       cant(*arg, "constructed input", 1);
  1156.   else
  1157.       *arg = newname;
  1158. }
  1159. /* Amiga C doesn't have all these extensions for directory... */
  1160. #endif
  1161.  
  1162. char *
  1163. myalloc(amount, why)
  1164. int      amount;
  1165. char      *why;
  1166. /*
  1167.  * Allocate or crash.
  1168.  */
  1169. {
  1170.   register char  *pointer;
  1171.  
  1172. #ifdef OSK
  1173.   amount += sizeof(int);
  1174. #endif
  1175.   if ((pointer = malloc((unsigned) amount)) == NULL)
  1176.       noroom(why);
  1177. #ifdef OSK
  1178.   *((int *)pointer) = amount;
  1179.   pointer += sizeof(int);
  1180. #ifdef DEBUG
  1181.   fprintf(stderr, "Myalloc: %d at %06o\n", amount, pointer);
  1182. #endif
  1183. #endif
  1184. #ifdef    AMIGA
  1185.    savsiz =  amount;
  1186.    savptr = pointer;
  1187. #endif
  1188.  
  1189.   return (pointer);
  1190. }
  1191.  
  1192.  
  1193. /*
  1194.  * Reallocate pointer, compacting storage
  1195.  *
  1196.  * The "compacting storage" part is probably not relevant any more.
  1197.  * There used to be horrid code here that malloc'd one byte and freed
  1198.  * it at magic times, to cause garbage collection of the freespace
  1199.  * or something.  It's safely gone now, you didn't have to see it.
  1200.  *    -- John Gilmore, Nebula Consultants, Sept 26, 1986
  1201.  */
  1202. char *
  1203. compact(pointer, new_amount, why)
  1204. char      *pointer;
  1205. int      new_amount;
  1206. char      *why;
  1207. {
  1208.   register char *new_pointer;
  1209.  
  1210. #ifndef AMIGA
  1211. #ifndef OSK
  1212. #ifdef TURBO
  1213.   extern void *realloc();
  1214. #else
  1215.   extern char *realloc();
  1216. #endif
  1217.  
  1218.   if ((new_pointer =  realloc(pointer, (unsigned) new_amount)) == NULL){
  1219.       noroom(why);
  1220.   }
  1221. #else
  1222.   register int old_amount;
  1223.   new_amount += sizeof(int);
  1224.   if((new_pointer = malloc(new_amount)) == NULL) noroom(why);
  1225.   *(int *)new_pointer = new_amount;
  1226.   new_pointer += sizeof(int);
  1227.   old_amount = *(((int *)pointer)-1);
  1228.   /* _strass is like bcopy with the first two arguments reversted */
  1229.   _strass(new_pointer, pointer, (new_amount <= old_amount ?
  1230.       new_amount : old_amount) - sizeof(int));
  1231. #ifdef DEBUG
  1232.   fprintf(stderr, "compact %d to %d from %06o to %06o\n", 
  1233.     old_amount, new_amount, pointer, new_pointer);
  1234. #endif
  1235.   free(pointer - sizeof(int));
  1236. #endif
  1237. #else
  1238.   /*
  1239.    * This routine is heavily dependent on C storage allocator hacks
  1240.    * For Amiga, we can't rely on storage being left alone "up to"
  1241.    * the boundary of allocation as in VMS or RSX. Therefore we have
  1242.    * to be different here and allocate a new larger segment, then
  1243.    * free the old one. Messy but hopefully it will work.
  1244.    */
  1245.   extern char  *malloc();
  1246.  
  1247.   /* No realloc().  Do a malloc and copy it.  */
  1248.   if ((new_pointer = malloc((unsigned) new_amount)) == NULL){
  1249.       noroom(why);
  1250.   }
  1251. /* This MUST assume the program calls compact using the old pointer as the
  1252.   last call of malloc... Reason is that RSX version is really simpleminded */
  1253.    cpysiz=savsiz;
  1254. /* Complain if deallocate area not same as last allocate area */
  1255.  if (savptr != pointer) bogus(why);
  1256.    wrk2=new_pointer;
  1257.    for (wrk=pointer;cpysiz > 0;cpysiz--){
  1258. /* copy data to new area */
  1259.      *wrk2++ = *wrk++;
  1260.      }
  1261. /* when done, free old memory area. */
  1262.    free(pointer);
  1263. #endif
  1264.  
  1265. #ifndef OSK
  1266. #ifdef  DEBUG
  1267.   if (new_pointer != pointer) {
  1268.       fprintf(stderr, "moved from %06o to %06o\n",
  1269.         pointer, new_pointer);
  1270.   }
  1271. /*  rdump(new_pointer, why);
  1272. */
  1273. #endif
  1274. #endif
  1275.   return (new_pointer);
  1276. }
  1277.  
  1278. noroom(why)
  1279. char      *why;
  1280. {
  1281.   fprintf(stderr, "?DIFF-F-out of room when %s\n", why);
  1282.   exit(IO_ERROR);
  1283. }
  1284.  
  1285. #ifdef    AMIGA
  1286. bogus(why)
  1287. char      *why;
  1288. {
  1289.   fprintf(stderr, "?DIFF-F-invalid compaction when %s\n", why);
  1290.   exit(IO_ERROR);
  1291. }
  1292. #endif
  1293.  
  1294. #ifdef  DEBUG
  1295. rdump(pointer, why)
  1296. int      *pointer;
  1297. char      *why;
  1298. /*
  1299.  * Dump memory block
  1300.  */
  1301. {
  1302.   int  *last;
  1303.   int  count;
  1304.  
  1305.   last = ((int **)pointer)[-1];
  1306.   fprintf(stderr, "dump %s of %06o -> %06o, %d words",
  1307.         why, pointer, last, last - pointer);
  1308.   last = (int *)(((int) last) & ~1);
  1309.   for (count = 0; pointer < last; ++count) {
  1310.       if ((count & 07) == 0) {
  1311.         fprintf(stderr, "\n%06o", pointer);
  1312.       }
  1313.       fprintf(stderr, "\t%06o", *pointer);
  1314.       pointer++;
  1315.   }
  1316.   fprintf(stderr, "\n");
  1317. }
  1318. #endif
  1319. cant(filename, what, fatalflag)
  1320. char      *filename;
  1321. char      *what;
  1322. int      fatalflag;
  1323. /*
  1324.  * Can't open file message
  1325.  */
  1326. {
  1327.   fprintf(stderr, "Can't open %s file \"%s\": ", what, filename);
  1328. #ifndef    OSK
  1329.   perror((char *)NULL);
  1330. #else
  1331.   prerr(0, errno);
  1332. #endif
  1333.   if (fatalflag) {
  1334.       exit(fatalflag);
  1335.   }
  1336. }
  1337. #ifdef  DEBUG
  1338. dump(d_linep, d_len, d_which)
  1339. LINE  *d_linep;
  1340. {
  1341.   register int i;
  1342.   
  1343.   printf("Dump of file%c, %d elements\n", "AB"[d_which], d_len);
  1344.   printf("linep @ %06o\n", d_linep);
  1345.   for (i = 0; i <= d_len; i++) {
  1346.       printf("%3d  %6d  %06o\n", i,
  1347.             d_linep[i].serial, d_linep[i].hash);
  1348.   }
  1349. }
  1350.  
  1351. dumpklist(kmax, why)
  1352. int  kmax;
  1353. char  *why;
  1354. /*
  1355.  * Dump klist
  1356.  */
  1357. {
  1358.   register int      i;
  1359.   register CANDIDATE  *cp;
  1360.   register int      count;
  1361.  
  1362.   printf("\nklist[0..%d] %s, clength = %d\n", kmax, why, clength);
  1363.   for (i = 0; i <= kmax; i++) {
  1364.       cp = &clist[klist[i]];
  1365.       printf("%2d %2d", i, klist[i]);
  1366.       if (cp >= &clist[0] && cp < &clist[clength])
  1367.         printf(" (%2d %2d -> %2d)\n", cp->a, cp->b, cp->link);
  1368.       else if (klist[i] == -1)
  1369.         printf(" End of chain\n");
  1370.       else  printf(" illegal klist element\n");
  1371.   }
  1372.   for (i = 0; i <= kmax; i++) {
  1373.       count = -1;
  1374.       for (cp = (CANDIDATE *)klist[i]; cp > &clist[0]; 
  1375.         cp = (CANDIDATE *)&cp->link) {
  1376.         if (++count >= 6) {
  1377.             printf("\n    ");
  1378.             count = 0;
  1379.         }
  1380.         printf(" (%2d: %2d,%2d -> %d)",
  1381.             cp-clist, cp->a, cp->b, cp->link);
  1382.       }
  1383.       printf("\n");
  1384.   }
  1385.   printf("*\n");
  1386. }
  1387. #endif
  1388. #ifdef  TIMING
  1389. ptime(why)
  1390. char      *why;
  1391. /*
  1392.  * Dump time buffer
  1393.  */
  1394. {
  1395.   long  ttemp;
  1396.  
  1397.   ttemp = time(NULL);
  1398.   printf("%ld seconds for %s\n",
  1399.       ttemp - sectiontime, why);
  1400.   sectiontime = ttemp;
  1401. }
  1402. #endif
  1403.  
  1404. /*
  1405.  *        s t r e q . c
  1406.  */
  1407.  
  1408. /*)LIBRARY
  1409. */
  1410.  
  1411.  
  1412. /* #define  EOS  0
  1413. #define  FALSE  0
  1414. #define  TRUE  1
  1415. */
  1416. int
  1417. streq(s1, s2)
  1418. register char  *s1;
  1419. register char  *s2;
  1420. /*
  1421.  * TRUE if strings are identical
  1422.  */
  1423. {
  1424.   while (*s1++ == *s2) {
  1425.       if (*s2++ == EOS)
  1426.       return (TRUE);
  1427.   }
  1428.   return (FALSE);
  1429. }
  1430. /*
  1431.  *        e r r o r . c
  1432.  */
  1433.  
  1434. /*)LIBRARY
  1435. */
  1436.  
  1437.  
  1438. /* VARARGS */
  1439. error(format, args)
  1440. char      *format;
  1441. /*
  1442.  * Error message before retiring.
  1443.  */
  1444. {
  1445.   fprintf(stderr, format, &args);
  1446.   putc('\n', stderr);
  1447.   _error();
  1448. }
  1449.  
  1450. _error()
  1451. {
  1452.   exit(1);
  1453. }
  1454.  
  1455. /* #include  <stdio.h> */
  1456.   
  1457. fputss(s, iop)
  1458. register char *s;
  1459. register FILE *iop;
  1460. /*
  1461.  * Like fput() except that it puts a newline at the end of the line.
  1462.  */
  1463. {
  1464. #ifndef OSK
  1465. /*
  1466.  * Why wasn't this written like the OSK section?  What's the difference between
  1467.  * fputc and putc other than I've never heard of fputc?
  1468.  */
  1469.   register c;
  1470.  
  1471.   while (c = *s++)
  1472.     fputc(c, iop);
  1473.   fputc('\n', iop);
  1474. #else
  1475.   fputs(s, iop);
  1476.   putc('\n', iop);
  1477. #endif
  1478. }
  1479.  
  1480.  
  1481. /*
  1482.  * Fgetss() is like fgets() except that the terminating newline
  1483.  * is removed.
  1484.  */
  1485. char *fgetss(s, n, iop)
  1486. char *s;
  1487. register FILE *iop;
  1488. {
  1489.   register c;
  1490.   register char *cs;
  1491.   
  1492.   cs = s;
  1493.   /*
  1494.    * The getc in the next line used to be an "fgetc".  Change it back if
  1495.    * getc doesn't work on your system, though that would be odd.
  1496.    */
  1497.   while ((c = getc(iop))>=0 && --n>0) {
  1498.       if (c=='\n')
  1499.         break;
  1500.       *cs++ = c;
  1501.   }
  1502.   if (c<0 && cs==s)
  1503.       return((char *)NULL);
  1504.   *cs = '\0';        /* Overwrite newline as null  */
  1505.   return(s);
  1506. }
  1507.