Ticket #2464: find file: don't check content regexp
[midnight-commander.git] / src / filemanager / command.c
blob497a69ca60ff4c9dbe74c72ab6c6dc95799538df
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.
25 /** \file command.c
26 * \brief Source: command line widget
29 #include <config.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <string.h>
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 */
40 #include "lib/util.h"
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 */
52 #include "command.h"
54 /*** global variables ****************************************************************************/
56 /* This holds the command line */
57 WInput *cmdline;
59 /*** file scope macro definitions ****************************************************************/
61 /*** file scope type declarations ****************************************************************/
63 /*** file scope variables ************************************************************************/
65 /*** file scope functions ************************************************************************/
66 /* --------------------------------------------------------------------------------------------- */
68 /**
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.
79 static int
80 examine_cd (const char *_path)
82 int result, qlen;
83 char *path_tilde, *path;
84 char *p, *q, *r, *s, c;
85 const char *t;
87 /* Tilde expansion */
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;
93 q = g_malloc (qlen);
95 /* Variable expansion */
96 for (p = path_tilde, r = q; *p && r < q + MC_MAXPATHLEN;)
98 if (*p != '$' || (p[1] == '[' || p[1] == '('))
99 *(r++) = *(p++);
100 else
102 p++;
103 if (*p == '{')
105 p++;
106 s = strchr (p, '}');
108 else
109 s = NULL;
110 if (s == NULL)
111 s = strchr (p, PATH_SEP);
112 if (s == NULL)
113 s = strchr (p, 0);
114 c = *s;
115 *s = 0;
116 t = getenv (p);
117 *s = c;
118 if (t == NULL)
120 *(r++) = '$';
121 if (*(p - 1) != '$')
122 *(r++) = '{';
124 else
126 if (r + strlen (t) < q + MC_MAXPATHLEN)
128 strcpy (r, t);
129 r = strchr (r, 0);
131 if (*s == '}')
132 p = s + 1;
133 else
134 p = s;
138 *r = 0;
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"));
146 p = cdpath;
147 if (p == NULL)
148 c = 0;
149 else
150 c = ':';
151 while (!result && c == ':')
153 s = strchr (p, ':');
154 if (s == NULL)
155 s = strchr (p, 0);
156 c = *s;
157 *s = 0;
158 if (*p)
160 r = concat_dir_and_file (p, q);
161 result = do_cd (r, cd_parse_command);
162 g_free (r);
164 *s = c;
165 p = s + 1;
167 g_free (cdpath);
169 g_free (q);
170 g_free (path_tilde);
171 g_free (path);
172 return result;
175 /* --------------------------------------------------------------------------------------------- */
176 /** Handle Enter on the command line */
178 static cb_ret_t
179 enter (WInput * lc_cmdline)
181 char *cmd = lc_cmdline->buffer;
183 if (!command_prompt)
184 return MSG_HANDLED;
186 /* Any initial whitespace should be removed at this point */
187 while (*cmd == ' ' || *cmd == '\t' || *cmd == '\n')
188 cmd++;
190 if (!*cmd)
191 return MSG_HANDLED;
193 if (strncmp (cmd, "cd ", 3) == 0 || strcmp (cmd, "cd") == 0)
195 do_cd_command (cmd);
196 input_clean (lc_cmdline);
197 return MSG_HANDLED;
199 else if (strcmp (cmd, "exit") == 0)
201 input_assign_text (lc_cmdline, "");
202 if (!quiet_quit_cmd ())
203 return MSG_NOT_HANDLED;
205 else
207 char *command, *s;
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;
223 #endif
224 cmd_len = strlen (cmd);
225 command = g_malloc (cmd_len + 1);
226 command[0] = 0;
227 for (i = j = 0; i < cmd_len; i++)
229 if (cmd[i] == '%')
231 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);
235 g_free (s);
236 j = strlen (command);
238 else
240 command[j] = cmd[i];
241 j++;
243 command[j] = 0;
245 input_clean (lc_cmdline);
246 shell_execute (command, 0);
247 g_free (command);
249 #ifdef HAVE_SUBSHELL_SUPPORT
250 if ((quit & SUBSHELL_EXIT) != 0)
252 if (quiet_quit_cmd ())
253 return MSG_HANDLED;
255 quit = 0;
256 /* restart subshell */
257 if (use_subshell)
258 init_subshell ();
261 if (use_subshell)
262 load_prompt (0, NULL);
263 #endif
265 return MSG_HANDLED;
268 /* --------------------------------------------------------------------------------------------- */
270 static cb_ret_t
271 command_callback (Widget * w, widget_msg_t msg, int parm)
273 WInput *cmd = (WInput *) w;
275 switch (msg)
277 case WIDGET_FOCUS:
278 /* Never accept focus, otherwise panels will be unselected */
279 return MSG_NOT_HANDLED;
281 case WIDGET_KEY:
282 /* Special case: we handle the enter key */
283 if (parm == '\n')
285 return enter (cmd);
287 /* fall through */
289 default:
290 return input_callback (w, msg, parm);
294 /* --------------------------------------------------------------------------------------------- */
295 /*** public functions ****************************************************************************/
296 /* --------------------------------------------------------------------------------------------- */
298 /* --------------------------------------------------------------------------------------------- */
299 /** Execute the cd command on the command line */
301 void
302 do_cd_command (char *orig_cmd)
304 int len;
305 const char *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'))
316 orig_cmd[len] = 0;
317 len--;
320 cmd = orig_cmd;
321 if (cmd[2] == 0)
322 cmd = "cd ";
324 if (get_current_type () == view_tree)
326 if (cmd[0] == 0)
328 sync_tree (home_dir);
330 else if (strcmp (cmd + 3, "..") == 0)
332 char *dir = current_panel->cwd;
333 len = strlen (dir);
334 while (len && dir[--len] != PATH_SEP);
335 dir[len] = 0;
336 if (len)
337 sync_tree (dir);
338 else
339 sync_tree (PATH_SEP_STR);
341 else if (cmd[3] == PATH_SEP)
343 sync_tree (cmd + 3);
345 else
347 char *old = current_panel->cwd;
348 char *new;
349 new = concat_dir_and_file (old, cmd + 3);
350 sync_tree (new);
351 g_free (new);
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));
358 g_free (d);
359 return;
363 /* --------------------------------------------------------------------------------------------- */
365 WInput *
366 command_new (int y, int x, int cols)
368 WInput *cmd;
369 const input_colors_t command_colors = {
370 DEFAULT_COLOR,
371 COMMAND_MARK_COLOR,
372 DEFAULT_COLOR,
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);
380 /* Add our hooks */
381 cmd->widget.callback = command_callback;
383 return cmd;
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.
392 void
393 command_insert (WInput * in, const char *text, gboolean insert_extra_space)
395 char *quoted_text;
397 quoted_text = name_quote (text, 1);
398 input_insert (in, quoted_text, insert_extra_space);
399 g_free (quoted_text);
402 /* --------------------------------------------------------------------------------------------- */