156 lines
6.6 KiB
C++
156 lines
6.6 KiB
C++
// cxxStreamProbe.cpp - exercise the C++ stream + format + path surface
|
|
// (Phase 5.4). Probes the cout-replacement pattern:
|
|
//
|
|
// 1. etl::string_stream<<int composing into a fixed-capacity buffer.
|
|
// 2. etl::format_to(buf, "{}", 42) — the std::format substitute (gated
|
|
// behind CXX_STREAM_PROBE_WITH_FORMAT; pulls ~50 KB of format
|
|
// machinery — see step 5 size spike below).
|
|
// 3. iigs::path::pathJoin + pathSplit + pathNormalize on a ProDOS-style
|
|
// colon-separated path.
|
|
// 4. Compile-time contract that etl::chrono::*_clock::duration::rep is
|
|
// int32_t (the i64-libcall guard from etl_profile.h).
|
|
//
|
|
// Build flavors:
|
|
// default : path + string_stream + chrono
|
|
// contract. Single-bank bin.
|
|
// GNO_CFLAGS=-DCXX_STREAM_PROBE_WITH_FORMAT=1
|
|
// : adds etl::format_to probe.
|
|
// Pulls in parse_format_spec /
|
|
// vformat_to / per-type
|
|
// format_aligned_int /
|
|
// format_alternate_form —
|
|
// total ~50 KB delta over the
|
|
// no-format flavor, crosses
|
|
// bank-0 IO window. Requires
|
|
// multi-seg or --layer2 link.
|
|
// Phase 5.4 step 5 size-spike
|
|
// outcome: downgrade scope
|
|
// (FP-format / full format
|
|
// are layer2-opt-in, not the
|
|
// default).
|
|
//
|
|
// Marker layout (16-bit little-endian at $025xxx):
|
|
// $025010 = 0xBEEF main entered
|
|
// $025012 = etl::chrono::steady_clock duration rep is i32 sentinel (1/0)
|
|
// $025014 = string_stream emitted expected string (1/0)
|
|
// $025016 = etl::format_to emitted expected string (1/0; sentinel 1
|
|
// when format probe gated off)
|
|
// $025018 = pathJoin("USR", "BIN") => "USR:BIN" check (1/0)
|
|
// $02501A = pathNormalize("USR::BIN::..::LIB") => "USR:LIB" check (1/0)
|
|
// $02501C = pathSplit("USR:BIN:LS") => parent="USR:BIN" + leaf="LS" (1/0)
|
|
// $02501E = pathJoin rejects 65-char component (1 = correctly rejected)
|
|
// $025020 = pathNormalize rejects 9-deep path (1 = correctly rejected)
|
|
// $025000 = 0xC0DE reached end-of-main (sentinel for runInGno --check)
|
|
#include <stdint.h>
|
|
|
|
#include <iigs/path.h>
|
|
#include <sstream>
|
|
#include "etl/chrono.h"
|
|
#include "etl/string.h"
|
|
#include "etl/string_stream.h"
|
|
#include "etl/string_view.h"
|
|
#include "etl/to_string.h"
|
|
|
|
#ifdef CXX_STREAM_PROBE_WITH_FORMAT
|
|
#include "etl/format.h"
|
|
#endif
|
|
|
|
|
|
static uint16_t streq(const char *a, const char *b) {
|
|
while (*a && *b) {
|
|
if (*a != *b) {
|
|
return 0;
|
|
}
|
|
a++;
|
|
b++;
|
|
}
|
|
return (uint16_t)((*a == 0 && *b == 0) ? 1 : 0);
|
|
}
|
|
|
|
|
|
int main(void) {
|
|
*(volatile uint16_t *)0x025010UL = 0xBEEF;
|
|
|
|
// Compile-time contract: clock-rep stays i32 (etl_profile.h override).
|
|
// Avoids i64 chrono libcalls in stream + format demos.
|
|
static_assert(sizeof(etl::chrono::steady_clock::duration::rep) == 4,
|
|
"etl::chrono::steady_clock::rep must be i32 -- check "
|
|
"ETL_CHRONO_STEADY_CLOCK_DURATION in etl_profile.h");
|
|
*(volatile uint16_t *)0x025012UL = 1;
|
|
|
|
// ---- (1) etl::string_stream << int ------------------------------
|
|
// Flattened layout (no nested {}-scopes) — the bracketed-scope form
|
|
// tripped a W65816 Wide32->2xi16 lowering bug on three nested
|
|
// etl::string<32> stack allocations. Sequential single-string use
|
|
// works fine and is the documented cout-replacement idiom.
|
|
{
|
|
etl::string<32> streamBuf;
|
|
etl::string_stream ss(streamBuf);
|
|
ss << "x=" << 42;
|
|
{
|
|
etl::string<32> tmp;
|
|
etl::string_stream ssTmp(tmp);
|
|
ssTmp << "y=" << 7;
|
|
{
|
|
etl::string<32> third;
|
|
etl::string_stream ss3(third);
|
|
ss3 << "z=" << 3;
|
|
*(volatile uint16_t *)0x025014UL = streq(ss3.str().c_str(), "z=3");
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---- (2) etl::format_to(buf, "{}", 42) --------------------------
|
|
#ifdef CXX_STREAM_PROBE_WITH_FORMAT
|
|
etl::string<32> formatBuf;
|
|
etl::format_to(formatBuf, "{}", 42);
|
|
*(volatile uint16_t *)0x025016UL = streq(formatBuf.c_str(), "42");
|
|
#else
|
|
// Sentinel: format probe gated off in single-bank flavor. See
|
|
// docs/GAP_CLOSURE_PLAN.md Phase 5.4 step 5 (size spike >10 KB
|
|
// delta -- explicit downgrade to layer2-opt-in).
|
|
*(volatile uint16_t *)0x025016UL = 1;
|
|
#endif
|
|
|
|
// ---- (3a) pathJoin -----------------------------------------------
|
|
char joinOut[64];
|
|
bool joinOk = iigs::path::pathJoin("USR", "BIN", joinOut, sizeof(joinOut));
|
|
*(volatile uint16_t *)0x025018UL =
|
|
(uint16_t)((joinOk && streq(joinOut, "USR:BIN")) ? 1 : 0);
|
|
|
|
// ---- (3b) pathNormalize collapsing & .. ---------------------------
|
|
char normOut[64];
|
|
bool normOk = iigs::path::pathNormalize("USR::BIN::..::LIB",
|
|
normOut, sizeof(normOut));
|
|
*(volatile uint16_t *)0x02501AUL =
|
|
(uint16_t)((normOk && streq(normOut, "USR:LIB")) ? 1 : 0);
|
|
|
|
// ---- (3c) pathSplit -----------------------------------------------
|
|
char splitParent[64];
|
|
char splitLeaf[64];
|
|
bool splitOk = iigs::path::pathSplit("USR:BIN:LS",
|
|
splitParent, sizeof(splitParent),
|
|
splitLeaf, sizeof(splitLeaf));
|
|
*(volatile uint16_t *)0x02501CUL =
|
|
(uint16_t)((splitOk && streq(splitParent, "USR:BIN") &&
|
|
streq(splitLeaf, "LS")) ? 1 : 0);
|
|
|
|
// ---- (3d) 65-char component rejection -----------------------------
|
|
char bigName[80];
|
|
for (uint16_t i = 0; i < 65; i++) {
|
|
bigName[i] = 'A';
|
|
}
|
|
bigName[65] = 0;
|
|
char bigOut[128];
|
|
bool bigRejected = !iigs::path::pathJoin("USR", bigName, bigOut, sizeof(bigOut));
|
|
*(volatile uint16_t *)0x02501EUL = (uint16_t)(bigRejected ? 1 : 0);
|
|
|
|
// ---- (3e) 9-deep path rejection -----------------------------------
|
|
char deepOut[128];
|
|
bool deepRejected = !iigs::path::pathNormalize(
|
|
"A:B:C:D:E:F:G:H:I", deepOut, sizeof(deepOut));
|
|
*(volatile uint16_t *)0x025020UL = (uint16_t)(deepRejected ? 1 : 0);
|
|
|
|
*(volatile uint16_t *)0x025000UL = 0xC0DE;
|
|
return 0;
|
|
}
|