4 Copyright (C) 1995-2024
5 Free Software Foundation, Inc.
8 Slava Zanko <slavazanko@gmail.com>, 2013
9 Andrew Borodin <aborodin@vmail.ru>, 2020
11 This file is part of the Midnight Commander.
13 The Midnight Commander is free software: you can redistribute it
14 and/or modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation, either version 3 of the License,
16 or (at your option) any later version.
18 The Midnight Commander is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 * \brief Source: cd_to() function
37 #include "lib/global.h"
38 #include "lib/vfs/vfs.h"
39 #include "lib/strutil.h"
40 #include "lib/util.h" /* whitespace() */
41 #include "lib/widget.h" /* message() */
43 #include "filemanager.h" /* current_panel, panel.h, layout.h */
44 #include "tree.h" /* sync_tree() */
48 /*** global variables ****************************************************************************/
50 /*** file scope macro definitions ****************************************************************/
52 /*** file scope type declarations ****************************************************************/
54 /*** forward declarations (file scope functions) *************************************************/
56 /*** file scope variables ************************************************************************/
58 /* --------------------------------------------------------------------------------------------- */
59 /*** file scope functions ************************************************************************/
60 /* --------------------------------------------------------------------------------------------- */
63 * Expand the argument to "cd" and change directory. First try tilde
64 * expansion, then variable substitution. If the CDPATH variable is set
65 * (e.g. CDPATH=".:~:/usr"), try all the paths contained there.
66 * We do not support such rare substitutions as ${var:-value} etc.
67 * No quoting is implemented here, so ${VAR} and $VAR will be always
68 * substituted. Wildcards are not supported either.
69 * Advanced users should be encouraged to use "\cd" instead of "cd" if
70 * they want the behavior they are used to in the shell.
72 * @param _path string to examine
73 * @return newly allocated string
77 examine_cd (const char *_path
)
87 state_t state
= copy_sym
;
89 char *path_tilde
, *path
;
93 path
= str_shell_unescape (_path
);
94 path_tilde
= tilde_expand (path
);
97 q
= g_string_sized_new (32);
99 /* Variable expansion */
100 for (p
= path_tilde
; *p
!= '\0';)
105 if (p
[0] == '\\' && p
[1] == '$')
107 g_string_append_c (q
, '$');
110 else if (p
[0] != '$' || p
[1] == '[' || p
[1] == '(')
112 g_string_append_c (q
, *p
);
123 const char *t
= NULL
;
134 s
= strchr (p
, PATH_SEP
);
136 s
= strchr (p
, '\0');
143 g_string_append_c (q
, '$');
145 g_string_append_c (q
, '{');
149 g_string_append (q
, t
);
169 /* --------------------------------------------------------------------------------------------- */
171 /* CDPATH handling */
173 handle_cdpath (const char *path
)
175 gboolean result
= FALSE
;
177 /* CDPATH handling */
178 if (!IS_PATH_SEP (*path
))
183 cdpath
= g_strdup (getenv ("CDPATH"));
185 c
= (p
== NULL
) ? '\0' : ':';
187 while (!result
&& c
== ':')
193 s
= strchr (p
, '\0');
200 r_vpath
= vfs_path_build_filename (p
, path
, (char *) NULL
);
201 result
= panel_cd (current_panel
, r_vpath
, cd_parse_command
);
202 vfs_path_free (r_vpath
, TRUE
);
213 /* --------------------------------------------------------------------------------------------- */
214 /*** public functions ****************************************************************************/
215 /* --------------------------------------------------------------------------------------------- */
217 /** Execute the cd command to specified path
219 * @param path path to cd
223 cd_to (const char *path
)
227 /* Remove leading whitespaces. */
228 /* Any final whitespace should be removed here (to see why, try "cd fred "). */
229 /* NOTE: I think we should not remove the extra space,
230 that way, we can cd into hidden directories */
231 /* FIXME: what about interpreting quoted strings like the shell.
232 so one could type "cd <tab> M-a <enter>" and it would work. */
233 p
= g_strstrip (g_strdup (path
));
235 if (get_current_type () == view_tree
)
237 vfs_path_t
*new_vpath
= NULL
;
241 new_vpath
= vfs_path_from_str (mc_config_get_home_dir ());
242 sync_tree (new_vpath
);
244 else if (DIR_IS_DOTDOT (p
))
246 if (vfs_path_elements_count (current_panel
->cwd_vpath
) != 1 ||
247 strlen (vfs_path_get_by_index (current_panel
->cwd_vpath
, 0)->path
) > 1)
249 vfs_path_t
*tmp_vpath
= current_panel
->cwd_vpath
;
251 current_panel
->cwd_vpath
=
252 vfs_path_vtokens_get (tmp_vpath
, 0, vfs_path_tokens_count (tmp_vpath
) - 1);
253 vfs_path_free (tmp_vpath
, TRUE
);
255 sync_tree (current_panel
->cwd_vpath
);
259 if (IS_PATH_SEP (*p
))
260 new_vpath
= vfs_path_from_str (p
);
262 new_vpath
= vfs_path_append_new (current_panel
->cwd_vpath
, p
, (char *) NULL
);
264 sync_tree (new_vpath
);
267 vfs_path_free (new_vpath
, TRUE
);
275 s_path
= examine_cd (p
);
277 if (s_path
->len
== 0)
278 q_vpath
= vfs_path_from_str (mc_config_get_home_dir ());
280 q_vpath
= vfs_path_from_str_flags (s_path
->str
, VPF_NO_CANON
);
282 ok
= panel_cd (current_panel
, q_vpath
, cd_parse_command
);
284 ok
= handle_cdpath (s_path
->str
);
289 d
= vfs_path_to_str_flags (q_vpath
, 0, VPF_STRIP_PASSWORD
);
290 cd_error_message (d
);
294 vfs_path_free (q_vpath
, TRUE
);
295 g_string_free (s_path
, TRUE
);
301 /* --------------------------------------------------------------------------------------------- */
304 cd_error_message (const char *path
)
306 message (D_ERROR
, MSG_ERROR
, _("Cannot change directory to\n%s\n%s"), path
,
307 unix_error_string (errno
));
310 /* --------------------------------------------------------------------------------------------- */