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

Diff for /src/usr.bin/sdiff/sdiff.c between version 1.12 and 1.13

version 1.12, 2005/12/28 05:57:46 version 1.13, 2006/02/14 08:26:20
Line 41 
Line 41 
 static void enqueue(const char *, const char, const char *);  static void enqueue(const char *, const char, const char *);
 static void freediff(const struct diffline *);  static void freediff(const struct diffline *);
 static void int_usage(void);  static void int_usage(void);
 static int parsecmd(FILE *, FILE *);  static int parsecmd(FILE *, FILE *, FILE *);
 static void printa(FILE *, size_t);  static void printa(FILE *, size_t);
 static void printc(FILE *, size_t, FILE *, size_t);  static void printc(FILE *, size_t, FILE *, size_t);
 static void printcol(const char *, size_t *, const size_t);  static void printcol(const char *, size_t *, const size_t);
 static void printd(FILE *, FILE *, size_t);  static void printd(FILE *, size_t);
 static void println(const char *, const char, const char *);  static void println(const char *, const char, const char *);
 static void processq(void);  static void processq(void);
 static void prompt(const char *, const char *);  static void prompt(const char *, const char *);
 static void undiff(char *);  
 __dead static void usage(void);  __dead static void usage(void);
 static char *xfgets(FILE *);  static char *xfgets(FILE *);
   
Line 57 
Line 56 
 size_t   line_width;    /* width of a line (two columns and divider) */  size_t   line_width;    /* width of a line (two columns and divider) */
 size_t   width;         /* width of each column */  size_t   width;         /* width of each column */
 size_t   file1ln, file2ln;      /* line number of file1 and file2 */  size_t   file1ln, file2ln;      /* line number of file1 and file2 */
   int      Iflag = 0;     /* ignore sets matching regexp */
 int      lflag;         /* print only left column for identical lines */  int      lflag;         /* print only left column for identical lines */
 int      sflag;         /* skip identical lines */  int      sflag;         /* skip identical lines */
 FILE    *outfile;       /* file to save changes to */  FILE    *outfile;       /* file to save changes to */
