diff options
author | Richard Jones <rjones@trick.home.annexia.org> | 2009-06-18 21:06:22 +0100 |
---|---|---|
committer | Richard Jones <rjones@trick.home.annexia.org> | 2009-06-18 21:06:22 +0100 |
commit | e395d7db8fd3fe3d1b121258fe2f401d6b3e64c8 (patch) | |
tree | e825bef2cf986c4d3cc3db34fcb19ee85cb27979 /fish/destpaths.c | |
parent | ace1f0ee2b0a2534e45f14599e38d2d06a03d4d4 (diff) | |
download | libguestfs-e395d7db8fd3fe3d1b121258fe2f401d6b3e64c8.tar.gz libguestfs-e395d7db8fd3fe3d1b121258fe2f401d6b3e64c8.tar.xz libguestfs-e395d7db8fd3fe3d1b121258fe2f401d6b3e64c8.zip |
Add tab-completion of guest filenames (currently disabled).
Diffstat (limited to 'fish/destpaths.c')
-rw-r--r-- | fish/destpaths.c | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/fish/destpaths.c b/fish/destpaths.c new file mode 100644 index 00000000..6cddafa2 --- /dev/null +++ b/fish/destpaths.c @@ -0,0 +1,173 @@ +/* guestfish - the filesystem interactive shell + * Copyright (C) 2009 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <config.h> + +#define _GNU_SOURCE // for strndup, asprintf + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef HAVE_LIBREADLINE +#include <readline/readline.h> +#endif + +#include <guestfs.h> + +#include "fish.h" + +/* Readline completion for paths on the guest filesystem, also for + * devices and LVM names. + */ + +int complete_dest_paths = 0; /* SEE NOTE */ + +/* NOTE: This is currently disabled by default (with no way to + * enable it). That's because it's not particularly natural. + * + * Also there is a quite serious performance problem. When listing + * even moderately long directories, this takes many seconds. The + * reason is because it calls guestfs_is_dir on each directory + * entry, thus lots of round trips to the server. We could have + * a "readdir and stat each entry" call to ease this. + */ + +char * +complete_dest_paths_generator (const char *text, int state) +{ +#ifdef HAVE_LIBREADLINE + + static int len, index; + static char **words = NULL; + static int nr_words = 0; + char *word; + guestfs_error_handler_cb old_error_cb; + void *old_error_cb_data; + + /* Temporarily replace the error handler so that messages don't + * get printed to stderr while we are issuing commands. + */ +#define SAVE_ERROR_CB \ + old_error_cb = guestfs_get_error_handler (g, &old_error_cb_data); \ + guestfs_set_error_handler (g, NULL, NULL); + + /* Restore error handler. */ +#define RESTORE_ERROR_CB \ + guestfs_set_error_handler (g, old_error_cb, old_error_cb_data); + + if (!state) { + char **strs; + int i, n; + + len = strlen (text); + index = 0; + + if (words) { + /* NB. 'words' array is NOT NULL-terminated. */ + for (i = 0; i < nr_words; ++i) + free (words[i]); + free (words); + } + + words = NULL; + nr_words = 0; + + SAVE_ERROR_CB + +#define APPEND_STRS_AND_FREE \ + if (strs) { \ + n = count_strings (strs); \ + words = realloc (words, sizeof (char *) * (nr_words + n)); \ + for (i = 0; i < n; ++i) \ + words[nr_words++] = strs[i]; \ + free (strs); \ + } + + /* Is it a device? */ + if (len < 5 || strncmp (text, "/dev/", 5) == 0) { + /* Get a list of everything that can possibly begin with /dev/ */ + strs = guestfs_list_devices (g); + APPEND_STRS_AND_FREE + + strs = guestfs_list_partitions (g); + APPEND_STRS_AND_FREE + + strs = guestfs_lvs (g); + APPEND_STRS_AND_FREE + } + + if (len < 1 || text[0] == '/') { + /* If we've got a partial path already, we need to list everything + * in that directory, otherwise list everything in / + */ + char *p, *dir; + + p = strrchr (text, '/'); + dir = p && p > text ? strndup (text, p - text) : strdup ("/"); + + strs = guestfs_ls (g, dir); + + /* Prepend directory to names. */ + if (strs) { + for (i = 0; strs[i]; ++i) { + p = NULL; + if (strcmp (dir, "/") == 0) + asprintf (&p, "/%s", strs[i]); + else + asprintf (&p, "%s/%s", dir, strs[i]); + free (strs[i]); + strs[i] = p; + } + } + + free (dir); + APPEND_STRS_AND_FREE + } + + /* else ... In theory we could complete other things here such as VG + * names. At the moment we don't do that. + */ + + RESTORE_ERROR_CB + } + + /* This inhibits ordinary (local filename) completion. */ + rl_attempted_completion_over = 1; + + /* Complete the string. */ + while (index < nr_words) { + word = words[index]; + index++; + if (strncasecmp (word, text, len) == 0) { + /* Is it a directory? */ + if (strncmp (word, "/dev/", 5) != 0) { + SAVE_ERROR_CB + if (guestfs_is_dir (g, word) > 0) + rl_completion_append_character = '/'; + RESTORE_ERROR_CB + } + + return strdup (word); + } + } + +#endif /* HAVE_LIBREADLINE */ + + return NULL; +} |