gdb: add some const in gdb/reggroups.c
[binutils-gdb.git] / gdbsupport / pathstuff.cc
1 /* Path manipulation routines for GDB and gdbserver.
2
3 Copyright (C) 1986-2022 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
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.
11
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.
16
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/>. */
19
20 #include "common-defs.h"
21 #include "pathstuff.h"
22 #include "host-defs.h"
23 #include "filenames.h"
24 #include "gdb_tilde_expand.h"
25
26 #ifdef USE_WIN32API
27 #include <windows.h>
28 #endif
29
30 /* See gdbsupport/pathstuff.h. */
31
32 char *current_directory;
33
34 /* See gdbsupport/pathstuff.h. */
35
36 gdb::unique_xmalloc_ptr<char>
37 gdb_realpath (const char *filename)
38 {
39 /* On most hosts, we rely on canonicalize_file_name to compute
40 the FILENAME's realpath.
41
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 backlashes (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. */
61
62 #if defined (_WIN32)
63 {
64 char buf[MAX_PATH];
65 DWORD len = GetFullPathName (filename, MAX_PATH, buf, NULL);
66
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);
73 }
74 #else
75 {
76 char *rp = canonicalize_file_name (filename);
77
78 if (rp != NULL)
79 return gdb::unique_xmalloc_ptr<char> (rp);
80 }
81 #endif
82
83 /* This system is a lost cause, just dup the buffer. */
84 return make_unique_xstrdup (filename);
85 }
86
87 /* See gdbsupport/pathstuff.h. */
88
89 gdb::unique_xmalloc_ptr<char>
90 gdb_realpath_keepfile (const char *filename)
91 {
92 const char *base_name = lbasename (filename);
93 char *dir_name;
94 char *result;
95
96 /* Extract the basename of filename, and return immediately
97 a copy of filename if it does not contain any directory prefix. */
98 if (base_name == filename)
99 return make_unique_xstrdup (filename);
100
101 dir_name = (char *) alloca ((size_t) (base_name - filename + 2));
102 /* Allocate enough space to store the dir_name + plus one extra
103 character sometimes needed under Windows (see below), and
104 then the closing \000 character. */
105 strncpy (dir_name, filename, base_name - filename);
106 dir_name[base_name - filename] = '\000';
107
108 #ifdef HAVE_DOS_BASED_FILE_SYSTEM
109 /* We need to be careful when filename is of the form 'd:foo', which
110 is equivalent of d:./foo, which is totally different from d:/foo. */
111 if (strlen (dir_name) == 2 && isalpha (dir_name[0]) && dir_name[1] == ':')
112 {
113 dir_name[2] = '.';
114 dir_name[3] = '\000';
115 }
116 #endif
117
118 /* Canonicalize the directory prefix, and build the resulting
119 filename. If the dirname realpath already contains an ending
120 directory separator, avoid doubling it. */
121 gdb::unique_xmalloc_ptr<char> path_storage = gdb_realpath (dir_name);
122 const char *real_path = path_storage.get ();
123 if (IS_DIR_SEPARATOR (real_path[strlen (real_path) - 1]))
124 result = concat (real_path, base_name, (char *) NULL);
125 else
126 result = concat (real_path, SLASH_STRING, base_name, (char *) NULL);
127
128 return gdb::unique_xmalloc_ptr<char> (result);
129 }
130
131 /* See gdbsupport/pathstuff.h. */
132
133 gdb::unique_xmalloc_ptr<char>
134 gdb_abspath (const char *path)
135 {
136 gdb_assert (path != NULL && path[0] != '\0');
137
138 if (path[0] == '~')
139 return gdb_tilde_expand_up (path);
140
141 if (IS_ABSOLUTE_PATH (path) || current_directory == NULL)
142 return make_unique_xstrdup (path);
143
144 /* Beware the // my son, the Emacs barfs, the botch that catch... */
145 return gdb::unique_xmalloc_ptr<char>
146 (concat (current_directory,
147 IS_DIR_SEPARATOR (current_directory[strlen (current_directory) - 1])
148 ? "" : SLASH_STRING,
149 path, (char *) NULL));
150 }
151
152 /* See gdbsupport/pathstuff.h. */
153
154 const char *
155 child_path (const char *parent, const char *child)
156 {
157 /* The child path must start with the parent path. */
158 size_t parent_len = strlen (parent);
159 if (filename_ncmp (parent, child, parent_len) != 0)
160 return NULL;
161
162 /* The parent path must be a directory and the child must contain at
163 least one component underneath the parent. */
164 const char *child_component;
165 if (parent_len > 0 && IS_DIR_SEPARATOR (parent[parent_len - 1]))
166 {
167 /* The parent path ends in a directory separator, so it is a
168 directory. The first child component starts after the common
169 prefix. */
170 child_component = child + parent_len;
171 }
172 else
173 {
174 /* The parent path does not end in a directory separator. The
175 first character in the child after the common prefix must be
176 a directory separator.
177
178 Note that CHILD must hold at least parent_len characters for
179 filename_ncmp to return zero. If the character at parent_len
180 is nul due to CHILD containing the same path as PARENT, the
181 IS_DIR_SEPARATOR check will fail here. */
182 if (!IS_DIR_SEPARATOR (child[parent_len]))
183 return NULL;
184
185 /* The first child component starts after the separator after the
186 common prefix. */
187 child_component = child + parent_len + 1;
188 }
189
190 /* The child must contain at least one non-separator character after
191 the parent. */
192 while (*child_component != '\0')
193 {
194 if (!IS_DIR_SEPARATOR (*child_component))
195 return child_component;
196
197 child_component++;
198 }
199 return NULL;
200 }
201
202 /* See gdbsupport/pathstuff.h. */
203
204 bool
205 contains_dir_separator (const char *path)
206 {
207 for (; *path != '\0'; path++)
208 {
209 if (IS_DIR_SEPARATOR (*path))
210 return true;
211 }
212
213 return false;
214 }
215
216 /* See gdbsupport/pathstuff.h. */
217
218 std::string
219 get_standard_cache_dir ()
220 {
221 #ifdef __APPLE__
222 #define HOME_CACHE_DIR "Library/Caches"
223 #else
224 #define HOME_CACHE_DIR ".cache"
225 #endif
226
227 #ifndef __APPLE__
228 const char *xdg_cache_home = getenv ("XDG_CACHE_HOME");
229 if (xdg_cache_home != NULL && xdg_cache_home[0] != '\0')
230 {
231 /* Make sure the path is absolute and tilde-expanded. */
232 gdb::unique_xmalloc_ptr<char> abs (gdb_abspath (xdg_cache_home));
233 return string_printf ("%s/gdb", abs.get ());
234 }
235 #endif
236
237 const char *home = getenv ("HOME");
238 if (home != NULL && home[0] != '\0')
239 {
240 /* Make sure the path is absolute and tilde-expanded. */
241 gdb::unique_xmalloc_ptr<char> abs (gdb_abspath (home));
242 return string_printf ("%s/" HOME_CACHE_DIR "/gdb", abs.get ());
243 }
244
245 #ifdef WIN32
246 const char *win_home = getenv ("LOCALAPPDATA");
247 if (win_home != NULL && win_home[0] != '\0')
248 {
249 /* Make sure the path is absolute and tilde-expanded. */
250 gdb::unique_xmalloc_ptr<char> abs (gdb_abspath (win_home));
251 return string_printf ("%s/gdb", abs.get ());
252 }
253 #endif
254
255 return {};
256 }
257
258 /* See gdbsupport/pathstuff.h. */
259
260 std::string
261 get_standard_temp_dir ()
262 {
263 #ifdef WIN32
264 const char *tmp = getenv ("TMP");
265 if (tmp != nullptr)
266 return tmp;
267
268 tmp = getenv ("TEMP");
269 if (tmp != nullptr)
270 return tmp;
271
272 error (_("Couldn't find temp dir path, both TMP and TEMP are unset."));
273
274 #else
275 const char *tmp = getenv ("TMPDIR");
276 if (tmp != nullptr)
277 return tmp;
278
279 return "/tmp";
280 #endif
281 }
282
283 /* See pathstuff.h. */
284
285 std::string
286 get_standard_config_dir ()
287 {
288 #ifdef __APPLE__
289 #define HOME_CONFIG_DIR "Library/Preferences"
290 #else
291 #define HOME_CONFIG_DIR ".config"
292 #endif
293
294 #ifndef __APPLE__
295 const char *xdg_config_home = getenv ("XDG_CONFIG_HOME");
296 if (xdg_config_home != NULL && xdg_config_home[0] != '\0')
297 {
298 /* Make sure the path is absolute and tilde-expanded. */
299 gdb::unique_xmalloc_ptr<char> abs (gdb_abspath (xdg_config_home));
300 return string_printf ("%s/gdb", abs.get ());
301 }
302 #endif
303
304 const char *home = getenv ("HOME");
305 if (home != NULL && home[0] != '\0')
306 {
307 /* Make sure the path is absolute and tilde-expanded. */
308 gdb::unique_xmalloc_ptr<char> abs (gdb_abspath (home));
309 return string_printf ("%s/" HOME_CONFIG_DIR "/gdb", abs.get ());
310 }
311
312 return {};
313 }
314
315 /* See pathstuff.h. */
316
317 std::string
318 get_standard_config_filename (const char *filename)
319 {
320 std::string config_dir = get_standard_config_dir ();
321 if (config_dir != "")
322 {
323 const char *tmp = (*filename == '.') ? (filename + 1) : filename;
324 std::string path = config_dir + SLASH_STRING + std::string (tmp);
325 return path;
326 }
327
328 return {};
329 }
330
331 /* See pathstuff.h. */
332
333 std::string
334 find_gdb_home_config_file (const char *name, struct stat *buf)
335 {
336 gdb_assert (name != nullptr);
337 gdb_assert (*name != '\0');
338
339 std::string config_dir_file = get_standard_config_filename (name);
340 if (!config_dir_file.empty ())
341 {
342 if (stat (config_dir_file.c_str (), buf) == 0)
343 return config_dir_file;
344 }
345
346 const char *homedir = getenv ("HOME");
347 if (homedir != nullptr && homedir[0] != '\0')
348 {
349 /* Make sure the path is absolute and tilde-expanded. */
350 gdb::unique_xmalloc_ptr<char> abs (gdb_abspath (homedir));
351 std::string path = (std::string (abs.get ()) + SLASH_STRING
352 + std::string (name));
353 if (stat (path.c_str (), buf) == 0)
354 return path;
355 }
356
357 return {};
358 }
359
360 /* See gdbsupport/pathstuff.h. */
361
362 const char *
363 get_shell ()
364 {
365 const char *ret = getenv ("SHELL");
366 if (ret == NULL)
367 ret = "/bin/sh";
368
369 return ret;
370 }
371
372 /* See gdbsupport/pathstuff.h. */
373
374 gdb::char_vector
375 make_temp_filename (const std::string &f)
376 {
377 gdb::char_vector filename_temp (f.length () + 8);
378 strcpy (filename_temp.data (), f.c_str ());
379 strcat (filename_temp.data () + f.size (), "-XXXXXX");
380 return filename_temp;
381 }