cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

action_configparser.c (10173B)


      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
     15static void
     16FreeAction(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
     42int
     43SDLVisualTest_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
     73int
     74SDLVisualTest_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
    104void
    105SDLVisualTest_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
    117SDLVisualTest_Action*
    118SDLVisualTest_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
    134int
    135SDLVisualTest_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
    148void
    149SDLVisualTest_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. */
    160static void
    161SortQueue(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
    200int
    201SDLVisualTest_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
    258int
    259SDLVisualTest_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}