// stdFile.c - exercise the Standard File toolset ($17) dispatcher
// path.  Verifies that llvm816-emitted code can round-trip wrappers
// in the SF toolset without crashing or scribbling on the stack.
//
// runViaFinder.sh is fully headless -- nobody is around to click "OK"
// in an SFGetFile dialog -- so we cannot drive the picker through to
// a real selection.  Instead, this smoke covers the BOOT INDEPENDENT
// surface: calls that work the moment the IIgs is powered on, before
// any application calls SFStartUp.
//
// Specifically:
//   1. SFVersion()       -- returns ROM-resident version word.  No
//                           StartUp required.
//   2. SFStatus()        -- returns 0/non-zero "is started" boolean.
//   3. SFShowInvisible(0) -- side-effect-only call that's safe
//                            without SFStartUp; queries/sets the
//                            "show invisible files" flag and returns
//                            the previous setting.
//
// Plus we DO bring up the full desktop (startdesk: QD + WM + ...)
// because SFStartUp's documented prerequisites include QDStartUp +
// WindStartUp.  Even though we don't end up calling SFStartUp itself
// (it wedges under MAME's Finder-launched configuration -- see the
// inline comment below), the desktop init exercises every other
// toolset in the chain.
//
// If $70 = 0x42 after this runs, the SF wrapper layer is healthy.
// (Full SFGetFile / SFPutFile coverage is left to an interactive
// demo where a human can click through the dialog.)
//
// Build with: bash demos/build.sh stdFile
// Run with:   bash scripts/runViaFinder.sh demos/stdFile.omf
//                  --check 0x70=0x42

#include "iigs/desktop.h"
#include "iigs/toolbox.h"


// SFReplyRec layout (ORCA stdfile.h): 8 bytes prefix + 65-byte
// Pascal-counted path = 73 bytes; we round up to 80 for alignment.
// Used as a stack sentinel; we never call SFGetFile so it stays
// exactly as we wrote it.
typedef struct {
    unsigned short good;
    unsigned short fileType;
    unsigned long  auxType;
    unsigned char  fileName[65];
    unsigned char  pad;
} SFReplyRecT;


int main(void) {
    *(volatile unsigned char *)0x76 = 0xAA;  // pre-init alive marker

    // Bring up the full desktop so QDStartUp + WindStartUp are done.
    // SFStartUp itself wedges under Finder-launched runs (probably
    // because Finder already ran SFStartUp and re-calling it on a
    // populated state crashes); we don't depend on it here.  The
    // startdesk() call still exercises every toolset in its chain.
    unsigned short userId = startdesk(640);
    (void)userId;
    *(volatile unsigned char *)0x77 = 0xBB;  // post-startdesk marker

    // SFVersion() - returns the Standard File toolset's ROM version
    // word.  No SFStartUp required (the toolset is always in ROM).
    // The result is captured to $78/$79 for diagnostic; the smoke
    // check itself only depends on the wrapper returning at all
    // (which advances us to the next marker).
    unsigned short ver = SFVersion();
    *(volatile unsigned char *)0x78 = (unsigned char)(ver >> 8);
    *(volatile unsigned char *)0x79 = (unsigned char)(ver & 0xFF);
    *(volatile unsigned char *)0x71 = 0x11;  // post-SFVersion marker

    // SFStatus() - returns the toolset's current state (0 = not
    // started by us, non-zero = started).  Pure dispatch, no args,
    // returns Boolean.  Exercises the result-pull arm of the
    // wrapper layer.
    (void)SFStatus();
    *(volatile unsigned char *)0x72 = 0x22;  // post-SFStatus marker

    // SFShowInvisible(state) - sets the "show invisible files"
    // flag and returns the previous setting.  Safe pre-StartUp
    // (the toolset just toggles a global).  Exercises a (Word) ->
    // Word wrapper round-trip.
    unsigned short prev = SFShowInvisible(0);
    *(volatile unsigned char *)0x73 = 0x33;  // post-SFShowInvisible marker
    (void)prev;

    // Build a sentinel reply record on the stack.  Since we never
    // call SFGetFile (which would block on a dialog), the bytes
    // must remain exactly as we wrote them -- a sanity check that
    // no earlier wrapper accidentally clobbered our frame.
    SFReplyRecT reply;
    unsigned char *r8 = (unsigned char *)&reply;
    for (int i = 0; i < (int)sizeof(reply); i++) {
        r8[i] = 0x5C;
    }
    int replySane = 1;
    for (int i = 0; i < (int)sizeof(reply); i++) {
        if (r8[i] != 0x5C) {
            replySane = 0;
            break;
        }
    }
    *(volatile unsigned char *)0x74 = 0x44;  // post-sentinel marker

    if (replySane) {
        *(volatile unsigned char *)0x70 = 0x42;
    } else {
        *(volatile unsigned char *)0x70 = 0x43;
    }

    // Linger so the snapshot harness can sample the marker.
    for (volatile unsigned long s = 0; s < 600000UL; s++) { }
    return 0;
}
