// yabridge: a Wine plugin bridge
// Copyright (C) 2020-2024 Robbert van der Helm
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

#include "linking.h"

#include <cassert>

#include <dlfcn.h>

namespace fs = ghc::filesystem;

fs::path get_this_file_location() {
    // We'll try to find the library this function was defined in. When called
    // from a copy of `libyabridge-*.so` this will return that library. Because
    // the chainloader libraries load the plugin libraries from fixed locations,
    // the plugin libraries cannot use this function directly when using the
    // chainloaders.

    // On success this returns a non-zero value, just to keep you on your toes
    Dl_info info;
    assert(dladdr(reinterpret_cast<void*>(get_this_file_location), &info) != 0);
    assert(info.dli_fname);

    std::string this_file(info.dli_fname);

    // HACK: Not sure why, but `boost::dll::this_line_location()` used to return
    //       a path starting with a double slash on some systems. I've seen this
    //       happen on both Ubuntu 18.04 and 20.04, but not on Arch based
    //       distros.  Under Linux a path starting with two slashes is treated
    //       the same as a path starting with only a single slash, but Wine will
    //       refuse to load any files when the path starts with two slashes. The
    //       easiest way to work around this if this happens is to just add
    //       another leading slash and then normalize the path, since three or
    //       more slashes will be coerced into a single slash. We no longer use
    //       Boost.Dll, but unless this was an obscure Boost.Filesystem bug it
    //       sounds more likely that it was caused by some `ld.so` setting.
    //       Unless we can really figure out what was causing this, it seems
    //       best to still account for it
    if (this_file.starts_with("//")) {
        const size_t path_start_pos = this_file.find_first_not_of('/');
        if (path_start_pos != std::string::npos) {
            // FIXME: This results in a spurious compiler warning if you inline
            //        `path_start`:
            //        https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105329
            const std::string path_start = this_file.substr(path_start_pos);
            this_file = "/" + path_start;
        }
    }

    return this_file;
}
