From 1badba03d8f5e14c061a15a5b1ac61601b4b2029 Mon Sep 17 00:00:00 2001 From: Rangi Date: Mon, 13 Oct 2025 13:14:22 -0400 Subject: [PATCH] Clean up some `#define` callables These are used where anonymous functions would not be sufficient --- src/fix/main.cpp | 22 +++++++------- src/gfx/pal_spec.cpp | 28 ++++++++--------- src/link/sdas_obj.cpp | 71 +++++++++++++++++++++++++------------------ 3 files changed, 66 insertions(+), 55 deletions(-) diff --git a/src/fix/main.cpp b/src/fix/main.cpp index f11d2d62..50714f06 100644 --- a/src/fix/main.cpp +++ b/src/fix/main.cpp @@ -180,21 +180,21 @@ int main(int argc, char *argv[]) { options.fixSpec = 0; while (*musl_optarg) { switch (*musl_optarg) { -#define OVERRIDE_SPEC(cur, bad, curFlag, badFlag) \ - case STR(cur)[0]: \ +#define overrideSpec(cur, bad, curFlag, badFlag) \ + case cur: \ if (options.fixSpec & badFlag) { \ - warnx("'" STR(cur) "' overriding '" STR(bad) "' in fix spec"); \ + warnx("'%c' overriding '%c' in fix spec", cur, bad); \ } \ options.fixSpec = (options.fixSpec & ~badFlag) | curFlag; \ break -#define overrideSpecs(fix, fixFlag, trash, trashFlag) \ - OVERRIDE_SPEC(fix, trash, fixFlag, trashFlag); \ - OVERRIDE_SPEC(trash, fix, trashFlag, fixFlag) - overrideSpecs(l, FIX_LOGO, L, TRASH_LOGO); - overrideSpecs(h, FIX_HEADER_SUM, H, TRASH_HEADER_SUM); - overrideSpecs(g, FIX_GLOBAL_SUM, G, TRASH_GLOBAL_SUM); -#undef OVERRIDE_SPEC -#undef overrideSpecs +#define overrideSpecPair(fix, fixFlag, trash, trashFlag) \ + overrideSpec(fix, trash, fixFlag, trashFlag); \ + overrideSpec(trash, fix, trashFlag, fixFlag) + overrideSpecPair('l', FIX_LOGO, 'L', TRASH_LOGO); + overrideSpecPair('h', FIX_HEADER_SUM, 'H', TRASH_HEADER_SUM); + overrideSpecPair('g', FIX_GLOBAL_SUM, 'G', TRASH_GLOBAL_SUM); +#undef overrideSpec +#undef overrideSpecPair default: fatal("Invalid character '%c' in fix spec", *musl_optarg); diff --git a/src/gfx/pal_spec.cpp b/src/gfx/pal_spec.cpp index 15d8c908..b8b08704 100644 --- a/src/gfx/pal_spec.cpp +++ b/src/gfx/pal_spec.cpp @@ -188,14 +188,6 @@ static bool readLine(std::filebuf &file, std::string &buffer) { } } -#define requireLine(kind, filename, file, buffer) \ - do { \ - if (!readLine(file, buffer)) { \ - error(kind " palette file \"%s\" is shorter than expected", filename); \ - return; \ - } \ - } while (0) - static void warnExtraColors( char const *kind, char const *filename, uint16_t nbColors, uint16_t maxNbColors ) { @@ -254,21 +246,28 @@ static std::optional parseColor(std::string const &str, size_t &n, uint16_ static void parsePSPFile(char const *filename, std::filebuf &file) { // https://www.selapa.net/swatches/colors/fileformats.php#psp_pal +#define requireLine() \ + do { \ + line.clear(); \ + if (!readLine(file, line)) { \ + error("PSP palette file \"%s\" is shorter than expected", filename); \ + return; \ + } \ + } while (0) + std::string line; if (!readLine(file, line) || line != "JASC-PAL") { error("File \"%s\" is not a valid PSP palette file", filename); return; } - line.clear(); - requireLine("PSP", filename, file, line); + requireLine(); if (line != "0100") { error("Unsupported PSP palette file version \"%s\"", line.c_str()); return; } - line.clear(); - requireLine("PSP", filename, file, line); + requireLine(); size_t n = 0; std::optional nbColors = parseDec(line, n); if (!nbColors || n != line.length()) { @@ -284,8 +283,7 @@ static void parsePSPFile(char const *filename, std::filebuf &file) { options.palSpec.clear(); for (uint16_t i = 0; i < *nbColors; ++i) { - line.clear(); - requireLine("PSP", filename, file, line); + requireLine(); n = 0; std::optional color = parseColor(line, n, i + 1); @@ -306,6 +304,8 @@ static void parsePSPFile(char const *filename, std::filebuf &file) { } options.palSpec.back()[i % options.nbColorsPerPal] = *color; } + +#undef requireLine } static void parseGPLFile(char const *filename, std::filebuf &file) { diff --git a/src/link/sdas_obj.cpp b/src/link/sdas_obj.cpp index 78e0835c..656295da 100644 --- a/src/link/sdas_obj.cpp +++ b/src/link/sdas_obj.cpp @@ -138,23 +138,30 @@ void sdobj_ReadFile(FileStackNode const &src, FILE *file, std::vector &f line.reserve(256); char const *token; -#define getToken(ptr, ...) \ - do { \ - token = strtok((ptr), delim); \ - if (!token) { \ - fatalAt(where, __VA_ARGS__); \ - } \ - } while (0) -#define expectEol(...) \ +#define expectEol(lineType) \ do { \ token = strtok(nullptr, delim); \ if (token) { \ - fatalAt(where, __VA_ARGS__); \ + fatalAt(where, "'%c' line is too long", (lineType)); \ + } \ + } while (0) +#define expectNext(ptr, lineType) \ + do { \ + token = strtok((ptr), delim); \ + if (!token) { \ + fatalAt(where, "'%c' line is too short", (lineType)); \ + } \ + } while (0) +#define expectRelocation() \ + do { \ + token = strtok(nullptr, delim); \ + if (!token) { \ + fatalAt(where, "Incomplete relocation"); \ } \ } while (0) #define expectToken(expected, lineType) \ do { \ - getToken(nullptr, "'%c' line is too short", (lineType)); \ + expectNext(nullptr, lineType); \ if (strcasecmp(token, (expected)) != 0) { \ fatalAt( \ where, \ @@ -223,12 +230,15 @@ void sdobj_ReadFile(FileStackNode const &src, FILE *file, std::vector &f } // Expected format: "A areas S global symbols" - getToken(line.data(), "Empty 'H' line"); + token = strtok(line.data(), delim); + if (!token) { + fatalAt(where, "Empty 'H' line"); + } uint32_t expectedNbAreas = readInt(where, token, numberBase); expectToken("areas", 'H'); - getToken(nullptr, "'H' line is too short"); + expectNext(nullptr, 'H'); uint32_t expectedNbSymbols = readInt(where, token, numberBase); fileSymbols.reserve(expectedNbSymbols); @@ -236,7 +246,7 @@ void sdobj_ReadFile(FileStackNode const &src, FILE *file, std::vector &f expectToken("symbols", 'H'); - expectEol("'H' line is too long"); + expectEol('H'); // Now, let's parse the rest of the lines as they come! @@ -267,7 +277,7 @@ void sdobj_ReadFile(FileStackNode const &src, FILE *file, std::vector &f curSection->src = where.src; curSection->lineNo = where.lineNo; - getToken(line.data(), "'A' line is too short"); + expectNext(line.data(), 'A'); assume(strlen(token) != 0); // This should be impossible, tokens are non-empty // The following is required for fragment offsets to be reliably predicted for (FileSection &entry : fileSections) { @@ -279,7 +289,7 @@ void sdobj_ReadFile(FileStackNode const &src, FILE *file, std::vector &f expectToken("size", 'A'); - getToken(nullptr, "'A' line is too short"); + expectNext(nullptr, 'A'); uint32_t tmp = readInt(where, token, numberBase); @@ -294,7 +304,7 @@ void sdobj_ReadFile(FileStackNode const &src, FILE *file, std::vector &f expectToken("flags", 'A'); - getToken(nullptr, "'A' line is too short"); + expectNext(nullptr, 'A'); tmp = readInt(where, token, numberBase); if (tmp & (1 << AREA_PAGING)) { fatalAt(where, "Paging is not supported"); @@ -313,12 +323,12 @@ void sdobj_ReadFile(FileStackNode const &src, FILE *file, std::vector &f expectToken("addr", 'A'); - getToken(nullptr, "'A' line is too short"); + expectNext(nullptr, 'A'); tmp = readInt(where, token, numberBase); curSection->org = tmp; // Truncation keeps the address portion only curSection->bank = tmp >> 16; - expectEol("'A' line is too long"); + expectEol('A'); // Init the rest of the members curSection->offset = 0; @@ -366,10 +376,10 @@ void sdobj_ReadFile(FileStackNode const &src, FILE *file, std::vector &f symbol.src = where.src; symbol.lineNo = where.lineNo; - getToken(line.data(), "'S' line is too short"); + expectNext(line.data(), 'S'); symbol.name = token; - getToken(nullptr, "'S' line is too short"); + expectNext(nullptr, 'S'); if (int32_t value = readInt(where, &token[3], numberBase); !fileSections.empty()) { // Symbols in sections are labels; their value is an offset @@ -438,7 +448,7 @@ void sdobj_ReadFile(FileStackNode const &src, FILE *file, std::vector &f fileSections.back().section->symbols.push_back(&symbol); } - expectEol("'S' line is too long"); + expectEol('S'); break; } @@ -467,13 +477,13 @@ void sdobj_ReadFile(FileStackNode const &src, FILE *file, std::vector &f } // First two bytes are ignored - getToken(line.data(), "'R' line is too short"); - getToken(nullptr, "'R' line is too short"); + expectNext(line.data(), 'R'); + expectNext(nullptr, 'R'); uint16_t areaIdx; - getToken(nullptr, "'R' line is too short"); + expectNext(nullptr, 'R'); areaIdx = readByte(where, token, numberBase); - getToken(nullptr, "'R' line is too short"); + expectNext(nullptr, 'R'); areaIdx |= static_cast(readByte(where, token, numberBase)) << 8; if (areaIdx >= fileSections.size()) { fatalAt( @@ -537,12 +547,12 @@ void sdobj_ReadFile(FileStackNode const &src, FILE *file, std::vector &f uint16_t flags = readByte(where, token, numberBase); if ((flags & 0xF0) == 0xF0) { - getToken(nullptr, "Incomplete relocation"); + expectRelocation(); flags = (flags & 0x0F) | static_cast(readByte(where, token, numberBase)) << 4; } - getToken(nullptr, "Incomplete relocation"); + expectRelocation(); uint8_t offset = readByte(where, token, numberBase); if (offset < addrSize) { @@ -562,10 +572,10 @@ void sdobj_ReadFile(FileStackNode const &src, FILE *file, std::vector &f ); } - getToken(nullptr, "Incomplete relocation"); + expectRelocation(); uint16_t idx = readByte(where, token, numberBase); - getToken(nullptr, "Incomplete relocation"); + expectRelocation(); idx |= static_cast(readByte(where, token, numberBase)); // Loudly fail on unknown flags @@ -819,8 +829,9 @@ void sdobj_ReadFile(FileStackNode const &src, FILE *file, std::vector &f } #undef expectEol +#undef expectNext +#undef expectRelocation #undef expectToken -#undef getToken if (!data.empty()) { warningAt(where, "Last 'T' line had no 'R' line (ignored)");