/*
 * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
 *                         University Research and Technology
 *                         Corporation.  All rights reserved.
 * Copyright (c) 2004-2005 The University of Tennessee and The University
 *                         of Tennessee Research Foundation.  All rights
 *                         reserved.
 * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
 *                         University of Stuttgart.  All rights reserved.
 * Copyright (c) 2004-2005 The Regents of the University of California.
 *                         All rights reserved.
 * Copyright (c) 2009-2014 Cisco Systems, Inc.  All rights reserved.
 * Copyright (c) 2014      Research Organization for Information Science
 *                         and Technology (RIST). All rights reserved.
 * Copyright (c) 2014-2020 Intel, Inc.  All rights reserved.
 * Copyright (c) 2021-2024 Nanook Consulting  All rights reserved.
 * $COPYRIGHT$
 *
 * Additional copyrights may follow
 *
 * $HEADER$
 */

#include "src/include/pmix_config.h"

#include <stdlib.h>
#ifdef HAVE_STRING_H
#    include <string.h>
#endif /* HAVE_STRING_H */
#ifdef HAVE_LIBGEN_H
#    include <libgen.h>
#endif /* HAVE_LIBGEN_H */

#include "src/util/pmix_basename.h"
#include "src/util/pmix_os_path.h"

/**
 * Return a pointer into the original string where the last PATH delimiter
 * was found. It does not modify the original string. Moreover, it does not
 * scan the full string, but only the part allowed by the specified number
 * of characters.
 * If the last character on the string is a path separator, it will be skipped.
 */
static inline char *pmix_find_last_path_separator(const char *filename, size_t n)
{
    char *p = (char *) filename + n;

    /* First skip the latest separators */
    for (; p >= filename; p--) {
        if (*p != PMIX_PATH_SEP[0])
            break;
    }

    for (; p >= filename; p--) {
        if (*p == PMIX_PATH_SEP[0])
            return p;
    }

    return NULL; /* nothing found inside the filename */
}

char *pmix_basename(const char *filename)
{
    size_t i;
    char *tmp, *ret = NULL;
    const char sep = PMIX_PATH_SEP[0];

    /* Check for the bozo case */
    if (NULL == filename) {
        return NULL;
    }
    if (0 == strlen(filename)) {
        return strdup("");
    }
    if (sep == filename[0] && '\0' == filename[1]) {
        return strdup(filename);
    }

    /* Remove trailing sep's (note that we already know that strlen > 0) */
    tmp = strdup(filename);
    if (1 < strlen(tmp)) {
        for (i = strlen(tmp) - 1; i > 0; --i) {
            if (sep == tmp[i]) {
                tmp[i] = '\0';
            } else {
                break;
            }
        }
        if (0 == i) {
            tmp[0] = sep;
            return tmp;
        }
    }

    /* Look for the final sep */
    ret = pmix_find_last_path_separator(tmp, strlen(tmp));
    if (NULL == ret) {
        return tmp;
    }
    ret = strdup(ret + 1);
    free(tmp);
    return ret;
}

char *pmix_dirname(const char *filename)
{
#if defined(HAVE_DIRNAME) || PMIX_HAVE_DIRNAME
    char *safe_tmp = strdup(filename), *result;
    result = strdup(dirname(safe_tmp));
    free(safe_tmp);
    return result;
#else
    const char *p = pmix_find_last_path_separator(filename, strlen(filename));
    /* NOTE: p will be NULL if no path separator was in the filename - i.e.,
     * if filename is just a local file */

    for (; NULL != p && p != filename; p--) {
        if ((*p == '\\') || (*p == '/')) {
            /* If there are several delimiters remove them all */
            for (--p; p != filename; p--) {
                if ((*p != '\\') && (*p != '/')) {
                    p++;
                    break;
                }
            }
            if (p != filename) {
                char *ret = (char *) malloc(p - filename + 1);
                pmix_strncpy(ret, filename, p - filename);
                ret[p - filename] = '\0';
                return pmix_make_filename_os_friendly(ret);
            }
            break; /* return the duplicate of "." */
        }
    }
    return strdup(".");
#endif /* defined(HAVE_DIRNAME) || PMIX_HAVE_DIRNAME */
}
