home *** CD-ROM | disk | FTP | other *** search
-
- /* pinpatch.c */
-
- #include <stdio.h>
- #include <stdarg.h>
- #include "OS:os.h"
- #include "OS:osmodule.h"
- #include "OS:wimp.h"
-
- #ifdef MemCheck_MEMCHECK
- #include "MemCheck:MemCheck.h"
- #endif
-
- #include "pinpatch.h"
- #include "options.h"
-
-
- #define PREFIX "PinPatch: "
-
- typedef struct patch_state patch_state;
- struct patch_state {
- char *module;
- int module_size;
- bool verbose;
- };
-
- static void patch_location(patch_state *info, char *patch,
- unsigned old, unsigned new, ...);
-
- char versions[][] = {
- "Unknown Pinboard version",
- "Pin 0.50/OS 3.1",
- "Pin 0.61/OS 3.5",
- "Pin 0.66/OS 3.7",
- };
- #define VERSION_310 1
- #define VERSION_350 2
- #define VERSION_370 3
-
-
- /* Patches the Pinboard module according to the options given. */
- void patch_pinboard(const thiniconbar_options *options, int verbose)
- {
- patch_state info;
- if(!options->patch_pinboard) return;
- info.verbose = verbose;
-
- if(info.verbose) printf(PREFIX "Beginning...\n");
-
- /* Find out where the module is, and ensure that it is in RAM. */
- {
- int rma_size;
- char *rma;
- osmodule_lookup("Pinboard", 0, (byte **) &info.module, 0, 0);
- rma = (char *) os_read_dynamic_area(os_DYNAMIC_AREA_RMA, &rma_size, 0);
- if(info.module < rma || info.module >= (rma + rma_size)) {
- /* Pinboard is outside module area, ie. in ROM still. So: */
- os_cli("RMFaster Pinboard");
- /* The module has moved, so read its location again. */
- osmodule_lookup("Pinboard", 0, (byte **) &info.module, 0, 0);
- if(info.verbose) printf(PREFIX "Module moved to RAM\n");
- }
- else if(info.verbose) printf(PREFIX "Module already in RAM\n");
- }
- #ifdef MemCheck_MEMCHECK
- MemCheck_RegisterMiscBlock(info.module - 4, 4);
- #endif
- /* Find the module's size. This relies on the OS's heap format storing
- a block's size in the word before the beginning of the block. */
- info.module_size = *(int *) (info.module - 4) - 4;
- #ifdef MemCheck_MEMCHECK
- MemCheck_UnRegisterMiscBlock(info.module - 4);
- MemCheck_RegisterMiscBlock(info.module, info.module_size);
- #endif
-
- /* Patch new background colours. */
- if(options->pinboard_bg_colour != -1) {
- /* Patch file icon flags. */
- /* Normal flags. */
- patch_location(&info, "File-bg-1", 0x4000A50B, 0x0000A50B |
- (options->pinboard_bg_colour << wimp_ICON_BG_COLOUR_SHIFT),
- 0x30D0, VERSION_370, 0);
- /* Selected flags? */
- patch_location(&info, "File-bg-2", 0x1700A50B, 0x1700A50B,
- 0x30D4, VERSION_370, 0);
-
- /* Patch iconise icon flags. */
- /* Normal flags. */
- patch_location(&info, "Iconise-bg-1", 0x4000A50B, 0x0000A50B |
- (options->pinboard_bg_colour << wimp_ICON_BG_COLOUR_SHIFT),
- 0x12CC, VERSION_370, 0);
- /* Selected flags? */
- patch_location(&info, "Iconise-bg-2", 0x1700310B, 0x0700310B,
- 0x12C8, VERSION_370, 0);
-
- /* Patch background clearing. */
- /* movne r0, #0x84 becomes movne r0, #0x80 | pinboard_bg_colour */
- patch_location(&info, "CLG-1", 0x13A00084, 0x13A00080 |
- options->pinboard_bg_colour,
- 0x0BE0, VERSION_370,
- 0x0E10, VERSION_310, 0);
- /* mov r0, #0x84 becomes mov r0, #0x80 | pinboard_bg_colour */
- patch_location(&info, "CLG-2", 0xE3A00084, 0xE3A00080 |
- options->pinboard_bg_colour,
- 0x24F4, VERSION_370,
- 0x24E8, VERSION_310, 0);
- }
-
- /* Patch new iconbar height. */
- /* mov r3, #0x86 becomes mov r3, #window_height... */
- patch_location(&info, "Iconbar-height", 0xE3A03000 + 0x86,
- /* If iconbar has border, it will be higher (assume 4 OS units). */
- 0xE3A03000 + options->window_height +
- (options->window_border ? 4 : 0),
- 0x4188, VERSION_310,
- 0x438C, VERSION_370, 0);
-
- /* Neuter the Pinboard of its error message `Use *Desktop to start
- Pinboard'. This makes Desktop_Pinboard work, and removes this rather
- fascist tendency. */
- /* Remove the check in the module start code. */
- /* swige OS_GenerateError becomes no-op (mov r0, r0) */
- patch_location(&info, "Bstd", 0xAF00002B, 0xE1A00000,
- 0x08E4, VERSION_370,
- 0x0B30, VERSION_310, 0);
- /* Remove the check in the *Desktop_Pinboard command code. */
- /* Hmm, not finished. Not sure if it will work cleanly. */
-
- #ifdef MemCheck_MEMCHECK
- MemCheck_UnRegisterMiscBlock(info.module);
- #endif
- if(info.verbose) printf(PREFIX "Finished\n");
- }
-
-
- /* Tries patching each location in turn, checking to see if it has been
- patched already or does not match. */
- static void patch_location(patch_state *info, char *patch,
- unsigned old, unsigned new, ...)
- {
- va_list args;
-
- /* Look at pre-supplied locations for patching. */
- va_start(args, new);
- while(1) {
- int offset, version;
- unsigned *location;
-
- /* Get location info from arguments. */
- offset = va_arg(args, int);
- if(!offset) break; /* End of the list. */
- version = va_arg(args, int);
- location = (unsigned *) (info->module + offset);
-
- /* Check the location in the module. */
- /* Does it fall outside the module? */
- if(offset >= info->module_size) continue;
- /* Has it already been patched? */
- if(*location == new) {
- if(info->verbose) printf(PREFIX "Patch `%s' already applied (to %s)\n",
- patch, versions[version]);
- va_end(args);
- return;
- }
- /* Does it match, and so can be patched? */
- if(*location == old) {
- *location = new;
- if(info->verbose) printf(PREFIX "Patch `%s' now applied (to %s)\n",
- patch, versions[version]);
- va_end(args);
- return;
- }
- }
- va_end(args);
-
- /* If that failed, search through the module to find the word given. It
- must only appear once (otherwise how do we know which to patch?). */
- {
- unsigned *i, *end = (unsigned *) (info->module + info->module_size),
- *found = 0;
- int found_patched = 0;
- for(i=(unsigned *) info->module; i<end; ++i) {
- if(*i == new) {
- ++found_patched;
- continue;
- }
- if(*i == old) {
- if(found) {
- if(info->verbose) printf(PREFIX "Patch `%s' could not be applied "
- "(multiple matches)\n", patch);
- return;
- }
- found = i;
- continue;
- }
- }
- if(found) {
- /* We can apply the patch! */
- *found = new;
- if(info->verbose) printf(PREFIX "Patch `%s' now applied "
- "(to %s, at 0x%x)\n", patch, versions[0],
- (char *) found - info->module);
- return;
- }
- else if(found_patched) {
- if(info->verbose) printf(PREFIX "Patch `%s' probably already applied "
- "(found %i match%s)\n", patch, found_patched,
- found_patched > 1 ? "es" : "");
- return;
- }
- }
-
- /* If we couldn't apply this patch, whinge. */
- if(info->verbose) printf(PREFIX "Patch `%s' could not be applied "
- "(no matches)\n", patch);
- }
-