Line 83 
Line 83 
 int  int
 main(int argc, char **argv)  main(int argc, char **argv)
 {  {
         FILE *difffile, *origfile;          FILE *diffpipe, *file1, *file2;
         size_t diffargc = 0, wflag = WIDTH;          size_t diffargc = 0, wflag = WIDTH;
         int ch, fd[2], status;          int ch, fd[2], status;
         pid_t pid;          pid_t pid;
         const char *cmd, **diffargv, *diffprog = "diff";          const char **diffargv, *diffprog = "diff", *s1, *s2;
   
         /*          /*
          * Process diff flags.           * Process diff flags.
Line 133 
Line 133 
                         diffargv[diffargc++] = "-H";                          diffargv[diffargc++] = "-H";
                         break;                          break;
                 case 'I':                  case 'I':
                           Iflag = 1;
                         diffargv[diffargc++] = "-I";                          diffargv[diffargc++] = "-I";
                         diffargv[diffargc++] = optarg;                          diffargv[diffargc++] = optarg;
                         break;                          break;
Line 216 
Line 217 
         close(fd[1]);          close(fd[1]);
   
         /* Open pipe to diff command. */          /* Open pipe to diff command. */
         if ((difffile = fdopen(fd[0], "r")) == NULL)          if ((diffpipe = fdopen(fd[0], "r")) == NULL)
                 err(2, "could not open diff pipe");                  err(2, "could not open diff pipe");
         /* If file1 was given as `-', open stdin. */          /* If file1 or file2 were given as `-', open stdin. */
         /* XXX - Does not work. */          /* XXX - Does not work. */
         if (strcmp(argv[0], "-") == 0)          if (strcmp(argv[0], "-") == 0)
                 origfile = stdin;                  file1 = stdin;
         /* Otherwise, open as normal file. */          /* Otherwise, open as normal file. */
         else if ((origfile = fopen(argv[0], "r")) == NULL)          else if ((file1 = fopen(argv[0], "r")) == NULL)
                 err(2, "could not open file1: %s", argv[0]);                  err(2, "could not open file1: %s", argv[0]);
           /* XXX - Handle (file1 == file2 == stdin) case. */
           if (strcmp(argv[1], "-") == 0)
                   file2 = stdin;
           /* Otherwise, open as normal file. */
           else if ((file2 = fopen(argv[1], "r")) == NULL)
                   err(2, "could not open file2: %s", argv[1]);
         /* Line numbers start at one. */          /* Line numbers start at one. */
         file1ln = file2ln = 1;          file1ln = file2ln = 1;
   
         /* Read and parse diff output. */          /* Read and parse diff output. */
         while (parsecmd(difffile, origfile) != EOF)          while (parsecmd(diffpipe, file1, file2) != EOF)
                 ;                  ;
         fclose(difffile);          fclose(diffpipe);
   
         /* Wait for diff to exit. */          /* Wait for diff to exit. */
         if (waitpid(pid, &status, 0) == -1 || !WIFEXITED(status) ||          if (waitpid(pid, &status, 0) == -1 || !WIFEXITED(status) ||
Line 239 
Line 246 
                 err(2, "diff exited abnormally");                  err(2, "diff exited abnormally");
   
         /* No more diffs, so print common lines. */          /* No more diffs, so print common lines. */
         while ((cmd = xfgets(origfile)))          if (lflag)
                 enqueue(cmd, ' ', lflag ? NULL : cmd);                  while ((s1 = xfgets(file1)))
         fclose(origfile);                          enqueue(s1, ' ', NULL);
           else
                   for (;;) {
                           s1 = xfgets(file1);
                           s2 = xfgets(file2);
                           if (s1 || s2)
                                   enqueue(s1, ' ', s2);
                           else
                                   break;
                   }
           fclose(file1);
           fclose(file2);
         /* Process unmodified lines. */          /* Process unmodified lines. */
         processq();          processq();
   
Line 445 
Line 463 
 }  }
   
 /*  /*
  * Parse ed commands from diff and print lines from difffile   * Parse ed commands from diffpipe and print lines from file1 (lines
  * (lines to add or change) or origfile (lines to change or delete).   * to change or delete) or file2 (lines to add or change).
  * Returns EOF or not.   * Returns EOF or 0.
  */   */
 static int  static int
 parsecmd(FILE *difffile, FILE *origfile)  parsecmd(FILE *diffpipe, FILE *file1, FILE *file2)
 {  {
         size_t file1start, file1end, file2start, file2end;          size_t file1start, file1end, file2start, file2end, n;
         /* ed command line and pointer to characters in line */          /* ed command line and pointer to characters in line */
         char *line, *p, *q;          char *line, *p, *q;
         const char *errstr;          const char *errstr;
         char c, cmd;          char c, cmd;
   
         /* Read ed command. */          /* Read ed command. */
         if (!(line = xfgets(difffile)))          if (!(line = xfgets(diffpipe)))
                 return (EOF);                  return (EOF);
   
         p = line;          p = line;
Line 544 
Line 562 
                 file2start = ++file2end;                  file2start = ++file2end;
         }          }
   
         /* Skip unmodified lines. */          /*
         for (; file1ln < file1start; ++file1ln, ++file2ln) {           * Continue reading file1 and file2 until we reach line numbers
                 const char *line;           * specified by diff.  Should only happen with -I flag.
            */
           for (; file1ln < file1start && file2ln < file2start;
               ++file1ln, ++file2ln) {
                   const char *s1, *s2;
   
                 if (!(line = xfgets(origfile)))                  if (!(s1 = xfgets(file1)))
                         errx(2, "file1 shorter than expected");                          errx(2, "file1 shorter than expected");
                   if (!(s2 = xfgets(file2)))
                           errx(2, "file2 shorter than expected");
   
                 /* If the -l flag was specified, print only left column. */                  /* If the -l flag was specified, print only left column. */
                 enqueue(line, ' ', lflag ? NULL : line);                  if (lflag) {
                           free((void *)s2);
                           /*
                            * XXX - If -l and -I are both specified, all
                            * unchanged or ignored lines are shown with a
                            * `(' divider.  This matches GNU sdiff, but I
                            * believe it is a bug.  Just check out:
                            * gsdiff -l -I '^$' samefile samefile.
                            */
                           if (Iflag)
                                   enqueue(s1, '(', NULL);
                           else
                                   enqueue(s1, ' ', NULL);
                   } else
                           enqueue(s1, ' ', s2);
         }          }
         /* Process unmodified lines. */          /* Ignore deleted lines. */
           for (; file1ln < file1start; ++file1ln) {
                   const char *s;
   
                   if (!(s = xfgets(file1)))
                           errx(2, "file1 shorter than expected");
   
                   enqueue(s, '(', NULL);
           }
           /* Ignore added lines. */
           for (; file2ln < file2start; ++file2ln) {
                   const char *s;
   
                   if (!(s = xfgets(file2)))
                           errx(2, "file2 shorter than expected");
   
                   /* If -l flag was given, don't print right column. */
                   if (lflag)
                           free((void *)s);
                   else
                           enqueue(NULL, ')', s);
           }
   
           /* Process unmodified or skipped lines. */
         processq();          processq();
   
         switch (cmd) {          switch (cmd) {
         case 'a':          case 'a':
                 printa(difffile, file2end);                  printa(file2, file2end);
                   n = file2end - file2start + 1;
                 break;                  break;
   
         case 'c':          case 'c':
                 printc(origfile, file1end, difffile, file2end);                  printc(file1, file1end, file2, file2end);
                   n = file1end - file1start + 1 + 1 + file2end - file2start + 1;
                 break;                  break;
   
         case 'd':          case 'd':
                 printd(origfile, difffile, file1end);                  printd(file1, file1end);
                   n = file1end - file1start + 1;
                 break;                  break;
   
         default:          default:
                 errx(2, "invalid diff command: %c: %s", cmd, line);                  errx(2, "invalid diff command: %c: %s", cmd, line);
         }          }
   
           /* Skip to next ed line. */
           while (n--)
                   if (!xfgets(diffpipe))
                           errx(2, "diff ended early");
   
         return (0);          return (0);
 }  }
   
