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

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/usr.bin/patch/pch.c between version 1.22 and 1.23

version 1.22, 2006/09/26 16:36:07 version 1.23, 2008/09/19 18:33:34
Line 1 
Line 1 
 /*      $NetBSD$        */  /*
    * $OpenBSD: pch.c,v 1.37 2007/09/02 15:19:33 deraadt Exp $
    * $DragonFly: src/usr.bin/patch/pch.c,v 1.6 2008/08/10 23:35:40 joerg Exp $
    * $NetBSD$
    */
   
 /*  /*
  * Copyright (c) 1988, Larry Wall   * patch - a program to apply diffs to original files
  *   *
    * Copyright 1986, Larry Wall
    *
  * Redistribution and use in source and binary forms, with or without   * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following condition   * modification, are permitted provided that the following condition is met:
  * is met:   * 1. Redistributions of source code must retain the above copyright notice,
  *  1. Redistributions of source code must retain the above copyright   * this condition and the following disclaimer.
  *     notice, this condition and the following disclaimer.   *
  *   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE   * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT  
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.   * SUCH DAMAGE.
    *
    * -C option added in 1998, original code by Marc Espie, based on FreeBSD
    * behaviour
  */   */
   
 #include <sys/cdefs.h>  #include <sys/cdefs.h>
 #ifndef lint  
 __RCSID("$NetBSD$");  __RCSID("$NetBSD$");
 #endif /* not lint */  
   
 #include "EXTERN.h"  #include <sys/types.h>
 #include "common.h"  #include <sys/stat.h>
 #include "util.h"  
 #include "INTERN.h"  
 #include "pch.h"  
   
   #include <ctype.h>
   #include <libgen.h>
   #include <limits.h>
   #include <stdio.h>
 #include <stdlib.h>  #include <stdlib.h>
   #include <string.h>
 #include <unistd.h>  #include <unistd.h>
   
 /* Patch (diff listing) abstract type. */  #include "common.h"
   #include "util.h"
   #include "pch.h"
   #include "pathnames.h"
   
 static long p_filesize;                 /* size of the patch file */  /* Patch (diff listing) abstract type. */
 static LINENUM p_first;                 /* 1st line number */  
 static LINENUM p_newfirst;              /* 1st line number of replacement */  
 static LINENUM p_ptrn_lines;            /* # lines in pattern */  
 static LINENUM p_repl_lines;            /* # lines in replacement text */  
 static LINENUM p_end = -1;              /* last line in hunk */  
 static LINENUM p_max;                   /* max allowed value of p_end */  
 static LINENUM p_context = 3;           /* # of context lines */  
 static LINENUM p_input_line = 0;        /* current line # from patch file */  
 static char **p_line = NULL;            /* the text of the hunk */  
 static size_t *p_len = NULL;            /* length of each line */  
 static char *p_char = NULL;             /* +, -, and ! */  
 static int hunkmax = INITHUNKMAX;       /* size of above arrays */  
 static int p_indent;                    /* indent to patch */  
 static long p_base;                     /* where to intuit this time */  
 static LINENUM p_bline;                 /* line # of p_base */  
 static long p_start;                    /* where intuit found a patch */  
 static LINENUM p_sline;                 /* and the line number for it */  
 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_bfake = -1;            /* beg of faked up lines */  
 static FILE *pfp = NULL;                /* patch file pointer */  
   
 /* Prepare to look for the next patch in the patch file. */  static long     p_filesize;     /* size of the patch file */
 static void malformed(void);  static LINENUM  p_first;        /* 1st line number */
   static LINENUM  p_newfirst;     /* 1st line number of replacement */
   static LINENUM  p_ptrn_lines;   /* # lines in pattern */
   static LINENUM  p_repl_lines;   /* # lines in replacement text */
   static LINENUM  p_end = -1;     /* last line in hunk */
   static LINENUM  p_max;          /* max allowed value of p_end */
   static LINENUM  p_context = 3;  /* # of context lines */
   static LINENUM  p_input_line = 0;       /* current line # from patch file */
   static char     **p_line = NULL;/* the text of the hunk */
   static short    *p_len = NULL;  /* length of each line */
   static char     *p_char = NULL; /* +, -, and ! */
   static int      hunkmax = INITHUNKMAX;  /* size of above arrays to begin with */
   static int      p_indent;       /* indent to patch */
   static LINENUM  p_base;         /* where to intuit this time */
   static LINENUM  p_bline;        /* line # of p_base */
   static LINENUM  p_start;        /* where intuit found a patch */
   static LINENUM  p_sline;        /* and the line number for it */
   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_bfake = -1;   /* beg of faked up lines */
   static FILE     *pfp = NULL;    /* patch file pointer */
   static char     *bestguess = NULL;      /* guess at correct filename */
   
   static void     grow_hunkmax(void);
   static int      intuit_diff_type(void);
   static void     next_intuit_at(LINENUM, LINENUM);
   static void     skip_to(LINENUM, LINENUM);
   static char     *pgets(char *, int, FILE *);
   static char     *best_name(const struct file_name *, bool);
   static char     *posix_name(const struct file_name *, bool);
   static size_t   num_components(const char *);
   
   /*
    * Prepare to look for the next patch in the patch file.
    */
 void  void
 re_patch(void)  re_patch(void)
 {  {
         p_first = Nulline;          p_first = 0;
         p_newfirst = Nulline;          p_newfirst = 0;
         p_ptrn_lines = Nulline;          p_ptrn_lines = 0;
         p_repl_lines = Nulline;          p_repl_lines = 0;
         p_end = -1;          p_end = (LINENUM) - 1;
         p_max = Nulline;          p_max = 0;
         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(char *filename)  open_patch_file(const char *filename)
 {  {
         if (filename == NULL || !*filename || strEQ(filename, "-")) {          struct stat filestat;
   
           if (filename == NULL || *filename == '\0' || strEQ(filename, "-")) {
                 pfp = fopen(TMPPATNAME, "w");                  pfp = fopen(TMPPATNAME, "w");
                 if (pfp == NULL)                  if (pfp == NULL)
                         pfatal("can't create %s", TMPPATNAME);                          pfatal("can't create %s", TMPPATNAME);
                 while (fgets(buf, sizeof buf, stdin) != NULL)                  while (fgets(buf, buf_len, stdin) != NULL)
                         fputs(buf, pfp);                          fputs(buf, pfp);
                 Fclose(pfp);                  if (ferror(pfp) || fclose(pfp))
                           pfatal("can't write %s", TMPPATNAME);
                 filename = TMPPATNAME;                  filename = TMPPATNAME;
         }          }
         pfp = fopen(filename, "r");          pfp = fopen(filename, "r");
         if (pfp == NULL)          if (pfp == NULL)
                 pfatal("patch file %s not found", filename);                  pfatal("patch file %s not found", filename);
         Fstat(fileno(pfp), &filestat);          fstat(fileno(pfp), &filestat);
         p_filesize = filestat.st_size;          p_filesize = filestat.st_size;
         next_intuit_at(0L, 1);                  /* start at the beginning */          next_intuit_at(0L, 1L); /* start at the beginning */
         set_hunkmax();          set_hunkmax();
 }  }
   
Line 107  void
Line 133  void
 set_hunkmax(void)  set_hunkmax(void)
 {  {
         if (p_line == NULL)          if (p_line == NULL)
                 p_line = xmalloc(hunkmax * sizeof(char *));                  p_line = calloc((size_t) hunkmax, sizeof(char *));
         if (p_len == NULL)          if (p_len == NULL)
                 p_len  = xmalloc(hunkmax * sizeof(size_t));                  p_len = calloc((size_t) hunkmax, sizeof(short));
         if (p_char == NULL)          if (p_char == NULL)
                 p_char = xmalloc(hunkmax * sizeof(char));                  p_char = calloc((size_t) hunkmax, sizeof(char));
 }  }
   
 /*  /*
  * Enlarge the arrays containing the current hunk of patch.   * Enlarge the arrays containing the current hunk of patch.
  */   */
 void  static void
 grow_hunkmax(void)  grow_hunkmax(void)
 {  {
         hunkmax *= 2;          int             new_hunkmax;
           char            **new_p_line;
           short           *new_p_len;
           char            *new_p_char;
   
           new_hunkmax = hunkmax * 2;
   
           if (p_line == NULL || p_len == NULL || p_char == NULL)
                   fatal("Internal memory allocation error\n");
   
           new_p_line = realloc(p_line, new_hunkmax * sizeof(char *));
           if (new_p_line == NULL)
                   free(p_line);
   
           new_p_len = realloc(p_len, new_hunkmax * sizeof(short));
           if (new_p_len == NULL)
                   free(p_len);
   
           new_p_char = realloc(p_char, new_hunkmax * sizeof(char));
           if (new_p_char == NULL)
                   free(p_char);
   
           p_char = new_p_char;
           p_len = new_p_len;
           p_line = new_p_line;
   
         p_line = xrealloc(p_line, hunkmax * sizeof(char *));          if (p_line != NULL && p_len != NULL && p_char != NULL) {
         p_len  = xrealloc(p_len,  hunkmax * sizeof(size_t));                  hunkmax = new_hunkmax;
         p_char = xrealloc(p_char, hunkmax * sizeof(char));                  return;
           }
   
           if (!using_plan_a)
                   fatal("out of memory\n");
           out_of_mem = true;      /* whatever is null will be allocated again */
                                   /* 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(void)  there_is_another_patch(void)
 {  {
           bool exists = false;
   
         if (p_base != 0L && p_base >= p_filesize) {          if (p_base != 0L && p_base >= p_filesize) {
                 if (verbose)                  if (verbose)
                         say("done\n");                          say("done\n");
                 return FALSE;                  return false;
         }          }
         if (verbose)          if (verbose)
                 say("Hmm...");                  say("Hmm...");
Line 144  there_is_another_patch(void)
Line 201  there_is_another_patch(void)
         if (!diff_type) {          if (!diff_type) {
                 if (p_base != 0L) {                  if (p_base != 0L) {
                         if (verbose)                          if (verbose)
                                 say("  Ignoring the trailing garbage.\n"                                  say("  Ignoring the trailing garbage.\ndone\n");
                                     "done\n");  
                 } else                  } else
                         say("  I can't seem to find a patch in there"                          say("  I can't seem to find a patch in there anywhere.\n");
                             " anywhere.\n");                  return false;
                 return FALSE;  
         }          }
         if (verbose)          if (verbose)
                 say("  %sooks like %s to me...\n",                  say("  %sooks like %s to me...\n",
                     (p_base == 0L ? "L" : "The next patch l"),                      (p_base == 0L ? "L" : "The next patch l"),
                     diff_type == UNI_DIFF ? "a unified diff" :                      diff_type == UNI_DIFF ? "a unified diff" :
                     diff_type == CONTEXT_DIFF ? "a context diff" :                      diff_type == CONTEXT_DIFF ? "a context diff" :
                     diff_type == NEW_CONTEXT_DIFF ?                  diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" :
                     "a new-style context diff" :  
                     diff_type == NORMAL_DIFF ? "a normal diff" :                      diff_type == NORMAL_DIFF ? "a normal diff" :
                     "an ed script" );                      "an ed script");
         if (p_indent && verbose)          if (p_indent && verbose)
                 say("(Patch is indented %d space%s.)\n",                  say("(Patch is indented %d space%s.)\n", p_indent,
                     p_indent, p_indent == 1 ? "" : "s");                      p_indent == 1 ? "" : "s");
         skip_to(p_start, p_sline);          skip_to(p_start, p_sline);
         while (filearg[0] == NULL) {          while (filearg[0] == NULL) {
                 if (force || batch) {                  if (force || batch) {
                         say("No file to patch.  Skipping...\n");                          say("No file to patch.  Skipping...\n");
                         if (bestguess)                          filearg[0] = savestr(bestguess);
                                 filearg[0] = xstrdup(bestguess);                          skip_rest_of_patch = true;
                         skip_rest_of_patch = TRUE;                          return true;
                         return TRUE;  
                 }                  }
                 ask("File to patch: ");                  ask("File to patch: ");
                 if (*buf != '\n') {                  if (*buf != '\n') {
                         if (bestguess)                          free(bestguess);
                                 free(bestguess);                          bestguess = savestr(buf);
                         bestguess = xstrdup(buf);                          filearg[0] = fetchname(buf, &exists, 0);
                         filearg[0] = fetchname(buf, 0, FALSE);  
                 }                  }
                 if (filearg[0] == NULL) {                  if (!exists) {
                         ask("No file found--skip this patch? [n] ");                          ask("No file found--skip this patch? [n] ");
                         if (*buf != 'y')                          if (*buf != 'y')
                                 continue;                                  continue;
                         if (verbose)                          if (verbose)
                                 say("Skipping patch...\n");                                  say("Skipping patch...\n");
                         filearg[0] = fetchname(bestguess, 0, TRUE);                          free(filearg[0]);
                         skip_rest_of_patch = TRUE;                          filearg[0] = fetchname(bestguess, &exists, 0);
                         return TRUE;                          skip_rest_of_patch = true;
                           return 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.  
  */  static int
 int  
 intuit_diff_type(void)  intuit_diff_type(void)
 {  {
         long this_line = 0;          long    this_line = 0, previous_line;
         long previous_line;          long    first_command_line = -1;
         long first_command_line = -1;          LINENUM fcl_line = -1;
         LINENUM fcl_line = -1;          bool    last_line_was_command = false, this_is_a_command = false;
         bool last_line_was_command = FALSE;          bool    stars_last_line = false, stars_this_line = false;
         bool this_is_a_command = FALSE;          char    *s, *t;
         bool stars_last_line = FALSE;          int     indent, retval;
         bool stars_this_line = FALSE;          struct file_name names[MAX_FILE];
         int indent;  
         char *s;          memset(names, 0, sizeof(names));
         char *t;          ok_to_create_file = false;
         char *indtmp = NULL;          fseek(pfp, p_base, SEEK_SET);
         char *oldtmp = NULL;  
         char *newtmp = NULL;  
         char *indname = NULL;  
         char *oldname = NULL;  
         char *newname = NULL;  
         int retval;  
         bool no_filearg = (filearg[0] == NULL);  
   
         ok_to_create_file = FALSE;  
         old_file_is_dev_null = FALSE;  
         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;
Line 230  intuit_diff_type(void)
Line 271  intuit_diff_type(void)
                 this_line = ftell(pfp);                  this_line = ftell(pfp);
                 indent = 0;                  indent = 0;
                 p_input_line++;                  p_input_line++;
                 if (fgets(buf, sizeof buf, pfp) == NULL) {                  if (fgets(buf, buf_len, pfp) == NULL) {
                         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;
Line 252  intuit_diff_type(void)
Line 293  intuit_diff_type(void)
                 }                  }
                 for (t = s; isdigit((unsigned char)*t) || *t == ','; t++)                  for (t = s; isdigit((unsigned char)*t) || *t == ','; t++)
                         ;                          ;
                 this_is_a_command =                  this_is_a_command = (isdigit((unsigned char)*s) &&
                     isdigit((unsigned char)*s) &&                      (*t == 'd' || *t == 'c' || *t == 'a'));
                     (*t == 'd' || *t == 'c' || *t == 'a');                  if (first_command_line < 0L && this_is_a_command) {
                 if (first_command_line < 0L && this_is_a_command) {  
                         first_command_line = this_line;                          first_command_line = this_line;
                         fcl_line = p_input_line;                          fcl_line = p_input_line;
                         p_indent = indent;      /* assume this for now */                          p_indent = indent;      /* assume this for now */
                 }                  }
                 if (!stars_last_line && strnEQ(s, "*** ", 4)) {                  if (!stars_last_line && strnEQ(s, "*** ", 4))
                         if (oldtmp)                          names[OLD_FILE].path = fetchname(s + 4,
                                 free(oldtmp);                              &names[OLD_FILE].exists, strippath);
                         oldtmp = xstrdup(s + 4);                  else if (strnEQ(s, "--- ", 4))
                 } else if (strnEQ(s, "--- ", 4)) {                          names[NEW_FILE].path = fetchname(s + 4,
                         if (newtmp)                              &names[NEW_FILE].exists, strippath);
                                 free(newtmp);                  else if (strnEQ(s, "+++ ", 4))
                         newtmp = xstrdup(s + 4);                          /* pretend it is the old name */
                 } else if (strnEQ(s, "+++ ", 4)) {                          names[OLD_FILE].path = fetchname(s + 4,
                         if (oldtmp)                              &names[OLD_FILE].exists, strippath);
                                 free(oldtmp);                  else if (strnEQ(s, "Index:", 6))
                         oldtmp = xstrdup(s + 4);        /* pretend it is the old name */                          names[INDEX_FILE].path = fetchname(s + 6,
                 } else if (strnEQ(s, "Index:", 6)) {                              &names[INDEX_FILE].exists, strippath);
                         if (indtmp)                  else if (strnEQ(s, "Prereq:", 7)) {
                                 free(indtmp);  
                         indtmp = xstrdup(s + 6);  
                 } else if (strnEQ(s, "Prereq:", 7)) {  
                         for (t = s + 7; isspace((unsigned char)*t); t++)                          for (t = s + 7; isspace((unsigned char)*t); t++)
                                 ;                                  ;
                         if (revision)                          revision = savestr(t);
                                 free(revision);                          for (t = revision; *t && !isspace((unsigned char)*t); t++)
                         revision = xstrdup(t);  
                         for (t = revision;  
                              *t && !isspace((unsigned char)*t);  
                              t++)  
                                 ;                                  ;
                         *t = '\0';                          *t = '\0';
                         if (*revision == '\0') {                          if (*revision == '\0') {
Line 294  intuit_diff_type(void)
Line 327  intuit_diff_type(void)
                 }                  }
                 if ((!diff_type || diff_type == ED_DIFF) &&                  if ((!diff_type || diff_type == ED_DIFF) &&
                     first_command_line >= 0L &&                      first_command_line >= 0L &&
                     strEQ(s, ".\n") ) {                      strEQ(s, ".\n")) {
                         p_indent = indent;                          p_indent = indent;
                         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;
                 }                  }
                 if ((!diff_type || diff_type == UNI_DIFF) &&                  if ((!diff_type || diff_type == UNI_DIFF) && strnEQ(s, "@@ -", 4)) {
                     strnEQ(s, "@@ -", 4)) {                          if (strnEQ(s + 4, "0,0", 3))
                         if (!atol(s + 3))                                  ok_to_create_file = true;
                                 ok_to_create_file = TRUE;  
                         p_indent = indent;                          p_indent = indent;
                         p_start = this_line;                          p_start = this_line;
                         p_sline = p_input_line;                          p_sline = p_input_line;
Line 312  intuit_diff_type(void)
Line 344  intuit_diff_type(void)
                         goto scan_exit;                          goto scan_exit;
                 }                  }
                 stars_this_line = strnEQ(s, "********", 8);                  stars_this_line = strnEQ(s, "********", 8);
                 if ((!diff_type || diff_type == CONTEXT_DIFF) &&                  if ((!diff_type || diff_type == CONTEXT_DIFF) && stars_last_line &&
                     stars_last_line &&  
                     strnEQ(s, "*** ", 4)) {                      strnEQ(s, "*** ", 4)) {
                         if (!atol(s + 4))                          if (atol(s + 4) == 0)
                                 ok_to_create_file = TRUE;                                  ok_to_create_file = true;
                         /*                          /*
                          * If this is a new context diff the character just                           * If this is a new context diff the character just
                          * before the newline is a '*'.                           * before the newline is a '*'.
Line 326  intuit_diff_type(void)
Line 357  intuit_diff_type(void)
                         p_indent = indent;                          p_indent = indent;
                         p_start = previous_line;                          p_start = previous_line;
                         p_sline = p_input_line - 1;                          p_sline = p_input_line - 1;
                         retval = (*(s - 1) == '*' ?                          retval = (*(s - 1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF);
                                   NEW_CONTEXT_DIFF : CONTEXT_DIFF);  
                         goto scan_exit;                          goto scan_exit;
                 }                  }
                 if ((!diff_type || diff_type == NORMAL_DIFF) &&                  if ((!diff_type || diff_type == NORMAL_DIFF) &&
                     last_line_was_command &&                      last_line_was_command &&
                     (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2)) ) {                      (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2))) {
                         p_start = previous_line;                          p_start = previous_line;
                         p_sline = p_input_line - 1;                          p_sline = p_input_line - 1;
                         p_indent = indent;                          p_indent = indent;
Line 340  intuit_diff_type(void)
Line 370  intuit_diff_type(void)
                         goto scan_exit;                          goto scan_exit;
                 }                  }
         }          }
  scan_exit:  scan_exit:
         if (no_filearg) {          if (retval == UNI_DIFF) {
                 if (indtmp != NULL)                  /* unswap old and new */
                         indname = fetchname(indtmp,                  struct file_name tmp = names[OLD_FILE];
                                             strippath,                  names[OLD_FILE] = names[NEW_FILE];
                                             ok_to_create_file);                  names[NEW_FILE] = tmp;
                 if (oldtmp != NULL) {          }
                         oldname = fetchname(oldtmp,          if (filearg[0] == NULL) {
                                             strippath,                  if (posix)
                                             ok_to_create_file);                          filearg[0] = posix_name(names, ok_to_create_file);
                         old_file_is_dev_null = filename_is_dev_null;                  else {
                 }                          /* Ignore the Index: name for context diffs, like GNU */
                 if (newtmp != NULL)                          if (names[OLD_FILE].path != NULL ||
                         newname = fetchname(newtmp,                              names[NEW_FILE].path != NULL) {
                                             strippath,                                  free(names[INDEX_FILE].path);
                                             ok_to_create_file);                                  names[INDEX_FILE].path = NULL;
                 if (oldname && newname) {                          }
                         if (strlen(oldname) < strlen(newname))                          filearg[0] = best_name(names, ok_to_create_file);
                                 filearg[0] = xstrdup(oldname);  
                         else  
                                 filearg[0] = xstrdup(newname);  
                 }                  }
                 else if (oldname)  
                         filearg[0] = xstrdup(oldname);  
                 else if (newname)  
                         filearg[0] = xstrdup(newname);  
                 else if (indname)  
                         filearg[0] = xstrdup(indname);  
         }  
         if (bestguess) {  
                 free(bestguess);  
                 bestguess = NULL;  
         }          }
   
           free(bestguess);
           bestguess = NULL;
         if (filearg[0] != NULL)          if (filearg[0] != NULL)
                 bestguess = xstrdup(filearg[0]);                  bestguess = savestr(filearg[0]);
         else if (indtmp != NULL)          else if (!ok_to_create_file) {
                 bestguess = fetchname(indtmp, strippath, TRUE);                  /*
         else {                   * We don't want to create a new file but we need a
                 if (oldtmp != NULL) {                   * filename to set bestguess.  Avoid setting filearg[0]
                         oldname = fetchname(oldtmp, strippath, TRUE);                   * so the file is not created automatically.
                         old_file_is_dev_null = filename_is_dev_null;                   */
                 }                  if (posix)
                 if (newtmp != NULL) {                          bestguess = posix_name(names, true);
                         if (newname)                  else
                                 free(newname);                          bestguess = best_name(names, true);
                         newname = fetchname(newtmp, strippath, TRUE);          }
                 }          free(names[OLD_FILE].path);
                 if (oldname && newname) {          free(names[NEW_FILE].path);
                         if (strlen(oldname) < strlen(newname))          free(names[INDEX_FILE].path);
                                 bestguess = xstrdup(oldname);  
                         else  
                                 bestguess = xstrdup(newname);  
                 }  
                 else if (oldname)  
                         bestguess = xstrdup(oldname);  
                 else if (newname)  
                         bestguess = xstrdup(newname);  
         }  
         if (indtmp != NULL)  
                 free(indtmp);  
         if (oldtmp != NULL)  
                 free(oldtmp);  
         if (newtmp != NULL)  
                 free(newtmp);  
         if (indname != NULL)  
                 free(indname);  
         if (oldname != NULL)  
                 free(oldname);  
         if (newname != NULL)  
                 free(newname);  
         return retval;          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  static void
 next_intuit_at(long file_pos, LINENUM file_line)  next_intuit_at(LINENUM file_pos, LINENUM file_line)
 {  {
         p_base = file_pos;          p_base = file_pos;
         p_bline = file_line;          p_bline = file_line;
Line 426  next_intuit_at(long file_pos, LINENUM fi
Line 425  next_intuit_at(long file_pos, LINENUM fi
 /*  /*
  * Basically a verbose fseek() to the actual diff listing.   * Basically a verbose fseek() to the actual diff listing.
  */   */
 void  static void
 skip_to(long file_pos, LINENUM file_line)  skip_to(LINENUM file_pos, LINENUM file_line)
 {  {
         char *ret;          char    *ret;
   
         if (p_base > file_pos)          if (p_base > file_pos)
                 fatal("seeked too far %ld > %ld\n", p_base, file_pos);                  fatal("Internal error: seek %ld>%ld\n", 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, SEEK_SET);
                 say("The text leading up to this was:\n"                  say("The text leading up to this was:\n--------------------------\n");
                     "--------------------------\n");  
                 while (ftell(pfp) < file_pos) {                  while (ftell(pfp) < file_pos) {
                         ret = fgets(buf, sizeof buf, pfp);                          ret = fgets(buf, buf_len, pfp);
                         if (ret == NULL)                          if (ret == NULL)
                                 fatal("Unexpected end of file\n");                                  fatal("Unexpected end of file\n");
                         say("|%s", buf);                          say("|%s", buf);
                 }                  }
                 say("--------------------------\n");                  say("--------------------------\n");
         }          } else
         else                  fseek(pfp, file_pos, SEEK_SET);
                 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 %d: %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 467  malformed(void)
Line 462  malformed(void)
 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 475  remove_special_line(void)
Line 470  remove_special_line(void)
                         c = fgetc(pfp);                          c = fgetc(pfp);
                 } while (c != EOF && c != '\n');                  } while (c != EOF && c != '\n');
   
                 return TRUE;                  return true;
         }          }
   
         if (c != EOF)          if (c != EOF)
                 fseek(pfp, -1L, SEEK_CUR);                  fseek(pfp, -1L, SEEK_CUR);
   
         return FALSE;          return false;
 }  }
   
 /*  /*
Line 490  remove_special_line(void)
Line 484  remove_special_line(void)
 bool  bool
 another_hunk(void)  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 */
     while (p_end >= 0) {          LINENUM filldst;                        /* index of first missing line */
         if (p_end == p_efake)          bool    ptrn_spaces_eaten;              /* ptrn was slightly misformed */
             p_end = p_bfake;            /* don't free twice */          bool    repl_could_be_missing;          /* no + or ! lines in this hunk */
         else          bool    repl_missing;                   /* we are now backtracking */
             free(p_line[p_end]);          long    repl_backtrack_position;        /* file pos of first repl line */
         p_end--;          LINENUM repl_patch_line;                /* input line number for same */
     }          LINENUM ptrn_copiable;                  /* # of copiable lines in ptrn */
     if (p_end != -1)          char    *s, *ret;
         fatal("Internal error\n");          int     context = 0;
     p_efake = -1;  
           while (p_end >= 0) {
     p_max = hunkmax;                    /* gets reduced when --- found */                  if (p_end == p_efake)
     if (diff_type == CONTEXT_DIFF || diff_type == NEW_CONTEXT_DIFF) {                          p_end = p_bfake;        /* don't free twice */
         long line_beginning = ftell(pfp);                  else
                                         /* file pos of the current line */                          free(p_line[p_end]);
         LINENUM repl_beginning = 0;     /* index of --- line */                  p_end--;
         LINENUM fillcnt = 0;            /* #lines of missing ptrn or repl */          }
         LINENUM fillsrc = 0;            /* index of first line to copy */          p_efake = -1;
         LINENUM filldst = 0;            /* index of first missing line */  
         bool ptrn_spaces_eaten = FALSE; /* ptrn was slightly misformed */          p_max = hunkmax;        /* gets reduced when --- found */
         bool repl_could_be_missing = TRUE;          if (diff_type == CONTEXT_DIFF || diff_type == NEW_CONTEXT_DIFF) {
                                         /* no + or ! lines in this hunk */                  line_beginning = ftell(pfp);
         bool repl_missing = FALSE;      /* we are now backtracking */                  repl_beginning = 0;
         long repl_backtrack_position = 0;                  fillcnt = 0;
                                         /* file pos of first repl line */                  fillsrc = 0;
         LINENUM repl_patch_line = 0;    /* input line number for same */                  filldst = 0;
         LINENUM ptrn_copiable = 0;      /* # of copiable lines in ptrn */                  ptrn_spaces_eaten = false;
                   repl_could_be_missing = true;
         ret = pgets(buf, sizeof buf, pfp);                  repl_missing = false;
         p_input_line++;                  repl_backtrack_position = 0;
         if (ret == NULL || strnNE(buf, "********", 8)) {                  repl_patch_line = 0;
             next_intuit_at(line_beginning,p_input_line);                  ptrn_copiable = 0;
             return FALSE;  
         }                  ret = pgets(buf, buf_len, pfp);
         p_context = 100;                  p_input_line++;
         p_hunk_beg = p_input_line + 1;                  if (ret == NULL || strnNE(buf, "********", 8)) {
         while (p_end < p_max) {                          next_intuit_at(line_beginning, p_input_line);
             line_beginning = ftell(pfp);                          return false;
             ret = pgets(buf, sizeof buf, pfp);                  }
             p_input_line++;                  p_context = 100;
             if (ret == NULL) {                  p_hunk_beg = p_input_line + 1;
                 if (p_max - p_end < 4) {                  while (p_end < p_max) {
                     /* assume blank lines got chopped */                          line_beginning = ftell(pfp);
                     strlcpy(buf, "  \n", sizeof(buf));                          ret = pgets(buf, buf_len, pfp);
                 } else {                          p_input_line++;
                     if (repl_beginning && repl_could_be_missing) {                          if (ret == NULL) {
                         repl_missing = TRUE;                                  if (p_max - p_end < 4) {
                         goto hunk_done;                                          /* assume blank lines got chopped */
                     }                                          strlcpy(buf, "  \n", buf_len);
                     fatal("unexpected end of file in patch\n");                                  } else {
                 }                                          if (repl_beginning && repl_could_be_missing) {
             }                                                  repl_missing = true;
             p_end++;                                                  goto hunk_done;
             if (p_end >= hunkmax)                                          }
                 fatal("hunk larger than current buffer size\n");                                          fatal("unexpected end of file in patch\n");
             p_char[p_end] = *buf;                                  }
             p_line[p_end] = NULL;                          }
             switch (*buf) {                          p_end++;
             case '*':                          if (p_end >= hunkmax)
                 if (strnEQ(buf, "********", 8)) {                                  fatal("Internal error: hunk larger than hunk "
                     if (repl_beginning && repl_could_be_missing) {                                      "buffer size");
                         repl_missing = TRUE;                          p_char[p_end] = *buf;
                         goto hunk_done;                          p_line[p_end] = NULL;
                     }                          switch (*buf) {
                     else                          case '*':
                         fatal("unexpected end of hunk at line %d\n",                                  if (strnEQ(buf, "********", 8)) {
                             p_input_line);                                          if (repl_beginning && repl_could_be_missing) {
                 }                                                  repl_missing = true;
                 if (p_end != 0) {                                                  goto hunk_done;
                     if (repl_beginning && repl_could_be_missing) {                                          } else
                         repl_missing = TRUE;                                                  fatal("unexpected end of hunk "
                         goto hunk_done;                                                      "at line %ld\n",
                     }                                                      p_input_line);
                     fatal("unexpected *** at line %d: %s", p_input_line, buf);                                  }
                                   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((unsigned char)*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((unsigned char)*s))
                                           s++;
                                   if (*s == ',') {
                                           for (; *s && !isdigit((unsigned char)*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;
                                   }
   
                                   /* we need this much at least */
                                   p_max = p_ptrn_lines + 6;
                                   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((unsigned char)*s); s++)
                                                   ;
                                           if (!*s)
                                                   malformed();
                                           p_newfirst = (LINENUM) atol(s);
                                           while (isdigit((unsigned char)*s))
                                                   s++;
                                           if (*s == ',') {
                                                   for (; *s && !isdigit((unsigned char)*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", buf_len - 1);
                                   if (!isspace((unsigned char)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((unsigned char)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;
                 }                  }
                 context = 0;  
                 p_line[p_end] = xstrdup(buf);  hunk_done:
                 for (s = buf; *s && !isdigit((unsigned char)*s); s++)                  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, SEEK_SET);
   
                           /* 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
                           if (fillsrc != p_end + 1 && fillsrc != repl_beginning)
                                   malformed();
                           if (filldst != p_end + 1 && filldst != repl_beginning)
                                   malformed();
                   }
                   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) {
                   LINENUM fillold;        /* index of old lines */
                   LINENUM fillnew;        /* index of new lines */
                   char    ch;
   
                   line_beginning = ftell(pfp); /* file pos of the current line */
                   ret = pgets(buf, buf_len, pfp);
                   p_input_line++;
                   if (ret == NULL || 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))                  p_first = (LINENUM) atol(s);
                     strlcpy(s, s + 2, sizeof(buf) - (s - buf));                  while (isdigit((unsigned char)*s))
                 p_first = atoi(s);                          s++;
                   if (*s == ',') {
                           p_ptrn_lines = (LINENUM) atol(++s);
                           while (isdigit((unsigned char)*s))
                                   s++;
                   } else
                           p_ptrn_lines = 1;
                   if (*s == ' ')
                           s++;
                   if (*s != '+' || !*++s)
                           malformed();
                   p_newfirst = (LINENUM) atol(s);
                 while (isdigit((unsigned char)*s))                  while (isdigit((unsigned char)*s))
                         s++;                          s++;
                 if (*s == ',') {                  if (*s == ',') {
                     for (; *s && !isdigit((unsigned char)*s); s++)                          p_repl_lines = (LINENUM) atol(++s);
                             ;                          while (isdigit((unsigned char)*s))
                     if (!*s)                                  s++;
                   } else
                           p_repl_lines = 1;
                   if (*s == ' ')
                           s++;
                   if (*s != '@')
                         malformed();                          malformed();
                     p_ptrn_lines = atoi(s) - p_first + 1;                  if (!p_ptrn_lines)
                 } else if (p_first)                          p_first++;      /* do append rather than insert */
                     p_ptrn_lines = 1;                  p_max = p_ptrn_lines + p_repl_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)                  while (p_max >= hunkmax)
                     grow_hunkmax();                          grow_hunkmax();
                 p_max = hunkmax;                  fillold = 1;
                 break;                  fillnew = fillold + p_ptrn_lines;
             case '-':                  p_end = fillnew + p_repl_lines;
                 if (buf[1] == '-') {                  snprintf(buf, buf_len, "*** %ld,%ld ****\n", p_first,
                     if (repl_beginning ||                      p_first + p_ptrn_lines - 1);
                         (p_end !=                  p_line[0] = savestr(buf);
                              p_ptrn_lines + 1 + (p_char[p_end - 1] == '\n'))) {                  if (out_of_mem) {
                         if (p_end == 1) {                          p_end = -1;
                             /* `old' lines were omitted - set up to fill */                          return false;
                             /* them in from 'new' context lines. */                  }
                             p_end = p_ptrn_lines + 1;                  p_char[0] = '*';
                             fillsrc = p_end + 1;                  snprintf(buf, buf_len, "--- %ld,%ld ----\n", p_newfirst,
                             filldst = 1;                      p_newfirst + p_repl_lines - 1);
                             fillcnt = p_ptrn_lines;                  p_line[fillnew] = savestr(buf);
                   if (out_of_mem) {
                           p_end = 0;
                           return false;
                   }
                   p_char[fillnew++] = '=';
                   p_context = 100;
                   context = 0;
                   p_hunk_beg = p_input_line + 1;
                   while (fillold <= p_ptrn_lines || fillnew <= p_end) {
                           line_beginning = ftell(pfp);
                           ret = pgets(buf, buf_len, pfp);
                           p_input_line++;
                           if (ret == NULL) {
                                   if (p_max - fillnew < 3) {
                                           /* assume blank lines got chopped */
                                           strlcpy(buf, " \n", buf_len);
                                   } else {
                                           fatal("unexpected end of file in patch\n");
                                   }
                           }
                           if (*buf == '\t' || *buf == '\n') {
                                   ch = ' ';       /* assume the space got eaten */
                                   s = savestr(buf);
                         } else {                          } else {
                             if (repl_beginning) {                                  ch = *buf;
                                 if (repl_could_be_missing) {                                  s = savestr(buf + 1);
                                     repl_missing = TRUE;  
                                     goto hunk_done;  
                                 }  
                                 fatal("duplicate \"---\" at line %d"  
                                       "--check line numbers at line %d\n",  
                                       p_input_line,  
                                       p_hunk_beg + repl_beginning);  
                             } else {  
                                 fatal("%s \"---\" at line %d"  
                                       "--check line numbers at line %d\n",  
                                       (p_end <= p_ptrn_lines  
                                        ? "Premature"  
                                        : "Overdue" ),  
                                       p_input_line, p_hunk_beg);  
                             }  
                         }                          }
                     }                          if (out_of_mem) {
                     repl_beginning = p_end;                                  while (--fillnew > p_ptrn_lines)
                     repl_backtrack_position = ftell(pfp);                                          free(p_line[fillnew]);
                     repl_patch_line = p_input_line;                                  p_end = fillold - 1;
                     p_line[p_end] = xstrdup(buf);                                  return false;
                     p_char[p_end] = '=';                          }
                     for (s = buf; *s && !isdigit((unsigned char)*s); s++)                          switch (ch) {
                             ;                          case '-':
                     if (!*s)                                  if (fillold > p_ptrn_lines) {
                         malformed();                                          free(s);
                     p_newfirst = atoi(s);                                          p_end = fillnew - 1;
                     while (isdigit((unsigned char)*s))                                          malformed();
                             s++;                                  }
                     if (*s == ',') {                                  p_char[fillold] = ch;
                         for (; *s && !isdigit((unsigned char)*s); s++)                                  p_line[fillold] = s;
                                 ;                                  p_len[fillold++] = strlen(s);
                         if (!*s)                                  if (fillold > p_ptrn_lines) {
                             malformed();                                          if (remove_special_line()) {
                         p_repl_lines = atoi(s) - p_newfirst + 1;                                                  p_len[fillold - 1] -= 1;
                     } else if (p_newfirst)                                                  s[p_len[fillold - 1]] = 0;
                         p_repl_lines = 1;                                          }
                     else {                                  }
                         p_repl_lines = 0;                                  break;
                         p_newfirst = 1;                          case '=':
                     }                                  ch = ' ';
                     p_max = p_repl_lines + p_end;                                  /* FALL THROUGH */
                     if (p_max > MAXHUNKSIZE)                          case ' ':
                         fatal("hunk too large (%d lines) at line %d: %s",                                  if (fillold > p_ptrn_lines) {
                               p_max, p_input_line, buf);                                          free(s);
                     while (p_max >= hunkmax)                                          while (--fillnew > p_ptrn_lines)
                                                   free(p_line[fillnew]);
                                           p_end = fillold - 1;
                                           malformed();
                                   }
                                   context++;
                                   p_char[fillold] = ch;
                                   p_line[fillold] = s;
                                   p_len[fillold++] = strlen(s);
                                   s = savestr(s);
                                   if (out_of_mem) {
                                           while (--fillnew > p_ptrn_lines)
                                                   free(p_line[fillnew]);
                                           p_end = fillold - 1;
                                           return false;
                                   }
                                   if (fillold > p_ptrn_lines) {
                                           if (remove_special_line()) {
                                                   p_len[fillold - 1] -= 1;
                                                   s[p_len[fillold - 1]] = 0;
                                           }
                                   }
                                   /* FALL THROUGH */
                           case '+':
                                   if (fillnew > p_end) {
                                           free(s);
                                           while (--fillnew > p_ptrn_lines)
                                                   free(p_line[fillnew]);
                                           p_end = fillold - 1;
                                           malformed();
                                   }
                                   p_char[fillnew] = ch;
                                   p_line[fillnew] = s;
                                   p_len[fillnew++] = strlen(s);
                                   if (fillold > p_ptrn_lines) {
                                           if (remove_special_line()) {
                                                   p_len[fillnew - 1] -= 1;
                                                   s[p_len[fillnew - 1]] = 0;
                                           }
                                   }
                                   break;
                           default:
                                   p_end = fillnew;
                                   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;
   
                   line_beginning = ftell(pfp);
                   p_context = 0;
                   ret = pgets(buf, buf_len, pfp);
                   p_input_line++;
                   if (ret == NULL || !isdigit((unsigned char)*buf)) {
                           next_intuit_at(line_beginning, p_input_line);
                           return false;
                   }
                   p_first = (LINENUM) atol(buf);
                   for (s = buf; isdigit((unsigned char)*s); s++)
                           ;
                   if (*s == ',') {
                           p_ptrn_lines = (LINENUM) atol(++s) - p_first + 1;
                           while (isdigit((unsigned char)*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((unsigned char)*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();                          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, buf_len, "*** %ld,%ld\n", p_first,
                     break;                      p_first + p_ptrn_lines - 1);
                 }                  p_line[0] = savestr(buf);
                 goto change_line;                  if (out_of_mem) {
             case '+':  case '!':                          p_end = -1;
                 repl_could_be_missing = FALSE;                          return false;
             change_line:                  }
                 if (buf[1] == '\n' && canonicalize)                  p_char[0] = '*';
                     strlcpy(buf + 1," \n", sizeof(buf) - 1);                  for (i = 1; i <= p_ptrn_lines; i++) {
                 if (!isspace((unsigned char)buf[1]) &&                          ret = pgets(buf, buf_len, pfp);
                     buf[1] != '>' && buf[1] != '<' &&                          p_input_line++;
                     repl_beginning && repl_could_be_missing) {                          if (ret == NULL)
                     repl_missing = TRUE;                                  fatal("unexpected end of file in patch at line %ld\n",
                     goto hunk_done;                                      p_input_line);
                 }                          if (*buf != '<')
                 if (context >= 0) {                                  fatal("< expected at line %ld of patch\n",
                     if (context < p_context)                                      p_input_line);
                         p_context = context;                          p_line[i] = savestr(buf + 2);
                     context = -1000;                          if (out_of_mem) {
                 }                                  p_end = i - 1;
                 p_line[p_end] = xstrdup(buf + 2);                                  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;  
                         }                          }
                           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] = xstrdup(buf);  
                 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((unsigned char)buf[1]) &&  
                     repl_beginning && repl_could_be_missing) {  
                     repl_missing = TRUE;  
                     goto hunk_done;  
                 }  
                 context++;  
                 if (!repl_beginning)  
                     ptrn_copiable++;  
                 p_line[p_end] = xstrdup(buf + 2);  
                 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 %d\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",  
                     "(Fascinating--this is really a new-style context diff"  
                     "but without\nthe telltale extra asterisks on the *** "  
                     "line that usually indicate\nthe 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 %d\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 %d, filldst %d, rb %d, e %d\n",  
                     fillsrc, filldst, repl_beginning, p_end);  
 #endif  
             if (fillsrc != p_end + 1 && fillsrc != repl_beginning)  
                 malformed();  
             if (filldst != p_end + 1 && filldst != repl_beginning)  
                 malformed();  
         }  
   
         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;
                 }  
         }  
     } 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 == NULL || strnNE(buf, "@@ -", 4)) {  
             next_intuit_at(line_beginning,p_input_line);  
             return FALSE;  
         }  
         s = buf + 4;  
         if (!*s)  
             malformed();  
         p_first = atoi(s);  
         while (isdigit((unsigned char)*s))  
                 s++;  
         if (*s == ',') {  
             p_ptrn_lines = atoi(++s);  
             while (isdigit((unsigned char)*s))  
                     s++;  
         } else  
             p_ptrn_lines = 1;  
         if (*s == ' ')  
                 s++;  
         if (*s != '+' || !*++s)  
             malformed();  
         p_newfirst = atoi(s);  
         while (isdigit((unsigned char)*s))  
                 s++;  
         if (*s == ',') {  
             p_repl_lines = atoi(++s);  
             while (isdigit((unsigned char)*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), "*** %d,%d ****\n", p_first,  
             p_first + p_ptrn_lines - 1);  
         p_line[0] = xstrdup(buf);  
         p_char[0] = '*';  
         snprintf(buf, sizeof(buf), "--- %d,%d ----\n", p_newfirst,  
                 p_newfirst + p_repl_lines - 1);  
         p_line[filldst] = xstrdup(buf);  
         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 == NULL) {  
                 if (p_max - filldst < 3) {  
                     /* assume blank lines got chopped */  
                     strlcpy(buf, " \n", sizeof(buf));  
                 } else {  
                     fatal("unexpected end of file in patch\n");  
                 }                  }
             }                  if (hunk_type == 'c') {
             if (*buf == '\t' || *buf == '\n') {                          ret = pgets(buf, buf_len, pfp);
                 ch = ' ';               /* assume the space got eaten */                          p_input_line++;
                 s = xstrdup(buf);                          if (ret == NULL)
             } else {                                  fatal("unexpected end of file in patch at line %ld\n",
                 ch = *buf;                                      p_input_line);
                 s = xstrdup(buf + 1);                          if (*buf != '-')
             }                                  fatal("--- expected at line %ld of patch\n",
             switch (ch) {                                      p_input_line);
             case '-':                  }
                 if (fillsrc > p_ptrn_lines) {                  snprintf(buf, buf_len, "--- %ld,%ld\n", min, max);
                     free(s);                  p_line[i] = savestr(buf);
                     p_end = filldst - 1;                  if (out_of_mem) {
                     malformed();                          p_end = i - 1;
                 }                          return false;
                 p_char[fillsrc] = ch;                  }
                 p_line[fillsrc] = s;                  p_char[i] = '=';
                 p_len[fillsrc++] = strlen(s);                  for (i++; i <= p_end; i++) {
                 if (fillsrc > p_ptrn_lines) {                          ret = pgets(buf, buf_len, pfp);
                         if (remove_special_line()) {                          p_input_line++;
                                 p_len[fillsrc - 1] -= 1;                          if (ret == NULL)
                                 s[p_len[fillsrc - 1]] = 0;                                  fatal("unexpected end of file in patch at line %ld\n",
                         }                                      p_input_line);
                 }                          if (*buf != '>')
                 break;                                  fatal("> expected at line %ld of patch\n",
             case '=':                                      p_input_line);
                 ch = ' ';                          p_line[i] = savestr(buf + 2);
                 /* FALLTHROUGH */                          if (out_of_mem) {
             case ' ':                                  p_end = i - 1;
                 if (fillsrc > p_ptrn_lines) {                                  return false;
                     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 = xstrdup(s);  
                 /* FALLTHROUGH */  
             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;  
                         }                          }
                           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 == NULL || !isdigit((unsigned char)*buf)) {                  }
             next_intuit_at(line_beginning, p_input_line);          }
             return FALSE;          if (reverse)            /* backwards patch? */
         }                  if (!pch_swap())
         p_first = atoi(buf);                          say("Not enough memory to swap next hunk!\n");
         for (s = buf; isdigit((unsigned char)*s); s++)  
                 ;  
         if (*s == ',') {  
             p_ptrn_lines = atoi(++s) - p_first + 1;  
             while (isdigit((unsigned char)*s))  
                     s++;  
         } else  
             p_ptrn_lines = (*s != 'a');  
         hunk_type = *s;  
         if (hunk_type == 'a')  
             p_first++;                  /* do append rather than insert */  
         min = atoi(++s);  
         for (; isdigit((unsigned char)*s); s++)  
                 ;  
         if (*s == ',')  
             max = atoi(++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 (%d lines) at line %d: %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), "*** %d,%d\n", p_first,  
             p_first + p_ptrn_lines - 1);  
         p_line[0] = xstrdup(buf);  
         p_char[0] = '*';  
         for (i = 1; i <= p_ptrn_lines; i++) {  
             ret = pgets(buf, sizeof buf, pfp);  
             p_input_line++;  
             if (ret == NULL)  
                 fatal("unexpected end of file in patch at line %d\n",  
                       p_input_line);  
             if (*buf != '<')  
                 fatal("< expected at line %d of patch\n", p_input_line);  
             p_line[i] = xstrdup(buf + 2);  
             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 == NULL)  
                 fatal("unexpected end of file in patch at line %d\n",  
                     p_input_line);  
             if (*buf != '-')  
                 fatal("--- expected at line %d of patch\n", p_input_line);  
         }  
         snprintf(buf, sizeof(buf), "--- %d,%d\n", min, max);  
         p_line[i] = xstrdup(buf);  
         p_char[i] = '=';  
         for (i++; i <= p_end; i++) {  
             ret = pgets(buf, sizeof buf, pfp);  
             p_input_line++;  
             if (ret == NULL)  
                 fatal("unexpected end of file in patch at line %d\n",  
                     p_input_line);  
             if (*buf != '>')  
                 fatal("> expected at line %d of patch\n", p_input_line);  
             p_line[i] = xstrdup(buf + 2);  
             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 *  static char *
 pgets(char *bf, int sz, FILE *fp)  pgets(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 != NULL) {          if (p_indent && ret != NULL) {
                 for (s = buf;                  for (s = buf;
                      indent < p_indent &&                      indent < p_indent && (*s == ' ' || *s == '\t' || *s == 'X');
                              (*s == ' ' || *s == '\t' || *s == 'X');                      s++) {
                      s++) {  
                         if (*s == '\t')                          if (*s == '\t')
                                 indent += 8 - (indent % 7);                                  indent += 8 - (indent % 7);
                         else                          else
                                 indent++;                                  indent++;
                 }                  }
                 if (buf != s)                  if (buf != s && strlcpy(buf, s, buf_len) >= buf_len)
                         strlcpy(buf, s, sizeof(buf));                          fatal("buffer too small in pgets()\n");
         }          }
         return ret;          return ret;
 }  }
Line 1110  pgets(char *bf, int sz, FILE *fp)
Line 1175  pgets(char *bf, int sz, FILE *fp)
 bool  bool
 pch_swap(void)  pch_swap(void)
 {  {
         char **tp_line;         /* the text of the hunk */          char    **tp_line;      /* the text of the hunk */
         size_t *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;          /* force set_hunkmax to allocate again */          p_line = NULL;  /* force set_hunkmax to allocate again */
         p_len = NULL;          p_len = NULL;
         p_char = NULL;          p_char = NULL;
         set_hunkmax();          set_hunkmax();
         if (p_line == NULL || p_len == NULL || p_char == NULL) {          if (p_line == NULL || p_len == NULL || p_char == NULL) {
                 if (p_line == NULL)  
                         free(p_line);                  free(p_line);
                 p_line = tp_line;                  p_line = tp_line;
                 if (p_len == NULL)                  free(p_len);
                         free(p_len);  
                 p_len = tp_len;                  p_len = tp_len;
                 if (p_char == NULL)                  free(p_char);
                         free(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;          i = p_ptrn_lines + 1;
         if (tp_char[i] == '\n') {       /* account for possible blank line */          if (tp_char[i] == '\n') {       /* account for possible blank line */
                 blankline = TRUE;                  blankline = true;
                 i++;                  i++;
         }          }
         if (p_efake >= 0) {             /* fix non-freeable ptr range */          if (p_efake >= 0) {     /* fix non-freeable ptr range */
                 if (p_efake <= i)                  if (p_efake <= i)
                         n = p_end - i + 1;                          n = p_end - i + 1;
                 else                  else
Line 1174  pch_swap(void)
Line 1236  pch_swap(void)
                 n++;                  n++;
         }          }
         if (p_char[0] != '=')          if (p_char[0] != '=')
                 fatal("malformed patch at line %d: expected `=' found `%c'\n",                  fatal("Malformed patch at line %ld: expected '=' found '%c'\n",
                     p_input_line, p_char[0]);                      p_input_line, p_char[0]);
         p_char[0] = '*';          p_char[0] = '*';
         for (s = p_line[0]; *s; s++)          for (s = p_line[0]; *s; s++)
Line 1183  pch_swap(void)
Line 1245  pch_swap(void)
   
         /* now turn the old into the new */          /* now turn the old into the new */
   
         if (tp_char[0] != '*')          if (p_char[0] != '*')
                 fatal("malformed patch at line %d: expected `*' found `%c'\n",                  fatal("Malformed patch at line %ld: expected '*' found '%c'\n",
                     p_input_line, tp_char[0]);                      p_input_line, p_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 == '*')
Line 1197  pch_swap(void)
Line 1259  pch_swap(void)
                         p_char[n] = '+';                          p_char[n] = '+';
                 p_len[n] = tp_len[i];                  p_len[n] = tp_len[i];
         }          }
   
         if (i != p_ptrn_lines + 1)          if (i != p_ptrn_lines + 1)
                 fatal("malformed patch at line %d: need %d lines, got %d\n",                  fatal("Malformed patch at line %ld: expected %ld lines, "
                       "got %ld\n",
                     p_input_line, p_ptrn_lines + 1, i);                      p_input_line, p_ptrn_lines + 1, i);
   
         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;
         if (tp_line == NULL)  
                 free(tp_line);          free(tp_line);
         if (tp_len == NULL)          free(tp_len);
                 free(tp_len);          free(tp_char);
         if (tp_char == NULL)  
                 free(tp_char);          return true;
         return TRUE;  
 }  }
   
 /*  /*
Line 1269  pch_context(void)
Line 1333  pch_context(void)
 /*  /*
  * Return the length of a particular patch line.   * Return the length of a particular patch line.
  */   */
 size_t  short
 pch_line_len(LINENUM line)  pch_line_len(LINENUM line)
 {  {
         return p_len[line];          return p_len[line];
Line 1308  pch_hunk_beg(void)
Line 1372  pch_hunk_beg(void)
 void  void
 do_ed_script(void)  do_ed_script(void)
 {  {
         char *t;          char    *t;
         long beginning_of_this_line;          long    beginning_of_this_line;
         bool this_line_is_command = FALSE;          FILE    *pipefp = NULL;
         FILE *pipefp = NULL;  
   
         if (!skip_rest_of_patch) {          if (!skip_rest_of_patch) {
                 Unlink(TMPOUTNAME);                  if (copy_file(filearg[0], TMPOUTNAME) < 0) {
                 copy_file(filearg[0], TMPOUTNAME);                          unlink(TMPOUTNAME);
                 if (verbose)                          fatal("can't create temp file %s", TMPOUTNAME);
                         snprintf(buf, sizeof(buf), "/bin/ed %s", TMPOUTNAME);                  }
                 else                  snprintf(buf, buf_len, "%s%s%s", _PATH_ED,
                         snprintf(buf, sizeof(buf), "/bin/ed - %s", TMPOUTNAME);                      verbose ? " " : " -s ", TMPOUTNAME);
                 pipefp = popen(buf, "w");                  pipefp = popen(buf, "w");
         }          }
         for (;;) {          for (;;) {
                 beginning_of_this_line = ftell(pfp);                  beginning_of_this_line = ftell(pfp);
                 if (pgets(buf, sizeof buf, pfp) == NULL) {                  if (pgets(buf, buf_len, pfp) == NULL) {
                         next_intuit_at(beginning_of_this_line, p_input_line);                          next_intuit_at(beginning_of_this_line, p_input_line);
                         break;                          break;
                 }                  }
                 p_input_line++;                  p_input_line++;
                 for (t = buf; isdigit((unsigned char)*t) || *t == ','; t++)                  for (t = buf; isdigit((unsigned char)*t) || *t == ','; t++)
                         ;                          ;
                 this_line_is_command = (isdigit((unsigned char)*buf) &&                  /* POSIX defines allowed commands as {a,c,d,i,s} */
                                         (*t == 'd' || *t == 'c' || *t == 'a'));                  if (isdigit((unsigned char)*buf) && (*t == 'a' || *t == 'c' ||
                 if (this_line_is_command) {                      *t == 'd' || *t == 'i' || *t == 's')) {
                         if (!skip_rest_of_patch)                          if (pipefp != NULL)
                                 fputs(buf, pipefp);                                  fputs(buf, pipefp);
                         if (*t != 'd') {                          if (*t != 'd') {
                                 while (pgets(buf, sizeof buf, pfp) != NULL) {                                  while (pgets(buf, buf_len, pfp) != NULL) {
                                         p_input_line++;                                          p_input_line++;
                                         if (!skip_rest_of_patch)                                          if (pipefp != NULL)
                                                 fputs(buf, pipefp);                                                  fputs(buf, pipefp);
                                         if (strEQ(buf, ".\n"))                                          if (strEQ(buf, ".\n"))
                                                 break;                                                  break;
                                 }                                  }
                         }                          }
                 } else {                  } else {
                         next_intuit_at(beginning_of_this_line,p_input_line);                          next_intuit_at(beginning_of_this_line, p_input_line);
                         break;                          break;
                 }                  }
         }          }
         if (skip_rest_of_patch)          if (pipefp == NULL)
                 return;                  return;
         fprintf(pipefp, "w\n");          fprintf(pipefp, "w\n");
         fprintf(pipefp, "q\n");          fprintf(pipefp, "q\n");
         Fflush(pipefp);          fflush(pipefp);
         Pclose(pipefp);          pclose(pipefp);
         ignore_signals();          ignore_signals();
         if (move_file(TMPOUTNAME, outname) < 0) {          if (!check_only) {
                 toutkeep = TRUE;                  if (move_file(TMPOUTNAME, outname) < 0) {
                 chmod(TMPOUTNAME, filemode);                          toutkeep = true;
         } else                          chmod(TMPOUTNAME, filemode);
                 chmod(outname, filemode);                  } else
                           chmod(outname, filemode);
           }
         set_signals(1);          set_signals(1);
 }  }
   
   /*
    * Choose the name of the file to be patched based on POSIX rules.
    * NOTE: the POSIX rules are amazingly stupid and we only follow them
    *       if the user specified --posix or set POSIXLY_CORRECT.
    */
   static char *
   posix_name(const struct file_name *names, bool assume_exists)
   {
           char *path = NULL;
           int i;
   
           /*
            * POSIX states that the filename will be chosen from one
            * of the old, new and index names (in that order) if
            * the file exists relative to CWD after -p stripping.
            */
           for (i = 0; i < MAX_FILE; i++) {
                   if (names[i].path != NULL && names[i].exists) {
                           path = names[i].path;
                           break;
                   }
           }
           if (path == NULL && !assume_exists) {
                   /*
                    * No files found, look for something we can checkout from
                    * RCS/SCCS dirs.  Same order as above.
                    */
                   for (i = 0; i < MAX_FILE; i++) {
                           if (names[i].path != NULL &&
                               (path = checked_in(names[i].path)) != NULL)
                                   break;
                   }
                   /*
                    * Still no match?  Check to see if the diff could be creating
                    * a new file.
                    */
                   if (path == NULL && ok_to_create_file &&
                       names[NEW_FILE].path != NULL)
                           path = names[NEW_FILE].path;
           }
   
           return path ? savestr(path) : NULL;
   }
   
   /*
    * Choose the name of the file to be patched based the "best" one
    * available.
    */
   static char *
   best_name(const struct file_name *names, bool assume_exists)
   {
           size_t min_components, min_baselen, min_len, tmp;
           char *best = NULL;
           int i;
   
           /*
            * The "best" name is the one with the fewest number of path
            * components, the shortest basename length, and the shortest
            * overall length (in that order).  We only use the Index: file
            * if neither of the old or new files could be intuited from
            * the diff header.
            */
           min_components = min_baselen = min_len = SIZE_MAX;
           for (i = INDEX_FILE; i >= OLD_FILE; i--) {
                   if (names[i].path == NULL ||
                       (!names[i].exists && !assume_exists))
                           continue;
                   if ((tmp = num_components(names[i].path)) > min_components)
                           continue;
                   min_components = tmp;
                   if ((tmp = strlen(basename(names[i].path))) > min_baselen)
                           continue;
                   min_baselen = tmp;
                   if ((tmp = strlen(names[i].path)) > min_len)
                           continue;
                   min_len = tmp;
                   best = names[i].path;
           }
           if (best == NULL) {
                   /*
                    * No files found, look for something we can checkout from
                    * RCS/SCCS dirs.  Logic is identical to that above...
                    */
                   min_components = min_baselen = min_len = SIZE_MAX;
                   for (i = INDEX_FILE; i >= OLD_FILE; i--) {
                           if (names[i].path == NULL ||
                               checked_in(names[i].path) == NULL)
                                   continue;
                           if ((tmp = num_components(names[i].path)) > min_components)
                                   continue;
                           min_components = tmp;
                           if ((tmp = strlen(basename(names[i].path))) > min_baselen)
                                   continue;
                           min_baselen = tmp;
                           if ((tmp = strlen(names[i].path)) > min_len)
                                   continue;
                           min_len = tmp;
                           best = names[i].path;
                   }
                   /*
                    * Still no match?  Check to see if the diff could be creating
                    * a new file.
                    */
                   if (best == NULL && ok_to_create_file &&
                       names[NEW_FILE].path != NULL)
                           best = names[NEW_FILE].path;
           }
   
           return best ? savestr(best) : NULL;
   }
   
   static size_t
   num_components(const char *path)
   {
           size_t n;
           const char *cp;
   
           for (n = 0, cp = path; (cp = strchr(cp, '/')) != NULL; n++, cp++) {
                   while (*cp == '/')
                           cp++;           /* skip consecutive slashes */
           }
           return n;
   }

Legend:
Removed from v.1.22  
changed lines
  Added in v.1.23

CVSweb <webmaster@jp.NetBSD.org>