summaryrefslogtreecommitdiff
path: root/tools/spec.c
diff options
context:
space:
mode:
authorDragorn421 <Dragorn421@users.noreply.github.com>2026-08-03 16:42:52 +0200
committerGitHub <noreply@github.com>2026-08-03 16:42:52 +0200
commit22d4ca0be7c37ffe5aa5cd8582ca1fb4e2dc73a6 (patch)
treebf70ce1bbc8a48b6a7601ad096fd4ebf42d326a1 /tools/spec.c
parentda4a1f661cc87c8a31b65310f8940a5c5f0927d6 (diff)
spec: change `include` to ignore duped includes across spec (#2777)HEADmain
* spec: impl `include_once` and error on duped includes across spec * duped includes fixups * rm get_single_segment_by_name from spec.c (unused code) * replace include logic with include_once's
Diffstat (limited to 'tools/spec.c')
-rw-r--r--tools/spec.c93
1 files changed, 21 insertions, 72 deletions
diff --git a/tools/spec.c b/tools/spec.c
index 4c079834f..187549ead 100644
--- a/tools/spec.c
+++ b/tools/spec.c
@@ -157,7 +157,7 @@ STMTId get_stmt_id_by_stmt_name(const char *stmtName, int lineNum) {
return -1;
}
-bool parse_segment_statement(struct Segment *currSeg, STMTId stmt, char* args, int lineNum) {
+bool parse_segment_statement(struct Segment *currSeg, STMTId stmt, char* args, int lineNum, const struct Segment *segments, int segment_count) {
// ensure no duplicates (except for 'include' or 'pad_text')
if (stmt != STMT_include && stmt != STMT_pad_text &&
(currSeg->fields & (1 << stmt)))
@@ -211,15 +211,28 @@ bool parse_segment_statement(struct Segment *currSeg, STMTId stmt, char* args, i
if (!is_pow_of_2(currSeg->romalign))
util_fatal_error("line %i: alignment is not a power of two", lineNum);
break;
- case STMT_include:
- currSeg->includesCount++;
- currSeg->includes = realloc(currSeg->includes, currSeg->includesCount * sizeof(*currSeg->includes));
+ case STMT_include: {
+ char *inc;
- if (!parse_quoted_string(args, &currSeg->includes[currSeg->includesCount - 1].fpath))
+ if (!parse_quoted_string(args, &inc))
util_fatal_error("line %i: invalid filename", lineNum);
- currSeg->includes[currSeg->includesCount - 1].linkerPadding = 0;
- break;
+ bool inc_is_dup = false;
+ for (int i = 0; i < segment_count; i++) {
+ for (int j = 0; j < segments[i].includesCount; j++) {
+ if (strcmp(segments[i].includes[j].fpath, inc) == 0) {
+ inc_is_dup = true;
+ }
+ }
+ }
+
+ if (!inc_is_dup) {
+ currSeg->includesCount++;
+ currSeg->includes = realloc(currSeg->includes, currSeg->includesCount * sizeof(*currSeg->includes));
+ currSeg->includes[currSeg->includesCount - 1].fpath = inc;
+ currSeg->includes[currSeg->includesCount - 1].linkerPadding = 0;
+ }
+ } break;
case STMT_increment:
if (!parse_number(args, &currSeg->increment))
util_fatal_error("line %i: expected number after 'increment'", lineNum);
@@ -267,7 +280,7 @@ void parse_rom_spec(char *spec, struct Segment **segments, int *segment_count)
if (currSeg != NULL)
{
- bool segmentEnded = parse_segment_statement(currSeg, stmt, args, lineNum);
+ bool segmentEnded = parse_segment_statement(currSeg, stmt, args, lineNum, *segments, *segment_count);
if (segmentEnded) {
currSeg = NULL;
}
@@ -296,70 +309,6 @@ void parse_rom_spec(char *spec, struct Segment **segments, int *segment_count)
}
}
-/**
- * @brief Parses the spec, looking only for the segment with the name `segmentName`.
- * Returns true if the segment was found, false otherwise
- *
- * @param[out] dstSegment The Segment to be filled. Will only contain the data of the searched segment, or garbage if the segment was not found. dstSegment must be previously allocated, a stack variable is recommended
- * @param[in,out] spec A null-terminated string containing the whole spec file. This string will be modified by this function
- * @param[in] segmentName The name of the segment being searched
- */
-bool get_single_segment_by_name(struct Segment* dstSegment, char *spec, const char *segmentName) {
- bool insideSegment = false;
- int lineNum = 1;
- char *line = spec;
-
- memset(dstSegment, 0, sizeof(struct Segment));
-
- // iterate over lines
- while (line[0] != '\0') {
- char *nextLine = line_split(line);
- char* stmtName = skip_whitespace(line);
-
- if (stmtName[0] != '\0') {
- char *args = token_split(stmtName);
- STMTId stmt = get_stmt_id_by_stmt_name(stmtName, lineNum);
-
- if (insideSegment) {
- bool segmentEnded = parse_segment_statement(dstSegment, stmt, args, lineNum);
-
- if (stmt == STMT_name) {
- if (strcmp(segmentName, dstSegment->name) != 0) {
- // Not the segment we are looking for
- insideSegment = false;
- }
- } else if (segmentEnded) {
- return true;
- }
- } else {
- if (stmt == STMT_beginseg) {
- insideSegment = true;
- if (dstSegment->includes != NULL) {
- free(dstSegment->includes);
- }
- memset(dstSegment, 0, sizeof(struct Segment));
- }
- }
- }
-
- line = nextLine;
- lineNum++;
- }
-
- return false;
-}
-
-/**
- * @brief Frees the elements of the passed Segment. Will not free the pointer itself
- *
- * @param segment
- */
-void free_single_segment_elements(struct Segment *segment) {
- if (segment->includes != NULL) {
- free(segment->includes);
- }
-}
-
void free_rom_spec(struct Segment *segments, int segment_count)
{
int i;