blob: 69236d8101f7a50c1f9f0a55578b7095cc57daa4 [file] [log] [blame] [edit]
//========================================================================
//
// 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 <lyngvi@gmail.com>
// Copyright (C) 2019 Albert Astals Cid <aacid@kde.org>
//
//========================================================================
#include "gbasename.h"
#ifndef _MSC_VER
# include <libgen.h>
#endif
#include <cstdlib>
#include <cstring>
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
}