Just a little correction at the it.po file.
[midnight-commander.git] / src / command.c
blob6024adf0116b38b2a3aea3090894a4151506e5ef
1 /* Command line widget.
2 Copyright (C) 1995 Miguel de Icaza
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 This widget is derived from the WInput widget, it's used to cope
19 with all the magic of the command input line, we depend on some
20 help from the program's callback.
24 #include <config.h>
25 #include <errno.h>
26 #include <string.h>
27 #include "global.h" /* home_dir */
28 #include "tty.h"
29 #include "widget.h" /* WInput */
30 #include "command.h"
31 #include "complete.h" /* completion constants */
32 #include "wtools.h" /* message () */
33 #include "panel.h" /* view_tree enum. Also, needed by main.h */
34 #include "main.h" /* do_cd */
35 #include "layout.h" /* for command_prompt variable */
36 #include "user.h" /* expand_format */
37 #include "subshell.h" /* SUBSHELL_EXIT */
38 #include "tree.h" /* for tree_chdir */
39 #include "color.h" /* DEFAULT_COLOR */
41 /* This holds the command line */
42 WInput *cmdline;
44 /*Tries variable substitution, and if a variable CDPATH
45 of the form e.g. CDPATH=".:~:/usr" exists, we try then all the paths which
46 are mentioned there. Also, we do not support such extraordinary things as
47 ${var:-value}, etc. Use the eval cd 'path' command instead.
48 Bugs: No quoting occurrs here, so ${VAR} and $VAR will be always
49 substituted. I think we can encourage users to use in such extreme
50 cases instead of >cd path< command a >eval cd 'path'< command, which works
51 as they might expect :)
52 FIXME: Perhaps we should do wildcard matching as well? */
53 static int examine_cd (char *path)
55 char *p;
56 int result;
57 char *q, *r, *s, *t, c;
59 q = g_malloc (MC_MAXPATHLEN + 10);
60 /* Variable expansion */
61 for (p = path, r = q; *p && r < q + MC_MAXPATHLEN; ) {
62 if (*p != '$' || (p [1] == '[' || p [1] == '('))
63 *(r++)=*(p++);
64 else {
65 p++;
66 if (*p == '{') {
67 p++;
68 s = strchr (p, '}');
69 } else
70 s = NULL;
71 if (s == NULL)
72 s = strchr (p, PATH_SEP);
73 if (s == NULL)
74 s = strchr (p, 0);
75 c = *s;
76 *s = 0;
77 t = getenv (p);
78 *s = c;
79 if (t == NULL) {
80 *(r++) = '$';
81 if (*(p - 1) != '$')
82 *(r++) = '{';
83 } else {
84 if (r + strlen (t) < q + MC_MAXPATHLEN) {
85 strcpy (r, t);
86 r = strchr (r, 0);
88 if (*s == '}')
89 p = s + 1;
90 else
91 p = s;
95 *r = 0;
97 result = do_cd (q, cd_parse_command);
99 /* CDPATH handling */
100 if (*q != PATH_SEP && !result) {
101 p = getenv ("CDPATH");
102 if (p == NULL)
103 c = 0;
104 else
105 c = ':';
106 while (!result && c == ':') {
107 s = strchr (p, ':');
108 if (s == NULL)
109 s = strchr (p, 0);
110 c = *s;
111 *s = 0;
112 if (*p) {
113 r = concat_dir_and_file (p, q);
114 result = do_cd (r, cd_parse_command);
115 g_free (r);
117 *s = c;
118 p = s + 1;
121 g_free (q);
122 return result;
125 /* Execute the cd command on the command line */
126 void do_cd_command (char *cmd)
128 int len;
130 /* Any final whitespace should be removed here
131 (to see why, try "cd fred "). */
132 /* NOTE: I think we should not remove the extra space,
133 that way, we can cd into hidden directories */
134 len = strlen (cmd) - 1;
135 while (len >= 0 &&
136 (cmd [len] == ' ' || cmd [len] == '\t' || cmd [len] == '\n')){
137 cmd [len] = 0;
138 len --;
141 if (cmd [2] == 0)
142 cmd = "cd ";
144 if (get_current_type () == view_tree){
145 if (cmd [0] == 0){
146 sync_tree (home_dir);
147 } else if (strcmp (cmd+3, "..") == 0){
148 char *dir = cpanel->cwd;
149 int len = strlen (dir);
150 while (len && dir [--len] != PATH_SEP);
151 dir [len] = 0;
152 if (len)
153 sync_tree (dir);
154 else
155 sync_tree (PATH_SEP_STR);
156 } else if (cmd [3] == PATH_SEP){
157 sync_tree (cmd+3);
158 } else {
159 char *old = cpanel->cwd;
160 char *new;
161 new = concat_dir_and_file (old, cmd+3);
162 sync_tree (new);
163 g_free (new);
165 } else
166 if (!examine_cd (&cmd [3])) {
167 message (1, MSG_ERROR, _(" Cannot chdir to \"%s\" \n %s "),
168 &cmd [3], unix_error_string (errno));
169 return;
173 /* Returns 1 if the we could handle the enter, 0 if not */
174 static int
175 enter (WInput *cmdline)
177 Dlg_head *old_dlg;
179 if (command_prompt && strlen (cmdline->buffer)) {
180 char *cmd;
182 /* Any initial whitespace should be removed at this point */
183 cmd = cmdline->buffer;
184 while (*cmd == ' ' || *cmd == '\t' || *cmd == '\n')
185 cmd++;
187 if (strncmp (cmd, "cd ", 3) == 0 || strcmp (cmd, "cd") == 0) {
188 do_cd_command (cmd);
189 new_input (cmdline);
190 return MSG_HANDLED;
191 } else {
192 char *command, *s;
193 int i, j;
195 if (!vfs_current_is_local ()) {
196 message (1, MSG_ERROR,
198 (" Cannot execute commands on non-local filesystems"));
200 return MSG_NOT_HANDLED;
202 #ifdef HAVE_SUBSHELL_SUPPORT
203 /* Check this early before we clean command line
204 * (will be checked again by shell_execute) */
205 if (use_subshell && subshell_state != INACTIVE) {
206 message (1, MSG_ERROR,
207 _(" The shell is already running a command "));
208 return MSG_NOT_HANDLED;
210 #endif
212 command = g_malloc (strlen (cmd) + 1);
213 command[0] = 0;
214 for (i = j = 0; i < strlen (cmd); i++) {
215 if (cmd[i] == '%') {
216 i++;
217 s = expand_format (NULL, cmd[i], 1);
218 command =
219 g_realloc (command, strlen (command) + strlen (s)
220 + strlen (cmd) - i + 1);
221 strcat (command, s);
222 g_free (s);
223 j = strlen (command);
224 } else {
225 command[j] = cmd[i];
226 j++;
228 command[j] = 0;
230 old_dlg = current_dlg;
231 current_dlg = 0;
232 new_input (cmdline);
233 execute (command);
234 g_free (command);
236 #ifdef HAVE_SUBSHELL_SUPPORT
237 if (quit & SUBSHELL_EXIT) {
238 quiet_quit_cmd ();
239 return MSG_HANDLED;
241 if (use_subshell)
242 load_prompt (0, 0);
243 #endif
245 current_dlg = old_dlg;
248 return MSG_HANDLED;
251 static int
252 command_callback (WInput *cmd, int msg, int par)
254 switch (msg) {
255 case WIDGET_FOCUS:
256 /* Never accept focus, otherwise panels will be unselected */
257 return MSG_NOT_HANDLED;
259 case WIDGET_KEY:
260 /* Special case: we handle the enter key */
261 if (par == '\n') {
262 return enter (cmd);
265 return input_callback (cmd, msg, par);
268 WInput *
269 command_new (int y, int x, int cols)
271 WInput *cmd = g_new (WInput, 1);
273 cmd = input_new (y, x, DEFAULT_COLOR, cols, "", "cmdline");
275 /* Add our hooks */
276 cmd->widget.callback = (callback_fn) command_callback;
277 cmd->completion_flags |= INPUT_COMPLETE_COMMANDS;
279 return cmd;
283 * Insert quoted text in input line. The function is meant for the
284 * command line, so the percent sign is quoted as well.
286 void
287 command_insert (WInput * in, char *text, int insert_extra_space)
289 char *quoted_text;
291 quoted_text = name_quote (text, 1);
292 stuff (in, quoted_text, insert_extra_space);
293 g_free (quoted_text);