/* See LICENSE.txt for the full license governing this code. */ /** * \file action_configparser.c * * Source file for the parser for action config files. */ #include #include #include #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; default: 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("SDL_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*)SDL_malloc(sizeof(SDLVisualTest_ActionNode)); if(!newnode) { SDLTest_LogError("SDL_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(const 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("SDL_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("SDL_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; }