ref: 6ffa751090c7c8db55fbf3cb0f7a28e90f558a56
parent: c3641321d7a71e3c4759b3e22209454a363c85bb
parent: 995265c5498cbabe86dd95026ffea03df42e02d7
author: Eldred Habert <eldredhabert0@gmail.com>
date: Thu Aug 29 16:12:32 EDT 2019
Merge pull request #390 from ISSOtm/print_types Add "print types" to bracketed symbols
--- a/include/asm/asm.h
+++ b/include/asm/asm.h
@@ -39,6 +39,7 @@
extern struct sSymbol *pPCSymbol;
extern bool oDontExpandStrings;
-size_t symvaluetostring(char *dest, size_t maxLength, char *sym);
+size_t symvaluetostring(char *dest, size_t maxLength, char *sym,
+ const char *mode);
#endif /* RGBDS_ASM_ASM_H */
--- a/src/asm/asmy.y
+++ b/src/asm/asmy.y
@@ -1,7 +1,7 @@
/*
* This file is part of RGBDS.
*
- * Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
+ * Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
@@ -75,7 +75,8 @@
out_NewAbsSection(name, secttype, org, bank);
}
-size_t symvaluetostring(char *dest, size_t maxLength, char *sym)
+size_t symvaluetostring(char *dest, size_t maxLength, char *sym,
+ const char *mode)
{
size_t length;
@@ -83,6 +84,9 @@
char *src = sym_GetStringValue(sym);
size_t i;
+ if (mode)
+ yyerror("Print types are only allowed for numbers");
+
for (i = 0; src[i] != 0; i++) {
if (i >= maxLength)
fatalerror("Symbol value too long to fit buffer");
@@ -94,8 +98,25 @@
} else {
uint32_t value = sym_GetConstantValue(sym);
- int32_t fullLength = snprintf(dest, maxLength + 1, "$%X",
- value);
+ int32_t fullLength;
+
+ /* Special cheat for binary */
+ if (mode && !mode[0]) {
+ char binary[33]; /* 32 bits + 1 terminator */
+ char *write_ptr = binary + 32;
+ fullLength = 0;
+ binary[32] = 0;
+ do {
+ *(--write_ptr) = (value & 1) + '0';
+ value >>= 1;
+ fullLength++;
+ } while(value);
+ strncpy(dest, write_ptr, maxLength + 1);
+ } else {
+ fullLength = snprintf(dest, maxLength + 1,
+ mode ? : "$%X",
+ value);
+ }
if (fullLength < 0) {
fatalerror("snprintf encoding error");
--- a/src/asm/lexer.c
+++ b/src/asm/lexer.c
@@ -1,7 +1,7 @@
/*
* This file is part of RGBDS.
*
- * Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
+ * Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
@@ -599,6 +599,7 @@
char ch;
size_t i = 0;
size_t length, maxLength;
+ const char *mode = NULL;
for (ch = *pLexBuffer;
ch != '}' && ch != '"' && ch != '\n';
@@ -612,16 +613,42 @@
i += length;
else
fatalerror("Illegal character escape '%c'", ch);
+ } else if (ch == ':' && !mode) { /* Only grab 1st colon */
+ /* Use a whitelist of modes, which does prevent the
+ * use of some features such as precision,
+ * but also avoids a security flaw
+ */
+ const char *acceptedModes = "bxXd";
+ /* Binary isn't natively supported,
+ * so it's handled differently
+ */
+ static const char * const formatSpecifiers[] = {
+ "", "%x", "%X", "%d"
+ };
+ /* Prevent reading out of bounds! */
+ const char *designatedMode;
+
+ if (i != 1)
+ fatalerror("Print types are exactly 1 character long");
+
+ designatedMode = strchr(acceptedModes, sym[i - 1]);
+ if (!designatedMode)
+ fatalerror("Illegal print type '%c'",
+ sym[i - 1]);
+ mode = formatSpecifiers[designatedMode - acceptedModes];
+ /* Begin writing the symbol again */
+ i = 0;
} else {
yylex_SymbolWriteChar(sym, i++, ch);
}
}
+ /* Properly terminate the string */
yylex_SymbolWriteChar(sym, i, 0);
/* It's assumed we're writing to a T_STRING */
maxLength = MAXSTRLEN - index;
- length = symvaluetostring(&dest[index], maxLength, sym);
+ length = symvaluetostring(&dest[index], maxLength, sym, mode);
if (*pLexBuffer == '}')
pLexBuffer++;
--- a/src/asm/rgbasm.5
+++ b/src/asm/rgbasm.5
@@ -1079,7 +1079,20 @@
This will examine the type of the symbol and insert its value accordingly.
If symbol is a string symbol, the symbols value is simply copied.
If it's a numeric symbol, the value is converted to hexadecimal notation and
-inserted as a string.
+inserted as a string with a dollar prepended.
+.Pp
+It's possible to change the way numeric symbols are converted by specifying
+a print type like so:
+.Sy {d:symbol}
+Valid print types are:
+.Bl -column -offset indent
+.It Sy Print type Ta Sy Format Ta Sy Example
+.It Li d Ta Decimal Ta 42
+.It Li x Ta Lowercase hexadecimal Ta 2a
+.It Li X Ta Uppercase hexadecimal Ta 2A
+.It Li b Ta Binary Ta 101010
+.Pp
+Note that print types should only be used with numeric values, not strings.
.Pp
HINT: The
.Sy {symbol}
--- /dev/null
+++ b/test/asm/bracketed-symbols.asm
@@ -1,0 +1,20 @@
+X = 42
+PRINTT "{X}\n"
+PRINTT "{x:X}\n"
+PRINTT "{X:X}\n"
+PRINTT "{d:X}\n"
+PRINTT "{b:X}\n"
+
+Y equ 1337
+PRINTT "{b:Y}\n"
+
+rsreset
+R rb 0
+PRINTT "{d:R}\n"
+
+S equs "You can't format me!"
+PRINTT "{X:S}\n"
+
+SECTION "Test", ROM0
+Label:
+PRINTT "{x:Label}\n"
--- /dev/null
+++ b/test/asm/bracketed-symbols.out
@@ -1,0 +1,12 @@
+ERROR: bracketed-symbols.asm(16):
+ Print types are only allowed for numbers
+ERROR: bracketed-symbols.asm(20):
+ Expression must have a constant value
+$2A
+2a
+2A
+42
+101010
+10100111001
+0
+You can't format me!
--- /dev/null
+++ b/test/asm/bracketed-symbols.out.pipe
@@ -1,0 +1,12 @@
+ERROR: -(16):
+ Print types are only allowed for numbers
+ERROR: -(20):
+ Expression must have a constant value
+$2A
+2a
+2A
+42
+101010
+10100111001
+0
+You can't format me!