summaryrefslogtreecommitdiff
path: root/Src/hist.c
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2009-03-15 01:17:05 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2009-03-15 01:17:05 +0000
commit7733ade831f01a00b93e88312c433dbc3d2cdaa2 (patch)
treef2ac483c0c9ec21c8460dc459b21da82816b2a47 /Src/hist.c
parentbf25c3a43f79f568b55c45e2701f5c961977b47c (diff)
downloadzsh-7733ade831f01a00b93e88312c433dbc3d2cdaa2.tar.gz
zsh-7733ade831f01a00b93e88312c433dbc3d2cdaa2.zip
Michael Hwang: 26731 with cosmetic changes: add "a" and "A" modifiers
26736: document the above
Diffstat (limited to 'Src/hist.c')
-rw-r--r--Src/hist.c141
1 files changed, 141 insertions, 0 deletions
diff --git a/Src/hist.c b/Src/hist.c
index 637976de7..c8625c7af 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,132 @@ hcomsearch(char *str)
/**/
int
+chabspath(char **junkptr)
+{
+ char *current, *dest;
+
+ if (!**junkptr)
+ return 1;
+
+ if (**junkptr != '/') {
+ *junkptr = zhtricat(zgetcwd(), "/", *junkptr);
+ }
+
+ current = *junkptr;
+ 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)
+{
+ char *lastpos, *nonreal, real[PATH_MAX];
+
+ 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;
+
+ lastpos = strend(*junkptr);
+ nonreal = lastpos + 1;
+
+ 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);