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);