/* * ToolAlias * * Commodity that patches loadseg to substitute specific programs * with others. With settings window and hotkey. Patches may be * disabled and re-enabled via Commodities Exchange. * * Martin W. Scott, 5 February 1993 */ #include #include #include #include #include #include #include #include #include #include #include #include "icon.h" #include "list.h" #include "file.h" #include "window.h" #define ASM __asm __saveds #define REG(x) register __## x /* Local protos */ BOOL OpenLibs(void); VOID CloseLibs(void); VOID _main(VOID); LONG ProcessMsg(void); BOOL InstallWedge(VOID); BOOL RemoveWedge(VOID); struct JumpTable *GetJumpTable(UBYTE *); /* Libraries etc. */ extern struct WBStartup *WBenchMsg; extern struct DosLibrary *DOSBase; struct IntuitionBase *IntuitionBase; struct Library *CxBase, *IconBase, *GadToolsBase; struct GfxBase *GfxBase; /* The number of 'replacement' functions */ #define NUMBEROFFUNCTIONS (1) /* prototypes for the functions to be SetFunction()'ed. */ #define DEC_LVO(lvoname) extern lvoname /* declare stuff for standard dos one-parameter function */ /* UBYTE * in d1 */ #define DEC11_OLD(oldname) LONG (*ASM oldname) (REG(d1) UBYTE *, REG(a6) struct Library *base) #define DEC11_NEW(newname) LONG ASM newname(REG(d1) UBYTE *, REG(a6) struct Library *base) #define DEC11(name) DEC11_OLD(old## name); DEC11_NEW(new## name); DEC_LVO(LVO## name) /* the patched functions themselves */ DEC11(LoadSeg); /* Use a table and an array to make it a little more generic and easier to * add functions. */ struct LVOTable { LONG lt_LVO; struct Library *lt_LibBase; ULONG lt_oldFunction; ULONG lt_newFunction; }; struct LVOTable LVOArray[] = { {&LVOLoadSeg, (struct Library *) & DOSBase, &oldLoadSeg, &newLoadSeg} }; struct JumpTable { struct SignalSemaphore jt_Semaphore; UWORD pad_word; struct Task *jt_Owner; UBYTE jt_Function[NUMBEROFFUNCTIONS * 6]; }; /* Strings */ /* The name this JumpTable/Semaphore will get. */ static UBYTE *JTName = "ToolAlias-JT"; static UBYTE *VersTag = "\0$VER: ToolAlias 1.02"; /* Commodity globals */ CxObj *broker, *popobj; struct MsgPort *broker_mp; struct NewBroker newbroker = { NB_VERSION, "ToolAlias", "ToolAlias 1.02", "Name substitution facility", NBU_UNIQUE | NBU_NOTIFY, COF_SHOW_HIDE }; #define EVT_POPKEY 1L ULONG cxsigflag, wndsigflag; UBYTE popstr[100]; int wedged = 1; /* initially, wedges will be in place */ /* close what we opened */ VOID CloseLibs() { if (IntuitionBase) CloseLibrary(IntuitionBase); if (IconBase) CloseLibrary(IconBase); if (GfxBase) CloseLibrary(GfxBase); if (GadToolsBase) CloseLibrary(GadToolsBase); if (CxBase) CloseLibrary(CxBase); } /* open libraries, devices that we need */ BOOL OpenLibs() { if ((IntuitionBase = (void *) OpenLibrary("intuition.library", 37L)) && (IconBase = (void *) OpenLibrary("icon.library", 37L)) && (GfxBase = (void *) OpenLibrary("graphics.library", 37L)) && (GadToolsBase = OpenLibrary("gadtools.library", 37L)) && (CxBase = OpenLibrary("commodities.library", 37L))) { return TRUE; } CloseLibs(); return FALSE; } /* pop up a requester */ void EasyEasyRequest(char *str) { struct EasyStruct es; es.es_StructSize = sizeof(struct EasyStruct); es.es_Flags = 0L; es.es_Title = "ToolAlias Message"; es.es_TextFormat = str; es.es_GadgetFormat = "OK"; EasyRequestArgs(NULL, &es, NULL, NULL); } #define Msg(s) EasyEasyRequest(s) VOID _main(VOID) { if (OpenLibs()) { if (get_config(DEF_CONFIG)) { if (broker_mp = CreateMsgPort()) { GetOurIcon(WBenchMsg); newbroker.nb_Pri = (BYTE) TTInt("CX_PRIORITY", 0); strcpy(popstr, TTString("CX_POPKEY", "control alt t")); newbroker.nb_Port = broker_mp; if (broker = CxBroker(&newbroker, NULL)) { if (popobj = HotKey(popstr, broker_mp, EVT_POPKEY)) { AttachCxObj(broker, popobj); cxsigflag = 1L << broker_mp->mp_SigBit; ActivateCxObj(broker, 1L); if (TTBool("CX_POPUP", TRUE)) ShowWindow(); FreeOurIcon(); if (InstallWedge()) while (ProcessMsg()); else Msg("Couldn't install patches"); HideWindow(); if (wedged) RemoveWedge(); } else Msg("Couldn't create HotKey"); DeleteCxObjAll(broker); } FreeOurIcon(); /* can be called twice avec no probs */ DeleteMsgPort(broker_mp); } else Msg("Couldn't create port"); free_list(); /* free memory */ } CloseLibs(); } } LONG ProcessMsg(void) { CxMsg *msg; ULONG sigrcvd, msgid, msgtype; LONG returnvalue = 1L; LONG gui_rc; /* wait for something to happen */ sigrcvd = Wait(SIGBREAKF_CTRL_C | cxsigflag | wndsigflag); if (sigrcvd & wndsigflag) /* settings change */ if (gui_rc = HandleIDCMP()) { returnvalue = 0; if (gui_rc == GUI_ABEND) Msg("No memory - terminating"); } /* process any messages */ while (msg = (CxMsg *) GetMsg(broker_mp)) { /* Extract necessary information from the CxMessage and return it */ msgid = CxMsgID(msg); msgtype = CxMsgType(msg); ReplyMsg((struct Message *) msg); if (msgtype == CXM_IEVENT) /* popkey */ { if (msgid == EVT_POPKEY) ShowWindow(); } else if (msgtype == CXM_COMMAND) /* std commodity message */ { switch (msgid) { case CXCMD_UNIQUE: case CXCMD_APPEAR: ShowWindow(); /* check error return? */ break; case CXCMD_DISAPPEAR: HideWindow(); break; case CXCMD_DISABLE: if (wedged) { RemoveWedge(); wedged = 0; } ActivateCxObj(broker, 0L); break; case CXCMD_ENABLE: if (!wedged) { InstallWedge(); wedged = 1; } ActivateCxObj(broker, 1L); break; case CXCMD_KILL: returnvalue = 0L; break; } } } /* Test to see if user tried to break */ if (sigrcvd & SIGBREAKF_CTRL_C) returnvalue = 0L; return (returnvalue); } BOOL InstallWedge(VOID) { struct JumpTable *jumptable; ULONG *addressptr; UCOUNT i, j; Forbid(); /* Get pointer to JumpTable. Create it if necessary */ if (jumptable = GetJumpTable(JTName)) { /* Try to get exclusive lock on semaphore, in case it already existed. */ if (AttemptSemaphore((struct SignalSemaphore *) jumptable)) { /* Make sure nobody else has function addresses in the jumptable */ if (jumptable->jt_Owner == NULL) { jumptable->jt_Owner = FindTask(0); /* Don't want to disable any longer than necessary */ Disable(); for (i = 2, j = 0; i < NUMBEROFFUNCTIONS * 6; i += 6, j++) { /* Replace addresses in the jumptable with my own. */ addressptr = (ULONG *) ((UBYTE *) jumptable->jt_Function + i); (*((ULONG *) LVOArray[j].lt_oldFunction)) = (ULONG) * addressptr; *addressptr = (ULONG) LVOArray[j].lt_newFunction; } CacheClearU(); Enable(); } else Msg("Already running.\n"); ReleaseSemaphore((struct SignalSemaphore *) jumptable); } else Msg("Can't lock table.\n"); } else Msg("Can't create jumptable\n"); Permit(); return ((BOOL) jumptable); } BOOL RemoveWedge(VOID) { struct JumpTable *jumptable; ULONG *addressptr; UCOUNT i, j; Forbid(); if (jumptable = GetJumpTable(JTName)) { /* Check if this task owns this jumptable */ if (jumptable->jt_Owner == FindTask(0)) { /* Get the semaphore exclusively. * Depending on what got SetFunction()'ed this could take some time. * Also note that shared locks are used to indicate the code is * being executed and that shared locks can jump ahead of queue'ed * exclusive locks, adding to the waittime. */ ObtainSemaphore((struct SignalSemaphore *) jumptable); Disable(); /* Restore old pointers in jumptable */ for (i = 2, j = 0; i < NUMBEROFFUNCTIONS * 6; i += 6, j++) { addressptr = (ULONG *) ((UBYTE *) jumptable->jt_Function + i); *addressptr = (*((ULONG *) LVOArray[j].lt_oldFunction)); } CacheClearU(); Enable(); jumptable->jt_Owner = NULL; ReleaseSemaphore((struct SignalSemaphore *) jumptable); } } Permit(); return (TRUE); } struct JumpTable * GetJumpTable(UBYTE * name) { struct JumpTable *jumptable; ULONG *addressptr; UWORD *jmpinstr; UBYTE *jtname; UCOUNT i, j; /* Not really necessary to forbid again, just to indicate that I don't * want another task to create the semaphore while I'm trying to do the * same. Here GetJumpTable() is only called from InstallWedge(), so it * will just bump the forbid count. */ Forbid(); if (!(jumptable = (struct JumpTable *) FindSemaphore(name))) { if (jumptable = AllocMem(sizeof(struct JumpTable), MEMF_PUBLIC | MEMF_CLEAR)) { if (jtname = AllocMem(strlen(name) + 1, MEMF_PUBLIC | MEMF_CLEAR)) { for (i = 0, j = 0; i < NUMBEROFFUNCTIONS * 6; i += 6, j++) { jmpinstr = (UWORD *) ((UBYTE *) jumptable->jt_Function + i); *jmpinstr = 0x4EF9; addressptr = (ULONG *) ((UBYTE *) jumptable->jt_Function + i + 2); *addressptr = (ULONG) SetFunction( (struct Library *) (*((ULONG *) LVOArray[j].lt_LibBase)), LVOArray[j].lt_LVO, (VOID *) ((UBYTE *) jumptable->jt_Function + i)); } jumptable->jt_Semaphore.ss_Link.ln_Pri = 0; strcpy(jtname, name); jumptable->jt_Semaphore.ss_Link.ln_Name = jtname; AddSemaphore((struct SignalSemaphore *) jumptable); } else { FreeMem(jumptable, sizeof(struct JumpTable)); jumptable = NULL; } } } Permit(); /* If succeeded, you now have a jumptable which entries point to the original * library functions. If another task SetFunction()'ed one or more of those * already, that task can never go away anymore. */ return (jumptable); } /******************************************************************************/ /******************* **************************/ /******************* NEW DOS ROUTINES START HERE **************************/ /******************* **************************/ /******************************************************************************/ LONG ASM newLoadSeg(REG(d1) UBYTE * name, REG(a6) struct Library * base) { struct SignalSemaphore *jt; char *newname; LONG rc = 0; if (jt = FindSemaphore(JTName)) { ObtainSemaphoreShared(jt); if (name && (newname = find_tool(name))) rc = oldLoadSeg(newname, DOSBase); else rc = oldLoadSeg(name, DOSBase); ReleaseSemaphore(jt); } return rc; }