Automatic date update in version.in
[binutils-gdb.git] / gdbsupport / pathstuff.cc
blob685f8fc3e60e970a6b92c92344f4251b372359bd
1 /* Path manipulation routines for GDB and gdbserver.
3 Copyright (C) 1986-2023 Free Software Foundation, Inc.
5 This file is part of GDB.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 #include "common-defs.h"
21 #include "pathstuff.h"
22 #include "host-defs.h"
23 #include "filenames.h"
24 #include "gdb_tilde_expand.h"
26 #ifdef USE_WIN32API
27 #include <windows.h>
28 #endif
30 /* See gdbsupport/pathstuff.h. */
32 char *current_directory;
34 /* See gdbsupport/pathstuff.h. */
36 gdb::unique_xmalloc_ptr<char>
37 gdb_realpath (const char *filename)
39 /* On most hosts, we rely on canonicalize_file_name to compute
40 the FILENAME's realpath.
42 But the situation is slightly more complex on Windows, due to some
43 versions of GCC which were reported to generate paths where
44 backslashes (the directory separator) were doubled. For instance:
45 c:\\some\\double\\slashes\\dir
46 ... instead of ...
47 c:\some\double\slashes\dir
48 Those double-slashes were getting in the way when comparing paths,
49 for instance when trying to insert a breakpoint as follow:
50 (gdb) b c:/some/double/slashes/dir/foo.c:4
51 No source file named c:/some/double/slashes/dir/foo.c:4.
52 (gdb) b c:\some\double\slashes\dir\foo.c:4
53 No source file named c:\some\double\slashes\dir\foo.c:4.
54 To prevent this from happening, we need this function to always
55 strip those extra backslashes. While canonicalize_file_name does
56 perform this simplification, it only works when the path is valid.
57 Since the simplification would be useful even if the path is not
58 valid (one can always set a breakpoint on a file, even if the file
59 does not exist locally), we rely instead on GetFullPathName to
60 perform the canonicalization. */
62 #if defined (_WIN32)
64 char buf[MAX_PATH];
65 DWORD len = GetFullPathName (filename, MAX_PATH, buf, NULL);
67 /* The file system is case-insensitive but case-preserving.
68 So it is important we do not lowercase the path. Otherwise,
69 we might not be able to display the original casing in a given
70 path. */
71 if (len > 0 && len < MAX_PATH)
72 return make_unique_xstrdup (buf);
74 #else
76 char *rp = canonicalize_file_name (filename);
78 if (rp != NULL)
79 return gdb::unique_xmalloc_ptr<char> (rp);
81 #endif
83 /* This system is a lost cause, just dup the buffer. */
84 return make_unique_xstrdup (filename);
87 /* See gdbsupport/pathstuff.h. */
89 std::string
90 gdb_realpath_keepfile (const char *filename)
92 const char *base_name = lbasename (filename);
93 char *dir_name;
95 /* Extract the basename of filename, and return immediately
96 a copy of filename if it does not contain any directory prefix. */
97 if (base_name == filename)
98 return filename;
100 dir_name = (char *) alloca ((size_t) (base_name - filename + 2));
101 /* Allocate enough space to store the dir_name + plus one extra
102 character sometimes needed under Windows (see below), and
103 then the closing \000 character. */
104 strncpy (dir_name, filename, base_name - filename);
105 dir_name[base_name - filename] = '\000';
107 #ifdef HAVE_DOS_BASED_FILE_SYSTEM
108 /* We need to be careful when filename is of the form 'd:foo', which
109 is equivalent of d:./foo, which is totally different from d:/foo. */
110 if (strlen (dir_name) == 2 && isalpha (dir_name[0]) && dir_name[1] == ':')
112 dir_name[2] = '.';
113 dir_name[3] = '\000';
115 #endif
117 /* Canonicalize the directory prefix, and build the resulting
118 filename. If the dirname realpath already contains an ending
119 directory separator, avoid doubling it. */
120 gdb::unique_xmalloc_ptr<char> path_storage = gdb_realpath (dir_name);
121 const char *real_path = path_storage.get ();
122 return path_join (real_path, base_name);
125 /* See gdbsupport/pathstuff.h. */
127 std::string
128 gdb_abspath (const char *path)
130 gdb_assert (path != NULL && path[0] != '\0');
132 if (path[0] == '~')
133 return gdb_tilde_expand (path);
135 if (IS_ABSOLUTE_PATH (path) || current_directory == NULL)
136 return path;
138 return path_join (current_directory, path);
141 /* See gdbsupport/pathstuff.h. */
143 const char *
144 child_path (const char *parent, const char *child)
146 /* The child path must start with the parent path. */
147 size_t parent_len = strlen (parent);
148 if (filename_ncmp (parent, child, parent_len) != 0)
149 return NULL;
151 /* The parent path must be a directory and the child must contain at
152 least one component underneath the parent. */
153 const char *child_component;
154 if (parent_len > 0 && IS_DIR_SEPARATOR (parent[parent_len - 1]))
156 /* The parent path ends in a directory separator, so it is a
157 directory. The first child component starts after the common
158 prefix. */
159 child_component = child + parent_len;
161 else
163 /* The parent path does not end in a directory separator. The
164 first character in the child after the common prefix must be
165 a directory separator.
167 Note that CHILD must hold at least parent_len characters for
168 filename_ncmp to return zero. If the character at parent_len
169 is nul due to CHILD containing the same path as PARENT, the
170 IS_DIR_SEPARATOR check will fail here. */
171 if (!IS_DIR_SEPARATOR (child[parent_len]))
172 return NULL;
174 /* The first child component starts after the separator after the
175 common prefix. */
176 child_component = child + parent_len + 1;
179 /* The child must contain at least one non-separator character after
180 the parent. */
181 while (*child_component != '\0')
183 if (!IS_DIR_SEPARATOR (*child_component))
184 return child_component;
186 child_component++;
188 return NULL;
191 /* See gdbsupport/pathstuff.h. */
193 std::string
194 path_join (gdb::array_view<const char *> paths)
196 std::string ret;
198 for (int i = 0; i < paths.size (); ++i)
200 const char *path = paths[i];
202 if (i > 0)
203 gdb_assert (strlen (path) == 0 || !IS_ABSOLUTE_PATH (path));
205 if (!ret.empty () && !IS_DIR_SEPARATOR (ret.back ()))
206 ret += '/';
208 ret.append (path);
211 return ret;
214 /* See gdbsupport/pathstuff.h. */
216 bool
217 contains_dir_separator (const char *path)
219 for (; *path != '\0'; path++)
221 if (IS_DIR_SEPARATOR (*path))
222 return true;
225 return false;
228 /* See gdbsupport/pathstuff.h. */
230 std::string
231 get_standard_cache_dir ()
233 #ifdef __APPLE__
234 #define HOME_CACHE_DIR "Library/Caches"
235 #else
236 #define HOME_CACHE_DIR ".cache"
237 #endif
239 #ifndef __APPLE__
240 const char *xdg_cache_home = getenv ("XDG_CACHE_HOME");
241 if (xdg_cache_home != NULL && xdg_cache_home[0] != '\0')
243 /* Make sure the path is absolute and tilde-expanded. */
244 std::string abs = gdb_abspath (xdg_cache_home);
245 return path_join (abs.c_str (), "gdb");
247 #endif
249 const char *home = getenv ("HOME");
250 if (home != NULL && home[0] != '\0')
252 /* Make sure the path is absolute and tilde-expanded. */
253 std::string abs = gdb_abspath (home);
254 return path_join (abs.c_str (), HOME_CACHE_DIR, "gdb");
257 #ifdef WIN32
258 const char *win_home = getenv ("LOCALAPPDATA");
259 if (win_home != NULL && win_home[0] != '\0')
261 /* Make sure the path is absolute and tilde-expanded. */
262 std::string abs = gdb_abspath (win_home);
263 return path_join (abs.c_str (), "gdb");
265 #endif
267 return {};
270 /* See gdbsupport/pathstuff.h. */
272 std::string
273 get_standard_temp_dir ()
275 #ifdef WIN32
276 const char *tmp = getenv ("TMP");
277 if (tmp != nullptr)
278 return tmp;
280 tmp = getenv ("TEMP");
281 if (tmp != nullptr)
282 return tmp;
284 error (_("Couldn't find temp dir path, both TMP and TEMP are unset."));
286 #else
287 const char *tmp = getenv ("TMPDIR");
288 if (tmp != nullptr)
289 return tmp;
291 return "/tmp";
292 #endif
295 /* See pathstuff.h. */
297 std::string
298 get_standard_config_dir ()
300 #ifdef __APPLE__
301 #define HOME_CONFIG_DIR "Library/Preferences"
302 #else
303 #define HOME_CONFIG_DIR ".config"
304 #endif
306 #ifndef __APPLE__
307 const char *xdg_config_home = getenv ("XDG_CONFIG_HOME");
308 if (xdg_config_home != NULL && xdg_config_home[0] != '\0')
310 /* Make sure the path is absolute and tilde-expanded. */
311 std::string abs = gdb_abspath (xdg_config_home);
312 return path_join (abs.c_str (), "gdb");
314 #endif
316 const char *home = getenv ("HOME");
317 if (home != NULL && home[0] != '\0')
319 /* Make sure the path is absolute and tilde-expanded. */
320 std::string abs = gdb_abspath (home);
321 return path_join (abs.c_str (), HOME_CONFIG_DIR, "gdb");
324 return {};
327 /* See pathstuff.h. */
329 std::string
330 get_standard_config_filename (const char *filename)
332 std::string config_dir = get_standard_config_dir ();
333 if (config_dir != "")
335 const char *tmp = (*filename == '.') ? (filename + 1) : filename;
336 std::string path = config_dir + SLASH_STRING + std::string (tmp);
337 return path;
340 return {};
343 /* See pathstuff.h. */
345 std::string
346 find_gdb_home_config_file (const char *name, struct stat *buf)
348 gdb_assert (name != nullptr);
349 gdb_assert (*name != '\0');
351 std::string config_dir_file = get_standard_config_filename (name);
352 if (!config_dir_file.empty ())
354 if (stat (config_dir_file.c_str (), buf) == 0)
355 return config_dir_file;
358 const char *homedir = getenv ("HOME");
359 if (homedir != nullptr && homedir[0] != '\0')
361 /* Make sure the path is absolute and tilde-expanded. */
362 std::string abs = gdb_abspath (homedir);
363 std::string path = string_printf ("%s/%s", abs.c_str (), name);
364 if (stat (path.c_str (), buf) == 0)
365 return path;
368 return {};
371 /* See gdbsupport/pathstuff.h. */
373 const char *
374 get_shell ()
376 const char *ret = getenv ("SHELL");
377 if (ret == NULL)
378 ret = "/bin/sh";
380 return ret;
383 /* See gdbsupport/pathstuff.h. */
385 gdb::char_vector
386 make_temp_filename (const std::string &f)
388 gdb::char_vector filename_temp (f.length () + 8);
389 strcpy (filename_temp.data (), f.c_str ());
390 strcat (filename_temp.data () + f.size (), "-XXXXXX");
391 return filename_temp;