all repos — mgba @ 18ea9502cd40b5b5ef288dcc92cbbef38aafcfea

mGBA Game Boy Advance Emulator

Test: Allow logging to mark messages as repeating
Vicki Pfau vi@endrift.com
Tue, 21 Jul 2020 23:49:26 -0700
commit

18ea9502cd40b5b5ef288dcc92cbbef38aafcfea

parent

f1d90e5f72c07ada7380685ec4bb5ceabe92fdb7

1 files changed, 95 insertions(+), 55 deletions(-)

jump to
M src/platform/test/cinema-main.csrc/platform/test/cinema-main.c

@@ -94,8 +94,15 @@ DECLARE_VECTOR(ImageList, void*)

DEFINE_VECTOR(ImageList, void*) struct StringBuilder { - struct StringList out; - struct StringList err; + struct StringList lines; + struct StringList partial; + unsigned repeat; + +}; + +struct CInemaLogStream { + struct StringBuilder err; + struct StringBuilder out; }; static bool showVersion = false;

@@ -115,7 +122,7 @@ static size_t jobIndex = 0;

static Mutex jobMutex; static Thread jobThreads[MAX_JOBS]; static int jobStatus; -static ThreadLocal stringBuilder; +static ThreadLocal logStream; static ThreadLocal currentTest; bool CInemaTestInit(struct CInemaTest*, const char* directory, const char* filename);

@@ -126,27 +133,70 @@ void CInemaConfigLoad(struct Table* configTree, const char* testName, struct mCore* core);

