1 /* See COPYING.txt for the full license governing this code. */
2 /**
3 * \file sut_configparser.c
4 *
5 * Source file for the parser for SUT config files.
6 */
7
8 #include <limits.h>
9 #include <string.h>
10 #include <SDL_test.h>
11 #include <SDL_rwops.h>
12 #include "SDL_visualtest_sut_configparser.h"
13 #include "SDL_visualtest_parsehelper.h"
14 #include "SDL_visualtest_rwhelper.h"
15
16 int
SDLVisualTest_ParseSUTConfig(char * file,SDLVisualTest_SUTConfig * config)17 SDLVisualTest_ParseSUTConfig(char* file, SDLVisualTest_SUTConfig* config)
18 {
19 char line[MAX_SUTOPTION_LINE_LENGTH];
20 SDLVisualTest_RWHelperBuffer buffer;
21 char* token_ptr;
22 char* token_end;
23 int num_lines, i, token_len;
24 SDL_RWops* rw;
25
26 if(!file)
27 {
28 SDLTest_LogError("file argument cannot be NULL");
29 return 0;
30 }
31 if(!config)
32 {
33 SDLTest_LogError("config argument cannot be NULL");
34 return 0;
35 }
36
37 /* count the number of lines */
38 rw = SDL_RWFromFile(file, "r");
39 if(!rw)
40 {
41 SDLTest_LogError("SDL_RWFromFile() failed");
42 return 0;
43 }
44 SDLVisualTest_RWHelperResetBuffer(&buffer);
45 num_lines = SDLVisualTest_RWHelperCountNonEmptyLines(rw, &buffer, '#');
46 if(num_lines == -1)
47 return 0;
48 else if(num_lines == 0)
49 {
50 config->options = NULL;
51 config->num_options = 0;
52 SDL_RWclose(rw);
53 return 1;
54 }
55
56 /* allocate memory */
57 SDL_RWseek(rw, 0, RW_SEEK_SET);
58 SDLVisualTest_RWHelperResetBuffer(&buffer);
59 config->num_options = num_lines;
60 config->options = (SDLVisualTest_SUTOption*)SDL_malloc(num_lines *
61 sizeof(SDLVisualTest_SUTOption));
62 if(!config->options)
63 {
64 SDLTest_LogError("malloc() failed");
65 SDL_RWclose(rw);
66 return 0;
67 }
68
69 /* actually parse the options */
70 for(i = 0; i < num_lines; i++)
71 {
72 if(!SDLVisualTest_RWHelperReadLine(rw, line, MAX_SUTOPTION_LINE_LENGTH,
73 &buffer, '#'))
74 {
75 SDLTest_LogError("SDLVisualTest_RWHelperReadLine() failed");
76 SDL_free(config->options);
77 SDL_RWclose(rw);
78 return 0;
79 }
80
81 /* parse name */
82 token_ptr = strtok(line, ", ");
83 if(!token_ptr)
84 {
85 SDLTest_LogError("Could not parse line %d", i + 1);
86 SDL_free(config->options);
87 SDL_RWclose(rw);
88 return 0;
89 }
90 token_len = SDL_strlen(token_ptr) + 1;
91 SDL_strlcpy(config->options[i].name, token_ptr, token_len);
92
93 /* parse type */
94 token_ptr = strtok(NULL, ", ");
95 if(!token_ptr)
96 {
97 SDLTest_LogError("Could not parse line %d", i + 1);
98 SDL_free(config->options);
99 SDL_RWclose(rw);
100 return 0;
101 }
102 if(SDL_strcmp(token_ptr, "string") == 0)
103 config->options[i].type = SDL_SUT_OPTIONTYPE_STRING;
104 else if(SDL_strcmp(token_ptr, "integer") == 0)
105 config->options[i].type = SDL_SUT_OPTIONTYPE_INT;
106 else if(SDL_strcmp(token_ptr, "enum") == 0)
107 config->options[i].type = SDL_SUT_OPTIONTYPE_ENUM;
108 else if(SDL_strcmp(token_ptr, "boolean") == 0)
109 config->options[i].type = SDL_SUT_OPTIONTYPE_BOOL;
110 else
111 {
112 SDLTest_LogError("Could not parse type token at line %d", i + 1);
113 SDL_free(config->options);
114 SDL_RWclose(rw);
115 return 0;
116 }
117
118 /* parse values */
119 token_ptr = strtok(NULL, "]");
120 if(!token_ptr)
121 {
122 SDLTest_LogError("Could not parse line %d", i + 1);
123 SDL_free(config->options);
124 SDL_RWclose(rw);
125 return 0;
126 }
127 token_ptr = SDL_strchr(token_ptr, '[');
128 if(!token_ptr)
129 {
130 SDLTest_LogError("Could not parse enum token at line %d", i + 1);
131 SDL_free(config->options);
132 SDL_RWclose(rw);
133 return 0;
134 }
135 token_ptr++;
136 if(config->options[i].type == SDL_SUT_OPTIONTYPE_INT)
137 {
138 if(SDL_sscanf(token_ptr, "%d %d", &config->options[i].data.range.min,
139 &config->options[i].data.range.max) != 2)
140 {
141 config->options[i].data.range.min = INT_MIN;
142 config->options[i].data.range.max = INT_MAX;
143 }
144 }
145 else if(config->options[i].type == SDL_SUT_OPTIONTYPE_ENUM)
146 {
147 config->options[i].data.enum_values = SDLVisualTest_Tokenize(token_ptr,
148 MAX_SUTOPTION_ENUMVAL_LEN);
149 if(!config->options[i].data.enum_values)
150 {
151 SDLTest_LogError("Could not parse enum token at line %d", i + 1);
152 SDL_free(config->options);
153 SDL_RWclose(rw);
154 return 0;
155 }
156 }
157
158 /* parse required */
159 token_ptr = strtok(NULL, ", ");
160 if(!token_ptr)
161 {
162 SDLTest_LogError("Could not parse line %d", i + 1);
163 SDL_free(config->options);
164 SDL_RWclose(rw);
165 return 0;
166 }
167
168 if(SDL_strcmp(token_ptr, "true") == 0)
169 config->options[i].required = SDL_TRUE;
170 else if(SDL_strcmp(token_ptr, "false") == 0)
171 config->options[i].required = SDL_FALSE;
172 else
173 {
174 SDLTest_LogError("Could not parse required token at line %d", i + 1);
175 SDL_free(config->options);
176 SDL_RWclose(rw);
177 return 0;
178 }
179
180 /* parse categories */
181 token_ptr = strtok(NULL, ",");
182 if(!token_ptr)
183 {
184 SDLTest_LogError("Could not parse line %d", i + 1);
185 SDL_free(config->options);
186 SDL_RWclose(rw);
187 return 0;
188 }
189 token_ptr = SDL_strchr(token_ptr, '[');
190 if(!token_ptr)
191 {
192 SDLTest_LogError("Could not parse enum token at line %d", i + 1);
193 SDL_free(config->options);
194 SDL_RWclose(rw);
195 return 0;
196 }
197 token_ptr++;
198 token_end = SDL_strchr(token_ptr, ']');
199 *token_end = '\0';
200 if(!token_end)
201 {
202 SDLTest_LogError("Could not parse enum token at line %d", i + 1);
203 SDL_free(config->options);
204 SDL_RWclose(rw);
205 return 0;
206 }
207 config->options[i].categories = SDLVisualTest_Tokenize(token_ptr,
208 MAX_SUTOPTION_CATEGORY_LEN);
209 }
210 SDL_RWclose(rw);
211 return 1;
212 }
213
214 void
SDLVisualTest_FreeSUTConfig(SDLVisualTest_SUTConfig * config)215 SDLVisualTest_FreeSUTConfig(SDLVisualTest_SUTConfig* config)
216 {
217 if(config && config->options)
218 {
219 SDLVisualTest_SUTOption* option;
220 for(option = config->options;
221 option != config->options + config->num_options; option++)
222 {
223 if(option->categories)
224 SDL_free(option->categories);
225 if(option->type == SDL_SUT_OPTIONTYPE_ENUM && option->data.enum_values)
226 SDL_free(option->data.enum_values);
227 }
228 SDL_free(config->options);
229 config->options = NULL;
230 config->num_options = 0;
231 }
232 }
233