[BACK]Return to diffreg.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / diff

Diff for /src/usr.bin/diff/diffreg.c between version 1.26 and 1.27

version 1.26, 2003/07/04 17:37:07 version 1.27, 2003/07/06 20:48:59
Line 33 
Line 33 
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE   * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.   * POSSIBILITY OF SUCH DAMAGE.
  */   */
   /*-
    * Copyright (c) 1991, 1993
    *      The Regents of the University of California.  All rights reserved.
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions
    * are met:
    * 1. Redistributions of source code must retain the above copyright
    *    notice, this list of conditions and the following disclaimer.
    * 2. Redistributions in binary form must reproduce the above copyright
    *    notice, this list of conditions and the following disclaimer in the
    *    documentation and/or other materials provided with the distribution.
    * 3. Neither the name of the University nor the names of its contributors
    *    may be used to endorse or promote products derived from this software
    *    without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
    * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
    * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    * SUCH DAMAGE.
    *
    *      @(#)diffreg.c   8.1 (Berkeley) 6/6/93
    */
   
   #ifndef lint
   static const char rcsid[] = "$OpenBSD$";
   #endif /* not lint */
   
 #include <sys/types.h>  #include <sys/types.h>
   #include <sys/stat.h>
   
 #include <stdlib.h>  #include <ctype.h>
 #include <unistd.h>  #include <err.h>
 #include <fcntl.h>  #include <fcntl.h>
   #include <libgen.h>
   #include <paths.h>
   #include <signal.h>
   #include <stdio.h>
   #include <stdlib.h>
 #include <string.h>  #include <string.h>
   #include <unistd.h>
   
 #include "diff.h"  #include "diff.h"
 #include "pathnames.h"  
   
 #if 0  
 static char const sccsid[] = "@(#)diffreg.c 4.21 4/6/90";  
 #endif  
   
 /*  /*
  * diff - compare two files.   * diff - compare two files.
  */   */
