2010-08-08 10:06:34 +02:00
|
|
|
#include <platform.h>
|
|
|
|
#include "parser.h"
|
|
|
|
#include "unicode.h"
|
2014-12-18 07:09:22 +01:00
|
|
|
#include "base36.h"
|
2010-08-08 10:06:34 +02:00
|
|
|
#include "log.h"
|
|
|
|
|
|
|
|
#include <assert.h>
|
2014-03-15 19:29:11 +01:00
|
|
|
#include <stdlib.h>
|
2010-08-08 10:06:34 +02:00
|
|
|
#include <wctype.h>
|
|
|
|
#include <memory.h>
|
|
|
|
|
|
|
|
#define SPACE_REPLACEMENT '~'
|
|
|
|
#define ESCAPE_CHAR '\\'
|
|
|
|
#define MAXTOKENSIZE 8192
|
|
|
|
|
|
|
|
typedef struct parser_state {
|
|
|
|
const char *current_token;
|
2011-03-07 08:02:35 +01:00
|
|
|
struct parser_state *next;
|
2010-08-08 10:06:34 +02:00
|
|
|
} parser_state;
|
|
|
|
|
2014-04-12 04:20:20 +02:00
|
|
|
static parser_state *states;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
static int eatwhitespace_c(const char **str_p)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
ucs4_t ucs;
|
|
|
|
size_t len;
|
2011-03-07 08:02:35 +01:00
|
|
|
const char *str = *str_p;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
/* skip over potential whitespace */
|
|
|
|
for (;;) {
|
|
|
|
unsigned char utf8_character = (unsigned char)*str;
|
|
|
|
if (~utf8_character & 0x80) {
|
2011-03-07 08:02:35 +01:00
|
|
|
if (!iswxspace(utf8_character))
|
|
|
|
break;
|
2010-08-08 10:06:34 +02:00
|
|
|
++str;
|
|
|
|
} else {
|
|
|
|
ret = unicode_utf8_to_ucs4(&ucs, str, &len);
|
2011-03-07 08:02:35 +01:00
|
|
|
if (ret != 0) {
|
2012-05-17 00:52:37 +02:00
|
|
|
log_warning("illegal character sequence in UTF8 string: %s\n", str);
|
2010-08-08 10:06:34 +02:00
|
|
|
break;
|
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
if (!iswxspace((wint_t) ucs))
|
|
|
|
break;
|
|
|
|
str += len;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
*str_p = str;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-12-22 14:21:24 +01:00
|
|
|
void init_tokens_str(const char *initstr)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2014-04-12 04:20:20 +02:00
|
|
|
if (states == NULL) {
|
|
|
|
states = malloc(sizeof(parser_state));
|
2014-08-14 09:57:05 +02:00
|
|
|
}
|
2014-04-12 04:20:20 +02:00
|
|
|
states->current_token = initstr;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
void parser_pushstate(void)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
parser_state *new_state = malloc(sizeof(parser_state));
|
2010-08-08 10:06:34 +02:00
|
|
|
new_state->current_token = NULL;
|
2014-04-12 04:20:20 +02:00
|
|
|
new_state->next = states;
|
|
|
|
states = new_state;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
void parser_popstate(void)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2014-04-12 04:20:20 +02:00
|
|
|
parser_state *new_state = states->next;
|
|
|
|
free(states);
|
|
|
|
states = new_state;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2012-06-24 07:41:07 +02:00
|
|
|
bool parser_end(void)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2014-08-23 09:17:58 +02:00
|
|
|
if (states->current_token) {
|
|
|
|
eatwhitespace_c(&states->current_token);
|
|
|
|
return *states->current_token == 0;
|
|
|
|
}
|
|
|
|
return true;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
void skip_token(void)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
|
|
|
char quotechar = 0;
|
2014-04-12 04:20:20 +02:00
|
|
|
eatwhitespace_c(&states->current_token);
|
2010-08-08 10:06:34 +02:00
|
|
|
|
2014-04-12 04:20:20 +02:00
|
|
|
while (*states->current_token) {
|
2010-08-08 10:06:34 +02:00
|
|
|
ucs4_t ucs;
|
|
|
|
size_t len;
|
|
|
|
|
2014-04-12 04:20:20 +02:00
|
|
|
unsigned char utf8_character = (unsigned char)states->current_token[0];
|
2010-08-08 10:06:34 +02:00
|
|
|
if (~utf8_character & 0x80) {
|
|
|
|
ucs = utf8_character;
|
2014-04-12 04:20:20 +02:00
|
|
|
++states->current_token;
|
2010-08-08 10:06:34 +02:00
|
|
|
} else {
|
2014-04-12 04:20:20 +02:00
|
|
|
int ret = unicode_utf8_to_ucs4(&ucs, states->current_token, &len);
|
2011-03-07 08:02:35 +01:00
|
|
|
if (ret == 0) {
|
2014-04-12 04:20:20 +02:00
|
|
|
states->current_token += len;
|
2010-08-08 10:06:34 +02:00
|
|
|
} else {
|
2014-04-12 04:20:20 +02:00
|
|
|
log_warning("illegal character sequence in UTF8 string: %s\n", states->current_token);
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
if (iswxspace((wint_t) ucs) && quotechar == 0) {
|
2010-08-08 10:06:34 +02:00
|
|
|
return;
|
|
|
|
} else {
|
2011-03-07 08:02:35 +01:00
|
|
|
switch (utf8_character) {
|
2010-08-08 10:06:34 +02:00
|
|
|
case '"':
|
|
|
|
case '\'':
|
2011-03-07 08:02:35 +01:00
|
|
|
if (utf8_character == quotechar)
|
|
|
|
return;
|
2010-08-08 10:06:34 +02:00
|
|
|
quotechar = utf8_character;
|
|
|
|
break;
|
|
|
|
case ESCAPE_CHAR:
|
2014-04-12 04:20:20 +02:00
|
|
|
++states->current_token;
|
2010-08-08 10:06:34 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-22 14:21:24 +01:00
|
|
|
char *parse_token(const char **str, char *lbuf, size_t len)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2014-12-22 14:21:24 +01:00
|
|
|
char *cursor = lbuf;
|
|
|
|
char quotechar = 0;
|
|
|
|
bool escape = false;
|
|
|
|
const char *ctoken = *str;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
2014-12-22 14:21:24 +01:00
|
|
|
if (!ctoken) {
|
|
|
|
return 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
2014-12-22 14:21:24 +01:00
|
|
|
eatwhitespace_c(&ctoken);
|
|
|
|
if (!*ctoken) {
|
2014-12-22 16:28:17 +01:00
|
|
|
if (len > 0) {
|
|
|
|
*cursor = 0;
|
|
|
|
}
|
2014-12-22 14:21:24 +01:00
|
|
|
return 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
2014-12-22 14:21:24 +01:00
|
|
|
while (*ctoken && cursor-len < lbuf-1) {
|
|
|
|
ucs4_t ucs;
|
|
|
|
size_t len;
|
|
|
|
bool copy = false;
|
|
|
|
|
|
|
|
unsigned char utf8_character = *(unsigned char *)ctoken;
|
|
|
|
if (~utf8_character & 0x80) {
|
|
|
|
ucs = utf8_character;
|
|
|
|
len = 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
int ret = unicode_utf8_to_ucs4(&ucs, ctoken, &len);
|
|
|
|
if (ret != 0) {
|
|
|
|
log_warning("illegal character sequence in UTF8 string: %s\n", ctoken);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (escape) {
|
|
|
|
copy = true;
|
|
|
|
escape = false;
|
|
|
|
}
|
|
|
|
else if (iswxspace((wint_t)ucs)) {
|
|
|
|
if (quotechar == 0)
|
|
|
|
break;
|
|
|
|
copy = true;
|
|
|
|
}
|
|
|
|
else if (utf8_character == '"' || utf8_character == '\'') {
|
|
|
|
if (utf8_character == quotechar) {
|
|
|
|
++ctoken;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (quotechar == 0) {
|
|
|
|
quotechar = utf8_character;
|
|
|
|
++ctoken;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*cursor++ = *ctoken++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (utf8_character == SPACE_REPLACEMENT) {
|
|
|
|
*cursor++ = ' ';
|
|
|
|
++ctoken;
|
|
|
|
}
|
|
|
|
else if (utf8_character == ESCAPE_CHAR) {
|
|
|
|
escape = true;
|
|
|
|
++ctoken;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
copy = true;
|
|
|
|
}
|
|
|
|
if (copy) {
|
|
|
|
memcpy(cursor, ctoken, len);
|
|
|
|
cursor += len;
|
|
|
|
ctoken += len;
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2014-12-22 14:21:24 +01:00
|
|
|
assert(cursor - len < lbuf - 1); // TODO: handle too-small buffers
|
|
|
|
*cursor = '\0';
|
|
|
|
*str = ctoken;
|
|
|
|
return lbuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *parse_token_depr(const char **str)
|
|
|
|
{
|
|
|
|
static char lbuf[MAXTOKENSIZE]; /* STATIC_RESULT: used for return, not across calls */
|
|
|
|
return parse_token(str, lbuf, MAXTOKENSIZE);
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
const char *getstrtoken(void)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2014-12-22 14:21:24 +01:00
|
|
|
char lbuf[MAXTOKENSIZE];
|
|
|
|
return parse_token((const char **)&states->current_token, lbuf, MAXTOKENSIZE);
|
|
|
|
}
|
|
|
|
|
2014-12-22 16:28:17 +01:00
|
|
|
const char *gettoken(char *lbuf, size_t bufsize)
|
2014-12-22 14:21:24 +01:00
|
|
|
{
|
|
|
|
return parse_token((const char **)&states->current_token, lbuf, bufsize);
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
2014-12-18 07:09:22 +01:00
|
|
|
|
|
|
|
int getid(void)
|
|
|
|
{
|
2014-12-22 14:21:24 +01:00
|
|
|
char token[16];
|
2014-12-22 16:28:17 +01:00
|
|
|
const char *str = gettoken(token, sizeof(token));
|
2014-12-18 07:09:22 +01:00
|
|
|
int i = str ? atoi36(str) : 0;
|
|
|
|
if (i < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|