visualtest/src/action_configparser.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 23 May 2018 17:15:35 -0700
changeset 11999 f3fc4b3d54f6
parent 7924 fcb86d323770
permissions -rw-r--r--
Better fix for axis sorting with some Android controllers
     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
    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
    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
    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
   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*
   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
   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
   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
   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
   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
   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 }