Line 115 
Line 151 
  *      6n words for files of length n.   *      6n words for files of length n.
  */   */
   
 #define prints(s)       fputs(s,stdout)  
   
 FILE *input[2];  
   
 struct cand {  struct cand {
         int x;          int x;
         int y;          int y;
Line 130 
Line 162 
         int value;          int value;
 } *file[2];  } *file[2];
   
 int len[2];  static int  *J;                 /* will be overlaid on class */
 struct line *sfile[2];  /* shortened by pruning common prefix and suffix */  static int  *class;             /* will be overlaid on file[0] */
 int slen[2];  static int  *klist;             /* will be overlaid on file[0] after class */
 int pref, suff;                 /* length of prefix and suffix */  static int  *member;            /* will be overlaid on file[1] */
 int inifdef;                    /* whether or not we are in a #ifdef block */  static int   clen;
 int *class;                     /* will be overlaid on file[0] */  static int   inifdef;           /* whether or not we are in a #ifdef block */
 int *member;                    /* will be overlaid on file[1] */  static int   len[2];
 int *klist;                     /* will be overlaid on file[0] after class */  static int   pref, suff;        /* length of prefix and suffix */
 struct cand *clist;             /* merely a free storage pot for candidates */  static int   slen[2];
 int clen = 0;  static int   anychange;
 int *J;                         /* will be overlaid on class */  static long *ixnew;             /* will be overlaid on file[1] */
 long *ixold;                    /* will be overlaid on klist */  static long *ixold;             /* will be overlaid on klist */
 long *ixnew;                    /* will be overlaid on file[1] */  static struct cand *clist;      /* merely a free storage pot for candidates */
 u_char *chrtran;                /* translation table for case-folding */  static struct line *sfile[2];   /* shortened by pruning common prefix/suffix */
   static u_char *chrtran;         /* translation table for case-folding */
   
 static void fetch(long *, int, int, FILE *, char *, int);  static void fetch(long *, int, int, FILE *, char *, int);
 static void output(void);  static void output(char *, FILE *, char *, FILE *);
 static void check(void);  static void check(char *, FILE *, char *, FILE *);
 static void range(int, int, char *);  static void range(int, int, char *);
 static void dump_context_vec(void);  static void dump_context_vec(FILE *, FILE *);
 static void dump_unified_vec(void);  static void dump_unified_vec(FILE *, FILE *);
 static void prepare(int, FILE *);  static void prepare(int, FILE *);
 static void prune(void);  static void prune(void);
 static void equiv(struct line *, int, struct line *, int, int *);  static void equiv(struct line *, int, struct line *, int, int *);
 static void unravel(int);  static void unravel(int);
 static void unsort(struct line *, int, int *);  static void unsort(struct line *, int, int *);
 static void change(int, int, int, int);  static void change(char *, FILE *, char *, FILE *, int, int, int, int);
 static void sort(struct line *, int);  static void sort(struct line *, int);
 static int newcand(int, int, int);  static int  asciifile(FILE *);
 static int search(int *, int, int);  static int  newcand(int, int, int);
 static int skipline(int);  static int  search(int *, int, int);
 static int asciifile(FILE *);  static int  skipline(FILE *);
 static int stone(int *, int, int *, int *);  static int  stone(int *, int, int *, int *);
 static int readhash(FILE *);  static int  readhash(FILE *);
   static int  files_differ(FILE *, FILE *, int);
   
 /*  /*
  * chrtran points to one of 2 translation tables: cup2low if folding upper to   * chrtran points to one of 2 translation tables: cup2low if folding upper to
Line 224 
Line 258 
 };  };
   
 void  void
 diffreg(void)  diffreg(char *ofile1, char *ofile2, int flags)
 {  {
         char buf1[BUFSIZ], buf2[BUFSIZ];          char *file1 = ofile1;
         FILE *f1, *f2;          char *file2 = ofile2;
         int i, j;          FILE *f1 = NULL;
           FILE *f2 = NULL;
           int i;
   
           anychange = 0;
         chrtran = (iflag ? cup2low : clow2low);          chrtran = (iflag ? cup2low : clow2low);
         if (strcmp(file1, "-") == 0 && strcmp(file2, "-") == 0)          if (strcmp(file1, "-") == 0 && strcmp(file2, "-") == 0)
                 errorx("can't specify - -");                  goto notsame;
         if (S_ISDIR(stb1.st_mode)) {  
                 file1 = splice(file1, file2);          /* XXX - only make temp file for stdin if not seekable? (millert) */
                 if (stat(file1, &stb1) < 0)          if (flags & D_EMPTY1)
                         error("%s", file1);                  f1 = fopen(_PATH_DEVNULL, "r");
         } else if (strcmp(file1, "-") == 0 ||          else {
             (!S_ISREG(stb1.st_mode) && strcmp(file1, _PATH_DEVNULL) != 0)) {                  if (S_ISDIR(stb1.st_mode)) {
                 file1 = copytemp(file1, 1);                          file1 = splice(file1, file2);
                 if (stat(file1, &stb1) < 0)                          if (stat(file1, &stb1) < 0) {
                         error("%s", file1);                                  warn("%s", file1);
                                   status |= 2;
                                   goto closem;
                           }
                   } else if (strcmp(file1, "-") == 0 || !S_ISREG(stb1.st_mode)) {
                           file1 = copytemp(file1, 1);
                           if (file1 == NULL || stat(file1, &stb1) < 0) {
                                   warn("%s", file1);
                                   status |= 2;
                                   goto closem;
                           }
                   }
                   f1 = fopen(file1, "r");
         }          }
         if (S_ISDIR(stb2.st_mode)) {          if (f1 == NULL) {
                 file2 = splice(file2, file1);                  warn("%s", file1);
                 if (stat(file2, &stb2) < 0)                  status |= 2;
                         error("%s", file2);                  goto closem;
         } else if (strcmp(file2, "-") == 0 ||  
             (!S_ISREG(stb2.st_mode) && strcmp(file2, _PATH_DEVNULL) != 0)) {  
                 file2 = copytemp(file2, 2);  
                 if (stat(file2, &stb2) < 0)  
                         error("%s", file2);  
         }          }
         if ((f1 = fopen(file1, "r")) == NULL)  
                 error("%s", file1);          if (flags & D_EMPTY2)
         if ((f2 = fopen(file2, "r")) == NULL)                  f2 = fopen(_PATH_DEVNULL, "r");
                 error("%s", file2);          else {
         if ((stb1.st_mode & S_IFMT) != (stb2.st_mode & S_IFMT) ||                  if (S_ISDIR(stb2.st_mode)) {
             stb1.st_size != stb2.st_size)                          file2 = splice(file2, file1);
                 goto notsame;                          if (stat(file2, &stb2) < 0) {
         for (;;) {                                  warn("%s", file2);
                 i = fread(buf1, 1, BUFSIZ, f1);                                  status |= 2;
                 j = fread(buf2, 1, BUFSIZ, f2);                                  goto closem;
                 if (i < 0 || j < 0 || i != j)                          }
                         goto notsame;                  } else if (strcmp(file2, "-") == 0 || !S_ISREG(stb2.st_mode)) {
                 if (i == 0 && j == 0) {                          file2 = copytemp(file2, 2);
                         fclose(f1);                          if (file2 == NULL || stat(file2, &stb2) < 0) {
                         fclose(f2);                                  warn("%s", file2);
                         status = 0;     /* files don't differ */                                  status |= 2;
                         goto same;                                  goto closem;
                           }
                 }                  }
                 for (j = 0; j < i; j++)                  f2 = fopen(file2, "r");
                         if (buf1[j] != buf2[j])  
                                 goto notsame;  
         }          }
           if (f2 == NULL) {
                   warn("%s", file2);
                   status |= 2;
                   goto closem;
           }
   
           switch (files_differ(f1, f2, flags)) {
           case 0:
                   goto same;
           case 1:
                   break;
           default:
                   /* error */
                   status |= 2;
                   goto closem;
           }
   
 notsame:  notsame:
         /*          /*
          * Files certainly differ at this point; set status accordingly           * Files certainly differ at this point; set status accordingly
          */           */
         status = 1;          status |= 1;
           if (flags & D_HEADER) {
                   if (format == D_EDIT)
                           printf("ed - %s << '-*-END-*-'\n", basename(file1));
                   else
                           printf("%s %s %s\n", diffargs, file1, file2);
           }
         if (!asciifile(f1) || !asciifile(f2)) {          if (!asciifile(f1) || !asciifile(f2)) {
                 printf("Binary files %s and %s differ\n", file1, file2);                  printf("Binary files %s and %s differ\n", file1, file2);
                 exit(status);                  goto closem;
         }          }
         prepare(0, f1);          prepare(0, f1);
         prepare(1, f2);          prepare(1, f2);
         fclose(f1);  
         fclose(f2);  
         prune();          prune();
         sort(sfile[0], slen[0]);          sort(sfile[0], slen[0]);
         sort(sfile[1], slen[1]);          sort(sfile[1], slen[1]);
