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"
39 #include "lib/skin.h" /* DEFAULT_COLOR */
41 #include "lib/widget.h"
43 #include "src/main.h" /* do_cd */
44 #include "src/subshell.h" /* SUBSHELL_EXIT */
45 #include "src/execute.h" /* shell_execute */
47 #include "midnight.h" /* current_panel */
48 #include "layout.h" /* for command_prompt variable */
49 #include "usermenu.h" /* expand_format */
50 #include "tree.h" /* for tree_chdir */
54 /*** global variables ****************************************************************************/
56 /* This holds the command line */
59 /*** file scope macro definitions ****************************************************************/
61 /*** file scope type declarations ****************************************************************/
63 /*** file scope variables ************************************************************************/
65 /*** file scope functions ************************************************************************/
66 /* --------------------------------------------------------------------------------------------- */
69 * Expand the argument to "cd" and change directory. First try tilde
70 * expansion, then variable substitution. If the CDPATH variable is set
71 * (e.g. CDPATH=".:~:/usr"), try all the paths contained there.
72 * We do not support such rare substitutions as ${var:-value} etc.
73 * No quoting is implemented here, so ${VAR} and $VAR will be always
74 * substituted. Wildcards are not supported either.
75 * Advanced users should be encouraged to use "\cd" instead of "cd" if
76 * they want the behavior they are used to in the shell.
80 examine_cd (const char *_path
)
83 char *path_tilde
, *path
;
84 char *p
, *q
, *r
, *s
, c
;
88 path
= strutils_shell_unescape (_path
);
89 path_tilde
= tilde_expand (path
);
91 /* Leave space for further expansion */
92 qlen
= strlen (path_tilde
) + MC_MAXPATHLEN
;
95 /* Variable expansion */
96 for (p
= path_tilde
, r
= q
; *p
&& r
< q
+ MC_MAXPATHLEN
;)
98 if (*p
!= '$' || (p
[1] == '[' || p
[1] == '('))
111 s
= strchr (p
, PATH_SEP
);
126 if (r
+ strlen (t
) < q
+ MC_MAXPATHLEN
)
140 result
= do_cd (q
, cd_parse_command
);
142 /* CDPATH handling */
143 if (*q
!= PATH_SEP
&& !result
)
145 char *const cdpath
= g_strdup (getenv ("CDPATH"));
151 while (!result
&& c
== ':')
160 r
= concat_dir_and_file (p
, q
);
161 result
= do_cd (r
, cd_parse_command
);
175 /* --------------------------------------------------------------------------------------------- */
176 /** Handle Enter on the command line */
179 enter (WInput
* lc_cmdline
)
181 char *cmd
= lc_cmdline
->buffer
;
186 /* Any initial whitespace should be removed at this point */
187 while (*cmd
== ' ' || *cmd
== '\t' || *cmd
== '\n')
193 if (strncmp (cmd
, "cd ", 3) == 0 || strcmp (cmd
, "cd") == 0)
196 input_clean (lc_cmdline
);
199 else if (strcmp (cmd
, "exit") == 0)
201 input_assign_text (lc_cmdline
, "");
202 if (!quiet_quit_cmd ())
203 return MSG_NOT_HANDLED
;
208 size_t i
, j
, cmd_len
;
210 if (!vfs_current_is_local ())
212 message (D_ERROR
, MSG_ERROR
, _("Cannot execute commands on non-local filesystems"));
213 return MSG_NOT_HANDLED
;
215 #ifdef HAVE_SUBSHELL_SUPPORT
216 /* Check this early before we clean command line
217 * (will be checked again by shell_execute) */
218 if (use_subshell
&& subshell_state
!= INACTIVE
)
220 message (D_ERROR
, MSG_ERROR
, _("The shell is already running a command"));
221 return MSG_NOT_HANDLED
;
224 cmd_len
= strlen (cmd
);
225 command
= g_malloc (cmd_len
+ 1);
227 for (i
= j
= 0; i
< cmd_len
; i
++)
232 s
= expand_format (NULL
, cmd
[i
], TRUE
);
233 command
= g_realloc (command
, j
+ strlen (s
) + cmd_len
- i
+ 1);
234 strcpy (command
+ j
, s
);
236 j
= strlen (command
);
245 input_clean (lc_cmdline
);
246 shell_execute (command
, 0);
249 #ifdef HAVE_SUBSHELL_SUPPORT
250 if ((quit
& SUBSHELL_EXIT
) != 0)
252 if (quiet_quit_cmd ())
256 /* restart subshell */
262 load_prompt (0, NULL
);
268 /* --------------------------------------------------------------------------------------------- */
271 command_callback (Widget
* w
, widget_msg_t msg
, int parm
)
273 WInput
*cmd
= (WInput
*) w
;
278 /* Never accept focus, otherwise panels will be unselected */
279 return MSG_NOT_HANDLED
;
282 /* Special case: we handle the enter key */
290 return input_callback (w
, msg
, parm
);
294 /* --------------------------------------------------------------------------------------------- */
295 /*** public functions ****************************************************************************/
296 /* --------------------------------------------------------------------------------------------- */
298 /* --------------------------------------------------------------------------------------------- */
299 /** Execute the cd command on the command line */
302 do_cd_command (char *orig_cmd
)
307 /* Any final whitespace should be removed here
308 (to see why, try "cd fred "). */
309 /* NOTE: I think we should not remove the extra space,
310 that way, we can cd into hidden directories */
311 /* FIXME: what about interpreting quoted strings like the shell.
312 so one could type "cd <tab> M-a <enter>" and it would work. */
313 len
= strlen (orig_cmd
) - 1;
314 while (len
>= 0 && (orig_cmd
[len
] == ' ' || orig_cmd
[len
] == '\t' || orig_cmd
[len
] == '\n'))
324 if (get_current_type () == view_tree
)
328 sync_tree (home_dir
);
330 else if (strcmp (cmd
+ 3, "..") == 0)
332 char *dir
= current_panel
->cwd
;
334 while (len
&& dir
[--len
] != PATH_SEP
);
339 sync_tree (PATH_SEP_STR
);
341 else if (cmd
[3] == PATH_SEP
)
347 char *old
= current_panel
->cwd
;
349 new = concat_dir_and_file (old
, cmd
+ 3);
354 else if (!examine_cd (&cmd
[3]))
356 char *d
= strip_password (g_strdup (&cmd
[3]), 1);
357 message (D_ERROR
, MSG_ERROR
, _("Cannot chdir to \"%s\"\n%s"), d
, unix_error_string (errno
));
363 /* --------------------------------------------------------------------------------------------- */
366 command_new (int y
, int x
, int cols
)
369 const input_colors_t command_colors
= {
373 COMMAND_HISTORY_COLOR
376 cmd
= input_new (y
, x
, (int *) command_colors
, cols
, "", "cmdline",
377 INPUT_COMPLETE_DEFAULT
| INPUT_COMPLETE_CD
| INPUT_COMPLETE_COMMANDS
|
378 INPUT_COMPLETE_SHELL_ESC
);
381 cmd
->widget
.callback
= command_callback
;
386 /* --------------------------------------------------------------------------------------------- */
388 * Insert quoted text in input line. The function is meant for the
389 * command line, so the percent sign is quoted as well.
393 command_insert (WInput
* in
, const char *text
, gboolean insert_extra_space
)
397 quoted_text
= name_quote (text
, 1);
398 input_insert (in
, quoted_text
, insert_extra_space
);
399 g_free (quoted_text
);
402 /* --------------------------------------------------------------------------------------------- */