// autostart.c - Program to be run by the Disk Basic DOS command.
// By Pierre Sarrazin <http://sarrazip.com/>
// This file is in the public domain.
//
// Reference: Roger Schrag, "A Special Use For The DOS Command",
// The Rainbow, November 1984, p.140.
//
// To compile: cmoc --dos autostart.c
// To install on CoCo disk image: install-coco-boot-loader some-image.dsk autostart.bin
// To run on CoCo: type DOS and <Enter> to automatically run *.BAS.
//
// Version history:
// 0.1.0    2016-01-16      Use of legacy.h discontinued.
// 0.1.1    2018-04-03      Adapted to CMOC 0.1.51 (const).
// 0.1.2    2018-08-04      Basic line now forced to be uppercase.

#include <coco.h>

#define ENDFLG  0x00            // STOP/END FLAG: POSITIVE=STOP, NEG=END
#define CINBFL  0x70            // CONSOLE IN BUFFER FLAG: 00=NOT EMPTY, $FF=EMPTY
#define RVEC4   0x016a          // RAM hook: CONSOLE IN


byte oldHookInstr;
word oldHookAddr;
const char *basicLineReader;


void feedKeyboard()
{
    word preservedX;
    asm("stx", preservedX);

    * (byte *) CINBFL = 0;  // console in buffer now not empty

    char nextBasicByte = (char) toupper(*basicLineReader);
    ++basicLineReader;
    if (nextBasicByte == 0)  // if finished returning Basic line
    {
        * (byte *) RVEC4 = oldHookInstr;
        * (word *) (RVEC4 + 1) = oldHookAddr;
        nextBasicByte = '\r';  // return "Enter" to cause execution of Basic line
    }

    asm {
        lda     nextBasicByte
        ldx     preservedX
        tfr     u,s             // discard stack frame
        leas    4,s             // discard previous stack frame ptr and return addr
        rts                     // return to caller of CONSOLE IN
    }
}


int main()
{
    * (byte *) ENDFLG = - * (byte *) ENDFLG;  // why?

    basicLineReader =
        #ifndef COMMAND
        "RUN\"*.BAS\""
        #else
        COMMAND
        #endif
        ;

    // Install function feedKeyboard() as CONSOLE IN routine.
    //
    oldHookInstr = * (byte *) RVEC4;
    oldHookAddr  = * (word *) (RVEC4 + 1);

    * (byte *) RVEC4 = 0x7e;  // JMP instruction
    * (word *) (RVEC4 + 1) = feedKeyboard;

    * (word *) 0x2600 = 0;  // overwrite "OS" marker with two null bytes
    
    asm("jmp", "$ac7c");  // go interpret a Basic line (which is read from console)

    return 0;  // avoids compiler error
}
