// strip.c -- Release build stripping // // Removes debug information from a compiled module: // - Clears debug variable info (names, scopes, types) // - Clears debug UDT definitions // - Mangles procedure names that aren't needed for runtime dispatch. // The form runtime dispatches events by name (Control_Event pattern) // and SetEvent looks up handlers by name at runtime, so those proc // names must be preserved. Everything else becomes F1, F2, F3... // // OP_LINE removal is deferred to a future version (requires // bytecode compaction and offset rewriting). #include "strip.h" #include "../runtime/values.h" #include #include #include // Events fired by name via basFormRtFireEvent* in formrt.c. Any proc // ending in "_" must keep its name so the dispatcher can // find it. static const char *sEventSuffixes[] = { "Load", "Unload", "QueryUnload", "Resize", "Activate", "Deactivate", "Click", "DblClick", "Change", "Timer", "GotFocus", "LostFocus", "KeyPress", "KeyDown", "KeyUp", "MouseDown", "MouseUp", "MouseMove", "Scroll", "Reposition", "Validate", NULL }; static bool nameEndsWithEventSuffix(const char *name) { const char *underscore = strrchr(name, '_'); if (!underscore) { return false; } const char *suffix = underscore + 1; for (int32_t i = 0; sEventSuffixes[i]; i++) { if (strcasecmp(suffix, sEventSuffixes[i]) == 0) { return true; } } return false; } static bool nameInConstantPool(const BasModuleT *mod, const char *name) { for (int32_t i = 0; i < mod->constCount; i++) { const BasStringT *s = mod->constants[i]; if (s && strcasecmp(s->data, name) == 0) { return true; } } return false; } void basStripModule(BasModuleT *mod) { if (!mod) { return; } // Clear debug variable info free(mod->debugVars); mod->debugVars = NULL; mod->debugVarCount = 0; // Clear debug UDT definitions if (mod->debugUdtDefs) { for (int32_t i = 0; i < mod->debugUdtDefCount; i++) { free(mod->debugUdtDefs[i].fields); } free(mod->debugUdtDefs); mod->debugUdtDefs = NULL; mod->debugUdtDefCount = 0; } // Mangle proc names. Keep names that are needed for runtime name // lookup: event handlers (Control_Event pattern) and any name // referenced as a string constant (e.g. SetEvent's target name). int32_t nextMangled = 1; for (int32_t i = 0; i < mod->procCount; i++) { BasProcEntryT *proc = &mod->procs[i]; if (proc->name[0] == '\0') { continue; } if (nameEndsWithEventSuffix(proc->name)) { continue; } if (nameInConstantPool(mod, proc->name)) { continue; } snprintf(proc->name, sizeof(proc->name), "F%ld", (long)nextMangled++); } }