Line 306 
Line 370 
         free(member);          free(member);
         free(class);          free(class);
   
         J = emalloc((len[0] + 2) * sizeof(int));          J = erealloc(J, (len[0] + 2) * sizeof(int));
         unravel(klist[i]);          unravel(klist[i]);
         free(clist);          free(clist);
         free(klist);          free(klist);
   
         ixold = emalloc((len[0] + 2) * sizeof(long));          ixold = erealloc(ixold, (len[0] + 2) * sizeof(long));
         ixnew = emalloc((len[1] + 2) * sizeof(long));          ixnew = erealloc(ixnew, (len[1] + 2) * sizeof(long));
         check();          check(file1, f1, file2, f2);
         output();          output(file1, f1, file2, f2);
         status = anychange;          if ((flags & D_HEADER) && format == D_EDIT)
                   printf("w\nq\n-*-END-*-\n");
 same:  same:
         if (anychange == 0 && (opt == D_CONTEXT || opt == D_UNIFIED))          if (anychange == 0 && sflag != 0)
                 printf("No differences encountered\n");                  printf("Files %s and %s are identical\n", file1, file2);
   
   closem:
           if (f1 != NULL)
                   fclose(f1);
           if (f2 != NULL)
                   fclose(f2);
           if (tempfiles[0] != NULL) {
                   unlink(tempfiles[0]);
                   free(tempfiles[0]);
                   tempfiles[0] = NULL;
           }
           if (tempfiles[1] != NULL) {
                   unlink(tempfiles[1]);
                   free(tempfiles[1]);
                   tempfiles[1] = NULL;
           }
           if (file1 != ofile1)
                   free(file1);
           if (file2 != ofile2)
                   free(file2);
 }  }
   
   /*
    * Check to see if the given files differ.
    * Returns 0 if they are the same, 1 if different, and -1 on error.
    * XXX - could use code from cmp(1) [faster]
    */
   static int
   files_differ(FILE *f1, FILE *f2, int flags)
   {
           char buf1[BUFSIZ], buf2[BUFSIZ];
           size_t i, j;
   
           if ((flags & (D_EMPTY1|D_EMPTY2)) || stb1.st_size != stb2.st_size ||
               (stb1.st_mode & S_IFMT) != (stb2.st_mode & S_IFMT))
                   return (1);
           for (;;) {
                   i = fread(buf1, 1, sizeof(buf1), f1);
                   j = fread(buf2, 1, sizeof(buf2), f2);
                   if (i != j)
                           return (1);
                   if (i == 0 && j == 0) {
                           if (ferror(f1) || ferror(f2))
                                   return (1);
                           return (0);
                   }
                   if (memcmp(buf1, buf2, i) != 0)
                           return (1);
           }
   }
   
 char *tempfiles[2];  char *tempfiles[2];
   
   /* XXX - pass back a FILE * too (millert) */
 char *  char *
 copytemp(const char *file, int n)  copytemp(const char *file, int n)
 {  {
Line 335 
Line 450 
         if (strcmp(file, "-") == 0)          if (strcmp(file, "-") == 0)
                 ifd = STDIN_FILENO;                  ifd = STDIN_FILENO;
         else if ((ifd = open(file, O_RDONLY, 0644)) < 0)          else if ((ifd = open(file, O_RDONLY, 0644)) < 0)
                 error("%s", file);                  return (NULL);
   
         if ((tempdir = getenv("TMPDIR")) == NULL)          if ((tempdir = getenv("TMPDIR")) == NULL)
                 tempdir = _PATH_TMP;                  tempdir = _PATH_TMP;
         if (asprintf(&tempfile, "%s/diff%d.XXXXXXXX", tempdir, n) == -1)          if (asprintf(&tempfile, "%s/diff%d.XXXXXXXX", tempdir, n) == -1)
                 error(NULL);                  return (NULL);
         tempfiles[n - 1] = tempfile;          tempfiles[n - 1] = tempfile;
   
         signal(SIGHUP, done);          signal(SIGHUP, quit);
         signal(SIGINT, done);          signal(SIGINT, quit);
         signal(SIGPIPE, done);          signal(SIGPIPE, quit);
         signal(SIGTERM, done);          signal(SIGTERM, quit);
         ofd = mkstemp(tempfile);          ofd = mkstemp(tempfile);
         if (ofd < 0)          if (ofd < 0)
                 error("%s", tempfile);                  return (NULL);
         while ((i = read(ifd, buf, BUFSIZ)) > 0) {          while ((i = read(ifd, buf, BUFSIZ)) > 0) {
                 if (write(ofd, buf, i) != i)                  if (write(ofd, buf, i) != i)
                         error("%s", tempfile);                          return (NULL);
         }          }
         close(ifd);          close(ifd);
         close(ofd);          close(ofd);
Line 365 
Line 480 
         char *tail, *buf;          char *tail, *buf;
         size_t len;          size_t len;
   
         if (!strcmp(file, "-"))  
                 errorx("can't specify - with other arg directory");  
         tail = strrchr(file, '/');          tail = strrchr(file, '/');
         if (tail == NULL)          if (tail == NULL)
                 tail = file;                  tail = file;
Line 384 
Line 497 
         struct line *p;          struct line *p;
         int j, h;          int j, h;
   
         fseek(fd, 0L, SEEK_SET);          rewind(fd);
         p = emalloc(3 * sizeof(struct line));          p = emalloc(3 * sizeof(struct line));
         for (j = 0; (h = readhash(fd));) {          for (j = 0; (h = readhash(fd));) {
                 p = erealloc(p, (++j + 3) * sizeof(struct line));                  p = erealloc(p, (++j + 3) * sizeof(struct line));
Line 538 
Line 651 
  *  2.  collect random access indexes to the two files   *  2.  collect random access indexes to the two files
  */   */
 static void  static void
 check(void)  check(char *file1, FILE *f1, char *file2, FILE *f2)
 {  {
         int i, j, jackpot, c, d;          int i, j, jackpot, c, d;
         long ctold, ctnew;          long ctold, ctnew;
   
         if ((input[0] = fopen(file1, "r")) == NULL)          rewind(f1);
                 error("%s", file1);          rewind(f2);
         if ((input[1] = fopen(file2, "r")) == NULL)  
                 error("%s", file2);  
         j = 1;          j = 1;
         ixold[0] = ixnew[0] = 0;          ixold[0] = ixnew[0] = 0;
         jackpot = 0;          jackpot = 0;
         ctold = ctnew = 0;          ctold = ctnew = 0;
         for (i = 1; i <= len[0]; i++) {          for (i = 1; i <= len[0]; i++) {
                 if (J[i] == 0) {                  if (J[i] == 0) {
                         ixold[i] = ctold += skipline(0);                          ixold[i] = ctold += skipline(f1);
                         continue;                          continue;
                 }                  }
                 while (j < J[i]) {                  while (j < J[i]) {
                         ixnew[j] = ctnew += skipline(1);                          ixnew[j] = ctnew += skipline(f2);
                         j++;                          j++;
                 }                  }
                 if (bflag || wflag || iflag) {                  if (bflag || wflag || iflag) {
                         for (;;) {                          for (;;) {
                                 c = getc(input[0]);                                  c = getc(f1);
                                 d = getc(input[1]);                                  d = getc(f2);
                                 ctold++;                                  ctold++;
                                 ctnew++;                                  ctnew++;
                                 if (bflag && isspace(c) && isspace(d)) {                                  if (bflag && isspace(c) && isspace(d)) {
Line 571 
Line 682 
                                                 if (c == '\n')                                                  if (c == '\n')
                                                         break;                                                          break;
                                                 ctold++;                                                  ctold++;
                                         } while (isspace(c = getc(input[0])));                                          } while (isspace(c = getc(f1)));
                                         do {                                          do {
                                                 if (d == '\n')                                                  if (d == '\n')
                                                         break;                                                          break;
                                                 ctnew++;                                                  ctnew++;
                                         } while (isspace(d = getc(input[1])));                                          } while (isspace(d = getc(f2)));
                                 } else if (wflag) {                                  } else if (wflag) {
                                         while (isspace(c) && c != '\n') {                                          while (isspace(c) && c != '\n') {
                                                 c = getc(input[0]);                                                  c = getc(f1);
                                                 ctold++;                                                  ctold++;
                                         }                                          }
                                         while (isspace(d) && d != '\n') {                                          while (isspace(d) && d != '\n') {
                                                 d = getc(input[1]);                                                  d = getc(f2);
                                                 ctnew++;                                                  ctnew++;
                                         }                                          }
                                 }                                  }
Line 591 
Line 702 
                                         jackpot++;                                          jackpot++;
                                         J[i] = 0;                                          J[i] = 0;
                                         if (c != '\n')                                          if (c != '\n')
                                                 ctold += skipline(0);                                                  ctold += skipline(f1);
                                         if (d != '\n')                                          if (d != '\n')
                                                 ctnew += skipline(1);                                                  ctnew += skipline(f2);
                                         break;                                          break;
                                 }                                  }
                                 if (c == '\n')                                  if (c == '\n')
Line 603 
Line 714 
                         for (;;) {                          for (;;) {
                                 ctold++;                                  ctold++;
                                 ctnew++;                                  ctnew++;
                                 if ((c = getc(input[0])) != (d = getc(input[1]))) {                                  if ((c = getc(f1)) != (d = getc(f2))) {
                                         /* jackpot++; */                                          /* jackpot++; */
                                         J[i] = 0;                                          J[i] = 0;
                                         if (c != '\n')                                          if (c != '\n')
                                                 ctold += skipline(0);                                                  ctold += skipline(f1);
                                         if (d != '\n')                                          if (d != '\n')
                                                 ctnew += skipline(1);                                                  ctnew += skipline(f2);
                                         break;                                          break;
                                 }                                  }
                                 if (c == '\n')                                  if (c == '\n')
Line 620 
Line 731 
                 ixnew[j] = ctnew;                  ixnew[j] = ctnew;
                 j++;                  j++;
         }          }
         for (; j <= len[1]; j++) {          for (; j <= len[1]; j++)
                 ixnew[j] = ctnew += skipline(1);                  ixnew[j] = ctnew += skipline(f2);
         }  
         fclose(input[0]);  
         fclose(input[1]);  
         /*          /*
          * if (jackpot)           * if (jackpot)
          *      fprintf(stderr, "jackpot\n");           *      fprintf(stderr, "jackpot\n");
Line 678 
Line 786 
 }  }
   
 static int  static int
 skipline(int f)  skipline(FILE *f)
 {  {
         int i, c;          int i, c;
   
         for (i = 1; (c = getc(input[f])) != '\n'; i++)          for (i = 1; (c = getc(f)) != '\n'; i++)
                 if (c < 0)                  if (c < 0)
                         return (i);                          return (i);
         return (i);          return (i);
 }  }
   
 static void  static void
 output(void)  output(char *file1, FILE *f1, char *file2, FILE *f2)
 {  {
         int m, i0, i1, j0, j1;          int m, i0, i1, j0, j1;
   
         input[0] = fopen(file1, "r");          rewind(f1);
         input[1] = fopen(file2, "r");          rewind(f2);
         m = len[0];          m = len[0];
         J[0] = 0;          J[0] = 0;
         J[m + 1] = len[1] + 1;          J[m + 1] = len[1] + 1;
         if (opt != D_EDIT) {          if (format != D_EDIT) {
                 for (i0 = 1; i0 <= m; i0 = i1 + 1) {                  for (i0 = 1; i0 <= m; i0 = i1 + 1) {
                         while (i0 <= m && J[i0] == J[i0 - 1] + 1)                          while (i0 <= m && J[i0] == J[i0 - 1] + 1)
                                 i0++;                                  i0++;
Line 708 
Line 816 
                                 i1++;                                  i1++;
                         j1 = J[i1 + 1] - 1;                          j1 = J[i1 + 1] - 1;
                         J[i1] = j1;                          J[i1] = j1;
                         change(i0, i1, j0, j1);                          change(file1, f1, file2, f2, i0, i1, j0, j1);
                 }                  }
         } else {          } else {
                 for (i0 = m; i0 >= 1; i0 = i1 - 1) {                  for (i0 = m; i0 >= 1; i0 = i1 - 1) {
Line 720 
Line 828 
                                 i1--;                                  i1--;
                         j1 = J[i1 - 1] + 1;                          j1 = J[i1 - 1] + 1;
                         J[i1] = j1;                          J[i1] = j1;
                         change(i1, i0, j1, j0);                          change(file1, f1, file2, f2, i1, i0, j1, j0);
                 }                  }
         }          }
         if (m == 0)          if (m == 0)
                 change(1, 0, 1, len[1]);                  change(file1, f1, file2, f2, 1, 0, 1, len[1]);
         if (opt == D_IFDEF) {          if (format == D_IFDEF) {
                 for (;;) {                  for (;;) {
 #define c i0  #define c i0
                         c = getc(input[0]);                          c = getc(f1);
                         if (c < 0)                          if (c < 0)
                                 return;                                  return;
                         putchar(c);                          putchar(c);
Line 736 
Line 844 
 #undef c  #undef c
         }          }
         if (anychange != 0) {          if (anychange != 0) {
                 if (opt == D_CONTEXT)                  if (format == D_CONTEXT)
                         dump_context_vec();                          dump_context_vec(f1, f2);
                 else if (opt == D_UNIFIED)                  else if (format == D_UNIFIED)
                         dump_unified_vec();                          dump_unified_vec(f1, f2);
         }          }
 }  }
   
 /*  /*
  * The following struct is used to record change information when   * The following struct is used to record change information when
  * doing a "context" diff.  (see routine "change" to understand the   * doing a "context" or "unified" diff.  (see routine "change" to
  * highly mneumonic field names)   * understand the highly mnemonic field names)
  */   */
 struct context_vec {  struct context_vec {
         int a;                  /* start line in old file */          int a;                  /* start line in old file */
Line 760 
Line 868 
 #define MAX_CONTEXT     128  #define MAX_CONTEXT     128
   
 /*  /*
  * indicate that there is a difference between lines a and b of the from file   * Indicate that there is a difference between lines a and b of the from file
  * to get to lines c to d of the to file. If a is greater then b then there   * to get to lines c to d of the to file.  If a is greater then b then there
  * are no lines in the from file involved and this means that there were   * are no lines in the from file involved and this means that there were
  * lines appended (beginning at b). If c is greater than d then there are   * lines appended (beginning at b).  If c is greater than d then there are
  * lines missing from the to file.   * lines missing from the to file.
  */   */
 static void  static void
 change(int a, int b, int c, int d)  change(char *file1, FILE *f1, char *file2, FILE *f2, int a, int b, int c, int d)
 {  {
         struct stat stbuf;          if (format != D_IFDEF && a > b && c > d)
   
         if (opt != D_IFDEF && a > b && c > d)  
                 return;                  return;
         if (anychange == 0) {          if (anychange == 0) {
                 anychange = 1;                  anychange = 1;
                 if (opt == D_CONTEXT || opt == D_UNIFIED) {                  if (format == D_CONTEXT || format == D_UNIFIED) {
                         stat(file1, &stbuf);                          printf("%s %s   %s", format == D_CONTEXT ? "***" : "---",
                         printf("%s %s   %s", opt == D_CONTEXT ? "***" : "---",                             file1, ctime(&stb1.st_mtime));
                            file1, ctime(&stbuf.st_mtime));                          printf("%s %s   %s", format == D_CONTEXT ? "---" : "+++",
                         stat(file2, &stbuf);                              file2, ctime(&stb2.st_mtime));
                         printf("%s %s   %s", opt == D_CONTEXT ? "---" : "+++",                          if (context_vec_start == NULL)
                             file2, ctime(&stbuf.st_mtime));                                  context_vec_start = emalloc(MAX_CONTEXT *
                         context_vec_start = emalloc(MAX_CONTEXT *                                      sizeof(struct context_vec));
                             sizeof(struct context_vec));  
                         context_vec_end = context_vec_start + MAX_CONTEXT;                          context_vec_end = context_vec_start + MAX_CONTEXT;
                         context_vec_ptr = context_vec_start - 1;                          context_vec_ptr = context_vec_start - 1;
                 }                  }
         }          }
         if (opt == D_CONTEXT || opt == D_UNIFIED) {          if (format == D_CONTEXT || format == D_UNIFIED) {
                 /*                  /*
                  * If this new change is within 'context' lines of                   * If this new change is within 'context' lines of
                  * the previous change, just add it to the change                   * the previous change, just add it to the change
Line 800 
Line 905 
                     (context_vec_ptr >= context_vec_start &&                      (context_vec_ptr >= context_vec_start &&
                     a > (context_vec_ptr->b + 2 * context) &&                      a > (context_vec_ptr->b + 2 * context) &&
                     c > (context_vec_ptr->d + 2 * context))) {                      c > (context_vec_ptr->d + 2 * context))) {
                         if (opt == D_CONTEXT)                          if (format == D_CONTEXT)
                                 dump_context_vec();                                  dump_context_vec(f1, f2);
                         else                          else
                                 dump_unified_vec();                                  dump_unified_vec(f1, f2);
                 }                  }
                 context_vec_ptr++;                  context_vec_ptr++;
                 context_vec_ptr->a = a;                  context_vec_ptr->a = a;
Line 812 
Line 917 
                 context_vec_ptr->d = d;                  context_vec_ptr->d = d;
                 return;                  return;
         }          }
         switch (opt) {          switch (format) {
   
         case D_NORMAL:          case D_NORMAL:
         case D_EDIT:          case D_EDIT:
                 range(a, b, ",");                  range(a, b, ",");
                 putchar(a > b ? 'a' : c > d ? 'd' : 'c');                  putchar(a > b ? 'a' : c > d ? 'd' : 'c');
                 if (opt == D_NORMAL)                  if (format == D_NORMAL)
                         range(c, d, ",");                          range(c, d, ",");
                 putchar('\n');                  putchar('\n');
                 break;                  break;
Line 838 
Line 943 
                 }                  }
                 break;                  break;
         }          }
         if (opt == D_NORMAL || opt == D_IFDEF) {          if (format == D_NORMAL || format == D_IFDEF) {
                 fetch(ixold, a, b, input[0], "< ", 1);                  fetch(ixold, a, b, f1, "< ", 1);
                 if (a <= b && c <= d && opt == D_NORMAL)                  if (a <= b && c <= d && format == D_NORMAL)
                         prints("---\n");                          puts("---");
         }          }
         fetch(ixnew, c, d, input[1], opt == D_NORMAL ? "> " : "", 0);          fetch(ixnew, c, d, f2, format == D_NORMAL ? "> " : "", 0);
         if ((opt == D_EDIT || opt == D_REVERSE) && c <= d)          if ((format == D_EDIT || format == D_REVERSE) && c <= d)
                 prints(".\n");                  puts(".");
         if (inifdef) {          if (inifdef) {
                 fprintf(stdout, "#endif /* %s */\n", ifdefname);                  fprintf(stdout, "#endif /* %s */\n", ifdefname);
                 inifdef = 0;                  inifdef = 0;
Line 869 
Line 974 
          * When doing #ifdef's, copy down to current line           * When doing #ifdef's, copy down to current line
          * if this is the first file, so that stuff makes it to output.           * if this is the first file, so that stuff makes it to output.
          */           */
         if (opt == D_IFDEF && oldfile) {          if (format == D_IFDEF && oldfile) {
                 long curpos = ftell(lb);                  long curpos = ftell(lb);
                 /* print through if append (a>b), else to (nb: 0 vs 1 orig) */                  /* print through if append (a>b), else to (nb: 0 vs 1 orig) */
                 nc = f[a > b ? b : a - 1] - curpos;                  nc = f[a > b ? b : a - 1] - curpos;
Line 878 
Line 983 
         }          }
         if (a > b)          if (a > b)
                 return;                  return;
         if (opt == D_IFDEF) {          if (format == D_IFDEF) {
                 if (inifdef) {                  if (inifdef) {
                         fprintf(stdout, "#else /* %s%s */\n",                          fprintf(stdout, "#else /* %s%s */\n",
                             oldfile == 1 ? "!" : "", ifdefname);                              oldfile == 1 ? "!" : "", ifdefname);
Line 893 
Line 998 
         for (i = a; i <= b; i++) {          for (i = a; i <= b; i++) {
                 fseek(lb, f[i - 1], SEEK_SET);                  fseek(lb, f[i - 1], SEEK_SET);
                 nc = f[i] - f[i - 1];                  nc = f[i] - f[i - 1];
                 if (opt != D_IFDEF)                  if (format != D_IFDEF)
                         prints(s);                          fputs(s, stdout);
                 col = 0;                  col = 0;
                 for (j = 0; j < nc; j++) {                  for (j = 0; j < nc; j++) {
                         c = getc(lb);                          c = getc(lb);
Line 984 
Line 1089 
         return ((short) low(sum) + (short) high(sum));          return ((short) low(sum) + (short) high(sum));
 }  }
   
 static int  int
 asciifile(FILE *f)  asciifile(FILE *f)
 {  {
         char buf[BUFSIZ], *cp;          char buf[BUFSIZ], *cp;
         int cnt;          int cnt;
   
         if (aflag)          if (aflag || f == NULL)
                 return (1);                  return (1);
   
         fseek(f, 0L, SEEK_SET);          rewind(f);
         cnt = fread(buf, 1, BUFSIZ, f);          cnt = fread(buf, 1, sizeof(buf), f);
         cp = buf;          cp = buf;
         while (--cnt >= 0)          while (--cnt >= 0)
                 if (*cp++ & 0200)                  if (*cp++ & 0200)
Line 1002 
Line 1107 
         return (1);          return (1);
 }  }
   
   static __inline int min(int a, int b)
   {
           return (a < b ? a : b);
   }
   
   static __inline int max(int a, int b)
   {
           return (a > b ? a : b);
   }
   
 /* dump accumulated "context" diff changes */  /* dump accumulated "context" diff changes */
 static void  static void
 dump_context_vec(void)  dump_context_vec(FILE *f1, FILE *f2)
 {  {
         struct context_vec *cvp = context_vec_start;          struct context_vec *cvp = context_vec_start;
         int lowa, upb, lowc, upd, do_output;          int lowa, upb, lowc, upd, do_output;
Line 1025 
Line 1140 
         printf(" ****\n");          printf(" ****\n");
   
         /*          /*
          * output changes to the "old" file.  The first loop suppresses           * Output changes to the "old" file.  The first loop suppresses
          * output if there were no changes to the "old" file (we'll see           * output if there were no changes to the "old" file (we'll see
          * the "old" lines as context in the "new" list).           * the "old" lines as context in the "new" list).
          */           */
Line 1049 
Line 1164 
                                 ch = (a <= b) ? 'd' : 'a';                                  ch = (a <= b) ? 'd' : 'a';
   
                         if (ch == 'a')                          if (ch == 'a')
                                 fetch(ixold, lowa, b, input[0], "  ", 0);                                  fetch(ixold, lowa, b, f1, "  ", 0);
                         else {                          else {
                                 fetch(ixold, lowa, a - 1, input[0], "  ", 0);                                  fetch(ixold, lowa, a - 1, f1, "  ", 0);
                                 fetch(ixold, a, b, input[0],                                  fetch(ixold, a, b, f1,
                                     ch == 'c' ? "! " : "- ", 0);                                      ch == 'c' ? "! " : "- ", 0);
                         }                          }
                         lowa = b + 1;                          lowa = b + 1;
                         cvp++;                          cvp++;
                 }                  }
                 fetch(ixold, b + 1, upb, input[0], "  ", 0);                  fetch(ixold, b + 1, upb, f1, "  ", 0);
         }          }
         /* output changes to the "new" file */          /* output changes to the "new" file */
         printf("--- ");          printf("--- ");
Line 1085 
Line 1200 
                                 ch = (a <= b) ? 'd' : 'a';                                  ch = (a <= b) ? 'd' : 'a';
   
                         if (ch == 'd')                          if (ch == 'd')
                                 fetch(ixnew, lowc, d, input[1], "  ", 0);                                  fetch(ixnew, lowc, d, f2, "  ", 0);
                         else {                          else {
                                 fetch(ixnew, lowc, c - 1, input[1], "  ", 0);                                  fetch(ixnew, lowc, c - 1, f2, "  ", 0);
                                 fetch(ixnew, c, d, input[1],                                  fetch(ixnew, c, d, f2,
                                     ch == 'c' ? "! " : "+ ", 0);                                      ch == 'c' ? "! " : "+ ", 0);
                         }                          }
                         lowc = d + 1;                          lowc = d + 1;
                         cvp++;                          cvp++;
                 }                  }
                 fetch(ixnew, d + 1, upd, input[1], "  ", 0);                  fetch(ixnew, d + 1, upd, f2, "  ", 0);
         }          }
         context_vec_ptr = context_vec_start - 1;          context_vec_ptr = context_vec_start - 1;
 }  }
   
 /* dump accumulated "unified" diff changes */  /* dump accumulated "unified" diff changes */
 static void  static void
 dump_unified_vec(void)  dump_unified_vec(FILE *f1, FILE *f2)
 {  {
         struct context_vec *cvp = context_vec_start;          struct context_vec *cvp = context_vec_start;
         int lowa, upb, lowc, upd;          int lowa, upb, lowc, upd;
Line 1142 
Line 1257 
   
                 switch (ch) {                  switch (ch) {
                 case 'c':                  case 'c':
                         fetch(ixold, lowa, a - 1, input[0], " ", 0);                          fetch(ixold, lowa, a - 1, f1, " ", 0);
                         fetch(ixold, a, b, input[0], "-", 0);                          fetch(ixold, a, b, f1, "-", 0);
                         fetch(ixnew, c, d, input[1], "+", 0);                          fetch(ixnew, c, d, f2, "+", 0);
                         break;                          break;
                 case 'd':                  case 'd':
                         fetch(ixold, lowa, a - 1, input[0], " ", 0);                          fetch(ixold, lowa, a - 1, f1, " ", 0);
                         fetch(ixold, a, b, input[0], "-", 0);                          fetch(ixold, a, b, f1, "-", 0);
                         break;                          break;
                 case 'a':                  case 'a':
                         fetch(ixnew, lowc, c - 1, input[1], " ", 0);                          fetch(ixnew, lowc, c - 1, f2, " ", 0);
                         fetch(ixnew, c, d, input[1], "+", 0);                          fetch(ixnew, c, d, f2, "+", 0);
                         break;                          break;
                 }                  }
                 lowa = b + 1;                  lowa = b + 1;
                 lowc = d + 1;                  lowc = d + 1;
         }          }
         fetch(ixnew, d + 1, upd, input[1], " ", 0);          fetch(ixnew, d + 1, upd, f2, " ", 0);
   
         context_vec_ptr = context_vec_start - 1;          context_vec_ptr = context_vec_start - 1;
 }  }

Legend:
Removed from v.1.26  
changed lines
  Added in v.1.27