1 | //======================================================================== |
2 | // |
3 | // gbasename.cc |
4 | // |
5 | // Wrapper for libgen's basename() call which returns a std::string. |
6 | // This is a convenience method working around questionable behavior |
7 | // in the copy of basename() provided by libgen.h. |
8 | // |
9 | // According to man 3 basename: |
10 | // |
11 | // Both dirname() and basename() may modify the contents of path, so it |
12 | // may be desirable to pass a copy when calling one of these functions. |
13 | // |
14 | // ... |
15 | // |
16 | // These functions may return pointers to statically allocated memory |
17 | // which may be overwritten by subsequent calls. Alternatively, they |
18 | // may return a pointer to some part of path, so that the string |
19 | // referred to by path should not be modified or freed until the pointer |
20 | // returned by the function is no longer required. |
21 | // |
22 | // Because basename can modify filename (for some reason), we have to |
23 | // duplicate our input into a mutable buffer before we can call it. |
24 | // The return value might be part of this mutable temporary, but not |
25 | // generally the front, so 'char *' cannot be used as our return value. |
26 | // The return value might also be a statically allocated string, |
27 | // rendering basename (and thus gbasename) non-thread-safe. Because |
28 | // we don't know how basename()'s return value is lifecycled, we need |
29 | // to duplicate it again into something whose lifecycle we can predict. |
30 | // |
31 | // This is how a method that should amount to finding the last slash |
32 | // in a string ends up requiring two memory allocations while managing |
33 | // not to be thread-safe. In a way, it's kind of impressive. |
34 | // |
35 | // This file is licensed under the GPLv2 or later |
36 | // |
37 | // Copyright (C) 2018, 2019 Greg Knight <lyngvi@gmail.com> |
38 | // Copyright (C) 2019 Albert Astals Cid <aacid@kde.org> |
39 | // |
40 | //======================================================================== |
41 | |
42 | #include "gbasename.h" |
43 | #ifndef _MSC_VER |
44 | # include <libgen.h> |
45 | #endif |
46 | #include <cstdlib> |
47 | #include <cstring> |
48 | |
49 | std::string gbasename(const char *filename) |
50 | { |
51 | #ifdef _MSC_VER |
52 | char fname[_MAX_FNAME] = {}, fext[_MAX_EXT] = {}; |
53 | errno_t z = _splitpath_s(filename, NULL, 0, NULL, 0, fname, _countof(fname), fext, _countof(fext)); |
54 | return std::string(fname) + std::string(fext); |
55 | #else |
56 | char *mutabl = strdup(s: filename); |
57 | std::string retu = basename(path: mutabl); |
58 | free(ptr: mutabl); |
59 | return retu; |
60 | #endif |
61 | } |
62 | |