Subject: bin/34938: --directory argument to patch does not work
To: None <gnats-admin@netbsd.org, netbsd-bugs@netbsd.org>
From: None <dieter.NetBSD@pandora.be>
List: netbsd-bugs
Date: 10/29/2006 16:40:00
>Number:         34938
>Category:       bin
>Synopsis:       --directory argument to patch does not work
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    bin-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Oct 29 16:40:00 +0000 2006
>Originator:     dieter roelants
>Release:        NetBSD 4.99.2
>Organization:
>Environment:
System: NetBSD simult.amelgem.be 4.99.2 NetBSD 4.99.2 (SIMULT) #15: Sat Sep 23 22:35:00 CEST 2006 dieter@simult.amelgem.be:/build/obj.i386.current/sys/arch/i386/compile/SIMULT i386
Architecture: i386
Machine: i386
>Description:
	According to the man page, patch has an option --directory
	which should do the same as -d. Only, it doesn't work. This
	has probably been broken since it was added more then 10
	years ago. Now somebody (me) noticed because it is used by
	pkgsrc/devel/meld. Well, that's almost true, because meld
	uses --directory=<dir> (that is '=' instead of ' '), which
	is what gnu patch provides.

	The same applies to some (all?) of the other long-options.

	The attached patch splits long options on '='. I don't
	think it breaks anything. I only changed the explanations
	in the man page for fuzz and directory, because I verified
	these didn't work as documented. Before I continue, I want
	to know what the right way to do so is. I'll query
	tech-userlevel for this.

	PS. I'm not sure I like the patch, perhaps there is a nicer way.

>How-To-Repeat:
	mkdir /tmp/patches
	sed 's,0,1,g' /etc/fstab | diff -u /etc/fstab - > /tmp/patches/1
	mkdir /tmp/apply
	cp /etc/fstab /tmp/apply/
	patch --directory /tmp/apply < /tmp/patches/1
	patch: **** can't cd to unexpected *** at line %d: %s: No such file or directory
>Fix:
Index: patch.1
===================================================================
RCS file: /cvsroot/src/usr.bin/patch/patch.1,v
retrieving revision 1.12
diff -u -r1.12 patch.1
--- patch.1	25 Mar 2005 23:55:02 -0000	1.12
+++ patch.1	29 Oct 2006 15:42:06 -0000
@@ -241,11 +241,10 @@
 .B \-D
 and the argument.
 .TP 5
-.B \-d or \-\-directory
+.B \-d\*[Lt]directory\*[Gt] or \-\-directory=\*[Lt]directory\*[Gt]
 causes
 .I patch
-to interpret the next argument as a directory, and cd to it before doing
-anything else.
+to cd to this directory before doing anything else.
 .TP 5
 .B \-E or \-\-remove-empty-files
 causes
@@ -257,7 +256,7 @@
 .I patch
 to interpret the patch file as an ed script.
 .TP 5
-.B \-F\*[Lt]number\*[Gt] or \-\-fuzz \*[Lt]number\*[Gt]
+.B \-F\*[Lt]number\*[Gt] or \-\-fuzz=\*[Lt]number\*[Gt]
 sets the maximum fuzz factor.
 This switch only applies to context diffs, and causes
 .I patch
Index: patch.c
===================================================================
RCS file: /cvsroot/src/usr.bin/patch/patch.c,v
retrieving revision 1.24
diff -u -r1.24 patch.c
--- patch.c	25 Mar 2005 23:55:02 -0000	1.24
+++ patch.c	29 Oct 2006 15:42:06 -0000
@@ -38,6 +38,7 @@
 #include "backupfile.h"
 
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
 /* procedures */
@@ -440,7 +441,7 @@
 static void
 get_some_switches(void)
 {
-    char *s;
+    char *s, *t;
 
     rejname[0] = '\0';
     if (!Argc)
@@ -462,8 +463,16 @@
 	    char opt;
 
 	    if (*(s + 1) == '-') {
-		opt = decode_long_option(s + 2);
-		s = "";
+		t = strtok(s, "=");
+		opt = decode_long_option(t + 2);
+		t = strtok(NULL, "");
+		if (t == NULL)
+		    s = "";
+		else {
+		    t--;
+		    t[0] = opt;
+		    s = t;
+		}
 	    }
 	    else
 		opt = *++s;