summaryrefslogtreecommitdiff
path: root/contrib/tsearch2/prs_dcfg.c
blob: e4b0e8b644d9630b59a72de2e387f97e34cf57f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/* 
 * Simple config parser 
 * Teodor Sigaev <[email protected]>
 */
#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");
}