added support for special characters in strings

This commit is contained in:
cozis
2022-04-24 19:21:38 +02:00
parent c34400eeca
commit f5b0cda5ad
+121 -13
View File
@@ -365,31 +365,139 @@ typedef struct {
xj_error *error;
} context_t;
typedef struct {
char *buffer;
int size, capacity;
char maybe[256];
} string_parsing_context_t;
_Bool spc_append(string_parsing_context_t *spc, const char *str, int len)
{
if(spc->size + len > spc->capacity)
{
// Grow the buffer.
int new_capacity = spc->capacity * 2;
if(new_capacity < (spc->size + len))
new_capacity = (spc->size + len);
char *temp;
if(spc->maybe == spc->buffer)
{
temp = malloc(new_capacity);
if(temp == NULL)
return 0;
memcpy(temp, spc->buffer, spc->size);
}
else
{
temp = realloc(spc->buffer, new_capacity);
if(temp == NULL)
return 0;
}
spc->buffer = temp;
spc->capacity = new_capacity;
}
memcpy(spc->buffer + spc->size, str, len);
spc->size += len;
return 1;
}
void spc_free(string_parsing_context_t *spc)
{
if(spc->maybe != spc->buffer)
free(spc->buffer);
}
static void *parse_string(context_t *ctx, _Bool raw)
{
assert(ctx->i < ctx->len && ctx->str[ctx->i] == '"');
ctx->i += 1; // Skip '"'.
int start = ctx->i;
while(ctx->i < ctx->len && ctx->str[ctx->i] != '"')
ctx->i += 1;
if(ctx->i == ctx->len)
string_parsing_context_t spc;
{
xj_report(ctx->error, "String ended inside a string");
return NULL;
spc.buffer = spc.maybe;
spc.size = 0;
spc.capacity = sizeof(spc.maybe);
}
int end = ctx->i;
ctx->i += 1; // Skip '"'.
while(1)
{
int start = ctx->i;
while(ctx->i < ctx->len && ctx->str[ctx->i] != '\\'
&& ctx->str[ctx->i] != '"')
ctx->i += 1;
if(ctx->i == ctx->len)
{
xj_report(ctx->error, "String ended inside a string");
spc_free(&spc);
return NULL;
}
int end = ctx->i;
if(!spc_append(&spc, ctx->str + start, end - start))
{
xj_report(ctx->error, "Out of memory");
spc_free(&spc);
return NULL;
}
if(ctx->str[ctx->i] == '"')
break;
assert(ctx->str[ctx->i] == '\\');
ctx->i += 1; // Skip '\'.
if(ctx->i == ctx->len)
{
xj_report(ctx->error, "String ended inside a string");
spc_free(&spc);
return NULL;
}
char c = ctx->str[ctx->i];
switch(c)
{
case 'n': c = '\n'; break;
case 't': c = '\t'; break;
case 'b': c = '\b'; break;
case 'f': c = '\f'; break;
case 'r': c = '\r'; break;
case 'u': xj_preport(ctx->error, ctx->str, ctx->i,
"The \\uXXXX form isn't supported yet!");
break;
}
if(!spc_append(&spc, &c, 1))
{
xj_report(ctx->error, "Out of memory");
spc_free(&spc);
return NULL;
}
ctx->i += 1; // Skip the character after the '\'.
}
ctx->i += 1; // Skip '"'.
void *p = raw ? (void*) xj_strdup(ctx->str + start, end - start, ctx->alloc, ctx->error)
: (void*) xj_value_string(ctx->str + start, end - start, ctx->alloc, ctx->error);
void *p = raw ? (void*) xj_strdup(spc.buffer, spc.size, ctx->alloc, ctx->error)
: (void*) xj_value_string(spc.buffer, spc.size, ctx->alloc, ctx->error);
if(p == NULL)
xj_report(ctx->error, "No memory");
spc_free(&spc);
return p;
}