another typo: too late at light corrections...:-(
[midnight-commander.git] / src / command.c
blobb8f6f41974e9ccb7c38ec853fde5d43dd3fe55a3
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 "dlg.h"
30 #include "widget.h"
31 #include "command.h"
32 #include "complete.h" /* completion constants */
33 #include "dialog.h" /* message () */
34 #include "dir.h" /* required by panel.h */
35 #include "panel.h" /* view_tree enum. Also, needed by main.h */
36 #include "main.h" /* do_cd */
37 #include "layout.h" /* for command_prompt variable */
38 #include "user.h" /* expand_format */
39 #include "subshell.h"
40 #include "tree.h" /* for tree_chdir */
41 #include "color.h"
42 #include "../vfs/vfs.h"
44 /* This holds the command line */
45 WInput *cmdline;
47 /*Tries variable substitution, and if a variable CDPATH
48 of the form e.g. CDPATH=".:~:/usr" exists, we try then all the paths which
49 are mentioned there. Also, we do not support such extraordinary things as
50 ${var:-value}, etc. Use the eval cd 'path' command instead.
51 Bugs: No quoting occurrs here, so ${VAR} and $VAR will be always
52 substituted. I think we can encourage users to use in such extreme
53 cases instead of >cd path< command a >eval cd 'path'< command, which works
54 as they might expect :)
55 FIXME: Perhaps we should do wildcard matching as well? */
56 static int examine_cd (char *path)
58 char *p;
59 int result;
60 char *q, *r, *s, *t, c;
62 q = g_malloc (MC_MAXPATHLEN + 10);
63 /* Variable expansion */
64 for (p = path, r = q; *p && r < q + MC_MAXPATHLEN; ) {
65 if (*p != '$' || (p [1] == '[' || p [1] == '('))
66 *(r++)=*(p++);
67 else {
68 p++;
69 if (*p == '{') {
70 p++;
71 s = strchr (p, '}');
72 } else
73 s = NULL;
74 if (s == NULL)
75 s = strchr (p, PATH_SEP);
76 if (s == NULL)
77 s = strchr (p, 0);
78 c = *s;
79 *s = 0;
80 t = getenv (p);
81 *s = c;
82 if (t == NULL) {
83 *(r++) = '$';
84 if (*(p - 1) != '$')
85 *(r++) = '{';
86 } else {
87 if (r + strlen (t) < q + MC_MAXPATHLEN) {
88 strcpy (r, t);
89 r = strchr (r, 0);
91 if (*s == '}')
92 p = s + 1;
93 else
94 p = s;
98 *r = 0;
100 result = do_cd (q, cd_parse_command);
102 /* CDPATH handling */
103 if (*q != PATH_SEP && !result) {
104 p = getenv ("CDPATH");
105 if (p == NULL)
106 c = 0;
107 else
108 c = ':';
109 while (!result && c == ':') {
110 s = strchr (p, ':');
111 if (s == NULL)
112 s = strchr (p, 0);
113 c = *s;
114 *s = 0;
115 if (*p) {
116 r = concat_dir_and_file (p, q);
117 result = do_cd (r, cd_parse_command);
118 g_free (r);
120 *s = c;
121 p = s + 1;
124 g_free (q);
125 return result;
128 /* Execute the cd command on the command line */
129 void do_cd_command (char *cmd)
131 int len;
133 /* Any final whitespace should be removed here
134 (to see why, try "cd fred "). */
135 /* NOTE: I think we should not remove the extra space,
136 that way, we can cd into hidden directories */
137 len = strlen (cmd) - 1;
138 while (len >= 0 &&
139 (cmd [len] == ' ' || cmd [len] == '\t' || cmd [len] == '\n')){
140 cmd [len] = 0;
141 len --;
144 if (cmd [2] == 0)
145 cmd = "cd ";
147 if (get_current_type () == view_tree){
148 if (cmd [0] == 0){
149 sync_tree (home_dir);
150 } else if (strcmp (cmd+3, "..") == 0){
151 char *dir = cpanel->cwd;
152 int len = strlen (dir);
153 while (len && dir [--len] != PATH_SEP);
154 dir [len] = 0;
155 if (len)
156 sync_tree (dir);
157 else
158 sync_tree (PATH_SEP_STR);
159 } else if (cmd [3] == PATH_SEP){
160 sync_tree (cmd+3);
161 } else {
162 char *old = cpanel->cwd;
163 char *new;
164 new = concat_dir_and_file (old, cmd+3);
165 sync_tree (new);
166 g_free (new);
168 } else
169 if (!examine_cd (&cmd [3])) {
170 message (1, MSG_ERROR, _(" Cannot chdir to '%s' \n %s "),
171 &cmd [3], unix_error_string (errno));
172 return;
176 /* Returns 1 if the we could handle the enter, 0 if not */
177 static int
178 enter (WInput * cmdline)
180 Dlg_head *old_dlg;
182 if (command_prompt && strlen (cmdline->buffer)) {
183 char *cmd;
185 /* Any initial whitespace should be removed at this point */
186 cmd = cmdline->buffer;
187 while (*cmd == ' ' || *cmd == '\t' || *cmd == '\n')
188 cmd++;
190 if (strncmp (cmd, "cd ", 3) == 0 || strcmp (cmd, "cd") == 0) {
191 do_cd_command (cmd);
192 new_input (cmdline);
193 return MSG_HANDLED;
194 } else {
195 char *command, *s;
196 int i, j;
198 if (!vfs_current_is_local ()) {
199 message (1, MSG_ERROR,
201 (" You can not execute commands on non-local filesystems"));
203 return MSG_NOT_HANDLED;
205 command = g_malloc (strlen (cmd) + 1);
206 command[0] = 0;
207 for (i = j = 0; i < strlen (cmd); i++) {
208 if (cmd[i] == '%') {
209 i++;
210 s = expand_format (NULL, cmd[i], 1);
211 command =
212 g_realloc (command, strlen (command) + strlen (s)
213 + strlen (cmd) - i + 1);
214 strcat (command, s);
215 g_free (s);
216 j = strlen (command);
217 } else {
218 command[j] = cmd[i];
219 j++;
221 command[j] = 0;
223 old_dlg = current_dlg;
224 current_dlg = 0;
225 new_input (cmdline);
226 execute (command);
227 g_free (command);
229 #ifdef HAVE_SUBSHELL_SUPPORT
230 if (quit & SUBSHELL_EXIT) {
231 quiet_quit_cmd ();
232 return MSG_HANDLED;
234 if (use_subshell)
235 load_prompt (0, 0);
236 #endif
238 current_dlg = old_dlg;
241 return MSG_HANDLED;
244 static int
245 command_callback (Dlg_head * h, WInput * cmd, int msg, int par)
247 switch (msg) {
248 case WIDGET_FOCUS:
249 /* Never accept focus, otherwise panels will be unselected */
250 return MSG_NOT_HANDLED;
252 case WIDGET_KEY:
253 /* Special case: we handle the enter key */
254 if (par == '\n') {
255 return enter (cmd);
258 return input_callback (h, cmd, msg, par);
261 WInput *
262 command_new (int y, int x, int cols)
264 WInput *cmd = g_new (WInput, 1);
266 cmd = input_new (y, x, DEFAULT_COLOR, cols, "", "cmdline");
268 /* Add our hooks */
269 cmd->widget.callback = (callback_fn) command_callback;
270 cmd->completion_flags |= INPUT_COMPLETE_COMMANDS;
272 return cmd;
276 * Insert quoted text in input line. The function is meant for the
277 * command line, so the percent sign is quoted as well.
279 void
280 command_insert (WInput * in, char *text, int insert_extra_space)
282 char *quoted_text;
284 quoted_text = name_quote (text, 1);
285 stuff (in, quoted_text, insert_extra_space);
286 g_free (quoted_text);