// manifest.bux — Manifest parser for bux.toml files // Parses package metadata: name, version, type, build output. module Manifest { extern func bux_strlen(s: String) -> uint; // --------------------------------------------------------------------------- // Manifest struct // --------------------------------------------------------------------------- struct Manifest { name: String; version: String; pkgType: String; output: String; depCount: int; depName0: String; depUrl0: String; depName1: String; depUrl1: String; depName2: String; depUrl2: String; depName3: String; depUrl3: String; depName4: String; depUrl4: String; depName5: String; depUrl5: String; depName6: String; depUrl6: String; depName7: String; depUrl7: String; } // --------------------------------------------------------------------------- // Simple TOML parser (handles [Package] and [Build] sections) // --------------------------------------------------------------------------- func Manifest_Parse(content: String) -> Manifest { var m: Manifest; m.name = ""; m.version = "0.1.0"; m.pkgType = "bin"; m.output = "Bin"; m.depCount = 0; if String_Eq(content, "") { return m; } var currentSection: String = ""; let count: uint = String_SplitCount(content, "\n"); var i: uint = 0; while i < count { let line: String = String_SplitPart(content, "\n", i); // Skip empty lines and comments if String_Eq(line, "") { i = i + 1; continue; } if String_StartsWith(line, "#") { i = i + 1; continue; } // Section header: [Section] if String_StartsWith(line, "[") { if String_StartsWith(line, "[Package]") { currentSection = "Package"; } else if String_StartsWith(line, "[Build]") { currentSection = "Build"; } else if String_StartsWith(line, "[dependencies]") { currentSection = "dependencies"; } else { currentSection = ""; } i = i + 1; continue; } // Key = Value let eqCount: uint = String_SplitCount(line, "="); if eqCount >= 2 { let key: String = String_Trim(String_SplitPart(line, "=", 0)); let rawVal: String = String_Trim(String_SplitPart(line, "=", 1)); // Strip quotes from value var val: String = rawVal; if String_StartsWith(val, "\"") && String_EndsWith(val, "\"") { let vlen: uint = bux_strlen(val); if vlen >= 2 { val = String_Slice(val, 1, vlen - 2); } } if String_Eq(currentSection, "Package") { if String_Eq(key, "Name") { m.name = val; } if String_Eq(key, "Version") { m.version = val; } if String_Eq(key, "Type") { m.pkgType = val; } } else if String_Eq(currentSection, "Build") { if String_Eq(key, "Output") { m.output = val; } } else if String_Eq(currentSection, "dependencies") { if m.depCount < 8 { if m.depCount == 0 { m.depName0 = key; m.depUrl0 = val; } else if m.depCount == 1 { m.depName1 = key; m.depUrl1 = val; } else if m.depCount == 2 { m.depName2 = key; m.depUrl2 = val; } else if m.depCount == 3 { m.depName3 = key; m.depUrl3 = val; } else if m.depCount == 4 { m.depName4 = key; m.depUrl4 = val; } else if m.depCount == 5 { m.depName5 = key; m.depUrl5 = val; } else if m.depCount == 6 { m.depName6 = key; m.depUrl6 = val; } else if m.depCount == 7 { m.depName7 = key; m.depUrl7 = val; } m.depCount = m.depCount + 1; } } } i = i + 1; } return m; } // --------------------------------------------------------------------------- // Dependency helpers // --------------------------------------------------------------------------- func Manifest_HasDep(m: Manifest, name: String) -> bool { var i: int = 0; while i < m.depCount { var depName: String = ""; if i == 0 { depName = m.depName0; } else if i == 1 { depName = m.depName1; } else if i == 2 { depName = m.depName2; } else if i == 3 { depName = m.depName3; } else if i == 4 { depName = m.depName4; } else if i == 5 { depName = m.depName5; } else if i == 6 { depName = m.depName6; } else if i == 7 { depName = m.depName7; } if String_Eq(depName, name) { return true; } i = i + 1; } return false; } func Manifest_GetDepUrl(m: Manifest, name: String) -> String { var i: int = 0; while i < m.depCount { var depName: String = ""; var depUrl: String = ""; if i == 0 { depName = m.depName0; depUrl = m.depUrl0; } else if i == 1 { depName = m.depName1; depUrl = m.depUrl1; } else if i == 2 { depName = m.depName2; depUrl = m.depUrl2; } else if i == 3 { depName = m.depName3; depUrl = m.depUrl3; } else if i == 4 { depName = m.depName4; depUrl = m.depUrl4; } else if i == 5 { depName = m.depName5; depUrl = m.depUrl5; } else if i == 6 { depName = m.depName6; depUrl = m.depUrl6; } else if i == 7 { depName = m.depName7; depUrl = m.depUrl7; } if String_Eq(depName, name) { return depUrl; } i = i + 1; } return ""; } func Manifest_AddDep(m: *Manifest, name: String, url: String) -> bool { if Manifest_HasDep(*m, name) { return false; } if m.depCount >= 8 { return false; } if m.depCount == 0 { m.depName0 = name; m.depUrl0 = url; } else if m.depCount == 1 { m.depName1 = name; m.depUrl1 = url; } else if m.depCount == 2 { m.depName2 = name; m.depUrl2 = url; } else if m.depCount == 3 { m.depName3 = name; m.depUrl3 = url; } else if m.depCount == 4 { m.depName4 = name; m.depUrl4 = url; } else if m.depCount == 5 { m.depName5 = name; m.depUrl5 = url; } else if m.depCount == 6 { m.depName6 = name; m.depUrl6 = url; } else if m.depCount == 7 { m.depName7 = name; m.depUrl7 = url; } m.depCount = m.depCount + 1; return true; } func Manifest_RemoveDep(m: *Manifest, name: String) -> bool { var found: int = -1; var i: int = 0; while i < m.depCount { var depName: String = ""; if i == 0 { depName = m.depName0; } else if i == 1 { depName = m.depName1; } else if i == 2 { depName = m.depName2; } else if i == 3 { depName = m.depName3; } else if i == 4 { depName = m.depName4; } else if i == 5 { depName = m.depName5; } else if i == 6 { depName = m.depName6; } else if i == 7 { depName = m.depName7; } if String_Eq(depName, name) { found = i; break; } i = i + 1; } if found < 0 { return false; } i = found; while i < m.depCount - 1 { if i == 0 { m.depName0 = m.depName1; m.depUrl0 = m.depUrl1; } else if i == 1 { m.depName1 = m.depName2; m.depUrl1 = m.depUrl2; } else if i == 2 { m.depName2 = m.depName3; m.depUrl2 = m.depUrl3; } else if i == 3 { m.depName3 = m.depName4; m.depUrl3 = m.depUrl4; } else if i == 4 { m.depName4 = m.depName5; m.depUrl4 = m.depUrl5; } else if i == 5 { m.depName5 = m.depName6; m.depUrl5 = m.depUrl6; } else if i == 6 { m.depName6 = m.depName7; m.depUrl6 = m.depUrl7; } i = i + 1; } m.depCount = m.depCount - 1; return true; } // --------------------------------------------------------------------------- // Serialize manifest back to TOML // --------------------------------------------------------------------------- func Manifest_ToString(m: Manifest) -> String { let sb: StringBuilder = StringBuilder_New(); StringBuilder_Append(&sb, "[Package]\n"); StringBuilder_Append(&sb, "Name = \""); StringBuilder_Append(&sb, m.name); StringBuilder_Append(&sb, "\"\n"); StringBuilder_Append(&sb, "Version = \""); StringBuilder_Append(&sb, m.version); StringBuilder_Append(&sb, "\"\n"); StringBuilder_Append(&sb, "Type = \""); StringBuilder_Append(&sb, m.pkgType); StringBuilder_Append(&sb, "\"\n\n"); StringBuilder_Append(&sb, "[Build]\n"); StringBuilder_Append(&sb, "Output = \""); StringBuilder_Append(&sb, m.output); StringBuilder_Append(&sb, "\"\n"); if m.depCount > 0 { StringBuilder_Append(&sb, "\n[dependencies]\n"); var i: int = 0; while i < m.depCount { var depName: String = ""; var depUrl: String = ""; if i == 0 { depName = m.depName0; depUrl = m.depUrl0; } else if i == 1 { depName = m.depName1; depUrl = m.depUrl1; } else if i == 2 { depName = m.depName2; depUrl = m.depUrl2; } else if i == 3 { depName = m.depName3; depUrl = m.depUrl3; } else if i == 4 { depName = m.depName4; depUrl = m.depUrl4; } else if i == 5 { depName = m.depName5; depUrl = m.depUrl5; } else if i == 6 { depName = m.depName6; depUrl = m.depUrl6; } else if i == 7 { depName = m.depName7; depUrl = m.depUrl7; } StringBuilder_Append(&sb, depName); StringBuilder_Append(&sb, " = \""); StringBuilder_Append(&sb, depUrl); StringBuilder_Append(&sb, "\"\n"); i = i + 1; } } return StringBuilder_Build(&sb); } // --------------------------------------------------------------------------- // Load manifest from file // --------------------------------------------------------------------------- func Manifest_Load(path: String) -> Manifest { let content: String = ReadFile(path); return Manifest_Parse(content); } }