2007-06-22 00:31:28 +02:00
|
|
|
#include <config.h>
|
|
|
|
#include "parser.h"
|
2007-06-26 11:32:28 +02:00
|
|
|
#include "unicode.h"
|
|
|
|
#include "log.h"
|
2007-06-22 00:31:28 +02:00
|
|
|
|
|
|
|
#include <assert.h>
|
2007-06-26 11:51:18 +02:00
|
|
|
#include <wctype.h>
|
2007-06-26 11:32:28 +02:00
|
|
|
#include <memory.h>
|
2007-06-22 00:31:28 +02:00
|
|
|
|
|
|
|
#define SPACE_REPLACEMENT '~'
|
|
|
|
#define ESCAPE_CHAR '\\'
|
|
|
|
#define MAXTOKENSIZE 8192
|
|
|
|
|
|
|
|
typedef struct parser_state {
|
2007-06-26 11:32:28 +02:00
|
|
|
const xmlChar *current_token;
|
|
|
|
xmlChar * current_cmd;
|
2007-06-22 00:31:28 +02:00
|
|
|
struct parser_state * next;
|
|
|
|
} parser_state;
|
|
|
|
|
|
|
|
static parser_state * state;
|
|
|
|
|
2007-06-26 11:32:28 +02:00
|
|
|
static int
|
|
|
|
eatwhitespace_c(const xmlChar ** str)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
wint_t ucs;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
/* skip over potential whitespace */
|
|
|
|
for (;;) {
|
|
|
|
xmlChar utf8_character = (*str)[0];
|
|
|
|
if (utf8_character <= 0x7F) {
|
2007-06-26 11:51:18 +02:00
|
|
|
if (!iswspace(utf8_character)) break;
|
2007-06-26 11:32:28 +02:00
|
|
|
++*str;
|
|
|
|
} else {
|
|
|
|
ret = unicode_utf8_to_ucs4(&ucs, *str, &len);
|
|
|
|
if (ret!=0) {
|
|
|
|
log_warning(("illegal character sequence in UTF8 string: %s\n", *str));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
if (!iswspace(ucs)) break;
|
|
|
|
*str+=len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-06-22 00:31:28 +02:00
|
|
|
void
|
2007-06-26 11:32:28 +02:00
|
|
|
init_tokens_str(const xmlChar * initstr, xmlChar * cmd)
|
2007-06-22 00:31:28 +02:00
|
|
|
{
|
|
|
|
if (state==NULL) {
|
|
|
|
state = malloc(sizeof(parser_state));
|
|
|
|
}
|
2007-06-25 03:50:34 +02:00
|
|
|
else if (state->current_cmd) free(state->current_cmd);
|
2007-06-22 00:31:28 +02:00
|
|
|
state->current_cmd = cmd;
|
2007-06-26 11:32:28 +02:00
|
|
|
state->current_token = (const xmlChar *)initstr;
|
2007-06-22 00:31:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
parser_pushstate(void)
|
|
|
|
{
|
|
|
|
parser_state * new_state = malloc(sizeof(parser_state));
|
|
|
|
new_state->current_cmd = NULL;
|
|
|
|
new_state->current_token = NULL;
|
|
|
|
new_state->next = state;
|
|
|
|
state = new_state;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
parser_popstate(void)
|
|
|
|
{
|
|
|
|
parser_state * new_state = state->next;
|
|
|
|
if (state->current_cmd!=NULL) free(state->current_cmd);
|
|
|
|
free(state);
|
|
|
|
state = new_state;
|
|
|
|
}
|
|
|
|
|
|
|
|
boolean
|
|
|
|
parser_end(void)
|
|
|
|
{
|
2007-06-26 11:32:28 +02:00
|
|
|
eatwhitespace_c(&state->current_token);
|
2007-06-22 00:31:28 +02:00
|
|
|
return *state->current_token == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
skip_token(void)
|
|
|
|
{
|
|
|
|
char quotechar = 0;
|
2007-06-26 11:32:28 +02:00
|
|
|
eatwhitespace_c(&state->current_token);
|
2007-06-22 00:31:28 +02:00
|
|
|
|
|
|
|
while (*state->current_token) {
|
2007-06-26 11:32:28 +02:00
|
|
|
wint_t ucs;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
xmlChar utf8_character = state->current_token[0];
|
|
|
|
if (utf8_character <= 0x7F) {
|
|
|
|
ucs = utf8_character;
|
|
|
|
++state->current_token;
|
|
|
|
} else {
|
|
|
|
int ret = unicode_utf8_to_ucs4(&ucs, state->current_token, &len);
|
|
|
|
if (ret==0) {
|
|
|
|
state->current_token+=len;
|
|
|
|
} else {
|
|
|
|
log_warning(("illegal character sequence in UTF8 string: %s\n", state->current_token));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (iswspace(ucs) && quotechar==0) {
|
2007-06-22 00:31:28 +02:00
|
|
|
return;
|
|
|
|
} else {
|
2007-06-26 11:32:28 +02:00
|
|
|
switch(utf8_character) {
|
2007-06-22 00:31:28 +02:00
|
|
|
case '"':
|
|
|
|
case '\'':
|
2007-06-26 11:32:28 +02:00
|
|
|
if (utf8_character==quotechar) return;
|
|
|
|
quotechar = utf8_character;
|
2007-06-22 00:31:28 +02:00
|
|
|
break;
|
|
|
|
case ESCAPE_CHAR:
|
|
|
|
++state->current_token;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-26 11:32:28 +02:00
|
|
|
const xmlChar *
|
|
|
|
parse_token(const xmlChar ** str)
|
2007-06-22 00:31:28 +02:00
|
|
|
{
|
2007-06-26 11:32:28 +02:00
|
|
|
static xmlChar lbuf[MAXTOKENSIZE];
|
|
|
|
xmlChar * cursor = lbuf;
|
2007-06-22 00:31:28 +02:00
|
|
|
char quotechar = 0;
|
|
|
|
boolean escape = false;
|
2007-06-26 11:32:28 +02:00
|
|
|
const xmlChar * ctoken = *str;
|
2007-06-22 00:31:28 +02:00
|
|
|
|
|
|
|
assert(ctoken);
|
|
|
|
|
2007-06-26 11:32:28 +02:00
|
|
|
eatwhitespace_c(&ctoken);
|
2007-06-22 00:31:28 +02:00
|
|
|
while (*ctoken && cursor-lbuf < MAXTOKENSIZE-1) {
|
2007-06-26 11:32:28 +02:00
|
|
|
wint_t ucs;
|
|
|
|
size_t len;
|
|
|
|
boolean copy = false;
|
|
|
|
|
|
|
|
xmlChar utf8_character = *ctoken;
|
|
|
|
if (utf8_character <= 0x7F) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2007-06-22 00:31:28 +02:00
|
|
|
if (escape) {
|
2007-06-26 11:32:28 +02:00
|
|
|
copy = true;
|
|
|
|
} else if (iswspace(ucs)) {
|
2007-06-22 00:31:28 +02:00
|
|
|
if (quotechar==0) break;
|
2007-06-26 11:32:28 +02:00
|
|
|
copy = true;
|
|
|
|
} else if (utf8_character=='"' || utf8_character=='\'') {
|
|
|
|
if (utf8_character==quotechar) {
|
2007-06-22 00:31:28 +02:00
|
|
|
++ctoken;
|
|
|
|
break;
|
|
|
|
} else if (quotechar==0) {
|
2007-06-26 11:32:28 +02:00
|
|
|
quotechar = utf8_character;
|
2007-06-22 00:31:28 +02:00
|
|
|
++ctoken;
|
|
|
|
} else {
|
|
|
|
*cursor++ = *ctoken++;
|
|
|
|
}
|
2007-06-26 11:32:28 +02:00
|
|
|
} else if (utf8_character==SPACE_REPLACEMENT) {
|
2007-06-22 00:31:28 +02:00
|
|
|
*cursor++ = ' ';
|
|
|
|
++ctoken;
|
2007-06-26 11:32:28 +02:00
|
|
|
} else if (utf8_character==ESCAPE_CHAR) {
|
2007-06-22 00:31:28 +02:00
|
|
|
escape = true;
|
|
|
|
++ctoken;
|
|
|
|
} else {
|
2007-06-26 11:32:28 +02:00
|
|
|
copy = true;
|
|
|
|
}
|
|
|
|
if (copy) {
|
|
|
|
memcpy(cursor, ctoken, len);
|
|
|
|
cursor+=len;
|
|
|
|
ctoken+=len;
|
2007-06-22 00:31:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*cursor = '\0';
|
2007-06-26 11:32:28 +02:00
|
|
|
*str = ctoken;
|
2007-06-22 00:31:28 +02:00
|
|
|
return lbuf;
|
|
|
|
}
|
|
|
|
|
2007-06-26 11:32:28 +02:00
|
|
|
const xmlChar *
|
2007-06-22 00:31:28 +02:00
|
|
|
getstrtoken(void)
|
|
|
|
{
|
2007-06-26 11:32:28 +02:00
|
|
|
return parse_token((const xmlChar**)&state->current_token);
|
2007-06-22 00:31:28 +02:00
|
|
|
}
|