1 /* Command line widget.
2 Copyright (C) 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
3 2007 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 This widget is derived from the WInput widget, it's used to cope
20 with all the magic of the command input line, we depend on some
21 help from the program's callback.
30 #include <mhl/memory.h>
31 #include <mhl/string.h>
32 #include <mhl/escape.h>
34 #include "global.h" /* home_dir */
36 #include "widget.h" /* WInput */
38 #include "wtools.h" /* message () */
39 #include "panel.h" /* view_tree enum. Also, needed by main.h */
40 #include "main.h" /* do_cd */
41 #include "layout.h" /* for command_prompt variable */
42 #include "user.h" /* expand_format */
43 #include "subshell.h" /* SUBSHELL_EXIT */
44 #include "tree.h" /* for tree_chdir */
45 #include "color.h" /* DEFAULT_COLOR */
46 #include "execute.h" /* shell_execute */
48 /* This holds the command line */
52 * Expand the argument to "cd" and change directory. First try tilde
53 * expansion, then variable substitution. If the CDPATH variable is set
54 * (e.g. CDPATH=".:~:/usr"), try all the paths contained there.
55 * We do not support such rare substitutions as ${var:-value} etc.
56 * No quoting is implemented here, so ${VAR} and $VAR will be always
57 * substituted. Wildcards are not supported either.
58 * Advanced users should be encouraged to use "\cd" instead of "cd" if
59 * they want the behavior they are used to in the shell.
62 examine_cd (char *path
)
66 char *p
, *q
, *r
, *s
, c
;
70 path
= mhl_shell_unescape_buf(path
);
71 path_tilde
= tilde_expand (path
);
73 /* Leave space for further expansion */
74 qlen
= strlen (path_tilde
) + MC_MAXPATHLEN
;
77 /* Variable expansion */
78 for (p
= path_tilde
, r
= q
; *p
&& r
< q
+ MC_MAXPATHLEN
;) {
79 if (*p
!= '$' || (p
[1] == '[' || p
[1] == '('))
89 s
= strchr (p
, PATH_SEP
);
101 if (r
+ strlen (t
) < q
+ MC_MAXPATHLEN
) {
114 result
= do_cd (q
, cd_parse_command
);
116 /* CDPATH handling */
117 if (*q
!= PATH_SEP
&& !result
) {
118 char * const cdpath
= g_strdup (getenv ("CDPATH"));
124 while (!result
&& c
== ':') {
131 r
= mhl_str_dir_plus_file (p
, q
);
132 result
= do_cd (r
, cd_parse_command
);
145 /* Execute the cd command on the command line */
146 void do_cd_command (char *cmd
)
150 /* Any final whitespace should be removed here
151 (to see why, try "cd fred "). */
152 /* NOTE: I think we should not remove the extra space,
153 that way, we can cd into hidden directories */
154 /* FIXME: what about interpreting quoted strings like the shell.
155 so one could type "cd <tab> M-a <enter>" and it would work. */
156 len
= strlen (cmd
) - 1;
158 (cmd
[len
] == ' ' || cmd
[len
] == '\t' || cmd
[len
] == '\n')){
166 if (get_current_type () == view_tree
){
168 sync_tree (home_dir
);
169 } else if (strcmp (cmd
+3, "..") == 0){
170 char *dir
= current_panel
->cwd
;
171 int len
= strlen (dir
);
172 while (len
&& dir
[--len
] != PATH_SEP
);
177 sync_tree (PATH_SEP_STR
);
178 } else if (cmd
[3] == PATH_SEP
){
181 char *old
= current_panel
->cwd
;
183 new = mhl_str_dir_plus_file (old
, cmd
+3);
188 if (!examine_cd (&cmd
[3])) {
189 char *d
= strip_password (g_strdup (&cmd
[3]), 1);
190 message (D_ERROR
, MSG_ERROR
, _(" Cannot chdir to \"%s\" \n %s "),
191 d
, unix_error_string (errno
));
197 /* Handle Enter on the command line */
199 enter (WInput
*cmdline
)
201 char *cmd
= cmdline
->buffer
;
206 /* Any initial whitespace should be removed at this point */
207 while (*cmd
== ' ' || *cmd
== '\t' || *cmd
== '\n')
213 if (strncmp (cmd
, "cd ", 3) == 0 || strcmp (cmd
, "cd") == 0) {
219 size_t i
, j
, cmd_len
;
221 if (!vfs_current_is_local ()) {
222 message (D_ERROR
, MSG_ERROR
,
224 (" Cannot execute commands on non-local filesystems"));
226 return MSG_NOT_HANDLED
;
228 #ifdef HAVE_SUBSHELL_SUPPORT
229 /* Check this early before we clean command line
230 * (will be checked again by shell_execute) */
231 if (use_subshell
&& subshell_state
!= INACTIVE
) {
232 message (D_ERROR
, MSG_ERROR
,
233 _(" The shell is already running a command "));
234 return MSG_NOT_HANDLED
;
237 cmd_len
= strlen (cmd
);
238 command
= g_malloc (cmd_len
+ 1);
240 for (i
= j
= 0; i
< cmd_len
; i
++) {
243 s
= expand_format (NULL
, cmd
[i
], 1);
244 command
= g_realloc (command
, j
+ strlen (s
) + cmd_len
- i
+ 1);
245 strcpy (command
+ j
, s
);
247 j
= strlen (command
);
255 shell_execute (command
, 0);
258 #ifdef HAVE_SUBSHELL_SUPPORT
259 if (quit
& SUBSHELL_EXIT
) {
271 command_callback (Widget
*w
, widget_msg_t msg
, int parm
)
273 WInput
*cmd
= (WInput
*) w
;
277 /* Never accept focus, otherwise panels will be unselected */
278 return MSG_NOT_HANDLED
;
281 /* Special case: we handle the enter key */
288 return input_callback (w
, msg
, parm
);
293 command_new (int y
, int x
, int cols
)
297 cmd
= input_new (y
, x
, DEFAULT_COLOR
, cols
, "", "cmdline",
298 INPUT_COMPLETE_DEFAULT
| INPUT_COMPLETE_CD
| INPUT_COMPLETE_COMMANDS
| INPUT_COMPLETE_SHELL_ESC
);
301 cmd
->widget
.callback
= command_callback
;
302 cmd
->completion_flags
|= INPUT_COMPLETE_COMMANDS
;
308 * Insert quoted text in input line. The function is meant for the
309 * command line, so the percent sign is quoted as well.
312 command_insert (WInput
* in
, const char *text
, int insert_extra_space
)
316 quoted_text
= name_quote (text
, 1);
317 stuff (in
, quoted_text
, insert_extra_space
);
318 g_free (quoted_text
);