//======================================================================== // // gbasename.cc // // Wrapper for libgen's basename() call which returns a std::string. // This is a convenience method working around questionable behavior // in the copy of basename() provided by libgen.h. // // According to man 3 basename: // // Both dirname() and basename() may modify the contents of path, so it // may be desirable to pass a copy when calling one of these functions. // // ... // // These functions may return pointers to statically allocated memory // which may be overwritten by subsequent calls. Alternatively, they // may return a pointer to some part of path, so that the string // referred to by path should not be modified or freed until the pointer // returned by the function is no longer required. // // Because basename can modify filename (for some reason), we have to // duplicate our input into a mutable buffer before we can call it. // The return value might be part of this mutable temporary, but not // generally the front, so 'char *' cannot be used as our return value. // The return value might also be a statically allocated string, // rendering basename (and thus gbasename) non-thread-safe. Because // we don't know how basename()'s return value is lifecycled, we need // to duplicate it again into something whose lifecycle we can predict. // // This is how a method that should amount to finding the last slash // in a string ends up requiring two memory allocations while managing // not to be thread-safe. In a way, it's kind of impressive. // // This file is licensed under the GPLv2 or later // // Copyright (C) 2018, 2019 Greg Knight // Copyright (C) 2019 Albert Astals Cid // //======================================================================== #include "gbasename.h" #ifndef _MSC_VER # include #endif #include #include std::string gbasename(const char *filename) { #ifdef _MSC_VER char fname[_MAX_FNAME] = {}, fext[_MAX_EXT] = {}; errno_t z = _splitpath_s(filename, NULL, 0, NULL, 0, fname, _countof(fname), fext, _countof(fext)); return std::string(fname) + std::string(fext); #else char *mutabl = strdup(filename); std::string retu = basename(mutabl); free(mutabl); return retu; #endif }