added new parameter mcview_eof into ini-file
[free-mc.git] / src / command.c
blobd8f6956d12ec08c083ff0a6170f80864309965fe
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 "global.h" /* home_dir */
36 #include "../src/tty/tty.h"
37 #include "../vfs/vfs.h"
38 #include "widget.h" /* WInput */
39 #include "command.h"
40 #include "wtools.h" /* message () */
41 #include "panel.h" /* view_tree enum. Also, needed by main.h */
42 #include "main.h" /* do_cd */
43 #include "layout.h" /* for command_prompt variable */
44 #include "user.h" /* expand_format */
45 #include "subshell.h" /* SUBSHELL_EXIT */
46 #include "tree.h" /* for tree_chdir */
47 #include "../src/skin/skin.h" /* DEFAULT_COLOR */
48 #include "execute.h" /* shell_execute */
49 #include "../src/strescape.h"
51 /* This holds the command line */
52 WInput *cmdline;
55 * Expand the argument to "cd" and change directory. First try tilde
56 * expansion, then variable substitution. If the CDPATH variable is set
57 * (e.g. CDPATH=".:~:/usr"), try all the paths contained there.
58 * We do not support such rare substitutions as ${var:-value} etc.
59 * No quoting is implemented here, so ${VAR} and $VAR will be always
60 * substituted. Wildcards are not supported either.
61 * Advanced users should be encouraged to use "\cd" instead of "cd" if
62 * they want the behavior they are used to in the shell.
64 static int
65 examine_cd (const char *_path)
67 int result, qlen;
68 char *path_tilde, *path;
69 char *p, *q, *r, *s, c;
70 const char *t;
72 /* Tilde expansion */
73 path = strutils_shell_unescape(_path);
74 path_tilde = tilde_expand (path);
76 /* Leave space for further expansion */
77 qlen = strlen (path_tilde) + MC_MAXPATHLEN;
78 q = g_malloc (qlen);
80 /* Variable expansion */
81 for (p = path_tilde, r = q; *p && r < q + MC_MAXPATHLEN;) {
82 if (*p != '$' || (p[1] == '[' || p[1] == '('))
83 *(r++) = *(p++);
84 else {
85 p++;
86 if (*p == '{') {
87 p++;
88 s = strchr (p, '}');
89 } else
90 s = NULL;
91 if (s == NULL)
92 s = strchr (p, PATH_SEP);
93 if (s == NULL)
94 s = strchr (p, 0);
95 c = *s;
96 *s = 0;
97 t = getenv (p);
98 *s = c;
99 if (t == NULL) {
100 *(r++) = '$';
101 if (*(p - 1) != '$')
102 *(r++) = '{';
103 } else {
104 if (r + strlen (t) < q + MC_MAXPATHLEN) {
105 strcpy (r, t);
106 r = strchr (r, 0);
108 if (*s == '}')
109 p = s + 1;
110 else
111 p = s;
115 *r = 0;
117 result = do_cd (q, cd_parse_command);
119 /* CDPATH handling */
120 if (*q != PATH_SEP && !result) {
121 char * const cdpath = g_strdup (getenv ("CDPATH"));
122 p = cdpath;
123 if (p == NULL)
124 c = 0;
125 else
126 c = ':';
127 while (!result && c == ':') {
128 s = strchr (p, ':');
129 if (s == NULL)
130 s = strchr (p, 0);
131 c = *s;
132 *s = 0;
133 if (*p) {
134 r = concat_dir_and_file (p, q);
135 result = do_cd (r, cd_parse_command);
136 g_free (r);
138 *s = c;
139 p = s + 1;
141 g_free (cdpath);
143 g_free (q);
144 g_free (path_tilde);
145 g_free (path);
146 return result;
149 /* Execute the cd command on the command line */
150 void do_cd_command (char * orig_cmd)
152 int len;
153 const char * cmd;
155 /* Any final whitespace should be removed here
156 (to see why, try "cd fred "). */
157 /* NOTE: I think we should not remove the extra space,
158 that way, we can cd into hidden directories */
159 /* FIXME: what about interpreting quoted strings like the shell.
160 so one could type "cd <tab> M-a <enter>" and it would work. */
161 len = strlen (orig_cmd) - 1;
162 while (len >= 0 &&
163 (orig_cmd [len] == ' ' || orig_cmd [len] == '\t' || orig_cmd [len] == '\n')){
164 orig_cmd [len] = 0;
165 len --;
168 cmd = orig_cmd;
169 if (cmd [2] == 0)
170 cmd = "cd ";
172 if (get_current_type () == view_tree){
173 if (cmd [0] == 0){
174 sync_tree (home_dir);
175 } else if (strcmp (cmd+3, "..") == 0){
176 char *dir = current_panel->cwd;
177 len = strlen (dir);
178 while (len && dir [--len] != PATH_SEP);
179 dir [len] = 0;
180 if (len)
181 sync_tree (dir);
182 else
183 sync_tree (PATH_SEP_STR);
184 } else if (cmd [3] == PATH_SEP){
185 sync_tree (cmd+3);
186 } else {
187 char *old = current_panel->cwd;
188 char *new;
189 new = concat_dir_and_file (old, cmd+3);
190 sync_tree (new);
191 g_free (new);
193 } else
194 if (!examine_cd (&cmd [3])) {
195 char *d = strip_password (g_strdup (&cmd [3]), 1);
196 message (D_ERROR, MSG_ERROR, _(" Cannot chdir to \"%s\" \n %s "),
197 d, unix_error_string (errno));
198 g_free (d);
199 return;
203 /* Handle Enter on the command line */
204 static cb_ret_t
205 enter (WInput *lc_cmdline)
207 char *cmd = lc_cmdline->buffer;
209 if (!command_prompt)
210 return MSG_HANDLED;
212 /* Any initial whitespace should be removed at this point */
213 while (*cmd == ' ' || *cmd == '\t' || *cmd == '\n')
214 cmd++;
216 if (!*cmd)
217 return MSG_HANDLED;
219 if (strncmp (cmd, "cd ", 3) == 0 || strcmp (cmd, "cd") == 0) {
220 do_cd_command (cmd);
221 new_input (lc_cmdline);
222 return MSG_HANDLED;
223 } else {
224 char *command, *s;
225 size_t i, j, cmd_len;
227 if (!vfs_current_is_local ()) {
228 if (strcmp (cmd, "exit") == 0) {
229 quiet_quit_cmd ();
230 return MSG_HANDLED;
233 message (D_ERROR, MSG_ERROR,
235 (" Cannot execute commands on non-local filesystems"));
237 return MSG_NOT_HANDLED;
239 #ifdef HAVE_SUBSHELL_SUPPORT
240 /* Check this early before we clean command line
241 * (will be checked again by shell_execute) */
242 if (use_subshell && subshell_state != INACTIVE) {
243 message (D_ERROR, MSG_ERROR,
244 _(" The shell is already running a command "));
245 return MSG_NOT_HANDLED;
247 #endif
248 cmd_len = strlen (cmd);
249 command = g_malloc (cmd_len + 1);
250 command[0] = 0;
251 for (i = j = 0; i < cmd_len; i++) {
252 if (cmd[i] == '%') {
253 i++;
254 s = expand_format (NULL, cmd[i], 1);
255 command = g_realloc (command, j + strlen (s) + cmd_len - i + 1);
256 strcpy (command + j, s);
257 g_free (s);
258 j = strlen (command);
259 } else {
260 command[j] = cmd[i];
261 j++;
263 command[j] = 0;
265 new_input (lc_cmdline);
266 shell_execute (command, 0);
267 g_free (command);
269 #ifdef HAVE_SUBSHELL_SUPPORT
270 if (quit & SUBSHELL_EXIT) {
271 quiet_quit_cmd ();
272 return MSG_HANDLED;
274 if (use_subshell)
275 load_prompt (0, 0);
276 #endif
278 return MSG_HANDLED;
281 static cb_ret_t
282 command_callback (Widget *w, widget_msg_t msg, int parm)
284 WInput *cmd = (WInput *) w;
286 switch (msg) {
287 case WIDGET_FOCUS:
288 /* Never accept focus, otherwise panels will be unselected */
289 return MSG_NOT_HANDLED;
291 case WIDGET_KEY:
292 /* Special case: we handle the enter key */
293 if (parm == '\n') {
294 return enter (cmd);
296 /* fall through */
298 default:
299 return input_callback (w, msg, parm);
303 WInput *
304 command_new (int y, int x, int cols)
306 WInput *cmd;
308 cmd = input_new (y, x, DEFAULT_COLOR, cols, "", "cmdline",
309 INPUT_COMPLETE_DEFAULT | INPUT_COMPLETE_CD | INPUT_COMPLETE_COMMANDS | INPUT_COMPLETE_SHELL_ESC);
311 /* Add our hooks */
312 cmd->widget.callback = command_callback;
313 cmd->completion_flags |= INPUT_COMPLETE_COMMANDS;
315 return cmd;
319 * Insert quoted text in input line. The function is meant for the
320 * command line, so the percent sign is quoted as well.
322 void
323 command_insert (WInput * in, const char *text, int insert_extra_space)
325 char *quoted_text;
327 quoted_text = name_quote (text, 1);
328 stuff (in, quoted_text, insert_extra_space);
329 g_free (quoted_text);