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 "global.h" /* home_dir */
36 #include "../src/tty/tty.h"
37 #include "widget.h" /* WInput */
39 #include "wtools.h" /* message () */
40 #include "panel.h" /* view_tree enum. Also, needed by main.h */
41 #include "main.h" /* do_cd */
42 #include "layout.h" /* for command_prompt variable */
43 #include "user.h" /* expand_format */
44 #include "subshell.h" /* SUBSHELL_EXIT */
45 #include "tree.h" /* for tree_chdir */
46 #include "../src/skin/skin.h" /* DEFAULT_COLOR */
47 #include "execute.h" /* shell_execute */
48 #include "../src/strescape.h"
50 /* This holds the command line */
54 * Expand the argument to "cd" and change directory. First try tilde
55 * expansion, then variable substitution. If the CDPATH variable is set
56 * (e.g. CDPATH=".:~:/usr"), try all the paths contained there.
57 * We do not support such rare substitutions as ${var:-value} etc.
58 * No quoting is implemented here, so ${VAR} and $VAR will be always
59 * substituted. Wildcards are not supported either.
60 * Advanced users should be encouraged to use "\cd" instead of "cd" if
61 * they want the behavior they are used to in the shell.
64 examine_cd (const char *_path
)
67 char *path_tilde
, *path
;
68 char *p
, *q
, *r
, *s
, c
;
72 path
= strutils_shell_unescape(_path
);
73 path_tilde
= tilde_expand (path
);
75 /* Leave space for further expansion */
76 qlen
= strlen (path_tilde
) + MC_MAXPATHLEN
;
79 /* Variable expansion */
80 for (p
= path_tilde
, r
= q
; *p
&& r
< q
+ MC_MAXPATHLEN
;) {
81 if (*p
!= '$' || (p
[1] == '[' || p
[1] == '('))
91 s
= strchr (p
, PATH_SEP
);
103 if (r
+ strlen (t
) < q
+ MC_MAXPATHLEN
) {
116 result
= do_cd (q
, cd_parse_command
);
118 /* CDPATH handling */
119 if (*q
!= PATH_SEP
&& !result
) {
120 char * const cdpath
= g_strdup (getenv ("CDPATH"));
126 while (!result
&& c
== ':') {
133 r
= concat_dir_and_file (p
, q
);
134 result
= do_cd (r
, cd_parse_command
);
148 /* Execute the cd command on the command line */
149 void do_cd_command (char * orig_cmd
)
154 /* Any final whitespace should be removed here
155 (to see why, try "cd fred "). */
156 /* NOTE: I think we should not remove the extra space,
157 that way, we can cd into hidden directories */
158 /* FIXME: what about interpreting quoted strings like the shell.
159 so one could type "cd <tab> M-a <enter>" and it would work. */
160 len
= strlen (orig_cmd
) - 1;
162 (orig_cmd
[len
] == ' ' || orig_cmd
[len
] == '\t' || orig_cmd
[len
] == '\n')){
171 if (get_current_type () == view_tree
){
173 sync_tree (home_dir
);
174 } else if (strcmp (cmd
+3, "..") == 0){
175 char *dir
= current_panel
->cwd
;
177 while (len
&& dir
[--len
] != PATH_SEP
);
182 sync_tree (PATH_SEP_STR
);
183 } else if (cmd
[3] == PATH_SEP
){
186 char *old
= current_panel
->cwd
;
188 new = concat_dir_and_file (old
, cmd
+3);
193 if (!examine_cd (&cmd
[3])) {
194 char *d
= strip_password (g_strdup (&cmd
[3]), 1);
195 message (D_ERROR
, MSG_ERROR
, _(" Cannot chdir to \"%s\" \n %s "),
196 d
, unix_error_string (errno
));
202 /* Handle Enter on the command line */
204 enter (WInput
*lc_cmdline
)
206 char *cmd
= lc_cmdline
->buffer
;
211 /* Any initial whitespace should be removed at this point */
212 while (*cmd
== ' ' || *cmd
== '\t' || *cmd
== '\n')
218 if (strncmp (cmd
, "cd ", 3) == 0 || strcmp (cmd
, "cd") == 0) {
220 new_input (lc_cmdline
);
224 size_t i
, j
, cmd_len
;
226 if (!vfs_current_is_local ()) {
227 if (strcmp (cmd
, "exit") == 0) {
232 message (D_ERROR
, MSG_ERROR
,
234 (" Cannot execute commands on non-local filesystems"));
236 return MSG_NOT_HANDLED
;
238 #ifdef HAVE_SUBSHELL_SUPPORT
239 /* Check this early before we clean command line
240 * (will be checked again by shell_execute) */
241 if (use_subshell
&& subshell_state
!= INACTIVE
) {
242 message (D_ERROR
, MSG_ERROR
,
243 _(" The shell is already running a command "));
244 return MSG_NOT_HANDLED
;
247 cmd_len
= strlen (cmd
);
248 command
= g_malloc (cmd_len
+ 1);
250 for (i
= j
= 0; i
< cmd_len
; i
++) {
253 s
= expand_format (NULL
, cmd
[i
], 1);
254 command
= g_realloc (command
, j
+ strlen (s
) + cmd_len
- i
+ 1);
255 strcpy (command
+ j
, s
);
257 j
= strlen (command
);
264 new_input (lc_cmdline
);
265 shell_execute (command
, 0);
268 #ifdef HAVE_SUBSHELL_SUPPORT
269 if (quit
& SUBSHELL_EXIT
) {
281 command_callback (Widget
*w
, widget_msg_t msg
, int parm
)
283 WInput
*cmd
= (WInput
*) w
;
287 /* Never accept focus, otherwise panels will be unselected */
288 return MSG_NOT_HANDLED
;
291 /* Special case: we handle the enter key */
298 return input_callback (w
, msg
, parm
);
303 command_new (int y
, int x
, int cols
)
307 cmd
= input_new (y
, x
, DEFAULT_COLOR
, cols
, "", "cmdline",
308 INPUT_COMPLETE_DEFAULT
| INPUT_COMPLETE_CD
| INPUT_COMPLETE_COMMANDS
| INPUT_COMPLETE_SHELL_ESC
);
311 cmd
->widget
.callback
= command_callback
;
312 cmd
->completion_flags
|= INPUT_COMPLETE_COMMANDS
;
318 * Insert quoted text in input line. The function is meant for the
319 * command line, so the percent sign is quoted as well.
322 command_insert (WInput
* in
, const char *text
, int insert_extra_space
)
326 quoted_text
= name_quote (text
, 1);
327 stuff (in
, quoted_text
, insert_extra_space
);
328 g_free (quoted_text
);