If there is any interest in creeping featurism, this patch adds file completion special character quoting to csh (like bash and tcsh but without the overhead of either program).

Brad

Index: bin/csh/file.c
===================================================================
RCS file: /cvs/src/bin/csh/file.c,v
retrieving revision 1.16
diff -u bin/csh/file.c
--- bin/csh/file.c      27 Oct 2009 23:59:21 -0000      1.16
+++ bin/csh/file.c      17 Feb 2012 17:35:12 -0000
@@ -75,6 +75,7 @@
 static void     pushback(Char *);
 static void     catn(Char *, Char *, int);
 static void     copyn(Char *, Char *, int);
+static void     copynex(Char *, Char *, int);
 static Char     filetype(Char *, Char *);
 static void     print_by_column(Char *, Char *[], int);
 static Char    *tilde(Char *, Char *);
@@ -97,6 +98,9 @@
  */
 bool    filec = 0;

+static Char delims[] = {' ', '\'', '"', '\t', ';', '&', '<',
+       '>', '(', ')', '|', '^', '%', '\0'};
+
 static void
 setup_tty(int on)
 {
@@ -171,32 +175,56 @@
 /*
  * Concatenate src onto tail of des.
  * Des is a string whose maximum length is count.
- * Always null terminate.
+ * Always null terminate.  Add '\' quotes
  */
 static void
 catn(Char *des, Char *src, int count)
 {
     while (--count >= 0 && *des)
        des++;
-    while (--count >= 0)
+    while (--count >= 0) {
+       if (*src && Strchr(delims, *src))
+           *des++ = '\\';
        if ((*des++ = *src++) == 0)
            return;
+    }
     *des = '\0';
 }

 /*
  * Like strncpy but always leave room for trailing \0
- * and always null terminate.
+ * and always null terminate.  Add '\' quotes
  */
 static void
 copyn(Char *des, Char *src, int count)
 {
-    while (--count >= 0)
+    while (--count >= 0) {
+       if (*src && Strchr(delims, *src))
+           *des++ = '\\';
        if ((*des++ = *src++) == 0)
            return;
+    }
     *des = '\0';
 }


+/*
+ * Like strncpy but always leave room for trailing \0
+ * and always null terminate.  Remove '\' quotes
+ */
+static void
+copynex(Char *des, Char *src, int count)
+{
+    while (--count >= 0) {
+       if (*src == '\\') {
+           src++;
+           count--;
+       }
+       if ((*des++ = *src++) == 0)
+           return;
+    }
+    *des = '\0';
+}
+
 static  Char
 filetype(Char *dir, Char *file)
 {
@@ -208,7 +236,7 @@
     if (lstat(short2str(path), &statb) == 0) {
        switch (statb.st_mode & S_IFMT) {
        case S_IFDIR:
-           return ('/');
+           return (' ');

        case S_IFLNK:
            if (stat(short2str(path), &statb) == 0 &&   /* follow it out */
@@ -363,12 +391,12 @@

     p = Strrchr(path, '/');
     if (p == NULL) {
-       copyn(name, path, MAXNAMLEN);
+       copynex(name, path, MAXNAMLEN);
        dir[0] = '\0';
     }
     else {
-       copyn(name, ++p, MAXNAMLEN);
-       copyn(dir, path, p - path);
+       copynex(name, ++p, MAXNAMLEN);
+       copynex(dir, path, p - path);
     }
 }

@@ -383,8 +411,13 @@
            return (NULL);
        return (str2short(pw->pw_name));
     }
-    if ((dirp = readdir(dir_fd)) != NULL)
+    if ((dirp = readdir(dir_fd)) != NULL) {
+       if (dirp->d_type == DT_DIR) {
+           dirp->d_name[dirp->d_namlen] = '/';
+           dirp->d_name[dirp->d_namlen+1] = '\0';
+       }
        return (str2short(dirp->d_name));
+    }
     return (NULL);
 }

@@ -458,7 +491,7 @@
            }
items[numitems] = (Char *) xmalloc((size_t) (Strlen(entry) + 1) *
                                               sizeof(Char));
-           copyn(items[numitems], entry, MAXNAMLEN);
+           copynex(items[numitems], entry, MAXNAMLEN);
            numitems++;
        }
        else {                  /* RECOGNIZE command */
@@ -518,14 +551,19 @@
 recognize(Char *extended_name, Char *entry, int name_length, int numitems)
 {
     if (numitems == 1)         /* 1st match */
-       copyn(extended_name, entry, MAXNAMLEN);
+       copynex(extended_name, entry, MAXNAMLEN);
     else {                     /* 2nd & subsequent matches */
        Char *x, *ent;
        int len = 0;

        x = extended_name;
-       for (ent = entry; *x && *x == *ent++; x++, len++)
-           continue;
+       for (ent = entry; *x; x++, len++) {
+               // Skip over '\' quotes
+               if (*x == '\\')
+                   x++;
+               if (*x != *entry++)
+                   break;
+       }
        *x = '\0';              /* Shorten at 1st Char diff */
        if (len == name_length) /* Ambiguous to prefix? */
            return (-1);        /* So stop now and save time */
@@ -579,8 +617,6 @@

     while ((num_read = read(SHIN, tinputline, BUFSIZ)) > 0) {
        int     i;
-       static Char delims[] = {' ', '\'', '"', '\t', ';', '&', '<',
-       '>', '(', ')', '|', '^', '%', '\0'};
        Char *str_end, *word_start, last_Char, should_retype;
        int space_left;
        COMMAND command;
@@ -602,9 +638,15 @@
* Find LAST occurrence of a delimiter in the inputline. The word start
         * is one Character past it.
         */
-       for (word_start = str_end; word_start > inputline; --word_start)
-           if (Strchr(delims, word_start[-1]))
-               break;
+       for (word_start = str_end; word_start > inputline; --word_start) {
+           if (Strchr(delims, word_start[-1])) {
+               // Skip over quoted deliminters....
+               if (word_start > inputline+1 && word_start[-2] == '\\') {
+                   word_start--;
+               } else
+                   break;
+           }
+       }
        space_left = inputline_size - (word_start - inputline) - 1;
        numitems = tsearch(word_start, command, space_left);

Reply via email to