mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-21 10:42:07 +00:00
Support Mac OS classic CR line endings in linkerscripts
This also refactors `readChar(file)` to `nextChar()` to be more like the rgbasm lexer.
This commit is contained in:
@@ -43,8 +43,7 @@ static void pushFile(char *newFileName)
|
|||||||
if (!fileStackSize) /* Init file stack */
|
if (!fileStackSize) /* Init file stack */
|
||||||
fileStackSize = 4;
|
fileStackSize = 4;
|
||||||
fileStackSize *= 2;
|
fileStackSize *= 2;
|
||||||
fileStack = realloc(fileStack,
|
fileStack = realloc(fileStack, sizeof(*fileStack) * fileStackSize);
|
||||||
sizeof(*fileStack) * fileStackSize);
|
|
||||||
if (!fileStack)
|
if (!fileStack)
|
||||||
err(1, "%s(%" PRIu32 "): Internal INCLUDE error",
|
err(1, "%s(%" PRIu32 "): Internal INCLUDE error",
|
||||||
linkerScriptName, lineNo);
|
linkerScriptName, lineNo);
|
||||||
@@ -173,11 +172,11 @@ static char const * const commands[] = {
|
|||||||
[COMMAND_ALIGN] = "ALIGN"
|
[COMMAND_ALIGN] = "ALIGN"
|
||||||
};
|
};
|
||||||
|
|
||||||
static int readChar(FILE *file)
|
static int nextChar(void)
|
||||||
{
|
{
|
||||||
int curchar = getc(file);
|
int curchar = getc(linkerScript);
|
||||||
|
|
||||||
if (curchar == EOF && ferror(file))
|
if (curchar == EOF && ferror(linkerScript))
|
||||||
err(1, "%s(%" PRIu32 "): Unexpected error in %s",
|
err(1, "%s(%" PRIu32 "): Unexpected error in %s",
|
||||||
linkerScriptName, lineNo, __func__);
|
linkerScriptName, lineNo, __func__);
|
||||||
return curchar;
|
return curchar;
|
||||||
@@ -194,14 +193,14 @@ static struct LinkerScriptToken *nextToken(void)
|
|||||||
|
|
||||||
/* Skip initial whitespace... */
|
/* Skip initial whitespace... */
|
||||||
do
|
do
|
||||||
curchar = readChar(linkerScript);
|
curchar = nextChar();
|
||||||
while (isWhiteSpace(curchar));
|
while (isWhiteSpace(curchar));
|
||||||
|
|
||||||
/* If this is a comment, skip to the end of the line */
|
/* If this is a comment, skip to the end of the line */
|
||||||
if (curchar == ';') {
|
if (curchar == ';') {
|
||||||
do
|
do {
|
||||||
curchar = readChar(linkerScript);
|
curchar = nextChar();
|
||||||
while (!isNewline(curchar) && curchar != EOF);
|
} while (!isNewline(curchar) && curchar != EOF);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curchar == EOF) {
|
if (curchar == EOF) {
|
||||||
@@ -210,9 +209,14 @@ static struct LinkerScriptToken *nextToken(void)
|
|||||||
/* If we have a newline char, this is a newline token */
|
/* If we have a newline char, this is a newline token */
|
||||||
token.type = TOKEN_NEWLINE;
|
token.type = TOKEN_NEWLINE;
|
||||||
|
|
||||||
/* FIXME: This works with CRLF newlines, but not CR-only */
|
if (curchar == '\r') {
|
||||||
if (curchar == '\r')
|
/* Handle CRLF */
|
||||||
readChar(linkerScript); /* Read and discard LF */
|
curchar = nextChar();
|
||||||
|
if (curchar != '\n') {
|
||||||
|
ungetc(curchar, linkerScript);
|
||||||
|
curchar = '\r';
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (curchar == '"') {
|
} else if (curchar == '"') {
|
||||||
/* If we have a string start, this is a string */
|
/* If we have a string start, this is a string */
|
||||||
token.type = TOKEN_STRING;
|
token.type = TOKEN_STRING;
|
||||||
@@ -222,7 +226,7 @@ static struct LinkerScriptToken *nextToken(void)
|
|||||||
size_t capacity = 16; /* Half of the default capacity */
|
size_t capacity = 16; /* Half of the default capacity */
|
||||||
|
|
||||||
do {
|
do {
|
||||||
curchar = readChar(linkerScript);
|
curchar = nextChar();
|
||||||
if (curchar == EOF || isNewline(curchar)) {
|
if (curchar == EOF || isNewline(curchar)) {
|
||||||
errx(1, "%s(%" PRIu32 "): Unterminated string",
|
errx(1, "%s(%" PRIu32 "): Unterminated string",
|
||||||
linkerScriptName, lineNo);
|
linkerScriptName, lineNo);
|
||||||
@@ -231,7 +235,7 @@ static struct LinkerScriptToken *nextToken(void)
|
|||||||
curchar = '\0';
|
curchar = '\0';
|
||||||
} else if (curchar == '\\') {
|
} else if (curchar == '\\') {
|
||||||
/* Backslashes are escape sequences */
|
/* Backslashes are escape sequences */
|
||||||
curchar = readChar(linkerScript);
|
curchar = nextChar();
|
||||||
if (curchar == EOF || isNewline(curchar))
|
if (curchar == EOF || isNewline(curchar))
|
||||||
errx(1, "%s(%" PRIu32 "): Unterminated string",
|
errx(1, "%s(%" PRIu32 "): Unterminated string",
|
||||||
linkerScriptName, lineNo);
|
linkerScriptName, lineNo);
|
||||||
@@ -248,8 +252,7 @@ static struct LinkerScriptToken *nextToken(void)
|
|||||||
|
|
||||||
if (size >= capacity || token.attr.string == NULL) {
|
if (size >= capacity || token.attr.string == NULL) {
|
||||||
capacity *= 2;
|
capacity *= 2;
|
||||||
token.attr.string = realloc(token.attr.string,
|
token.attr.string = realloc(token.attr.string, capacity);
|
||||||
capacity);
|
|
||||||
if (!token.attr.string)
|
if (!token.attr.string)
|
||||||
err(1, "%s: Failed to allocate memory for string",
|
err(1, "%s: Failed to allocate memory for string",
|
||||||
__func__);
|
__func__);
|
||||||
@@ -276,10 +279,9 @@ static struct LinkerScriptToken *nextToken(void)
|
|||||||
if (!curchar)
|
if (!curchar)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
curchar = readChar(linkerScript);
|
curchar = nextChar();
|
||||||
/* Whitespace, a newline or a comment end the token */
|
/* Whitespace, a newline or a comment end the token */
|
||||||
if (isWhiteSpace(curchar) || isNewline(curchar)
|
if (isWhiteSpace(curchar) || isNewline(curchar) || curchar == ';') {
|
||||||
|| curchar == ';') {
|
|
||||||
ungetc(curchar, linkerScript);
|
ungetc(curchar, linkerScript);
|
||||||
curchar = '\0';
|
curchar = '\0';
|
||||||
}
|
}
|
||||||
@@ -298,8 +300,7 @@ static struct LinkerScriptToken *nextToken(void)
|
|||||||
|
|
||||||
if (token.type == TOKEN_INVALID) {
|
if (token.type == TOKEN_INVALID) {
|
||||||
/* Try to match a bank specifier */
|
/* Try to match a bank specifier */
|
||||||
for (enum SectionType type = 0; type < SECTTYPE_INVALID;
|
for (enum SectionType type = 0; type < SECTTYPE_INVALID; type++) {
|
||||||
type++) {
|
|
||||||
if (!strcmp(typeNames[type], str)) {
|
if (!strcmp(typeNames[type], str)) {
|
||||||
token.type = TOKEN_BANK;
|
token.type = TOKEN_BANK;
|
||||||
token.attr.secttype = type;
|
token.attr.secttype = type;
|
||||||
@@ -329,8 +330,7 @@ static struct LinkerScriptToken *nextToken(void)
|
|||||||
return &token;
|
return &token;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void processCommand(enum LinkerScriptCommand command, uint16_t arg,
|
static void processCommand(enum LinkerScriptCommand command, uint16_t arg, uint16_t *pc)
|
||||||
uint16_t *pc)
|
|
||||||
{
|
{
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case COMMAND_INVALID:
|
case COMMAND_INVALID:
|
||||||
@@ -475,8 +475,7 @@ struct SectionPlacement *script_NextSection(void)
|
|||||||
errx(1, "%s(%" PRIu32 "): Command specified without an argument",
|
errx(1, "%s(%" PRIu32 "): Command specified without an argument",
|
||||||
linkerScriptName, lineNo);
|
linkerScriptName, lineNo);
|
||||||
|
|
||||||
processCommand(attr.command, arg,
|
processCommand(attr.command, arg, &curaddr[type][bankID]);
|
||||||
&curaddr[type][bankID]);
|
|
||||||
} else { /* TOKEN_BANK */
|
} else { /* TOKEN_BANK */
|
||||||
type = attr.secttype;
|
type = attr.secttype;
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -1,3 +1 @@
|
|||||||
ROM0
|
; This uses CR line endings
|
||||||
"A\"B\tC\rD\nE"
|
|
||||||
"in\{valid"
|
|
||||||
@@ -1 +1 @@
|
|||||||
error: ./linkerscript-escapes-test.link(3): Illegal character escape
|
error: ./linkerscript-escapes-test.link(4): Illegal character escape
|
||||||
|
|||||||
Reference in New Issue
Block a user