Line 599 
Line 668 
 static void  static void
 freediff(const struct diffline *diffp)  freediff(const struct diffline *diffp)
 {  {
   
         if (diffp->left)          if (diffp->left)
                 free((void *)diffp->left);                  free((void *)diffp->left);
         /*          if (diffp->right)
          * Free right string only if it is different than left.  
          * The strings are the same when the lines are identical.  
          */  
         if (diffp->right && diffp->right != diffp->left)  
                 free((void *)diffp->right);                  free((void *)diffp->right);
           free((void *)diffp);
 }  }
   
 /*  /*
Line 706 
Line 771 
                         div = diffp->div;                          div = diffp->div;
   
                 /*                  /*
                  * If the -s flag was not given or the lines are not                   * Print changed lines if -s was given,
                  * identical then print columns.                   * print all lines if -s was not given.
                  */                   */
                 if (!sflag || diffp->div != ' ')                  if (!sflag || div == '|' || div == '<' || div == '>')
                         println(diffp->left, diffp->div, diffp->right);                          println(diffp->left, diffp->div, diffp->right);
   
                 /* Append new lines to diff set. */                  /* Append new lines to diff set. */
Line 722 
Line 787 
         /* Empty queue and free each diff line and its elements. */          /* Empty queue and free each diff line and its elements. */
         while (!SIMPLEQ_EMPTY(&diffhead)) {          while (!SIMPLEQ_EMPTY(&diffhead)) {
                 diffp = SIMPLEQ_FIRST(&diffhead);                  diffp = SIMPLEQ_FIRST(&diffhead);
                 freediff(diffp);  
                 SIMPLEQ_REMOVE_HEAD(&diffhead, diffentries);                  SIMPLEQ_REMOVE_HEAD(&diffhead, diffentries);
                 free(diffp);                  freediff(diffp);
         }          }
   
         /* Write to outfile, prompting user if lines are different. */          /* Write to outfile, prompting user if lines are different. */
         if (outfile) {          if (outfile)
                 if (div == ' ')                  switch (div) {
                   case ' ': case '(': case ')':
                         fprintf(outfile, "%s\n", left);                          fprintf(outfile, "%s\n", left);
                 else                          break;
                   case '|': case '<': case '>':
                         prompt(left, right);                          prompt(left, right);
         }                          break;
                   default:
                           errx(2, "invalid divider: %c", div);
                   }
   
         /* Free left and right. */          /* Free left and right. */
         if (left)          if (left)
Line 743 
Line 812 
 }  }
   
 /*  /*
  * Remove angle bracket in front of diff line.  
  */  
 static void  
 undiff(char *s)  
 {  
         size_t len;  
   
         /* Remove angle bracket and space but keep the NUL. */  
         len = strlen(s) - 2 + 1;  
         /* Move everything two characters over. */  
         memmove(s, s + 2, len);  
 }  
   
 /*  
  * Print lines following an (a)ppend command.   * Print lines following an (a)ppend command.
  */   */
 static void  static void
