summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruen@suse.de>2010-04-29 15:09:36 +0200
committerAndreas Gruenbacher <agruen@suse.de>2010-05-02 11:44:03 +0200
commit5f3b6a06a14899717ecefbbf8f20975fa4875e71 (patch)
treee36daf83a73d1b1163624954d19f901692d2f96f
parentb68294e3e1177bcf98d6d23f90ef3e6b5576af2a (diff)
downloadpatch-5f3b6a06a14899717ecefbbf8f20975fa4875e71.tar.gz
git diffs: Parse copy and rename headers
* src/pch.c (p_copy, p_rename): New variables. (pch_copy, pch_rename): New functions. (intuit_diff_type): Parse the "copy from", "copy to", "rename from", and "rename to" headers. * src/util.c (fetchname): Return the fetched name per reference (after freeing the previous name if any). Also free the previous timestamp string if any.
-rw-r--r--ChangeLog8
-rw-r--r--src/pch.c77
-rw-r--r--src/pch.h2
-rw-r--r--src/util.c23
-rw-r--r--src/util.h2
5 files changed, 86 insertions, 26 deletions
diff --git a/ChangeLog b/ChangeLog
index 9b4f7a9..4e96bc3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
2009-04-29 Andreas Gruenbacher <agruen@suse.de>
+ * src/pch.c (p_copy, p_rename): New variables.
+ (pch_copy, pch_rename): New functions.
+ (intuit_diff_type): Parse the "copy from", "copy to", "rename from",
+ and "rename to" headers.
+ * src/util.c (fetchname): Return the fetched name per reference (after
+ freeing the previous name if any). Also free the previous timestamp
+ string if any.
+
* src/patch.c (main): When a git diff includes a file mode change,
change to the new mode.
* src/util.c (set_file_attributes): Add a mode parameter.
diff --git a/src/pch.c b/src/pch.c
index 1db4d11..5d8a6f5 100644
--- a/src/pch.c
+++ b/src/pch.c
@@ -39,6 +39,8 @@ static int p_says_nonexistent[2]; /* [0] for old file, [1] for new:
2 for nonexistent */
static int p_rfc934_nesting; /* RFC 934 nesting level */
static char *p_name[3]; /* filenames in patch headers */
+bool p_copy[2]; /* Does this patch create a copy? */
+bool p_rename[2]; /* Does this patch rename a file? */
static char *p_timestr[2]; /* timestamps as strings */
static mode_t p_mode[2]; /* file modes */
static off_t p_filesize; /* size of the patch file */
@@ -368,7 +370,11 @@ intuit_diff_type (bool need_header, mode_t *p_file_type)
p_timestr[i] = 0;
}
for (i = OLD; i <= NEW; i++)
- p_mode[i] = 0;
+ {
+ p_mode[i] = 0;
+ p_copy[i] = false;
+ p_rename[i] = false;
+ }
/* Ed and normal format patches don't have filename headers. */
if (diff_type == ED_DIFF || diff_type == NORMAL_DIFF)
@@ -451,24 +457,21 @@ intuit_diff_type (bool need_header, mode_t *p_file_type)
}
if (!stars_last_line && strnEQ(s, "*** ", 4))
{
- free (p_name[OLD]);
- p_name[OLD] = fetchname (s+4, strippath, &p_timestr[OLD],
- &p_timestamp[OLD]);
+ fetchname (s+4, strippath, &p_name[OLD], &p_timestr[OLD],
+ &p_timestamp[OLD]);
need_header = false;
}
else if (strnEQ(s, "+++ ", 4))
{
/* Swap with NEW below. */
- free (p_name[OLD]);
- p_name[OLD] = fetchname (s+4, strippath, &p_timestr[OLD],
- &p_timestamp[OLD]);
+ fetchname (s+4, strippath, &p_name[OLD], &p_timestr[OLD],
+ &p_timestamp[OLD]);
need_header = false;
p_strip_trailing_cr = strip_trailing_cr;
}
else if (strnEQ(s, "Index:", 6))
{
- free (p_name[INDEX]);
- p_name[INDEX] = fetchname (s+6, strippath, (char **) 0, NULL);
+ fetchname (s+6, strippath, &p_name[INDEX], (char **) 0, NULL);
need_header = false;
p_strip_trailing_cr = strip_trailing_cr;
}
@@ -513,11 +516,14 @@ intuit_diff_type (bool need_header, mode_t *p_file_type)
goto scan_exit;
}
- if (! ((free (p_name[OLD]),
- (p_name[OLD] = parse_name (s + 11, strippath, &u)))
+ for (i = OLD; i <= NEW; i++)
+ {
+ free (p_name[i]);
+ p_name[i] = 0;
+ }
+ if (! ((p_name[OLD] = parse_name (s + 11, strippath, &u))
&& ISSPACE (*u)
- && (free (p_name[NEW]),
- (p_name[NEW] = parse_name (u, strippath, &u)))
+ && (p_name[NEW] = parse_name (u, strippath, &u))
&& (u = skip_spaces (u), ! *u)))
for (i = OLD; i <= NEW; i++)
{
@@ -558,6 +564,34 @@ intuit_diff_type (bool need_header, mode_t *p_file_type)
p_says_nonexistent[OLD] = 2;
extended_headers = true;
}
+ else if (git_diff && strnEQ (s, "rename from ", 12))
+ {
+ /* Git leaves out the prefix in the file name in this header,
+ so we can only ignore the file name. */
+ p_rename[OLD] = true;
+ extended_headers = true;
+ }
+ else if (git_diff && strnEQ (s, "rename to ", 10))
+ {
+ /* Git leaves out the prefix in the file name in this header,
+ so we can only ignore the file name. */
+ p_rename[NEW] = true;
+ extended_headers = true;
+ }
+ else if (git_diff && strnEQ (s, "copy from ", 10))
+ {
+ /* Git leaves out the prefix in the file name in this header,
+ so we can only ignore the file name. */
+ p_copy[OLD] = true;
+ extended_headers = true;
+ }
+ else if (git_diff && strnEQ (s, "copy to ", 8))
+ {
+ /* Git leaves out the prefix in the file name in this header,
+ so we can only ignore the file name. */
+ p_copy[NEW] = true;
+ extended_headers = true;
+ }
else if (git_diff && strnEQ (s, "GIT binary patch", 16))
{
p_start = this_line;
@@ -573,9 +607,8 @@ intuit_diff_type (bool need_header, mode_t *p_file_type)
{
struct timespec timestamp;
timestamp.tv_sec = -1;
- free (p_name[NEW]);
- p_name[NEW] = fetchname (t+4, strippath, &p_timestr[NEW],
- &timestamp);
+ fetchname (t+4, strippath, &p_name[NEW], &p_timestr[NEW],
+ &timestamp);
need_header = false;
if (timestamp.tv_sec != -1)
{
@@ -2006,6 +2039,18 @@ pch_name (enum nametype type)
return type == NONE ? NULL : p_name[type];
}
+bool pch_copy (void)
+{
+ return p_copy[OLD] && p_copy[NEW]
+ && p_name[OLD] && p_name[NEW];
+}
+
+bool pch_rename (void)
+{
+ return p_rename[OLD] && p_rename[NEW]
+ && p_name[OLD] && p_name[NEW];
+}
+
/* Return the specified line position in the old file of the old context. */
lin
diff --git a/src/pch.h b/src/pch.h
index 084c918..6c9c899 100644
--- a/src/pch.h
+++ b/src/pch.h
@@ -40,6 +40,8 @@ int another_hunk (enum diff, bool);
int pch_says_nonexistent (bool);
size_t pch_line_len (lin);
const char *pch_name(enum nametype);
+bool pch_copy (void);
+bool pch_rename (void);
void do_ed_script (FILE *);
void open_patch_file (char const *);
void re_patch (void);
diff --git a/src/util.c b/src/util.c
index c21828b..f7819d2 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1316,12 +1316,13 @@ strip_leading_slashes (char *name, int strip_leading)
/* Make filenames more reasonable. */
-char *
-fetchname (char const *at, int strip_leading, char **ptimestr,
+void
+fetchname (char const *at, int strip_leading, char **pname, char **ptimestr,
struct timespec *pstamp)
{
char *name;
const char *t;
+ char *timestr = NULL;
struct timespec stamp;
stamp.tv_sec = -1;
@@ -1338,7 +1339,7 @@ fetchname (char const *at, int strip_leading, char **ptimestr,
{
if (debug & 128)
say ("ignoring malformed filename %s\n", quotearg (at));
- return 0;
+ return;
}
}
else
@@ -1372,19 +1373,18 @@ fetchname (char const *at, int strip_leading, char **ptimestr,
pstamp->tv_sec = 0;
pstamp->tv_nsec = 0;
}
- return 0;
+ return;
}
/* Ignore the name if it doesn't have enough slashes to strip off. */
if (! strip_leading_slashes (name, strip_leading))
{
free (name);
- return 0;
+ return;
}
if (ptimestr)
{
- char *timestr;
char const *u = t + strlen (t);
if (u != t && *(u-1) == '\n')
@@ -1393,7 +1393,6 @@ fetchname (char const *at, int strip_leading, char **ptimestr,
u--;
timestr = savebuf (t, u - t + 1);
timestr[u - t] = 0;
- *ptimestr = timestr;
}
if (*t == '\n')
@@ -1403,7 +1402,7 @@ fetchname (char const *at, int strip_leading, char **ptimestr,
if (! pstamp)
{
free (name);
- return 0;
+ return;
}
if (set_time | set_utc)
@@ -1426,9 +1425,15 @@ fetchname (char const *at, int strip_leading, char **ptimestr,
}
}
+ free (*pname);
+ *pname = name;
+ if (ptimestr)
+ {
+ free (*ptimestr);
+ *ptimestr = timestr;
+ }
if (pstamp)
*pstamp = stamp;
- return name;
}
char *
diff --git a/src/util.h b/src/util.h
index 609aa26..aff9cb5 100644
--- a/src/util.h
+++ b/src/util.h
@@ -38,7 +38,7 @@ void fatal (char const *, ...)
void pfatal (char const *, ...)
__attribute__ ((noreturn, format (printf, 1, 2)));
-char *fetchname (char const *, int, char **, struct timespec *);
+void fetchname (char const *, int, char **, char **, struct timespec *);
char *parse_name (char const *, int, char const **);
char *savebuf (char const *, size_t);
char *savestr (char const *);