/*------------------------------------------------------------------------------

 Example source code of an application which runs a BASIC program (test.basic)
 synchronously and adds a command (FILESELECT) to BASIC.

*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <exec/exec.h>
#include <libraries/asl.h>
#include <utility/tagitem.h>
#include <clib/exec_protos.h>
#include <clib/asl_protos.h>
#include <pragmas/exec_pragmas.h>
#include <pragmas/asl_pragmas.h>

// includes for BASIC.library

#include "include/basic.h"
#include "clib/basiclib_protos.h"
#include "pragmas/basiclib_pragmas.h"

// prototypes

extern __saveds LONG parser(void *context, UBYTE *commandline);

// globals

struct Library *AslBase;
struct Library *BASICBase;

/*------------------------------------------------------------------------------

 Main entry point. Note that this program should be started with the stack set
 to 16 KB or higher (because the interpreter is executed synchronously, ie. it
 uses our stack).

*/

int
main(int argc, UBYTE **argv)
{
    int rc = 20;

    if (AslBase = OpenLibrary("asl.library", 37))
    {
        if (BASICBase = OpenLibrary("BASIC.library", BASIC_VERSION))
        {
            // prepare to create interpreter with active callback hook (to add commands to BASIC)

            static struct TagItem ctags[] = { BASIC_CONSOLE, (ULONG)NULL, BASIC_PARSER, (ULONG)parser, TAG_END };

            // use current console (BASIC_CONSOLE, NULL) if not started via wb, ie. if argc != 0

            void *context;

            if (argc)
                context = basic_context(&ctags[0]);
            else
                context = basic_context(&ctags[1]);

            if (context)
            {
                static struct TagItem ltags[] = { BASIC_FILENAME, (ULONG)"test.basic", TAG_END };

                // load test program into interpreter

                if (basic_load(context, ltags))
                {
                    printf("Error loading program test.basic (error code %d)\n", rc);
                }
                else
                {
                    // main loop: execute program synchronously

                    do
                    {
                        rc = basic_iterate(context);

                    } while (rc == BASIC_OK);
                }

                // dispose of interpreter context

                rc = basic_dispose(context);
            }
            else
                puts("Failed to create interpreter context");

            CloseLibrary(BASICBase);
        }
        else
            puts("Can not open BASIC.library");

        CloseLibrary(AslBase);
    }
    else
        puts("Can not open asl.library");

    return(rc);
}

/*------------------------------------------------------------------------------

 This hook function is called by the BASIC interpreter if it detects an unknown
 command. This example implements a FILESELECT command.

*/

__saveds LONG
parser(void *context, UBYTE *commandline)
{
    // check if FILESELECT command is in line (real programs must have a case-insensitive check)

    if (memcmp(commandline, "FILESELECT ", 11) == 0)
    {
        void *args;

        // skip over FILESELECT to arguments

        commandline += 11;

        // preparse pattern

        if (args = basic_preparse("TITLE/K,TO/V/A"))
        {
            // template contains two options that need to be examined

            LONG values[2];

            // parse command line, have results put into values array

            if (basic_readargs(context, args, commandline, values) == 0)
            {
                struct FileRequester *request;
                UBYTE                *title;
                BOOL                  selection;

                // TITLE/K (unlike TO/V/A) is an optional argument, check if we got it

                title = (UBYTE *)values[0];

                if (title == NULL)
                {
                    title = "Choose a file";
                }

                // allocate a file requester

                if (request = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest, ASL_Hail, title, TAG_DONE))
                {
                    // show file requester

                    if (selection = AslRequest(request, NULL))
                    {
                        // assign selected file to variable specified after TO/K

                        basic_let(context, (UBYTE *)values[1], request->fr_File);
                    }

                    FreeAslRequest(request);
                }
                else
                {
                    basic_message(context, "Error in asl.library");

                    return(BASIC_STOP);
                }

                // free memory allocated for parsing

                basic_freeargs(args);

                // clear variable specified after TO/K if no file was selected

                if (selection == FALSE)
                {
                    basic_erase(context, (UBYTE *)values[1]);
                }

                // signal that we have accepted (and processed) the command line

                return(BASIC_ACCEPT);
            }
            else
            {
                basic_freeargs(args);

                return(BASIC_STOP);
            }
        }
        else
            return(BASIC_STOP);
    }

    // defer processing to interpreter

    return(BASIC_DEFER);
}
