1 #include "pgrn-global.h"
2 #include "pgrn-groonga.h"
3 #include "pgrn-string.h"
4 
5 static grn_ctx *ctx = &PGrnContext;
6 static struct PGrnBuffers *buffers = &PGrnBuffers;
7 
8 void
PGrnStringSubstituteIndex(const char * string,unsigned int stringSize,grn_obj * output,const char * indexName,int section)9 PGrnStringSubstituteIndex(const char *string,
10 						  unsigned int stringSize,
11 						  grn_obj *output,
12 						  const char *indexName,
13 						  int section)
14 {
15 	const char variable[] = "$index";
16 	const size_t variableSize = sizeof(variable) - 1;
17 	const char *current = string;
18 	const char *end = current + stringSize;
19 
20 	while (current < end)
21 	{
22 		int char_length = grn_charlen(ctx, current, end);
23 		if (char_length == 0) {
24 			return;
25 		}
26 		if (char_length == 1 &&
27 			current[0] == '$' &&
28 			(end - current) >= variableSize &&
29 			memcmp(current, variable, variableSize) == 0)
30 		{
31 			grn_text_printf(ctx, output, "%s[%d]", indexName, section);
32 			current += variableSize;
33 			continue;
34 		}
35 
36 		GRN_TEXT_PUT(ctx, output, current, char_length);
37 		current += char_length;
38 	}
39 }
40 
41 void
PGrnStringSubstituteVariables(const char * string,unsigned int stringSize,grn_obj * output)42 PGrnStringSubstituteVariables(const char *string,
43 							  unsigned int stringSize,
44 							  grn_obj *output)
45 {
46 	const char *current = string;
47 	const char *end = current + stringSize;
48 	enum {
49 		STATE_RAW,
50 		STATE_ESCAPE,
51 		STATE_VARIABLE_START,
52 		STATE_IN_VARIABLE_BLOCK,
53 	} state = STATE_RAW;
54 	const char *variableSubstitutionStart = NULL;
55 	enum {
56 		VARIABLE_TYPE_NONE,
57 		VARIABLE_TYPE_TABLE,
58 		/* TODO */
59 		/* VARIABLE_TYPE_INDEX_COLUMN, */
60 	} variableType = VARIABLE_TYPE_NONE;
61 	const char *targetStart = NULL;
62 
63 	while (current < end)
64 	{
65 		int charLength = grn_charlen(ctx, current, end);
66 		if (charLength == 0) {
67 			return;
68 		}
69 		switch (state)
70 		{
71 		case STATE_RAW:
72 			if (charLength == 1 && current[0] == '\\')
73 			{
74 				state = STATE_ESCAPE;
75 			}
76 			else if (charLength == 1 && current[0] == '$')
77 			{
78 				state = STATE_VARIABLE_START;
79 				variableSubstitutionStart = current;
80 			}
81 			else
82 			{
83 				GRN_TEXT_PUT(ctx, output, current, charLength);
84 			}
85 			break;
86 		case STATE_ESCAPE:
87 			GRN_TEXT_PUT(ctx, output, current, charLength);
88 			state = STATE_RAW;
89 			break;
90 		case STATE_VARIABLE_START:
91 			if (charLength == 1 && current[0] == '{')
92 			{
93 				state = STATE_IN_VARIABLE_BLOCK;
94 			}
95 			else
96 			{
97 				/* Not variable substitution. */
98 				GRN_TEXT_PUT(ctx,
99 							 output,
100 							 variableSubstitutionStart,
101 							 (current - variableSubstitutionStart) + charLength);
102 				state = STATE_RAW;
103 				variableSubstitutionStart = NULL;
104 				variableType = VARIABLE_TYPE_NONE;
105 				targetStart = NULL;
106 			}
107 			break;
108 		case STATE_IN_VARIABLE_BLOCK:
109 			if (charLength == 1 &&
110 				variableType == VARIABLE_TYPE_NONE &&
111 				current[0] == ':')
112 			{
113 				grn_raw_string rawVariable;
114 				rawVariable.value = variableSubstitutionStart + strlen("${");
115 				rawVariable.length = current - rawVariable.value;
116 				if (GRN_RAW_STRING_EQUAL_CSTRING(rawVariable, "table"))
117 				{
118 					variableType = VARIABLE_TYPE_TABLE;
119 					targetStart = current + charLength;
120 				}
121 				/*
122 				else if (GRN_RAW_STRING_EQUAL_CSTRING(rawVariable, "index_column"))
123 				{
124 					variableType = VARIABLE_TYPE_INDEX_COLUMN;
125 					targetStart = current + charLength;
126 				}
127 				*/
128 			}
129 			else if (charLength == 1 && current[0] == '}')
130 			{
131 				switch (variableType)
132 				{
133 				case VARIABLE_TYPE_TABLE:
134 				{
135 					grn_obj *indexName = &(buffers->text);
136 					char tableName[GRN_TABLE_MAX_KEY_SIZE];
137 					GRN_TEXT_SET(ctx,
138 								 indexName,
139 								 targetStart,
140 								 current - targetStart);
141 					GRN_TEXT_PUTC(ctx, indexName, '\0');
142 					PGrnFormatSourcesTableName(GRN_TEXT_VALUE(indexName),
143 											   tableName);
144 					GRN_TEXT_PUTS(ctx, output, tableName);
145 					break;
146 				}
147 				/* TODO:  */
148 				/* case VARIABLE_TYPE_INDEX_COLUMN: */
149 				default:
150 					/* Not variable substitution. */
151 					GRN_TEXT_PUT(ctx,
152 								 output,
153 								 variableSubstitutionStart,
154 								 (current - variableSubstitutionStart) + charLength);
155 					break;
156 				}
157 				state = STATE_RAW;
158 				variableSubstitutionStart = NULL;
159 				variableType = VARIABLE_TYPE_NONE;
160 				targetStart = NULL;
161 			}
162 			break;
163 		default:
164 			break;
165 		}
166 		current += charLength;
167 	}
168 }
169