1 /* See COPYING.txt for the full license governing this code. */
2 /**
3 * \file action_configparser.c
4 *
5 * Source file for the parser for action config files.
6 */
7
8 #include <SDL_stdinc.h>
9 #include <SDL_test.h>
10 #include <string.h>
11 #include "SDL_visualtest_action_configparser.h"
12 #include "SDL_visualtest_rwhelper.h"
13 #include "SDL_visualtest_parsehelper.h"
14
15 static void
FreeAction(SDLVisualTest_Action * action)16 FreeAction(SDLVisualTest_Action* action)
17 {
18 if(!action)
19 return;
20 switch(action->type)
21 {
22 case SDL_ACTION_LAUNCH:
23 {
24 char* path;
25 char* args;
26
27 path = action->extra.process.path;
28 args = action->extra.process.args;
29
30 if(path)
31 SDL_free(path);
32 if(args)
33 SDL_free(args);
34
35 action->extra.process.path = NULL;
36 action->extra.process.args = NULL;
37 }
38 break;
39 }
40 }
41
42 int
SDLVisualTest_EnqueueAction(SDLVisualTest_ActionQueue * queue,SDLVisualTest_Action action)43 SDLVisualTest_EnqueueAction(SDLVisualTest_ActionQueue* queue,
44 SDLVisualTest_Action action)
45 {
46 SDLVisualTest_ActionNode* node;
47 if(!queue)
48 {
49 SDLTest_LogError("queue argument cannot be NULL");
50 return 0;
51 }
52
53 node = (SDLVisualTest_ActionNode*)SDL_malloc(
54 sizeof(SDLVisualTest_ActionNode));
55 if(!node)
56 {
57 SDLTest_LogError("malloc() failed");
58 return 0;
59 }
60 node->action = action;
61 node->next = NULL;
62 queue->size++;
63 if(!queue->rear)
64 queue->rear = queue->front = node;
65 else
66 {
67 queue->rear->next = node;
68 queue->rear = node;
69 }
70 return 1;
71 }
72
73 int
SDLVisualTest_DequeueAction(SDLVisualTest_ActionQueue * queue)74 SDLVisualTest_DequeueAction(SDLVisualTest_ActionQueue* queue)
75 {
76 SDLVisualTest_ActionNode* node;
77 if(!queue)
78 {
79 SDLTest_LogError("queue argument cannot be NULL");
80 return 0;
81 }
82 if(SDLVisualTest_IsActionQueueEmpty(queue))
83 {
84 SDLTest_LogError("cannot dequeue from empty queue");
85 return 0;
86 }
87 if(queue->front == queue->rear)
88 {
89 FreeAction(&queue->front->action);
90 SDL_free(queue->front);
91 queue->front = queue->rear = NULL;
92 }
93 else
94 {
95 node = queue->front;
96 queue->front = queue->front->next;
97 FreeAction(&node->action);
98 SDL_free(node);
99 }
100 queue->size--;
101 return 1;
102 }
103
104 void
SDLVisualTest_InitActionQueue(SDLVisualTest_ActionQueue * queue)105 SDLVisualTest_InitActionQueue(SDLVisualTest_ActionQueue* queue)
106 {
107 if(!queue)
108 {
109 SDLTest_LogError("queue argument cannot be NULL");
110 return;
111 }
112 queue->front = NULL;
113 queue->rear = NULL;
114 queue->size = 0;
115 }
116
117 SDLVisualTest_Action*
SDLVisualTest_GetQueueFront(SDLVisualTest_ActionQueue * queue)118 SDLVisualTest_GetQueueFront(SDLVisualTest_ActionQueue* queue)
119 {
120 if(!queue)
121 {
122 SDLTest_LogError("queue argument cannot be NULL");
123 return NULL;
124 }
125 if(!queue->front)
126 {
127 SDLTest_LogError("cannot get front of empty queue");
128 return NULL;
129 }
130
131 return &queue->front->action;
132 }
133
134 int
SDLVisualTest_IsActionQueueEmpty(SDLVisualTest_ActionQueue * queue)135 SDLVisualTest_IsActionQueueEmpty(SDLVisualTest_ActionQueue* queue)
136 {
137 if(!queue)
138 {
139 SDLTest_LogError("queue argument cannot be NULL");
140 return 1;
141 }
142
143 if(queue->size > 0)
144 return 0;
145 return 1;
146 }
147
148 void
SDLVisualTest_EmptyActionQueue(SDLVisualTest_ActionQueue * queue)149 SDLVisualTest_EmptyActionQueue(SDLVisualTest_ActionQueue* queue)
150 {
151 if(queue)
152 {
153 while(!SDLVisualTest_IsActionQueueEmpty(queue))
154 SDLVisualTest_DequeueAction(queue);
155 }
156 }
157
158 /* Since the size of the queue is not likely to be larger than 100 elements
159 we can get away with using insertion sort. */
160 static void
SortQueue(SDLVisualTest_ActionQueue * queue)161 SortQueue(SDLVisualTest_ActionQueue* queue)
162 {
163 SDLVisualTest_ActionNode* head;
164 SDLVisualTest_ActionNode* tail;
165
166 if(!queue || SDLVisualTest_IsActionQueueEmpty(queue))
167 return;
168
169 head = queue->front;
170 for(tail = head; tail && tail->next;)
171 {
172 SDLVisualTest_ActionNode* pos;
173 SDLVisualTest_ActionNode* element = tail->next;
174
175 if(element->action.time < head->action.time)
176 {
177 tail->next = tail->next->next;
178 element->next = head;
179 head = element;
180 }
181 else if(element->action.time >= tail->action.time)
182 {
183 tail = tail->next;
184 }
185 else
186 {
187 for(pos = head;
188 (pos->next->action.time < element->action.time);
189 pos = pos->next);
190 tail->next = tail->next->next;
191 element->next = pos->next;
192 pos->next = element;
193 }
194 }
195
196 queue->front = head;
197 queue->rear = tail;
198 }
199
200 int
SDLVisualTest_InsertIntoActionQueue(SDLVisualTest_ActionQueue * queue,SDLVisualTest_Action action)201 SDLVisualTest_InsertIntoActionQueue(SDLVisualTest_ActionQueue* queue,
202 SDLVisualTest_Action action)
203 {
204 SDLVisualTest_ActionNode* n;
205 SDLVisualTest_ActionNode* prev;
206 SDLVisualTest_ActionNode* newnode;
207 if(!queue)
208 {
209 SDLTest_LogError("queue argument cannot be NULL");
210 return 0;
211 }
212
213 if(SDLVisualTest_IsActionQueueEmpty(queue))
214 {
215 if(!SDLVisualTest_EnqueueAction(queue, action))
216 {
217 SDLTest_LogError("SDLVisualTest_EnqueueAction() failed");
218 return 0;
219 }
220 return 1;
221 }
222
223 newnode = (SDLVisualTest_ActionNode*)malloc(sizeof(SDLVisualTest_ActionNode));
224 if(!newnode)
225 {
226 SDLTest_LogError("malloc() failed");
227 return 0;
228 }
229 newnode->action = action;
230
231 queue->size++;
232 for(n = queue->front, prev = NULL; n; n = n->next)
233 {
234 if(action.time < n->action.time)
235 {
236 if(prev)
237 {
238 prev->next = newnode;
239 newnode->next = n;
240 }
241 else
242 {
243 newnode->next = queue->front;
244 queue->front = newnode;
245 }
246 return 1;
247 }
248 prev = n;
249 }
250
251 queue->rear->next = newnode;
252 newnode->next = NULL;
253 queue->rear = newnode;
254
255 return 1;
256 }
257
258 int
SDLVisualTest_ParseActionConfig(char * file,SDLVisualTest_ActionQueue * queue)259 SDLVisualTest_ParseActionConfig(char* file, SDLVisualTest_ActionQueue* queue)
260 {
261 char line[MAX_ACTION_LINE_LENGTH];
262 SDLVisualTest_RWHelperBuffer buffer;
263 char* token_ptr;
264 int linenum;
265 SDL_RWops* rw;
266
267 if(!file)
268 {
269 SDLTest_LogError("file argument cannot be NULL");
270 return 0;
271 }
272 if(!queue)
273 {
274 SDLTest_LogError("queue argument cannot be NULL");
275 return 0;
276 }
277
278 rw = SDL_RWFromFile(file, "r");
279 if(!rw)
280 {
281 SDLTest_LogError("SDL_RWFromFile() failed");
282 return 0;
283 }
284
285 SDLVisualTest_RWHelperResetBuffer(&buffer);
286 SDLVisualTest_InitActionQueue(queue);
287 linenum = 0;
288 while(SDLVisualTest_RWHelperReadLine(rw, line, MAX_ACTION_LINE_LENGTH,
289 &buffer, '#'))
290 {
291 SDLVisualTest_Action action;
292 int hr, min, sec;
293
294 /* parse time */
295 token_ptr = strtok(line, " ");
296 if(!token_ptr ||
297 (SDL_sscanf(token_ptr, "%d:%d:%d", &hr, &min, &sec) != 3))
298 {
299 SDLTest_LogError("Could not parse time token at line: %d",
300 linenum);
301 SDLVisualTest_EmptyActionQueue(queue);
302 SDL_RWclose(rw);
303 return 0;
304 }
305 action.time = (((hr * 60 + min) * 60) + sec) * 1000;
306
307 /* parse type */
308 token_ptr = strtok(NULL, " ");
309 if(SDL_strcasecmp(token_ptr, "launch") == 0)
310 action.type = SDL_ACTION_LAUNCH;
311 else if(SDL_strcasecmp(token_ptr, "kill") == 0)
312 action.type = SDL_ACTION_KILL;
313 else if(SDL_strcasecmp(token_ptr, "quit") == 0)
314 action.type = SDL_ACTION_QUIT;
315 else if(SDL_strcasecmp(token_ptr, "screenshot") == 0)
316 action.type = SDL_ACTION_SCREENSHOT;
317 else if(SDL_strcasecmp(token_ptr, "verify") == 0)
318 action.type = SDL_ACTION_VERIFY;
319 else
320 {
321 SDLTest_LogError("Could not parse type token at line: %d",
322 linenum);
323 SDLVisualTest_EmptyActionQueue(queue);
324 SDL_RWclose(rw);
325 return 0;
326 }
327
328 /* parse the extra field */
329 if(action.type == SDL_ACTION_LAUNCH)
330 {
331 int len;
332 char* args;
333 char* path;
334 token_ptr = strtok(NULL, " ");
335 len = token_ptr ? SDL_strlen(token_ptr) : 0;
336 if(len <= 0)
337 {
338 SDLTest_LogError("Please specify the process to launch at line: %d",
339 linenum);
340 SDLVisualTest_EmptyActionQueue(queue);
341 SDL_RWclose(rw);
342 return 0;
343 }
344 path = (char*)SDL_malloc(sizeof(char) * (len + 1));
345 if(!path)
346 {
347 SDLTest_LogError("malloc() failed");
348 SDLVisualTest_EmptyActionQueue(queue);
349 SDL_RWclose(rw);
350 return 0;
351 }
352 SDL_strlcpy(path, token_ptr, len + 1);
353
354 token_ptr = strtok(NULL, "");
355 len = token_ptr ? SDL_strlen(token_ptr) : 0;
356 if(len > 0)
357 {
358 args = (char*)SDL_malloc(sizeof(char) * (len + 1));
359 if(!args)
360 {
361 SDLTest_LogError("malloc() failed");
362 SDL_free(path);
363 SDLVisualTest_EmptyActionQueue(queue);
364 SDL_RWclose(rw);
365 return 0;
366 }
367 SDL_strlcpy(args, token_ptr, len + 1);
368 }
369 else
370 args = NULL;
371
372 action.extra.process.path = path;
373 action.extra.process.args = args;
374 }
375
376 /* add the action to the queue */
377 if(!SDLVisualTest_EnqueueAction(queue, action))
378 {
379 SDLTest_LogError("SDLVisualTest_EnqueueAction() failed");
380 if(action.type == SDL_ACTION_LAUNCH)
381 {
382 SDL_free(action.extra.process.path);
383 if(action.extra.process.args)
384 SDL_free(action.extra.process.args);
385 }
386 SDLVisualTest_EmptyActionQueue(queue);
387 SDL_RWclose(rw);
388 return 0;
389 }
390 }
391 /* sort the queue of actions */
392 SortQueue(queue);
393
394 SDL_RWclose(rw);
395 return 1;
396 }