postgresql/contrib/tsearch2/prs_dcfg.c

120 lines
2.9 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(*ptr)) {
begin=ptr;
state=CS_INKEY;
} else if ( !isspace(*ptr) )
elog(ERROR,"Syntax error in position %d near '%c'", ptr-VARDATA(in), *ptr);
} else if (state==CS_INKEY) {
if ( isspace(*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(*ptr) )
elog(ERROR,"Syntax error in position %d near '%c'", ptr-VARDATA(in), *ptr);
} else if ( state==CS_WAITEQ ) {
if ( *ptr=='=' )
state=CS_WAITVALUE;
else if ( !isspace(*ptr) )
elog(ERROR,"Syntax error in position %d near '%c'", ptr-VARDATA(in), *ptr);
} else if ( state==CS_WAITVALUE ) {
if ( *ptr=='"' ) {
begin=ptr+1;
state=CS_INVALUE;
} else if ( !isspace(*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(*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(*ptr) )
elog(ERROR,"Syntax error in position %d near '%c'", ptr-VARDATA(in), *ptr);
} else if ( state == CS_INESC ) {
state=CS_INVALUE;
} else if ( state == CS_IN2ESC ) {
state=CS_IN2VALUE;
} else
elog(ERROR,"Bad parser state: %d at position %d near '%c'", state, ptr-VARDATA(in), *ptr);
ptr++;
}
if (state==CS_IN2VALUE) {
mptr->value = nstrdup(begin, ptr-begin);
mptr++;
} else if ( !(state==CS_WAITDELIM || state==CS_WAITKEY) )
elog(ERROR,"Unexpected end of line");
}