changeset 216:5697a3f7c8cf

Make patch's file add actually work, including directory creating and understanding zero-context hunks.
author Rob Landley <rob@landley.net>
date Thu, 27 Dec 2007 21:36:33 -0600
parents 34e36dffd47a
children ca48a878255d
files lib/lib.c lib/lib.h toys/patch.c
diffstat 3 files changed, 60 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/lib/lib.c	Mon Dec 24 19:53:20 2007 -0600
+++ b/lib/lib.c	Thu Dec 27 21:36:33 2007 -0600
@@ -322,6 +322,33 @@
 	return path;
 }
 
+// Ensure entire path exists.
+// If mode != -1 set permissions on newly created dirs.
+// Requires that path string be writable (for temporary null terminators).
+void xmkpath(char *path, int mode)
+{
+	char *p, old;
+	mode_t mask;
+	int rc;
+	struct stat st;
+
+	for (p = path; ; p++) {
+		if (!*p || *p == '/') {
+			old = *p;
+			*p = rc = 0;
+			if (stat(path, &st) || !S_ISDIR(st.st_mode)) {
+				if (mode != -1) {
+					mask=umask(0);
+					rc = mkdir(path, mode);
+					umask(mask);
+				} else rc = mkdir(path, 0777);
+			}
+			*p = old;
+			if(rc) perror_exit("mkpath '%s'",path);
+		}
+		if (!*p) break;
+	}
+}
 // Find all file in a colon-separated path with access type "type" (generally
 // X_OK or R_OK).  Returns a list of absolute paths to each file found, in
 // order.
--- a/lib/lib.h	Mon Dec 24 19:53:20 2007 -0600
+++ b/lib/lib.h	Thu Dec 27 21:36:33 2007 -0600
@@ -73,6 +73,7 @@
 char *xgetcwd(void);
 void xstat(char *path, struct stat *st);
 char *xabspath(char *path);
+void xmkpath(char *path, int mode);
 struct string_list *find_in_path(char *path, char *filename);
 void utoa_to_buf(unsigned n, char *buf, unsigned buflen);
 void itoa_to_buf(int n, char *buf, unsigned buflen);
--- a/toys/patch.c	Mon Dec 24 19:53:20 2007 -0600
+++ b/toys/patch.c	Thu Dec 27 21:36:33 2007 -0600
@@ -37,7 +37,8 @@
 	struct double_list *dlist = (struct double_list *)data;
 
 	if (TT.state && *dlist->data != TT.state)
-		fdprintf(TT.fileout, "%s\n", dlist->data+(TT.state>1 ? 1 : 0));
+		fdprintf(TT.state == 2 ? 2: TT.fileout,
+			"%s\n", dlist->data+(TT.state>2 ? 1 : 0));
 	free(dlist->data);
 	free(dlist);
 }
@@ -79,19 +80,22 @@
 		} else i = 0;
 	}
 	if (i < TT.context) goto fail_hunk;
-	llist_free(temp->next, do_line);
-	temp->next = NULL;
+	if (temp) {
+		llist_free(temp->next, do_line);
+		temp->next = NULL;
+	}
 
-	// Search for a place to apply this hunk
+	// Search for a place to apply this hunk.  Match all context lines and
+	// lines to be removed.
 	plist = TT.plines;
 	buf = NULL;
 	i = 0;
-	for (;;) {
+	if (TT.context) for (;;) {
 		char *data = get_line(TT.filein);
 		TT.linenum++;
 
 		// If the file ended before we found a home for this hunk, fail.
-		if (!data) break;
+		if (!data) goto fail_hunk;
 
 		dlist_add(&buf, data);
 		if (!backwards && *plist->data == "+-"[reverse]) {
@@ -110,25 +114,28 @@
 			plist = TT.plines;
 		} else {
 			plist = plist->next;
-			if (!plist) {
-				// Got it.  Emit changed data.
-				TT.state = "-+"[reverse];
-				llist_free(TT.plines, do_line);
-				TT.plines = NULL;
-				buf->prev->next = NULL;
-				TT.state = 0;
-				llist_free(buf, do_line);
-				return;
-			}
+			if (!plist) break;
 		}
 	}
+
+	// Got it.  Emit changed data.
+	TT.state = "-+"[reverse];
+	llist_free(TT.plines, do_line);
+	TT.plines = NULL;
+	TT.state = 0;
+	if (buf) {
+		buf->prev->next = NULL;
+		llist_free(buf, do_line);
+	}
+	return;
+
 fail_hunk:
 	printf("Hunk FAILED.\n");
 
 	// If we got to this point, we've seeked to the end.  Discard changes to
 	// this file and advance to next file.
 
-	TT.state = 0;
+	TT.state = 2;
 	llist_free(TT.plines, do_line);
 	TT.plines = 0;
 	if (buf) {
@@ -137,6 +144,7 @@
 	}
 	delete_tempfile(TT.filein, TT.fileout, &TT.tempname);
 	TT.filein = -1;
+	TT.state = 0;
 }
 
 // state 0: Not in a hunk, look for +++.
@@ -181,6 +189,7 @@
 			// Trim date from end of filename (if any).  We don't care.
 			for (s = patchline+4; *s && *s!='\t'; s++)
 				if (*s=='\\' && s[1]) s++;
+			*s = 0;
 
 			TT.oldname = xstrdup(patchline+4);
 		} else if (!strncmp("+++ ", patchline, 4)) {
@@ -219,6 +228,12 @@
 				// If the old file was null, we're creating a new one.
 				if (!strcmp(TT.oldname, "/dev/null")) {
 					printf("creating %s\n", start);
+					s = strrchr(start, '/');
+					if (s) {
+						*s = 0;
+						xmkpath(start, -1);
+						*s = '/';
+					}
 					TT.filein = xcreate(start, O_CREAT|O_RDWR, 0666);
 				} else {
 					printf("patching %s\n", start);