Edit

kc3-lang/SDL/visualtest/src/action_configparser.c

Branch :

  • Show log

    Commit

  • Author : Philipp Wiesemann
    Date : 2015-06-21 17:33:46
    Hash : 0e45984f
    Message : Fixed crash if initialization of EGL failed but was tried again later. The internal function SDL_EGL_LoadLibrary() did not delete and remove a mostly uninitialized data structure if loading the library first failed. A later try to use EGL then skipped initialization and assumed it was previously successful because the data structure now already existed. This led to at least one crash in the internal function SDL_EGL_ChooseConfig() because a NULL pointer was dereferenced to make a call to eglBindAPI().

  • visualtest/src/action_configparser.c
  • /* See COPYING.txt for the full license governing this code. */
    /**
     * \file action_configparser.c
     *
     * Source file for the parser for action config files.
     */
    
    #include <SDL_stdinc.h>
    #include <SDL_test.h>
    #include <string.h>
    #include "SDL_visualtest_action_configparser.h"
    #include "SDL_visualtest_rwhelper.h"
    #include "SDL_visualtest_parsehelper.h"
    
    static void
    FreeAction(SDLVisualTest_Action* action)
    {
        if(!action)
            return;
        switch(action->type)
        {
            case SDL_ACTION_LAUNCH:
            {
                char* path;
                char* args;
    
                path = action->extra.process.path;
                args = action->extra.process.args;
    
                if(path)
                    SDL_free(path);
                if(args)
                    SDL_free(args);
    
                action->extra.process.path = NULL;
                action->extra.process.args = NULL;
            }
            break;
        }
    }
    
    int
    SDLVisualTest_EnqueueAction(SDLVisualTest_ActionQueue* queue,
                                SDLVisualTest_Action action)
    {
        SDLVisualTest_ActionNode* node;
        if(!queue)
        {
            SDLTest_LogError("queue argument cannot be NULL");
            return 0;
        }
    
        node = (SDLVisualTest_ActionNode*)SDL_malloc(
                                          sizeof(SDLVisualTest_ActionNode));
        if(!node)
        {
            SDLTest_LogError("malloc() failed");
            return 0;
        }
        node->action = action;
        node->next = NULL;
        queue->size++;
        if(!queue->rear)
            queue->rear = queue->front = node;
        else
        {
            queue->rear->next = node;
            queue->rear = node;
        }
        return 1;
    }
    
    int
    SDLVisualTest_DequeueAction(SDLVisualTest_ActionQueue* queue)
    {
        SDLVisualTest_ActionNode* node;
        if(!queue)
        {
            SDLTest_LogError("queue argument cannot be NULL");
            return 0;
        }
        if(SDLVisualTest_IsActionQueueEmpty(queue))
        {
            SDLTest_LogError("cannot dequeue from empty queue");
            return 0;
        }
        if(queue->front == queue->rear)
        {
            FreeAction(&queue->front->action);
            SDL_free(queue->front);
            queue->front = queue->rear = NULL;
        }
        else
        {
            node = queue->front;
            queue->front = queue->front->next;
            FreeAction(&node->action);
            SDL_free(node);
        }
        queue->size--;
        return 1;
    }
    
    void
    SDLVisualTest_InitActionQueue(SDLVisualTest_ActionQueue* queue)
    {
        if(!queue)
        {
            SDLTest_LogError("queue argument cannot be NULL");
            return;
        }
        queue->front = NULL;
        queue->rear = NULL;
        queue->size = 0;
    }
    
    SDLVisualTest_Action*
    SDLVisualTest_GetQueueFront(SDLVisualTest_ActionQueue* queue)
    {
        if(!queue)
        {
            SDLTest_LogError("queue argument cannot be NULL");
            return NULL;
        }
        if(!queue->front)
        {
            SDLTest_LogError("cannot get front of empty queue");
            return NULL;
        }
    
        return &queue->front->action;
    }
    
    int
    SDLVisualTest_IsActionQueueEmpty(SDLVisualTest_ActionQueue* queue)
    {
        if(!queue)
        {
            SDLTest_LogError("queue argument cannot be NULL");
            return 1;
        }
    
        if(queue->size > 0)
            return 0;
        return 1;
    }
    
    void
    SDLVisualTest_EmptyActionQueue(SDLVisualTest_ActionQueue* queue)
    {
        if(queue)
        {
            while(!SDLVisualTest_IsActionQueueEmpty(queue))
                SDLVisualTest_DequeueAction(queue);
        }
    }
    
    /* Since the size of the queue is not likely to be larger than 100 elements
       we can get away with using insertion sort. */
    static void
    SortQueue(SDLVisualTest_ActionQueue* queue)
    {
        SDLVisualTest_ActionNode* head;
        SDLVisualTest_ActionNode* tail;
    
        if(!queue || SDLVisualTest_IsActionQueueEmpty(queue))
            return;
    
        head = queue->front;
        for(tail = head; tail && tail->next;)
        {
            SDLVisualTest_ActionNode* pos;
            SDLVisualTest_ActionNode* element = tail->next;
    
            if(element->action.time < head->action.time)
            {
                tail->next = tail->next->next;
                element->next = head;
                head = element;
            }
            else if(element->action.time >= tail->action.time)
            {
                tail = tail->next;
            }
            else
            {
                for(pos = head;
                    (pos->next->action.time < element->action.time);
                    pos = pos->next);
                tail->next = tail->next->next;
                element->next = pos->next;
                pos->next = element;
            }
        }
    
        queue->front = head;
        queue->rear = tail;
    }
    
    int
    SDLVisualTest_InsertIntoActionQueue(SDLVisualTest_ActionQueue* queue,
                                        SDLVisualTest_Action action)
    {
        SDLVisualTest_ActionNode* n;
        SDLVisualTest_ActionNode* prev;
        SDLVisualTest_ActionNode* newnode;
        if(!queue)
        {
            SDLTest_LogError("queue argument cannot be NULL");
            return 0;
        }
    
        if(SDLVisualTest_IsActionQueueEmpty(queue))
        {
            if(!SDLVisualTest_EnqueueAction(queue, action))
            {
                SDLTest_LogError("SDLVisualTest_EnqueueAction() failed");
                return 0;
            }
            return 1;
        }
    
        newnode = (SDLVisualTest_ActionNode*)malloc(sizeof(SDLVisualTest_ActionNode));
        if(!newnode)
        {
            SDLTest_LogError("malloc() failed");
            return 0;
        }
        newnode->action = action;
    
        queue->size++;
        for(n = queue->front, prev = NULL; n; n = n->next)
        {
            if(action.time < n->action.time)
            {
                if(prev)
                {
                    prev->next = newnode;
                    newnode->next = n;
                }
                else
                {
                    newnode->next = queue->front;
                    queue->front = newnode;
                }
                return 1;
            }
            prev = n;
        }
    
        queue->rear->next = newnode;
        newnode->next = NULL;
        queue->rear = newnode;
    
        return 1;
    }
    
    int
    SDLVisualTest_ParseActionConfig(char* file, SDLVisualTest_ActionQueue* queue)
    {
        char line[MAX_ACTION_LINE_LENGTH];
        SDLVisualTest_RWHelperBuffer buffer;
        char* token_ptr;
        int linenum;
        SDL_RWops* rw;
    
        if(!file)
        {
            SDLTest_LogError("file argument cannot be NULL");
            return 0;
        }
        if(!queue)
        {
            SDLTest_LogError("queue argument cannot be NULL");
            return 0;
        }
    
        rw = SDL_RWFromFile(file, "r");
        if(!rw)
        {
            SDLTest_LogError("SDL_RWFromFile() failed");
            return 0;
        }
    
        SDLVisualTest_RWHelperResetBuffer(&buffer);
        SDLVisualTest_InitActionQueue(queue);
        linenum = 0;
        while(SDLVisualTest_RWHelperReadLine(rw, line, MAX_ACTION_LINE_LENGTH,
                                             &buffer, '#'))
        {
            SDLVisualTest_Action action;
            int hr, min, sec;
    
            /* parse time */
            token_ptr = strtok(line, " ");
            if(!token_ptr ||
               (SDL_sscanf(token_ptr, "%d:%d:%d", &hr, &min, &sec) != 3))
            {
                SDLTest_LogError("Could not parse time token at line: %d",
                                 linenum);
                SDLVisualTest_EmptyActionQueue(queue);
                SDL_RWclose(rw);
                return 0;
            }
            action.time = (((hr * 60 + min) * 60) + sec) * 1000;
    
            /* parse type */
            token_ptr = strtok(NULL, " ");
            if(SDL_strcasecmp(token_ptr, "launch") == 0)
                action.type = SDL_ACTION_LAUNCH;
            else if(SDL_strcasecmp(token_ptr, "kill") == 0)
                action.type = SDL_ACTION_KILL;
            else if(SDL_strcasecmp(token_ptr, "quit") == 0)
                action.type = SDL_ACTION_QUIT;
            else if(SDL_strcasecmp(token_ptr, "screenshot") == 0)
                action.type = SDL_ACTION_SCREENSHOT;
            else if(SDL_strcasecmp(token_ptr, "verify") == 0)
                action.type = SDL_ACTION_VERIFY;
            else
            {
                SDLTest_LogError("Could not parse type token at line: %d",
                                 linenum);
                SDLVisualTest_EmptyActionQueue(queue);
                SDL_RWclose(rw);
                return 0;
            }
    
            /* parse the extra field */
            if(action.type == SDL_ACTION_LAUNCH)
            {
                int len;
                char* args;
                char* path;
                token_ptr = strtok(NULL, " ");
                len = token_ptr ? SDL_strlen(token_ptr) : 0;
                if(len <= 0)
                {
                    SDLTest_LogError("Please specify the process to launch at line: %d",
                                     linenum);
                    SDLVisualTest_EmptyActionQueue(queue);
                    SDL_RWclose(rw);
                    return 0;
                }
                path = (char*)SDL_malloc(sizeof(char) * (len + 1));
                if(!path)
                {
                    SDLTest_LogError("malloc() failed");
                    SDLVisualTest_EmptyActionQueue(queue);
                    SDL_RWclose(rw);
                    return 0;
                }
                SDL_strlcpy(path, token_ptr, len + 1);
    
                token_ptr = strtok(NULL, "");
                len = token_ptr ? SDL_strlen(token_ptr) : 0;
                if(len > 0)
                {
                    args = (char*)SDL_malloc(sizeof(char) * (len + 1));
                    if(!args)
                    {
                        SDLTest_LogError("malloc() failed");
                        SDL_free(path);
                        SDLVisualTest_EmptyActionQueue(queue);
                        SDL_RWclose(rw);
                        return 0;
                    }
                    SDL_strlcpy(args, token_ptr, len + 1);
                }
                else
                    args = NULL;
    
                action.extra.process.path = path;
                action.extra.process.args = args;
            }
    
            /* add the action to the queue */
            if(!SDLVisualTest_EnqueueAction(queue, action))
            {
                SDLTest_LogError("SDLVisualTest_EnqueueAction() failed");
                if(action.type == SDL_ACTION_LAUNCH)
                {
                    SDL_free(action.extra.process.path);
                    if(action.extra.process.args)
                        SDL_free(action.extra.process.args);
                }
                SDLVisualTest_EmptyActionQueue(queue);
                SDL_RWclose(rw);
                return 0;
            }
        }
        /* sort the queue of actions */
        SortQueue(queue);
    
        SDL_RWclose(rw);
        return 1;
    }