home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD v1.2 / amidev_cd_12.iso / reference / amiga_mail_vol2 / iii-1 / ispy.c < prev    next >
C/C++ Source or Header  |  1996-01-30  |  17KB  |  519 lines

  1. ;/* Execute me to compile with SAS/C 6.56
  2. sc DATA=NEAR NMINC STRMERGE NODEBUG NOSTKCHK OPTIMIZE IGNORE=73 ispy.c
  3. asm -iINCLUDE: ispy_stubs.asm
  4. slink from lib:c.o ispy.o ispy_stubs.o LIB lib:amiga.lib lib:scnb.lib lib:debug.lib SC SD ND
  5. quit
  6. **      ISpy. AmigaMail SetFunction() example.
  7. **
  8.  
  9. Copyright (c) 1991 Commodore-Amiga, Inc.
  10.  
  11. This example is provided in electronic form by Commodore-Amiga,
  12. Inc. for use with the Amiga Mail Volume II technical publication.
  13. Amiga Mail Volume II contains additional information on the correct
  14. usage of the techniques and operating system functions presented in
  15. these examples.  The source and executable code of these examples may
  16. only be distributed in free electronic form, via bulletin board or
  17. as part of a fully non-commercial and freely redistributable
  18. diskette.  Both the source and executable code (including comments)
  19. must be included, without modification, in any copy.  This example
  20. may not be published in printed form or distributed with any
  21. commercial product. However, the programming techniques and support
  22. routines set forth in these examples may be used in the development
  23. of original executable software products for Commodore Amiga
  24. computers.
  25.  
  26. All other rights reserved.
  27.  
  28. This example is provided "as-is" and is subject to change; no
  29. warranties are made.  All use is at your own risk. No liability or
  30. responsibility is assumed.
  31. */
  32.  
  33.  
  34. #include <exec/types.h>
  35. #include <exec/execbase.h>
  36. #include <exec/memory.h>
  37. #include <exec/semaphores.h>
  38. #include <dos/dos.h>
  39. #include <libraries/gadtools.h>
  40. #include <string.h>
  41. #include <clib/dos_protos.h>
  42. #include <clib/exec_protos.h>
  43. #include <clib/intuition_protos.h>
  44.  
  45. #ifdef LATTICE
  46. int CXBRK(void) { return(0); }  /* Disable Lattice CTRL/C handling */
  47. int chkabort(void) { return(0); }
  48. #endif
  49.  
  50. #define ASM __asm __saveds
  51. #define REG(x) register __## x
  52.  
  53. #ifdef PARALLEL
  54. #define zprintf dprintf
  55. extern VOID     dprintf(STRPTR,...);
  56. #else
  57. #define zprintf kprintf
  58. extern VOID     kprintf(STRPTR,...);
  59. #endif
  60.  
  61. #ifdef DEBUG
  62. #define D(x) x
  63. #else
  64. #define D(x) ;
  65. #endif
  66.  
  67. /* Local protos */
  68. VOID            main(VOID);
  69. BOOL            InstallWedge(VOID);
  70. BOOL            RemoveWedge(VOID);
  71. struct JumpTable *GetJumpTable(UBYTE *);
  72.  
  73. /* Assembler stubs will return a pointer to the caller's stack in a4.
  74.  * The only system function at this moment using a4 is the workbench.library
  75.  * AddAppIconA() function.
  76.  */
  77. #define ACALLER (0)             /* StackPtr[0] = ACaller, StackPtr[1] = saved A6 in stub */
  78. #define CCALLER (2)             /* StackPtr[2] = CCaller */
  79.  
  80. /* The number of 'replacement' functions */
  81. #define NUMBEROFFUNCTIONS (4)
  82.  
  83. /* prototypes for the functions to be SetFunction()'ed. */
  84.  
  85. /* intuition.library */
  86. struct Screen  *(*ASM oldOpenScreen) (REG(a0) struct NewScreen *,
  87.                                       REG(a6) struct Library *);
  88. struct Window  *(*ASM oldOpenWindowTagList) (REG(a0) struct NewWindow *,
  89.                                              REG(a1) struct TagItem *,
  90.                                              REG(a6) struct Library *);
  91. struct Screen  *ASM newOpenScreen(REG(a0) struct NewScreen *,
  92.                                   REG(a4) ULONG *,
  93.                                   REG(a6) struct Library *);
  94. struct Window  *ASM newOpenWindowTagList(REG(a0) struct NewWindow *,
  95.                                          REG(a1) struct TagItem *,
  96.                                          REG(a4) ULONG *,
  97.                                          REG(a6) struct Library *);
  98.  
  99. /* exec.library */
  100. VOID(*ASM oldFreeMem) (REG(a1) VOID *,
  101.                        REG(d0) ULONG,
  102.                        REG(a6) struct Library *);
  103. VOID ASM        newFreeMem(REG(a1) VOID *,
  104.                            REG(d0) ULONG,
  105.                            REG(a4) ULONG *,
  106.                            REG(a6) struct Library *);
  107.  
  108. /* graphics.library */
  109. VOID(*ASM oldSetFont) (REG(a1) struct RastPort *,
  110.                        REG(a0) struct TextFont *,
  111.                        REG(a6) struct Library *);
  112. VOID ASM        newSetFont(REG(a1) struct RastPort *,
  113.                            REG(a0) struct TextFont *,
  114.                            REG(a4) ULONG *,
  115.                            REG(a6) struct Library *);
  116.  
  117. /* Assembler Stubs */
  118. extern          OpenScreenStub();
  119. extern          OpenWindowTagListStub();
  120. extern          FreeMemStub();
  121. extern          SetFontStub();
  122.  
  123. /* The LVO's to use from amiga.lib */
  124. extern          LVOOpenScreen;
  125. extern          LVOOpenWindowTagList;
  126. extern          LVOFreeMem;
  127. extern          LVOSetFont;
  128.  
  129. extern struct ExecBase *SysBase;
  130. struct IntuitionBase *IntuitionBase;
  131. struct GfxBase *GfxBase;
  132.  
  133. /* Use a table and an array to make it a little more generic and easier to
  134.  * add functions.
  135.  */
  136. struct LVOTable
  137. {
  138.     LONG            lt_LVO;
  139.     struct Library *lt_LibBase;
  140.     ULONG           lt_oldFunction;
  141.     ULONG           lt_newFunction;
  142. };
  143.  
  144. struct LVOTable LVOArray[] =
  145. {
  146.     {&LVOOpenScreen, (struct Library *) &IntuitionBase,
  147.         &oldOpenScreen,
  148.         &OpenScreenStub},
  149.     {&LVOOpenWindowTagList, (struct Library *) &IntuitionBase,
  150.                         &oldOpenWindowTagList, &OpenWindowTagListStub},
  151.     {&LVOFreeMem, (struct Library *) & SysBase, &oldFreeMem, &FreeMemStub},
  152.     {&LVOSetFont, (struct Library *) & GfxBase, &oldSetFont, &SetFontStub},
  153. };
  154.  
  155. struct JumpTable
  156. {
  157.     struct SignalSemaphore jt_Semaphore;
  158.     UWORD           pad_word;
  159.     struct Task    *jt_Owner;
  160.     UBYTE           jt_Function[NUMBEROFFUNCTIONS * 6];
  161. };
  162.  
  163. /* Strings */
  164. /* The name this JumpTable/Semaphore will get. */
  165. static UBYTE   *JTName = "ISpy-MiscJumpTable";
  166.  
  167. static UBYTE   *VersTag = "\0$VER: ISpy 37.4 (21.3.91)";
  168. static UBYTE   *VerTitle = "Ispy 37.4";
  169. static UBYTE   *Copyright = "\nCopyright (c) 1991 Commodore-Amiga, Inc.\n";
  170. static UBYTE   *CBreak = "CTRL-C or BREAK to exit...\n";
  171. VOID
  172. main(VOID)
  173. {
  174.  
  175.     Write(Output(), (STRPTR) VerTitle, strlen((STRPTR) VerTitle));
  176.     Write(Output(), Copyright, strlen(Copyright));
  177.  
  178.     if (SysBase->LibNode.lib_Version > 36)
  179.     {
  180.         if (IntuitionBase = OpenLibrary("intuition.library", 37))
  181.         {
  182.             if (GfxBase = OpenLibrary("graphics.library", 37))
  183.             {
  184.                 if (InstallWedge())
  185.                 {
  186.                     Write(Output(), CBreak, strlen(CBreak));
  187.                     Wait(SIGBREAKF_CTRL_C);
  188.                     RemoveWedge();
  189.                 }
  190.                 CloseLibrary(GfxBase);
  191.             }
  192.             else
  193.                 Write(Output(), "Couldn't open graphics.library\n", 31);
  194.             CloseLibrary(IntuitionBase);
  195.         }
  196.         else
  197.             Write(Output(), "Couldn't open intuition.library\n", 32);
  198.     }
  199.     else
  200.         Write(Output(), "Requires at least Kickstart 2.04\n", 33);
  201. }
  202.  
  203.  
  204. BOOL
  205. InstallWedge(VOID)
  206. {
  207.     struct JumpTable *jumptable;
  208.     ULONG          *addressptr;
  209.     UCOUNT          i, j;
  210.  
  211.     Forbid();
  212.  
  213.     /* Get pointer to JumpTable. Create it if necessary */
  214.     if (jumptable = GetJumpTable(JTName))
  215.     {
  216.         /* Try to get exclusive lock on semaphore, in case it already existed. */
  217.         if (AttemptSemaphore((struct SignalSemaphore *) jumptable))
  218.         {
  219.             /* Make sure nobody else has function addresses in the jumptable */
  220.             if (jumptable->jt_Owner == NULL)
  221.             {
  222.                 jumptable->jt_Owner = FindTask(0);
  223.                 /* Don't want to disable any longer than necessary */
  224.                 Disable();
  225.  
  226.                 for (i = 2, j = 0; i < NUMBEROFFUNCTIONS * 6; i += 6, j++)
  227.                 {
  228.                     /* Replace addresses in the jumptable with my own. */
  229.                     addressptr = (ULONG *) ((UBYTE *) jumptable->jt_Function + i);
  230.                     (*((ULONG *) LVOArray[j].lt_oldFunction)) = (ULONG) * addressptr;
  231.                     *addressptr = (ULONG) LVOArray[j].lt_newFunction;
  232.                     D(zprintf("setting table to Function: 0x%lx\n", *addressptr));
  233.                 }
  234.                 Enable();
  235.             }
  236.             else
  237.                 Write(Output(), "Already running.\n", 16);
  238.             ReleaseSemaphore((struct SignalSemaphore *) jumptable);
  239.         }
  240.         else
  241.             Write(Output(), "Can't lock table.\n", 18);
  242.     }
  243.     else
  244.         Write(Output(), "Can't create jumptable\n", 23);
  245.     Permit();
  246.     return ((BOOL) jumptable);
  247. }
  248.  
  249. BOOL
  250. RemoveWedge(VOID)
  251. {
  252.     struct JumpTable *jumptable;
  253.     ULONG          *addressptr;
  254.     UCOUNT          i, j;
  255.  
  256.     Forbid();
  257.  
  258.     if (jumptable = GetJumpTable(JTName))
  259.     {
  260.         D(zprintf("jumptable @ 0x%lx\n", jumptable));
  261.  
  262.         /* Check if this task owns this jumptable */
  263.         if (jumptable->jt_Owner == FindTask(0))
  264.         {
  265.  
  266.             /* Get the semaphore exclusively.
  267.              * Depending on what got SetFunction()'ed this could take some time.
  268.              * Also note that shared locks are used to indicate the code is
  269.              * being executed and that shared locks can jump ahead of queue'ed
  270.              * exclusive locks, adding to the waittime.
  271.              */
  272.             ObtainSemaphore((struct SignalSemaphore *) jumptable);
  273.  
  274.             Disable();
  275.  
  276.             /* Restore old pointers in jumptable */
  277.  
  278.             for (i = 2, j = 0; i < NUMBEROFFUNCTIONS * 6; i += 6, j++)
  279.             {
  280.                 addressptr = (ULONG *) ((UBYTE *) jumptable->jt_Function + i);
  281.                 *addressptr = (*((ULONG *) LVOArray[j].lt_oldFunction));
  282.                 D(zprintf("setting table to oldFunction: 0x%lx\n", *addressptr));
  283.             }
  284.  
  285.             Enable();
  286.  
  287.             jumptable->jt_Owner = NULL;
  288.             ReleaseSemaphore((struct SignalSemaphore *) jumptable);
  289.         }
  290.     }
  291.  
  292.     Permit();
  293.  
  294.     return (TRUE);
  295. }
  296.  
  297. struct JumpTable *
  298. GetJumpTable(UBYTE * name)
  299. {
  300.     struct JumpTable *jumptable;
  301.     ULONG          *addressptr;
  302.     UWORD          *jmpinstr;
  303.     UBYTE          *jtname;
  304.     UCOUNT          i, j;
  305.  
  306.     /* Not really necessary to forbid again, just to indicate that I don't
  307.      * want another task to create the semaphore while I'm trying to do the
  308.      * same. Here GetJumpTable() is only called from InstallWedge(), so it
  309.      * will just bump the forbid count.
  310.      */
  311.     Forbid();
  312.  
  313.     if (!(jumptable = (struct JumpTable *) FindSemaphore(name)))
  314.     {
  315.         if (jumptable = AllocMem(sizeof(struct JumpTable), MEMF_PUBLIC | MEMF_CLEAR))
  316.         {
  317.             if (jtname = AllocMem(32, MEMF_PUBLIC | MEMF_CLEAR))
  318.             {
  319.  
  320.                 for (i = 0, j = 0; i < NUMBEROFFUNCTIONS * 6; i += 6, j++)
  321.                 {
  322.                     jmpinstr = (UWORD *) ((UBYTE *) jumptable->jt_Function + i);
  323.                     *jmpinstr = 0x4EF9;
  324.  
  325.                     addressptr = (ULONG *) ((UBYTE *) jumptable->jt_Function + i + 2);
  326.                     *addressptr = (ULONG) SetFunction(
  327.                         (struct Library *) (*((ULONG *) LVOArray[j].lt_LibBase)),
  328.                         LVOArray[j].lt_LVO,
  329.                         (VOID *) ((UBYTE *) jumptable->jt_Function + i));
  330.                 }
  331.  
  332.                 jumptable->jt_Semaphore.ss_Link.ln_Pri = 0;
  333.  
  334.                 strcpy(jtname, name);
  335.                 jumptable->jt_Semaphore.ss_Link.ln_Name = jtname;
  336.                 AddSemaphore((struct SignalSemaphore *) jumptable);
  337.                 /* In 1.2/1.3 AddSemaphore() didn't work properly.
  338.                 ** Under 1.2/1.3, change it to:
  339.                 ** InitSemaphore(jumptable);
  340.                 ** Forbid();
  341.                 ** Enqueue(&SysBase->SemaphoreList, jumptable);
  342.                 ** Permit();
  343.                 */
  344.             }
  345.             else
  346.             {
  347.                 FreeMem(jumptable, sizeof(struct JumpTable));
  348.                 jumptable = NULL;
  349.             }
  350.         }
  351.     }
  352.  
  353.     Permit();
  354.  
  355.     /* If succeeded, you now have a jumptable which entries point to the original
  356.      * library functions. If another task SetFunction()'ed one or more of those
  357.      * already, that task can never go away anymore.
  358.      */
  359.     return (jumptable);
  360. }
  361.  
  362.  
  363. /* Note: if you'd want this to work with 1.3, you wouldn't/couldn't lock the
  364.  * semaphore, but instead would have to use a global to in- and decrement.
  365.  * When exiting, you'd spin around the global counter, waiting for it to reach
  366.  * zero. At that point you'd Disable(), reset the pointers in the jumptable and
  367.  * Enable() again.
  368.  */
  369.  
  370.  
  371. struct Screen  *ASM
  372. newOpenScreen(REG(a0) struct NewScreen * newscreen,
  373.               REG(a4) ULONG * stackptr,
  374.               REG(a6) struct Library * base)
  375. {
  376.     struct SignalSemaphore *jt;
  377.     struct Screen  *screen = NULL;
  378.  
  379.     /* Find the semaphore to lock shared, indicating the routine is being run. */
  380.     /* For speed reasons you may want to cache the pointer to the semaphore
  381.     ** in a global variable */
  382.     if (jt = FindSemaphore(JTName))
  383.     {
  384.         /* Lock shared in 2.0. In 1.3 you'd increment a global counter */
  385.         ObtainSemaphoreShared(jt);
  386.         /* Simple test for valid argument. Could check all the fields too. */
  387.         if (newscreen != NULL)
  388.         {
  389.             screen = (*oldOpenScreen) (newscreen, base);
  390.         }
  391.         else
  392.         {
  393.             ULONG           ACaller = stackptr[ACALLER];
  394.             ULONG           CCaller = stackptr[CCALLER];
  395.  
  396.             Forbid();           /* To make sure the output isn't garbled */
  397.             zprintf("OpenScreen(NULL) by `%s' (at 0x%lx) from A:0x%lx C:0x%lx SP:0x%lx\n",
  398.                     SysBase->ThisTask->tc_Node.ln_Name,
  399.                     SysBase->ThisTask,
  400.                     ACaller,
  401.                     CCaller,
  402.                     stackptr);
  403.             Permit();
  404.         }
  405.         /* Release shared lock. In 1.3  you'd decrement the global pointer */
  406.         ReleaseSemaphore(jt);
  407.     }
  408.  
  409.     return (screen);
  410. }
  411.  
  412. struct Window  *ASM
  413. newOpenWindowTagList(REG(a0) struct NewWindow * newwindow,
  414.                      REG(a1) struct TagItem * tags,
  415.                      REG(a4) ULONG * stackptr,
  416.                      REG(a6) struct Library * base)
  417. {
  418.     struct SignalSemaphore *jt;
  419.     struct Window  *window = NULL;
  420.  
  421.  
  422.     if (jt = FindSemaphore(JTName))
  423.     {
  424.         ObtainSemaphoreShared(jt);
  425.         if (newwindow != NULL || tags != NULL)
  426.         {
  427.             window = (*oldOpenWindowTagList) (newwindow, tags, base);
  428.         }
  429.         else
  430.         {
  431.             ULONG           ACaller = stackptr[ACALLER];
  432.             ULONG           CCaller = stackptr[CCALLER];
  433.  
  434.             Forbid();
  435.             zprintf("OpenWindowTagList(NULL,NULL) by `%s' (at 0x%lx) from A:0x%lx C:0x%lx SP:0x%lx\n",
  436.                     SysBase->ThisTask->tc_Node.ln_Name,
  437.                     SysBase->ThisTask,
  438.                     ACaller,
  439.                     CCaller,
  440.                     stackptr);
  441.             Permit();
  442.         }
  443.         ReleaseSemaphore(jt);
  444.     }
  445.  
  446.     return (window);
  447. }
  448.  
  449.  
  450. VOID ASM
  451. newFreeMem(REG(a1) VOID * memptr,
  452.            REG(d0) ULONG size,
  453.            REG(a4) ULONG * stackptr,
  454.            REG(a6) struct Library * base)
  455. {
  456.     struct SignalSemaphore *jt;
  457.  
  458.     if (jt = FindSemaphore(JTName))
  459.     {
  460.         ObtainSemaphoreShared(jt);
  461.         if (memptr != NULL && size != 0L)
  462.         {
  463.             (*oldFreeMem) (memptr, size, base);
  464.         }
  465.         else
  466.         {
  467.             ULONG           ACaller = stackptr[ACALLER];
  468.             ULONG           CCaller = stackptr[CCALLER];
  469.  
  470.             Forbid();
  471.             zprintf("FreeMem(0x%lx,%ld) by `%s' (at 0x%lx) from A:0x%lx C:0x%lx SP:0x%lx\n",
  472.                     memptr, size,
  473.                     SysBase->ThisTask->tc_Node.ln_Name,
  474.                     SysBase->ThisTask,
  475.                     ACaller,
  476.                     CCaller,
  477.                     stackptr);
  478.             Permit();
  479.         }
  480.  
  481.         ReleaseSemaphore(jt);
  482.     }
  483. }
  484.  
  485. VOID ASM
  486. newSetFont(REG(a1) struct RastPort * rp,
  487.            REG(a0) struct TextFont * font,
  488.            REG(a4) ULONG * stackptr,
  489.            REG(a6) struct Library * base)
  490. {
  491.     struct SignalSemaphore *jt;
  492.  
  493.  
  494.     if (jt = FindSemaphore(JTName))
  495.     {
  496.         ObtainSemaphoreShared(jt);
  497.         if (rp != NULL && font != NULL)
  498.         {
  499.             (*oldSetFont) (rp, font, base);
  500.         }
  501.         else
  502.         {
  503.             ULONG           ACaller = stackptr[ACALLER];
  504.             ULONG           CCaller = stackptr[CCALLER];
  505.  
  506.             Forbid();
  507.             zprintf("SetFont(0x%lx,0x%lx) by `%s' (at 0x%lx) from A:0x%lx C:0x%lx SP:0x%lx\n",
  508.                     rp, font,
  509.                     SysBase->ThisTask->tc_Node.ln_Name,
  510.                     SysBase->ThisTask,
  511.                     ACaller,
  512.                     CCaller,
  513.                     stackptr);
  514.             Permit();
  515.         }
  516.         ReleaseSemaphore(jt);
  517.     }
  518. }
  519.