From 2c660e9d27881c3e874831af069fb83c80f3e7d2 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 3 Nov 2010 22:54:17 -0400 Subject: [PATCH] Cut-and-paste cleanup: unified the ErrorList functionality. Also removed the NULL checks from most free() calls: they make the code ugly, and the app should really do this check itself anyhow (the docs say it behaves like ANSI C's free(), which does check for this. I think.) --- mojoshader.c | 200 +++++++------------------ mojoshader.h | 2 +- mojoshader_assembler.c | 120 +++++---------- mojoshader_common.c | 147 ++++++++++++++++++ mojoshader_compiler.c | 304 ++++++++++++-------------------------- mojoshader_internal.h | 37 ++++- mojoshader_preprocessor.c | 148 +++++-------------- 7 files changed, 394 insertions(+), 564 deletions(-) diff --git a/mojoshader.c b/mojoshader.c index f7408ce0..33d6417b 100644 --- a/mojoshader.c +++ b/mojoshader.c @@ -75,6 +75,7 @@ typedef struct const VariableList *relative_array; } SourceArgInfo; +// !!! FIXME: can we get rid of this nonsense? #define SCRATCH_BUFFER_SIZE 128 #define SCRATCH_BUFFERS 32 @@ -143,7 +144,6 @@ typedef struct Context int last_address_reg_component; RegisterList used_registers; RegisterList defined_registers; - int error_count; ErrorList *errors; int constant_count; ConstantsList *constants; @@ -298,10 +298,19 @@ static inline char *StrDup(Context *ctx, const char *str) static inline void Free(Context *ctx, void *ptr) { - if (ptr != NULL) // check for NULL in case of dumb free() impl. - ctx->free(ptr, ctx->malloc_data); + ctx->free(ptr, ctx->malloc_data); } // Free +static void *MallocBridge(int bytes, void *data) +{ + return Malloc((Context *) data, (size_t) bytes); +} // MallocBridge + +static void FreeBridge(void *ptr, void *data) +{ + Free((Context *) data, ptr); +} // FreeBridge + // jump between output sections in the context... @@ -381,68 +390,28 @@ static void failf(Context *ctx, const char *fmt, ...) if (ctx->out_of_memory) return; - int error_position = 0; + int errpos = 0; switch (ctx->parse_phase) { case MOJOSHADER_PARSEPHASE_NOTSTARTED: - error_position = -2; + errpos = -2; break; case MOJOSHADER_PARSEPHASE_WORKING: - error_position = (ctx->tokens - ctx->orig_tokens) * sizeof (uint32); + errpos = (ctx->tokens - ctx->orig_tokens) * sizeof (uint32); break; case MOJOSHADER_PARSEPHASE_DONE: - error_position = -1; + errpos = -1; break; default: assert(0 && "Unexpected value"); return; } // switch - ErrorList *error = (ErrorList *) Malloc(ctx, sizeof (ErrorList)); - if (error == NULL) - return; - - char *scratch = get_scratch_buffer(ctx); + // no filename at this level (we pass a NULL to errorlist_add_va()...) va_list ap; va_start(ap, fmt); - const int len = vsnprintf(scratch, SCRATCH_BUFFER_SIZE, fmt, ap); + errorlist_add_va(ctx->errors, NULL, errpos, fmt, ap); va_end(ap); - - char *failstr = (char *) Malloc(ctx, len + 1); - if (failstr == NULL) - Free(ctx, error); - else - { - // see comments about scratch buffer overflow in output_line(). - if (len < SCRATCH_BUFFER_SIZE) - strcpy(failstr, scratch); // copy it over. - else - { - va_start(ap, fmt); - vsnprintf(failstr, len + 1, fmt, ap); // rebuild it. - va_end(ap); - } // else - - error->error.error = failstr; - error->error.filename = NULL; // no filename at this level. - error->error.error_position = error_position; - error->next = NULL; - - ErrorList *prev = NULL; - ErrorList *item = ctx->errors; - while (item != NULL) - { - prev = item; - item = item->next; - } // while - - if (prev == NULL) - ctx->errors = error; - else - prev->next = error; - - ctx->error_count++; - } // else } // failf @@ -6940,6 +6909,13 @@ static Context *build_context(const char *profile, ctx->last_address_reg_component = -1; ctx->parse_phase = MOJOSHADER_PARSEPHASE_NOTSTARTED; + ctx->errors = errorlist_create(MallocBridge, FreeBridge, ctx); + if (ctx->errors == NULL) + { + f(ctx, d); + return NULL; + } // if + const int profileid = find_profile_id(profile); ctx->profileid = profileid; if (profileid >= 0) @@ -6986,19 +6962,6 @@ static void free_variable_list(MOJOSHADER_free f, void *d, VariableList *item) } // free_variable_list -static void free_error_list(MOJOSHADER_free f, void *d, ErrorList *item) -{ - while (item != NULL) - { - ErrorList *next = item->next; - f((void *) item->error.error, d); - f((void *) item->error.filename, d); - f(item, d); - item = next; - } // while -} // free_error_list - - static void destroy_context(Context *ctx) { if (ctx != NULL) @@ -7021,7 +6984,7 @@ static void destroy_context(Context *ctx) free_reglist(f, d, ctx->attributes.next); free_reglist(f, d, ctx->samplers.next); free_variable_list(f, d, ctx->variables); - free_error_list(f, d, ctx->errors); + errorlist_destroy(ctx->errors); f(ctx, d); } // if } // destroy_context @@ -7257,31 +7220,6 @@ static MOJOSHADER_sampler *build_samplers(Context *ctx) } // build_samplers -static MOJOSHADER_error *build_errors(Context *ctx) -{ - int total = 0; - MOJOSHADER_error *retval = (MOJOSHADER_error *) - Malloc(ctx, sizeof (MOJOSHADER_error) * ctx->error_count); - if (retval == NULL) - return NULL; - - ErrorList *item = ctx->errors; - while (item != NULL) - { - ErrorList *next = item->next; - // reuse the string allocations - memcpy(&retval[total], &item->error, sizeof (MOJOSHADER_error)); - Free(ctx, item); - item = next; - total++; - } // while - ctx->errors = NULL; - - assert(total == ctx->error_count); - return retval; -} // build_errors - - static MOJOSHADER_attribute *build_attributes(Context *ctx, int *_count) { int count = 0; @@ -7390,7 +7328,8 @@ static MOJOSHADER_parseData *build_parsedata(Context *ctx) if (!isfail(ctx)) samplers = build_samplers(ctx); - errors = build_errors(ctx); + const int error_count = ctx->errors->count; + errors = errorlist_flatten(ctx->errors); if (!isfail(ctx)) { @@ -7435,12 +7374,12 @@ static MOJOSHADER_parseData *build_parsedata(Context *ctx) if (ctx->out_of_memory) { - for (i = 0; i < ctx->sampler_count; i++) + for (i = 0; i < error_count; i++) { Free(ctx, (void *) errors[i].filename); Free(ctx, (void *) errors[i].error); } // for - Free(ctx, ctx->errors); + Free(ctx, errors); Free(ctx, retval); return &MOJOSHADER_out_of_mem_data; } // if @@ -7466,7 +7405,7 @@ static MOJOSHADER_parseData *build_parsedata(Context *ctx) retval->swizzles = swizzles; } // else - retval->error_count = ctx->error_count; + retval->error_count = error_count; retval->errors = errors; retval->malloc = (ctx->malloc == MOJOSHADER_internal_malloc) ? NULL : ctx->malloc; retval->free = (ctx->free == MOJOSHADER_internal_free) ? NULL : ctx->free; @@ -7749,68 +7688,35 @@ void MOJOSHADER_freeParseData(const MOJOSHADER_parseData *_data) // we don't f(data->profile), because that's internal static data. - if (data->output != NULL) // check for NULL in case of dumb free() impl. - f((void *) data->output, d); + f((void *) data->output, d); + f((void *) data->constants, d); + f((void *) data->swizzles, d); - if (data->constants != NULL) - f((void *) data->constants, d); - - if (data->swizzles != NULL) - f((void *) data->swizzles, d); - - if (data->errors != NULL) + for (i = 0; i < data->error_count; i++) { - for (i = 0; i < data->error_count; i++) - { - if (data->errors[i].error != NULL) - f((void *) data->errors[i].error, d); - if (data->errors[i].filename != NULL) - f((void *) data->errors[i].filename, d); - } // for - f((void *) data->errors, d); - } // if + f((void *) data->errors[i].error, d); + f((void *) data->errors[i].filename, d); + } // for + f((void *) data->errors, d); - if (data->uniforms != NULL) - { - for (i = 0; i < data->uniform_count; i++) - { - if (data->uniforms[i].name != NULL) - f((void *) data->uniforms[i].name, d); - } // for - f((void *) data->uniforms, d); - } // if + for (i = 0; i < data->uniform_count; i++) + f((void *) data->uniforms[i].name, d); + f((void *) data->uniforms, d); - if (data->attributes != NULL) - { - for (i = 0; i < data->attribute_count; i++) - { - if (data->attributes[i].name != NULL) - f((void *) data->attributes[i].name, d); - } // for - f((void *) data->attributes, d); - } // if + for (i = 0; i < data->attribute_count; i++) + f((void *) data->attributes[i].name, d); + f((void *) data->attributes, d); - if (data->samplers != NULL) - { - for (i = 0; i < data->sampler_count; i++) - { - if (data->samplers[i].name != NULL) - f((void *) data->samplers[i].name, d); - } // for - f((void *) data->samplers, d); - } // if + for (i = 0; i < data->sampler_count; i++) + f((void *) data->samplers[i].name, d); + f((void *) data->samplers, d); - if (data->symbols != NULL) + for (i = 0; i < data->symbol_count; i++) { - for (i = 0; i < data->symbol_count; i++) - { - if (data->symbols[i].name != NULL) - f((void *) data->symbols[i].name, d); - if (data->symbols[i].default_value != NULL) - f((void *) data->symbols[i].default_value, d); - } // for - f((void *) data->symbols, d); - } // if + f((void *) data->symbols[i].name, d); + f((void *) data->symbols[i].default_value, d); + } // for + f((void *) data->symbols, d); f(data, d); } // MOJOSHADER_freeParseData diff --git a/mojoshader.h b/mojoshader.h index 578efbf3..caa02222 100644 --- a/mojoshader.h +++ b/mojoshader.h @@ -1521,7 +1521,7 @@ typedef struct MOJOSHADER_astData /* * This is internal data, and not for the application to touch. */ - void *strcache; + void *opaque; } MOJOSHADER_astData; diff --git a/mojoshader_assembler.c b/mojoshader_assembler.c index 8cde0e72..0fa0abb5 100644 --- a/mojoshader_assembler.c +++ b/mojoshader_assembler.c @@ -40,7 +40,6 @@ typedef struct Context MOJOSHADER_malloc malloc; MOJOSHADER_free free; void *malloc_data; - int error_count; ErrorList *errors; Preprocessor *preprocessor; MOJOSHADER_parsePhase parse_phase; @@ -90,75 +89,51 @@ static inline char *StrDup(Context *ctx, const char *str) static inline void Free(Context *ctx, void *ptr) { - if (ptr != NULL) // check for NULL in case of dumb free() impl. - ctx->free(ptr, ctx->malloc_data); + ctx->free(ptr, ctx->malloc_data); } // Free +static void *MallocBridge(int bytes, void *data) +{ + return Malloc((Context *) data, (size_t) bytes); +} // MallocBridge + +static void FreeBridge(void *ptr, void *data) +{ + Free((Context *) data, ptr); +} // FreeBridge + static void failf(Context *ctx, const char *fmt, ...) ISPRINTF(2,3); static void failf(Context *ctx, const char *fmt, ...) { const char *fname = NULL; unsigned int linenum = 0; - int error_position = 0; ctx->isfail = 1; + if (ctx->out_of_memory) + return; + int errpos = 0; switch (ctx->parse_phase) { case MOJOSHADER_PARSEPHASE_NOTSTARTED: - error_position = -2; + errpos = -2; break; case MOJOSHADER_PARSEPHASE_WORKING: fname = preprocessor_sourcepos(ctx->preprocessor, &linenum); - error_position = (int) linenum; + errpos = (int) linenum; break; case MOJOSHADER_PARSEPHASE_DONE: - error_position = -1; + errpos = -1; break; default: assert(0 && "Unexpected value"); return; } // switch - ErrorList *error = (ErrorList *) Malloc(ctx, sizeof (ErrorList)); - if (error == NULL) - return; - - char scratch = 0; va_list ap; va_start(ap, fmt); - const int len = vsnprintf(&scratch, sizeof (scratch), fmt, ap); + errorlist_add_va(ctx->errors, fname, errpos, fmt, ap); va_end(ap); - - char *failstr = (char *) Malloc(ctx, len + 1); - if (failstr == NULL) - Free(ctx, error); - else - { - va_start(ap, fmt); - vsnprintf(failstr, len + 1, fmt, ap); // rebuild it. - va_end(ap); - - error->error.error = failstr; - error->error.filename = fname ? StrDup(ctx, fname) : NULL; - error->error.error_position = error_position; - error->next = NULL; - - ErrorList *prev = NULL; - ErrorList *item = ctx->errors; - while (item != NULL) - { - prev = item; - item = item->next; - } // while - - if (prev == NULL) - ctx->errors = error; - else - prev->next = error; - - ctx->error_count++; - } // else } // failf static inline void fail(Context *ctx, const char *reason) @@ -1468,12 +1443,22 @@ static Context *build_context(const char *filename, ctx->free = f; ctx->malloc_data = d; ctx->parse_phase = MOJOSHADER_PARSEPHASE_NOTSTARTED; + + ctx->errors = errorlist_create(MallocBridge, FreeBridge, ctx); + if (ctx->errors == NULL) + { + f(ctx, d); + return NULL; + } // if + ctx->preprocessor = preprocessor_start(filename, source, sourcelen, include_open, include_close, - defines, define_count, 1, m, f, d); + defines, define_count, 1, + MallocBridge, FreeBridge, ctx); if (ctx->preprocessor == NULL) { + errorlist_destroy(ctx->errors); f(ctx, d); return NULL; } // if @@ -1482,26 +1467,14 @@ static Context *build_context(const char *filename, } // build_context -static void free_error_list(MOJOSHADER_free f, void *d, ErrorList *item) -{ - while (item != NULL) - { - ErrorList *next = item->next; - f((void *) item->error.error, d); - f((void *) item->error.filename, d); - f(item, d); - item = next; - } // while -} // free_error_list - - static void destroy_context(Context *ctx) { if (ctx != NULL) { MOJOSHADER_free f = ((ctx->free != NULL) ? ctx->free : MOJOSHADER_internal_free); void *d = ctx->malloc_data; - free_error_list(f, d, ctx->errors); + if (ctx->errors != NULL) + errorlist_destroy(ctx->errors); if (ctx->preprocessor != NULL) preprocessor_end(ctx->preprocessor); if (ctx->output != NULL) @@ -1515,31 +1488,6 @@ static void destroy_context(Context *ctx) } // destroy_context -static MOJOSHADER_error *build_errors(Context *ctx) -{ - int total = 0; - MOJOSHADER_error *retval = (MOJOSHADER_error *) - Malloc(ctx, sizeof (MOJOSHADER_error) * ctx->error_count); - if (retval == NULL) - return NULL; - - ErrorList *item = ctx->errors; - while (item != NULL) - { - ErrorList *next = item->next; - // reuse the string allocations - memcpy(&retval[total], &item->error, sizeof (MOJOSHADER_error)); - Free(ctx, item); - item = next; - total++; - } // while - ctx->errors = NULL; - - assert(total == ctx->error_count); - return retval; -} // build_errors - - static const MOJOSHADER_parseData *build_failed_assembly(Context *ctx) { assert(isfail(ctx)); @@ -1557,9 +1505,9 @@ static const MOJOSHADER_parseData *build_failed_assembly(Context *ctx) retval->free = (ctx->free == MOJOSHADER_internal_free) ? NULL : ctx->free; retval->malloc_data = ctx->malloc_data; - retval->error_count = ctx->error_count; - retval->errors = build_errors(ctx); - if ((retval->errors == NULL) && (ctx->error_count > 0)) + retval->error_count = ctx->errors->count; + retval->errors = errorlist_flatten(ctx->errors); + if (ctx->out_of_memory) { Free(ctx, retval); return &MOJOSHADER_out_of_mem_data; diff --git a/mojoshader_common.c b/mojoshader_common.c index 16d4baa2..313937bd 100644 --- a/mojoshader_common.c +++ b/mojoshader_common.c @@ -365,6 +365,9 @@ StringCache *stringcache_create(MOJOSHADER_malloc m, MOJOSHADER_free f, void *d) void stringcache_destroy(StringCache *cache) { + if (cache == NULL) + return; + MOJOSHADER_free f = cache->f; void *d = cache->d; size_t i; @@ -386,5 +389,149 @@ void stringcache_destroy(StringCache *cache) f(cache, d); } // stringcache_destroy + + +ErrorList *errorlist_create(MOJOSHADER_malloc m, MOJOSHADER_free f, void *d) +{ + ErrorList *retval = (ErrorList *) m(sizeof (ErrorList), d); + if (retval != NULL) + { + memset(retval, '\0', sizeof (ErrorList)); + retval->tail = &retval->head; + retval->m = m; + retval->f = f; + retval->d = d; + } // if + + return retval; +} // errorlist_create + + +int errorlist_add(ErrorList *list, const char *fname, + const int errpos, const char *str) +{ + return errorlist_add_fmt(list, fname, errpos, "%s", str); +} // errorlist_add + + +int errorlist_add_fmt(ErrorList *list, const char *fname, + const int errpos, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + const int retval = errorlist_add_va(list, fname, errpos, fmt, ap); + va_end(ap); + return retval; +} // errorlist_add_fmt + + +int errorlist_add_va(ErrorList *list, const char *_fname, + const int errpos, const char *fmt, va_list va) +{ + ErrorItem *error = (ErrorItem *) list->m(sizeof (ErrorItem), list->d); + if (error == NULL) + return 0; + + char *fname = NULL; + if (_fname != NULL) + { + fname = (char *) list->m(strlen(_fname) + 1, list->d); + if (fname == NULL) + { + list->f(error, list->d); + return 0; + } // if + strcpy(fname, _fname); + } // if + + char scratch[128]; + va_list ap; + va_copy(ap, va); + const int len = vsnprintf(scratch, sizeof (scratch), fmt, ap); + va_end(ap); + + char *failstr = (char *) list->m(len + 1, list->d); + if (failstr == NULL) + { + list->f(error, list->d); + list->f(fname, list->d); + return 0; + } // if + + // If we overflowed our scratch buffer, that's okay. We were going to + // allocate anyhow...the scratch buffer just lets us avoid a second + // run of vsnprintf(). + if (len < sizeof (scratch)) + strcpy(failstr, scratch); // copy it over. + else + { + va_copy(ap, va); + vsnprintf(failstr, len + 1, fmt, ap); // rebuild it. + va_end(ap); + } // else + + error->error.error = failstr; + error->error.filename = fname; + error->error.error_position = errpos; + error->next = NULL; + + list->tail->next = error; + list->tail = error; + + list->count++; + return 1; +} // errorlist_add_va + + +MOJOSHADER_error *errorlist_flatten(ErrorList *list) +{ + if (list->count == 0) + return NULL; + + int total = 0; + MOJOSHADER_error *retval = (MOJOSHADER_error *) + list->m(sizeof (MOJOSHADER_error) * list->count, list->d); + if (retval == NULL) + return NULL; + + ErrorItem *item = list->head.next; + while (item != NULL) + { + ErrorItem *next = item->next; + // reuse the string allocations + memcpy(&retval[total], &item->error, sizeof (MOJOSHADER_error)); + list->f(item, list->d); + item = next; + total++; + } // while + + assert(total == list->count); + list->count = 0; + list->head.next = NULL; + list->tail = &list->head; + return retval; +} // errorlist_flatten + + +void errorlist_destroy(ErrorList *list) +{ + if (list == NULL) + return; + + MOJOSHADER_free f = list->f; + void *d = list->d; + ErrorItem *item = list->head.next; + while (item != NULL) + { + ErrorItem *next = item->next; + f((void *) item->error.error, d); + f((void *) item->error.filename, d); + f(item, d); + item = next; + } // while + f(list, d); +} // errorlist_destroy + + // end of mojoshader_common.c ... diff --git a/mojoshader_compiler.c b/mojoshader_compiler.c index f0dde777..f66eaacf 100644 --- a/mojoshader_compiler.c +++ b/mojoshader_compiler.c @@ -86,9 +86,7 @@ typedef struct Context MOJOSHADER_malloc malloc; MOJOSHADER_free free; void *malloc_data; - int error_count; ErrorList *errors; - int warning_count; ErrorList *warnings; StringCache *strcache; const char *sourcefile; // current source file that we're parsing. @@ -150,63 +148,30 @@ static inline char *StrDup(Context *ctx, const char *str) static inline void Free(Context *ctx, void *ptr) { - if (ptr != NULL) // check for NULL in case of dumb free() impl. - ctx->free(ptr, ctx->malloc_data); + ctx->free(ptr, ctx->malloc_data); } // Free +static void *MallocBridge(int bytes, void *data) +{ + return Malloc((Context *) data, (size_t) bytes); +} // MallocBridge + +static void FreeBridge(void *ptr, void *data) +{ + Free((Context *) data, ptr); +} // FreeBridge + static void failf(Context *ctx, const char *fmt, ...) ISPRINTF(2,3); static void failf(Context *ctx, const char *fmt, ...) { - const char *fname = ctx->sourcefile; - const unsigned int error_position = ctx->sourceline; - ctx->isfail = 1; - - const int MAX_ERROR_COUNT = 128; - if (ctx->error_count == (MAX_ERROR_COUNT-1)) - fmt = "Too many errors, not reporting any more."; - else if (ctx->error_count >= MAX_ERROR_COUNT) - return; - - ErrorList *error = (ErrorList *) Malloc(ctx, sizeof (ErrorList)); - if (error == NULL) + if (ctx->out_of_memory) return; - char scratch = 0; va_list ap; va_start(ap, fmt); - const int len = vsnprintf(&scratch, sizeof (scratch), fmt, ap); + errorlist_add_va(ctx->errors, ctx->sourcefile, ctx->sourceline, fmt, ap); va_end(ap); - - char *failstr = (char *) Malloc(ctx, len + 1); - if (failstr == NULL) - Free(ctx, error); - else - { - va_start(ap, fmt); - vsnprintf(failstr, len + 1, fmt, ap); // rebuild it. - va_end(ap); - - error->error.error = failstr; - error->error.filename = fname ? StrDup(ctx, fname) : NULL; - error->error.error_position = error_position; - error->next = NULL; - - ErrorList *prev = NULL; - ErrorList *item = ctx->errors; - while (item != NULL) - { - prev = item; - item = item->next; - } // while - - if (prev == NULL) - ctx->errors = error; - else - prev->next = error; - - ctx->error_count++; - } // else } // failf static inline void fail(Context *ctx, const char *reason) @@ -214,6 +179,23 @@ static inline void fail(Context *ctx, const char *reason) failf(ctx, "%s", reason); } // fail +static void warnf(Context *ctx, const char *fmt, ...) ISPRINTF(2,3); +static void warnf(Context *ctx, const char *fmt, ...) +{ + if (ctx->out_of_memory) + return; + + va_list ap; + va_start(ap, fmt); + errorlist_add_va(ctx->warnings, ctx->sourcefile, ctx->sourceline, fmt, ap); + va_end(ap); +} // warnf + +static inline void warn(Context *ctx, const char *reason) +{ + warnf(ctx, "%s", reason); +} // warn + static inline int isfail(const Context *ctx) { return ctx->isfail; @@ -227,15 +209,8 @@ static int create_symbolmap(Context *ctx, SymbolMap *map) // !!! FIXME: should compare string pointer, with string in cache. map->scope = NULL; map->hash = hash_create(ctx, hash_hash_string, hash_keymatch_string, - symbolmap_nuke, 1, ctx->malloc, ctx->free, - ctx->malloc_data); - if (!map->hash) - { - out_of_memory(ctx); - return 0; - } // if - - return 1; + symbolmap_nuke, 1, MallocBridge, FreeBridge, ctx); + return (map->hash != NULL); } // create_symbolmap @@ -2164,13 +2139,12 @@ static void destroy_context(Context *ctx) MOJOSHADER_free f = ((ctx->free != NULL) ? ctx->free : MOJOSHADER_internal_free); void *d = ctx->malloc_data; - // !!! FIXME: free ctx->errors delete_compilation_unit(ctx, (MOJOSHADER_astCompilationUnit*)ctx->ast); destroy_symbolmap(ctx, &ctx->usertypes); destroy_symbolmap(ctx, &ctx->variables); - - if (ctx->strcache) - stringcache_destroy(ctx->strcache); + stringcache_destroy(ctx->strcache); + errorlist_destroy(ctx->errors); + errorlist_destroy(ctx->warnings); // !!! FIXME: more to clean up here, now. @@ -2194,7 +2168,9 @@ static Context *build_context(MOJOSHADER_malloc m, MOJOSHADER_free f, void *d) //ctx->parse_phase = MOJOSHADER_PARSEPHASE_NOTSTARTED; create_symbolmap(ctx, &ctx->usertypes); // !!! FIXME: check for failure. create_symbolmap(ctx, &ctx->variables); // !!! FIXME: check for failure. - ctx->strcache = stringcache_create(m, f, d); // !!! FIXME: check for failure. + ctx->strcache = stringcache_create(MallocBridge, FreeBridge, ctx); // !!! FIXME: check for failure. + ctx->errors = errorlist_create(MallocBridge, FreeBridge, ctx); // !!! FIXME: check for failure. + ctx->warnings = errorlist_create(MallocBridge, FreeBridge, ctx); // !!! FIXME: check for failure. // fill in some common strings we'll want to use without further hashing. ctx->str_b = stringcache(ctx->strcache, "b"); @@ -2242,7 +2218,7 @@ static void parse_source(Context *ctx, const char *filename, pp = preprocessor_start(filename, source, sourcelen, include_open, include_close, defines, define_count, 0, - ctx->malloc, ctx->free, ctx->malloc_data); + MallocBridge, FreeBridge, ctx); // !!! FIXME: check if (pp == NULL)... @@ -2282,11 +2258,8 @@ static void parse_source(Context *ctx, const char *filename, do { token = preprocessor_nexttoken(pp, &tokenlen, &tokenval); - if (preprocessor_outofmemory(pp)) - { - out_of_memory(ctx); + if (ctx->out_of_memory) break; - } // if fname = preprocessor_sourcepos(pp, &ctx->sourceline); ctx->sourcefile = fname ? stringcache(ctx->strcache, fname) : 0; @@ -2368,33 +2341,6 @@ static MOJOSHADER_astData MOJOSHADER_out_of_mem_ast_data = { 1, &MOJOSHADER_out_of_mem_error, 0, 0, 0, 0, 0, 0 }; -// !!! FIXME: cut and paste from assembler. -// !!! FIXME: make ErrorList into something with a head/tail and count -// !!! FIXME: inherent. -static MOJOSHADER_error *build_errors(Context *ctx, ErrorList **list, const int count) -{ - int total = 0; - MOJOSHADER_error *retval = (MOJOSHADER_error *) - Malloc(ctx, sizeof (MOJOSHADER_error) * count); - if (retval == NULL) - return NULL; - - ErrorList *item = *list; - while (item != NULL) - { - ErrorList *next = item->next; - // reuse the string allocations - memcpy(&retval[total], &item->error, sizeof (MOJOSHADER_error)); - Free(ctx, item); - item = next; - total++; - } // while - *list = NULL; - - assert(total == count); - return retval; -} // build_errors - // !!! FIXME: cut and paste from assembler. static const MOJOSHADER_astData *build_failed_ast(Context *ctx) @@ -2414,10 +2360,10 @@ static const MOJOSHADER_astData *build_failed_ast(Context *ctx) retval->malloc = (ctx->malloc == MOJOSHADER_internal_malloc) ? NULL : ctx->malloc; retval->free = (ctx->free == MOJOSHADER_internal_free) ? NULL : ctx->free; retval->malloc_data = ctx->malloc_data; + retval->error_count = ctx->errors->count; + retval->errors = errorlist_flatten(ctx->errors); - retval->error_count = ctx->error_count; - retval->errors = build_errors(ctx, &ctx->errors, ctx->error_count); - if ((retval->errors == NULL) && (ctx->error_count > 0)) + if (ctx->out_of_memory) { Free(ctx, retval); return &MOJOSHADER_out_of_mem_ast_data; @@ -2439,28 +2385,25 @@ static const MOJOSHADER_astData *build_astdata(Context *ctx) return &MOJOSHADER_out_of_mem_ast_data; memset(retval, '\0', sizeof (MOJOSHADER_astData)); + retval->malloc = (ctx->malloc == MOJOSHADER_internal_malloc) ? NULL : ctx->malloc; + retval->free = (ctx->free == MOJOSHADER_internal_free) ? NULL : ctx->free; + retval->malloc_data = ctx->malloc_data; if (!isfail(ctx)) { retval->source_profile = ctx->source_profile; retval->ast = ctx->ast; - ctx->ast = NULL; // don't free this with the context, now. } // if - retval->error_count = ctx->error_count; - retval->errors = build_errors(ctx, &ctx->errors, ctx->error_count); - if (retval->errors == NULL) + retval->error_count = ctx->errors->count; + retval->errors = errorlist_flatten(ctx->errors); + if (ctx->out_of_memory) { Free(ctx, retval); return &MOJOSHADER_out_of_mem_ast_data; } // if - retval->malloc = (ctx->malloc == MOJOSHADER_internal_malloc) ? NULL : ctx->malloc; - retval->free = (ctx->free == MOJOSHADER_internal_free) ? NULL : ctx->free; - retval->malloc_data = ctx->malloc_data; - - retval->strcache = ctx->strcache; - ctx->strcache = NULL; + retval->opaque = ctx; return retval; } // build_astdata @@ -2501,9 +2444,6 @@ static const MOJOSHADER_compileData *build_failed_compile(Context *ctx) { assert(isfail(ctx)); - if (ctx->out_of_memory) - return &MOJOSHADER_out_of_mem_compile_data; - MOJOSHADER_compileData *retval = NULL; retval = (MOJOSHADER_compileData *) Malloc(ctx, sizeof (MOJOSHADER_compileData)); if (retval == NULL) @@ -2513,20 +2453,13 @@ static const MOJOSHADER_compileData *build_failed_compile(Context *ctx) retval->malloc = (ctx->malloc == MOJOSHADER_internal_malloc) ? NULL : ctx->malloc; retval->free = (ctx->free == MOJOSHADER_internal_free) ? NULL : ctx->free; retval->malloc_data = ctx->malloc_data; - retval->source_profile = ctx->source_profile; + retval->error_count = ctx->errors->count; + retval->errors = errorlist_flatten(ctx->errors); + retval->warning_count = ctx->warnings->count; + retval->warnings = errorlist_flatten(ctx->warnings); - retval->error_count = ctx->error_count; - retval->errors = build_errors(ctx, &ctx->errors, ctx->error_count); - if ((retval->errors == NULL) && (retval->error_count > 0)) - { - MOJOSHADER_freeCompileData(retval); - return &MOJOSHADER_out_of_mem_compile_data; - } // if - - retval->warning_count = ctx->warning_count; - retval->warnings = build_errors(ctx, &ctx->warnings, ctx->warning_count); - if ((retval->warnings == NULL) && (retval->warning_count > 0)) + if (ctx->out_of_memory) // in case something failed up there. { MOJOSHADER_freeCompileData(retval); return &MOJOSHADER_out_of_mem_compile_data; @@ -2538,10 +2471,9 @@ static const MOJOSHADER_compileData *build_failed_compile(Context *ctx) static const MOJOSHADER_compileData *build_compiledata(Context *ctx) { - MOJOSHADER_compileData *retval = NULL; + assert(!isfail(ctx)); - if (ctx->out_of_memory) - return &MOJOSHADER_out_of_mem_compile_data; + MOJOSHADER_compileData *retval = NULL; retval = (MOJOSHADER_compileData *) Malloc(ctx, sizeof (MOJOSHADER_compileData)); if (retval == NULL) @@ -2551,7 +2483,6 @@ static const MOJOSHADER_compileData *build_compiledata(Context *ctx) retval->malloc = (ctx->malloc == MOJOSHADER_internal_malloc) ? NULL : ctx->malloc; retval->free = (ctx->free == MOJOSHADER_internal_free) ? NULL : ctx->free; retval->malloc_data = ctx->malloc_data; - retval->source_profile = ctx->source_profile; if (!isfail(ctx)) @@ -2564,26 +2495,15 @@ static const MOJOSHADER_compileData *build_compiledata(Context *ctx) // !!! FIXME: build symbols and symbol_count here. } // if - if (!isfail(ctx)) - { - retval->error_count = ctx->error_count; - retval->errors = build_errors(ctx, &ctx->errors, ctx->error_count); - if ((retval->errors == NULL) && (retval->error_count > 0)) - { - MOJOSHADER_freeCompileData(retval); - return &MOJOSHADER_out_of_mem_compile_data; - } // if - } // if + retval->error_count = ctx->errors->count; + retval->errors = errorlist_flatten(ctx->errors); + retval->warning_count = ctx->warnings->count; + retval->warnings = errorlist_flatten(ctx->warnings); - if (!isfail(ctx)) + if (ctx->out_of_memory) // in case something failed up there. { - retval->warning_count = ctx->warning_count; - retval->warnings = build_errors(ctx, &ctx->warnings, ctx->warning_count); - if ((retval->warnings == NULL) && (retval->warning_count > 0)) - { - MOJOSHADER_freeCompileData(retval); - return &MOJOSHADER_out_of_mem_compile_data; - } // if + MOJOSHADER_freeCompileData(retval); + return &MOJOSHADER_out_of_mem_compile_data; } // if return retval; @@ -2621,12 +2541,14 @@ const MOJOSHADER_astData *MOJOSHADER_parseAst(const char *srcprofile, include_open, include_close); } // if - if (isfail(ctx)) - retval = (MOJOSHADER_astData *) build_failed_ast(ctx); + if (!isfail(ctx)) + retval = build_astdata(ctx); // ctx isn't destroyed yet! else - retval = build_astdata(ctx); + { + retval = (MOJOSHADER_astData *) build_failed_ast(ctx); + destroy_context(ctx); + } // else - destroy_context(ctx); return retval; } // MOJOSHADER_parseAst @@ -2637,41 +2559,25 @@ void MOJOSHADER_freeAstData(const MOJOSHADER_astData *_data) if ((data == NULL) || (data == &MOJOSHADER_out_of_mem_ast_data)) return; // no-op. + // !!! FIXME: this needs to live for deleting the stringcache and the ast. + Context *ctx = (Context *) data->opaque; MOJOSHADER_free f = (data->free == NULL) ? MOJOSHADER_internal_free : data->free; void *d = data->malloc_data; int i; // we don't f(data->source_profile), because that's internal static data. - // check for NULL in case of dumb free() impl. - if (data->errors != NULL) + for (i = 0; i < data->error_count; i++) { - for (i = 0; i < data->error_count; i++) - { - if (data->errors[i].error != NULL) - f((void *) data->errors[i].error, d); - if (data->errors[i].filename != NULL) - f((void *) data->errors[i].filename, d); - } // for - f((void *) data->errors, d); - } // if - - if (data->ast != NULL) - { - // !!! FIXME: make this not require a Context. - Context ctx; - memset(&ctx, '\0', sizeof (Context)); - ctx.malloc = data->malloc; - ctx.free = f; - ctx.malloc_data = d; - delete_compilation_unit(&ctx, - (MOJOSHADER_astCompilationUnit *) &data->ast->compunit); - } // if - - if (data->strcache != NULL) - stringcache_destroy((StringCache *) data->strcache); + f((void *) data->errors[i].error, d); + f((void *) data->errors[i].filename, d); + } // for + f((void *) data->errors, d); + // don't delete data->ast (it'll delete with the context). f(data, d); + + destroy_context(ctx); // finally safe to destroy this. } // MOJOSHADER_freeAstData @@ -2729,46 +2635,28 @@ void MOJOSHADER_freeCompileData(const MOJOSHADER_compileData *_data) // we don't f(data->source_profile), because that's internal static data. - // check for NULL in case of dumb free() impl. - if (data->errors != NULL) + for (i = 0; i < data->error_count; i++) { - for (i = 0; i < data->error_count; i++) - { - if (data->errors[i].error != NULL) - f((void *) data->errors[i].error, d); - if (data->errors[i].filename != NULL) - f((void *) data->errors[i].filename, d); - } // for - f((void *) data->errors, d); - } // if + f((void *) data->errors[i].error, d); + f((void *) data->errors[i].filename, d); + } // for + f((void *) data->errors, d); - if (data->warnings != NULL) + for (i = 0; i < data->warning_count; i++) { - for (i = 0; i < data->warning_count; i++) - { - if (data->warnings[i].error != NULL) - f((void *) data->warnings[i].error, d); - if (data->warnings[i].filename != NULL) - f((void *) data->warnings[i].filename, d); - } // for - f((void *) data->warnings, d); - } // if + f((void *) data->warnings[i].error, d); + f((void *) data->warnings[i].filename, d); + } // for + f((void *) data->warnings, d); - if (data->symbols != NULL) + for (i = 0; i < data->symbol_count; i++) { - for (i = 0; i < data->symbol_count; i++) - { - if (data->symbols[i].name != NULL) - f((void *) data->symbols[i].name, d); - if (data->symbols[i].default_value != NULL) - f((void *) data->symbols[i].default_value, d); - } // for - f((void *) data->symbols, d); - } // if - - if (data->output != NULL) - f((void *) data->output, d); + f((void *) data->symbols[i].name, d); + f((void *) data->symbols[i].default_value, d); + } // for + f((void *) data->symbols, d); + f((void *) data->output, d); f(data, d); } // MOJOSHADER_freeCompileData diff --git a/mojoshader_internal.h b/mojoshader_internal.h index 3ce2afdb..89a3f631 100644 --- a/mojoshader_internal.h +++ b/mojoshader_internal.h @@ -83,6 +83,7 @@ typedef unsigned int uint; // this is a printf() helper. don't use for code. #ifdef _MSC_VER #include +#define va_copy(a, b) a = b #define snprintf _snprintf #define strcasecmp stricmp typedef unsigned __int8 uint8; @@ -193,6 +194,35 @@ const char *stringcache_fmt(StringCache *cache, const char *fmt, ...); void stringcache_destroy(StringCache *cache); +// We chain errors as a linked list with a head/tail for easy appending. +// These get flattened before passing to the application. +typedef struct ErrorItem +{ + MOJOSHADER_error error; + struct ErrorItem *next; +} ErrorItem; + +typedef struct ErrorList +{ + ErrorItem head; + ErrorItem *tail; + int count; + MOJOSHADER_malloc m; + MOJOSHADER_free f; + void *d; +} ErrorList; + +ErrorList *errorlist_create(MOJOSHADER_malloc m, MOJOSHADER_free f, void *d); +int errorlist_add(ErrorList *list, const char *fname, + const int errpos, const char *str); +int errorlist_add_fmt(ErrorList *list, const char *fname, + const int errpos, const char *fmt, ...) ISPRINTF(4,5); +int errorlist_add_va(ErrorList *list, const char *_fname, + const int errpos, const char *fmt, va_list va); +MOJOSHADER_error *errorlist_flatten(ErrorList *list); // resets the list! +void errorlist_destroy(ErrorList *list); + + // This is the ID for a D3DXSHADER_CONSTANTTABLE in the bytecode comments. #define CTAB_ID 0x42415443 // 0x42415443 == 'CTAB' #define CTAB_SIZE 28 // sizeof (D3DXSHADER_CONSTANTTABLE). @@ -367,13 +397,6 @@ typedef enum extern MOJOSHADER_error MOJOSHADER_out_of_mem_error; extern MOJOSHADER_parseData MOJOSHADER_out_of_mem_data; -// !!! FIXME: unify all the routines in various modules that deal with these. -typedef struct ErrorList -{ - MOJOSHADER_error error; - struct ErrorList *next; -} ErrorList; - // preprocessor stuff. diff --git a/mojoshader_preprocessor.c b/mojoshader_preprocessor.c index 1757e8b2..d497077c 100644 --- a/mojoshader_preprocessor.c +++ b/mojoshader_preprocessor.c @@ -78,8 +78,7 @@ static inline void *Malloc(Context *ctx, const size_t len) static inline void Free(Context *ctx, void *ptr) { - if (ptr != NULL) // check for NULL in case of dumb free() impl. - ctx->free(ptr, ctx->malloc_data); + ctx->free(ptr, ctx->malloc_data); } // Free static inline char *StrDup(Context *ctx, const char *str) @@ -2253,47 +2252,6 @@ const char *preprocessor_sourcepos(Preprocessor *_ctx, unsigned int *pos) } // preprocessor_sourcepos -// !!! FIXME: cut and paste. -static void free_error_list(ErrorList *item, MOJOSHADER_free f, void *d) -{ - while (item != NULL) - { - ErrorList *next = item->next; - f((void *) item->error.error, d); - f((void *) item->error.filename, d); - f(item, d); - item = next; - } // while -} // free_error_list - - -// !!! FIXME: cut and paste. -static MOJOSHADER_error *build_errors(ErrorList **errors, const int count, - MOJOSHADER_malloc m, MOJOSHADER_free f, void *d) -{ - int total = 0; - MOJOSHADER_error *retval = (MOJOSHADER_error *) - m(sizeof (MOJOSHADER_error) * count, d); - if (retval == NULL) - return NULL; - - ErrorList *item = *errors; - while (item != NULL) - { - ErrorList *next = item->next; - // reuse the string allocations - memcpy(&retval[total], &item->error, sizeof (MOJOSHADER_error)); - f(item, d); - item = next; - total++; - } // while - *errors = NULL; - - assert(total == count); - return retval; -} // build_errors - - static int indent_buffer(Buffer *buffer, int n, int newline, MOJOSHADER_malloc m, void *d) { @@ -2336,23 +2294,24 @@ const MOJOSHADER_preprocessData *MOJOSHADER_preprocess(const char *filename, static const char endline[] = { '\n' }; #endif - ErrorList *errors = NULL; - int error_count = 0; - if (!m) m = MOJOSHADER_internal_malloc; if (!f) f = MOJOSHADER_internal_free; - -#if !MOJOSHADER_FORCE_INCLUDE_CALLBACKS if (!include_open) include_open = MOJOSHADER_internal_include_open; if (!include_close) include_close = MOJOSHADER_internal_include_close; -#endif + + ErrorList *errors = errorlist_create(m, f, d); + if (errors == NULL) + return &out_of_mem_data_preprocessor; Preprocessor *pp = preprocessor_start(filename, source, sourcelen, include_open, include_close, defines, define_count, 0, m, f, d); if (pp == NULL) + { + errorlist_destroy(errors); return &out_of_mem_data_preprocessor; + } // if Token token = TOKEN_UNKNOWN; const char *tokstr = NULL; @@ -2421,51 +2380,10 @@ const MOJOSHADER_preprocessData *MOJOSHADER_preprocess(const char *filename, { if (!out_of_memory) { - ErrorList *error = (ErrorList *) m(sizeof (ErrorList), d); unsigned int pos = 0; - char *fname = NULL; - const char *str = preprocessor_sourcepos(pp, &pos); - if (str != NULL) - { - fname = (char *) m(strlen(str) + 1, d); - if (fname != NULL) - strcpy(fname, str); - } // if - - // !!! FIXME: cut and paste with other error handlers. - char *errstr = (char *) m(len + 1, d); - if (errstr != NULL) - strcpy(errstr, tokstr); - - out_of_memory = ((!error) || ((!fname) && (str)) || (!errstr)); - if (out_of_memory) - { - if (errstr) f(errstr, d); - if (fname) f(fname, d); - if (error) f(error, d); - } // if - else - { - error->error.error = errstr; - error->error.filename = fname; - error->error.error_position = pos; - error->next = NULL; - - ErrorList *prev = NULL; - ErrorList *item = errors; - while (item != NULL) - { - prev = item; - item = item->next; - } // while - - if (prev == NULL) - errors = error; - else - prev->next = error; - - error_count++; - } // else + const char *fname = preprocessor_sourcepos(pp, &pos); + if (!errorlist_add(errors, fname, (int) pos, tokstr)) + out_of_memory = 1; } // if } // else if @@ -2485,7 +2403,7 @@ const MOJOSHADER_preprocessData *MOJOSHADER_preprocess(const char *filename, { preprocessor_end(pp); free_buffer(&buffer, f, d); - free_error_list(errors, f, d); + errorlist_destroy(errors); return &out_of_mem_data_preprocessor; } // if } // while @@ -2499,7 +2417,7 @@ const MOJOSHADER_preprocessData *MOJOSHADER_preprocess(const char *filename, free_buffer(&buffer, f, d); if (output == NULL) { - free_error_list(errors, f, d); + errorlist_destroy(errors); return &out_of_mem_data_preprocessor; } // if @@ -2507,21 +2425,27 @@ const MOJOSHADER_preprocessData *MOJOSHADER_preprocess(const char *filename, m(sizeof (MOJOSHADER_preprocessData), d); if (retval == NULL) { - free_error_list(errors, f, d); + errorlist_destroy(errors); f(output, d); return &out_of_mem_data_preprocessor; } // if - retval->errors = build_errors(&errors, error_count, m, f, d); - if (retval->errors == NULL) + memset(retval, '\0', sizeof (*retval)); + if (errors->count > 0) { - free_error_list(errors, f, d); - f(retval, d); - f(output, d); - return &out_of_mem_data_preprocessor; + retval->error_count = errors->count; + retval->errors = errorlist_flatten(errors); + if (retval->errors == NULL) + { + errorlist_destroy(errors); + f(retval, d); + f(output, d); + return &out_of_mem_data_preprocessor; + } // if } // if - retval->error_count = error_count; + errorlist_destroy(errors); + retval->output = output; retval->output_len = total_bytes; retval->malloc = m; @@ -2541,20 +2465,14 @@ void MOJOSHADER_freePreprocessData(const MOJOSHADER_preprocessData *_data) void *d = data->malloc_data; int i; - if (data->output != NULL) - f((void *) data->output, d); + f((void *) data->output, d); - if (data->errors != NULL) + for (i = 0; i < data->error_count; i++) { - for (i = 0; i < data->error_count; i++) - { - if (data->errors[i].error != NULL) - f((void *) data->errors[i].error, d); - if (data->errors[i].filename != NULL) - f((void *) data->errors[i].filename, d); - } // for - f(data->errors, d); - } // if + f((void *) data->errors[i].error, d); + f((void *) data->errors[i].filename, d); + } // for + f(data->errors, d); f(data, d); } // MOJOSHADER_freePreprocessData