// dvxPlatformUtil.c  -- small cross-build platform utilities
//
// Functions here are linked into every DVX build variant: DOS dvx.exe,
// the BASIC standalone compiler BASCOMP.EXE, and the host-side test
// binaries.  Kept independent of the VESA / DPMI / INT-33h code in
// dvxPlatformDos.c so minimal builds without the full platform layer
// can still use them.

#include "dvxPlat.h"

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#ifdef __DJGPP__
#include <dir.h>
#endif


const char *dvxSkipWs(const char *s) {
    if (!s) {
        return s;
    }

    while (*s == ' ' || *s == '\t') {
        s++;
    }

    return s;
}


int32_t dvxTrimRight(char *buf) {
    if (!buf) {
        return 0;
    }

    int32_t len = (int32_t)strlen(buf);

    while (len > 0 && (buf[len - 1] == ' ' || buf[len - 1] == '\t' ||
                       buf[len - 1] == '\r' || buf[len - 1] == '\n')) {
        buf[--len] = '\0';
    }

    return len;
}


int32_t platformChdir(const char *path) {
#ifdef __DJGPP__
    if (path[0] && path[1] == ':') {
        int drive = toupper((unsigned char)path[0]) - 'A';
        setdisk(drive);
    }
#endif

    return chdir(path) == 0 ? 0 : -1;
}


const char *platformPathBaseName(const char *path) {
    if (!path) {
        return "";
    }

    const char *sep = platformPathDirEnd(path);
    return sep ? sep + 1 : path;
}


// Return the last path separator in `path`, or NULL if none.
//
// Platform-specific, because what counts as a separator varies:
//   - DJGPP/DOS and Win32 accept both '/' and '\\' -- we have to check
//     both and return whichever appears last.
//   - Unix-like systems use only '/'.  '\\' is a legal filename
//     character there, so treating it as a separator would incorrectly
//     split paths containing literal backslashes.
char *platformPathDirEnd(const char *path) {
#if defined(__DJGPP__) || defined(_WIN32) || defined(_WIN64)
    char *fwd  = strrchr(path, '/');
    char *back = strrchr(path, '\\');

    if (back > fwd) {
        return back;
    }

    return fwd;
#else
    return strrchr(path, '/');
#endif
}


char *platformReadFile(const char *path, int32_t *outLen) {
    if (outLen) {
        *outLen = 0;
    }

    FILE *f = fopen(path, "rb");

    if (!f) {
        return NULL;
    }

    if (fseek(f, 0, SEEK_END) != 0) {
        fclose(f);
        return NULL;
    }

    long size = ftell(f);

    if (size < 0) {
        fclose(f);
        return NULL;
    }

    if (fseek(f, 0, SEEK_SET) != 0) {
        fclose(f);
        return NULL;
    }

    char *buf = (char *)malloc((size_t)size + 1);

    if (!buf) {
        fclose(f);
        return NULL;
    }

    size_t got = fread(buf, 1, (size_t)size, f);
    fclose(f);

    if (got != (size_t)size) {
        free(buf);
        return NULL;
    }

    buf[size] = '\0';

    if (outLen) {
        *outLen = (int32_t)size;
    }

    return buf;
}
