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.
26 * \brief Source: command line widget
35 #include "lib/global.h" /* home_dir */
36 #include "lib/tty/tty.h"
37 #include "lib/vfs/mc-vfs/vfs.h"
38 #include "lib/strescape.h"
40 #include "widget.h" /* WInput */
42 #include "wtools.h" /* message () */
43 #include "panel.h" /* view_tree enum. Also, needed by main.h */
44 #include "main.h" /* do_cd */
45 #include "layout.h" /* for command_prompt variable */
46 #include "user.h" /* expand_format */
47 #include "subshell.h" /* SUBSHELL_EXIT */
48 #include "tree.h" /* for tree_chdir */
49 #include "lib/skin.h" /* DEFAULT_COLOR */
50 #include "execute.h" /* shell_execute */
52 /* This holds the command line */
56 * Expand the argument to "cd" and change directory. First try tilde
57 * expansion, then variable substitution. If the CDPATH variable is set
58 * (e.g. CDPATH=".:~:/usr"), try all the paths contained there.
59 * We do not support such rare substitutions as ${var:-value} etc.
60 * No quoting is implemented here, so ${VAR} and $VAR will be always
61 * substituted. Wildcards are not supported either.
62 * Advanced users should be encouraged to use "\cd" instead of "cd" if
63 * they want the behavior they are used to in the shell.
66 examine_cd (const char *_path
)
69 char *path_tilde
, *path
;
70 char *p
, *q
, *r
, *s
, c
;
74 path
= strutils_shell_unescape(_path
);
75 path_tilde
= tilde_expand (path
);
77 /* Leave space for further expansion */
78 qlen
= strlen (path_tilde
) + MC_MAXPATHLEN
;
81 /* Variable expansion */
82 for (p
= path_tilde
, r
= q
; *p
&& r
< q
+ MC_MAXPATHLEN
;) {
83 if (*p
!= '$' || (p
[1] == '[' || p
[1] == '('))
93 s
= strchr (p
, PATH_SEP
);
105 if (r
+ strlen (t
) < q
+ MC_MAXPATHLEN
) {
118 result
= do_cd (q
, cd_parse_command
);
120 /* CDPATH handling */
121 if (*q
!= PATH_SEP
&& !result
) {
122 char * const cdpath
= g_strdup (getenv ("CDPATH"));
128 while (!result
&& c
== ':') {
135 r
= concat_dir_and_file (p
, q
);
136 result
= do_cd (r
, cd_parse_command
);
150 /* Execute the cd command on the command line */
151 void do_cd_command (char * orig_cmd
)
156 /* Any final whitespace should be removed here
157 (to see why, try "cd fred "). */
158 /* NOTE: I think we should not remove the extra space,
159 that way, we can cd into hidden directories */
160 /* FIXME: what about interpreting quoted strings like the shell.
161 so one could type "cd <tab> M-a <enter>" and it would work. */
162 len
= strlen (orig_cmd
) - 1;
164 (orig_cmd
[len
] == ' ' || orig_cmd
[len
] == '\t' || orig_cmd
[len
] == '\n')){
173 if (get_current_type () == view_tree
){
175 sync_tree (home_dir
);
176 } else if (strcmp (cmd
+3, "..") == 0){
177 char *dir
= current_panel
->cwd
;
179 while (len
&& dir
[--len
] != PATH_SEP
);
184 sync_tree (PATH_SEP_STR
);
185 } else if (cmd
[3] == PATH_SEP
){
188 char *old
= current_panel
->cwd
;
190 new = concat_dir_and_file (old
, cmd
+3);
195 if (!examine_cd (&cmd
[3])) {
196 char *d
= strip_password (g_strdup (&cmd
[3]), 1);
197 message (D_ERROR
, MSG_ERROR
, _(" Cannot chdir to \"%s\" \n %s "),
198 d
, unix_error_string (errno
));
204 /* Handle Enter on the command line */
206 enter (WInput
*lc_cmdline
)
208 char *cmd
= lc_cmdline
->buffer
;
213 /* Any initial whitespace should be removed at this point */
214 while (*cmd
== ' ' || *cmd
== '\t' || *cmd
== '\n')
220 if (strncmp (cmd
, "cd ", 3) == 0 || strcmp (cmd
, "cd") == 0) {
222 new_input (lc_cmdline
);
226 size_t i
, j
, cmd_len
;
228 if (!vfs_current_is_local ()) {
229 if (strcmp (cmd
, "exit") == 0) {
234 message (D_ERROR
, MSG_ERROR
,
236 (" Cannot execute commands on non-local filesystems"));
238 return MSG_NOT_HANDLED
;
240 #ifdef HAVE_SUBSHELL_SUPPORT
241 /* Check this early before we clean command line
242 * (will be checked again by shell_execute) */
243 if (use_subshell
&& subshell_state
!= INACTIVE
) {
244 message (D_ERROR
, MSG_ERROR
,
245 _(" The shell is already running a command "));
246 return MSG_NOT_HANDLED
;
249 cmd_len
= strlen (cmd
);
250 command
= g_malloc (cmd_len
+ 1);
252 for (i
= j
= 0; i
< cmd_len
; i
++) {
255 s
= expand_format (NULL
, cmd
[i
], TRUE
);
256 command
= g_realloc (command
, j
+ strlen (s
) + cmd_len
- i
+ 1);
257 strcpy (command
+ j
, s
);
259 j
= strlen (command
);
266 new_input (lc_cmdline
);
267 shell_execute (command
, 0);
270 #ifdef HAVE_SUBSHELL_SUPPORT
271 if (quit
& SUBSHELL_EXIT
) {
283 command_callback (Widget
*w
, widget_msg_t msg
, int parm
)
285 WInput
*cmd
= (WInput
*) w
;
289 /* Never accept focus, otherwise panels will be unselected */
290 return MSG_NOT_HANDLED
;
293 /* Special case: we handle the enter key */
300 return input_callback (w
, msg
, parm
);
305 command_new (int y
, int x
, int cols
)
309 cmd
= input_new (y
, x
, DEFAULT_COLOR
, cols
, "", "cmdline",
310 INPUT_COMPLETE_DEFAULT
| INPUT_COMPLETE_CD
| INPUT_COMPLETE_COMMANDS
| INPUT_COMPLETE_SHELL_ESC
);
313 cmd
->widget
.callback
= command_callback
;
314 cmd
->completion_flags
|= INPUT_COMPLETE_COMMANDS
;
320 * Insert quoted text in input line. The function is meant for the
321 * command line, so the percent sign is quoted as well.
324 command_insert (WInput
* in
, const char *text
, int insert_extra_space
)
328 quoted_text
= name_quote (text
, 1);
329 stuff (in
, quoted_text
, insert_extra_space
);
330 g_free (quoted_text
);