OSDN Git Service

Make patch's file add actually work, including directory creating and
authorRob Landley <rob@landley.net>
Fri, 28 Dec 2007 03:36:33 +0000 (21:36 -0600)
committerRob Landley <rob@landley.net>
Fri, 28 Dec 2007 03:36:33 +0000 (21:36 -0600)
understanding zero-context hunks.

lib/lib.c
lib/lib.h
toys/patch.c

index 985c580..6699a68 100644 (file)
--- a/lib/lib.c
+++ b/lib/lib.c
@@ -322,6 +322,33 @@ char *xabspath(char *path)
        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.
index 28ff0da..afc3a8b 100644 (file)
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -73,6 +73,7 @@ void xwrite(int fd, void *buf, size_t len);
 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);
index b296b1e..a8a2172 100644 (file)
@@ -37,7 +37,8 @@ static void do_line(void *data)
        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 @@ static void apply_hunk(void)
                } 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 @@ static void apply_hunk(void)
                        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 @@ fail_hunk:
        }
        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 @@ void patch_main(void)
                        // 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 @@ void patch_main(void)
                                // 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);