You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
3.3 KiB
144 lines
3.3 KiB
3 years ago
|
#include <ctype.h>
|
||
|
#include <stdint.h>
|
||
|
#include <stddef.h>
|
||
|
#include "fh_print.h"
|
||
|
#include "fh_runtime.h"
|
||
|
#include "fh_error.h"
|
||
|
#include "fh_parse.h"
|
||
|
|
||
|
void fh_input_consume_matching(struct fh_thread_s *fh, chartest_t test, void* param) {
|
||
|
char *rp = (char *) &fh->heap[INPUTBUF_ADDR + fh->inputptr];
|
||
|
while (test(*rp, param)) {
|
||
|
rp++;
|
||
|
fh->inputptr++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void fh_input_consume_spaces(struct fh_thread_s *fh) {
|
||
|
char *rp = (char *) &fh->heap[INPUTBUF_ADDR + fh->inputptr];
|
||
|
while (isspace(*rp)) {
|
||
|
rp++;
|
||
|
fh->inputptr++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
enum fh_error fh_input_read_delimited(struct fh_thread_s *fh, char **out, size_t *len, chartest_t test, void* param)
|
||
|
{
|
||
|
char *rp = (char *) &fh->heap[INPUTBUF_ADDR + fh->inputptr];
|
||
|
char *start = rp;
|
||
|
while (1) {
|
||
|
char c = *rp;
|
||
|
if (test(c, param)) {
|
||
|
if (rp == start) {
|
||
|
LOGE("Expected a word!");
|
||
|
return FH_ERR_SYNTAX;
|
||
|
}
|
||
|
*out = start;
|
||
|
*len = rp - start;
|
||
|
fh->inputptr++; // advance past the delimiter
|
||
|
return FH_OK;
|
||
|
}
|
||
|
rp++;
|
||
|
fh->inputptr++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static bool chartest_space_or_end(char c, void *param)
|
||
|
{
|
||
|
(void)param;
|
||
|
return isspace(c) || c == 0;
|
||
|
}
|
||
|
|
||
|
enum fh_error fh_input_read_word(struct fh_thread_s *fh, char **out, size_t *len) {
|
||
|
return fh_input_read_delimited(fh, out, len, chartest_space_or_end, NULL);
|
||
|
}
|
||
|
|
||
|
enum fh_error fh_input_read_quotedstring(struct fh_thread_s *fh, bool escaped, char *outbuf, size_t capacity, size_t *out_len) {
|
||
|
char *rp = (char *) &fh->heap[INPUTBUF_ADDR + fh->inputptr];
|
||
|
bool next_escaped = false;
|
||
|
size_t remains = capacity;
|
||
|
size_t len = 0;
|
||
|
int hexdigits = 0;
|
||
|
uint32_t hex = 0;
|
||
|
while (len < capacity) {
|
||
|
char c = *rp;
|
||
|
if (c == 0) {
|
||
|
LOGE("Unterminated quoted string!");
|
||
|
return FH_ERR_SYNTAX;
|
||
|
}
|
||
|
|
||
|
if (hexdigits) {
|
||
|
hex <<= 4;
|
||
|
if (isdigit(c)) {
|
||
|
hex |= c - '0';
|
||
|
} else if (c>='a' && c<='f') {
|
||
|
hex |= c - 'a';
|
||
|
} else if (c>='A' && c<='F') {
|
||
|
hex |= c - 'A';
|
||
|
} else {
|
||
|
LOGE("Bad hex escape");
|
||
|
return FH_ERR_SYNTAX;
|
||
|
}
|
||
|
hexdigits--;
|
||
|
if (hexdigits == 0) {
|
||
|
c = (char) hex;
|
||
|
goto append;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!escaped || !next_escaped) {
|
||
|
if (c == '\"') {
|
||
|
*outbuf = 0;
|
||
|
*out_len = len;
|
||
|
// advance past the quote
|
||
|
fh->inputptr++;
|
||
|
return FH_OK;
|
||
|
}
|
||
|
|
||
|
if (c == '\\') {
|
||
|
next_escaped = true;
|
||
|
goto skip;
|
||
|
}
|
||
|
} else {
|
||
|
next_escaped = false;
|
||
|
switch (c) {
|
||
|
case 'a': c = 7; break;
|
||
|
case 'b': c = 8; break;
|
||
|
case 'e': c = 27; break;
|
||
|
case 'f': c = 12; break;
|
||
|
case 'l': c = 10; break;
|
||
|
case 'm':
|
||
|
case 'n':
|
||
|
if (remains < 2) goto full;
|
||
|
*outbuf++ = '\r';
|
||
|
*outbuf++ = '\n';
|
||
|
remains -= 2;
|
||
|
len += 2;
|
||
|
goto skip;
|
||
|
case 'q': c = '"'; break;
|
||
|
case 'r': c = '\r'; break;
|
||
|
case 't': c = '\t'; break;
|
||
|
case 'v': c = '\v'; break;
|
||
|
case 'z': c = 0; break; // XXX this will cause problems!
|
||
|
case 'x':
|
||
|
hex = 0;
|
||
|
hexdigits = 2;
|
||
|
goto skip;
|
||
|
default:;
|
||
|
// just append normally
|
||
|
}
|
||
|
}
|
||
|
|
||
|
append:
|
||
|
*outbuf++ = c;
|
||
|
len++;
|
||
|
skip:
|
||
|
rp++;
|
||
|
fh->inputptr++;
|
||
|
}
|
||
|
|
||
|
full:
|
||
|
LOGE("String too long!");
|
||
|
return FH_ERR_SYNTAX;
|
||
|
}
|