Merge branch 'mc-4.6'

* mc-4.6: (38 commits)
  mhl: mhl_shell_unescape_buf(): fixed memory array OOB.
  completion: fixed complete already escaped secuences.
  completion: added changelog entry for solved #147
  completion: fixed completion of escaped commands in commandline
  Removed unused char*.
  mhl: added mhl_strmove() function (memmove semantics)
  completion: added escapes in command line on completion
  complete: cleanup: #define to enum INPUT_COMPLETION_FLAGS
  added a new parameter for completion flags to input_new
  fish: cleanup: unboxed quoted strings when generate shell commands
  introduced new type SHELL_ESCAPED_STR for more type safety
  added mhl/types.h which defines bool enum, escape.h now using this type
  Removed unused variable
  Changes for use MHL.
  Fixed bug with renamig/copying files with backshashes in names
  Remove some testing stuff
  Temporarry commit. Fixed completion in browse by directoryes.
  Fixed some memory leaks.
  Add $ and ` for escaping and reorder it according to the ascii values
  Rewrite it to use g_string_append_c instead of some homebrew stuff
  ...
This commit is contained in:
Sergei Trofimovich 2009-02-01 14:26:54 +02:00
commit df4129517b
20 changed files with 387 additions and 204 deletions

View File

@ -1,3 +1,11 @@
2009-01-31 Enrico Weigelt, metux ITS <weigelt@metux.de>, Patrick Winnertz <winnie@debian.org>, Slava Zanko <slavazanko@gmail.com>, Sergei Trofimovich <slyfox@inbox.ru>
* edit/editcmd.c, mhl/escape.h, mhl/string.h, mhl/types.h, src/Makefile.am,
* src/boxes.c, src/command.c, src/complete.c, src/complete.h, src/file.c,
* src/find.c, src/main.c, src/panelize.c, src/util.c, src/utilunix.c,
* src/widget.c, src/widget.h, src/wtools.c, vfs/fish.c:
fixed shell escaping issues in commandline completion engine
2009-01-31 Enrico Weigelt, metux ITS <weigelt@metux.de> 2009-01-31 Enrico Weigelt, metux ITS <weigelt@metux.de>
* replaced buggy concat_dir_and_file() by mhl_str_dir_plus_file() (in mhl/string.h) * replaced buggy concat_dir_and_file() by mhl_str_dir_plus_file() (in mhl/string.h)
@ -17,6 +25,11 @@
This solves "strange" rename cases, when copying/moving is performed into This solves "strange" rename cases, when copying/moving is performed into
deleted directory. deleted directory.
2009-01-27 Enrico Weigelt, metux ITS <weigelt@metux.de>
* mhl/escape.h, src/complete.c, vfs/fish.c: introduced new type
SHELL_ESCAPED_STR for more type safety
2009-01-27 Enrico Weigelt, metux IT service <weigelt@metux.de> 2009-01-27 Enrico Weigelt, metux IT service <weigelt@metux.de>
* mhl/escape.h, mhl/string.h: fixed comments to use /* ... */ * mhl/escape.h, mhl/string.h: fixed comments to use /* ... */

View File

@ -626,7 +626,7 @@ edit_raw_key_query (const char *heading, const char *query, int cancel)
NULL, heading, NULL, heading,
DLG_CENTER | DLG_TRYUP | DLG_WANT_TAB); DLG_CENTER | DLG_TRYUP | DLG_WANT_TAB);
add_widget (raw_dlg, add_widget (raw_dlg,
input_new (3 - cancel, w - 5, INPUT_COLOR, 2, "", 0)); input_new (3 - cancel, w - 5, INPUT_COLOR, 2, "", 0, INPUT_COMPLETE_DEFAULT));
add_widget (raw_dlg, label_new (3 - cancel, 2, query)); add_widget (raw_dlg, label_new (3 - cancel, 2, query));
if (cancel) if (cancel)
add_widget (raw_dlg, add_widget (raw_dlg,

View File

@ -6,6 +6,8 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <mhl/types.h>
#define mhl_shell_escape_toesc(x) \ #define mhl_shell_escape_toesc(x) \
(((x)==' ')||((x)=='!')||((x)=='#')||((x)=='$')||((x)=='%')|| \ (((x)==' ')||((x)=='!')||((x)=='#')||((x)=='$')||((x)=='%')|| \
((x)=='(')||((x)==')')||((x)=='\'')||((x)=='&')||((x)=='~')|| \ ((x)=='(')||((x)==')')||((x)=='\'')||((x)=='&')||((x)=='~')|| \
@ -16,10 +18,21 @@
#define mhl_shell_escape_nottoesc(x) \ #define mhl_shell_escape_nottoesc(x) \
(((x)!=0) && (!mhl_shell_escape_toesc((x)))) (((x)!=0) && (!mhl_shell_escape_toesc((x))))
static inline char* mhl_shell_escape_dup(const char* src) /* type for escaped string - just for a bit more type safety ;-p */
typedef struct { char* s; } SHELL_ESCAPED_STR;
/** To be compatible with the general posix command lines we have to escape
strings for the command line
/params const char * in
string for escaping
/returns
return escaped string (later need to free)
*/
static inline SHELL_ESCAPED_STR mhl_shell_escape_dup(const char* src)
{ {
if ((src==NULL)||(!(*src))) if ((src==NULL)||(!(*src)))
return strdup(""); return (SHELL_ESCAPED_STR){ .s = strdup("") };
char* buffer = calloc(1, strlen(src)*2+2); char* buffer = calloc(1, strlen(src)*2+2);
char* ptr = buffer; char* ptr = buffer;
@ -38,7 +51,7 @@ static inline char* mhl_shell_escape_dup(const char* src)
/* at this point we either have an \0 or an char to escape */ /* at this point we either have an \0 or an char to escape */
if (!c) if (!c)
return buffer; return (SHELL_ESCAPED_STR){ .s = buffer };
*ptr = '\\'; *ptr = '\\';
ptr++; ptr++;
@ -48,7 +61,14 @@ static inline char* mhl_shell_escape_dup(const char* src)
} }
} }
/* shell-unescape within a given buffer (writing to it!) */ /** Unescape paths or other strings for e.g the internal cd
shell-unescape within a given buffer (writing to it!)
/params const char * in
string for unescaping
/returns
return unescaped string
*/
static inline char* mhl_shell_unescape_buf(char* text) static inline char* mhl_shell_unescape_buf(char* text)
{ {
if (!text) if (!text)
@ -93,6 +113,8 @@ static inline char* mhl_shell_unescape_buf(char* text)
case '`': case '`':
case '"': case '"':
case ';': case ';':
case '\0': /* end of line! malformed escape string */
goto out;
default: default:
(*writeptr) = c; writeptr++; break; (*writeptr) = c; writeptr++; break;
} }
@ -104,9 +126,28 @@ static inline char* mhl_shell_unescape_buf(char* text)
} }
readptr++; readptr++;
} }
out:
*writeptr = 0; *writeptr = 0;
return text; return text;
} }
/** Check if char in pointer contain escape'd chars
/params const char * in
string for checking
/returns
return TRUE if string contain escaped chars
otherwise return FALSE
*/
static inline bool
mhl_shell_is_char_escaped ( const char *in )
{
if (in == NULL || !*in || in[0] != '\\')
return false;
if (mhl_shell_escape_toesc(in[1]))
return true;
return false;
}
#endif #endif

View File

@ -3,6 +3,7 @@
#include <ctype.h> #include <ctype.h>
#include <stdarg.h> #include <stdarg.h>
#include <assert.h>
#include <mhl/memory.h> #include <mhl/memory.h>
#define mhl_str_dup(str) ((str ? strdup(str) : strdup(""))) #define mhl_str_dup(str) ((str ? strdup(str) : strdup("")))
@ -121,6 +122,19 @@ static inline char* mhl_str_reverse(char* ptr)
return ptr; return ptr;
} }
/*
* strcpy is unsafe on overlapping memory areas, so define memmove-alike
* string function. Has sense only when dest <= src.
*/
static inline char * mhl_strmove(char * dest, const char * src)
{
size_t n = strlen (src) + 1; /* + '\0' */
assert (dest<=src);
return memmove(dest, src, n);
}
static inline char* mhl_str_dir_plus_file(const char* dirname, const char* filename) static inline char* mhl_str_dir_plus_file(const char* dirname, const char* filename)
{ {
/* make sure we have valid strings */ /* make sure we have valid strings */

16
mhl/types.h Normal file
View File

@ -0,0 +1,16 @@
/*
Micro Helper Library: generic type declarations
*/
#ifndef __MHL_TYPES_H
#define __MHL_TYPES_H
typedef enum
{
false = 0,
true = 1
} bool;
#endif

View File

@ -45,7 +45,7 @@ CHARSET_SRC = charsets.c charsets.h selcodepage.c selcodepage.h
SRCS = achown.c achown.h background.c background.h boxes.c boxes.h \ SRCS = achown.c achown.h background.c background.h boxes.c boxes.h \
chmod.c chmod.h chown.c chown.h cmd.c cmd.h color.c color.h \ chmod.c chmod.h chown.c chown.h cmd.c cmd.h color.c color.h \
command.c command.h complete.c complete.h cons.handler.c \ command.c command.h complete.c cons.handler.c \
cons.saver.h dialog.c dialog.h dir.c dir.h \ cons.saver.h dialog.c dialog.h dir.c dir.h \
eregex.h execute.c execute.h ext.c ext.h file.c filegui.c \ eregex.h execute.c execute.h ext.c ext.h file.c filegui.c \
filegui.h file.h filenot.c fileopctx.c fileopctx.h find.c \ filegui.h file.h filenot.c fileopctx.c fileopctx.h find.c \

View File

@ -197,7 +197,7 @@ display_init (int radio_sel, char *init_text, int _check_status,
status = status =
input_new (10, 9, INPUT_COLOR, DISPLAY_X - 14, _status[radio_sel], input_new (10, 9, INPUT_COLOR, DISPLAY_X - 14, _status[radio_sel],
"mini-input"); "mini-input", INPUT_COMPLETE_DEFAULT);
add_widget (dd, status); add_widget (dd, status);
input_set_point (status, 0); input_set_point (status, 0);
@ -207,7 +207,7 @@ display_init (int radio_sel, char *init_text, int _check_status,
user = user =
input_new (7, 9, INPUT_COLOR, DISPLAY_X - 14, init_text, input_new (7, 9, INPUT_COLOR, DISPLAY_X - 14, init_text,
"user-fmt-input"); "user-fmt-input", INPUT_COMPLETE_DEFAULT);
add_widget (dd, user); add_widget (dd, user);
input_set_point (user, 0); input_set_point (user, 0);
@ -1085,17 +1085,17 @@ vfs_smb_get_authinfo (const char *host, const char *share, const char *domain,
g_free (title); g_free (title);
in_user = input_new (5, istart, INPUT_COLOR, ilen, user, "auth_name"); in_user = input_new (5, istart, INPUT_COLOR, ilen, user, "auth_name", INPUT_COMPLETE_DEFAULT);
add_widget (auth_dlg, in_user); add_widget (auth_dlg, in_user);
in_domain = input_new (3, istart, INPUT_COLOR, ilen, domain, "auth_domain"); in_domain = input_new (3, istart, INPUT_COLOR, ilen, domain, "auth_domain", INPUT_COMPLETE_DEFAULT);
add_widget (auth_dlg, in_domain); add_widget (auth_dlg, in_domain);
add_widget (auth_dlg, button_new (9, b2, B_CANCEL, NORMAL_BUTTON, add_widget (auth_dlg, button_new (9, b2, B_CANCEL, NORMAL_BUTTON,
buts[1], 0)); buts[1], 0));
add_widget (auth_dlg, button_new (9, b0, B_ENTER, DEFPUSH_BUTTON, add_widget (auth_dlg, button_new (9, b0, B_ENTER, DEFPUSH_BUTTON,
buts[0], 0)); buts[0], 0));
in_password = input_new (7, istart, INPUT_COLOR, ilen, "", "auth_password"); in_password = input_new (7, istart, INPUT_COLOR, ilen, "", "auth_password", INPUT_COMPLETE_DEFAULT);
in_password->completion_flags = 0; in_password->completion_flags = 0;
in_password->is_password = 1; in_password->is_password = 1;
add_widget (auth_dlg, in_password); add_widget (auth_dlg, in_password);

View File

@ -27,13 +27,14 @@
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <mhl/memory.h>
#include <mhl/escape.h>
#include <mhl/string.h> #include <mhl/string.h>
#include "global.h" /* home_dir */ #include "global.h" /* home_dir */
#include "tty.h" #include "tty.h"
#include "widget.h" /* WInput */ #include "widget.h" /* WInput */
#include "command.h" #include "command.h"
#include "complete.h" /* completion constants */
#include "wtools.h" /* message () */ #include "wtools.h" /* message () */
#include "panel.h" /* view_tree enum. Also, needed by main.h */ #include "panel.h" /* view_tree enum. Also, needed by main.h */
#include "main.h" /* do_cd */ #include "main.h" /* do_cd */
@ -66,6 +67,7 @@ examine_cd (char *path)
const char *t; const char *t;
/* Tilde expansion */ /* Tilde expansion */
path = mhl_shell_unescape_buf(path);
path_tilde = tilde_expand (path); path_tilde = tilde_expand (path);
/* Leave space for further expansion */ /* Leave space for further expansion */
@ -137,6 +139,7 @@ examine_cd (char *path)
} }
g_free (q); g_free (q);
g_free (path_tilde); g_free (path_tilde);
// mhl_mem_free(path);
return result; return result;
} }
@ -292,7 +295,8 @@ command_new (int y, int x, int cols)
{ {
WInput *cmd; WInput *cmd;
cmd = input_new (y, x, DEFAULT_COLOR, cols, "", "cmdline"); cmd = input_new (y, x, DEFAULT_COLOR, cols, "", "cmdline",
INPUT_COMPLETE_DEFAULT | INPUT_COMPLETE_CD | INPUT_COMPLETE_COMMANDS | INPUT_COMPLETE_SHELL_ESC);
/* Add our hooks */ /* Add our hooks */
cmd->widget.callback = command_callback; cmd->widget.callback = command_callback;

View File

@ -30,6 +30,8 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <mhl/memory.h>
#include <mhl/escape.h>
#include <mhl/string.h> #include <mhl/string.h>
#include "global.h" #include "global.h"
@ -39,21 +41,38 @@
#include "dialog.h" #include "dialog.h"
#include "widget.h" #include "widget.h"
#include "wtools.h" #include "wtools.h"
#include "complete.h"
#include "main.h" #include "main.h"
#include "util.h"
#include "key.h" /* XCTRL and ALT macros */ #include "key.h" /* XCTRL and ALT macros */
typedef char *CompletionFunction (char *, int); typedef char *CompletionFunction (char * text, int state, INPUT_COMPLETE_FLAGS flags);
/* This flag is used in filename_completion_function */ //#define DO_COMPLETION_DEBUG
static int ignore_filenames = 0; #ifdef DO_COMPLETION_DEBUG
/*
* Useful to print/debug completion flags
*/
static const char * show_c_flags(INPUT_COMPLETE_FLAGS flags)
{
static char s_cf[] = "FHCVUDS";
/* This flag is used by command_completion_function */ s_cf[0] = (flags & INPUT_COMPLETE_FILENAMES) ? 'F' : ' ';
/* to hint the filename_completion_function */ s_cf[1] = (flags & INPUT_COMPLETE_HOSTNAMES) ? 'H' : ' ';
static int look_for_executables = 0; s_cf[2] = (flags & INPUT_COMPLETE_COMMANDS) ? 'C' : ' ';
s_cf[3] = (flags & INPUT_COMPLETE_VARIABLES) ? 'V' : ' ';
s_cf[4] = (flags & INPUT_COMPLETE_USERNAMES) ? 'U' : ' ';
s_cf[5] = (flags & INPUT_COMPLETE_CD) ? 'D' : ' ';
s_cf[6] = (flags & INPUT_COMPLETE_SHELL_ESC) ? 'S' : ' ';
return s_cf;
}
#define SHOW_C_CTX(func) fprintf(stderr, "%s: text='%s' flags=%s\n", func, text, show_c_flags(flags))
#else
#define SHOW_C_CTX(func)
#endif /* DO_CMPLETION_DEBUG */
static char * static char *
filename_completion_function (char *text, int state) filename_completion_function (char *text, int state, INPUT_COMPLETE_FLAGS flags)
{ {
static DIR *directory; static DIR *directory;
static char *filename = NULL; static char *filename = NULL;
@ -64,6 +83,11 @@ filename_completion_function (char *text, int state)
struct dirent *entry = NULL; struct dirent *entry = NULL;
SHOW_C_CTX("filename_completion_function");
if (text && (flags & INPUT_COMPLETE_SHELL_ESC))
text = mhl_shell_unescape_buf (text);
/* If we're starting the match process, initialize us a bit. */ /* If we're starting the match process, initialize us a bit. */
if (!state){ if (!state){
const char *temp; const char *temp;
@ -85,6 +109,7 @@ filename_completion_function (char *text, int state)
/* Save the version of the directory that the user typed. */ /* Save the version of the directory that the user typed. */
users_dirname = dirname; users_dirname = dirname;
{ {
// FIXME: memleak ?
dirname = tilde_expand (dirname); dirname = tilde_expand (dirname);
canonicalize_pathname (dirname); canonicalize_pathname (dirname);
/* Here we should do something with variable expansion /* Here we should do something with variable expansion
@ -136,18 +161,15 @@ filename_completion_function (char *text, int state)
} }
g_free (tmp); g_free (tmp);
} }
switch (look_for_executables) if ((flags & INPUT_COMPLETE_COMMANDS)
{ && (isexec || isdir))
case 2: if (!isexec) break;
continue; if ((flags & INPUT_COMPLETE_CD)
break; && isdir)
case 1: if (!isexec && !isdir) break;
continue; if (flags & (INPUT_COMPLETE_FILENAMES))
break; break;
} continue;
if (ignore_filenames && !isdir)
continue;
break;
} }
if (!entry){ if (!entry){
@ -181,18 +203,28 @@ filename_completion_function (char *text, int state)
} }
if (isdir) if (isdir)
strcat (temp, PATH_SEP_STR); strcat (temp, PATH_SEP_STR);
return temp;
if (temp && (flags & INPUT_COMPLETE_SHELL_ESC))
{
SHELL_ESCAPED_STR e_temp = mhl_shell_escape_dup(temp);
mhl_mem_free (temp);
temp = e_temp.s;
}
return temp;
} }
} }
/* We assume here that text[0] == '~' , if you want to call it in another way, /* We assume here that text[0] == '~' , if you want to call it in another way,
you have to change the code */ you have to change the code */
static char * static char *
username_completion_function (char *text, int state) username_completion_function (char *text, int state, INPUT_COMPLETE_FLAGS flags)
{ {
static struct passwd *entry; static struct passwd *entry;
static int userlen; static int userlen;
SHOW_C_CTX("username_completion_function");
if (text[0] == '\\' && text[1] == '~') text++;
if (!state){ /* Initialization stuff */ if (!state){ /* Initialization stuff */
setpwent (); setpwent ();
userlen = strlen (text + 1); userlen = strlen (text + 1);
@ -227,12 +259,14 @@ extern char **environ;
/* We assume text [0] == '$' and want to have a look at text [1], if it is /* We assume text [0] == '$' and want to have a look at text [1], if it is
equal to '{', so that we should append '}' at the end */ equal to '{', so that we should append '}' at the end */
static char * static char *
variable_completion_function (char *text, int state) variable_completion_function (char *text, int state, INPUT_COMPLETE_FLAGS flags)
{ {
static char **env_p; static char **env_p;
static int varlen, isbrace; static int varlen, isbrace;
const char *p = NULL; const char *p = NULL;
SHOW_C_CTX("variable_completion_function");
if (!state){ /* Initialization stuff */ if (!state){ /* Initialization stuff */
isbrace = (text [1] == '{'); isbrace = (text [1] == '{');
varlen = strlen (text + 1 + isbrace); varlen = strlen (text + 1 + isbrace);
@ -342,11 +376,13 @@ static void fetch_hosts (const char *filename)
} }
static char * static char *
hostname_completion_function (char *text, int state) hostname_completion_function (char *text, int state, INPUT_COMPLETE_FLAGS flags)
{ {
static char **host_p; static char **host_p;
static int textstart, textlen; static int textstart, textlen;
SHOW_C_CTX("hostname_completion_function");
if (!state){ /* Initialization stuff */ if (!state){ /* Initialization stuff */
const char *p; const char *p;
@ -396,7 +432,7 @@ hostname_completion_function (char *text, int state)
* table of shell built-ins. * table of shell built-ins.
*/ */
static char * static char *
command_completion_function (char *text, int state) command_completion_function (char *text, int state, INPUT_COMPLETE_FLAGS flags)
{ {
static const char *path_end; static const char *path_end;
static int isabsolute; static int isabsolute;
@ -422,9 +458,16 @@ command_completion_function (char *text, int state)
}; };
char *p, *found; char *p, *found;
SHOW_C_CTX("command_completion_function");
if (!(flags & INPUT_COMPLETE_COMMANDS))
return 0;
text = mhl_shell_unescape_buf(text);
flags &= ~INPUT_COMPLETE_SHELL_ESC;
if (!state) { /* Initialize us a little bit */ if (!state) { /* Initialize us a little bit */
isabsolute = strchr (text, PATH_SEP) != 0; isabsolute = strchr (text, PATH_SEP) != 0;
look_for_executables = isabsolute ? 1 : 2;
if (!isabsolute) { if (!isabsolute) {
words = bash_reserved; words = bash_reserved;
phase = 0; phase = 0;
@ -440,10 +483,12 @@ command_completion_function (char *text, int state)
} }
if (isabsolute) { if (isabsolute) {
p = filename_completion_function (text, state); p = filename_completion_function (text, state, flags);
if (!p) if (!p)
look_for_executables = 0; return 0;
return p; SHELL_ESCAPED_STR e_p = mhl_shell_escape_dup(p);
mhl_mem_free(p);
return e_p.s;
} }
found = NULL; found = NULL;
@ -483,7 +528,7 @@ command_completion_function (char *text, int state)
} }
found = found =
filename_completion_function (cur_word, filename_completion_function (cur_word,
state - init_state); state - init_state, flags);
if (!found) { if (!found) {
g_free (cur_word); g_free (cur_word);
cur_word = NULL; cur_word = NULL;
@ -492,16 +537,16 @@ command_completion_function (char *text, int state)
} }
if (!found) { if (!found) {
look_for_executables = 0;
g_free (path); g_free (path);
path = NULL; path = NULL;
return NULL; return NULL;
} }
if ((p = strrchr (found, PATH_SEP)) != NULL) { if ((p = strrchr (found, PATH_SEP)) != NULL) {
p++; p++;
p = g_strdup (p);
g_free (found); SHELL_ESCAPED_STR e_p = mhl_shell_escape_dup(p);
return p; mhl_mem_free(found);
return e_p.s;
} }
return found; return found;
@ -521,7 +566,7 @@ match_compare (const void *a, const void *b)
as the second. as the second.
In case no matches were found we return NULL. */ In case no matches were found we return NULL. */
static char ** static char **
completion_matches (char *text, CompletionFunction entry_function) completion_matches (char *text, CompletionFunction entry_function, INPUT_COMPLETE_FLAGS flags)
{ {
/* Number of slots in match_list. */ /* Number of slots in match_list. */
int match_list_size; int match_list_size;
@ -537,7 +582,7 @@ completion_matches (char *text, CompletionFunction entry_function)
match_list[1] = NULL; match_list[1] = NULL;
while ((string = (*entry_function) (text, matches)) != NULL){ while ((string = (*entry_function) (text, matches, flags)) != NULL){
if (matches + 1 == match_list_size) if (matches + 1 == match_list_size)
match_list = (char **) g_realloc (match_list, ((match_list_size += 30) + 1) * sizeof (char *)); match_list = (char **) g_realloc (match_list, ((match_list_size += 30) + 1) * sizeof (char *));
match_list[++matches] = string; match_list[++matches] = string;
@ -597,14 +642,12 @@ completion_matches (char *text, CompletionFunction entry_function)
/* Check if directory completion is needed */ /* Check if directory completion is needed */
static int static int
check_is_cd (const char *text, int start, int flags) check_is_cd (const char *text, int start, INPUT_COMPLETE_FLAGS flags)
{ {
const char *p, *q; const char *p, *q;
if (flags & INPUT_COMPLETE_CD) SHOW_C_CTX("check_is_cd");
return 1; if (!(flags & INPUT_COMPLETE_CD))
if (!(flags & INPUT_COMPLETE_COMMANDS))
return 0; return 0;
/* Skip initial spaces */ /* Skip initial spaces */
@ -623,16 +666,17 @@ check_is_cd (const char *text, int start, int flags)
/* Returns an array of matches, or NULL if none. */ /* Returns an array of matches, or NULL if none. */
static char ** static char **
try_complete (char *text, int *start, int *end, int flags) try_complete (char *text, int *start, int *end, INPUT_COMPLETE_FLAGS flags)
{ {
int in_command_position = 0, i; int in_command_position = 0;
char *word, c; char *word, c;
char **matches = NULL; char **matches = NULL;
const char *command_separator_chars = ";|&{(`"; const char *command_separator_chars = ";|&{(`";
char *p = NULL, *q = NULL, *r = NULL; char *p = NULL, *q = NULL, *r = NULL;
int is_cd = check_is_cd (text, *start, flags); int is_cd = check_is_cd (text, *start, flags);
ignore_filenames = 0; SHOW_C_CTX("try_complete");
c = text [*end]; c = text [*end];
text [*end] = 0; text [*end] = 0;
word = g_strdup (text + *start); word = g_strdup (text + *start);
@ -643,9 +687,16 @@ try_complete (char *text, int *start, int *end, int flags)
appears after a character that separates commands. And we have to appears after a character that separates commands. And we have to
be in a INPUT_COMPLETE_COMMANDS flagged Input line. */ be in a INPUT_COMPLETE_COMMANDS flagged Input line. */
if (!is_cd && (flags & INPUT_COMPLETE_COMMANDS)){ if (!is_cd && (flags & INPUT_COMPLETE_COMMANDS)){
i = *start - 1; int i = *start - 1;
while (i > -1 && (text[i] == ' ' || text[i] == '\t')) for (i = *start - 1; i > -1; i--) {
i--; if (text[i] == ' ' || text[i] == '\t'){
if (i == 0 ) continue;
if (text[i-1] != '\\') {
i--;
break;
}
}
}
if (i < 0) if (i < 0)
in_command_position++; in_command_position++;
else if (strchr (command_separator_chars, text[i])){ else if (strchr (command_separator_chars, text[i])){
@ -679,17 +730,19 @@ try_complete (char *text, int *start, int *end, int flags)
p = q + 1; p = q + 1;
q = NULL; q = NULL;
} }
/* Command substitution? */ /* Command substitution? */
if (p > q && p > r){ if (p > q && p > r){
matches = completion_matches (p + 1, command_completion_function); SHOW_C_CTX("try_complete:cmd_backq_subst");
matches = completion_matches (p + 1, command_completion_function, flags & (~INPUT_COMPLETE_FILENAMES));
if (matches) if (matches)
*start += p + 1 - word; *start += p + 1 - word;
} }
/* Variable name? */ /* Variable name? */
else if (q > p && q > r){ else if (q > p && q > r){
matches = completion_matches (q, variable_completion_function); SHOW_C_CTX("try_complete:var_subst");
matches = completion_matches (q, variable_completion_function, flags);
if (matches) if (matches)
*start += q - word; *start += q - word;
} }
@ -697,7 +750,8 @@ try_complete (char *text, int *start, int *end, int flags)
/* Starts with '@', then look through the known hostnames for /* Starts with '@', then look through the known hostnames for
completion first. */ completion first. */
else if (r > p && r > q){ else if (r > p && r > q){
matches = completion_matches (r, hostname_completion_function); SHOW_C_CTX("try_complete:host_subst");
matches = completion_matches (r, hostname_completion_function, flags);
if (matches) if (matches)
*start += r - word; *start += r - word;
} }
@ -705,26 +759,46 @@ try_complete (char *text, int *start, int *end, int flags)
/* Starts with `~' and there is no slash in the word, then /* Starts with `~' and there is no slash in the word, then
try completing this word as a username. */ try completing this word as a username. */
if (!matches && *word == '~' && (flags & INPUT_COMPLETE_USERNAMES) && !strchr (word, PATH_SEP)) if (!matches && *word == '~' && (flags & INPUT_COMPLETE_USERNAMES) && !strchr (word, PATH_SEP))
matches = completion_matches (word, username_completion_function); {
SHOW_C_CTX("try_complete:user_subst");
matches = completion_matches (word, username_completion_function, flags);
}
/* And finally if this word is in a command position, then /* And finally if this word is in a command position, then
complete over possible command names, including aliases, functions, complete over possible command names, including aliases, functions,
and command names. */ and command names. */
if (!matches && in_command_position) if (!matches && in_command_position)
matches = completion_matches (word, command_completion_function); {
SHOW_C_CTX("try_complete:cmd_subst");
matches = completion_matches (word, command_completion_function, flags & (~INPUT_COMPLETE_FILENAMES));
}
else if (!matches && (flags & INPUT_COMPLETE_FILENAMES)){ else if (!matches && (flags & INPUT_COMPLETE_FILENAMES)){
if (is_cd) if (is_cd)
ignore_filenames = 1; flags &= ~(INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_COMMANDS);
matches = completion_matches (word, filename_completion_function); SHOW_C_CTX("try_complete:filename_subst_1");
ignore_filenames = 0; matches = completion_matches (word, filename_completion_function, flags);
if (!matches && is_cd && *word != PATH_SEP && *word != '~'){ if (!matches && is_cd && *word != PATH_SEP && *word != '~'){
char *p, *q = text + *start; char *p, *q = text + *start;
for (p = text; *p && p < q && (*p == ' ' || *p == '\t'); p++); for (p = text; *p && p < q; p++){
if (*p == ' ' || *p == '\t') {
if (p == text) continue;
if (*(p-1) == '\\') {
p--;
break;
}
}
}
if (!strncmp (p, "cd", 2)) if (!strncmp (p, "cd", 2))
for (p += 2; *p && p < q && (*p == ' ' || *p == '\t'); p++); for (p += 2; *p && p < q && (*p == ' ' || *p == '\t'); p++){
if (p == text) continue;
if (*(p-1) == '\\') {
p--;
break;
}
}
if (p == q){ if (p == q){
char * const cdpath_ref = g_strdup (getenv ("CDPATH")); char * const cdpath_ref = g_strdup (getenv ("CDPATH"));
char *cdpath = cdpath_ref; char *cdpath = cdpath_ref;
@ -742,10 +816,9 @@ try_complete (char *text, int *start, int *end, int flags)
*s = 0; *s = 0;
if (*cdpath){ if (*cdpath){
r = mhl_str_dir_plus_file (cdpath, word); r = mhl_str_dir_plus_file (cdpath, word);
ignore_filenames = 1; SHOW_C_CTX("try_complete:filename_subst_2");
matches = completion_matches (r, filename_completion_function); matches = completion_matches (r, filename_completion_function, flags);
ignore_filenames = 0; g_free (r);
g_free (r);
} }
*s = c; *s = c;
cdpath = s + 1; cdpath = s + 1;
@ -917,15 +990,21 @@ complete_engine (WInput *in, int what_to_do)
if (!in->completions){ if (!in->completions){
end = in->point; end = in->point;
for (start = end ? end - 1 : 0; start > -1; start--) for (start = end ? end - 1 : 0; start > -1; start--)
if (strchr (" \t;|<>", in->buffer [start])) if (strchr (" \t;|<>", in->buffer [start])){
break; if (start > 0 && in->buffer [start-1] == '\\')
continue;
else
break;
}
if (start < end) if (start < end)
start++; start++;
in->completions = try_complete (in->buffer, &start, &end, in->completion_flags); in->completions = try_complete (in->buffer, &start, &end, in->completion_flags);
} }
if (in->completions){ if (in->completions){
if (what_to_do & DO_INSERTION || ((what_to_do & DO_QUERY) && !in->completions[1])) { if (what_to_do & DO_INSERTION || ((what_to_do & DO_QUERY) && !in->completions[1])) {
if (insert_text (in, in->completions [0], strlen (in->completions [0]))){ char * complete = in->completions [0];
if (insert_text (in, complete, strlen (complete))){
if (in->completions [1]) if (in->completions [1])
beep (); beep ();
else else
@ -940,10 +1019,11 @@ complete_engine (WInput *in, int what_to_do)
char **p, *q; char **p, *q;
Dlg_head *query_dlg; Dlg_head *query_dlg;
WListbox *query_list; WListbox *query_list;
for (p=in->completions + 1; *p; count++, p++) for (p=in->completions + 1; *p; count++, p++) {
if ((i = strlen (*p)) > maxlen) if ((i = strlen (*p)) > maxlen)
maxlen = i; maxlen = i;
}
start_x = in->widget.x; start_x = in->widget.x;
start_y = in->widget.y; start_y = in->widget.y;
if (start_y - 2 >= count) { if (start_y - 2 >= count) {

View File

@ -1,16 +0,0 @@
#ifndef MC_COMPLETE_H
#define MC_COMPLETE_H
#define INPUT_COMPLETE_FILENAMES 1
#define INPUT_COMPLETE_HOSTNAMES 2
#define INPUT_COMPLETE_COMMANDS 4
#define INPUT_COMPLETE_VARIABLES 8
#define INPUT_COMPLETE_USERNAMES 16
#define INPUT_COMPLETE_CD 32
#include "widget.h"
void free_completions (WInput *);
void complete (WInput *);
#endif

View File

@ -50,6 +50,8 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <mhl/memory.h>
#include <mhl/escape.h>
#include <mhl/string.h> #include <mhl/string.h>
#include "global.h" #include "global.h"
@ -65,6 +67,7 @@
#include "widget.h" #include "widget.h"
#include "wtools.h" #include "wtools.h"
#include "background.h" /* we_are_background */ #include "background.h" /* we_are_background */
#include "util.h"
/* Needed for current_panel, other_panel and WTree */ /* Needed for current_panel, other_panel and WTree */
#include "dir.h" #include "dir.h"
@ -178,37 +181,43 @@ do_transform_source (FileOpContext *ctx, const char *source)
for (next_reg = 1, j = 0, k = 0; j < strlen (ctx->dest_mask); j++) { for (next_reg = 1, j = 0, k = 0; j < strlen (ctx->dest_mask); j++) {
switch (ctx->dest_mask[j]) { switch (ctx->dest_mask[j]) {
case '\\': case '\\':
j++; if (mhl_shell_is_char_escaped (&ctx->dest_mask[j])){
if (!isdigit ((unsigned char) ctx->dest_mask[j])) { fntarget[k++] = ctx->dest_mask[j++];
/* Backslash followed by non-digit */ fntarget[k++] = ctx->dest_mask[j];
switch (ctx->dest_mask[j]) {
case 'U':
case_conv |= UP_SECT;
case_conv &= ~LOW_SECT;
break;
case 'u':
case_conv |= UP_CHAR;
break;
case 'L':
case_conv |= LOW_SECT;
case_conv &= ~UP_SECT;
break;
case 'l':
case_conv |= LOW_CHAR;
break;
case 'E':
case_conv = NO_CONV;
break;
default:
/* Backslash as quote mark */
fntarget[k++] =
convert_case (ctx->dest_mask[j], &case_conv);
}
break; break;
} else { } else {
/* Backslash followed by digit */ j++;
next_reg = ctx->dest_mask[j] - '0'; if (!isdigit ((unsigned char) ctx->dest_mask[j])) {
/* Fall through */ /* Backslash followed by non-digit */
switch (ctx->dest_mask[j]) {
case 'U':
case_conv |= UP_SECT;
case_conv &= ~LOW_SECT;
break;
case 'u':
case_conv |= UP_CHAR;
break;
case 'L':
case_conv |= LOW_SECT;
case_conv &= ~UP_SECT;
break;
case 'l':
case_conv |= LOW_CHAR;
break;
case 'E':
case_conv = NO_CONV;
break;
default:
/* Backslash as quote mark */
fntarget[k++] =
convert_case (ctx->dest_mask[j], &case_conv);
}
break;
} else {
/* Backslash followed by digit */
next_reg = ctx->dest_mask[j] - '0';
/* Fall through */
}
} }
case '*': case '*':
@ -793,7 +802,7 @@ copy_file_file (FileOpContext *ctx, const char *src_path, const char *dst_path,
} }
} }
if (!appending) { if (!appending && ctx->preserve) {
while (mc_chmod (dst_path, (src_mode & ctx->umask_kill))) { while (mc_chmod (dst_path, (src_mode & ctx->umask_kill))) {
temp_status = file_error ( temp_status = file_error (
_(" Cannot chmod target file \"%s\" \n %s "), dst_path); _(" Cannot chmod target file \"%s\" \n %s "), dst_path);
@ -1896,7 +1905,7 @@ panel_operate (void *source_panel, FileOperation operation,
g_free (dest); g_free (dest);
dest = temp2; dest = temp2;
temp = NULL; temp = NULL;
switch (operation) { switch (operation) {
case OP_COPY: case OP_COPY:
/* /*
@ -1988,6 +1997,9 @@ panel_operate (void *source_panel, FileOperation operation,
else { else {
char *temp2 = mhl_str_dir_plus_file (dest, temp); char *temp2 = mhl_str_dir_plus_file (dest, temp);
source_with_path = mhl_shell_unescape_buf(source_with_path);
temp2 = mhl_shell_unescape_buf(temp2);
switch (operation) { switch (operation) {
case OP_COPY: case OP_COPY:
/* /*

View File

@ -276,16 +276,16 @@ find_parameters (char **start_dir, char **pattern, char **content)
add_widget (find_dlg, case_sense); add_widget (find_dlg, case_sense);
in_with = in_with =
input_new (8, istart, INPUT_COLOR, ilen, in_contents, "content"); input_new (8, istart, INPUT_COLOR, ilen, in_contents, "content", INPUT_COMPLETE_DEFAULT);
add_widget (find_dlg, in_with); add_widget (find_dlg, in_with);
add_widget (find_dlg, recursively_cbox); add_widget (find_dlg, recursively_cbox);
in_name = in_name =
input_new (5, istart, INPUT_COLOR, ilen, in_start_name, "name"); input_new (5, istart, INPUT_COLOR, ilen, in_start_name, "name", INPUT_COMPLETE_DEFAULT);
add_widget (find_dlg, in_name); add_widget (find_dlg, in_name);
in_start = in_start =
input_new (3, istart, INPUT_COLOR, ilen, in_start_dir, "start"); input_new (3, istart, INPUT_COLOR, ilen, in_start_dir, "start", INPUT_COMPLETE_DEFAULT);
add_widget (find_dlg, in_start); add_widget (find_dlg, in_start);
add_widget (find_dlg, label_new (8, 3, labs[2])); add_widget (find_dlg, label_new (8, 3, labs[2]));

View File

@ -67,7 +67,6 @@
#include "widget.h" #include "widget.h"
#include "command.h" #include "command.h"
#include "wtools.h" #include "wtools.h"
#include "complete.h" /* For the free_completion */
#include "chmod.h" #include "chmod.h"
#include "chown.h" #include "chown.h"

View File

@ -165,7 +165,7 @@ init_panelize (void)
pname = pname =
input_new (UY + 14, UX, INPUT_COLOR, panelize_dlg->cols - 10, "", input_new (UY + 14, UX, INPUT_COLOR, panelize_dlg->cols - 10, "",
"in"); "in", INPUT_COMPLETE_DEFAULT);
add_widget (panelize_dlg, pname); add_widget (panelize_dlg, pname);
add_widget (panelize_dlg, label_new (UY + 13, UX, _("Command"))); add_widget (panelize_dlg, label_new (UY + 13, UX, _("Command")));

View File

@ -35,6 +35,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <mhl/escape.h>
#include <mhl/string.h> #include <mhl/string.h>
#include "global.h" #include "global.h"
@ -1516,4 +1517,3 @@ Q_ (const char *s)
sep = strchr(result, '|'); sep = strchr(result, '|');
return (sep != NULL) ? sep + 1 : result; return (sep != NULL) ? sep + 1 : result;
} }

View File

@ -41,6 +41,8 @@
#endif #endif
#include <unistd.h> #include <unistd.h>
#include <mhl/string.h>
#include "global.h" #include "global.h"
#include "execute.h" #include "execute.h"
#include "wtools.h" /* message() */ #include "wtools.h" /* message() */
@ -426,7 +428,7 @@ canonicalize_pathname (char *path)
if (p[0] == PATH_SEP && p[1] == PATH_SEP) { if (p[0] == PATH_SEP && p[1] == PATH_SEP) {
s = p + 1; s = p + 1;
while (*(++s) == PATH_SEP); while (*(++s) == PATH_SEP);
strcpy (p + 1, s); mhl_strmove (p + 1, s);
} }
p++; p++;
} }
@ -435,7 +437,7 @@ canonicalize_pathname (char *path)
p = lpath; p = lpath;
while (*p) { while (*p) {
if (p[0] == PATH_SEP && p[1] == '.' && p[2] == PATH_SEP) if (p[0] == PATH_SEP && p[1] == '.' && p[2] == PATH_SEP)
strcpy (p, p + 2); mhl_strmove (p, p + 2);
else else
p++; p++;
} }
@ -451,7 +453,7 @@ canonicalize_pathname (char *path)
lpath[1] = 0; lpath[1] = 0;
return; return;
} else { } else {
strcpy (lpath, lpath + 2); mhl_strmove (lpath, lpath + 2);
} }
} }
@ -497,10 +499,10 @@ canonicalize_pathname (char *path)
if (p[3] != 0) { if (p[3] != 0) {
if (s == lpath && *s == PATH_SEP) { if (s == lpath && *s == PATH_SEP) {
/* "/../foo" -> "/foo" */ /* "/../foo" -> "/foo" */
strcpy (s + 1, p + 4); mhl_strmove (s + 1, p + 4);
} else { } else {
/* "token/../foo" -> "foo" */ /* "token/../foo" -> "foo" */
strcpy (s, p + 4); mhl_strmove (s, p + 4);
} }
p = (s > lpath) ? s - 1 : s; p = (s > lpath) ? s - 1 : s;
continue; continue;

View File

@ -43,7 +43,6 @@
#include "dialog.h" #include "dialog.h"
#include "widget.h" #include "widget.h"
#include "win.h" #include "win.h"
#include "complete.h"
#include "key.h" /* XCTRL and ALT macros */ #include "key.h" /* XCTRL and ALT macros */
#include "profile.h" /* for history loading and saving */ #include "profile.h" /* for history loading and saving */
#include "wtools.h" /* For common_dialog_repaint() */ #include "wtools.h" /* For common_dialog_repaint() */
@ -1660,7 +1659,7 @@ input_event (Gpm_Event * event, void *data)
WInput * WInput *
input_new (int y, int x, int color, int len, const char *def_text, input_new (int y, int x, int color, int len, const char *def_text,
const char *histname) const char *histname, INPUT_COMPLETE_FLAGS completion_flags)
{ {
WInput *in = g_new (WInput, 1); WInput *in = g_new (WInput, 1);
int initial_buffer_len; int initial_buffer_len;
@ -1689,9 +1688,7 @@ input_new (int y, int x, int color, int len, const char *def_text,
initial_buffer_len = 1 + max ((size_t) len, strlen (def_text)); initial_buffer_len = 1 + max ((size_t) len, strlen (def_text));
in->widget.options |= W_IS_INPUT; in->widget.options |= W_IS_INPUT;
in->completions = NULL; in->completions = NULL;
in->completion_flags = in->completion_flags = completion_flags;
INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_HOSTNAMES |
INPUT_COMPLETE_VARIABLES | INPUT_COMPLETE_USERNAMES;
in->current_max_len = initial_buffer_len; in->current_max_len = initial_buffer_len;
in->buffer = g_malloc (initial_buffer_len); in->buffer = g_malloc (initial_buffer_len);
in->color = color; in->color = color;

View File

@ -3,6 +3,23 @@
#include "dialog.h" /* Widget */ #include "dialog.h" /* Widget */
/* Completion stuff */
typedef enum {
INPUT_COMPLETE_FILENAMES = 1<<0,
INPUT_COMPLETE_HOSTNAMES = 1<<1,
INPUT_COMPLETE_COMMANDS = 1<<2,
INPUT_COMPLETE_VARIABLES = 1<<3,
INPUT_COMPLETE_USERNAMES = 1<<4,
INPUT_COMPLETE_CD = 1<<5,
INPUT_COMPLETE_SHELL_ESC = 1<<6,
INPUT_COMPLETE_DEFAULT = INPUT_COMPLETE_FILENAMES
| INPUT_COMPLETE_HOSTNAMES
| INPUT_COMPLETE_VARIABLES
| INPUT_COMPLETE_USERNAMES
} INPUT_COMPLETE_FLAGS;
/* Please note that the first element in all the widgets is a */ /* Please note that the first element in all the widgets is a */
/* widget variable of type Widget. We abuse this fact everywhere */ /* widget variable of type Widget. We abuse this fact everywhere */
@ -70,7 +87,7 @@ typedef struct {
GList *history; /* The history */ GList *history; /* The history */
int need_push; /* need to push the current Input on hist? */ int need_push; /* need to push the current Input on hist? */
char **completions; /* Possible completions array */ char **completions; /* Possible completions array */
int completion_flags; /* INPUT_COMPLETE* bitwise flags(complete.h) */ INPUT_COMPLETE_FLAGS completion_flags; /* INPUT_COMPLETE* bitwise flags(complete.h) */
char *history_name; /* name of history for loading and saving */ char *history_name; /* name of history for loading and saving */
} WInput; } WInput;
@ -122,12 +139,13 @@ typedef struct WGroupbox {
char *title; char *title;
} WGroupbox; } WGroupbox;
/* Constructors */ /* Constructors */
WButton *button_new (int y, int x, int action, int flags, const char *text, WButton *button_new (int y, int x, int action, int flags, const char *text,
bcback callback); bcback callback);
WRadio *radio_new (int y, int x, int count, const char **text); WRadio *radio_new (int y, int x, int count, const char **text);
WCheck *check_new (int y, int x, int state, const char *text); WCheck *check_new (int y, int x, int state, const char *text);
WInput *input_new (int y, int x, int color, int len, const char *text, const char *histname); WInput *input_new (int y, int x, int color, int len, const char *text, const char *histname, INPUT_COMPLETE_FLAGS completion_flags);
WLabel *label_new (int y, int x, const char *text); WLabel *label_new (int y, int x, const char *text);
WGauge *gauge_new (int y, int x, int shown, int max, int current); WGauge *gauge_new (int y, int x, int shown, int max, int current);
WListbox *listbox_new (int x, int y, int width, int height, lcback callback); WListbox *listbox_new (int x, int y, int width, int height, lcback callback);
@ -200,4 +218,7 @@ void buttonbar_set_label_data (Dlg_head *h, int idx, const char *text,
void buttonbar_set_visible (WButtonBar *, gboolean); void buttonbar_set_visible (WButtonBar *, gboolean);
void buttonbar_redraw (Dlg_head *h); void buttonbar_redraw (Dlg_head *h);
void free_completions (WInput *);
void complete (WInput *);
#endif #endif

View File

@ -36,7 +36,6 @@
#include "widget.h" #include "widget.h"
#include "wtools.h" #include "wtools.h"
#include "key.h" /* mi_getch() */ #include "key.h" /* mi_getch() */
#include "complete.h" /* INPUT_COMPLETE_CD */
#include "background.h" /* parent_call */ #include "background.h" /* parent_call */
@ -361,7 +360,7 @@ quick_dialog_skip (QuickDialog *qd, int nskip)
case quick_input: case quick_input:
input = input =
input_new (ypos, xpos, INPUT_COLOR, qw->hotkey_pos, input_new (ypos, xpos, INPUT_COLOR, qw->hotkey_pos,
qw->text, qw->histname); qw->text, qw->histname, INPUT_COMPLETE_DEFAULT);
input->is_password = qw->value == 1; input->is_password = qw->value == 1;
input->point = 0; input->point = 0;
if (qw->value & 2) if (qw->value & 2)

View File

@ -144,7 +144,7 @@ fish_command (struct vfs_class *me, struct vfs_s_super *super,
enable_interrupt_key (); enable_interrupt_key ();
status = write (SUP.sockw, str, strlen (str)); status = write (SUP.sockw, str, strlen (str));
g_free (str); mhl_mem_free (str);
disable_interrupt_key (); disable_interrupt_key ();
if (status < 0) if (status < 0)
@ -168,10 +168,10 @@ fish_free_archive (struct vfs_class *me, struct vfs_s_super *super)
close (SUP.sockr); close (SUP.sockr);
SUP.sockw = SUP.sockr = -1; SUP.sockw = SUP.sockr = -1;
} }
g_free (SUP.host); mhl_mem_free (SUP.host);
g_free (SUP.user); mhl_mem_free (SUP.user);
g_free (SUP.cwdir); mhl_mem_free (SUP.cwdir);
g_free (SUP.password); mhl_mem_free (SUP.password);
} }
static void static void
@ -260,7 +260,7 @@ fish_open_archive_int (struct vfs_class *me, struct vfs_s_super *super)
p = g_strconcat (_(" fish: Password required for "), p = g_strconcat (_(" fish: Password required for "),
SUP.user, " ", (char *) NULL); SUP.user, " ", (char *) NULL);
op = vfs_get_password (p); op = vfs_get_password (p);
g_free (p); mhl_mem_free (p);
if (op == NULL) if (op == NULL)
ERRNOR (EPERM, -1); ERRNOR (EPERM, -1);
SUP.password = op; SUP.password = op;
@ -323,7 +323,7 @@ fish_open_archive (struct vfs_class *me, struct vfs_s_super *super,
p = vfs_split_url (strchr (op, ':') + 1, &host, &user, &flags, p = vfs_split_url (strchr (op, ':') + 1, &host, &user, &flags,
&password, 0, URL_NOSLASH); &password, 0, URL_NOSLASH);
g_free (p); mhl_mem_free (p);
SUP.host = host; SUP.host = host;
SUP.user = user; SUP.user = user;
@ -350,12 +350,12 @@ fish_archive_same (struct vfs_class *me, struct vfs_s_super *super,
op = vfs_split_url (strchr (op, ':') + 1, &host, &user, &flags, 0, 0, op = vfs_split_url (strchr (op, ':') + 1, &host, &user, &flags, 0, 0,
URL_NOSLASH); URL_NOSLASH);
g_free (op); mhl_mem_free (op);
flags = ((strcmp (host, SUP.host) == 0) flags = ((strcmp (host, SUP.host) == 0)
&& (strcmp (user, SUP.user) == 0) && (flags == SUP.flags)); && (strcmp (user, SUP.user) == 0) && (flags == SUP.flags));
g_free (host); mhl_mem_free (host);
g_free (user); mhl_mem_free (user);
return flags; return flags;
} }
@ -367,7 +367,7 @@ fish_dir_load(struct vfs_class *me, struct vfs_s_inode *dir, char *remote_path)
char buffer[8192]; char buffer[8192];
struct vfs_s_entry *ent = NULL; struct vfs_s_entry *ent = NULL;
FILE *logfile; FILE *logfile;
char *quoted_path; SHELL_ESCAPED_STR quoted_path;
int reply_code; int reply_code;
#if 0 #if 0
@ -462,8 +462,8 @@ fish_dir_load(struct vfs_class *me, struct vfs_s_inode *dir, char *remote_path)
"else\n" "else\n"
"echo '### 500'\n" "echo '### 500'\n"
"fi\n", "fi\n",
quoted_path, quoted_path, quoted_path, quoted_path, quoted_path, quoted_path); quoted_path.s, quoted_path.s, quoted_path.s, quoted_path.s, quoted_path.s, quoted_path.s);
mhl_mem_free (quoted_path); mhl_mem_free (quoted_path.s);
ent = vfs_s_generate_entry(me, NULL, dir, 0); ent = vfs_s_generate_entry(me, NULL, dir, 0);
while (1) { while (1) {
int res = vfs_s_get_line_interruptible (me, buffer, sizeof (buffer), SUP.sockr); int res = vfs_s_get_line_interruptible (me, buffer, sizeof (buffer), SUP.sockr);
@ -594,7 +594,7 @@ fish_dir_load(struct vfs_class *me, struct vfs_s_inode *dir, char *remote_path)
vfs_s_free_entry (me, ent); vfs_s_free_entry (me, ent);
reply_code = fish_decode_reply(buffer + 4, 0); reply_code = fish_decode_reply(buffer + 4, 0);
if (reply_code == COMPLETE) { if (reply_code == COMPLETE) {
g_free (SUP.cwdir); mhl_mem_free (SUP.cwdir);
SUP.cwdir = g_strdup (remote_path); SUP.cwdir = g_strdup (remote_path);
print_vfs_message (_("%s: done."), me->name); print_vfs_message (_("%s: done."), me->name);
return 0; return 0;
@ -618,7 +618,7 @@ fish_file_store(struct vfs_class *me, struct vfs_s_fh *fh, char *name, char *loc
struct stat s; struct stat s;
int was_error = 0; int was_error = 0;
int h; int h;
char *quoted_name; SHELL_ESCAPED_STR quoted_name;
h = open (localname, O_RDONLY); h = open (localname, O_RDONLY);
@ -659,7 +659,7 @@ fish_file_store(struct vfs_class *me, struct vfs_s_fh *fh, char *name, char *loc
*/ */
quoted_name = mhl_shell_escape_dup(name); quoted_name = mhl_shell_escape_dup(name);
print_vfs_message(_("fish: store %s: sending command..."), quoted_name ); print_vfs_message(_("fish: store %s: sending command..."), quoted_name.s );
/* FIXME: File size is limited to ULONG_MAX */ /* FIXME: File size is limited to ULONG_MAX */
if (!fh->u.fish.append) if (!fh->u.fish.append)
@ -683,8 +683,8 @@ fish_file_store(struct vfs_class *me, struct vfs_s_fh *fh, char *name, char *loc
" rest=`expr $rest - $n`\n" " rest=`expr $rest - $n`\n"
"done\n" "done\n"
"}; echo '### 200'\n", "}; echo '### 200'\n",
(unsigned long) s.st_size, quoted_name, (unsigned long) s.st_size, quoted_name.s,
quoted_name, (unsigned long) s.st_size, quoted_name.s, (unsigned long) s.st_size,
(unsigned long) s.st_size); (unsigned long) s.st_size);
else else
n = fish_command (me, super, WAIT_REPLY, n = fish_command (me, super, WAIT_REPLY,
@ -700,8 +700,8 @@ fish_file_store(struct vfs_class *me, struct vfs_s_fh *fh, char *name, char *loc
" rest=`expr $rest - $n`\n" " rest=`expr $rest - $n`\n"
"done\n" "done\n"
"}; echo '### 200'\n", "}; echo '### 200'\n",
(unsigned long) s.st_size, quoted_name, (unsigned long) s.st_size, quoted_name.s,
quoted_name, (unsigned long) s.st_size); quoted_name.s, (unsigned long) s.st_size);
if (n != PRELIM) { if (n != PRELIM) {
close (h); close (h);
@ -735,14 +735,14 @@ fish_file_store(struct vfs_class *me, struct vfs_s_fh *fh, char *name, char *loc
(unsigned long) s.st_size); (unsigned long) s.st_size);
} }
close(h); close(h);
mhl_mem_free(quoted_name); mhl_mem_free(quoted_name.s);
if ((fish_get_reply (me, SUP.sockr, NULL, 0) != COMPLETE) || was_error) if ((fish_get_reply (me, SUP.sockr, NULL, 0) != COMPLETE) || was_error)
ERRNOR (E_REMOTE, -1); ERRNOR (E_REMOTE, -1);
return 0; return 0;
error_return: error_return:
close(h); close(h);
fish_get_reply(me, SUP.sockr, NULL, 0); fish_get_reply(me, SUP.sockr, NULL, 0);
mhl_mem_free(quoted_name); mhl_mem_free(quoted_name.s);
return -1; return -1;
} }
@ -750,7 +750,7 @@ static int
fish_linear_start (struct vfs_class *me, struct vfs_s_fh *fh, off_t offset) fish_linear_start (struct vfs_class *me, struct vfs_s_fh *fh, off_t offset)
{ {
char *name; char *name;
char *quoted_name; SHELL_ESCAPED_STR quoted_name;
if (offset) if (offset)
ERRNOR (E_NOTSUPP, 0); ERRNOR (E_NOTSUPP, 0);
name = vfs_s_fullpath (me, fh->ino); name = vfs_s_fullpath (me, fh->ino);
@ -779,8 +779,8 @@ fish_linear_start (struct vfs_class *me, struct vfs_s_fh *fh, off_t offset)
"else\n" "else\n"
"echo '### 500'\n" "echo '### 500'\n"
"fi\n", "fi\n",
quoted_name, quoted_name, quoted_name, quoted_name ); quoted_name.s, quoted_name.s, quoted_name.s, quoted_name.s );
g_free (quoted_name); mhl_mem_free (quoted_name.s);
if (offset != PRELIM) ERRNOR (E_REMOTE, 0); if (offset != PRELIM) ERRNOR (E_REMOTE, 0);
fh->linear = LS_LINEAR_OPEN; fh->linear = LS_LINEAR_OPEN;
fh->u.fish.got = 0; fh->u.fish.got = 0;
@ -889,17 +889,18 @@ fish_send_command(struct vfs_class *me, struct vfs_s_super *super, const char *c
#define PREFIX \ #define PREFIX \
char buf[BUF_LARGE]; \ char buf[BUF_LARGE]; \
const char *crpath; \ const char *crpath; \
char *rpath, *mpath = g_strdup (path); \ char *mpath = mhl_str_dup (path); \
SHELL_ESCAPED_STR rpath; \
struct vfs_s_super *super; \ struct vfs_s_super *super; \
if (!(crpath = vfs_s_get_path_mangle (me, mpath, &super, 0))) { \ if (!(crpath = vfs_s_get_path_mangle (me, mpath, &super, 0))) { \
g_free (mpath); \ mhl_mem_free (mpath); \
return -1; \ return -1; \
} \ } \
rpath = mhl_shell_escape_dup(crpath); \ rpath = mhl_shell_escape_dup(crpath); \
g_free (mpath); mhl_mem_free (mpath);
#define POSTFIX(flags) \ #define POSTFIX(flags) \
g_free (rpath); \ mhl_mem_free (rpath.s); \
return fish_send_command(me, super, buf, flags); return fish_send_command(me, super, buf, flags);
static int static int
@ -909,8 +910,8 @@ fish_chmod (struct vfs_class *me, const char *path, int mode)
g_snprintf(buf, sizeof(buf), "#CHMOD %4.4o /%s\n" g_snprintf(buf, sizeof(buf), "#CHMOD %4.4o /%s\n"
"chmod %4.4o /%s 2>/dev/null\n" "chmod %4.4o /%s 2>/dev/null\n"
"echo '### 000'\n", "echo '### 000'\n",
mode & 07777, rpath, mode & 07777, rpath.s,
mode & 07777, rpath); mode & 07777, rpath.s);
POSTFIX(OPT_FLUSH); POSTFIX(OPT_FLUSH);
} }
@ -919,24 +920,24 @@ static int fish_##name (struct vfs_class *me, const char *path1, const char *pat
{ \ { \
char buf[BUF_LARGE]; \ char buf[BUF_LARGE]; \
const char *crpath1, *crpath2; \ const char *crpath1, *crpath2; \
char *rpath1, *rpath2, *mpath1, *mpath2; \ char *mpath1, *mpath2; \
struct vfs_s_super *super1, *super2; \ struct vfs_s_super *super1, *super2; \
if (!(crpath1 = vfs_s_get_path_mangle (me, mpath1 = g_strdup(path1), &super1, 0))) { \ if (!(crpath1 = vfs_s_get_path_mangle (me, mpath1 = g_strdup(path1), &super1, 0))) { \
g_free (mpath1); \ mhl_mem_free (mpath1); \
return -1; \ return -1; \
} \ } \
if (!(crpath2 = vfs_s_get_path_mangle (me, mpath2 = g_strdup(path2), &super2, 0))) { \ if (!(crpath2 = vfs_s_get_path_mangle (me, mpath2 = g_strdup(path2), &super2, 0))) { \
g_free (mpath1); \ mhl_mem_free (mpath1); \
g_free (mpath2); \ mhl_mem_free (mpath2); \
return -1; \ return -1; \
} \ } \
rpath1 = mhl_shell_escape_dup (crpath1); \ SHELL_ESCAPED_STR rpath1 = mhl_shell_escape_dup (crpath1); \
g_free (mpath1); \ mhl_mem_free (mpath1); \
rpath2 = mhl_shell_escape_dup (crpath2); \ SHELL_ESCAPED_STR rpath2 = mhl_shell_escape_dup (crpath2); \
g_free (mpath2); \ mhl_mem_free (mpath2); \
g_snprintf(buf, sizeof(buf), string "\n", rpath1, rpath2, rpath1, rpath2); \ g_snprintf(buf, sizeof(buf), string "\n", rpath1.s, rpath2.s, rpath1.s, rpath2.s); \
mhl_mem_free (rpath1); \ mhl_mem_free (rpath1.s); \
mhl_mem_free (rpath2); \ mhl_mem_free (rpath2.s); \
return fish_send_command(me, super2, buf, OPT_FLUSH); \ return fish_send_command(me, super2, buf, OPT_FLUSH); \
} }
@ -949,15 +950,15 @@ FISH_OP(link, "#LINK /%s /%s\n"
static int fish_symlink (struct vfs_class *me, const char *setto, const char *path) static int fish_symlink (struct vfs_class *me, const char *setto, const char *path)
{ {
char *qsetto; SHELL_ESCAPED_STR qsetto;
PREFIX PREFIX
qsetto = mhl_shell_escape_dup (setto); qsetto = mhl_shell_escape_dup (setto);
g_snprintf(buf, sizeof(buf), g_snprintf(buf, sizeof(buf),
"#SYMLINK %s /%s\n" "#SYMLINK %s /%s\n"
"ln -s %s /%s 2>/dev/null\n" "ln -s %s /%s 2>/dev/null\n"
"echo '### 000'\n", "echo '### 000'\n",
qsetto, rpath, qsetto, rpath); qsetto.s, rpath.s, qsetto.s, rpath.s);
mhl_mem_free (qsetto); mhl_mem_free (qsetto.s);
POSTFIX(OPT_FLUSH); POSTFIX(OPT_FLUSH);
} }
@ -982,16 +983,16 @@ fish_chown (struct vfs_class *me, const char *path, int owner, int group)
"#CHOWN %s /%s\n" "#CHOWN %s /%s\n"
"chown %s /%s 2>/dev/null\n" "chown %s /%s 2>/dev/null\n"
"echo '### 000'\n", "echo '### 000'\n",
sowner, rpath, sowner, rpath.s,
sowner, rpath); sowner, rpath.s);
fish_send_command (me, super, buf, OPT_FLUSH); fish_send_command (me, super, buf, OPT_FLUSH);
/* FIXME: what should we report if chgrp succeeds but chown fails? */ /* FIXME: what should we report if chgrp succeeds but chown fails? */
g_snprintf (buf, sizeof(buf), g_snprintf (buf, sizeof(buf),
"#CHGRP /%s \"/%s\"\n" "#CHGRP /%s \"/%s\"\n"
"chgrp %s \"/%s\" 2>/dev/null\n" "chgrp %s \"/%s\" 2>/dev/null\n"
"echo '### 000'\n", "echo '### 000'\n",
sgroup, rpath, sgroup, rpath.s,
sgroup, rpath); sgroup, rpath.s);
/* fish_send_command(me, super, buf, OPT_FLUSH); */ /* fish_send_command(me, super, buf, OPT_FLUSH); */
POSTFIX (OPT_FLUSH) POSTFIX (OPT_FLUSH)
} }
@ -1004,7 +1005,7 @@ static int fish_unlink (struct vfs_class *me, const char *path)
"#DELE /%s\n" "#DELE /%s\n"
"rm -f /%s 2>/dev/null\n" "rm -f /%s 2>/dev/null\n"
"echo '### 000'\n", "echo '### 000'\n",
rpath, rpath); rpath.s, rpath.s);
POSTFIX(OPT_FLUSH); POSTFIX(OPT_FLUSH);
} }
@ -1018,7 +1019,7 @@ static int fish_mkdir (struct vfs_class *me, const char *path, mode_t mode)
"#MKD /%s\n" "#MKD /%s\n"
"mkdir /%s 2>/dev/null\n" "mkdir /%s 2>/dev/null\n"
"echo '### 000'\n", "echo '### 000'\n",
rpath, rpath); rpath.s, rpath.s);
POSTFIX(OPT_FLUSH); POSTFIX(OPT_FLUSH);
} }
@ -1029,7 +1030,7 @@ static int fish_rmdir (struct vfs_class *me, const char *path)
"#RMD /%s\n" "#RMD /%s\n"
"rmdir /%s 2>/dev/null\n" "rmdir /%s 2>/dev/null\n"
"echo '### 000'\n", "echo '### 000'\n",
rpath, rpath); rpath.s, rpath.s);
POSTFIX(OPT_FLUSH); POSTFIX(OPT_FLUSH);
} }
@ -1093,7 +1094,7 @@ fish_fill_names (struct vfs_class *me, fill_names_f func)
name = g_strconcat ("/#sh:", SUP.user, "@", SUP.host, flags, name = g_strconcat ("/#sh:", SUP.user, "@", SUP.host, flags,
"/", SUP.cwdir, (char *) NULL); "/", SUP.cwdir, (char *) NULL);
(*func)(name); (*func)(name);
g_free (name); mhl_mem_free (name);
super = super->next; super = super->next;
} }
} }