static void _log(struct mLogger* log, int category, enum mLogLevel level, const char* format, va_list args); -void CIflush(struct StringList* list, FILE* out); +void CIflush(struct StringBuilder* list, FILE* file); -ATTRIBUTE_FORMAT(printf, 2, 3) void CIlog(int minlevel, const char* format, ...) { - if (verbosity < minlevel) { - return; +static char* _compileStringList(struct StringList* list) { + size_t len = 0; + size_t i; + for (i = 0; i < StringListSize(list); ++i) { + len += strlen(*StringListGetPointer(list, i)); } - va_list args; - va_start(args, format); + char* string = calloc(len + 1, sizeof(char)); + char* cur = string; + for (i = 0; i < StringListSize(list); ++i) { + char* brick = *StringListGetPointer(list, i); + size_t portion = strlen(brick); + memcpy(cur, brick, portion); + free(brick); + cur += portion; + } + StringListClear(list); + return string; +} + +static void _logToStream(FILE* file, const char* format, va_list args) { #ifdef HAVE_VASPRINTF - struct StringBuilder* builder = ThreadLocalGetValue(stringBuilder); - if (!builder) { - vprintf(format, args); + struct CInemaLogStream* stream = ThreadLocalGetValue(logStream); + if (!stream) { + vfprintf(file, format, args); } else { - if (StringListSize(&builder->out) > LOG_THRESHOLD) { - CIflush(&builder->out, stdout); + struct StringBuilder* builder = &stream->out; + if (file == stderr) { + builder = &stream->err; + } + if (StringListSize(&builder->lines) > LOG_THRESHOLD) { + CIflush(builder, file); } - vasprintf(StringListAppend(&builder->out), format, args); + char** line = StringListAppend(&builder->partial); + vasprintf(line, format, args); + size_t len = strlen(*line); + if (len && (*line)[len - 1] == '\n') { + char* string = _compileStringList(&builder->partial); + size_t linecount = StringListSize(&builder->lines); + if (linecount && strcmp(string, *StringListGetPointer(&builder->lines, linecount - 1)) == 0) { + ++builder->repeat; + free(string); + } else { + if (builder->repeat > 1) { + asprintf(StringListAppend(&builder->lines), "The previous message was repeated %u times.\n", builder->repeat); + } + *StringListAppend(&builder->lines) = string; + builder->repeat = 1; + } + } } #else - vprintf(format, args); + vfprintf(file, format, args); #endif +} + +ATTRIBUTE_FORMAT(printf, 2, 3) void CIlog(int minlevel, const char* format, ...) { + if (verbosity < minlevel) { + return; + } + va_list args; + va_start(args, format); + _logToStream(stdout, format, args); va_end(args); }

@@ -156,40 +206,24 @@ return;

} va_list args; va_start(args, format); -#ifdef HAVE_VASPRINTF - struct StringBuilder* builder = ThreadLocalGetValue(stringBuilder); - if (!builder) { - vfprintf(stderr, format, args); - } else { - if (StringListSize(&builder->err) > LOG_THRESHOLD) { - CIflush(&builder->err, stderr); - } - vasprintf(StringListAppend(&builder->err), format, args); - } -#else - vfprintf(stderr, format, args); -#endif + _logToStream(stderr, format, args); va_end(args); } -void CIflush(struct StringList* list, FILE* out) { - size_t len = 0; - size_t i; - for (i = 0; i < StringListSize(list); ++i) { - len += strlen(*StringListGetPointer(list, i)); +void CIflush(struct StringBuilder* builder, FILE* out) { + if (StringListSize(&builder->partial)) { + *StringListAppend(&builder->lines) = _compileStringList(&builder->partial); } - char* string = calloc(len + 1, sizeof(char)); - char* cur = string; - for (i = 0; i < StringListSize(list); ++i) { - char* brick = *StringListGetPointer(list, i); - size_t portion = strlen(brick); - memcpy(cur, brick, portion); - free(brick); - cur += portion; +#ifdef HAVE_VASPRINTF + if (builder->repeat > 1) { + asprintf(StringListAppend(&builder->lines), "The previous message was repeated %u times.\n", builder->repeat); } +#endif + + char* string = _compileStringList(&builder->lines); + builder->repeat = 0; fputs(string, out); free(string); - StringListClear(list); } static bool parseCInemaArgs(int argc, char* const* argv) {

@@ -989,10 +1023,14 @@ }

static THREAD_ENTRY CInemaJob(void* context) { struct CInemaTestList* tests = context; - struct StringBuilder builder; - StringListInit(&builder.out, 0); - StringListInit(&builder.err, 0); - ThreadLocalSetKey(stringBuilder, &builder); + struct CInemaLogStream stream; + StringListInit(&stream.out.lines, 0); + StringListInit(&stream.out.partial, 0); + stream.out.repeat = 0; + StringListInit(&stream.err.lines, 0); + StringListInit(&stream.err.partial, 0); + stream.err.repeat = 0; + ThreadLocalSetKey(logStream, &stream); bool success = true; while (true) {

@@ -1007,8 +1045,8 @@ }

if (!CInemaTask(tests, i)) { success = false; } - CIflush(&builder.out, stdout); - CIflush(&builder.err, stderr); + CIflush(&stream.out, stdout); + CIflush(&stream.err, stderr); } MutexLock(&jobMutex); if (!success) {

@@ -1016,11 +1054,13 @@ jobStatus = 1;

} MutexUnlock(&jobMutex); - CIflush(&builder.out, stdout); - StringListDeinit(&builder.out); + CIflush(&stream.out, stdout); + StringListDeinit(&stream.out.lines); + StringListDeinit(&stream.out.partial); - CIflush(&builder.err, stderr); - StringListDeinit(&builder.err); + CIflush(&stream.err, stderr); + StringListDeinit(&stream.err.lines); + StringListDeinit(&stream.err.partial); } void _log(struct mLogger* log, int category, enum mLogLevel level, const char* format, va_list args) {

@@ -1055,8 +1095,8 @@ CIerr(0, "[%s] %s\n", mLogCategoryName(category), buffer);

} int main(int argc, char** argv) { - ThreadLocalInitKey(&stringBuilder); - ThreadLocalSetKey(stringBuilder, NULL); + ThreadLocalInitKey(&logStream); + ThreadLocalSetKey(logStream, NULL); int status = 0; if (!parseCInemaArgs(argc, argv)) {