home *** CD-ROM | disk | FTP | other *** search
- ;/* Execute me to compile with SAS/C 6.56
- sc DATA=NEAR NMINC STRMERGE NODEBUG NOSTKCHK OPTIMIZE IGNORE=73 ispy.c
- asm -iINCLUDE: ispy_stubs.asm
- slink from lib:c.o ispy.o ispy_stubs.o LIB lib:amiga.lib lib:scnb.lib lib:debug.lib SC SD ND
- quit
- ** ISpy. AmigaMail SetFunction() example.
- **
-
- Copyright (c) 1991-1999 Amiga, Inc.
-
- This example is provided in electronic form by Amiga, Inc.
- for use with the Amiga Mail Volume II technical publication.
- Amiga Mail Volume II contains additional information on the correct
- usage of the techniques and operating system functions presented in
- these examples. The source and executable code of these examples may
- only be distributed in free electronic form, via bulletin board or
- as part of a fully non-commercial and freely redistributable
- diskette. Both the source and executable code (including comments)
- must be included, without modification, in any copy. This example
- may not be published in printed form or distributed with any
- commercial product. However, the programming techniques and support
- routines set forth in these examples may be used in the development
- of original executable software products for Amiga
- computers.
-
- All other rights reserved.
-
- This example is provided "as-is" and is subject to change; no
- warranties are made. All use is at your own risk. No liability or
- responsibility is assumed.
- */
-
-
- #include <exec/types.h>
- #include <exec/execbase.h>
- #include <exec/memory.h>
- #include <exec/semaphores.h>
- #include <dos/dos.h>
- #include <libraries/gadtools.h>
- #include <string.h>
- #include <clib/dos_protos.h>
- #include <clib/exec_protos.h>
- #include <clib/intuition_protos.h>
-
- #ifdef LATTICE
- int CXBRK(void) { return(0); } /* Disable Lattice CTRL/C handling */
- int chkabort(void) { return(0); }
- #endif
-
- #define ASM __asm __saveds
- #define REG(x) register __## x
-
- #ifdef PARALLEL
- #define zprintf dprintf
- extern VOID dprintf(STRPTR,...);
- #else
- #define zprintf kprintf
- extern VOID kprintf(STRPTR,...);
- #endif
-
- #ifdef DEBUG
- #define D(x) x
- #else
- #define D(x) ;
- #endif
-
- /* Local protos */
- VOID main(VOID);
- BOOL InstallWedge(VOID);
- BOOL RemoveWedge(VOID);
- struct JumpTable *GetJumpTable(UBYTE *);
-
- /* Assembler stubs will return a pointer to the caller's stack in a4.
- * The only system function at this moment using a4 is the workbench.library
- * AddAppIconA() function.
- */
- #define ACALLER (0) /* StackPtr[0] = ACaller, StackPtr[1] = saved A6 in stub */
- #define CCALLER (2) /* StackPtr[2] = CCaller */
-
- /* The number of 'replacement' functions */
- #define NUMBEROFFUNCTIONS (4)
-
- /* prototypes for the functions to be SetFunction()'ed. */
-
- /* intuition.library */
- struct Screen *(*ASM oldOpenScreen) (REG(a0) struct NewScreen *,
- REG(a6) struct Library *);
- struct Window *(*ASM oldOpenWindowTagList) (REG(a0) struct NewWindow *,
- REG(a1) struct TagItem *,
- REG(a6) struct Library *);
- struct Screen *ASM newOpenScreen(REG(a0) struct NewScreen *,
- REG(a4) ULONG *,
- REG(a6) struct Library *);
- struct Window *ASM newOpenWindowTagList(REG(a0) struct NewWindow *,
- REG(a1) struct TagItem *,
- REG(a4) ULONG *,
- REG(a6) struct Library *);
-
- /* exec.library */
- VOID(*ASM oldFreeMem) (REG(a1) VOID *,
- REG(d0) ULONG,
- REG(a6) struct Library *);
- VOID ASM newFreeMem(REG(a1) VOID *,
- REG(d0) ULONG,
- REG(a4) ULONG *,
- REG(a6) struct Library *);
-
- /* graphics.library */
- VOID(*ASM oldSetFont) (REG(a1) struct RastPort *,
- REG(a0) struct TextFont *,
- REG(a6) struct Library *);
- VOID ASM newSetFont(REG(a1) struct RastPort *,
- REG(a0) struct TextFont *,
- REG(a4) ULONG *,
- REG(a6) struct Library *);
-
- /* Assembler Stubs */
- extern OpenScreenStub();
- extern OpenWindowTagListStub();
- extern FreeMemStub();
- extern SetFontStub();
-
- /* The LVO's to use from amiga.lib */
- extern LVOOpenScreen;
- extern LVOOpenWindowTagList;
- extern LVOFreeMem;
- extern LVOSetFont;
-
- extern struct ExecBase *SysBase;
- struct IntuitionBase *IntuitionBase;
- struct GfxBase *GfxBase;
-
- /* 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[] =
- {
- {&LVOOpenScreen, (struct Library *) &IntuitionBase,
- &oldOpenScreen,
- &OpenScreenStub},
- {&LVOOpenWindowTagList, (struct Library *) &IntuitionBase,
- &oldOpenWindowTagList, &OpenWindowTagListStub},
- {&LVOFreeMem, (struct Library *) & SysBase, &oldFreeMem, &FreeMemStub},
- {&LVOSetFont, (struct Library *) & GfxBase, &oldSetFont, &SetFontStub},
- };
-
- 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 = "ISpy-MiscJumpTable";
-
- static UBYTE *VersTag = "\0$VER: ISpy 37.4 (21.3.91)";
- static UBYTE *VerTitle = "Ispy 37.4";
- static UBYTE *Copyright = "\nCopyright (c) 1991-1999 Amiga, Inc.\n";
- static UBYTE *CBreak = "CTRL-C or BREAK to exit...\n";
- VOID
- main(VOID)
- {
-
- Write(Output(), (STRPTR) VerTitle, strlen((STRPTR) VerTitle));
- Write(Output(), Copyright, strlen(Copyright));
-
- if (SysBase->LibNode.lib_Version > 36)
- {
- if (IntuitionBase = OpenLibrary("intuition.library", 37))
- {
- if (GfxBase = OpenLibrary("graphics.library", 37))
- {
- if (InstallWedge())
- {
- Write(Output(), CBreak, strlen(CBreak));
- Wait(SIGBREAKF_CTRL_C);
- RemoveWedge();
- }
- CloseLibrary(GfxBase);
- }
- else
- Write(Output(), "Couldn't open graphics.library\n", 31);
- CloseLibrary(IntuitionBase);
- }
- else
- Write(Output(), "Couldn't open intuition.library\n", 32);
- }
- else
- Write(Output(), "Requires at least Kickstart 2.04\n", 33);
- }
-
-
- 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;
- D(zprintf("setting table to Function: 0x%lx\n", *addressptr));
- }
- Enable();
- }
- else
- Write(Output(), "Already running.\n", 16);
- ReleaseSemaphore((struct SignalSemaphore *) jumptable);
- }
- else
- Write(Output(), "Can't lock table.\n", 18);
- }
- else
- Write(Output(), "Can't create jumptable\n", 23);
- Permit();
- return ((BOOL) jumptable);
- }
-
- BOOL
- RemoveWedge(VOID)
- {
- struct JumpTable *jumptable;
- ULONG *addressptr;
- UCOUNT i, j;
-
- Forbid();
-
- if (jumptable = GetJumpTable(JTName))
- {
- D(zprintf("jumptable @ 0x%lx\n", jumptable));
-
- /* 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));
- D(zprintf("setting table to oldFunction: 0x%lx\n", *addressptr));
- }
-
- 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(32, 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);
- /* In 1.2/1.3 AddSemaphore() didn't work properly.
- ** Under 1.2/1.3, change it to:
- ** InitSemaphore(jumptable);
- ** Forbid();
- ** Enqueue(&SysBase->SemaphoreList, jumptable);
- ** Permit();
- */
- }
- 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);
- }
-
-
- /* Note: if you'd want this to work with 1.3, you wouldn't/couldn't lock the
- * semaphore, but instead would have to use a global to in- and decrement.
- * When exiting, you'd spin around the global counter, waiting for it to reach
- * zero. At that point you'd Disable(), reset the pointers in the jumptable and
- * Enable() again.
- */
-
-
- struct Screen *ASM
- newOpenScreen(REG(a0) struct NewScreen * newscreen,
- REG(a4) ULONG * stackptr,
- REG(a6) struct Library * base)
- {
- struct SignalSemaphore *jt;
- struct Screen *screen = NULL;
-
- /* Find the semaphore to lock shared, indicating the routine is being run. */
- /* For speed reasons you may want to cache the pointer to the semaphore
- ** in a global variable */
- if (jt = FindSemaphore(JTName))
- {
- /* Lock shared in 2.0. In 1.3 you'd increment a global counter */
- ObtainSemaphoreShared(jt);
- /* Simple test for valid argument. Could check all the fields too. */
- if (newscreen != NULL)
- {
- screen = (*oldOpenScreen) (newscreen, base);
- }
- else
- {
- ULONG ACaller = stackptr[ACALLER];
- ULONG CCaller = stackptr[CCALLER];
-
- Forbid(); /* To make sure the output isn't garbled */
- zprintf("OpenScreen(NULL) by `%s' (at 0x%lx) from A:0x%lx C:0x%lx SP:0x%lx\n",
- SysBase->ThisTask->tc_Node.ln_Name,
- SysBase->ThisTask,
- ACaller,
- CCaller,
- stackptr);
- Permit();
- }
- /* Release shared lock. In 1.3 you'd decrement the global pointer */
- ReleaseSemaphore(jt);
- }
-
- return (screen);
- }
-
- struct Window *ASM
- newOpenWindowTagList(REG(a0) struct NewWindow * newwindow,
- REG(a1) struct TagItem * tags,
- REG(a4) ULONG * stackptr,
- REG(a6) struct Library * base)
- {
- struct SignalSemaphore *jt;
- struct Window *window = NULL;
-
-
- if (jt = FindSemaphore(JTName))
- {
- ObtainSemaphoreShared(jt);
- if (newwindow != NULL || tags != NULL)
- {
- window = (*oldOpenWindowTagList) (newwindow, tags, base);
- }
- else
- {
- ULONG ACaller = stackptr[ACALLER];
- ULONG CCaller = stackptr[CCALLER];
-
- Forbid();
- zprintf("OpenWindowTagList(NULL,NULL) by `%s' (at 0x%lx) from A:0x%lx C:0x%lx SP:0x%lx\n",
- SysBase->ThisTask->tc_Node.ln_Name,
- SysBase->ThisTask,
- ACaller,
- CCaller,
- stackptr);
- Permit();
- }
- ReleaseSemaphore(jt);
- }
-
- return (window);
- }
-
-
- VOID ASM
- newFreeMem(REG(a1) VOID * memptr,
- REG(d0) ULONG size,
- REG(a4) ULONG * stackptr,
- REG(a6) struct Library * base)
- {
- struct SignalSemaphore *jt;
-
- if (jt = FindSemaphore(JTName))
- {
- ObtainSemaphoreShared(jt);
- if (memptr != NULL && size != 0L)
- {
- (*oldFreeMem) (memptr, size, base);
- }
- else
- {
- ULONG ACaller = stackptr[ACALLER];
- ULONG CCaller = stackptr[CCALLER];
-
- Forbid();
- zprintf("FreeMem(0x%lx,%ld) by `%s' (at 0x%lx) from A:0x%lx C:0x%lx SP:0x%lx\n",
- memptr, size,
- SysBase->ThisTask->tc_Node.ln_Name,
- SysBase->ThisTask,
- ACaller,
- CCaller,
- stackptr);
- Permit();
- }
-
- ReleaseSemaphore(jt);
- }
- }
-
- VOID ASM
- newSetFont(REG(a1) struct RastPort * rp,
- REG(a0) struct TextFont * font,
- REG(a4) ULONG * stackptr,
- REG(a6) struct Library * base)
- {
- struct SignalSemaphore *jt;
-
-
- if (jt = FindSemaphore(JTName))
- {
- ObtainSemaphoreShared(jt);
- if (rp != NULL && font != NULL)
- {
- (*oldSetFont) (rp, font, base);
- }
- else
- {
- ULONG ACaller = stackptr[ACALLER];
- ULONG CCaller = stackptr[CCALLER];
-
- Forbid();
- zprintf("SetFont(0x%lx,0x%lx) by `%s' (at 0x%lx) from A:0x%lx C:0x%lx SP:0x%lx\n",
- rp, font,
- SysBase->ThisTask->tc_Node.ln_Name,
- SysBase->ThisTask,
- ACaller,
- CCaller,
- stackptr);
- Permit();
- }
- ReleaseSemaphore(jt);
- }
- }
-