/* Eldo dot cards that ngspice does not implement.
 *
 * A stimulus file written for Eldo carries output and measurement cards
 * alongside the sources. Without this pass the first of them aborts the deck
 * with "unimplemented dot command", so a file that is otherwise perfectly
 * usable cannot be read at all. Each card below is turned into a comment and
 * announced once per deck, naming what was dropped and what to use instead.
 *
 * Ignoring is safe for the output and measurement cards: they produce results
 * rather than affecting them, so what is lost is a number you can get another
 * way. It is NOT harmless for .ramp and .use, which influence how the
 * operating point is reached and what state the run starts from -- those two
 * say so explicitly in their warning, because a deck that reads cleanly and
 * starts from the wrong state is worse than one that refuses to read.
 *
 * The warning is per card type, not per occurrence: real decks carry hundreds
 * of .extract lines and a warning per line would bury everything else.
 */

#include "ngspice/ngspice.h"

#include "ngspice/cpdefs.h"
#include "ngspice/fteinp.h"
#include "ngspice/stringskip.h"
#include "ngspice/stringutil.h"

#include "inpcom.h"
#include "inpeldo.h"

struct eldo_card {
    const char *name;
    const char *what;    /* what the card does in Eldo */
    const char *advice;  /* the ngspice way to get it */
    bool affects_result; /* dropping it can change the answer, not just output */
    bool warned;
};

static struct eldo_card eldo_cards[] = {
    {".conso", "supply-consumption measurement",
            "use .meas tran <name> avg i(<source>)", FALSE, FALSE},
    {".extract", "post-processing measurement",
            "use .meas, or measure in .control", FALSE, FALSE},
    {".defwave", "a named derived waveform",
            "use let in .control", FALSE, FALSE},
    {".plotbus", "plots a bus as a grouped digital waveform",
            "plot the individual bits", FALSE, FALSE},
    {".checkbus", "checks a bus against expected values",
            "compare the bits with .meas or in .control", FALSE, FALSE},
    {".ramp", "ramps the sources to help the operating point converge",
            "see the operating-point options; this one can change how, or "
            "whether, the run converges", TRUE, FALSE},
    {".use", "loads a saved node state as .ic or .nodeset",
            ".include the state file if it holds .ic/.nodeset cards; without "
            "it the run starts from a different state", TRUE, FALSE},
};

static const int n_eldo_cards = (int) NUMELEMS(eldo_cards);


void inpeldo_reset(void)
{
    int i;
    for (i = 0; i < n_eldo_cards; i++)
        eldo_cards[i].warned = FALSE;
}


void inpeldo_ignore(struct card *deck)
{
    struct card *c;

    for (c = deck; c; c = c->nextcard) {
        const char *s = skip_ws(c->line);
        int i;

        if (*s != '.')
            continue;

        for (i = 0; i < n_eldo_cards; i++) {
            struct eldo_card *e = &eldo_cards[i];
            const char *rest;

            if (!ciprefix(e->name, s))
                continue;
            /* .use must not swallow a longer card that starts the same way */
            rest = s + strlen(e->name);
            if (*rest && !isspace_c(*rest))
                continue;

            if (!e->warned) {
                e->warned = TRUE;
                fprintf(cp_err,
                        "Warning: %s (%s) is not supported and is ignored%s\n"
                        "    %s\n"
                        "    first seen in %s, line %d\n",
                        e->name, e->what,
                        e->affects_result ? " -- THIS CAN CHANGE THE RESULT"
                                          : "",
                        e->advice,
                        c->linesource ? c->linesource : "<input>",
                        c->linenum_orig);
            }

            {
                char *old = c->line;
                c->line = tprintf("* ignored: %s", old);
                tfree(old);
            }
            break;
        }
    }
}
