home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 320.lha / DiskSpeed_v2.0 / DiskSpeed.c < prev    next >
C/C++ Source or Header  |  1989-12-09  |  17KB  |  645 lines

  1. /*
  2.  *                          DiskSpeed v2.0
  3.  *                                by
  4.  *                           Michael Sinz
  5.  *
  6.  *             Copyright (c) 1989 by MKSoft Development
  7.  *
  8.  *
  9.  * Yes, this is yet another disk speed testing program, but with a few
  10.  * differences.  It was designed to give the most accurate results of the
  11.  * true disk performance in the system.  For this reason many of
  12.  * DiskSpeed's results may look either lower or higher than current disk
  13.  * performance tests.
  14.  *
  15.  * This program was thrown together in a few hours because I needed more
  16.  * accurate and consistent results for disk performance as seen from the
  17.  * application's standpoint.  This program has now served its purpose and
  18.  * I am now giving it to the rest of the Amiga world to play with as long
  19.  * as all of the files remain together in unmodified form.  (That is, the
  20.  * files DiskSpeed, DiskSpeed.info, DiskSpeed.c, DiskSpeedWindow.c,
  21.  * DiskSpeedWindow.h, MakeBoxes.c, MakeBoxes.h, StandardGadgets.c,
  22.  * StandardGadgets.h, RenderInfo.c, RenderInfo.h, DiskSpeed.doc, and
  23.  * MakeFile)
  24.  *
  25.  * Version 2.0 of this program added a few features and cleaned up the
  26.  * user interface.  I hope you like this...
  27.  *
  28.  ******************************************************************************
  29.  *                                          *
  30.  *    Reading legal mush can turn your bain into guacamole!              *
  31.  *                                          *
  32.  *        So here is some of that legal mush:                  *
  33.  *                                          *
  34.  * Permission is hereby granted to distribute this program's source          *
  35.  * executable, and documentation for non-commercial purposes, so long as the  *
  36.  * copyright notices are not removed from the sources, executable or          *
  37.  * documentation.  This program may not be distributed for a profit without   *
  38.  * the express written consent of the author Michael Sinz.              *
  39.  *                                          *
  40.  * This program is not in the public domain.                      *
  41.  *                                          *
  42.  * Fred Fish is expressly granted permission to distribute this program's     *
  43.  * source and executable as part of the "Fred Fish freely redistributable     *
  44.  * Amiga software library."                              *
  45.  *                                          *
  46.  * Permission is expressly granted for this program and it's source to be     *
  47.  * distributed as part of the Amicus Amiga software disks, and the          *
  48.  * First Amiga User Group's Hot Mix disks.                      *
  49.  *                                          *
  50.  ******************************************************************************
  51.  *
  52.  * Main code and testing sections...
  53.  */
  54.  
  55. #include    <EXEC/Types.h>
  56. #include    <EXEC/Memory.h>
  57. #include    <Intuition/Intuition.h>
  58. #include    <Libraries/DOS.h>
  59. #include    <Libraries/DOSextens.h>
  60. #include    <Graphics/RastPort.h>
  61. #include    <Devices/Timer.h>
  62.  
  63. #include    <PROTO/All.h>
  64.  
  65. #include    <string.h>
  66.  
  67. #include    "RenderInfo.h"
  68. #include    "DiskSpeedWindow.h"
  69.  
  70. extern    struct    IntuitionBase    *IntuitionBase;
  71.     struct    Library        *TimerBase;
  72.  
  73. #define    TIMESCALER        256L
  74. #define    SEEK_READ_SIZE        300L
  75.  
  76. #define    IO_BUFFER_SIZE        262144L
  77.  
  78. /* Define the file name limits for file create/delete/open/scan */
  79. #define    FINAL    'R'
  80.  
  81. static char ErrorText1[28]    ="Can't create test directory";
  82. static char ErrorText2[16]    ="Bad device name";
  83. static char ErrorText3[24]    ="Can't open results file";
  84. static char ErrorText4[19]    ="Can't open printer";
  85.  
  86. static char PrinterFile[5]    ="PRT:";
  87. static char ResultFile[18]    ="DiskSpeed.Results";
  88. static char DirectoryName[22]    =" Disk Test Directory ";
  89. static char FileNameRoot[22]    =" -- DiskTest File -- ";
  90.  
  91. static char Testing_String[10]    =">Testing<";
  92.  
  93. /* The Wait pointer I use... */
  94. USHORT __chip WaitPointer[48] =
  95. {
  96.     0x0000, 0x0000,    0x6700, 0xC700,    0xCFA0, 0xCFA0,    0xBFF0, 0x3FF0,
  97.     0x70F8, 0x7FF8,    0x7DFC, 0x7FFC,    0xFBFC, 0xFFFC,    0x70FC, 0x7FFC,
  98.     0x7FFE, 0x7FFE,    0x7F0E, 0x7FFE,    0x3FDF, 0x3FFF,    0x7FBE, 0x7FFE,
  99.     0x3F0E, 0x3FFE,    0x1FFC, 0x1FFC,    0x07F8, 0x07F8,    0x01E0, 0x01E0,
  100.     0x0780, 0x0780,    0x0FE0, 0x0FE0,    0x0740, 0x0740,    0x0000, 0x0000,
  101.     0x0070, 0x0070,    0x0078, 0x0078,    0x0030, 0x0030,    0x0000, 0x0000,
  102. };
  103.  
  104. /*
  105.  * These two defines set up and clear the WaitPointer...
  106.  */
  107. #define    SetWait(x)    SetPointer(x,WaitPointer,22L,16L,NULL,NULL)
  108. #define    ClearWait(x)    ClearPointer(x)
  109.  
  110. /*
  111.  * This does a requester on the window to tell the user something...
  112.  */
  113. VOID TellUser(struct MyWindow *MyWindow,char *Text)
  114. {
  115. register    struct    IntuiMessage    *msg;
  116. register        SHORT        flag=TRUE;
  117.  
  118.     MyWindow->ReqIText.LeftEdge=(MyWindow->Req.Width>>1)-(strlen(Text)<<2);
  119.     MyWindow->ReqIText.IText=Text;
  120.  
  121.     Request(&(MyWindow->Req),MyWindow->Window);
  122.     while (flag)
  123.     {
  124.         WaitPort(MyWindow->Window->UserPort);
  125.         while (msg=(struct IntuiMessage *)GetMsg(MyWindow->Window->UserPort))
  126.         {
  127.             if (msg->Class==GADGETUP)
  128.             {
  129.                 if (((struct Gadget *)(msg->IAddress))->GadgetID==GADGET_REQ) flag=FALSE;
  130.             }
  131.             ReplyMsg((struct Message *)msg);
  132.         }
  133.     }
  134.     EndRequest(&(MyWindow->Req),MyWindow->Window);
  135. }
  136.  
  137. /*
  138.  * Returns FALSE if the user clicked on the CLOSE gadget...
  139.  */
  140. SHORT Check_Quit(struct MyWindow *MyWindow)
  141. {
  142. register    struct    IntuiMessage    *msg;
  143. register        SHORT        flag=TRUE;
  144.  
  145.     while(msg=(struct IntuiMessage *)GetMsg(MyWindow->Window->UserPort))
  146.     {
  147.         if (msg->Class==CLOSEWINDOW) flag=FALSE;
  148.         ReplyMsg((struct Message *)msg);
  149.     }
  150.     return(flag);
  151. }
  152.  
  153. /*
  154.  * Clears a string entry to spaces...
  155.  */
  156. VOID Clear_Entry(char *String)
  157. {
  158. register    SHORT    t;
  159.  
  160.     for (t=0;t<9;t++) String[t]=' ';
  161.     String[9]='\0';
  162. }
  163.  
  164. /*
  165.  * Sets a string entry to the string >Testing< and does a
  166.  * PrintIText() to display it...
  167.  */
  168. VOID Set_Testing(SHORT ResultNum,struct MyWindow *MyWindow)
  169. {
  170.     strcpy(MyWindow->MyResults[ResultNum].text,Testing_String);
  171.     PrintIText(MyWindow->Window->RPort,&(MyWindow->MyResults[ResultNum].IntuiText),NULL,NULL);
  172. }
  173.  
  174. /*
  175.  * Sets a string entry to the value passed and does a PrintIText()
  176.  * to display it...
  177.  */
  178. VOID Set_Entry(SHORT ResultNum,LONG Value,struct MyWindow *MyWindow)
  179. {
  180. register    SHORT    t;
  181. register    SHORT    tmp;
  182. register    char    *String;
  183.  
  184.     String=MyWindow->MyResults[ResultNum].text;
  185.     Clear_Entry(String);
  186.     t=9;
  187.     while (Value)
  188.     {
  189.         tmp=Value%10;
  190.         Value=Value/10;
  191.         String[--t]=(char)(tmp)+'0';
  192.     }
  193.     if (!String[t]) String[--t]='0';
  194.     PrintIText(MyWindow->Window->RPort,&(MyWindow->MyResults[ResultNum].IntuiText),NULL,NULL);
  195. }
  196.  
  197. /*
  198.  * This gets the starting time...
  199.  */
  200. VOID Timer_Start(struct MyWindow *MyWindow)
  201. {
  202. register    struct    timerequest    *Time_Req;
  203.  
  204.     Time_Req=&(MyWindow->TimeReq);
  205.  
  206.     Time_Req->tr_node.io_Command=TR_GETSYSTIME;
  207.     Time_Req->tr_node.io_Flags=IOF_QUICK;
  208.     DoIO((struct IORequest *)Time_Req);
  209.     MyWindow->StartTime=Time_Req->tr_time;
  210. }
  211.  
  212. /*
  213.  * This gets the ending time and finds out what the per second speed is...
  214.  * It also does a RefreshGadgets() to display the text...
  215.  */
  216. VOID Timer_Stop(struct MyWindow *MyWindow,SHORT ResultNum,LONG Number)
  217. {
  218. register    struct    timerequest    *Time_Req;
  219. register        LONG        Value;
  220.  
  221.     Time_Req=&(MyWindow->TimeReq);
  222.  
  223.     Time_Req->tr_node.io_Command=TR_GETSYSTIME;
  224.     Time_Req->tr_node.io_Flags=IOF_QUICK;
  225.     DoIO((struct IORequest *)Time_Req);
  226.     MyWindow->StopTime=Time_Req->tr_time;
  227.  
  228.     SubTime(&(MyWindow->StopTime),&(MyWindow->StartTime));
  229.  
  230.     /* Now calculate Value based on Number and the time... */
  231.     Value=(Number*TIMESCALER) /
  232.         (    (MyWindow->StopTime.tv_secs*TIMESCALER) +
  233.             (MyWindow->StopTime.tv_micro/(1000000L/TIMESCALER))
  234.         );
  235.  
  236.     Set_Entry(ResultNum,Value,MyWindow);
  237. }
  238.  
  239. /*
  240.  * File create test...
  241.  * This creates a bunch of files in our test directory...
  242.  * The delete test deletes these files...
  243.  */
  244. VOID Do_FileCreate_Test(struct MyWindow *MyWindow)
  245. {
  246. register    char    *t1;
  247. register    char    *t2;
  248. register    BPTR    file;
  249. register    LONG    count=0;
  250.  
  251.     t1=FileNameRoot+1;
  252.     t2=t1+1;
  253.  
  254.     Set_Testing(RESULTS_CREATE,MyWindow);
  255.     Timer_Start(MyWindow);
  256.     for (*t1='A';*t1<FINAL;(*t1)++) for (*t2='A';*t2<FINAL;(*t2)++)
  257.     {
  258.         if (file=Open(FileNameRoot,MODE_NEWFILE)) Close(file);
  259.         count++;
  260.     }
  261.     Timer_Stop(MyWindow,RESULTS_CREATE,count);
  262. }
  263.  
  264. /*
  265.  * File Open/Close test...
  266.  * This Opens/Closes a bunch of files in our test directory...
  267.  */
  268. VOID Do_OpenClose_Test(struct MyWindow *MyWindow)
  269. {
  270. register    char    *t1;
  271. register    char    *t2;
  272. register    BPTR    file;
  273. register    LONG    count=0;
  274.  
  275.     t1=FileNameRoot+1;
  276.     t2=t1+1;
  277.  
  278.     Set_Testing(RESULTS_OPEN_CLOSE,MyWindow);
  279.     Timer_Start(MyWindow);
  280.     for (*t1='A';*t1<FINAL;(*t1)++) for (*t2='A';*t2<FINAL;(*t2)++)
  281.     {
  282.         if (file=Open(FileNameRoot,MODE_OLDFILE)) Close(file);
  283.         count++;
  284.     }
  285.     Timer_Stop(MyWindow,RESULTS_OPEN_CLOSE,count);
  286. }
  287.  
  288. /*
  289.  * Directory scan test...  This is done by scanning the directory we
  290.  * just created in the create test... (Three times...)
  291.  */
  292. VOID Do_DirScan_Test(struct MyWindow *MyWindow)
  293. {
  294. register    struct    FileInfoBlock    *FIB;
  295. register        BPTR        lock;
  296. register        LONG        count=0;
  297. register        SHORT        loop;
  298.  
  299.     lock=CurrentDir(NULL);    /* Get our directory lock... */
  300.     if (FIB=AllocMem(sizeof(struct FileInfoBlock),MEMF_PUBLIC))
  301.     {
  302.         Set_Testing(RESULTS_DIR_SCAN,MyWindow);
  303.         Timer_Start(MyWindow);
  304.         for (loop=0;loop<3;loop++)
  305.         {
  306.             Examine(lock,FIB);
  307.             while (ExNext(lock,FIB)) count++;
  308.         }
  309.         Timer_Stop(MyWindow,RESULTS_DIR_SCAN,count);
  310.  
  311.         FreeMem(FIB,sizeof(struct FileInfoBlock));
  312.     }
  313.     CurrentDir(lock);    /* Return the locked directory... */
  314. }
  315.  
  316. /*
  317.  * File delete test...  We delete the files created in the create test...
  318.  */
  319. VOID Do_FileDelete_Test(struct MyWindow *MyWindow)
  320. {
  321. register    char    *t1;
  322. register    char    *t2;
  323. register    LONG    count=0;
  324.  
  325.     t1=FileNameRoot+1;
  326.     t2=t1+1;
  327.  
  328.     Set_Testing(RESULTS_DELETE,MyWindow);
  329.     Timer_Start(MyWindow);
  330.     for (*t1='A';*t1<FINAL;(*t1)++) for (*t2='A';*t2<FINAL;(*t2)++)
  331.     {
  332.         DeleteFile(FileNameRoot);
  333.         count++;
  334.     }
  335.     Timer_Stop(MyWindow,RESULTS_DELETE,count);
  336. }
  337.  
  338. /*
  339.  * This does the seek/read test...
  340.  */
  341. VOID Do_SeekRead_Test(struct MyWindow *MyWindow,char *Buffer)
  342. {
  343. register    short    t;
  344. register    LONG    count=0;
  345. register    LONG    pos;
  346. register    BPTR    bigfile;
  347.  
  348.     if (bigfile=Open(FileNameRoot,MODE_NEWFILE))
  349.     {
  350.         Set_Testing(RESULTS_SEEK_READ,MyWindow);
  351.         Write(bigfile,Buffer,IO_BUFFER_SIZE);
  352.         Timer_Start(MyWindow);
  353.         for (t=0;t<200;t++)
  354.         {
  355.             Seek(bigfile,0L,OFFSET_BEGINNING);
  356.             Read(bigfile,Buffer,SEEK_READ_SIZE);
  357.             count++;
  358.  
  359.             pos=Seek(bigfile,-(2*SEEK_READ_SIZE),OFFSET_END);
  360.             Read(bigfile,Buffer,SEEK_READ_SIZE);
  361.             count++;
  362.  
  363.             Seek(bigfile,-(pos>>1),OFFSET_CURRENT);
  364.             Read(bigfile,Buffer,SEEK_READ_SIZE);
  365.             count++;
  366.         }
  367.         Timer_Stop(MyWindow,RESULTS_SEEK_READ,count);
  368.         Close(bigfile);
  369.         DeleteFile(FileNameRoot);
  370.     }
  371. }
  372.  
  373. /*
  374.  * This does the testing at a set buffer size...
  375.  */
  376. SHORT Do_File_Test(LONG BufSize,struct MyWindow *MyWindow,UBYTE *Buffer,SHORT ResultNum)
  377. {
  378. register    SHORT    flag=TRUE;
  379. register    SHORT    t;
  380. register    SHORT    loop;
  381. register    LONG    count;
  382. register    LONG    numblocks;
  383. register    BPTR    bigfile;
  384.  
  385.     if (bigfile=Open(FileNameRoot,MODE_NEWFILE))
  386.     {
  387.         numblocks=IO_BUFFER_SIZE/BufSize;
  388.         if (flag&=Check_Quit(MyWindow))
  389.         {
  390.             count=0;
  391.             Set_Testing(ResultNum,MyWindow);
  392.             Timer_Start(MyWindow);
  393.             for (t=0;t<(1<<(MyWindow->TestFlag));t++)
  394.             {
  395.                 Close(bigfile);
  396.                 bigfile=Open(FileNameRoot,MODE_NEWFILE);
  397.                 for (loop=0;loop<numblocks;loop++) count+=Write(bigfile,Buffer,BufSize);
  398.             }
  399.             Timer_Stop(MyWindow,ResultNum++,count);
  400.         }
  401.         if (flag&=Check_Quit(MyWindow))
  402.         {
  403.             count=0;
  404.             Set_Testing(ResultNum,MyWindow);
  405.             Timer_Start(MyWindow);
  406.             for (t=0;t<(2<<(MyWindow->TestFlag));t++)
  407.             {
  408.                 Seek(bigfile,NULL,OFFSET_BEGINNING);
  409.                 for (loop=0;loop<numblocks;loop++) count+=Write(bigfile,Buffer,BufSize);
  410.             }
  411.             Timer_Stop(MyWindow,ResultNum++,count);
  412.         }
  413.         if (flag&=Check_Quit(MyWindow))
  414.         {
  415.             count=0;
  416.             Set_Testing(ResultNum,MyWindow);
  417.             Timer_Start(MyWindow);
  418.             for (t=0;t<(3<<(MyWindow->TestFlag));t++)
  419.             {
  420.                 Seek(bigfile,NULL,OFFSET_BEGINNING);
  421.                 for (loop=0;loop<numblocks;loop++) count+=Read(bigfile,Buffer,BufSize);
  422.             }
  423.             Timer_Stop(MyWindow,ResultNum++,count);
  424.         }
  425.         Close(bigfile);
  426.         DeleteFile(FileNameRoot);
  427.     }
  428.     return(flag);
  429. }
  430.  
  431. /*
  432.  * This is the master test routine...  It calles the ones above...
  433.  */
  434. VOID Do_Disk_Test(struct MyWindow *MyWindow)
  435. {
  436. register        BPTR    lock;
  437. register        BPTR    mydir;
  438. register        SHORT    flag=TRUE;
  439. register        UBYTE    *Buffer;
  440. register        SHORT    loop;
  441. register    struct    Gadget    *gad;
  442.  
  443.     for (loop=0;loop<NUM_GADGETS;loop++)
  444.     {
  445.         gad=&(MyWindow->MyGadgets[loop].Gadget);
  446.         RemoveGadget(MyWindow->Window,gad);
  447.         gad->Flags|=GADGDISABLED;
  448.         AddGadget(MyWindow->Window,gad,NULL);
  449.         RefreshGList(gad,MyWindow->Window,NULL,1L);
  450.     }
  451.  
  452.     if (lock=Lock(MyWindow->DeviceName,ACCESS_READ))
  453.     {
  454.         lock=CurrentDir(lock);
  455.         if (mydir=CreateDir(DirectoryName))
  456.         {
  457.             mydir=CurrentDir(mydir);
  458.  
  459.             for (loop=0;loop<NUM_RESULTS;loop++)
  460.             {
  461.                 Clear_Entry(MyWindow->MyResults[loop].text);
  462.             }
  463.             RefreshGList(&(MyWindow->Detail),MyWindow->Window,NULL,1L);
  464.  
  465.             if (flag&=Check_Quit(MyWindow))
  466.             {
  467.                 Do_FileCreate_Test(MyWindow);
  468.                 if (flag&=Check_Quit(MyWindow)) Do_OpenClose_Test(MyWindow);
  469.                 if (flag&=Check_Quit(MyWindow)) Do_DirScan_Test(MyWindow);
  470.                 Do_FileDelete_Test(MyWindow);
  471.             }
  472.             if (Buffer=AllocMem(IO_BUFFER_SIZE,MEMF_PUBLIC))
  473.             {
  474.                 if (flag&=Check_Quit(MyWindow)) Do_SeekRead_Test(MyWindow,Buffer);
  475.  
  476.                 if (flag&=Check_Quit(MyWindow)) flag&=Do_File_Test(512L,MyWindow,Buffer,RESULTS_512_CREATE);
  477.                 if (flag&=Check_Quit(MyWindow)) flag&=Do_File_Test(4096L,MyWindow,Buffer,RESULTS_4096_CREATE);
  478.                 if (flag&=Check_Quit(MyWindow)) flag&=Do_File_Test(32768L,MyWindow,Buffer,RESULTS_32768_CREATE);
  479.                 if (flag&=Check_Quit(MyWindow)) flag&=Do_File_Test(262144L,MyWindow,Buffer,RESULTS_262144_CREATE);
  480.  
  481.                 FreeMem(Buffer,IO_BUFFER_SIZE);
  482.             }
  483.  
  484.             mydir=CurrentDir(mydir);
  485.             UnLock(mydir);
  486.             DeleteFile(DirectoryName);
  487.         }
  488.         else
  489.         {    /* Tell user he messed up... */
  490.             TellUser(MyWindow,ErrorText1);
  491.         }
  492.  
  493.         lock=CurrentDir(lock);
  494.         UnLock(lock);
  495.     }
  496.     else
  497.     {    /* Tell user he messed up... */
  498.         TellUser(MyWindow,ErrorText2);
  499.     }
  500.  
  501.     for (loop=0;loop<NUM_GADGETS;loop++)
  502.     {
  503.         gad=&(MyWindow->MyGadgets[loop].Gadget);
  504.         RemoveGadget(MyWindow->Window,gad);
  505.         gad->Flags&=~GADGDISABLED;
  506.         AddGadget(MyWindow->Window,gad,NULL);
  507.     }
  508.     RefreshGadgets(gad,MyWindow->Window,NULL);
  509. }
  510.  
  511. /*
  512.  * This function will open the file, append to the end of it the
  513.  * test results and close it...
  514.  */
  515. VOID Save_To_File(struct MyWindow *MyWindow)
  516. {
  517. register    BPTR    TheFile;
  518.  
  519.  
  520.     TheFile=Open(ResultFile,MODE_OLDFILE);
  521.     if (!TheFile) TheFile=Open(ResultFile,MODE_NEWFILE);
  522.     if (TheFile)
  523.     {
  524.         Seek(TheFile,0L,OFFSET_END);
  525.         Write_Results(MyWindow,TheFile);
  526.         Close(TheFile);
  527.     }
  528.     else
  529.     {    /* Tell the user the file did not open... */
  530.         TellUser(MyWindow,ErrorText3);
  531.     }
  532. }
  533.  
  534. /*
  535.  * This function will open the printer, append to the end of it the
  536.  * test results and close it...
  537.  */
  538. VOID Save_To_Printer(struct MyWindow *MyWindow)
  539. {
  540. register    BPTR    TheFile;
  541.  
  542.     if (TheFile=Open(PrinterFile,MODE_NEWFILE))
  543.     {
  544.         Write_Results(MyWindow,TheFile);
  545.         Close(TheFile);
  546.     }
  547.     else
  548.     {    /* Tell the user the file did not open... */
  549.         TellUser(MyWindow,ErrorText4);
  550.     }
  551. }
  552.  
  553. VOID main(VOID)
  554. {
  555. register    struct    MyWindow    *MyWindow;
  556. register    struct    Window        *Window;
  557. register    struct    IntuiMessage    *msg;
  558. register    struct    Gadget        *gad;
  559. register    struct    timerequest    *Time_Req;
  560. register        SHORT        QuitFlag=0;
  561. register    struct    Process        *pr;
  562. register        APTR        Old_WindowPtr;
  563. register        SHORT        loop;
  564.         struct    RenderInfo    RenderInfo;
  565.  
  566.     pr=(struct Process *)FindTask(NULL);
  567.     Old_WindowPtr=pr->pr_WindowPtr;
  568.     pr->pr_WindowPtr=(APTR)(-1);
  569.  
  570.     if (IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",33L))
  571.     {
  572.         FillIn_RenderInfo(&RenderInfo);
  573.         if (MyWindow=OpenMyWindow(&RenderInfo))
  574.         {
  575.             Window=MyWindow->Window;
  576.             Time_Req=&(MyWindow->TimeReq);
  577.             if (!OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)Time_Req,NULL))
  578.             {
  579.                 Time_Req->tr_node.io_Message.mn_ReplyPort=Window->UserPort;
  580.                 TimerBase=(struct Library *)Time_Req->tr_node.io_Device;
  581.                 while (!QuitFlag)
  582.                 {
  583.                     WaitPort(Window->UserPort);
  584.                     if (msg=(struct IntuiMessage *)GetMsg(Window->UserPort))
  585.                     {
  586.                         if (msg->Class==CLOSEWINDOW) QuitFlag=TRUE;
  587.                         else if (msg->Class==ACTIVEWINDOW) ActivateGadget(&(MyWindow->DeviceGadget),Window,NULL);
  588.                         else if (msg->Class==GADGETDOWN)
  589.                         {
  590.                             gad=(struct Gadget *)msg->IAddress;
  591.                             if (gad->Flags & SELECTED)
  592.                             {
  593.                                 MyWindow->TestFlag=gad->GadgetID;
  594.                                 for (loop=0;loop<3;loop++)
  595.                                 {
  596.                                     gad=&(MyWindow->MyGadgets[loop].Gadget);
  597.                                     if (MyWindow->TestFlag!=gad->GadgetID)
  598.                                     {
  599.                                         if (gad->Flags & SELECTED)
  600.                                         {
  601.                                             RemoveGadget(Window,gad);
  602.                                             gad->Flags&=~SELECTED;
  603.                                             AddGadget(Window,gad,NULL);
  604.                                             RefreshGList(gad,Window,NULL,1L);
  605.                                         }
  606.                                     }
  607.                                 }
  608.                             }
  609.                             else
  610.                             {
  611.                                 RemoveGadget(Window,gad);
  612.                                 gad->Flags|=SELECTED;
  613.                                 AddGadget(Window,gad,NULL);
  614.                                 RefreshGList(gad,Window,NULL,1L);
  615.                             }
  616.                         }
  617.                         else if (msg->Class==GADGETUP)
  618.                         {
  619.                             SetWait(Window);
  620.                             gad=(struct Gadget *)msg->IAddress;
  621.                             switch (gad->GadgetID)
  622.                             {
  623.                             case GADGET_STRING:    ActivateGadget((struct Gadget *)gad->UserData,Window,NULL);
  624.                                         break;
  625.                             case GADGET_START:    Do_Disk_Test(MyWindow);
  626.                                         break;
  627.                             case GADGET_SAVE:    Save_To_File(MyWindow);
  628.                                         break;
  629.                             case GADGET_PRINT:    Save_To_Printer(MyWindow);
  630.                                         break;
  631.                             }
  632.                             ClearWait(Window);
  633.                         }
  634.                         ReplyMsg((struct Message *)msg);
  635.                     }
  636.                 }
  637.                 CloseDevice((struct IORequest *)Time_Req);
  638.             }
  639.             CloseMyWindow(MyWindow);
  640.         }
  641.         CloseLibrary((struct Library *)IntuitionBase);
  642.     }
  643.     pr->pr_WindowPtr=Old_WindowPtr;
  644. }
  645.