Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: PATCH: Modifiers that implement realpath-like feature



Sorry, here.



----- Original Message ----
From: Peter Stephenson <p.w.stephenson@xxxxxxxxxxxx>
To: Michael Hwang <nomex45@xxxxxxxxx>
Cc: zsh-workers@xxxxxxxxxx
Sent: Saturday, March 14, 2009 2:14:58 PM
Subject: Re: PATCH: Modifiers that implement realpath-like feature

On Thu, 12 Mar 2009 15:42:25 -0700 (PDT)
Michael Hwang <nomex45@xxxxxxxxx> wrote:
> I'm particularly proud of this patch, as it's my first time
> contributing to an open source project. (I'm sure the novelty will wear
> off in a while.) It implements two history-style realpath-like modifiers
> for getting the absolute path of a file. I chose the letter 'a' for
> 'absolute' (r was already taken). Both 'a' and 'A' have different
> meanings. The uppercase A will resolve symbolic links. 

This looks useful but your mailer's screwed it up.  Could you send it as
an attachment?

Thanks

-- 
Peter Stephenson <p.w.stephenson@xxxxxxxxxxxx>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/



      
diff --git a/Src/hist.c b/Src/hist.c
index 38ceac3..0dd8c21 100644
--- a/Src/hist.c
+++ b/Src/hist.c
@@ -623,6 +623,21 @@ histsubchar(int c)
 	    case 'p':
 		histdone = HISTFLAG_DONE | HISTFLAG_NOEXEC;
 		break;
+	    case 'a':
+		if (!chabspath(&sline)) {
+		    herrflush();
+		    zerr("modifier failed: a");
+		    return -1;
+		}
+		break;
+
+	    case 'A':
+		if (!chrealpath(&sline)) {
+		    herrflush();
+		    zerr("modifier failed: A");
+		    return -1;
+		}
+		break;
 	    case 'h':
 		if (!remtpath(&sline)) {
 		    herrflush();
@@ -1484,6 +1499,119 @@ hcomsearch(char *str)
 
 /**/
 int
+chabspath(char **junkptr)
+{
+    if (!**junkptr)
+	return 1;
+
+    if (**junkptr != '/') {
+	*junkptr = zhtricat(zgetcwd(), "/", *junkptr);
+    }
+
+    char *current = *junkptr;
+    char *dest = *junkptr;
+
+#ifdef HAVE_SUPERROOT
+    while (*current == '/' && current[1] == '.' && current[2] == '.' && (!current[3] || current[3] == '/')) {
+	*dest++ = '/';
+	*dest++ = '.';
+	*dest++ = '.';
+	current += 3;
+    }
+#endif
+	
+    for (;;) {
+	if (*current == '/') {
+#ifdef __CYGWIN__
+	    if (current == *junkptr && current[1] == '/')
+		*dest++ = *current++;
+#endif
+	    *dest++ = *current++;
+	    while (*current == '/')
+		current++;
+	} else if (!*current) {
+	    while (dest > *junkptr + 1 && dest[-1] == '/')
+		dest--;
+	    *dest = '\0';
+	    break;
+	} else if (current[0] == '.' && current[1] == '.' && (!current[2] || current[2] == '/')) {
+		if (current == *junkptr || dest == *junkptr) {
+		    *dest++ = '.';
+		    *dest++ = '.';
+		    current += 2;
+		} else if (dest > *junkptr + 2 && !strncmp(dest - 3, "../", 3)) {
+		    *dest++ = '.';
+		    *dest++ = '.';
+		    current += 2;
+		} else if (dest > *junkptr + 1) {
+		    *dest = '\0';
+		    for (dest--; dest > *junkptr + 1 && dest[-1] != '/'; dest--);
+		    if (dest[-1] != '/')
+			dest--;
+		    current += 2;
+		} else if (dest == *junkptr + 1) { /* This might break with Cygwin's leading double slashes? */
+		    current += 2;
+		} else {
+		    return 0;
+		}
+	} else if (current[0] == '.' && (current[1] == '/' || !current[1])) {
+	     while (*++current == '/');
+	} else {
+	    while (*current != '/' && *current != '\0')
+		if ((*dest++ = *current++) == Meta)
+		    dest[-1] = *current++ ^ 32;
+	}
+    }
+    return 1;
+}
+
+/**/
+int
+chrealpath(char **junkptr)
+{
+    if (!**junkptr)
+	return 1;
+
+    /* Notice that this means ..'s are applied before symlinks are resolved! */
+    if (!chabspath(junkptr))
+	return 0;
+
+    /* Notice that this means you cannot pass relative paths into this function! */
+    if (**junkptr != '/')
+	return 0;
+
+    char *lastpos = strend(*junkptr);
+    char *nonreal = lastpos + 1;
+    char real[PATH_MAX];
+
+    while (!realpath(*junkptr, real)) {
+	if (errno == EINVAL || errno == ELOOP || errno == ENAMETOOLONG || errno == ENOMEM)
+	    return 0;
+
+	if (nonreal == *junkptr) {
+	    *real = '\0';
+	    break;
+	}
+
+	while (*nonreal != '/' && nonreal >= *junkptr)
+	    nonreal--;
+	*nonreal = '\0';
+    }
+
+    char *str = nonreal;
+    while (str <= lastpos) {
+	if (*str == '\0')
+	    *str = '/';
+	str++;
+    }
+
+    *junkptr = bicat(real, nonreal);
+
+    return 1;
+}
+
+/**/
+int
 remtpath(char **junkptr)
 {
     char *str = strend(*junkptr);
diff --git a/Src/subst.c b/Src/subst.c
index 9e3f06f..5033dd4 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -3199,6 +3199,8 @@ modify(char **str, char **ptr)
 
 	for (; !c && **ptr;) {
 	    switch (**ptr) {
+            case 'a':
+            case 'A':
 	    case 'h':
 	    case 'r':
 	    case 'e':
@@ -3337,6 +3339,12 @@ modify(char **str, char **ptr)
 			copy = dupstring(tt);
 		    *e = tc;
 		    switch (c) {
+                    case 'a':
+			chabspath(&copy);
+			break;
+		    case 'A':
+			chrealpath(&copy);
+			break;
 		    case 'h':
 			remtpath(&copy);
 			break;
@@ -3396,6 +3404,12 @@ modify(char **str, char **ptr)
 
 	    } else {
 		switch (c) {
+		case 'a':
+		    chabspath(str);
+		    break;
+		case 'A':
+		    chrealpath(str);
+		    break;
 		case 'h':
 		    remtpath(str);
 		    break;


Messages sorted by: Reverse Date, Date, Thread, Author