mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Use automatic allocation for STRFMT args
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
#define RGBDS_FORMAT_SPEC_H
|
#define RGBDS_FORMAT_SPEC_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
enum FormatState {
|
enum FormatState {
|
||||||
FORMAT_SIGN, // expects '+' or ' ' (optional)
|
FORMAT_SIGN, // expects '+' or ' ' (optional)
|
||||||
@@ -36,12 +37,9 @@ struct StrFmtArg {
|
|||||||
bool isNumeric;
|
bool isNumeric;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define INITIAL_STRFMT_ARG_SIZE 4
|
|
||||||
struct StrFmtArgList {
|
struct StrFmtArgList {
|
||||||
char *format;
|
char *format;
|
||||||
size_t nbArgs;
|
std::vector<struct StrFmtArg> *args;
|
||||||
size_t capacity;
|
|
||||||
struct StrFmtArg *args;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FormatSpec fmt_NewSpec(void);
|
struct FormatSpec fmt_NewSpec(void);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include <new>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -254,36 +255,22 @@ static void strrpl(char *dest, size_t destLen, char const *src, char const *old,
|
|||||||
|
|
||||||
static void initStrFmtArgList(struct StrFmtArgList *args)
|
static void initStrFmtArgList(struct StrFmtArgList *args)
|
||||||
{
|
{
|
||||||
args->nbArgs = 0;
|
args->args = new(std::nothrow) std::vector<struct StrFmtArg>();
|
||||||
args->capacity = INITIAL_STRFMT_ARG_SIZE;
|
|
||||||
args->args = (struct StrFmtArg *)malloc(args->capacity * sizeof(*args->args));
|
|
||||||
if (!args->args)
|
if (!args->args)
|
||||||
fatalerror("Failed to allocate memory for STRFMT arg list: %s\n",
|
fatalerror("Failed to allocate memory for STRFMT arg list: %s\n",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t nextStrFmtArgListIndex(struct StrFmtArgList *args)
|
|
||||||
{
|
|
||||||
if (args->nbArgs == args->capacity) {
|
|
||||||
args->capacity = (args->capacity + 1) * 2;
|
|
||||||
args->args = (struct StrFmtArg *)realloc(args->args, args->capacity * sizeof(*args->args));
|
|
||||||
if (!args->args)
|
|
||||||
fatalerror("realloc error while resizing STRFMT arg list: %s\n",
|
|
||||||
strerror(errno));
|
|
||||||
}
|
|
||||||
return args->nbArgs++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void freeStrFmtArgList(struct StrFmtArgList *args)
|
static void freeStrFmtArgList(struct StrFmtArgList *args)
|
||||||
{
|
{
|
||||||
free(args->format);
|
free(args->format);
|
||||||
for (size_t i = 0; i < args->nbArgs; i++)
|
for (struct StrFmtArg &arg : *args->args)
|
||||||
if (!args->args[i].isNumeric)
|
if (!arg.isNumeric)
|
||||||
free(args->args[i].string);
|
free(arg.string);
|
||||||
free(args->args);
|
delete args->args;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void strfmt(char *dest, size_t destLen, char const *fmt, size_t nbArgs, struct StrFmtArg *args)
|
static void strfmt(char *dest, size_t destLen, char const *fmt, std::vector<struct StrFmtArg> &args)
|
||||||
{
|
{
|
||||||
size_t a = 0;
|
size_t a = 0;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
@@ -323,28 +310,29 @@ static void strfmt(char *dest, size_t destLen, char const *fmt, size_t nbArgs, s
|
|||||||
dest[i++] = '%';
|
dest[i++] = '%';
|
||||||
a++;
|
a++;
|
||||||
continue;
|
continue;
|
||||||
} else if (a >= nbArgs) {
|
} else if (a >= args.size()) {
|
||||||
// Will warn after formatting is done.
|
// Will warn after formatting is done.
|
||||||
dest[i++] = '%';
|
dest[i++] = '%';
|
||||||
a++;
|
a++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StrFmtArg *arg = &args[a++];
|
struct StrFmtArg &arg = args[a++];
|
||||||
static char buf[MAXSTRLEN + 1];
|
static char buf[MAXSTRLEN + 1];
|
||||||
|
|
||||||
if (arg->isNumeric)
|
if (arg.isNumeric)
|
||||||
fmt_PrintNumber(buf, sizeof(buf), &spec, arg->number);
|
fmt_PrintNumber(buf, sizeof(buf), &spec, arg.number);
|
||||||
else
|
else
|
||||||
fmt_PrintString(buf, sizeof(buf), &spec, arg->string);
|
fmt_PrintString(buf, sizeof(buf), &spec, arg.string);
|
||||||
|
|
||||||
i += snprintf(&dest[i], destLen - i, "%s", buf);
|
i += snprintf(&dest[i], destLen - i, "%s", buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a < nbArgs)
|
if (a < args.size())
|
||||||
error("STRFMT: %zu unformatted argument(s)\n", nbArgs - a);
|
error("STRFMT: %zu unformatted argument(s)\n", args.size() - a);
|
||||||
else if (a > nbArgs)
|
else if (a > args.size())
|
||||||
error("STRFMT: Not enough arguments for format spec, got: %zu, need: %zu\n", nbArgs, a);
|
error("STRFMT: Not enough arguments for format spec, got: %zu, need: %zu\n",
|
||||||
|
args.size(), a);
|
||||||
|
|
||||||
if (i > destLen - 1) {
|
if (i > destLen - 1) {
|
||||||
warning(WARNING_LONG_STR, "STRFMT: String too long, got truncated\n");
|
warning(WARNING_LONG_STR, "STRFMT: String too long, got truncated\n");
|
||||||
@@ -1701,7 +1689,7 @@ string : T_STRING
|
|||||||
strrpl($$, sizeof($$), $3, $5, $7);
|
strrpl($$, sizeof($$), $3, $5, $7);
|
||||||
}
|
}
|
||||||
| T_OP_STRFMT T_LPAREN strfmt_args T_RPAREN {
|
| T_OP_STRFMT T_LPAREN strfmt_args T_RPAREN {
|
||||||
strfmt($$, sizeof($$), $3.format, $3.nbArgs, $3.args);
|
strfmt($$, sizeof($$), $3.format, *$3.args);
|
||||||
freeStrFmtArgList(&$3);
|
freeStrFmtArgList(&$3);
|
||||||
}
|
}
|
||||||
| T_POP_SECTION T_LPAREN scoped_anon_id T_RPAREN {
|
| T_POP_SECTION T_LPAREN scoped_anon_id T_RPAREN {
|
||||||
@@ -1733,8 +1721,6 @@ strcat_args : string
|
|||||||
|
|
||||||
strfmt_args : string strfmt_va_args {
|
strfmt_args : string strfmt_va_args {
|
||||||
$$.format = strdup($1);
|
$$.format = strdup($1);
|
||||||
$$.capacity = $2.capacity;
|
|
||||||
$$.nbArgs = $2.nbArgs;
|
|
||||||
$$.args = $2.args;
|
$$.args = $2.args;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@@ -1743,17 +1729,17 @@ strfmt_va_args : %empty {
|
|||||||
initStrFmtArgList(&$$);
|
initStrFmtArgList(&$$);
|
||||||
}
|
}
|
||||||
| strfmt_va_args T_COMMA const_no_str {
|
| strfmt_va_args T_COMMA const_no_str {
|
||||||
size_t i = nextStrFmtArgListIndex(&$1);
|
struct StrFmtArg &arg = $1.args->emplace_back();
|
||||||
|
|
||||||
$1.args[i].number = $3;
|
arg.number = $3;
|
||||||
$1.args[i].isNumeric = true;
|
arg.isNumeric = true;
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
}
|
}
|
||||||
| strfmt_va_args T_COMMA string {
|
| strfmt_va_args T_COMMA string {
|
||||||
size_t i = nextStrFmtArgListIndex(&$1);
|
struct StrFmtArg &arg = $1.args->emplace_back();
|
||||||
|
|
||||||
$1.args[i].string = strdup($3);
|
arg.string = strdup($3);
|
||||||
$1.args[i].isNumeric = false;
|
arg.isNumeric = false;
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|||||||
Reference in New Issue
Block a user