Line 767 
Line 822 
         for (; file2ln <= line2; ++file2ln) {          for (; file2ln <= line2; ++file2ln) {
                 if (!(line = xfgets(file)))                  if (!(line = xfgets(file)))
                         errx(2, "append ended early");                          errx(2, "append ended early");
                 undiff(line);  
                 enqueue(NULL, '>', line);                  enqueue(NULL, '>', line);
         }          }
   
Line 786 
Line 840 
                 const char      *line;                  const char      *line;
         };          };
         SIMPLEQ_HEAD(, fileline) delqhead = SIMPLEQ_HEAD_INITIALIZER(delqhead);          SIMPLEQ_HEAD(, fileline) delqhead = SIMPLEQ_HEAD_INITIALIZER(delqhead);
         char *line;  
   
         /* Read lines to be deleted. */          /* Read lines to be deleted. */
         for (; file1ln <= file1end; ++file1ln) {          for (; file1ln <= file1end; ++file1ln) {
                 struct fileline *linep;                  struct fileline *linep;
                 const char *line1, *line2;                  const char *line1;
   
                 /* Read lines from both. */                  /* Read lines from both. */
                 if (!(line1 = xfgets(file1)))                  if (!(line1 = xfgets(file1)))
                         errx(2, "error reading file1 in delete in change");                          errx(2, "error reading file1 in delete in change");
                 if (!(line2 = xfgets(file2)))  
                         errx(2, "error reading diff in delete in change");  
   
                 /* Unused now. */  
                 free((void *)line2);  
   
                 /* Add to delete queue. */                  /* Add to delete queue. */
                 if (!(linep = malloc(sizeof(struct fileline))))                  if (!(linep = malloc(sizeof(struct fileline))))
                         err(2, "printc");                          err(2, "printc");
Line 809 
Line 857 
                 SIMPLEQ_INSERT_TAIL(&delqhead, linep, fileentries);                  SIMPLEQ_INSERT_TAIL(&delqhead, linep, fileentries);
         }          }
   
         /* There should be a divider here. */  
         if (!(line = xfgets(file2)))  
                 errx(2, "error reading diff in change: expected divider");  
         free(line);  
   
 #define getaddln(add) do {                                      \  
         /* Read diff for line. */                               \  
         if (!((add) = xfgets(file2)))                           \  
                 errx(2, "error reading add in change");         \  
         /* Remove ``> ''. */                                    \  
         undiff(add);                                            \  
 } while (0)  
         /* Process changed lines.. */          /* Process changed lines.. */
         for (; !SIMPLEQ_EMPTY(&delqhead) && file2ln <= file2end;          for (; !SIMPLEQ_EMPTY(&delqhead) && file2ln <= file2end;
             ++file2ln) {              ++file2ln) {
Line 828 
Line 864 
                 char *add;                  char *add;
   
                 /* Get add line. */                  /* Get add line. */
                 getaddln(add);                  if (!(add = xfgets(file2)))
                           errx(2, "error reading add in change");
   
                 del = SIMPLEQ_FIRST(&delqhead);                  del = SIMPLEQ_FIRST(&delqhead);
                 enqueue(del->line, '|', add);                  enqueue(del->line, '|', add);
Line 846 
Line 883 
                 char *add;                  char *add;
   
                 /* Get add line. */                  /* Get add line. */
                 getaddln(add);                  if (!(add = xfgets(file2)))
                           errx(2, "error reading add in change");
   
                 enqueue(NULL, '>', add);                  enqueue(NULL, '>', add);
         }          }
Line 869 
Line 907 
  * Print deleted lines from file, from file1ln to file1end.   * Print deleted lines from file, from file1ln to file1end.
  */   */
 static void  static void
 printd(FILE *file1, FILE *file2, size_t file1end)  printd(FILE *file1, size_t file1end)
 {  {
         const char *line1, *line2;          const char *line1;
   
         /* Print out lines file1ln to line2. */          /* Print out lines file1ln to line2. */
         for (; file1ln <= file1end; ++file1ln) {          for (; file1ln <= file1end; ++file1ln) {
                 /* XXX - Why can't this handle stdin? */                  /* XXX - Why can't this handle stdin? */
                 if (!(line1 = xfgets(file1)))                  if (!(line1 = xfgets(file1)))
                         errx(2, "file1 ended early in delete");                          errx(2, "file1 ended early in delete");
                 if (!(line2 = xfgets(file2)))  
                         errx(2, "diff ended early in delete");  
                 free((void *)line2);  
                 enqueue(line1, '<', NULL);                  enqueue(line1, '<', NULL);
         }          }
         processq();          processq();

Legend:
Removed from v.1.12  
changed lines
  Added in v.1.13