home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ARM Club 3
/
TheARMClub_PDCD3.iso
/
programs
/
desktop
/
newbar
/
Source
/
NewBar
/
c
/
pinpatch
< prev
Wrap
Text File
|
1998-08-02
|
7KB
|
217 lines
/* 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);
}