Take care of one BSOD in NtGdiDdCreateDirectDrawObject, it is not correct fix, it...
[reactos.git] / rosapps / mc / src / command.c
1 /* Command line widget.
2 Copyright (C) 1995 Miguel de Icaza
3
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.
8
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.
13
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., 675 Mass Ave, Cambridge, MA 02139, USA.
17
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.
21
22 */
23
24 #include <config.h>
25 #include <errno.h>
26 #include "tty.h"
27 #include "fs.h"
28 #include <malloc.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include "mad.h"
32 #include "dlg.h"
33 #include "widget.h"
34 #include "command.h"
35 #include "complete.h" /* completion constants */
36 #include "global.h" /* home_dir */
37 #include "dialog.h" /* message () */
38 #include "dir.h" /* required by panel.h */
39 #include "panel.h" /* view_tree enum. Also, needed by main.h */
40 #include "main.h" /* do_cd */
41 #include "layout.h" /* for command_prompt variable */
42 #include "user.h" /* expand_format */
43 #include "subshell.h"
44 #include "tree.h" /* for tree_chdir */
45 #include "color.h"
46 #include "../vfs/vfs.h"
47
48 /* This holds the command line */
49 WCommand *cmdline;
50
51 /*Tries variable substitution, and if a variable CDPATH
52 of the form e.g. CDPATH=".:~:/usr" exists, we try then all the paths which
53 are mentioned there. Also, we do not support such extraordinary things as
54 ${var:-value}, etc. Use the eval cd 'path' command instead.
55 Bugs: No quoting occurrs here, so ${VAR} and $VAR will be always
56 substituted. I think we can encourage users to use in such extreme
57 cases instead of >cd path< command a >eval cd 'path'< command, which works
58 as they might expect :)
59 FIXME: Perhaps we should do wildcard matching as well? */
60 static int examine_cd (char *path)
61 {
62 char *p;
63 int result;
64 char *q = xmalloc (MC_MAXPATHLEN + 10, "examine_cd"), *r, *s, *t, c;
65
66 /* Variable expansion */
67 for (p = path, r = q; *p && r < q + MC_MAXPATHLEN; ) {
68 if (*p != '$' || (p [1] == '[' || p [1] == '('))
69 *(r++)=*(p++);
70 else {
71 p++;
72 if (*p == '{') {
73 p++;
74 s = strchr (p, '}');
75 } else
76 s = NULL;
77 if (s == NULL)
78 s = strchr (p, PATH_SEP);
79 if (s == NULL)
80 s = strchr (p, 0);
81 c = *s;
82 *s = 0;
83 t = getenv (p);
84 *s = c;
85 if (t == NULL) {
86 *(r++) = '$';
87 if (*(p - 1) != '$')
88 *(r++) = '{';
89 } else {
90 if (r + strlen (t) < q + MC_MAXPATHLEN) {
91 strcpy (r, t);
92 r = strchr (r, 0);
93 }
94 if (*s == '}')
95 p = s + 1;
96 else
97 p = s;
98 }
99 }
100 }
101 *r = 0;
102
103 result = do_cd (q, cd_parse_command);
104
105 /* CDPATH handling */
106 if (*q != PATH_SEP && !result) {
107 p = getenv ("CDPATH");
108 if (p == NULL)
109 c = 0;
110 else
111 c = ':';
112 while (!result && c == ':') {
113 s = strchr (p, ':');
114 if (s == NULL)
115 s = strchr (p, 0);
116 c = *s;
117 *s = 0;
118 if (*p) {
119 r = concat_dir_and_file (p, q);
120 result = do_cd (r, cd_parse_command);
121 free (r);
122 }
123 *s = c;
124 p = s + 1;
125 }
126 }
127 free (q);
128 return result;
129 }
130
131 /* Execute the cd command on the command line */
132 void do_cd_command (char *cmd)
133 {
134 int len;
135
136 /* Any final whitespace should be removed here
137 (to see why, try "cd fred "). */
138 /* NOTE: I think we should not remove the extra space,
139 that way, we can cd into hidden directories */
140 len = strlen (cmd) - 1;
141 while (len >= 0 &&
142 (cmd [len] == ' ' || cmd [len] == '\t' || cmd [len] == '\n')){
143 cmd [len] = 0;
144 len --;
145 }
146
147 if (cmd [2] == 0)
148 cmd = "cd ";
149
150 if (get_current_type () == view_tree){
151 if (cmd [0] == 0){
152 tree_chdir (the_tree, home_dir);
153 } else if (strcmp (cmd+3, "..") == 0){
154 char *dir = cpanel->cwd;
155 int len = strlen (dir);
156 while (len && dir [--len] != PATH_SEP);
157 dir [len] = 0;
158 if (len)
159 tree_chdir (the_tree, dir);
160 else
161 tree_chdir (the_tree, PATH_SEP_STR);
162 } else if (cmd [3] == PATH_SEP){
163 tree_chdir (the_tree, cmd+3);
164 } else {
165 char *old = cpanel->cwd;
166 char *new;
167 new = concat_dir_and_file (old, cmd+3);
168 tree_chdir (the_tree, new);
169 free (new);
170 }
171 } else
172 if (!examine_cd (&cmd [3])) {
173 message (1, MSG_ERROR, _(" Can't chdir to '%s' \n %s "),
174 &cmd [3], unix_error_string (errno));
175 return;
176 }
177 }
178
179 /* Returns 1 if the we could handle the enter, 0 if not */
180 static int enter (WCommand *cmdline)
181 {
182 Dlg_head *old_dlg;
183
184 if (command_prompt && strlen (input_w (cmdline)->buffer)){
185 char *cmd;
186
187 /* Any initial whitespace should be removed at this point */
188 cmd = input_w (cmdline)->buffer;
189 while (*cmd == ' ' || *cmd == '\t' || *cmd == '\n')
190 cmd++;
191
192 if (strncmp (cmd, "cd ", 3) == 0 || strcmp (cmd, "cd") == 0){
193 do_cd_command (cmd);
194 new_input (input_w (cmdline));
195 return MSG_HANDLED;
196 }
197 #ifdef OS2_NT
198 else if ( (strncmp (cmd, "set ", 4) == 0 || strncmp (cmd, "Set ", 4) == 0 || strncmp (cmd, "SET ", 4) == 0) && strchr(cmd,'=') ){
199 cmd+=4;
200 while (*cmd == ' ' || *cmd == '\t' || *cmd == '\n')
201 cmd++;
202 _putenv(cmd);
203 new_input (input_w (cmdline));
204 return MSG_HANDLED;
205 }
206 #endif
207 else {
208 char *command, *s;
209 int i, j;
210
211 if (!vfs_current_is_local ())
212 return MSG_NOT_HANDLED;
213 command = xmalloc (strlen (cmd) + 1, "main, enter");
214 command [0] = 0;
215 for (i = j = 0; i < strlen (cmd); i ++){
216 if (cmd [i] == '%'){
217 i ++;
218 s = expand_format (cmd [i], 1);
219 command = realloc (command, strlen (command) + strlen (s)
220 + strlen (cmd) - i + 1);
221 strcat (command, s);
222 free (s);
223 j = strlen (command);
224 } else {
225 command [j] = cmd [i];
226 j ++;
227 }
228 command [j] = 0;
229 }
230 old_dlg = current_dlg;
231 current_dlg = 0;
232 new_input (input_w (cmdline));
233 execute (command);
234 free (command);
235
236 #ifdef HAVE_SUBSHELL_SUPPORT
237 if (quit & SUBSHELL_EXIT){
238 quiet_quit_cmd ();
239 return MSG_HANDLED;
240 }
241 if (use_subshell)
242 load_prompt (0, 0);
243 #endif
244
245 current_dlg = old_dlg;
246 }
247 }
248 return MSG_HANDLED;
249 }
250
251 static int command_callback (Dlg_head *h, WCommand *cmd, int msg, int par)
252 {
253 switch (msg){
254 case WIDGET_FOCUS:
255 /* We refuse the focus always: needed not to unselect the panel */
256 return MSG_NOT_HANDLED;
257
258 case WIDGET_KEY:
259 /* Special case: we handle the enter key */
260 if (par == '\n'){
261 return enter (cmd);
262 }
263 }
264 return (*cmd->old_callback)(h, cmd, msg, par);
265 }
266
267 WCommand *command_new (int y, int x, int cols)
268 {
269 WInput *in;
270 WCommand *cmd = xmalloc (sizeof (WCommand), "command_new");
271
272 in = input_new (y, x, DEFAULT_COLOR, cols, "", "cmdline");
273 cmd->input = *in;
274 free (in);
275
276 /* Add our hooks */
277 cmd->old_callback = (callback_fn) cmd->input.widget.callback;
278 cmd->input.widget.callback = (int (*) (Dlg_head *, void *, int, int))
279 command_callback;
280
281 cmd->input.completion_flags |= INPUT_COMPLETE_COMMANDS;
282 return cmd;
283 }
284
285