#if defined(WIN32) || defined(_WIN32)

#include "wingetopt.h"
#include <string.h>
#include <stdio.h>

/* Option-parsing state shared across calls */
char *optarg = NULL;
int   optind = 0;   /* 0 = not yet started; first call advances to 1 */
int   opterr = 1;   /* print errors to stderr when non-zero */
int   optopt = 0;   /* holds the unknown option char on '?' return */

/* -------------------------------------------------------------------------
 * getopt() — POSIX short-option parser
 * ------------------------------------------------------------------------- */
int
getopt(int argc, char *argv[], const char *optstring)
{
    static char *next = NULL;
    char c;
    const char *cp;

    /* optind == 0 is the GNU reset convention */
    if (optind == 0) {
        optind = 1;
        next   = NULL;
    }

    optarg = NULL;

    /* Advance to next argv element when current one is exhausted */
    if (next == NULL || *next == '\0') {
        if (optind >= argc ||
            argv[optind][0] != '-' ||
            argv[optind][1] == '\0')
            return -1;

        if (strcmp(argv[optind], "--") == 0) {
            optind++;
            return -1;
        }

        next = argv[optind] + 1; /* skip the leading '-' */
        optind++;
    }

    c  = *next++;
    cp = strchr(optstring, c);

    if (cp == NULL || c == ':') {
        optopt = c;
        if (opterr && optstring[0] != ':')
            fprintf(stderr, "lft: invalid option -- '%c'\n", c);
        return '?';
    }

    if (cp[1] == ':') {             /* option requires an argument */
        if (*next != '\0') {
            optarg = next;
            next   = NULL;
        } else if (optind < argc) {
            optarg = argv[optind++];
        } else {
            optopt = c;
            if (optstring[0] == ':')
                return ':';
            if (opterr)
                fprintf(stderr, "lft: option requires an argument -- '%c'\n", c);
            return '?';
        }
    }

    return c;
}

/* -------------------------------------------------------------------------
 * getopt_long() — GNU-style long-option parser
 *
 * Long options take the form --name or --name=value.
 * When a match is found:
 *   - if longopts[i].flag != NULL  →  *flag = val, return 0
 *   - if longopts[i].flag == NULL  →  return val
 * Short options are handled by delegating to getopt().
 * ------------------------------------------------------------------------- */
int
getopt_long(int argc, char * const argv[], const char *optstring,
            const struct option *longopts, int *longindex)
{
    /* optind == 0: reset (GNU extension) */
    if (optind == 0)
        optind = 1;

    /* Is the current token a long option? */
    if (optind < argc &&
        argv[optind][0] == '-' &&
        argv[optind][1] == '-' &&
        argv[optind][2] != '\0') {

        const char *token   = argv[optind] + 2; /* skip "--" */
        const char *eq      = strchr(token, '=');
        size_t      namelen = eq ? (size_t)(eq - token) : strlen(token);
        int i;

        for (i = 0; longopts[i].name != NULL; i++) {
            if (strncmp(token, longopts[i].name, namelen) == 0 &&
                longopts[i].name[namelen] == '\0') {

                if (longindex)
                    *longindex = i;

                optind++;   /* consume the --name token */
                optarg = NULL;

                switch (longopts[i].has_arg) {
                case required_argument:
                    if (eq) {
                        optarg = (char *)(eq + 1);
                    } else if (optind < argc) {
                        optarg = argv[optind++];
                    } else {
                        /* required argument missing */
                        optopt = longopts[i].val;
                        if (optstring[0] == ':')
                            return ':';
                        if (opterr)
                            fprintf(stderr,
                                    "lft: option '--%s' requires an argument\n",
                                    longopts[i].name);
                        return '?';
                    }
                    break;
                case optional_argument:
                    optarg = eq ? (char *)(eq + 1) : NULL;
                    break;
                case no_argument:
                default:
                    if (eq) {
                        /* argument supplied to a no-argument option */
                        optopt = longopts[i].val;
                        if (opterr)
                            fprintf(stderr,
                                    "lft: option '--%s' doesn't allow an argument\n",
                                    longopts[i].name);
                        return '?';
                    }
                    break;
                }

                if (longopts[i].flag != NULL) {
                    *longopts[i].flag = longopts[i].val;
                    return 0;
                }
                return longopts[i].val;
            }
        }

        /* No match — unknown long option */
        if (opterr)
            fprintf(stderr, "lft: unrecognized option '--%.*s'\n",
                    (int)namelen, token);
        optind++;
        return '?';
    }

    /* "--" end-of-options sentinel */
    if (optind < argc && strcmp(argv[optind], "--") == 0) {
        optind++;
        return -1;
    }

    /* Not a long option — delegate to short-option parser */
    return getopt(argc, (char **)argv, optstring);
}

#endif /* WIN32 */
