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

Diff for /src/usr.bin/patch/pch.c between version 1.16 and 1.17

version 1.16, 2003/07/18 02:00:09 version 1.17, 2003/07/21 14:00:41
Line 1 
Line 1 
 /*      $OpenBSD$       */  /* $OpenBSD$     */
   
 #ifndef lint  #ifndef lint
 static char rcsid[] = "$OpenBSD$";  static char rcsid[] = "$OpenBSD$";
Line 10 
Line 10 
 #include "INTERN.h"  #include "INTERN.h"
 #include "pch.h"  #include "pch.h"
   
 extern bool check_only;  extern bool     check_only;
 /* Patch (diff listing) abstract type. */  /* Patch (diff listing) abstract type. */
   
 static long p_filesize;                 /* size of the patch file */  static long     p_filesize;     /* size of the patch file */
 static LINENUM p_first;                 /* 1st line number */  static LINENUM  p_first;        /* 1st line number */
 static LINENUM p_newfirst;              /* 1st line number of replacement */  static LINENUM  p_newfirst;     /* 1st line number of replacement */
 static LINENUM p_ptrn_lines;            /* # lines in pattern */  static LINENUM  p_ptrn_lines;   /* # lines in pattern */
 static LINENUM p_repl_lines;            /* # lines in replacement text */  static LINENUM  p_repl_lines;   /* # lines in replacement text */
 static LINENUM p_end = -1;              /* last line in hunk */  static LINENUM  p_end = -1;     /* last line in hunk */
 static LINENUM p_max;                   /* max allowed value of p_end */  static LINENUM  p_max;          /* max allowed value of p_end */
 static LINENUM p_context = 3;           /* # of context lines */  static LINENUM  p_context = 3;  /* # of context lines */
 static LINENUM p_input_line = 0;        /* current line # from patch file */  static LINENUM  p_input_line = 0;       /* current line # from patch file */
 static char **p_line = Null(char**);    /* the text of the hunk */  static char     **p_line = Null(char **);       /* the text of the hunk */
 static short *p_len = Null(short*);     /* length of each line */  static short    *p_len = Null(short *); /* length of each line */
 static char *p_char = Nullch;           /* +, -, and ! */  static char     *p_char = Nullch;/* +, -, and ! */
 static int hunkmax = INITHUNKMAX;       /* size of above arrays to begin with */  static int      hunkmax = INITHUNKMAX;  /* size of above arrays to begin with */
 static int p_indent;                    /* indent to patch */  static int      p_indent;       /* indent to patch */
 static LINENUM p_base;                  /* where to intuit this time */  static LINENUM  p_base;         /* where to intuit this time */
 static LINENUM p_bline;                 /* line # of p_base */  static LINENUM  p_bline;        /* line # of p_base */
 static LINENUM p_start;                 /* where intuit found a patch */  static LINENUM  p_start;        /* where intuit found a patch */
 static LINENUM p_sline;                 /* and the line number for it */  static LINENUM  p_sline;        /* and the line number for it */
 static LINENUM p_hunk_beg;              /* line number of current hunk */  static LINENUM  p_hunk_beg;     /* line number of current hunk */
 static LINENUM p_efake = -1;            /* end of faked up lines--don't free */  static LINENUM  p_efake = -1;   /* end of faked up lines--don't free */
 static LINENUM p_bfake = -1;            /* beg of faked up lines */  static LINENUM  p_bfake = -1;   /* beg of faked up lines */
   
 /* Prepare to look for the next patch in the patch file. */  /*
    * Prepare to look for the next patch in the patch file.
    */
 void  void
 re_patch()  re_patch(void)
 {  {
     p_first = Nulline;          p_first = Nulline;
     p_newfirst = Nulline;          p_newfirst = Nulline;
     p_ptrn_lines = Nulline;          p_ptrn_lines = Nulline;
     p_repl_lines = Nulline;          p_repl_lines = Nulline;
     p_end = (LINENUM)-1;          p_end = (LINENUM) - 1;
     p_max = Nulline;          p_max = Nulline;
     p_indent = 0;          p_indent = 0;
 }  }
   
 /* Open the patch file at the beginning of time. */  /*
    * Open the patch file at the beginning of time.
    */
 void  void
 open_patch_file(filename)  open_patch_file(char *filename)
 char *filename;  
 {  {
     if (filename == Nullch || !*filename || strEQ(filename, "-")) {          if (filename == Nullch || !*filename || strEQ(filename, "-")) {
         pfp = fopen(TMPPATNAME, "w");                  pfp = fopen(TMPPATNAME, "w");
                   if (pfp == Nullfp)
                           pfatal("can't create %s", TMPPATNAME);
                   while (fgets(buf, sizeof buf, stdin) != Nullch)
                           fputs(buf, pfp);
                   fclose(pfp);
                   filename = TMPPATNAME;
           }
           pfp = fopen(filename, "r");
         if (pfp == Nullfp)          if (pfp == Nullfp)
             pfatal("can't create %s", TMPPATNAME);                  pfatal("patch file %s not found", filename);
         while (fgets(buf, sizeof buf, stdin) != Nullch)          fstat(fileno(pfp), &filestat);
             fputs(buf, pfp);          p_filesize = filestat.st_size;
         fclose(pfp);          next_intuit_at(0L, 1L); /* start at the beginning */
         filename = TMPPATNAME;          set_hunkmax();
     }  
     pfp = fopen(filename, "r");  
     if (pfp == Nullfp)  
         pfatal("patch file %s not found", filename);  
     fstat(fileno(pfp), &filestat);  
     p_filesize = filestat.st_size;  
     next_intuit_at(0L,1L);                      /* start at the beginning */  
     set_hunkmax();  
 }  }
   
 /* Make sure our dynamically realloced tables are malloced to begin with. */  /*
    * Make sure our dynamically realloced tables are malloced to begin with.
    */
 void  void
 set_hunkmax()  set_hunkmax(void)
 {  {
 #ifndef lint  #ifndef lint
     if (p_line == Null(char**))          if (p_line == Null(char **))
         p_line = (char**) malloc((MEM)hunkmax * sizeof(char *));                  p_line = (char **) malloc((MEM) hunkmax * sizeof(char *));
     if (p_len == Null(short*))          if (p_len == Null(short *))
         p_len  = (short*) malloc((MEM)hunkmax * sizeof(short));                  p_len = (short *) malloc((MEM) hunkmax * sizeof(short));
 #endif  #endif
     if (p_char == Nullch)          if (p_char == Nullch)
         p_char = (char*)  malloc((MEM)hunkmax * sizeof(char));                  p_char = (char *) malloc((MEM) hunkmax * sizeof(char));
 }  }
   
 /* Enlarge the arrays containing the current hunk of patch. */  /*
    * Enlarge the arrays containing the current hunk of patch.
    */
 void  void
 grow_hunkmax()  grow_hunkmax(void)
 {  {
     hunkmax *= 2;          hunkmax *= 2;
     /*  
      * Note that on most systems, only the p_line array ever gets fresh memory          /*
      * since p_len can move into p_line's old space, and p_char can move into           * Note that on most systems, only the p_line array ever gets fresh memory
      * p_len's old space.  Not on PDP-11's however.  But it doesn't matter.           * since p_len can move into p_line's old space, and p_char can move into
      */           * p_len's old space.  Not on PDP-11's however.  But it doesn't matter.
     assert(p_line != Null(char**) && p_len != Null(short*) && p_char != Nullch);           */
           assert(p_line != Null(char **) &&p_len != Null(short *) &&p_char != Nullch);
 #ifndef lint  #ifndef lint
     p_line = (char**) realloc((char*)p_line, (MEM)hunkmax * sizeof(char *));          p_line = (char **) realloc((char *) p_line, (MEM) hunkmax * sizeof(char *));
     p_len  = (short*) realloc((char*)p_len,  (MEM)hunkmax * sizeof(short));          p_len = (short *) realloc((char *) p_len, (MEM) hunkmax * sizeof(short));
     p_char = (char*)  realloc((char*)p_char, (MEM)hunkmax * sizeof(char));          p_char = (char *) realloc((char *) p_char, (MEM) hunkmax * sizeof(char));
 #endif  #endif
     if (p_line != Null(char**) && p_len != Null(short*) && p_char != Nullch)          if (p_line != Null(char **) &&p_len != Null(short *) &&p_char != Nullch)
         return;                  return;
     if (!using_plan_a)          if (!using_plan_a)
         fatal("out of memory\n");                  fatal("out of memory\n");
     out_of_mem = TRUE;          /* whatever is null will be allocated again */          out_of_mem = TRUE;      /* whatever is null will be allocated again */
                                 /* from within plan_a(), of all places */          /* from within plan_a(), of all places */
 }  }
   
 /* True if the remainder of the patch file contains a diff of some sort. */  /* True if the remainder of the patch file contains a diff of some sort. */
   
 bool  bool
 there_is_another_patch()  there_is_another_patch(void)
 {  {
     if (p_base != 0L && p_base >= p_filesize) {          if (p_base != 0L && p_base >= p_filesize) {
                   if (verbose)
                           say("done\n");
                   return FALSE;
           }
         if (verbose)          if (verbose)
             say("done\n");                  say("Hmm...");
         return FALSE;          diff_type = intuit_diff_type();
     }          if (!diff_type) {
     if (verbose)                  if (p_base != 0L) {
         say("Hmm...");                          if (verbose)
     diff_type = intuit_diff_type();                                  say("  Ignoring the trailing garbage.\ndone\n");
     if (!diff_type) {                  } else
         if (p_base != 0L) {                          say("  I can't seem to find a patch in there anywhere.\n");
             if (verbose)                  return FALSE;
                 say("  Ignoring the trailing garbage.\ndone\n");  
         }          }
         else          if (verbose)
             say("  I can't seem to find a patch in there anywhere.\n");                  say("  %sooks like %s to me...\n",
         return FALSE;                      (p_base == 0L ? "L" : "The next patch l"),
     }                      diff_type == UNI_DIFF ? "a unified diff" :
     if (verbose)                      diff_type == CONTEXT_DIFF ? "a context diff" :
         say("  %sooks like %s to me...\n",                  diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" :
             (p_base == 0L ? "L" : "The next patch l"),                      diff_type == NORMAL_DIFF ? "a normal diff" :
             diff_type == UNI_DIFF ? "a unified diff" :                      "an ed script");
             diff_type == CONTEXT_DIFF ? "a context diff" :          if (p_indent && verbose)
             diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" :                  say("(Patch is indented %d space%s.)\n", p_indent,
             diff_type == NORMAL_DIFF ? "a normal diff" :                      p_indent == 1 ? "" : "s");
             "an ed script" );          skip_to(p_start, p_sline);
     if (p_indent && verbose)          while (filearg[0] == Nullch) {
         say("(Patch is indented %d space%s.)\n", p_indent, p_indent==1?"":"s");                  if (force || batch) {
     skip_to(p_start,p_sline);                          say("No file to patch.  Skipping...\n");
     while (filearg[0] == Nullch) {                          filearg[0] = savestr(bestguess);
         if (force || batch) {                          skip_rest_of_patch = TRUE;
             say("No file to patch.  Skipping...\n");                          return TRUE;
             filearg[0] = savestr(bestguess);                  }
             skip_rest_of_patch = TRUE;                  ask("File to patch: ");
             return TRUE;                  if (*buf != '\n') {
                           if (bestguess)
                                   free(bestguess);
                           bestguess = savestr(buf);
                           filearg[0] = fetchname(buf, 0, FALSE);
                   }
                   if (filearg[0] == Nullch) {
                           ask("No file found--skip this patch? [n] ");
                           if (*buf != 'y')
                                   continue;
                           if (verbose)
                                   say("Skipping patch...\n");
                           filearg[0] = fetchname(bestguess, 0, TRUE);
                           skip_rest_of_patch = TRUE;
                           return TRUE;
                   }
         }          }
         ask("File to patch: ");          return TRUE;
         if (*buf != '\n') {  
             if (bestguess)  
                 free(bestguess);  
             bestguess = savestr(buf);  
             filearg[0] = fetchname(buf, 0, FALSE);  
         }  
         if (filearg[0] == Nullch) {  
             ask("No file found--skip this patch? [n] ");  
             if (*buf != 'y') {  
                 continue;  
             }  
             if (verbose)  
                 say("Skipping patch...\n");  
             filearg[0] = fetchname(bestguess, 0, TRUE);  
             skip_rest_of_patch = TRUE;  
             return TRUE;  
         }  
     }  
     return TRUE;  
 }  }
   
 /* Determine what kind of diff is in the remaining part of the patch file. */  /* Determine what kind of diff is in the remaining part of the patch file. */
   
 int  int
 intuit_diff_type()  intuit_diff_type(void)
 {  {
     long this_line = 0;          long    this_line = 0, previous_line;
     long previous_line;          long    first_command_line = -1, fcl_line;
     long first_command_line = -1;          bool    last_line_was_command = FALSE, this_is_a_command = FALSE;
     long fcl_line;          bool    stars_last_line = FALSE, stars_this_line = FALSE;
     bool last_line_was_command = FALSE;          char    *s, *t;
     bool this_is_a_command = FALSE;          char    *indtmp = Nullch;
     bool stars_last_line = FALSE;          char    *oldtmp = Nullch;
     bool stars_this_line = FALSE;          char    *newtmp = Nullch;
     int indent;          char    *indname = Nullch;
     char *s;          char    *oldname = Nullch;
     char *t;          char    *newname = Nullch;
     char *indtmp = Nullch;          int     indent, retval;
     char *oldtmp = Nullch;          bool    no_filearg = (filearg[0] == Nullch);
     char *newtmp = Nullch;  
     char *indname = Nullch;  
     char *oldname = Nullch;  
     char *newname = Nullch;  
     int retval;  
     bool no_filearg = (filearg[0] == Nullch);  
   
     ok_to_create_file = FALSE;          ok_to_create_file = FALSE;
     fseek(pfp, p_base, 0);          fseek(pfp, p_base, 0);
     p_input_line = p_bline - 1;          p_input_line = p_bline - 1;
     for (;;) {          for (;;) {
         previous_line = this_line;                  previous_line = this_line;
         last_line_was_command = this_is_a_command;                  last_line_was_command = this_is_a_command;
         stars_last_line = stars_this_line;                  stars_last_line = stars_this_line;
         this_line = ftell(pfp);                  this_line = ftell(pfp);
         indent = 0;                  indent = 0;
         p_input_line++;                  p_input_line++;
         if (fgets(buf, sizeof buf, pfp) == Nullch) {                  if (fgets(buf, sizeof buf, pfp) == Nullch) {
             if (first_command_line >= 0L) {                          if (first_command_line >= 0L) {
                                         /* nothing but deletes!? */                                  /* nothing but deletes!? */
                 p_start = first_command_line;                                  p_start = first_command_line;
                 p_sline = fcl_line;                                  p_sline = fcl_line;
                 retval = ED_DIFF;                                  retval = ED_DIFF;
                 goto scan_exit;                                  goto scan_exit;
             }                          } else {
             else {                                  p_start = this_line;
                 p_start = this_line;                                  p_sline = p_input_line;
                 p_sline = p_input_line;                                  retval = 0;
                 retval = 0;                                  goto scan_exit;
                 goto scan_exit;                          }
             }                  }
                   for (s = buf; *s == ' ' || *s == '\t' || *s == 'X'; s++) {
                           if (*s == '\t')
                                   indent += 8 - (indent % 8);
                           else
                                   indent++;
                   }
                   for (t = s; isdigit(*t) || *t == ','; t++)
                           ;
                   this_is_a_command = (isdigit(*s) &&
                       (*t == 'd' || *t == 'c' || *t == 'a'));
                   if (first_command_line < 0L && this_is_a_command) {
                           first_command_line = this_line;
                           fcl_line = p_input_line;
                           p_indent = indent;      /* assume this for now */
                   }
                   if (!stars_last_line && strnEQ(s, "*** ", 4))
                           oldtmp = savestr(s + 4);
                   else if (strnEQ(s, "--- ", 4))
                           newtmp = savestr(s + 4);
                   else if (strnEQ(s, "+++ ", 4))
                           oldtmp = savestr(s + 4);        /* pretend it is the old
                                                            * name */
                   else if (strnEQ(s, "Index:", 6))
                           indtmp = savestr(s + 6);
                   else if (strnEQ(s, "Prereq:", 7)) {
                           for (t = s + 7; isspace(*t); t++);
                           revision = savestr(t);
                           for (t = revision; *t && !isspace(*t); t++);
                           *t = '\0';
                           if (!*revision) {
                                   free(revision);
                                   revision = Nullch;
                           }
                   }
                   if ((!diff_type || diff_type == ED_DIFF) &&
                       first_command_line >= 0L &&
                       strEQ(s, ".\n")) {
                           p_indent = indent;
                           p_start = first_command_line;
                           p_sline = fcl_line;
                           retval = ED_DIFF;
                           goto scan_exit;
                   }
                   if ((!diff_type || diff_type == UNI_DIFF) && strnEQ(s, "@@ -", 4)) {
                           if (!atol(s + 3))
                                   ok_to_create_file = TRUE;
                           p_indent = indent;
                           p_start = this_line;
                           p_sline = p_input_line;
                           retval = UNI_DIFF;
                           goto scan_exit;
                   }
                   stars_this_line = strnEQ(s, "********", 8);
                   if ((!diff_type || diff_type == CONTEXT_DIFF) && stars_last_line &&
                       strnEQ(s, "*** ", 4)) {
                           if (!atol(s + 4))
                                   ok_to_create_file = TRUE;
                           /*
                            * if this is a new context diff the character just
                            * before
                            */
                           /* the newline is a '*'. */
                           while (*s != '\n')
                                   s++;
                           p_indent = indent;
                           p_start = previous_line;
                           p_sline = p_input_line - 1;
                           retval = (*(s - 1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF);
                           goto scan_exit;
                   }
                   if ((!diff_type || diff_type == NORMAL_DIFF) &&
                       last_line_was_command &&
                       (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2))) {
                           p_start = previous_line;
                           p_sline = p_input_line - 1;
                           p_indent = indent;
                           retval = NORMAL_DIFF;
                           goto scan_exit;
                   }
         }          }
         for (s = buf; *s == ' ' || *s == '\t' || *s == 'X'; s++) {  scan_exit:
             if (*s == '\t')          if (no_filearg) {
                 indent += 8 - (indent % 8);                  if (indtmp != Nullch)
             else                          indname = fetchname(indtmp, strippath, ok_to_create_file);
                 indent++;                  if (oldtmp != Nullch)
                           oldname = fetchname(oldtmp, strippath, ok_to_create_file);
                   if (newtmp != Nullch)
                           newname = fetchname(newtmp, strippath, ok_to_create_file);
                   if (indname)
                           filearg[0] = savestr(indname);
                   else if (oldname && newname) {
                           if (strlen(oldname) < strlen(newname))
                                   filearg[0] = savestr(oldname);
                           else
                                   filearg[0] = savestr(newname);
                   } else if (oldname)
                           filearg[0] = savestr(oldname);
                   else if (newname)
                           filearg[0] = savestr(newname);
         }          }
         for (t=s; isdigit(*t) || *t == ','; t++) ;          if (bestguess) {
         this_is_a_command = (isdigit(*s) &&                  free(bestguess);
           (*t == 'd' || *t == 'c' || *t == 'a') );                  bestguess = Nullch;
         if (first_command_line < 0L && this_is_a_command) {  
             first_command_line = this_line;  
             fcl_line = p_input_line;  
             p_indent = indent;          /* assume this for now */  
         }          }
         if (!stars_last_line && strnEQ(s, "*** ", 4))          if (filearg[0] != Nullch)
             oldtmp = savestr(s+4);                  bestguess = savestr(filearg[0]);
         else if (strnEQ(s, "--- ", 4))          else if (indtmp != Nullch)
             newtmp = savestr(s+4);                  bestguess = fetchname(indtmp, strippath, TRUE);
         else if (strnEQ(s, "+++ ", 4))          else {
             oldtmp = savestr(s+4);      /* pretend it is the old name */                  if (oldtmp != Nullch)
         else if (strnEQ(s, "Index:", 6))                          oldname = fetchname(oldtmp, strippath, TRUE);
             indtmp = savestr(s+6);                  if (newtmp != Nullch)
         else if (strnEQ(s, "Prereq:", 7)) {                          newname = fetchname(newtmp, strippath, TRUE);
             for (t=s+7; isspace(*t); t++) ;                  if (oldname && newname) {
             revision = savestr(t);                          if (strlen(oldname) < strlen(newname))
             for (t=revision; *t && !isspace(*t); t++) ;                                  bestguess = savestr(oldname);
             *t = '\0';                          else
             if (!*revision) {                                  bestguess = savestr(newname);
                 free(revision);                  } else if (oldname)
                 revision = Nullch;                          bestguess = savestr(oldname);
             }                  else if (newname)
                           bestguess = savestr(newname);
         }          }
         if ((!diff_type || diff_type == ED_DIFF) &&  
           first_command_line >= 0L &&  
           strEQ(s, ".\n") ) {  
             p_indent = indent;  
             p_start = first_command_line;  
             p_sline = fcl_line;  
             retval = ED_DIFF;  
             goto scan_exit;  
         }  
         if ((!diff_type || diff_type == UNI_DIFF) && strnEQ(s, "@@ -", 4)) {  
             if (!atol(s+3))  
                 ok_to_create_file = TRUE;  
             p_indent = indent;  
             p_start = this_line;  
             p_sline = p_input_line;  
             retval = UNI_DIFF;  
             goto scan_exit;  
         }  
         stars_this_line = strnEQ(s, "********", 8);  
         if ((!diff_type || diff_type == CONTEXT_DIFF) && stars_last_line &&  
                  strnEQ(s, "*** ", 4)) {  
             if (!atol(s+4))  
                 ok_to_create_file = TRUE;  
             /* if this is a new context diff the character just before */  
             /* the newline is a '*'. */  
             while (*s != '\n')  
                 s++;  
             p_indent = indent;  
             p_start = previous_line;  
             p_sline = p_input_line - 1;  
             retval = (*(s-1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF);  
             goto scan_exit;  
         }  
         if ((!diff_type || diff_type == NORMAL_DIFF) &&  
           last_line_was_command &&  
           (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2)) ) {  
             p_start = previous_line;  
             p_sline = p_input_line - 1;  
             p_indent = indent;  
             retval = NORMAL_DIFF;  
             goto scan_exit;  
         }  
     }  
   scan_exit:  
     if (no_filearg) {  
         if (indtmp != Nullch)          if (indtmp != Nullch)
             indname = fetchname(indtmp, strippath, ok_to_create_file);                  free(indtmp);
         if (oldtmp != Nullch)          if (oldtmp != Nullch)
             oldname = fetchname(oldtmp, strippath, ok_to_create_file);                  free(oldtmp);
         if (newtmp != Nullch)          if (newtmp != Nullch)
             newname = fetchname(newtmp, strippath, ok_to_create_file);                  free(newtmp);
         if (indname)          if (indname != Nullch)
             filearg[0] = savestr(indname);                  free(indname);
         else if (oldname && newname) {          if (oldname != Nullch)
             if (strlen(oldname) < strlen(newname))                  free(oldname);
                 filearg[0] = savestr(oldname);          if (newname != Nullch)
             else                  free(newname);
                 filearg[0] = savestr(newname);          return retval;
         }  
         else if (oldname)  
             filearg[0] = savestr(oldname);  
         else if (newname)  
             filearg[0] = savestr(newname);  
     }  
     if (bestguess) {  
         free(bestguess);  
         bestguess = Nullch;  
     }  
     if (filearg[0] != Nullch)  
         bestguess = savestr(filearg[0]);  
     else if (indtmp != Nullch)  
         bestguess = fetchname(indtmp, strippath, TRUE);  
     else {  
         if (oldtmp != Nullch)  
             oldname = fetchname(oldtmp, strippath, TRUE);  
         if (newtmp != Nullch)  
             newname = fetchname(newtmp, strippath, TRUE);  
         if (oldname && newname) {  
             if (strlen(oldname) < strlen(newname))  
                 bestguess = savestr(oldname);  
             else  
                 bestguess = savestr(newname);  
         }  
         else if (oldname)  
             bestguess = savestr(oldname);  
         else if (newname)  
             bestguess = savestr(newname);  
     }  
     if (indtmp != Nullch)  
         free(indtmp);  
     if (oldtmp != Nullch)  
         free(oldtmp);  
     if (newtmp != Nullch)  
         free(newtmp);  
     if (indname != Nullch)  
         free(indname);  
     if (oldname != Nullch)  
         free(oldname);  
     if (newname != Nullch)  
         free(newname);  
     return retval;  
 }  }
   
 /* Remember where this patch ends so we know where to start up again. */  /*
    * Remember where this patch ends so we know where to start up again.
    */
 void  void
 next_intuit_at(file_pos,file_line)  next_intuit_at(long file_pos, long file_line)
 long file_pos;  
 long file_line;  
 {  {
     p_base = file_pos;          p_base = file_pos;
     p_bline = file_line;          p_bline = file_line;
 }  }
   
 /* Basically a verbose fseek() to the actual diff listing. */  /*
    * Basically a verbose fseek() to the actual diff listing.
    */
 void  void
 skip_to(file_pos,file_line)  skip_to(long file_pos, long file_line)
 long file_pos;  
 long file_line;  
 {  {
     char *ret;          char    *ret;
   
     assert(p_base <= file_pos);          assert(p_base <= file_pos);
     if (verbose && p_base < file_pos) {          if (verbose && p_base < file_pos) {
         fseek(pfp, p_base, 0);                  fseek(pfp, p_base, 0);
         say("The text leading up to this was:\n--------------------------\n");                  say("The text leading up to this was:\n--------------------------\n");
         while (ftell(pfp) < file_pos) {                  while (ftell(pfp) < file_pos) {
             ret = fgets(buf, sizeof buf, pfp);                          ret = fgets(buf, sizeof buf, pfp);
             assert(ret != Nullch);                          assert(ret != Nullch);
             say("|%s", buf);                          say("|%s", buf);
         }                  }
         say("--------------------------\n");                  say("--------------------------\n");
     }          } else
     else                  fseek(pfp, file_pos, 0);
         fseek(pfp, file_pos, 0);          p_input_line = file_line - 1;
     p_input_line = file_line - 1;  
 }  }
   
 /* Make this a function for better debugging.  */  /* Make this a function for better debugging.  */
 static void  static void
 malformed(void)  malformed(void)
 {  {
     fatal("malformed patch at line %ld: %s", p_input_line, buf);          fatal("malformed patch at line %ld: %s", p_input_line, buf);
                 /* about as informative as "Syntax error" in C */          /* about as informative as "Syntax error" in C */
 }  }
   
 /*  /*
Line 411 
Line 407 
 static bool  static bool
 remove_special_line(void)  remove_special_line(void)
 {  {
         int c;          int     c;
   
         c = fgetc(pfp);          c = fgetc(pfp);
         if (c == '\\') {          if (c == '\\') {
Line 421 
Line 417 
   
                 return TRUE;                  return TRUE;
         }          }
   
         if (c != EOF)          if (c != EOF)
                 fseek(pfp, -1L, SEEK_CUR);                  fseek(pfp, -1L, SEEK_CUR);
   
         return FALSE;          return FALSE;
 }  }
   
 /* True if there is more of the current diff listing to process. */  /*
    * True if there is more of the current diff listing to process.
    */
 bool  bool
 another_hunk()  another_hunk(void)
 {  {
     char *s;          long    line_beginning;                 /* file pos of the current line */
     char *ret;          LINENUM repl_beginning;                 /* index of --- line */
     int context = 0;          LINENUM fillcnt;                        /* #lines of missing ptrn or repl */
           LINENUM fillsrc;                        /* index of first line to copy */
           LINENUM filldst;                        /* index of first missing line */
           bool    ptrn_spaces_eaten;              /* ptrn was slightly misformed */
           bool    repl_could_be_missing;          /* no + or ! lines in this hunk */
           bool    repl_missing;                   /* we are now backtracking */
           long    repl_backtrack_position;        /* file pos of first repl line */
           LINENUM repl_patch_line;                /* input line number for same */
           LINENUM ptrn_copiable;                  /* # of copiable lines in ptrn */
           char    *s, *ret;
           int     context = 0;
   
     while (p_end >= 0) {          while (p_end >= 0) {
         if (p_end == p_efake)                  if (p_end == p_efake)
             p_end = p_bfake;            /* don't free twice */                          p_end = p_bfake;        /* don't free twice */
         else                  else
             free(p_line[p_end]);                          free(p_line[p_end]);
         p_end--;                  p_end--;
     }          }
     assert(p_end == -1);          assert(p_end == -1);
     p_efake = -1;          p_efake = -1;
   
     p_max = hunkmax;                    /* gets reduced when --- found */          p_max = hunkmax;        /* gets reduced when --- found */
     if (diff_type == CONTEXT_DIFF || diff_type == NEW_CONTEXT_DIFF) {          if (diff_type == CONTEXT_DIFF || diff_type == NEW_CONTEXT_DIFF) {
         long line_beginning = ftell(pfp);                  line_beginning = ftell(pfp);
                                         /* file pos of the current line */                  repl_beginning = 0;
         LINENUM repl_beginning = 0;     /* index of --- line */                  fillcnt = 0;
         LINENUM fillcnt = 0;    /* #lines of missing ptrn or repl */                  ptrn_spaces_eaten = FALSE;
         LINENUM fillsrc;                /* index of first line to copy */                  repl_could_be_missing = TRUE;
         LINENUM filldst;                /* index of first missing line */                  repl_missing = FALSE;
         bool ptrn_spaces_eaten = FALSE; /* ptrn was slightly misformed */                  repl_backtrack_position = 0;
         bool repl_could_be_missing = TRUE;                  ptrn_copiable = 0;
                                         /* no + or ! lines in this hunk */  
         bool repl_missing = FALSE;      /* we are now backtracking */  
         long repl_backtrack_position = 0;  
                                         /* file pos of first repl line */  
         LINENUM repl_patch_line;        /* input line number for same */  
         LINENUM ptrn_copiable = 0;  
                                         /* # of copiable lines in ptrn */  
   
         ret = pgets(buf, sizeof buf, pfp);                  ret = pgets(buf, sizeof buf, pfp);
         p_input_line++;                  p_input_line++;
         if (ret == Nullch || strnNE(buf, "********", 8)) {                  if (ret == Nullch || strnNE(buf, "********", 8)) {
             next_intuit_at(line_beginning,p_input_line);                          next_intuit_at(line_beginning, p_input_line);
             return FALSE;                          return FALSE;
         }  
         p_context = 100;  
         p_hunk_beg = p_input_line + 1;  
         while (p_end < p_max) {  
             line_beginning = ftell(pfp);  
             ret = pgets(buf, sizeof buf, pfp);  
             p_input_line++;  
             if (ret == Nullch) {  
                 if (p_max - p_end < 4) {  
                     /* assume blank lines got chopped */  
                     strlcpy(buf, "  \n", sizeof buf);  
                 } else {  
                     if (repl_beginning && repl_could_be_missing) {  
                         repl_missing = TRUE;  
                         goto hunk_done;  
                     }  
                     fatal("unexpected end of file in patch\n");  
                 }                  }
             }                  p_context = 100;
             p_end++;                  p_hunk_beg = p_input_line + 1;
             assert(p_end < hunkmax);                  while (p_end < p_max) {
             p_char[p_end] = *buf;                          line_beginning = ftell(pfp);
 #ifdef zilog                          ret = pgets(buf, sizeof buf, pfp);
             p_line[(short)p_end] = Nullch;                          p_input_line++;
 #else                          if (ret == Nullch) {
             p_line[p_end] = Nullch;                                  if (p_max - p_end < 4) {
                                           /* assume blank lines got chopped */
                                           strlcpy(buf, "  \n", sizeof buf);
                                   } else {
                                           if (repl_beginning && repl_could_be_missing) {
                                                   repl_missing = TRUE;
                                                   goto hunk_done;
                                           }
                                           fatal("unexpected end of file in patch\n");
                                   }
                           }
                           p_end++;
                           assert(p_end < hunkmax);
                           p_char[p_end] = *buf;
                           p_line[p_end] = Nullch;
                           switch (*buf) {
                           case '*':
                                   if (strnEQ(buf, "********", 8)) {
                                           if (repl_beginning && repl_could_be_missing) {
                                                   repl_missing = TRUE;
                                                   goto hunk_done;
                                           } else
                                                   fatal("unexpected end of hunk "
                                                       "at line %ld\n",
                                                       p_input_line);
                                   }
                                   if (p_end != 0) {
                                           if (repl_beginning && repl_could_be_missing) {
                                                   repl_missing = TRUE;
                                                   goto hunk_done;
                                           }
                                           fatal("unexpected *** at line %ld: %s",
                                               p_input_line, buf);
                                   }
                                   context = 0;
                                   p_line[p_end] = savestr(buf);
                                   if (out_of_mem) {
                                           p_end--;
                                           return FALSE;
                                   }
                                   for (s = buf; *s && !isdigit(*s); s++)
                                           ;
                                   if (!*s)
                                           malformed();
                                   if (strnEQ(s, "0,0", 3))
                                           memmove(s, s + 2, strlen(s + 2) + 1);
                                   p_first = (LINENUM) atol(s);
                                   while (isdigit(*s))
                                           s++;
                                   if (*s == ',') {
                                           for (; *s && !isdigit(*s); s++);
                                           if (!*s)
                                                   malformed();
                                           p_ptrn_lines = ((LINENUM) atol(s)) - p_first + 1;
                                   } else if (p_first)
                                           p_ptrn_lines = 1;
                                   else {
                                           p_ptrn_lines = 0;
                                           p_first = 1;
                                   }
                                   p_max = p_ptrn_lines + 6;       /* we need this much at
                                                                    * least */
                                   while (p_max >= hunkmax)
                                           grow_hunkmax();
                                   p_max = hunkmax;
                                   break;
                           case '-':
                                   if (buf[1] == '-') {
                                           if (repl_beginning ||
                                               (p_end != p_ptrn_lines + 1 +
                                               (p_char[p_end - 1] == '\n'))) {
                                                   if (p_end == 1) {
                                                           /*
                                                            * `old' lines were omitted;
                                                            * set up to fill them in
                                                            * from 'new' context lines.
                                                            */
                                                           p_end = p_ptrn_lines + 1;
                                                           fillsrc = p_end + 1;
                                                           filldst = 1;
                                                           fillcnt = p_ptrn_lines;
                                                   } else {
                                                           if (repl_beginning) {
                                                                   if (repl_could_be_missing) {
                                                                           repl_missing = TRUE;
                                                                           goto hunk_done;
                                                                   }
                                                                   fatal("duplicate \"---\" at line %ld--check line numbers at line %ld\n",
                                                                       p_input_line, p_hunk_beg + repl_beginning);
                                                           } else {
                                                                   fatal("%s \"---\" at line %ld--check line numbers at line %ld\n",
                                                                       (p_end <= p_ptrn_lines
                                                                       ? "Premature"
                                                                       : "Overdue"),
                                                                       p_input_line, p_hunk_beg);
                                                           }
                                                   }
                                           }
                                           repl_beginning = p_end;
                                           repl_backtrack_position = ftell(pfp);
                                           repl_patch_line = p_input_line;
                                           p_line[p_end] = savestr(buf);
                                           if (out_of_mem) {
                                                   p_end--;
                                                   return FALSE;
                                           }
                                           p_char[p_end] = '=';
                                           for (s = buf; *s && !isdigit(*s); s++)
                                                   ;
                                           if (!*s)
                                                   malformed();
                                           p_newfirst = (LINENUM) atol(s);
                                           while (isdigit(*s))
                                                   s++;
                                           if (*s == ',') {
                                                   for (; *s && !isdigit(*s); s++)
                                                           ;
                                                   if (!*s)
                                                           malformed();
                                                   p_repl_lines = ((LINENUM) atol(s)) -
                                                       p_newfirst + 1;
                                           } else if (p_newfirst)
                                                   p_repl_lines = 1;
                                           else {
                                                   p_repl_lines = 0;
                                                   p_newfirst = 1;
                                           }
                                           p_max = p_repl_lines + p_end;
                                           if (p_max > MAXHUNKSIZE)
                                                   fatal("hunk too large (%ld lines) at line %ld: %s",
                                                       p_max, p_input_line, buf);
                                           while (p_max >= hunkmax)
                                                   grow_hunkmax();
                                           if (p_repl_lines != ptrn_copiable &&
                                               (p_context != 0 || p_repl_lines != 1))
                                                   repl_could_be_missing = FALSE;
                                           break;
                                   }
                                   goto change_line;
                           case '+':
                           case '!':
                                   repl_could_be_missing = FALSE;
                   change_line:
                                   if (buf[1] == '\n' && canonicalize)
                                           strlcpy(buf + 1, " \n", sizeof buf - 1);
                                   if (!isspace(buf[1]) && buf[1] != '>' &&
                                       buf[1] != '<' &&
                                       repl_beginning && repl_could_be_missing) {
                                           repl_missing = TRUE;
                                           goto hunk_done;
                                   }
                                   if (context >= 0) {
                                           if (context < p_context)
                                                   p_context = context;
                                           context = -1000;
                                   }
                                   p_line[p_end] = savestr(buf + 2);
                                   if (out_of_mem) {
                                           p_end--;
                                           return FALSE;
                                   }
                                   if (p_end == p_ptrn_lines) {
                                           if (remove_special_line()) {
                                                   int     len;
   
                                                   len = strlen(p_line[p_end]) - 1;
                                                   (p_line[p_end])[len] = 0;
                                           }
                                   }
                                   break;
                           case '\t':
                           case '\n':      /* assume the 2 spaces got eaten */
                                   if (repl_beginning && repl_could_be_missing &&
                                       (!ptrn_spaces_eaten ||
                                       diff_type == NEW_CONTEXT_DIFF)) {
                                           repl_missing = TRUE;
                                           goto hunk_done;
                                   }
                                   p_line[p_end] = savestr(buf);
                                   if (out_of_mem) {
                                           p_end--;
                                           return FALSE;
                                   }
                                   if (p_end != p_ptrn_lines + 1) {
                                           ptrn_spaces_eaten |= (repl_beginning != 0);
                                           context++;
                                           if (!repl_beginning)
                                                   ptrn_copiable++;
                                           p_char[p_end] = ' ';
                                   }
                                   break;
                           case ' ':
                                   if (!isspace(buf[1]) &&
                                     repl_beginning && repl_could_be_missing) {
                                           repl_missing = TRUE;
                                           goto hunk_done;
                                   }
                                   context++;
                                   if (!repl_beginning)
                                           ptrn_copiable++;
                                   p_line[p_end] = savestr(buf + 2);
                                   if (out_of_mem) {
                                           p_end--;
                                           return FALSE;
                                   }
                                   break;
                           default:
                                   if (repl_beginning && repl_could_be_missing) {
                                           repl_missing = TRUE;
                                           goto hunk_done;
                                   }
                                   malformed();
                           }
                           /* set up p_len for strncmp() so we don't have to */
                           /* assume null termination */
                           if (p_line[p_end])
                                   p_len[p_end] = strlen(p_line[p_end]);
                           else
                                   p_len[p_end] = 0;
                   }
   
   hunk_done:
                   if (p_end >= 0 && !repl_beginning)
                           fatal("no --- found in patch at line %ld\n", pch_hunk_beg());
   
                   if (repl_missing) {
   
                           /* reset state back to just after --- */
                           p_input_line = repl_patch_line;
                           for (p_end--; p_end > repl_beginning; p_end--)
                                   free(p_line[p_end]);
                           fseek(pfp, repl_backtrack_position, 0);
   
                           /* redundant 'new' context lines were omitted - set */
                           /* up to fill them in from the old file context */
                           if (!p_context && p_repl_lines == 1) {
                                   p_repl_lines = 0;
                                   p_max--;
                           }
                           fillsrc = 1;
                           filldst = repl_beginning + 1;
                           fillcnt = p_repl_lines;
                           p_end = p_max;
                   } else if (!p_context && fillcnt == 1) {
                           /* the first hunk was a null hunk with no context */
                           /* and we were expecting one line -- fix it up. */
                           while (filldst < p_end) {
                                   p_line[filldst] = p_line[filldst + 1];
                                   p_char[filldst] = p_char[filldst + 1];
                                   p_len[filldst] = p_len[filldst + 1];
                                   filldst++;
                           }
   #if 0
                           repl_beginning--;       /* this doesn't need to be
                                                    * fixed */
 #endif  #endif
             switch (*buf) {                          p_end--;
             case '*':                          p_first++;      /* do append rather than insert */
                 if (strnEQ(buf, "********", 8)) {                          fillcnt = 0;
                     if (repl_beginning && repl_could_be_missing) {                          p_ptrn_lines = 0;
                         repl_missing = TRUE;  
                         goto hunk_done;  
                     }  
                     else  
                         fatal("unexpected end of hunk at line %ld\n",  
                             p_input_line);  
                 }                  }
                 if (p_end != 0) {                  if (diff_type == CONTEXT_DIFF &&
                     if (repl_beginning && repl_could_be_missing) {                      (fillcnt || (p_first > 1 && ptrn_copiable > 2 * p_context))) {
                         repl_missing = TRUE;                          if (verbose)
                         goto hunk_done;                                  say("%s\n%s\n%s\n",
                     }                                      "(Fascinating--this is really a new-style context diff but without",
                     fatal("unexpected *** at line %ld: %s", p_input_line, buf);                                      "the telltale extra asterisks on the *** line that usually indicate",
                                       "the new style...)");
                           diff_type = NEW_CONTEXT_DIFF;
                 }                  }
                 context = 0;                  /* if there were omitted context lines, fill them in now */
                 p_line[p_end] = savestr(buf);                  if (fillcnt) {
                 if (out_of_mem) {                          p_bfake = filldst;      /* remember where not to
                     p_end--;                                                   * free() */
                     return FALSE;                          p_efake = filldst + fillcnt - 1;
                           while (fillcnt-- > 0) {
                                   while (fillsrc <= p_end && p_char[fillsrc] != ' ')
                                           fillsrc++;
                                   if (fillsrc > p_end)
                                           fatal("replacement text or line numbers mangled in hunk at line %ld\n",
                                               p_hunk_beg);
                                   p_line[filldst] = p_line[fillsrc];
                                   p_char[filldst] = p_char[fillsrc];
                                   p_len[filldst] = p_len[fillsrc];
                                   fillsrc++;
                                   filldst++;
                           }
                           while (fillsrc <= p_end && fillsrc != repl_beginning &&
                               p_char[fillsrc] != ' ')
                                   fillsrc++;
   #ifdef DEBUGGING
                           if (debug & 64)
                                   printf("fillsrc %ld, filldst %ld, rb %ld, e+1 %ld\n",
                                   fillsrc, filldst, repl_beginning, p_end + 1);
   #endif
                           assert(fillsrc == p_end + 1 || fillsrc == repl_beginning);
                           assert(filldst == p_end + 1 || filldst == repl_beginning);
                 }                  }
                 for (s=buf; *s && !isdigit(*s); s++) ;                  if (p_line[p_end] != NULL) {
                           if (remove_special_line()) {
                                   p_len[p_end] -= 1;
                                   (p_line[p_end])[p_len[p_end]] = 0;
                           }
                   }
           } else if (diff_type == UNI_DIFF) {
                   long    line_beginning = ftell(pfp); /* file pos of the current line */
                   LINENUM fillsrc;        /* index of old lines */
                   LINENUM filldst;        /* index of new lines */
                   char    ch;
   
                   ret = pgets(buf, sizeof buf, pfp);
                   p_input_line++;
                   if (ret == Nullch || strnNE(buf, "@@ -", 4)) {
                           next_intuit_at(line_beginning, p_input_line);
                           return FALSE;
                   }
                   s = buf + 4;
                 if (!*s)                  if (!*s)
                     malformed ();                          malformed();
                 if (strnEQ(s,"0,0",3))  
                     memmove(s, s+2, strlen(s+2)+1);  
                 p_first = (LINENUM) atol(s);                  p_first = (LINENUM) atol(s);
                 while (isdigit(*s)) s++;                  while (isdigit(*s))
                           s++;
                 if (*s == ',') {                  if (*s == ',') {
                     for (; *s && !isdigit(*s); s++) ;                          p_ptrn_lines = (LINENUM) atol(++s);
                     if (!*s)                          while (isdigit(*s))
                         malformed ();                                  s++;
                     p_ptrn_lines = ((LINENUM)atol(s)) - p_first + 1;                  } else
                           p_ptrn_lines = 1;
                   if (*s == ' ')
                           s++;
                   if (*s != '+' || !*++s)
                           malformed();
                   p_newfirst = (LINENUM) atol(s);
                   while (isdigit(*s))
                           s++;
                   if (*s == ',') {
                           p_repl_lines = (LINENUM) atol(++s);
                           while (isdigit(*s))
                                   s++;
                   } else
                           p_repl_lines = 1;
                   if (*s == ' ')
                           s++;
                   if (*s != '@')
                           malformed();
                   if (!p_ptrn_lines)
                           p_first++;      /* do append rather than insert */
                   p_max = p_ptrn_lines + p_repl_lines + 1;
                   while (p_max >= hunkmax)
                           grow_hunkmax();
                   fillsrc = 1;
                   filldst = fillsrc + p_ptrn_lines;
                   p_end = filldst + p_repl_lines;
                   snprintf(buf, sizeof buf, "*** %ld,%ld ****\n", p_first,
                            p_first + p_ptrn_lines - 1);
                   p_line[0] = savestr(buf);
                   if (out_of_mem) {
                           p_end = -1;
                           return FALSE;
                 }                  }
                 else if (p_first)                  p_char[0] = '*';
                     p_ptrn_lines = 1;                  snprintf(buf, sizeof buf, "--- %ld,%ld ----\n", p_newfirst,
                 else {                           p_newfirst + p_repl_lines - 1);
                     p_ptrn_lines = 0;                  p_line[filldst] = savestr(buf);
                     p_first = 1;                  if (out_of_mem) {
                           p_end = 0;
                           return FALSE;
                 }                  }
                 p_max = p_ptrn_lines + 6;       /* we need this much at least */                  p_char[filldst++] = '=';
                 while (p_max >= hunkmax)                  p_context = 100;
                     grow_hunkmax();                  context = 0;
                 p_max = hunkmax;                  p_hunk_beg = p_input_line + 1;
                 break;                  while (fillsrc <= p_ptrn_lines || filldst <= p_end) {
             case '-':                          line_beginning = ftell(pfp);
                 if (buf[1] == '-') {                          ret = pgets(buf, sizeof buf, pfp);
                     if (repl_beginning ||                          p_input_line++;
                         (p_end != p_ptrn_lines + 1 + (p_char[p_end-1] == '\n')))                          if (ret == Nullch) {
                     {                                  if (p_max - filldst < 3) {
                         if (p_end == 1) {                                          /* assume blank lines got chopped */
                             /* `old' lines were omitted - set up to fill */                                          strlcpy(buf, " \n", sizeof buf);
                             /* them in from 'new' context lines. */                                  } else {
                             p_end = p_ptrn_lines + 1;                                          fatal("unexpected end of file in patch\n");
                             fillsrc = p_end + 1;                                  }
                             filldst = 1;  
                             fillcnt = p_ptrn_lines;  
                         }                          }
                         else {                          if (*buf == '\t' || *buf == '\n') {
                             if (repl_beginning) {                                  ch = ' ';       /* assume the space got eaten */
                                 if (repl_could_be_missing){                                  s = savestr(buf);
                                     repl_missing = TRUE;                          } else {
                                     goto hunk_done;                                  ch = *buf;
                                   s = savestr(buf + 1);
                           }
                           if (out_of_mem) {
                                   while (--filldst > p_ptrn_lines)
                                           free(p_line[filldst]);
                                   p_end = fillsrc - 1;
                                   return FALSE;
                           }
                           switch (ch) {
                           case '-':
                                   if (fillsrc > p_ptrn_lines) {
                                           free(s);
                                           p_end = filldst - 1;
                                           malformed();
                                 }                                  }
                                 fatal(                                  p_char[fillsrc] = ch;
 "duplicate \"---\" at line %ld--check line numbers at line %ld\n",                                  p_line[fillsrc] = s;
                                     p_input_line, p_hunk_beg + repl_beginning);                                  p_len[fillsrc++] = strlen(s);
                             }                                  if (fillsrc > p_ptrn_lines) {
                             else {                                          if (remove_special_line()) {
                                 fatal(                                                  p_len[fillsrc - 1] -= 1;
 "%s \"---\" at line %ld--check line numbers at line %ld\n",                                                  s[p_len[fillsrc - 1]] = 0;
                                     (p_end <= p_ptrn_lines                                          }
                                         ? "Premature"                                  }
                                         : "Overdue" ),                                  break;
                                     p_input_line, p_hunk_beg);                          case '=':
                             }                                  ch = ' ';
                                   /* FALL THROUGH */
                           case ' ':
                                   if (fillsrc > p_ptrn_lines) {
                                           free(s);
                                           while (--filldst > p_ptrn_lines)
                                                   free(p_line[filldst]);
                                           p_end = fillsrc - 1;
                                           malformed();
                                   }
                                   context++;
                                   p_char[fillsrc] = ch;
                                   p_line[fillsrc] = s;
                                   p_len[fillsrc++] = strlen(s);
                                   s = savestr(s);
                                   if (out_of_mem) {
                                           while (--filldst > p_ptrn_lines)
                                                   free(p_line[filldst]);
                                           p_end = fillsrc - 1;
                                           return FALSE;
                                   }
                                   /* FALL THROUGH */
                           case '+':
                                   if (filldst > p_end) {
                                           free(s);
                                           while (--filldst > p_ptrn_lines)
                                                   free(p_line[filldst]);
                                           p_end = fillsrc - 1;
                                           malformed();
                                   }
                                   p_char[filldst] = ch;
                                   p_line[filldst] = s;
                                   p_len[filldst++] = strlen(s);
                                   if (fillsrc > p_ptrn_lines) {
                                           if (remove_special_line()) {
                                                   p_len[filldst - 1] -= 1;
                                                   s[p_len[filldst - 1]] = 0;
                                           }
                                   }
                                   break;
                           default:
                                   p_end = filldst;
                                   malformed();
                         }                          }
                     }                          if (ch != ' ' && context > 0) {
                     repl_beginning = p_end;                                  if (context < p_context)
                     repl_backtrack_position = ftell(pfp);                                          p_context = context;
                     repl_patch_line = p_input_line;                                  context = -1000;
                     p_line[p_end] = savestr(buf);                          }
                     if (out_of_mem) {                  }               /* while */
                         p_end--;          } else {                /* normal diff--fake it up */
                   char    hunk_type;
                   int     i;
                   LINENUM min, max;
                   long    line_beginning = ftell(pfp);
   
                   p_context = 0;
                   ret = pgets(buf, sizeof buf, pfp);
                   p_input_line++;
                   if (ret == Nullch || !isdigit(*buf)) {
                           next_intuit_at(line_beginning, p_input_line);
                         return FALSE;                          return FALSE;
                     }                  }
                     p_char[p_end] = '=';                  p_first = (LINENUM) atol(buf);
                     for (s=buf; *s && !isdigit(*s); s++) ;                  for (s = buf; isdigit(*s); s++);
                     if (!*s)                  if (*s == ',') {
                         malformed ();                          p_ptrn_lines = (LINENUM) atol(++s) - p_first + 1;
                     p_newfirst = (LINENUM) atol(s);                          while (isdigit(*s))
                     while (isdigit(*s)) s++;                                  s++;
                     if (*s == ',') {                  } else
                         for (; *s && !isdigit(*s); s++) ;                          p_ptrn_lines = (*s != 'a');
                         if (!*s)                  hunk_type = *s;
                             malformed ();                  if (hunk_type == 'a')
                         p_repl_lines = ((LINENUM)atol(s)) - p_newfirst + 1;                          p_first++;      /* do append rather than insert */
                     }                  min = (LINENUM) atol(++s);
                     else if (p_newfirst)                  for (; isdigit(*s); s++);
                         p_repl_lines = 1;                  if (*s == ',')
                     else {                          max = (LINENUM) atol(++s);
                         p_repl_lines = 0;                  else
                         p_newfirst = 1;                          max = min;
                     }                  if (hunk_type == 'd')
                     p_max = p_repl_lines + p_end;                          min++;
                     if (p_max > MAXHUNKSIZE)                  p_end = p_ptrn_lines + 1 + max - min + 1;
                   if (p_end > MAXHUNKSIZE)
                         fatal("hunk too large (%ld lines) at line %ld: %s",                          fatal("hunk too large (%ld lines) at line %ld: %s",
                               p_max, p_input_line, buf);                              p_end, p_input_line, buf);
                     while (p_max >= hunkmax)                  while (p_end >= hunkmax)
                         grow_hunkmax();                          grow_hunkmax();
                     if (p_repl_lines != ptrn_copiable                  p_newfirst = min;
                      && (p_context != 0 || p_repl_lines != 1))                  p_repl_lines = max - min + 1;
                         repl_could_be_missing = FALSE;                  snprintf(buf, sizeof buf, "*** %ld,%ld\n", p_first,
                     break;                           p_first + p_ptrn_lines - 1);
                 }                  p_line[0] = savestr(buf);
                 goto change_line;  
             case '+':  case '!':  
                 repl_could_be_missing = FALSE;  
               change_line:  
                 if (buf[1] == '\n' && canonicalize)  
                     strlcpy(buf+1," \n", sizeof buf -1);  
                 if (!isspace(buf[1]) && buf[1] != '>' && buf[1] != '<' &&  
                   repl_beginning && repl_could_be_missing) {  
                     repl_missing = TRUE;  
                     goto hunk_done;  
                 }  
                 if (context >= 0) {  
                     if (context < p_context)  
                         p_context = context;  
                     context = -1000;  
                 }  
                 p_line[p_end] = savestr(buf+2);  
                 if (out_of_mem) {                  if (out_of_mem) {
                     p_end--;                          p_end = -1;
                     return FALSE;                          return FALSE;
                 }                  }
                 if (p_end == p_ptrn_lines) {                  p_char[0] = '*';
                         if (remove_special_line()) {                  for (i = 1; i <= p_ptrn_lines; i++) {
                                 int len;                          ret = pgets(buf, sizeof buf, pfp);
                           p_input_line++;
                                 len = strlen(p_line[p_end]) - 1;                          if (ret == Nullch)
                                 (p_line[p_end])[len] = 0;                                  fatal("unexpected end of file in patch at line %ld\n",
                                       p_input_line);
                           if (*buf != '<')
                                   fatal("< expected at line %ld of patch\n",
                                       p_input_line);
                           p_line[i] = savestr(buf + 2);
                           if (out_of_mem) {
                                   p_end = i - 1;
                                   return FALSE;
                         }                          }
                           p_len[i] = strlen(p_line[i]);
                           p_char[i] = '-';
                 }                  }
                 break;  
             case '\t': case '\n':       /* assume the 2 spaces got eaten */  
                 if (repl_beginning && repl_could_be_missing &&  
                   (!ptrn_spaces_eaten || diff_type == NEW_CONTEXT_DIFF) ) {  
                     repl_missing = TRUE;  
                     goto hunk_done;  
                 }  
                 p_line[p_end] = savestr(buf);  
                 if (out_of_mem) {  
                     p_end--;  
                     return FALSE;  
                 }  
                 if (p_end != p_ptrn_lines + 1) {  
                     ptrn_spaces_eaten |= (repl_beginning != 0);  
                     context++;  
                     if (!repl_beginning)  
                         ptrn_copiable++;  
                     p_char[p_end] = ' ';  
                 }  
                 break;  
             case ' ':  
                 if (!isspace(buf[1]) &&  
                   repl_beginning && repl_could_be_missing) {  
                     repl_missing = TRUE;  
                     goto hunk_done;  
                 }  
                 context++;  
                 if (!repl_beginning)  
                     ptrn_copiable++;  
                 p_line[p_end] = savestr(buf+2);  
                 if (out_of_mem) {  
                     p_end--;  
                     return FALSE;  
                 }  
                 break;  
             default:  
                 if (repl_beginning && repl_could_be_missing) {  
                     repl_missing = TRUE;  
                     goto hunk_done;  
                 }  
                 malformed ();  
             }  
             /* set up p_len for strncmp() so we don't have to */  
             /* assume null termination */  
             if (p_line[p_end])  
                 p_len[p_end] = strlen(p_line[p_end]);  
             else  
                 p_len[p_end] = 0;  
         }  
   
     hunk_done:  
         if (p_end >=0 && !repl_beginning)  
             fatal("no --- found in patch at line %ld\n", pch_hunk_beg());  
   
         if (repl_missing) {  
   
             /* reset state back to just after --- */  
             p_input_line = repl_patch_line;  
             for (p_end--; p_end > repl_beginning; p_end--)  
                 free(p_line[p_end]);  
             fseek(pfp, repl_backtrack_position, 0);  
   
             /* redundant 'new' context lines were omitted - set */  
             /* up to fill them in from the old file context */  
             if (!p_context && p_repl_lines == 1) {  
                 p_repl_lines = 0;  
                 p_max--;  
             }  
             fillsrc = 1;  
             filldst = repl_beginning+1;  
             fillcnt = p_repl_lines;  
             p_end = p_max;  
         }  
         else if (!p_context && fillcnt == 1) {  
             /* the first hunk was a null hunk with no context */  
             /* and we were expecting one line -- fix it up. */  
             while (filldst < p_end) {  
                 p_line[filldst] = p_line[filldst+1];  
                 p_char[filldst] = p_char[filldst+1];  
                 p_len[filldst] = p_len[filldst+1];  
                 filldst++;  
             }  
 #if 0  
             repl_beginning--;           /* this doesn't need to be fixed */  
 #endif  
             p_end--;  
             p_first++;                  /* do append rather than insert */  
             fillcnt = 0;  
             p_ptrn_lines = 0;  
         }  
   
         if (diff_type == CONTEXT_DIFF &&  
           (fillcnt || (p_first > 1 && ptrn_copiable > 2*p_context)) ) {  
             if (verbose)  
                 say("%s\n%s\n%s\n",  
 "(Fascinating--this is really a new-style context diff but without",  
 "the telltale extra asterisks on the *** line that usually indicate",  
 "the new style...)");  
             diff_type = NEW_CONTEXT_DIFF;  
         }  
   
         /* if there were omitted context lines, fill them in now */  
         if (fillcnt) {  
             p_bfake = filldst;          /* remember where not to free() */  
             p_efake = filldst + fillcnt - 1;  
             while (fillcnt-- > 0) {  
                 while (fillsrc <= p_end && p_char[fillsrc] != ' ')  
                     fillsrc++;  
                 if (fillsrc > p_end)  
                     fatal("replacement text or line numbers mangled in hunk at line %ld\n",  
                         p_hunk_beg);  
                 p_line[filldst] = p_line[fillsrc];  
                 p_char[filldst] = p_char[fillsrc];  
                 p_len[filldst] = p_len[fillsrc];  
                 fillsrc++; filldst++;  
             }  
             while (fillsrc <= p_end && fillsrc != repl_beginning &&  
               p_char[fillsrc] != ' ')  
                 fillsrc++;  
 #ifdef DEBUGGING  
             if (debug & 64)  
                 printf("fillsrc %ld, filldst %ld, rb %ld, e+1 %ld\n",  
                     fillsrc,filldst,repl_beginning,p_end+1);  
 #endif  
             assert(fillsrc==p_end+1 || fillsrc==repl_beginning);  
             assert(filldst==p_end+1 || filldst==repl_beginning);  
         }  
         if (p_line[p_end] != NULL) {  
                 if (remove_special_line()) {                  if (remove_special_line()) {
                         p_len[p_end] -= 1;                          p_len[i - 1] -= 1;
                         (p_line[p_end])[p_len[p_end]] = 0;                          (p_line[i - 1])[p_len[i - 1]] = 0;
                 }                  }
         }                  if (hunk_type == 'c') {
     }                          ret = pgets(buf, sizeof buf, pfp);
     else if (diff_type == UNI_DIFF) {                          p_input_line++;
         long line_beginning = ftell(pfp);                          if (ret == Nullch)
                                         /* file pos of the current line */                                  fatal("unexpected end of file in patch at line %ld\n",
         LINENUM fillsrc;                /* index of old lines */                                      p_input_line);
         LINENUM filldst;                /* index of new lines */                          if (*buf != '-')
         char ch;                                  fatal("--- expected at line %ld of patch\n",
                                       p_input_line);
         ret = pgets(buf, sizeof buf, pfp);  
         p_input_line++;  
         if (ret == Nullch || strnNE(buf, "@@ -", 4)) {  
             next_intuit_at(line_beginning,p_input_line);  
             return FALSE;  
         }  
         s = buf+4;  
         if (!*s)  
             malformed ();  
         p_first = (LINENUM) atol(s);  
         while (isdigit(*s)) s++;  
         if (*s == ',') {  
             p_ptrn_lines = (LINENUM) atol(++s);  
             while (isdigit(*s)) s++;  
         } else  
             p_ptrn_lines = 1;  
         if (*s == ' ') s++;  
         if (*s != '+' || !*++s)  
             malformed ();  
         p_newfirst = (LINENUM) atol(s);  
         while (isdigit(*s)) s++;  
         if (*s == ',') {  
             p_repl_lines = (LINENUM) atol(++s);  
             while (isdigit(*s)) s++;  
         } else  
             p_repl_lines = 1;  
         if (*s == ' ') s++;  
         if (*s != '@')  
             malformed ();  
         if (!p_ptrn_lines)  
             p_first++;                  /* do append rather than insert */  
         p_max = p_ptrn_lines + p_repl_lines + 1;  
         while (p_max >= hunkmax)  
             grow_hunkmax();  
         fillsrc = 1;  
         filldst = fillsrc + p_ptrn_lines;  
         p_end = filldst + p_repl_lines;  
         snprintf(buf, sizeof buf, "*** %ld,%ld ****\n", p_first,  
             p_first + p_ptrn_lines - 1);  
         p_line[0] = savestr(buf);  
         if (out_of_mem) {  
             p_end = -1;  
             return FALSE;  
         }  
         p_char[0] = '*';  
         snprintf(buf, sizeof buf, "--- %ld,%ld ----\n", p_newfirst,  
             p_newfirst + p_repl_lines - 1);  
         p_line[filldst] = savestr(buf);  
         if (out_of_mem) {  
             p_end = 0;  
             return FALSE;  
         }  
         p_char[filldst++] = '=';  
         p_context = 100;  
         context = 0;  
         p_hunk_beg = p_input_line + 1;  
         while (fillsrc <= p_ptrn_lines || filldst <= p_end) {  
             line_beginning = ftell(pfp);  
             ret = pgets(buf, sizeof buf, pfp);  
             p_input_line++;  
             if (ret == Nullch) {  
                 if (p_max - filldst < 3) {  
                     /* assume blank lines got chopped */  
                     strlcpy(buf, " \n", sizeof buf);  
                 } else {  
                     fatal("unexpected end of file in patch\n");  
                 }                  }
             }                  snprintf(buf, sizeof(buf), "--- %ld,%ld\n", min, max);
             if (*buf == '\t' || *buf == '\n') {                  p_line[i] = savestr(buf);
                 ch = ' ';               /* assume the space got eaten */  
                 s = savestr(buf);  
             }  
             else {  
                 ch = *buf;  
                 s = savestr(buf+1);  
             }  
             if (out_of_mem) {  
                 while (--filldst > p_ptrn_lines)  
                     free(p_line[filldst]);  
                 p_end = fillsrc-1;  
                 return FALSE;  
             }  
             switch (ch) {  
             case '-':  
                 if (fillsrc > p_ptrn_lines) {  
                     free(s);  
                     p_end = filldst-1;  
                     malformed ();  
                 }  
                 p_char[fillsrc] = ch;  
                 p_line[fillsrc] = s;  
                 p_len[fillsrc++] = strlen(s);  
                 if (fillsrc > p_ptrn_lines) {  
                         if (remove_special_line()) {  
                                 p_len[fillsrc - 1] -= 1;  
                                 s[p_len[fillsrc - 1]] = 0;  
                         }  
                 }  
                 break;  
             case '=':  
                 ch = ' ';  
                 /* FALL THROUGH */  
             case ' ':  
                 if (fillsrc > p_ptrn_lines) {  
                     free(s);  
                     while (--filldst > p_ptrn_lines)  
                         free(p_line[filldst]);  
                     p_end = fillsrc-1;  
                     malformed ();  
                 }  
                 context++;  
                 p_char[fillsrc] = ch;  
                 p_line[fillsrc] = s;  
                 p_len[fillsrc++] = strlen(s);  
                 s = savestr(s);  
                 if (out_of_mem) {                  if (out_of_mem) {
                     while (--filldst > p_ptrn_lines)                          p_end = i - 1;
                         free(p_line[filldst]);                          return FALSE;
                     p_end = fillsrc-1;  
                     return FALSE;  
                 }                  }
                 /* FALL THROUGH */                  p_char[i] = '=';
             case '+':                  for (i++; i <= p_end; i++) {
                 if (filldst > p_end) {                          ret = pgets(buf, sizeof buf, pfp);
                     free(s);                          p_input_line++;
                     while (--filldst > p_ptrn_lines)                          if (ret == Nullch)
                         free(p_line[filldst]);                                  fatal("unexpected end of file in patch at line %ld\n",
                     p_end = fillsrc-1;                                      p_input_line);
                     malformed ();                          if (*buf != '>')
                 }                                  fatal("> expected at line %ld of patch\n",
                 p_char[filldst] = ch;                                      p_input_line);
                 p_line[filldst] = s;                          p_line[i] = savestr(buf + 2);
                 p_len[filldst++] = strlen(s);                          if (out_of_mem) {
                 if (fillsrc > p_ptrn_lines) {                                  p_end = i - 1;
                         if (remove_special_line()) {                                  return FALSE;
                                 p_len[filldst - 1] -= 1;  
                                 s[p_len[filldst - 1]] = 0;  
                         }                          }
                           p_len[i] = strlen(p_line[i]);
                           p_char[i] = '+';
                 }                  }
                 break;  
             default:  
                 p_end = filldst;  
                 malformed ();  
             }  
             if (ch != ' ' && context > 0) {  
                 if (context < p_context)  
                     p_context = context;  
                 context = -1000;  
             }  
         }/* while */  
     }  
     else {                              /* normal diff--fake it up */  
         char hunk_type;  
         int i;  
         LINENUM min, max;  
         long line_beginning = ftell(pfp);  
   
         p_context = 0;                  if (remove_special_line()) {
         ret = pgets(buf, sizeof buf, pfp);                          p_len[i - 1] -= 1;
         p_input_line++;                          (p_line[i - 1])[p_len[i - 1]] = 0;
         if (ret == Nullch || !isdigit(*buf)) {                  }
             next_intuit_at(line_beginning,p_input_line);  
             return FALSE;  
         }          }
         p_first = (LINENUM)atol(buf);          if (reverse)            /* backwards patch? */
         for (s=buf; isdigit(*s); s++) ;                  if (!pch_swap())
         if (*s == ',') {                          say("Not enough memory to swap next hunk!\n");
             p_ptrn_lines = (LINENUM)atol(++s) - p_first + 1;  
             while (isdigit(*s)) s++;  
         }  
         else  
             p_ptrn_lines = (*s != 'a');  
         hunk_type = *s;  
         if (hunk_type == 'a')  
             p_first++;                  /* do append rather than insert */  
         min = (LINENUM)atol(++s);  
         for (; isdigit(*s); s++) ;  
         if (*s == ',')  
             max = (LINENUM)atol(++s);  
         else  
             max = min;  
         if (hunk_type == 'd')  
             min++;  
         p_end = p_ptrn_lines + 1 + max - min + 1;  
         if (p_end > MAXHUNKSIZE)  
             fatal("hunk too large (%ld lines) at line %ld: %s",  
                   p_end, p_input_line, buf);  
         while (p_end >= hunkmax)  
             grow_hunkmax();  
         p_newfirst = min;  
         p_repl_lines = max - min + 1;  
         snprintf(buf, sizeof buf, "*** %ld,%ld\n", p_first,  
             p_first + p_ptrn_lines - 1);  
         p_line[0] = savestr(buf);  
         if (out_of_mem) {  
             p_end = -1;  
             return FALSE;  
         }  
         p_char[0] = '*';  
         for (i=1; i<=p_ptrn_lines; i++) {  
             ret = pgets(buf, sizeof buf, pfp);  
             p_input_line++;  
             if (ret == Nullch)  
                 fatal("unexpected end of file in patch at line %ld\n",  
                   p_input_line);  
             if (*buf != '<')  
                 fatal("< expected at line %ld of patch\n", p_input_line);  
             p_line[i] = savestr(buf+2);  
             if (out_of_mem) {  
                 p_end = i-1;  
                 return FALSE;  
             }  
             p_len[i] = strlen(p_line[i]);  
             p_char[i] = '-';  
         }  
   
         if (remove_special_line()) {  
                 p_len[i - 1] -= 1;  
                 (p_line[i - 1])[p_len[i - 1]] = 0;  
         }  
   
         if (hunk_type == 'c') {  
             ret = pgets(buf, sizeof buf, pfp);  
             p_input_line++;  
             if (ret == Nullch)  
                 fatal("unexpected end of file in patch at line %ld\n",  
                     p_input_line);  
             if (*buf != '-')  
                 fatal("--- expected at line %ld of patch\n", p_input_line);  
         }  
         snprintf(buf, sizeof(buf), "--- %ld,%ld\n", min, max);  
         p_line[i] = savestr(buf);  
         if (out_of_mem) {  
             p_end = i-1;  
             return FALSE;  
         }  
         p_char[i] = '=';  
         for (i++; i<=p_end; i++) {  
             ret = pgets(buf, sizeof buf, pfp);  
             p_input_line++;  
             if (ret == Nullch)  
                 fatal("unexpected end of file in patch at line %ld\n",  
                     p_input_line);  
             if (*buf != '>')  
                 fatal("> expected at line %ld of patch\n", p_input_line);  
             p_line[i] = savestr(buf+2);  
             if (out_of_mem) {  
                 p_end = i-1;  
                 return FALSE;  
             }  
             p_len[i] = strlen(p_line[i]);  
             p_char[i] = '+';  
         }  
   
         if (remove_special_line()) {  
                 p_len[i - 1] -= 1;  
                 (p_line[i - 1])[p_len[i - 1]] = 0;  
         }  
     }  
     if (reverse)                        /* backwards patch? */  
         if (!pch_swap())  
             say("Not enough memory to swap next hunk!\n");  
 #ifdef DEBUGGING  #ifdef DEBUGGING
     if (debug & 2) {          if (debug & 2) {
         int i;                  int     i;
         char special;                  char    special;
   
         for (i=0; i <= p_end; i++) {                  for (i = 0; i <= p_end; i++) {
             if (i == p_ptrn_lines)                          if (i == p_ptrn_lines)
                 special = '^';                                  special = '^';
             else                          else
                 special = ' ';                                  special = ' ';
             fprintf(stderr, "%3d %c %c %s", i, p_char[i], special, p_line[i]);                          fprintf(stderr, "%3d %c %c %s", i, p_char[i],
             fflush(stderr);                              special, p_line[i]);
                           fflush(stderr);
                   }
         }          }
     }  
 #endif  #endif
     if (p_end+1 < hunkmax)      /* paranoia reigns supreme... */          if (p_end + 1 < hunkmax)/* paranoia reigns supreme... */
         p_char[p_end+1] = '^';  /* add a stopper for apply_hunk */                  p_char[p_end + 1] = '^';        /* add a stopper for apply_hunk */
     return TRUE;          return TRUE;
 }  }
   
 /* Input a line from the patch file, worrying about indentation. */  /*
    * Input a line from the patch file, worrying about indentation.
    */
 char *  char *
 pgets(bf,sz,fp)  pgets(char *bf, int sz, FILE *fp)
 char *bf;  
 int sz;  
 FILE *fp;  
 {  {
     char *ret = fgets(bf, sz, fp);          char    *s, *ret = fgets(bf, sz, fp);
     char *s;          int     indent = 0;
     int indent = 0;  
   
     if (p_indent && ret != Nullch) {          if (p_indent && ret != Nullch) {
         for (s=buf;                  for (s = buf;
           indent < p_indent && (*s == ' ' || *s == '\t' || *s == 'X'); s++) {                      indent < p_indent && (*s == ' ' || *s == '\t' || *s == 'X');
             if (*s == '\t')                      s++) {
                 indent += 8 - (indent % 7);                          if (*s == '\t')
             else                                  indent += 8 - (indent % 7);
                 indent++;                          else
                                   indent++;
                   }
                   if (buf != s && strlcpy(buf, s, sizeof(buf)) >= sizeof(buf))
                           fatal("buffer too small in pgets()\n");
         }          }
         if (buf != s && strlcpy(buf, s, sizeof(buf)) >= sizeof(buf))          return ret;
             fatal("buffer too small in pgets()\n");  
     }  
     return ret;  
 }  }
   
 /* Reverse the old and new portions of the current hunk. */  /*
    * Reverse the old and new portions of the current hunk.
    */
 bool  bool
 pch_swap()  pch_swap(void)
 {  {
     char **tp_line;             /* the text of the hunk */          char    **tp_line;      /* the text of the hunk */
     short *tp_len;              /* length of each line */          short   *tp_len;        /* length of each line */
     char *tp_char;              /* +, -, and ! */          char    *tp_char;       /* +, -, and ! */
     LINENUM i;          LINENUM i;
     LINENUM n;          LINENUM n;
     bool blankline = FALSE;          bool    blankline = FALSE;
     char *s;          char    *s;
   
     i = p_first;          i = p_first;
     p_first = p_newfirst;          p_first = p_newfirst;
     p_newfirst = i;          p_newfirst = i;
   
     /* make a scratch copy */          /* make a scratch copy */
   
     tp_line = p_line;          tp_line = p_line;
     tp_len = p_len;          tp_len = p_len;
     tp_char = p_char;          tp_char = p_char;
     p_line = Null(char**);      /* force set_hunkmax to allocate again */          p_line = Null(char **); /* force set_hunkmax to allocate again */
     p_len = Null(short*);          p_len = Null(short *);
     p_char = Nullch;          p_char = Nullch;
     set_hunkmax();          set_hunkmax();
     if (p_line == Null(char**) || p_len == Null(short*) || p_char == Nullch) {          if (p_line == Null(char **) ||p_len == Null(short *) ||p_char == Nullch) {
 #ifndef lint  #ifndef lint
         if (p_line == Null(char**))                  if (p_line == Null(char **))
             free((char*)p_line);                          free((char *) p_line);
         p_line = tp_line;                  p_line = tp_line;
         if (p_len == Null(short*))                  if (p_len == Null(short *))
             free((char*)p_len);                          free((char *) p_len);
         p_len = tp_len;                  p_len = tp_len;
 #endif  #endif
         if (p_char == Nullch)                  if (p_char == Nullch)
             free((char*)p_char);                          free((char *) p_char);
         p_char = tp_char;                  p_char = tp_char;
         return FALSE;           /* not enough memory to swap hunk! */                  return FALSE;   /* not enough memory to swap hunk! */
     }          }
           /* now turn the new into the old */
   
     /* now turn the new into the old */  
   
     i = p_ptrn_lines + 1;  
     if (tp_char[i] == '\n') {           /* account for possible blank line */  
         blankline = TRUE;  
         i++;  
     }  
     if (p_efake >= 0) {                 /* fix non-freeable ptr range */  
         if (p_efake <= i)  
             n = p_end - i + 1;  
         else  
             n = -i;  
         p_efake += n;  
         p_bfake += n;  
     }  
     for (n=0; i <= p_end; i++,n++) {  
         p_line[n] = tp_line[i];  
         p_char[n] = tp_char[i];  
         if (p_char[n] == '+')  
             p_char[n] = '-';  
         p_len[n] = tp_len[i];  
     }  
     if (blankline) {  
         i = p_ptrn_lines + 1;          i = p_ptrn_lines + 1;
         p_line[n] = tp_line[i];          if (tp_char[i] == '\n') {       /* account for possible blank line */
         p_char[n] = tp_char[i];                  blankline = TRUE;
         p_len[n] = tp_len[i];                  i++;
         n++;          }
     }          if (p_efake >= 0) {     /* fix non-freeable ptr range */
     assert(p_char[0] == '=');                  if (p_efake <= i)
     p_char[0] = '*';                          n = p_end - i + 1;
     for (s=p_line[0]; *s; s++)                  else
         if (*s == '-')                          n = -i;
             *s = '*';                  p_efake += n;
                   p_bfake += n;
           }
           for (n = 0; i <= p_end; i++, n++) {
                   p_line[n] = tp_line[i];
                   p_char[n] = tp_char[i];
                   if (p_char[n] == '+')
                           p_char[n] = '-';
                   p_len[n] = tp_len[i];
           }
           if (blankline) {
                   i = p_ptrn_lines + 1;
                   p_line[n] = tp_line[i];
                   p_char[n] = tp_char[i];
                   p_len[n] = tp_len[i];
                   n++;
           }
           assert(p_char[0] == '=');
           p_char[0] = '*';
           for (s = p_line[0]; *s; s++)
                   if (*s == '-')
                           *s = '*';
   
     /* now turn the old into the new */          /* now turn the old into the new */
   
     assert(tp_char[0] == '*');          assert(tp_char[0] == '*');
     tp_char[0] = '=';          tp_char[0] = '=';
     for (s=tp_line[0]; *s; s++)          for (s = tp_line[0]; *s; s++)
         if (*s == '*')                  if (*s == '*')
             *s = '-';                          *s = '-';
     for (i=0; n <= p_end; i++,n++) {          for (i = 0; n <= p_end; i++, n++) {
         p_line[n] = tp_line[i];                  p_line[n] = tp_line[i];
         p_char[n] = tp_char[i];                  p_char[n] = tp_char[i];
         if (p_char[n] == '-')                  if (p_char[n] == '-')
             p_char[n] = '+';                          p_char[n] = '+';
         p_len[n] = tp_len[i];                  p_len[n] = tp_len[i];
     }          }
     assert(i == p_ptrn_lines + 1);          assert(i == p_ptrn_lines + 1);
     i = p_ptrn_lines;          i = p_ptrn_lines;
     p_ptrn_lines = p_repl_lines;          p_ptrn_lines = p_repl_lines;
     p_repl_lines = i;          p_repl_lines = i;
 #ifndef lint  #ifndef lint
     if (tp_line == Null(char**))          if (tp_line == Null(char **))
         free((char*)tp_line);                  free((char *) tp_line);
     if (tp_len == Null(short*))          if (tp_len == Null(short *))
         free((char*)tp_len);                  free((char *) tp_len);
 #endif  #endif
     if (tp_char == Nullch)          if (tp_char == Nullch)
         free((char*)tp_char);                  free((char *) tp_char);
     return TRUE;          return TRUE;
 }  }
   
 /* Return the specified line position in the old file of the old context. */  /*
    * Return the specified line position in the old file of the old context.
    */
 LINENUM  LINENUM
 pch_first()  pch_first(void)
 {  {
     return p_first;          return p_first;
 }  }
   
 /* Return the number of lines of old context. */  /*
    * Return the number of lines of old context.
    */
 LINENUM  LINENUM
 pch_ptrn_lines()  pch_ptrn_lines(void)
 {  {
     return p_ptrn_lines;          return p_ptrn_lines;
 }  }
   
 /* Return the probable line position in the new file of the first line. */  /*
    * Return the probable line position in the new file of the first line.
    */
 LINENUM  LINENUM
 pch_newfirst()  pch_newfirst(void)
 {  {
     return p_newfirst;          return p_newfirst;
 }  }
   
 /* Return the number of lines in the replacement text including context. */  /*
    * Return the number of lines in the replacement text including context.
    */
 LINENUM  LINENUM
 pch_repl_lines()  pch_repl_lines(void)
 {  {
     return p_repl_lines;          return p_repl_lines;
 }  }
   
 /* Return the number of lines in the whole hunk. */  /*
    * Return the number of lines in the whole hunk.
    */
 LINENUM  LINENUM
 pch_end()  pch_end(void)
 {  {
     return p_end;          return p_end;
 }  }
   
 /* Return the number of context lines before the first changed line. */  /*
    * Return the number of context lines before the first changed line.
    */
 LINENUM  LINENUM
 pch_context()  pch_context(void)
 {  {
     return p_context;          return p_context;
 }  }
   
 /* Return the length of a particular patch line. */  /*
    * Return the length of a particular patch line.
    */
 short  short
 pch_line_len(line)  pch_line_len(LINENUM line)
 LINENUM line;  
 {  {
     return p_len[line];          return p_len[line];
 }  }
   
 /* Return the control character (+, -, *, !, etc) for a patch line. */  /*
    * Return the control character (+, -, *, !, etc) for a patch line.
    */
 char  char
 pch_char(line)  pch_char(LINENUM line)
 LINENUM line;  
 {  {
     return p_char[line];          return p_char[line];
 }  }
   
 /* Return a pointer to a particular patch line. */  /*
    * Return a pointer to a particular patch line.
    */
 char *  char *
 pfetch(line)  pfetch(LINENUM line)
 LINENUM line;  
 {  {
     return p_line[line];          return p_line[line];
 }  }
   
 /* Return where in the patch file this hunk began, for error messages. */  /*
    * Return where in the patch file this hunk began, for error messages.
    */
 LINENUM  LINENUM
 pch_hunk_beg()  pch_hunk_beg(void)
 {  {
     return p_hunk_beg;          return p_hunk_beg;
 }  }
   
 /* Apply an ed script by feeding ed itself. */  /*
    * Apply an ed script by feeding ed itself.
    */
 void  void
 do_ed_script()  do_ed_script(void)
 {  {
     char *t;          char    *t;
     long beginning_of_this_line;          long    beginning_of_this_line;
     bool this_line_is_command = FALSE;          bool    this_line_is_command = FALSE;
     FILE *pipefp;          FILE    *pipefp;
   
     if (!skip_rest_of_patch) {          if (!skip_rest_of_patch) {
         unlink(TMPOUTNAME);                  unlink(TMPOUTNAME);
         copy_file(filearg[0], TMPOUTNAME);                  copy_file(filearg[0], TMPOUTNAME);
         if (verbose)                  if (verbose)
             snprintf(buf, sizeof buf, "/bin/ed %s", TMPOUTNAME);                          snprintf(buf, sizeof buf, "/bin/ed %s", TMPOUTNAME);
         else                  else
             snprintf(buf, sizeof buf, "/bin/ed - %s", TMPOUTNAME);                          snprintf(buf, sizeof buf, "/bin/ed - %s", TMPOUTNAME);
         pipefp = popen(buf, "w");                  pipefp = popen(buf, "w");
     }  
     for (;;) {  
         beginning_of_this_line = ftell(pfp);  
         if (pgets(buf, sizeof buf, pfp) == Nullch) {  
             next_intuit_at(beginning_of_this_line,p_input_line);  
             break;  
         }          }
         p_input_line++;          for (;;) {
         for (t=buf; isdigit(*t) || *t == ','; t++) ;                  beginning_of_this_line = ftell(pfp);
         this_line_is_command = (isdigit(*buf) &&                  if (pgets(buf, sizeof buf, pfp) == Nullch) {
           (*t == 'd' || *t == 'c' || *t == 'a') );                          next_intuit_at(beginning_of_this_line, p_input_line);
         if (this_line_is_command) {  
             if (!skip_rest_of_patch)  
                 fputs(buf, pipefp);  
             if (*t != 'd') {  
                 while (pgets(buf, sizeof buf, pfp) != Nullch) {  
                     p_input_line++;  
                     if (!skip_rest_of_patch)  
                         fputs(buf, pipefp);  
                     if (strEQ(buf, ".\n"))  
                         break;                          break;
                 }                  }
             }                  p_input_line++;
                   for (t = buf; isdigit(*t) || *t == ','; t++);
                   this_line_is_command = (isdigit(*buf) &&
                       (*t == 'd' || *t == 'c' || *t == 'a'));
                   if (this_line_is_command) {
                           if (!skip_rest_of_patch)
                                   fputs(buf, pipefp);
                           if (*t != 'd') {
                                   while (pgets(buf, sizeof buf, pfp) != Nullch) {
                                           p_input_line++;
                                           if (!skip_rest_of_patch)
                                                   fputs(buf, pipefp);
                                           if (strEQ(buf, ".\n"))
                                                   break;
                                   }
                           }
                   } else {
                           next_intuit_at(beginning_of_this_line, p_input_line);
                           break;
                   }
         }          }
         else {          if (skip_rest_of_patch)
             next_intuit_at(beginning_of_this_line,p_input_line);                  return;
             break;          fprintf(pipefp, "w\n");
           fprintf(pipefp, "q\n");
           fflush(pipefp);
           pclose(pipefp);
           ignore_signals();
           if (!check_only) {
                   if (move_file(TMPOUTNAME, outname) < 0) {
                           toutkeep = TRUE;
                           chmod(TMPOUTNAME, filemode);
                   } else
                           chmod(outname, filemode);
         }          }
     }          set_signals(1);
     if (skip_rest_of_patch)  
         return;  
     fprintf(pipefp, "w\n");  
     fprintf(pipefp, "q\n");  
     fflush(pipefp);  
     pclose(pipefp);  
     ignore_signals();  
     if (!check_only) {  
         if (move_file(TMPOUTNAME, outname) < 0) {  
             toutkeep = TRUE;  
             chmod(TMPOUTNAME, filemode);  
         }  
         else  
             chmod(outname, filemode);  
     }  
     set_signals(1);  
 }  }

Legend:
Removed from v.1.16  
changed lines
  Added in v.1.17