/************************************************************************************/ /**
// Copyright (c) 2006-2024 Advanced Micro Devices, Inc. All rights reserved.
/// \author AMD Developer Tools Team
/// \file
****************************************************************************************/
#ifndef OPTION_H
#define OPTION_H

#include <cstring>

static inline int match(const char* opt, const char* lname)
{
    while (*lname && *opt && *opt != '=')
    {
        if (*opt != *lname)
        {
            return 0;
        }

        opt++;
        lname++;
    }

    return !(*lname) && (!(*opt) || *opt == '=');
}

class Option
{
public:
    Option(void);
    void Reset(void);
    int  GetIndex(void);
    typedef struct
    {
        int         sname;
        const char* lname;
    } Definition;
    enum State
    {
        DONE,
        LONG,
        SHORT,
        ARG
    };
    int         Parse(int argc, char* argv[], const Definition* def);
    const char* GetArgument(int argc, char* argv[]);

private:
    void        Advance(int argc, char* argv[]);
    int         index;
    const char* where;
    int         state;
};

Option::Option(void)
{
    Reset();
}

int Option::GetIndex(void)
{
    return index;
}

const char* Option::GetArgument(int argc, char* argv[])
{
    Advance(argc, argv);
    const char* arg = where;
    where           = NULL;
    return arg;
}

void Option::Reset(void)
{
    index = 1;
    where = NULL;
    state = DONE;
}

void Option::Advance(int argc, char* argv[])
{
    if (!where || !(*where))
    {
        if (index < argc)
        {
            where = argv[index++];

            if (*where == '-')
            {
                where++;

                if (*where == '-')
                {
                    where++;

                    if (!(*where))
                    {
                        state = DONE;
                    }
                    else
                    {
                        state = LONG;
                    }
                }
                else
                {
                    state = SHORT;
                }
            }
            else
            {
                state = ARG;
            }
        }
        else
        {
            state = DONE;
        }
    }
}

int Option::Parse(int argc, char* argv[], const Definition* def)
{
    // advance to next command line option if needed
    Advance(argc, argv);

    // move to next argument
    switch (state)
    {
    case SHORT:
        for (; def->sname; def++)
        {
            if (def->sname == *where)
            {
                where++;
                return def->sname;
            }
        }

        return '?';

    case LONG:
        for (; def->lname; def++)
        {
            if (match(where, def->lname))
            {
                where += strcspn(where, "=") + 1;
                return def->sname;
            }
        }

        return '?';

    case ARG:
        return '?';

    default:
        return -1;
    }
}

#endif
