home *** CD-ROM | disk | FTP | other *** search
/ Scene Storm / Scene Storm - Volume 1.iso / coding / c / unixdirsii / source / unixdirs.c < prev   
Encoding:
C/C++ Source or Header  |  1995-11-05  |  14.9 KB  |  592 lines

  1. #include <exec/types.h>
  2. #include <exec/execbase.h>
  3. #include <exec/memory.h>
  4. #include <exec/semaphores.h>
  5. #include <dos/dos.h>
  6. #include <libraries/commodities.h>
  7. #include <string.h>
  8. #include <proto/dos.h>
  9. #include <proto/exec.h>
  10. #include <proto/commodities.h>
  11.  
  12. #define ASM __asm __saveds
  13. #define REG(x) register __## x
  14.  
  15. /*#define DEBUG*/
  16.  
  17. #ifdef DEBUG
  18. #define BEEP    DisplayBeep(NULL);
  19. #else
  20. #define BEEP
  21. #endif
  22.  
  23. /* Local protos */
  24. VOID _main(VOID);
  25. LONG ProcessMsg(void);
  26. BOOL InstallWedge(VOID);
  27. BOOL RemoveWedge(VOID);
  28. struct JumpTable *GetJumpTable(UBYTE *);
  29.  
  30. /* Libraries */
  31. extern struct ExecBase *SysBase;
  32. extern struct DosLibrary *DOSBase;
  33. struct Library *CxBase;
  34. #ifdef DEBUG
  35. struct IntuitionBase *IntuitionBase;
  36. #endif
  37. /* The number of 'replacement' functions */
  38. #define NUMBEROFFUNCTIONS (15)
  39.  
  40. /* prototypes for the functions to be SetFunction()'ed. */
  41. #define DEC_LVO(lvoname)   extern lvoname
  42.  
  43. /* declare stuff for standard one-parameter function */
  44. /* UBYTE * in d1 */
  45. #define DEC11_OLD(oldname) LONG (*ASM oldname) (REG(d1) UBYTE *, REG(a6) struct Library *base)
  46. #define DEC11_NEW(newname) LONG ASM newname(REG(d1) UBYTE *, REG(a6) struct Library *base)
  47. #define DEC11(name) DEC11_OLD(old## name); DEC11_NEW(new## name); DEC_LVO(LVO## name)
  48.  
  49. /* declare stuff for standard two-parameter function */
  50. /* UBYTE * in d1 */
  51. #define DEC21_OLD(oldname) LONG (*ASM oldname) (REG(d1) UBYTE *, REG(d2) LONG, REG(a6) struct Library *base)
  52. #define DEC21_NEW(newname) LONG ASM newname(REG(d1) UBYTE *, REG(d2) LONG, REG(a6) struct Library *base)
  53. #define DEC21(name) DEC21_OLD(old## name); DEC21_NEW(new## name); DEC_LVO(LVO## name)
  54.  
  55. /* declare stuff for standard two-parameter function */
  56. /* UBYTE * in d2 */
  57. #define DEC22_OLD(oldname) LONG (*ASM oldname) (REG(d1) LONG, REG(d2) UBYTE *, REG(a6) struct Library *base)
  58. #define DEC22_NEW(newname) LONG ASM newname(REG(d1) LONG, REG(d2) UBYTE *, REG(a6) struct Library *base)
  59. #define DEC22(name) DEC22_OLD(old## name); DEC22_NEW(new## name); DEC_LVO(LVO## name)
  60.  
  61. /* the patched functions themselves */
  62. DEC11(CreateDir);
  63. DEC11(DeleteFile);
  64. DEC11(LoadSeg);
  65. DEC21(Lock);
  66. DEC21(NewLoadSeg);
  67. DEC21(Open);
  68. DEC21(SetComment);
  69. DEC21(SetFileDate);
  70. DEC21(SetFileSize);
  71. DEC21(SetProtection);
  72. DEC22(AssignLate);
  73. DEC22(AssignPath);
  74. DEC21(MatchFirst);
  75.  
  76. /* manually decalred, because different from standard */
  77. LONG (*ASM oldRename) (REG(d1) UBYTE *, REG(d2) UBYTE *, REG(a6) struct Library *);
  78. LONG ASM newRename(REG(d1) UBYTE *, REG(d2) UBYTE *, REG(a6) struct Library *);
  79. extern LVORename;
  80.  
  81. LONG (*ASM oldParsePattern) (REG(d1) UBYTE *, REG(d2) UBYTE *, REG(d3) LONG, REG(a6) struct Library *);
  82. LONG ASM newParsePattern(REG(d1) UBYTE *, REG(d2) UBYTE *, REG(d3) LONG, REG(a6) struct Library *);
  83. extern LVOParsePattern;
  84.  
  85. /* Use a table and an array to make it a little more generic and easier to
  86.  * add functions.
  87.  */
  88. struct LVOTable
  89. {
  90.     LONG lt_LVO;
  91.     struct Library *lt_LibBase;
  92.     ULONG lt_oldFunction;
  93.     ULONG lt_newFunction;
  94. };
  95.  
  96. struct LVOTable LVOArray[] =
  97. {
  98.     {&LVOCreateDir, (struct Library *) & DOSBase, &oldCreateDir, &newCreateDir },
  99.     {&LVODeleteFile, (struct Library *) & DOSBase, &oldDeleteFile, &newDeleteFile },
  100.     {&LVOLoadSeg, (struct Library *) & DOSBase, &oldLoadSeg, &newLoadSeg },
  101.  
  102.     {&LVOLock, (struct Library *) & DOSBase, &oldLock, &newLock },
  103.     {&LVONewLoadSeg, (struct Library *) & DOSBase, &oldNewLoadSeg, &newNewLoadSeg },
  104.     {&LVOOpen, (struct Library *) & DOSBase, &oldOpen, &newOpen },
  105.  
  106.     {&LVOSetComment, (struct Library *) & DOSBase, &oldSetComment, &newSetComment },
  107.     {&LVOSetFileDate, (struct Library *) & DOSBase, &oldSetFileDate, &newSetFileDate },
  108.     {&LVOSetFileSize, (struct Library *) & DOSBase, &oldSetFileSize, &newSetFileSize },
  109.  
  110.     {&LVOSetProtection, (struct Library *) & DOSBase, &oldSetProtection, &newSetProtection },
  111.     {&LVOAssignLate, (struct Library *) & DOSBase, &oldAssignLate, &newAssignLate },
  112.     {&LVOAssignPath, (struct Library *) & DOSBase, &oldAssignPath, &newAssignPath },
  113.  
  114.     {&LVOMatchFirst, (struct Library *) & DOSBase, &oldMatchFirst, &newMatchFirst },
  115.     {&LVORename, (struct Library *) & DOSBase, &oldRename, &newRename },
  116.     {&LVOParsePattern, (struct Library *) & DOSBase, &oldParsePattern, &newParsePattern },
  117.  
  118. /*    {&LVO, (struct Library *) & DOSBase, &old, &new }*/
  119. };
  120.  
  121. struct JumpTable
  122. {
  123.     struct SignalSemaphore jt_Semaphore;
  124.     UWORD pad_word;
  125.     struct Task *jt_Owner;
  126.     UBYTE jt_Function[NUMBEROFFUNCTIONS * 6];
  127. };
  128.  
  129. /* Strings */
  130. /* The name this JumpTable/Semaphore will get. */
  131. static UBYTE *JTName = "UnixDirsII-JT";
  132. static UBYTE *VersTag = "\0$VER: UnixDirsII 1.0";
  133.  
  134. /* Commodity globals */
  135. CxObj *broker;
  136. struct MsgPort *broker_mp;
  137.  
  138. struct NewBroker newbroker =
  139. {
  140.     NB_VERSION,
  141.     "UnixDirsII",
  142.     "UnixDirsII v1.0, © Martin Scott, 1993",
  143.     "Patch DOS to use Unix-style paths",
  144.     NBU_UNIQUE | NBU_NOTIFY
  145. };
  146.  
  147. ULONG cxsigflag;
  148.  
  149. int wedged = 1;            /* initially, wedges will be in place */
  150.  
  151. VOID
  152. _main(VOID)
  153. {
  154. #ifdef DEBUG
  155.     if (IntuitionBase = OpenLibrary("intuition.library", 37L))
  156.     {
  157. #endif
  158.     if (CxBase = OpenLibrary("commodities.library", 37L))
  159.     {
  160.         if (broker_mp = CreateMsgPort())
  161.         {
  162.             newbroker.nb_Port = broker_mp;
  163.             if (broker = CxBroker(&newbroker, NULL))
  164.             {
  165.                 cxsigflag = 1L << broker_mp->mp_SigBit;
  166.                 ActivateCxObj(broker, 1L);
  167.  
  168.                 if (InstallWedge())
  169.                     while (ProcessMsg());
  170.                 DeleteCxObj(broker);
  171.  
  172.                 if (wedged)
  173.                     RemoveWedge();
  174.             }
  175.             DeleteMsgPort(broker_mp);
  176.         }
  177.         CloseLibrary(CxBase);
  178.     }
  179. #ifdef DEBUG
  180.     CloseLibrary(IntuitionBase);
  181.     }
  182. #endif
  183. }
  184.  
  185. LONG
  186. ProcessMsg(void)
  187. {
  188.     CxMsg *msg;
  189.  
  190.     ULONG sigrcvd, msgid, msgtype;
  191.     LONG returnvalue = 1L;
  192.  
  193.     /* wait for something to happen */
  194.     sigrcvd = Wait(SIGBREAKF_CTRL_C | cxsigflag);
  195.  
  196.     /* process any messages */
  197.     while (msg = (CxMsg *) GetMsg(broker_mp))
  198.     {
  199.         /* Extract necessary information from the CxMessage and return it */
  200.         msgid = CxMsgID(msg);
  201.         msgtype = CxMsgType(msg);
  202.         ReplyMsg((struct Message *) msg);
  203.  
  204.         if (msgtype == CXM_COMMAND)    /* all we care about */
  205.         {
  206.             switch (msgid)
  207.             {
  208.             case CXCMD_DISABLE:
  209.                 if (wedged)
  210.                 {
  211.                     RemoveWedge();
  212.                     wedged = 0;
  213.                 }
  214.                 ActivateCxObj(broker, 0L);
  215.                 break;
  216.  
  217.             case CXCMD_ENABLE:
  218.                 if (!wedged)
  219.                 {
  220.                     InstallWedge();
  221.                     wedged = 1;
  222.                 }
  223.                 ActivateCxObj(broker, 1L);
  224.                 break;
  225.  
  226.             case CXCMD_UNIQUE:
  227.             case CXCMD_KILL:
  228.                 returnvalue = 0L;
  229.                 break;
  230.             }
  231.         }
  232.     }
  233.  
  234.     /* Test to see if user tried to break */
  235.     if (sigrcvd & SIGBREAKF_CTRL_C)
  236.         returnvalue = 0L;
  237.  
  238.     return (returnvalue);
  239. }
  240.  
  241. BOOL
  242. InstallWedge(VOID)
  243. {
  244.     struct JumpTable *jumptable;
  245.     ULONG *addressptr;
  246.     UCOUNT i, j;
  247.  
  248.     Forbid();
  249.  
  250.     /* Get pointer to JumpTable. Create it if necessary */
  251.     if (jumptable = GetJumpTable(JTName))
  252.     {
  253.         /* Try to get exclusive lock on semaphore, in case it already existed. */
  254.         if (AttemptSemaphore((struct SignalSemaphore *) jumptable))
  255.         {
  256.             /* Make sure nobody else has function addresses in the jumptable */
  257.             if (jumptable->jt_Owner == NULL)
  258.             {
  259.                 jumptable->jt_Owner = FindTask(0);
  260.                 /* Don't want to disable any longer than necessary */
  261.                 Disable();
  262.  
  263.                 for (i = 2, j = 0; i < NUMBEROFFUNCTIONS * 6; i += 6, j++)
  264.                 {
  265.                     /* Replace addresses in the jumptable with my own. */
  266.                     addressptr = (ULONG *) ((UBYTE *) jumptable->jt_Function + i);
  267.                     (*((ULONG *) LVOArray[j].lt_oldFunction)) = (ULONG) * addressptr;
  268.                     *addressptr = (ULONG) LVOArray[j].lt_newFunction;
  269.                 }
  270.                 Enable();
  271.             } else
  272.                 PutStr("Already running.\n");
  273.             ReleaseSemaphore((struct SignalSemaphore *) jumptable);
  274.         } else
  275.             PutStr("Can't lock table.\n");
  276.     } else
  277.         PutStr("Can't create jumptable\n");
  278.     Permit();
  279.     return ((BOOL) jumptable);
  280. }
  281.  
  282. BOOL
  283. RemoveWedge(VOID)
  284. {
  285.     struct JumpTable *jumptable;
  286.     ULONG *addressptr;
  287.     UCOUNT i, j;
  288.  
  289.     Forbid();
  290.  
  291.     if (jumptable = GetJumpTable(JTName))
  292.     {
  293.         /* Check if this task owns this jumptable */
  294.         if (jumptable->jt_Owner == FindTask(0))
  295.         {
  296.  
  297.             /* Get the semaphore exclusively.
  298.                      * Depending on what got SetFunction()'ed this could take some time.
  299.                      * Also note that shared locks are used to indicate the code is
  300.                      * being executed and that shared locks can jump ahead of queue'ed
  301.                      * exclusive locks, adding to the waittime.
  302.                      */
  303.             ObtainSemaphore((struct SignalSemaphore *) jumptable);
  304.  
  305.             Disable();
  306.  
  307.             /* Restore old pointers in jumptable */
  308.  
  309.             for (i = 2, j = 0; i < NUMBEROFFUNCTIONS * 6; i += 6, j++)
  310.             {
  311.                 addressptr = (ULONG *) ((UBYTE *) jumptable->jt_Function + i);
  312.                 *addressptr = (*((ULONG *) LVOArray[j].lt_oldFunction));
  313.             }
  314.  
  315.             Enable();
  316.  
  317.             jumptable->jt_Owner = NULL;
  318.             ReleaseSemaphore((struct SignalSemaphore *) jumptable);
  319.         }
  320.     }
  321.     Permit();
  322.  
  323.     return (TRUE);
  324. }
  325.  
  326. struct JumpTable *
  327. GetJumpTable(UBYTE * name)
  328. {
  329.     struct JumpTable *jumptable;
  330.     ULONG *addressptr;
  331.     UWORD *jmpinstr;
  332.     UBYTE *jtname;
  333.     UCOUNT i, j;
  334.  
  335.     /* Not really necessary to forbid again, just to indicate that I don't
  336.          * want another task to create the semaphore while I'm trying to do the
  337.          * same. Here GetJumpTable() is only called from InstallWedge(), so it
  338.          * will just bump the forbid count.
  339.          */
  340.     Forbid();
  341.  
  342.     if (!(jumptable = (struct JumpTable *) FindSemaphore(name)))
  343.     {
  344.         if (jumptable = AllocMem(sizeof(struct JumpTable), MEMF_PUBLIC | MEMF_CLEAR))
  345.         {
  346.             if (jtname = AllocMem(strlen(name) + 1, MEMF_PUBLIC | MEMF_CLEAR))
  347.             {
  348.  
  349.                 for (i = 0, j = 0; i < NUMBEROFFUNCTIONS * 6; i += 6, j++)
  350.                 {
  351.                     jmpinstr = (UWORD *) ((UBYTE *) jumptable->jt_Function + i);
  352.                     *jmpinstr = 0x4EF9;
  353.  
  354.                     addressptr = (ULONG *) ((UBYTE *) jumptable->jt_Function + i + 2);
  355.                     *addressptr = (ULONG) SetFunction(
  356.                                          (struct Library *) (*((ULONG *) LVOArray[j].lt_LibBase)),
  357.                              LVOArray[j].lt_LVO,
  358.                                          (VOID *) ((UBYTE *) jumptable->jt_Function + i));
  359.                 }
  360.  
  361.                 jumptable->jt_Semaphore.ss_Link.ln_Pri = 0;
  362.  
  363.                 strcpy(jtname, name);
  364.                 jumptable->jt_Semaphore.ss_Link.ln_Name = jtname;
  365.                 AddSemaphore((struct SignalSemaphore *) jumptable);
  366.             } else
  367.             {
  368.                 FreeMem(jumptable, sizeof(struct JumpTable));
  369.                 jumptable = NULL;
  370.             }
  371.         }
  372.     }
  373.     Permit();
  374.  
  375.     /* If succeeded, you now have a jumptable which entries point to the original
  376.          * library functions. If another task SetFunction()'ed one or more of those
  377.          * already, that task can never go away anymore.
  378.          */
  379.     return (jumptable);
  380. }
  381.  
  382.  
  383. /******************************************************************************/
  384. /*******************                                 **************************/
  385. /*******************   NEW DOS ROUTINES START HERE   **************************/
  386. /*******************                                 **************************/
  387. /******************************************************************************/
  388.  
  389. /*
  390.  * These are the generic patch routines.
  391.  * They handle most patches automatically.
  392.  */
  393.  
  394. extern BOOL adjustpath(UBYTE *path, UBYTE *newpath, LONG len);
  395. #define PATHSIZE    512L    /* enough for most purposes? */
  396.  
  397. /* 1 args, convert arg in d1 */
  398. LONG ASM Wedge11(REG(a0) LONG (*ASM dosroutine)(REG(d1) UBYTE *, REG(a6) struct Library *),
  399.             REG(d1) UBYTE *);
  400.  
  401. LONG ASM
  402. Wedge11(REG(a0) LONG (*ASM dosroutine)(REG(d1) UBYTE *, REG(a6) struct Library *),
  403.        REG(d1) UBYTE *arg1)
  404. {
  405.     struct SignalSemaphore *jt;
  406.     UBYTE *newpath;
  407.     LONG rc = 0;
  408.  
  409.     if (jt = FindSemaphore(JTName))
  410.     {
  411.         ObtainSemaphoreShared(jt);
  412.  
  413.         if (newpath = AllocVec(PATHSIZE, 0L))
  414.         {
  415.             if (adjustpath(arg1, newpath, PATHSIZE))
  416.                 rc = dosroutine(newpath, DOSBase);
  417.             else
  418.                 rc = dosroutine(arg1, DOSBase);
  419.  
  420.             FreeVec(newpath);
  421.         }
  422.         else SetIoErr(ERROR_NO_FREE_STORE);
  423.  
  424.         ReleaseSemaphore(jt);
  425.     }
  426.     return rc;
  427. }
  428.  
  429. /* 2 args, convert arg in d1 */
  430. LONG ASM Wedge21(REG(a0) LONG (*ASM dosroutine)(REG(d1) UBYTE *, REG(d2) LONG, REG(a6) struct Library *),
  431.             REG(d1) UBYTE *, REG(d2) LONG);
  432.  
  433. LONG ASM
  434. Wedge21(REG(a0) LONG (*ASM dosroutine)(REG(d1) UBYTE *, REG(d2) LONG, REG(a6) struct Library *),
  435.        REG(d1) UBYTE *arg1, REG(d2) LONG arg2)
  436. {
  437.     struct SignalSemaphore *jt;
  438.     UBYTE *newpath;
  439.     LONG rc = 0;
  440.  
  441.     if (jt = FindSemaphore(JTName))
  442.     {
  443.         ObtainSemaphoreShared(jt);
  444.  
  445.         if (newpath = AllocVec(PATHSIZE, 0L))
  446.         {
  447.             if (adjustpath(arg1, newpath, PATHSIZE))
  448.                 rc = dosroutine(newpath, arg2, DOSBase);
  449.             else
  450.                 rc = dosroutine(arg1, arg2, DOSBase);
  451.             FreeVec(newpath);
  452.         }
  453.         else SetIoErr(ERROR_NO_FREE_STORE);
  454.  
  455.         ReleaseSemaphore(jt);
  456.     }
  457.     return rc;
  458. }
  459.  
  460. /* 2 args, convert arg in d2 */
  461. LONG ASM Wedge22(REG(a0) LONG (*ASM dosroutine)(REG(d1) LONG, REG(d2) UBYTE *, REG(a6) struct Library *),
  462.             REG(d1) LONG, REG(d2) UBYTE *);
  463.  
  464. LONG ASM
  465. Wedge22(REG(a0) LONG (*ASM dosroutine)(REG(d1) LONG, REG(d2) UBYTE *, REG(a6) struct Library *),
  466.        REG(d1) LONG arg1, REG(d2) UBYTE *arg2)
  467. {
  468.     struct SignalSemaphore *jt;
  469.     UBYTE *newpath;
  470.     LONG rc = 0;
  471.  
  472.     if (jt = FindSemaphore(JTName))
  473.     {
  474.         ObtainSemaphoreShared(jt);
  475.  
  476.         if (newpath = AllocVec(PATHSIZE, 0L))
  477.         {
  478.             if (adjustpath(arg2, newpath, PATHSIZE))
  479.                 rc = dosroutine(arg1, newpath, DOSBase);
  480.             else
  481.                 rc = dosroutine(arg1, arg2, DOSBase);
  482.  
  483.             FreeVec(newpath);
  484.         }
  485.         else SetIoErr(ERROR_NO_FREE_STORE);
  486.  
  487.         ReleaseSemaphore(jt);
  488.     }
  489.     return rc;
  490. }
  491.  
  492. #define PATCH11(name) \
  493. LONG ASM \
  494. new## name(REG(d1) UBYTE *arg1, \
  495.     REG(a6) struct Library *base) \
  496. { return Wedge11(old## name, arg1); }
  497.  
  498. #define PATCH21(name) \
  499. LONG ASM \
  500. new## name(REG(d1) UBYTE *arg1, REG(d2) LONG arg2, \
  501.     REG(a6) struct Library *base) \
  502. { return Wedge21(old## name, arg1, arg2); }
  503.  
  504. #define PATCH22(name) \
  505. LONG ASM \
  506. new## name(REG(d1) LONG arg1, REG(d2) UBYTE *arg2, \
  507.     REG(a6) struct Library *base) \
  508. { return Wedge22(old## name, arg1, arg2); }
  509.  
  510. PATCH11(CreateDir)
  511. PATCH11(DeleteFile)
  512. PATCH11(LoadSeg)
  513. PATCH21(Lock)
  514. PATCH21(NewLoadSeg)
  515. PATCH21(Open)
  516. PATCH21(SetComment)
  517. PATCH21(SetFileDate)
  518. PATCH21(SetFileSize)
  519. PATCH21(SetProtection)
  520. PATCH22(AssignLate)
  521. PATCH22(AssignPath)
  522. PATCH21(MatchFirst)
  523.  
  524. /*** And the following routines are handmade ***/
  525.  
  526. /* two to do here... */
  527. LONG ASM
  528. newRename(REG(d1) UBYTE *oldname, REG(d2) UBYTE *newname,
  529.       REG(a6) struct Library *base)
  530. {
  531.     struct SignalSemaphore *jt;
  532.     UBYTE *from, *to;
  533.     LONG rc = 0;
  534.  
  535.     if (jt = FindSemaphore(JTName))
  536.     {
  537.         ObtainSemaphoreShared(jt);
  538.  
  539.         if (from = AllocVec(PATHSIZE, 0L))
  540.         {
  541.             adjustpath(oldname, from, PATHSIZE);
  542.             if (to = AllocVec(PATHSIZE, 0L))
  543.             {
  544.                 adjustpath(newname, to, PATHSIZE);
  545.                 rc = oldRename(from, to, DOSBase);
  546.                 FreeVec(to);
  547.             }
  548.             else SetIoErr(ERROR_NO_FREE_STORE);
  549.             FreeVec(from);
  550.         }
  551.         else SetIoErr(ERROR_NO_FREE_STORE);
  552.  
  553.         ReleaseSemaphore(jt);
  554.     }
  555.     return rc;
  556. }
  557.  
  558. /* a bit more suspect this; will buflen be big enough given a . substitution? */
  559. LONG ASM
  560. newParsePattern(REG(d1) UBYTE *pat, REG(d2) UBYTE *buf, REG(d3) LONG buflen,
  561.         REG(a6) struct Library *base)
  562. {
  563.     struct SignalSemaphore *jt;
  564.     UBYTE *newpat;
  565.     LONG rc = 0;
  566.  
  567.     if (jt = FindSemaphore(JTName))
  568.     {
  569.         ObtainSemaphoreShared(jt);
  570.  
  571.         if (newpat = AllocVec(PATHSIZE, 0L))
  572.         {
  573.             adjustpath(pat, newpat, PATHSIZE);
  574.             rc = oldParsePattern(newpat, buf, buflen, DOSBase);
  575.             FreeVec(newpat);
  576.         }
  577.         else SetIoErr(ERROR_NO_FREE_STORE);
  578.  
  579.         ReleaseSemaphore(jt);
  580.     }
  581.     return rc;
  582. }
  583.  
  584. /*
  585. LONG ASM
  586. new(REG(d1) LONG arg1, REG(d2) LONG arg2,
  587.         REG(a6) struct Library *base)
  588. {
  589.     return old(arg1, arg2, base);
  590. }
  591. */
  592.