// SPDX-License-Identifier: LGPL-3.0-or-later

/* osx_dir.h implementation for Windows.
 *
 * Copyright: 2022, The DoubleFourteen Code Forge
 * Author: Lorenzo Cogotti
 */

#include "xconf.h"
#include "osx_dir.h"

#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

DF_OSXLIB_API df_os_dirhn os_opendir(const char *path)
{
    if (*path == '\0') {  // avoid generating \* search path
        errno = ENOENT;
        return NULL;
    }

    char buf[_MAX_PATH + 2 + 1];
    int n = snprintf(buf, sizeof(buf), "%s\\*", path);
    if (n < 0)
        return NULL;
    if ((size_t) n >= sizeof(buf)) {
        errno = ERANGE;
        return NULL;
    }

    df_os_dirhn hn = malloc(sizeof(*hn));
    if (!hn)
        return NULL;

    hn->dirh = _findfirst(buf, &hn->data);
    if (hn->dirh == -1) {
        free(hn);
        return NULL;
    }

    hn->startflag = true;
    hn->errflag = false;
    hn->endflag = false;

    return hn;
}

DF_OSXLIB_API char *os_readdir(df_os_dirhn hn)
{
    if (hn->startflag) {
        // Return first item found by _findfirst()
        hn->startflag = false;
        return hn->data.name;
    }

    // Reset status flags and advance directory iterator
    hn->errflag = false;
    hn->endflag = false;

    int err = errno;

    if (_findnext(hn->dirh, &hn->data) == -1) {
        if (errno == ENOENT) {
            // End of directory, this is not an error, restore old errno
            errno = err;
            hn->endflag = true;
        } else {
            hn->errflag = true;
        }

        return NULL;
    }
    
    return hn->data.name;
}

DF_OSXLIB_API void os_closedir(df_os_dirhn hn)
{
    _findclose(hn->dirh);
    free(hn);
}