/* * Simple config parser * Teodor Sigaev */ #include #include #include #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) ) 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(*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) ) 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(*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(*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) ) 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"))); }