From 354834114662d369ce96cac5e787623df1cc68f8 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Thu, 27 Dec 2007 21:36:33 -0600 Subject: [PATCH] Make patch's file add actually work, including directory creating and understanding zero-context hunks. --- lib/lib.c | 27 +++++++++++++++++++++++++++ lib/lib.h | 1 + toys/patch.c | 49 ++++++++++++++++++++++++++++++++----------------- 3 files changed, 60 insertions(+), 17 deletions(-) diff --git a/lib/lib.c b/lib/lib.c index 985c580..6699a68 100644 --- 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. diff --git a/lib/lib.h b/lib/lib.h index 28ff0da..afc3a8b 100644 --- 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); diff --git a/toys/patch.c b/toys/patch.c index b296b1e..a8a2172 100644 --- a/toys/patch.c +++ b/toys/patch.c @@ -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); -- 2.7.4