Skip to content

Commit

Permalink
[WIP] Allow longer strings, not '\0'-terminated
Browse files Browse the repository at this point in the history
Fixes gbdev#650
Fixes gbdev#505
  • Loading branch information
Rangi42 committed Jun 27, 2021
1 parent a67f5d6 commit 49e611b
Show file tree
Hide file tree
Showing 17 changed files with 593 additions and 344 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ rgbasm_obj := \
src/asm/parser.o \
src/asm/rpn.o \
src/asm/section.o \
src/asm/string.o \
src/asm/symbol.o \
src/asm/util.o \
src/asm/warning.o \
Expand Down
8 changes: 5 additions & 3 deletions include/asm/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@ struct FormatSpec {
bool valid;
};

struct String;

struct StrFmtArg {
union {
uint32_t number;
char *string;
struct String *string;
};
bool isNumeric;
};
Expand All @@ -57,7 +59,7 @@ bool fmt_IsValid(struct FormatSpec const *fmt);
bool fmt_IsFinished(struct FormatSpec const *fmt);
void fmt_UseCharacter(struct FormatSpec *fmt, int c);
void fmt_FinishCharacters(struct FormatSpec *fmt);
void fmt_PrintString(char *buf, size_t bufLen, struct FormatSpec const *fmt, char const *value);
void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uint32_t value);
struct String *fmt_PrintString(struct FormatSpec const *fmt, struct String const *value);
struct String *fmt_PrintNumber(struct FormatSpec const *fmt, uint32_t value);

#endif /* RGBDS_FORMAT_SPEC_H */
7 changes: 4 additions & 3 deletions include/asm/fstack.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ struct FileStackNamedNode { /* NODE_FILE, NODE_MACRO */
extern size_t maxRecursionDepth;

struct MacroArgs;
struct String;

void fstk_Dump(struct FileStackNode const *node, uint32_t lineNo);
void fstk_DumpCurrent(void);
Expand All @@ -71,10 +72,10 @@ bool fstk_FindFile(char const *path, char **fullPath, size_t *size);

bool yywrap(void);
void fstk_RunInclude(char const *path);
void fstk_RunMacro(char const *macroName, struct MacroArgs *args);
void fstk_RunMacro(struct String const *macroName, struct MacroArgs *args);
void fstk_RunRept(uint32_t count, int32_t reptLineNo, char *body, size_t size);
void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step,
int32_t reptLineNo, char *body, size_t size);
void fstk_RunFor(struct String *symName, int32_t start, int32_t stop, int32_t step,
int32_t reptLineNo, char *body, size_t size);
void fstk_StopRept(void);
bool fstk_Break(void);

Expand Down
2 changes: 0 additions & 2 deletions include/asm/lexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@

#include <stdbool.h>

#define MAXSTRLEN 255

struct LexerState;
extern struct LexerState *lexerState;
extern struct LexerState *lexerStateEOL;
Expand Down
3 changes: 2 additions & 1 deletion include/asm/section.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@
extern uint8_t fillByte;

struct Expression;
struct String;

struct Section {
char *name;
struct String *name;
enum SectionType type;
enum SectionModifier modifier;
struct FileStackNode *src; /* Where the section was defined */
Expand Down
54 changes: 54 additions & 0 deletions include/asm/string.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 2021, Eldred Habert and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/

#ifndef RGBDS_STRING_H
#define RGBDS_STRING_H

#include <assert.h>
#include <stdbool.h>
#include <stdint.h>

#include "helpers.h"

struct String;

#define PRI_STR ".*s"
// WARNING: **DO NOT** pass any side-effecting parameters to the macros below!
#define STR_FMT(str) (int)str_Len(str), str_Chars(str)

#define MUTATE_STR(str, ...) do { \
struct String *___orig_str = str; \
(void)___orig_str; /* Suppress `-Wunused-variable` */ \
str = __VA_ARGS__; \
assert(___orig_str == str); /* This shouldn't have been reallocated */ \
} while (0)

