Files
perfect_dark/port/src/utils.c
T
fgsfds d98575d77b port: add basic mod directory support with config files for custom stages
select mod directory with --moddir whatever

these should contain a modconfig.txt that can specify replacements for some stage table fields, etc
2023-09-26 23:05:07 +02:00

198 lines
2.9 KiB
C

#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#include <PR/ultratypes.h>
#include "platform.h"
#include "system.h"
#include "utils.h"
static inline bool isSingleCharToken(const s32 ch)
{
switch (ch) {
case '{':
case '}':
case '[':
case ']':
case '(':
case ')':
case ',':
case '\'':
case '=':
return true;
default:
return false;
}
}
char *strFmt(const char *fmt, ...)
{
static char buf[4096];
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
return buf;
}
char *strRightTrim(char *str)
{
if (!str) {
return NULL;
}
const s32 len = strlen(str);
for (s32 i = len - 1; i >= 0 && isspace(str[i]); --i) {
str[i] = '\0';
}
return str;
}
char *strTrim(char *str)
{
if (!str) {
return NULL;
}
// left trim
while (*str && (u8)*str < ' ') {
++str;
}
// right trim
const s32 len = strlen(str);
for (s32 i = len - 1; i > 0 && isspace(str[i]); --i) {
str[i] = '\0';
}
return str;
}
char *strUnquote(char *str)
{
if (!str) {
return NULL;
}
if (*str == '"') {
++str;
}
char *end = strrchr(str, '"');
if (end && end[1] == '\0') {
*end = '\0';
}
return str;
}
char *strParseToken(char *str, char *out, s32 *outCount)
{
if (outCount) {
*outCount = 0;
}
if (!out) {
return NULL;
}
out[0] = '\0';
if (!str) {
return NULL;
}
s32 cnt = 0;
while (*str) {
// skip whitespace and other garbage
while (*str && (u8)*str <= ' ') {
++str;
}
if (!*str) {
// just whitespace
return NULL;
}
// skip #, ; and // comments
if (*str == ';' || *str == '#' || (str[0] == '/' && str[1] == '/')) {
while (*str && *str != '\n') {
++str;
}
continue;
}
if (*str == '"') {
// quoted string; treat it as an entire token, including the quotes
out[cnt++] = *str++;
while (true) {
if (*str == '\0') {
// unterminated quoted string
break;
}
if (str[0] == '\\' && str[1] == '"') {
// escaped quote; add to token
if (cnt + 1 < UTIL_MAX_TOKEN) {
out[cnt++] = str[1];
}
str += 2;
continue;
}
// add char to token
const s32 ch = (u8)*str++;
if (cnt + 1 < UTIL_MAX_TOKEN) {
out[cnt++] = ch;
}
if (ch == '"') {
// ch was the closing quote
break;
}
}
break;
}
if (isSingleCharToken(*str)) {
// single char token
out[cnt++] = *str++;
break;
}
// regular single word
do {
if (cnt + 1 < UTIL_MAX_TOKEN) {
out[cnt++] = *str++;
}
if (isSingleCharToken(*str)) {
break;
}
} while ((u8)*str > ' ');
break;
}
out[cnt] = '\0';
if (outCount) {
*outCount = cnt;
}
return str;
}
char *strDuplicate(const char *str)
{
if (!str) {
return NULL;
}
const u32 len = strlen(str);
char *out = sysMemAlloc(len + 1);
if (out) {
memcpy(out, str, len + 1);
}
return out;
}