X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=fish%2Fdestpaths.c;h=5ed93ec78f2eafebdc86b45df7146633dc064f2c;hb=123610f1b5133a9e541a245467f60d065ea96575;hp=f4f131881ee2d8aa6d9d7e30ded33cfb7b0f779d;hpb=2f1a50d81671810256dce0852e6b1e0810ac44af;p=libguestfs.git diff --git a/fish/destpaths.c b/fish/destpaths.c index f4f1318..5ed93ec 100644 --- a/fish/destpaths.c +++ b/fish/destpaths.c @@ -18,8 +18,6 @@ #include -#define _GNU_SOURCE // for strndup, asprintf - #include #include #include @@ -33,6 +31,7 @@ #include "fish.h" +#ifdef HAVE_LIBREADLINE // From gnulib's xalloc.h: /* Return 1 if an array of N objects, each of size S, cannot exist due to size arithmetic overflow. S must be positive and N must be @@ -48,6 +47,7 @@ branch when S is known to be 1. */ # define xalloc_oversized(n, s) \ ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n)) +#endif /* Readline completion for paths on the guest filesystem, also for * devices and LVM names. @@ -60,8 +60,9 @@ struct word { int is_dir; }; +#ifdef HAVE_LIBREADLINE static void -free_words (struct word *words, int nr_words) +free_words (struct word *words, size_t nr_words) { size_t i; @@ -71,6 +72,15 @@ free_words (struct word *words, int nr_words) free (words); } +static int +compare_words (const void *vp1, const void *vp2) +{ + const struct word *w1 = (const struct word *) vp1; + const struct word *w2 = (const struct word *) vp2; + return strcmp (w1->name, w2->name); +} +#endif + char * complete_dest_paths_generator (const char *text, int state) { @@ -113,7 +123,7 @@ complete_dest_paths_generator (const char *text, int state) size_t i; \ size_t n = count_strings (strs); \ \ - if ( ! xalloc_oversized (nr_words + n, sizeof (struct word))) { \ + if ( n > 0 && ! xalloc_oversized (nr_words + n, sizeof (struct word))) { \ struct word *w; \ w = realloc (words, sizeof (struct word) * (nr_words + n)); \ \ @@ -129,13 +139,13 @@ complete_dest_paths_generator (const char *text, int state) nr_words++; \ } \ } \ - free (strs); \ } \ + free (strs); \ } \ } while (0) /* Is it a device? */ - if (len < 5 || strncmp (text, "/dev/", 5) == 0) { + if (len < 5 || STREQLEN (text, "/dev/", 5)) { /* Get a list of everything that can possibly begin with /dev/ */ strs = guestfs_list_devices (g); APPEND_STRS_AND_FREE; @@ -168,9 +178,9 @@ complete_dest_paths_generator (const char *text, int state) for (i = 0; i < dirents->len; ++i) { int err; - if (strcmp (dirents->val[i].name, ".") != 0 && - strcmp (dirents->val[i].name, "..") != 0) { - if (strcmp (dir, "/") == 0) + if (STRNEQ (dirents->val[i].name, ".") && + STRNEQ (dirents->val[i].name, "..")) { + if (STREQ (dir, "/")) err = asprintf (&p, "/%s", dirents->val[i].name); else err = asprintf (&p, "%s/%s", dir, dirents->val[i].name); @@ -210,6 +220,9 @@ complete_dest_paths_generator (const char *text, int state) /* This inhibits ordinary (local filename) completion. */ rl_attempted_completion_over = 1; + /* Sort the words so the list is stable over multiple calls. */ + qsort (words, nr_words, sizeof (struct word), compare_words); + /* Complete the string. */ while (index < nr_words) { struct word *word; @@ -217,7 +230,20 @@ complete_dest_paths_generator (const char *text, int state) word = &words[index]; index++; - if (strncasecmp (word->name, text, len) == 0) { + /* Whether we should match case insensitively here or not is + * determined by the value of the completion-ignore-case readline + * variable. Default to case insensitive. (See: RHBZ#582993). + */ + char *cic_var = rl_variable_value ("completion-ignore-case"); + int cic = 1; + if (cic_var && STREQ (cic_var, "off")) + cic = 0; + + int matches = + cic ? STRCASEEQLEN (word->name, text, len) + : STREQLEN (word->name, text, len); + + if (matches) { if (word->is_dir) rl_completion_append_character = '/';