static inline bool str_IsWhitespace(int c)
{
return c == ' ' || c == '\t';
}

size_t str_Len(struct String const *str) attr_(pure);
void str_Trunc(struct String *str, size_t len);
char str_Index(struct String const *str, size_t i) attr_(pure);
bool str_Find(struct String const *str, char c) attr_(pure);
char const *str_Chars(struct String const *str) attr_(pure);

/**
* @param capacity The capacity to use, or 0 if unknown
*/
struct String *str_New(size_t capacity) attr_(malloc);
void str_Ref(struct String *str);
void str_Unref(struct String *str);

struct String *str_Push(struct String *str, char c) attr_(warn_unused_result);
struct String *str_Append(struct String *lhs, struct String const *rhs) attr_(warn_unused_result);
struct String *str_AppendSlice(struct String *lhs, char const *rhs, size_t len)
attr_(warn_unused_result);

#endif
51 changes: 26 additions & 25 deletions include/asm/symbol.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@
#include <time.h>

#include "asm/section.h"
#include "asm/string.h"

#include "platform.h" // MIN_NB_ELMS
#include "types.h"

#define HASHSIZE (1 << 16)
#define MAXSYMLEN 256

enum SymbolType {
SYM_LABEL,
Expand All @@ -32,7 +32,7 @@ enum SymbolType {
};

struct Symbol {
char name[MAXSYMLEN + 1];
struct String *name;
enum SymbolType type;
bool isExported; /* Whether the symbol is to be exported */
bool isBuiltin; /* Whether the symbol is a built-in */
Expand All @@ -45,13 +45,14 @@ struct Symbol {
/* If sym_IsNumeric */
int32_t value;
int32_t (*numCallback)(void);
/* For SYM_MACRO and SYM_EQUS; TODO: have separate fields */
/* For SYM_MACRO */
struct {
size_t macroSize;
char *macro;
};
/* For SYM_EQUS */
char const *(*strCallback)(void);
struct String *str;
struct String *(*strCallback)(void);
};

uint32_t ID; /* ID of the symbol in the object file (-1 if none) */
Expand Down Expand Up @@ -92,7 +93,7 @@ static inline bool sym_IsLabel(struct Symbol const *sym)

static inline bool sym_IsLocal(struct Symbol const *sym)
{
return sym_IsLabel(sym) && strchr(sym->name, '.');
return sym_IsLabel(sym) && str_Find(sym->name, '.');
}

static inline bool sym_IsExported(struct Symbol const *sym)
Expand All @@ -103,50 +104,50 @@ static inline bool sym_IsExported(struct Symbol const *sym)
/*
* Get a string equate's value
*/
static inline char const *sym_GetStringValue(struct Symbol const *sym)
static inline struct String *sym_GetStringValue(struct Symbol const *sym)
{
if (sym->hasCallback)
return sym->strCallback();
return sym->macro;
return sym->str;
}

void sym_ForEach(void (*func)(struct Symbol *, void *), void *arg);

int32_t sym_GetValue(struct Symbol const *sym);
void sym_SetExportAll(bool set);
struct Symbol *sym_AddLocalLabel(char const *symName);
struct Symbol *sym_AddLabel(char const *symName);
struct Symbol *sym_AddLocalLabel(struct String *symName);
struct Symbol *sym_AddLabel(struct String *symName);
struct Symbol *sym_AddAnonLabel(void);
void sym_WriteAnonLabelName(char buf[MIN_NB_ELMS(MAXSYMLEN + 1)], uint32_t ofs, bool neg);
void sym_Export(char const *symName);
struct Symbol *sym_AddEqu(char const *symName, int32_t value);
struct Symbol *sym_RedefEqu(char const *symName, int32_t value);
struct Symbol *sym_AddSet(char const *symName, int32_t value);
struct String *sym_WriteAnonLabelName(uint32_t ofs, bool neg);
void sym_Export(struct String const *symName);
struct Symbol *sym_AddEqu(struct String const *symName, int32_t value);
struct Symbol *sym_RedefEqu(struct String *symName, int32_t value);
struct Symbol *sym_AddSet(struct String const *symName, int32_t value);
uint32_t sym_GetPCValue(void);
uint32_t sym_GetConstantSymValue(struct Symbol const *sym);
uint32_t sym_GetConstantValue(char const *symName);
uint32_t sym_GetConstantValue(struct String const *symName);
/*
* Find a symbol by exact name, bypassing expansion checks
*/
struct Symbol *sym_FindExactSymbol(char const *symName);
struct Symbol *sym_FindExactSymbol(struct String const *symName);
/*
* Find a symbol by exact name; may not be scoped, produces an error if it is
*/
struct Symbol *sym_FindUnscopedSymbol(char const *symName);
struct Symbol *sym_FindUnscopedSymbol(struct String const *symName);
/*
* Find a symbol, possibly scoped, by name
*/
struct Symbol *sym_FindScopedSymbol(char const *symName);
struct Symbol *sym_FindScopedSymbol(struct String const *symName);
struct Symbol const *sym_GetPC(void);
struct Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char *body, size_t size);
struct Symbol *sym_Ref(char const *symName);
struct Symbol *sym_AddString(char const *symName, char const *value);
struct Symbol *sym_RedefString(char const *symName, char const *value);
void sym_Purge(char const *symName);
struct Symbol *sym_AddMacro(struct String *symName, int32_t defLineNo, char *body, size_t size);
struct Symbol *sym_Ref(struct String *symName);
struct Symbol *sym_AddString(struct String *symName, struct String *value);
struct Symbol *sym_RedefString(struct String *symName, struct String *value);
void sym_Purge(struct String const *symName);
void sym_Init(time_t now);

/* Functions to save and restore the current symbol scope. */
char const *sym_GetCurrentSymbolScope(void);
void sym_SetCurrentSymbolScope(char const *newScope);
struct String const *sym_GetCurrentSymbolScope(void);
void sym_SetCurrentSymbolScope(struct String const *newScope);

#endif /* RGBDS_SYMBOL_H */
1 change: 0 additions & 1 deletion include/asm/warning.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ enum WarningID {
WARNING_EMPTY_MACRO_ARG, /* Empty macro argument */
WARNING_EMPTY_STRRPL, /* Empty second argument in `STRRPL` */
WARNING_LARGE_CONSTANT, /* Constants too large */
WARNING_LONG_STR, /* String too long for internal buffers */
WARNING_MACRO_SHIFT, /* Shift past available arguments in macro */
WARNING_NESTED_COMMENT, /* Comment-start delimiter in a block comment */
WARNING_OBSOLETE, /* Obsolete things */
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ set(rgbasm_src
"asm/output.c"
"asm/rpn.c"
"asm/section.c"
"asm/string.c"
"asm/symbol.c"
"asm/util.c"
"asm/warning.c"
Expand Down
74 changes: 31 additions & 43 deletions src/asm/format.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <string.h>

#include "asm/format.h"
#include "asm/string.h"
#include "asm/warning.h"

struct FormatSpec fmt_NewSpec(void)
Expand Down Expand Up @@ -133,7 +134,7 @@ void fmt_FinishCharacters(struct FormatSpec *fmt)
fmt->state = FORMAT_INVALID;
}

void fmt_PrintString(char *buf, size_t bufLen, struct FormatSpec const *fmt, char const *value)
struct String *fmt_PrintString(struct FormatSpec const *fmt, struct String const *value)
{
if (fmt->sign)
error("Formatting string with sign flag '%c'\n", fmt->sign);
Expand All @@ -146,33 +147,28 @@ void fmt_PrintString(char *buf, size_t bufLen, struct FormatSpec const *fmt, cha
if (fmt->type != 's')
error("Formatting string as type '%c'\n", fmt->type);

size_t len = strlen(value);
size_t len = str_Len(value);
size_t totalLen = fmt->width > len ? fmt->width : len;

if (totalLen > bufLen - 1) { /* bufLen includes terminator */
error("Formatted string value too long\n");
totalLen = bufLen - 1;
if (len > totalLen)
len = totalLen;
}
assert(len < bufLen && totalLen < bufLen && len <= totalLen);

size_t padLen = totalLen - len;
struct String *str = str_New(totalLen);

if (!str)
return NULL;

if (fmt->alignLeft) {
memcpy(buf, value, len);
for (size_t i = len; i < totalLen; i++)
buf[i] = ' ';
MUTATE_STR(str, str_Append(str, value));
for (size_t i = 0; i < padLen; i++)
MUTATE_STR(str, str_Push(str, ' '));
} else {
for (size_t i = 0; i < padLen; i++)
buf[i] = ' ';
memcpy(buf + padLen, value, len);
MUTATE_STR(str, str_Push(str, ' '));
MUTATE_STR(str, str_Append(str, value));
}

buf[totalLen] = '\0';
return str;
}

void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uint32_t value)
struct String *fmt_PrintNumber(struct FormatSpec const *fmt, uint32_t value)
{
if (fmt->type != 'X' && fmt->type != 'x' && fmt->type != 'b' && fmt->type != 'o'
&& fmt->prefix)
Expand Down Expand Up @@ -257,48 +253,40 @@ void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uin
size_t len = strlen(valueBuf);
size_t numLen = !!sign + !!prefix + len;
size_t totalLen = fmt->width > numLen ? fmt->width : numLen;

if (totalLen > bufLen - 1) { /* bufLen includes terminator */
error("Formatted numeric value too long\n");
totalLen = bufLen - 1;
if (numLen > totalLen) {
len -= numLen - totalLen;
numLen = totalLen;
}
}
assert(numLen < bufLen && totalLen < bufLen && numLen <= totalLen && len <= numLen);

size_t padLen = totalLen - numLen;
size_t pos = 0;
struct String *str = str_New(totalLen);

if (!str)
return NULL;

if (fmt->alignLeft) {
if (sign)
buf[pos++] = sign;
MUTATE_STR(str, str_Push(str, sign));
if (prefix)
buf[pos++] = prefix;
memcpy(buf + pos, valueBuf, len);
for (size_t i = pos + len; i < totalLen; i++)
buf[i] = ' ';
MUTATE_STR(str, str_Push(str, prefix));
MUTATE_STR(str, str_AppendSlice(str, valueBuf, len));
for (size_t i = 0; i < padLen; i++)
MUTATE_STR(str, str_Push(str, ' '));
} else {
if (fmt->padZero) {
/* sign, then prefix, then zero padding */
if (sign)
buf[pos++] = sign;
MUTATE_STR(str, str_Push(str, sign));
if (prefix)
buf[pos++] = prefix;
MUTATE_STR(str, str_Push(str, prefix));
for (size_t i = 0; i < padLen; i++)
buf[pos++] = '0';
MUTATE_STR(str, str_Push(str, '0'));
} else {
/* space padding, then sign, then prefix */
for (size_t i = 0; i < padLen; i++)
buf[pos++] = ' ';
MUTATE_STR(str, str_Push(str, ' '));
if (sign)
buf[pos++] = sign;
MUTATE_STR(str, str_Push(str, sign));
if (prefix)
buf[pos++] = prefix;
MUTATE_STR(str, str_Push(str, prefix));
}
memcpy(buf + pos, valueBuf, len);
MUTATE_STR(str, str_AppendSlice(str, valueBuf, len));
}

buf[totalLen] = '\0';
return str;
}
Loading

0 comments on commit 49e611b

Please sign in to comment.