postgres/contrib/tsearch2/prs_dcfg.c

180 lines
3.7 KiB
C

/*
* Simple config parser
* Teodor Sigaev <teodor@sigaev.ru>
*/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "postgres.h"
#include "dict.h"
#include "common.h"
#define CS_WAITKEY 0
#define CS_INKEY 1
#define CS_WAITEQ 2
#define CS_WAITVALUE 3
#define CS_INVALUE 4
#define CS_IN2VALUE 5
#define CS_WAITDELIM 6
#define CS_INESC 7
#define CS_IN2ESC 8
static char *
nstrdup(char *ptr, int len)
{
char *res = palloc(len + 1),
*cptr;
memcpy(res, ptr, len);
res[len] = '\0';
cptr = ptr = res;
while (*ptr)
{
if (*ptr == '\\')
ptr++;
*cptr = *ptr;
ptr++;
cptr++;
}
*cptr = '\0';
return res;
}
void
parse_cfgdict(text *in, Map ** m)
{
Map *mptr;
char *ptr = VARDATA(in),
*begin = NULL;
char num = 0;
int state = CS_WAITKEY;
while (ptr - VARDATA(in) < VARSIZE(in) - VARHDRSZ)
{
if (*ptr == ',')
num++;
ptr++;
}
*m = mptr = (Map *) palloc(sizeof(Map) * (num + 2));
memset(mptr, 0, sizeof(Map) * (num + 2));
ptr = VARDATA(in);
while (ptr - VARDATA(in) < VARSIZE(in) - VARHDRSZ)
{
if (state == CS_WAITKEY)
{
if (isalpha((unsigned char) *ptr))
{
begin = ptr;
state = CS_INKEY;
}
else if (!isspace((unsigned char) *ptr))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("syntax error"),
errdetail("Syntax error in position %d near \"%c\"",
(int) (ptr - VARDATA(in)), *ptr)));
}
else if (state == CS_INKEY)
{
if (isspace((unsigned char) *ptr))
{
mptr->key = nstrdup(begin, ptr - begin);
state = CS_WAITEQ;
}
else if (*ptr == '=')
{
mptr->key = nstrdup(begin, ptr - begin);
state = CS_WAITVALUE;
}
else if (!isalpha((unsigned char) *ptr))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("syntax error"),
errdetail("Syntax error in position %d near \"%c\"",
(int) (ptr - VARDATA(in)), *ptr)));
}
else if (state == CS_WAITEQ)
{
if (*ptr == '=')
state = CS_WAITVALUE;
else if (!isspace((unsigned char) *ptr))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("syntax error"),
errdetail("Syntax error in position %d near \"%c\"",
(int) (ptr - VARDATA(in)), *ptr)));
}
else if (state == CS_WAITVALUE)
{
if (*ptr == '"')
{
begin = ptr + 1;
state = CS_INVALUE;
}
else if (!isspace((unsigned char) *ptr))
{
begin = ptr;
state = CS_IN2VALUE;
}
}
else if (state == CS_INVALUE)
{
if (*ptr == '"')
{
mptr->value = nstrdup(begin, ptr - begin);
mptr++;
state = CS_WAITDELIM;
}
else if (*ptr == '\\')
state = CS_INESC;
}
else if (state == CS_IN2VALUE)
{
if (isspace((unsigned char) *ptr) || *ptr == ',')
{
mptr->value = nstrdup(begin, ptr - begin);
mptr++;
state = (*ptr == ',') ? CS_WAITKEY : CS_WAITDELIM;
}
else if (*ptr == '\\')
state = CS_INESC;
}
else if (state == CS_WAITDELIM)
{
if (*ptr == ',')
state = CS_WAITKEY;
else if (!isspace((unsigned char) *ptr))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("syntax error"),
errdetail("Syntax error in position %d near \"%c\"",
(int) (ptr - VARDATA(in)), *ptr)));
}
else if (state == CS_INESC)
state = CS_INVALUE;
else if (state == CS_IN2ESC)
state = CS_IN2VALUE;
else
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("bad parser state"),
errdetail("%d at position %d near \"%c\"",
state, (int) (ptr - VARDATA(in)), *ptr)));
ptr++;
}
if (state == CS_IN2VALUE)
{
mptr->value = nstrdup(begin, ptr - begin);
mptr++;
}
else if (!(state == CS_WAITDELIM || state == CS_WAITKEY))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("unexpected end of line")));
}