home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 300-399 / ff312.lzh / TrackSalve / Source / main.c < prev    next >
C/C++ Source or Header  |  1990-02-12  |  23KB  |  746 lines

  1. /*                 TrackSalve   -    main.c
  2.  
  3. TrackSalve can be separated into two parts.  The patches of Trackdisk and the
  4. part that controls it.  Because of some compiling problems all patches are
  5. gathered into one large file named patches.a. All other sources belong to the
  6. controlling part.  Most obvious controlling is covered by this file main.c.
  7.  
  8. The patch exists of an allocation of memory to merge our code and Trackdisk
  9. into.  Two functions use a buffer of 26k.  These resources are accessable from
  10. here, we allocate them, and from one to four Trackdisk unit tasks.  These
  11. accesses can interfere in very bad ways, so we have to protect them.  This is
  12. done with semaphores.  The memory in which Trackdisk is executed is protected
  13. by a semaphore that once installed, never will leave us anymore.  It is used
  14. under the name Hook and exists of a TSHook structure.  It is also used as an
  15. anchor in the system.  Any subsequent execution of the controlling task can
  16. find the hook with FindSemaphore(). Another semaphore regulates the usage of
  17. the salve/verify buffer, which is shared by all units.
  18.  
  19. Installing the patch exists of some clearly distinguishable stages:
  20.  
  21. The allocation of the memory in which the patched TD unit tasks will run.  It
  22. takes about 10k bytes fast memory.  This memory is descripted by a structure
  23. named TSControl.  All members begin with TSC_. The begin contains some arrays,
  24. whose elements are data structures used by the different unit tasks.  Then
  25. there are some global variables, like which units use what resources and the
  26. salve buffer semaphore.  Here after begins an area in which the extension code
  27. is copied into, directly followed by the copy of Trackdisk code.
  28.  
  29. Now that we have the TSControl structure we must furnish it.  We copy the
  30. extension code into it.  This code is not completely position independent, and
  31. must be relocated.  Then Trackdisk code is copied tight hereafter.  Trackdisk
  32. also is not position indepent, and must be relocated too.  The last
  33. modification is the installation of the patches.
  34.  
  35. The code is ready to be executed, but it takes more than just adding an offset
  36. to the PC of the unit we want to patch.  We must catch the unit in its highest
  37. taskloop, otherwise a rts would pull a ROM-adress from the stack, and we lose
  38. the PC again.  Fortunately TD has a small toplevel task loop with a point where
  39. the PC will be most of its time.  We will switch PC only if the unit task is
  40. here (waiting()). This has an additional benefit:  we can let the unit do some
  41. special initialisation.  We donot want to spend our resources to uncatchable
  42. units, so we spend some time catching and if not successful we print some error
  43. message and delete the request.
  44.  
  45. If we want a unit to go back to ROM, it is not enough to catch the PC again and
  46. put it back.  If f.e. readonly is selected, that must be undone before the PC
  47. can go back.  Therefore we TELL the unit to go back.  Then it has time to clean
  48. up. But what if it was the last unit that executed in RAM?  Forget the 10k?
  49. No, it has to cleanup the TSControl structure as well.  Tricky bussiness
  50. freeing currently executed memory.  A nice exercise!  WE must be able to free
  51. the structure as well.  If we did not catch any unit, we must cleanup the
  52. TSControl structure ourselves.  So all involved tasks can free about
  53. everything.  This must be arranged very careful.  If we get GURU $81000009, we
  54. know we were not careful enough.
  55.  
  56. For each unit there is a data area available.  It is organised as the UnitData
  57. structure.  These are part of the TSControl structure.  That way we donot have
  58. to allocate it individually and handle involved errors.  The structure contains
  59. data as an IORequest, the ROM-PC, the address of the TSControl structure, some
  60. data fields used in the patch and a command byte:  UD_Cmd1. Its a byte in which
  61. we tell a unit what to do and what not.
  62.  
  63. The task control block has a member TC_UserData.  This is not used by a TD
  64. unit.  We use it to store a pointer to our UnitData structure.  There is
  65. another member we can use:  UNIT_pad.  UNIT_pad is a byte that should be the
  66. same as the UD_Cmd1. While it is not, TD will take actions to achieve that.
  67. More about this in patch.a.
  68.  
  69. The commandline is scanned and all commands are collected but not executed.
  70. Commands are initially gathered in UD_Cmd0. If no error is found in the
  71. commandline, the commands are passed from UD_Cmd0 to UD_Cmd1, thus passing them
  72. to the unit tasks.  Before we can do so, we have done an OpenDevice() for each
  73. unit.  Now it is known which units are available.  If a unit is not
  74. transferred, a CloseDevice() is done with it.  We have two reasons to do an
  75. OpenDevice(). First to find its data area (io_Unit) and TCB
  76. (io_Message.mn_ReplyPort->mp_SigTask). Second we donot want a real
  77. CloseDevice(), deleting the patched unit task before we can perform our
  78. cleanups. (And what if the unit was already closed, huh?)
  79.  
  80. All messages are stored in a buffer and printed later.  This program can hold
  81. up Trackdisk tasks and must not be blocked by malfunctioning output.
  82.  
  83. */
  84.  
  85.  
  86. #include <exec/types.h>
  87. #include <exec/memory.h>
  88. #include <exec/resident.h>
  89. #include <exec/execbase.h>
  90. #include <exec/semaphores.h>
  91. #include <devices/trackdisk.h>
  92. #include <string.h>
  93. #include "ts.h"
  94. #include <proto/exec.h>
  95. #pragma syscall FindSemaphore 252 901        /*  Use a1 instead of a0  */
  96. #include <string.h>
  97.  
  98.  
  99. #define btst(a,b) ((1<<a)&b)
  100. #define bset(a,b) (b|=1<<a)
  101. #define bclr(a,b) (b&=~(1<<a))
  102.  
  103. extern struct Resident *FindResident();
  104. extern char *strcpy();
  105. extern char *TSCodeBegin();                     /*  Not a function but begin of extension code                  */
  106. extern LONG R2;                                 /*  Secondary result code  (Why uses it)                        */
  107. extern char Cr[];                               /*  Creation/Version line                                       */
  108. extern ULONG TSCodeSize;                        /*  Size of extension code (should be a constant)               */
  109. extern ULONG BufferSize;                        /*  Size of a chip buffer used for tracksalvage and verify      */
  110. extern void TSPatchTable();                     /*  Not realy a function but data in a code hunk                */
  111. extern struct ExecBase *SysBase;
  112. extern ULONG TSVersion;                         /*  Perhaps generations are not compatible, check it!           */
  113.  
  114. int  __regargs PatchMem(struct Resident *, void (*)());
  115. int  __regargs XCommands(int, char *[], struct TSHook *);
  116. int  __regargs Help(int, char *[]);
  117. int  __regargs ScanCmdLine(int, char *[], struct TSControl *);
  118. int  __regargs PCtoTS(struct UnitData *);
  119. int  __regargs ShowTS(struct TSControl *);
  120. void __regargs ConMsg(char *);
  121. void __regargs RelocateTS(struct TSControl *);
  122. void __regargs RelocateTD(struct TSControl *);
  123. void __regargs AddLine(char *, char *);
  124. void __regargs AddStr(char *);
  125.  
  126. struct TSControl *AllocTSControl();
  127.  
  128.  
  129. #define MSGBUFSIZE 750                          /*  Little careful with this, stack checking is disabled        */
  130.  
  131. char *OP;                                       /*  Pointer into the message buffer                             */
  132. char *Pr;                                       /*  Program name from the commandline                           */
  133. LONG R2a;                                       /*  Error from subs which return a pointer                      */
  134. struct Library *IntuitionBase;                  /*  We find Intuition for the unit tasks  (Requesters)          */
  135.  
  136. char             TDName[]=TD_NAME;
  137. char    TSSemaphoreName[]=TSSEMAPHORENAME;
  138. char             LowMem[]="Did not get memory";
  139. char            *Number[]={ "0","1","2","3" };
  140.  
  141.  
  142. /*********************************************************
  143.  *
  144.  *  main
  145.  *
  146.  *  Scan the commandline for the help command.  If found print the text and leave.
  147.  *  Set up a buffer to collect all output.  Find or create the semaphore that controls
  148.  *  access to the TSControl structure.  Call XCommands and print the buffer.
  149.  *
  150.  *  Input:      argc and argv
  151.  *
  152.  *  Return:     ZERO or return value from XCommands()
  153.  *
  154.  */
  155.  
  156. __stdargs main(argc,argv)
  157. int argc;
  158. char *argv[];
  159. {
  160.   struct TSHook *Hook;
  161.   int RVal;
  162.   char OutBuf[MSGBUFSIZE];      /* Buffer on the stack */
  163.  
  164.   OP=OutBuf;                    /* Init bufferpointer  */
  165.   *OP='\0';
  166.   Pr=argv[0];                   /* Adapt programname from the commandline (WB already in startup disabled) */
  167.  
  168.   if (Help(argc,argv))          /* Scan cmdline for help function  */
  169.     return(ZERO);
  170.  
  171.  /*
  172.   *  Why spend time to protect this program against people who try to mess things up?
  173.   *  Anyway, protect the creation of the Semaphore against doublure by disabling
  174.   *  taskswitching during search, creation and instalation.
  175.   */
  176.  
  177.   Forbid();
  178.   if (!(Hook=(struct TSHook *)FindSemaphore(TSSemaphoreName))){
  179.     if (!(Hook=(struct TSHook *)AllocMem(sizeof(struct TSHook)+sizeof(TSSemaphoreName),PUBCLR))){
  180.       AddLine(LowMem,0);
  181.       R2=E_ALLOCMEM;
  182.       RVal=FAILURE;
  183.     } else{
  184.       Hook->TSH_Semaphore.ss_Link.ln_Name=strcpy((char *)Hook+sizeof(struct TSHook),TSSemaphoreName);
  185.       InitSemaphore((struct SignalSemaphore *)Hook);
  186.       Enqueue(&SysBase->SemaphoreList,(struct Node *)Hook);
  187.     }
  188.   }
  189.   Permit();
  190.  
  191.  /*
  192.   *  Get exclusive right to modify the Hook and its attachments.  Check for commands to perform.
  193.   */
  194.  
  195.   if (Hook){
  196.     ObtainSemaphore((struct SignalSemaphore *)Hook);
  197.     RVal=XCommands(argc,argv,Hook);
  198.     ReleaseSemaphore((struct SignalSemaphore *)Hook);
  199.   }
  200.  
  201.   if (RVal>SERIOUS)
  202.     AddLine("NB! No commands passed or executed!",0);
  203.   Write(Output(),OutBuf,strlen(OutBuf));
  204.   return(RVal);
  205. }
  206.  
  207.  
  208. /*********************************************************
  209.  *
  210.  *  XCommands
  211.  *
  212.  *  Build the TSControl structure if it does not exist.  Open all possible
  213.  *  Trackdisk devices and scan the command line for commands for them to perform.
  214.  *  Let selected TD units execute in RAM.  Allocate the salve buffer if needed.
  215.  *  Release all unused resources and print a status report.
  216.  *
  217.  *  Input:      argc, argv and Hook
  218.  *
  219.  *  Return:     ZERO, WARNING, SERIOUS and FAILURE
  220.  *
  221.  */
  222.  
  223. int __regargs XCommands(argc,argv,Hook)
  224. register int argc;
  225. char *argv[];
  226. struct TSHook *Hook;
  227. {
  228.   register struct TSControl *Control;
  229.   register struct UnitData *UD;
  230.   register short i;
  231.   register char Collect;
  232.   int RVal=ZERO;
  233.  
  234.   Control=Hook->TSH_TSControl;
  235.  
  236.  /*
  237.   *  Check the version number of the anchor.  If TD is patched and it is not ours, return
  238.   *  with some message.
  239.   */
  240.  
  241.   if (Control){
  242.     if (Hook->TSH_Version!=TSVersion){
  243.       AddLine("Another version of TrackSalve is already active",0);
  244.       return(FAILURE);
  245.     }
  246.   } else   Hook->TSH_Version=TSVersion;
  247.  
  248.  /*
  249.   *  If the command line has no arguments we just print the present situation.
  250.   */
  251.  
  252.   if (argc==1)   return(ShowTS(Control));
  253.  
  254.  /*
  255.   *  If there is not yet a TSControl structure, build one and connect it with the Hook
  256.   */
  257.  
  258.   if (!Control){
  259.     Control=Hook->TSH_TSControl=AllocTSControl();
  260.     R2=R2a;
  261.     if (!Control)  return(FAILURE);
  262.     Control->TSC_TSHook=Hook;
  263.   }
  264.  
  265.  /*
  266.   *  We have two arrays in the TSControl structure. One is an array of UnitData structures
  267.   *  and the other is an array of pointers to them.  If the pointer is zero, the unit is
  268.   *  closed and we try to open it.  In that case the unit will run in ROM and does not
  269.   *  execute special functions.  So we init UD_Cmd0 and UD_Cmd1 to 0.  If the OpenDevice()
  270.   *  fails the pointer stays zero.  If the pointer was not zero, the unit is already open
  271.   *  and it executes already in RAM.  In that case we are interested in its current
  272.   *  commands and copy them from UD_Cmd1 to UD_Cmd0.
  273.   *  We will not do any IO with the units, therefore our IORquest does not need a port.
  274.   */
  275.  
  276.   Control->TSC_AvailUnits=0;
  277.   for (i=0;i<NUMUNITS;++i){
  278.     if (UD=Control->TSC_UnitData[i]){
  279.       UD->UD_Cmd0=UD->UD_Cmd1;
  280.     } else{
  281.       UD=&Control->TSC_UDAlloc[i];
  282.       if (!OpenDevice(TDName,i,(struct IORequest *)&UD->UD_TDReq,TDF_ALLOW_NON_3_5)){
  283.         Control->TSC_UnitData[i]=UD;
  284.         UD->UD_Cmd0=UD->UD_Cmd1=0;
  285.       } else  UD=0;
  286.     }
  287.     if (UD)   bset(i,Control->TSC_AvailUnits);
  288.   }
  289.  
  290.  /*
  291.   *  Scan the commandline and translate commandline arguments into real commands in UD_Cmd0.
  292.   *  If no serious cmdline error is met, pass for each existing unit UD_Cmd0 to UD_Cmd1.
  293.   *  If an unit has special functions to execute, but is not yet in RAM, see that that is
  294.   *  done.  If not successful print a message and clear its commands as a signal to close
  295.   *  the device again (later).  If a unit is in RAM, but its UD_Cmd1 is empty, set the
  296.   *  F_TERM flag in it.  This will bring the unit to clean up and go back to ROM.
  297.   */
  298.  
  299.   if (RVal=ScanCmdLine(argc,argv,Control)){
  300.     R2=E_CMDLINE;
  301.     if (RVal>SERIOUS) return(RVal);
  302.   }
  303.  
  304.  
  305.   for (Collect=0,i=0;i<NUMUNITS;++i){
  306.     if (UD=Control->TSC_UnitData[i]){
  307.  
  308.       if ((UD->UD_Cmd1=UD->UD_Cmd0)&FUNCTIONS){
  309.         if (!btst(i,Control->TSC_InUse)){
  310.           if (PCtoTS(UD)){
  311.             AddLine("Cannot find trackdisk task for unit ",Number[i]);
  312.             UD->UD_Cmd1=0;
  313.             RVal=SERIOUS;
  314.           }
  315.         }
  316.         Collect|=UD->UD_Cmd1;
  317.       } else{
  318.         if (btst(i,Control->TSC_InUse)){
  319.           UD->UD_Cmd1=F_TERM;
  320.         }
  321.       }
  322.  
  323.     }/*Unit is open*/
  324.   }/*For every possible unit*/
  325.  
  326.  
  327.  /*
  328.   *  If any unit has its salve function active and there is not yet a buffer, try
  329.   *  to allocate it.
  330.   */
  331.  
  332.   if ((Collect&(F_SALVE+F_VERIFY))&&!Control->TSC_Buffer)
  333.     if (!(Control->TSC_Buffer=AllocMem(BufferSize,MEMF_CHIP)))   RVal=SERIOUS;
  334.  
  335.  
  336.  /*
  337.   *  Close all devices which are open but not executed in RAM, and clear their pointers.
  338.   */
  339.  
  340.   for (i=0;i<NUMUNITS;++i){
  341.     if ((!btst(i,Control->TSC_InUse))&&(UD=Control->TSC_UnitData[i])){
  342.       if (UD->UD_TDReq.iotd_Req.io_Device>0)
  343.         CloseDevice((struct IORequest *)&UD->UD_TDReq);
  344.       Control->TSC_UnitData[i]=0;
  345.     }
  346.   }
  347.  
  348.  /*
  349.   *  Free TSCcontrol structure if no users of it and untie it from the hook.
  350.   */
  351.  
  352.   if (!Control->TSC_InUse){
  353.     CloseLibrary(IntuitionBase);
  354.     FreeMem(Control,Control->TSC_Size);
  355.     Hook->TSH_TSControl=0;
  356.   }
  357.  
  358.  /*
  359.   *  Print a status report and return.
  360.   */
  361.  
  362.   ShowTS(Hook->TSH_TSControl);
  363.  
  364.   return(RVal);
  365. }
  366.  
  367.  
  368.  
  369. /*********************************************************
  370.  *
  371.  *  Help
  372.  *
  373.  *  Scan the commandline for any chars that could be a request for help.
  374.  *  If found print a apropriate message and return.
  375.  *
  376.  *  Input:      argc and argv
  377.  *
  378.  *  Return:     Non zero if help request detected and zero if not.
  379.  */
  380.  
  381. int __regargs Help(argc,argv)
  382. int argc;
  383. char *argv[];
  384. {
  385.   register int argcnt;
  386.   register char *Option;
  387.   register short avail;
  388.  
  389.   for (argcnt=1;argcnt<argc;++argcnt){
  390.     Option=argv[argcnt];
  391.     avail=1;
  392.     while (avail){
  393.       switch(*(Option++)){
  394.  
  395.         case'?':
  396.         case'h':
  397.         case'H':
  398.           if (*Option=='?')   ConMsg(Cr);
  399.           else                Explain();
  400.           return(-1);
  401.  
  402.         case'\0':
  403.           avail=0;
  404.       }
  405.     }
  406.   }
  407.  
  408.   return(0);
  409. }
  410.  
  411.  
  412. /*********************************************************
  413.  *
  414.  *  ScanCmdLine
  415.  *
  416.  *  Scan the commandline for unit numbers and commands.  Check whether unit numbers
  417.  *  select existing units.  Return FAILURE if a non-existing unit is selected unless
  418.  *  a special option us used.  Modify the UD_Cmd0 member of the selected units.
  419.  *  Unrecognised chars result in a FAILURE.
  420.  *
  421.  *  Input:      argc and argv
  422.  *              TSControl structure
  423.  *
  424.  *  Return:     ZERO if no errors detected,
  425.  *              WARNING if a special option is used together with the selection of a non existing unit
  426.  *              FAILURE if a non existing unit is selected or a command is given without a selected
  427.  *                      unit, or a not recognised command is detected.
  428.  */
  429.  
  430. int __regargs ScanCmdLine(argc,argv,Control)
  431. register int argc;
  432. char *argv[];
  433. struct TSControl *Control;
  434. {
  435.   short ArgCnt,i, UnitNr;
  436.   char *Argument, *Arg0;
  437.   UBYTE OnCmd, OffCmd, BeStrictOnUnitNumbers, Avail, CmdUnits0, CmdUnits1;
  438.   int RVal;
  439.  
  440.   RVal=0;
  441.   CmdUnits0=0;
  442.   CmdUnits1=0;
  443.   BeStrictOnUnitNumbers=1;
  444.  
  445.   for (ArgCnt=1;ArgCnt<argc;++ArgCnt){
  446.     Argument=argv[ArgCnt];
  447.     Avail=1;
  448.     while (Avail){
  449.       OnCmd=0;
  450.       OffCmd=0;
  451.       UnitNr=-1;
  452.       switch(tolower(*(Arg0=Argument++))){
  453.  
  454.         case'\0':
  455.           Avail=0;
  456.         case'\t':
  457.         case' ':
  458.         case',':
  459.         case'-':
  460.         break;
  461.  
  462.         case'a':
  463.           CmdUnits0=CmdUnits1=Control->TSC_AvailUnits;
  464.           for (i=0;i<NUMUNITS;++i){
  465.             if (btst(i,CmdUnits1))
  466.               Control->TSC_UnitData[i]->UD_Cmd0|=F_RAM;
  467.           }
  468.         break;
  469.  
  470.         case'!':
  471.           BeStrictOnUnitNumbers=0;
  472.         break;
  473.  
  474.         case'/':
  475.           CmdUnits0=0;
  476.           BeStrictOnUnitNumbers=1;
  477.         break;
  478.  
  479.         case'0':
  480.           UnitNr=0;
  481.         break;
  482.  
  483.         case'1':
  484.           UnitNr=1;
  485.         break;
  486.  
  487.         case'2':
  488.           UnitNr=2;
  489.         break;
  490.  
  491.         case'3':
  492.           UnitNr=3;
  493.         break;
  494.  
  495.         case's':
  496.           OnCmd|=F_SALVE;
  497.         break;
  498.  
  499.         case't':
  500.           OffCmd|=F_SALVE;
  501.         break;
  502.  
  503.         case'n':
  504.           OnCmd|=F_NOCLICK;
  505.         break;
  506.  
  507.         case'c':
  508.           OffCmd|=F_NOCLICK;
  509.         break;
  510.  
  511.         case'r':
  512.           OnCmd|=F_READONLY;
  513.         break;
  514.  
  515.         case'w':
  516.           OffCmd|=F_READONLY;
  517.         break;
  518.  
  519.         case'v':
  520.           OnCmd|=F_VERIFY;
  521.         break;
  522.  
  523.         case'b':
  524.           OffCmd|=F_VERIFY;
  525.         break;
  526.  
  527.         case'o':
  528.           OffCmd|=FUNCTIONS;
  529.         break;
  530.  
  531.         default:
  532.           AddLine("Not recognised: ",Arg0);
  533.           R2=E_CMDLINE;
  534.           return(FAILURE);
  535.         break;
  536.  
  537.       }
  538.  
  539.      /*
  540.       *  Check if a unit selection is made.  If so, check its presence and act accordingly.
  541.       *  If the unit exists, set its bit in CmdUnits0 and copy CmdUnits0 to CmdUnits1.
  542.       *  Set the B_RAM bit int the UD_Cmd0 of the selected unit.
  543.       */
  544.  
  545.       if (UnitNr>=0){
  546.         if (!btst(UnitNr,Control->TSC_AvailUnits)){
  547.           AddLine("Trackdisk does not control this unit: ",Number[UnitNr]);
  548.           RVal=WARNING;
  549.           R2=E_CMDLINE;
  550.           if (BeStrictOnUnitNumbers){
  551.             return(FAILURE);
  552.           }
  553.         }
  554.         bset(UnitNr,CmdUnits0);
  555.         CmdUnits1=CmdUnits0;
  556.         Control->TSC_UnitData[UnitNr]->UD_Cmd0|=F_RAM;
  557.         BeStrictOnUnitNumbers=1;
  558.       }
  559.  
  560.      /*
  561.       *  If a command is detected, delete the old unit select base so that later a new unit pattern
  562.       *  can be build.  If the pattern is empty, the command is floating, which is an error.
  563.       *  Else apply the command to the units in the pattern CmdUnits1.
  564.       */
  565.  
  566.       if (OnCmd||OffCmd){
  567.         BeStrictOnUnitNumbers=1;
  568.         CmdUnits0=0;
  569.         if (!CmdUnits1){
  570.           AddLine("Command not applied to a unit: ",Arg0);
  571.           R2=E_CMDLINE;
  572.           return(FAILURE);
  573.         }
  574.         for (UnitNr=0;UnitNr<NUMUNITS;++UnitNr){
  575.           if (btst(UnitNr,CmdUnits1)){
  576.             Control->TSC_UnitData[UnitNr]->UD_Cmd0|=OnCmd;
  577.             Control->TSC_UnitData[UnitNr]->UD_Cmd0&=~OffCmd;
  578.           }
  579.         }
  580.       }
  581.  
  582.     } /* while Avail */
  583.   } /* for ArgCnt */
  584.  
  585.   return(RVal);
  586. }
  587.  
  588.  
  589. /*********************************************************
  590.  *
  591.  *  AllocTSControl
  592.  *
  593.  *  Find the Trackdisk code in ROM, check version numbers, allocate space for
  594.  *  data and code for the patched Trackdisk tasks.  Init the structure as far
  595.  *  as possible, copy our patch extension code into it, relocate it, copy TD
  596.  *  code into it,  relocate the TD code and patch it.
  597.  *
  598.  *  Return:     TSControl structure or 0
  599.  */
  600.  
  601. struct TSControl *AllocTSControl()
  602. {
  603. struct TSControl *Control;
  604. struct Resident *TDTag;
  605. char *AllocPtr;
  606. ULONG Size, TDCodeSize;
  607. int i;
  608.  
  609.   if (!(IntuitionBase=OpenLibrary("intuition.library",0))){
  610.     AddLine("No intuition",0);
  611.     R2a=E_INTUITION;
  612.     return(0);
  613.   }
  614.  
  615.   if (!(TDTag=FindResident(TDName))){
  616.     AddLine("Did not find resident module: ",TDName);
  617.     R2a=E_RTAG;
  618.     return(0);
  619.   }
  620.   if ((TDTag->rt_Version!=TD_VERSION1_2)&&(TDTag->rt_Version!=TD_VERSION1_3)){
  621.     AddLine("Wrong Trackdisk version (not 33 or 34)",0);
  622.     R2a=E_TD_VERSION;
  623.     return(0);
  624.   }
  625.   TDCodeSize=(char *)TDTag->rt_EndSkip-(char *)TDTag->rt_MatchTag;
  626.   Size=sizeof(struct TSControl)+TSCodeSize+TDCodeSize;
  627.   if (!(AllocPtr=AllocMem(Size,PUBCLR))){
  628.     AddLine(LowMem,0);
  629.     R2a=E_ALLOCMEM;
  630.     return(0);
  631.   }
  632.   Control=(struct TSControl *)AllocPtr;
  633.   for (i=0;i<NUMUNITS;++i)
  634.     Control->TSC_UDAlloc[i].UD_TSControl=Control;
  635.   Control->TSC_IntuBase=IntuitionBase;
  636.   Control->TSC_Size=Size;
  637.   Control->TSC_TDTag=TDTag;
  638.   Control->TSC_TDCodeSize=TDCodeSize;
  639.   CopyMem((char *)TSCodeBegin,AllocPtr+=sizeof(struct TSControl),TSCodeSize);
  640.   Control->TSC_TSCode=AllocPtr;
  641.   Control->TSC_TSCodeSize=TSCodeSize;
  642.   RelocateTS(Control);
  643.   CopyMem((char *)TDTag,AllocPtr+=TSCodeSize,TDCodeSize);
  644.   Control->TSC_TSTag=(struct Resident *)AllocPtr;
  645.   RelocateTD(Control);
  646.   PatchMem(Control->TSC_TSTag,TSPatchTable);
  647.   InitSemaphore(&Control->TSC_OwnBuffer);
  648.   return(Control);
  649. }
  650.  
  651.  
  652.  
  653.  
  654. /*********************************************************
  655.  *
  656.  *  ShowTS
  657.  *
  658.  *  Build a string which shows the modifications presently active
  659.  *  on the various TD-drives.
  660.  *
  661.  *  Input:      TSConTrol structure
  662.  */
  663.  
  664. __regargs ShowTS(Control)
  665. struct TSControl *Control;
  666. {
  667.   register short i;
  668.   UBYTE Func, Collect;
  669.   int RVal=0;
  670.  
  671.   static char On[]= "    On   ";
  672.   static char Off[]="    Off  ";
  673.   static char Onf[]="  Not Yet";
  674.  
  675.   if (!Control||!Control->TSC_InUse){
  676.     AddLine("Trackdisk not patched for any drive",0);
  677.   } else{
  678.     Collect=0;
  679.     AddLine("Present situation:",0);
  680.     AddStr(" Unit    Code     Verify    Salve   NoClick  ReadOnly\n");
  681.     for (i=0;i<NUMUNITS;++i){
  682.       if (btst(i,Control->TSC_AvailUnits)){
  683.         AddStr("   ");
  684.         AddStr(Number[i]);
  685.         if (Control->TSC_UnitData[i]){
  686.           Func=Control->TSC_UnitData[i]->UD_Cmd1;
  687.           if (Func&F_TERM){
  688.             AddStr("   Terminating");
  689.           } else{
  690.             Collect|=Func;
  691.             AddStr("   Patched  ");
  692.             AddStr((Func&F_VERIFY)?(Control->TSC_Buffer?On:Onf):Off);
  693.             AddStr((Func&F_SALVE)?(Control->TSC_Buffer?On:Onf):Off);
  694.             AddStr((Func&F_NOCLICK)?On:Off);
  695.             AddStr((Func&F_READONLY)?On:Off);
  696.           }
  697.         } else{
  698.           AddStr("   Original");
  699.         }
  700.  
  701.         AddStr("\n");
  702.       }
  703.     }
  704.     if ((Collect&(F_VERIFY+F_SALVE))&&!Control->TSC_Buffer){
  705.       AddStr("Low chip memory, Salve and/or Verify functions not yet active!!\n");
  706.       RVal=SERIOUS;
  707.     }
  708.   }
  709.   return(RVal);
  710. }
  711.  
  712.  
  713. /*********************************************************
  714.  *
  715.  *  AddLine - AddStr
  716.  *
  717.  *  Copy string arguments into the stringbuffer
  718.  */
  719.  
  720. void __regargs AddLine(a,b)
  721. char *a,*b;
  722. {
  723.   AddStr(Pr);
  724.   AddStr(": ");
  725.   AddStr(a);
  726.   AddStr(b);
  727.   AddStr("\n");
  728. }
  729.  
  730.  
  731. void __regargs AddStr(a)
  732. char *a;
  733. {
  734.   static short Size=MSGBUFSIZE-2;
  735.   short Len;
  736.  
  737.   if (a){
  738.     Len=strlen(a);
  739.     if (Len<Size){
  740.       OP=stpcpy(OP,a);
  741.       Size-=Len;
  742.     }
  743.     else  Size=0;
  744.   }
  745. }
  746.