• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }