#include #include #include #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; }