home *** CD-ROM | disk | FTP | other *** search
/ World of A1200 / World_Of_A1200.iso / programs / disk / misc / dcmp / source / source.lha / dcmp.c < prev    next >
C/C++ Source or Header  |  1993-01-23  |  79KB  |  2,488 lines

  1. /*--------------------------------------------------------------------------*
  2.            __
  3.           / /                            $RCSfile dcmp.c,v $
  4.      ____/ /______ _   _   ______        $Release 1.0$
  5.     / __/ // ____// \_/ \ / __  /        $Revision: 1.51 $
  6.    / /_/ // /___ / /__/ // /_/ /         $Date: 93/01/17 16:45:27 $
  7.   /_____//_____//_/  /_// ____/          $Author: tf $
  8.                        / /               $State: Exp $
  9.      Revision 1.51    /_/
  10.  
  11.            (c) Copyright 1992 Tobias Ferber, All Rights Reserved.
  12.  
  13.  *--------------------------------------------------------------------------*/
  14.  
  15. #include <exec/types.h>
  16. #include <exec/nodes.h>
  17. #include <exec/memory.h>
  18. #include <exec/libraries.h>
  19. #include <exec/tasks.h>
  20. #include <exec/io.h>
  21. #include <intuition/intuitionbase.h>
  22. #include <intuition/intuition.h>
  23. #include <graphics/gfxbase.h>
  24. #include <graphics/gfx.h>
  25. #include <graphics/rastport.h>
  26.  
  27. /* for wbmain() */
  28.  
  29. #include <workbench/workbench.h>
  30. #include <workbench/startup.h>
  31. #include <workbench/icon.h>
  32.  
  33. #include <stdio.h>
  34.  
  35. /* system stuff */
  36.  
  37. static struct IntuitionBase *IntuitionBase;
  38. static struct GfxBase *GfxBase;
  39. static struct Window *Window;
  40. static struct TextFont *TextFont;
  41. static struct IntuiMessage *imsg;
  42. static BOOL MenuFlag;       /* SetMenuStrip() successfull? */
  43. struct IconBase *IconBase;  /* not always opened! */
  44.  
  45. /* stuff for the req.library */
  46.  
  47. #include <libraries/dosextens.h>
  48. #include <libraries/reqbase.h>
  49.  
  50. struct ReqLib *ReqBase;
  51. static struct Process *MyProcess;
  52. static APTR OldWindowPtr;
  53.  
  54. /* stuff for the reqtools.library */
  55.  
  56. #include <libraries/reqtools.h>
  57. #include <proto/reqtools.h>
  58.  
  59. struct ReqToolsBase *ReqToolsBase;
  60.  
  61. /* pre-declarations for cdglue.o */
  62.  
  63. BOOL a_Requester();
  64. BOOL a_GetLongRequester();
  65. VOID a_FileRequester();
  66.  
  67. int dos_rkcv(), dos_rkcvinit(), dos_rkcvexit(); /* ... rkcv.o */
  68. int dcmp_Request();
  69.  
  70. /* nice.o */
  71.  
  72. extern struct Window *NiceOpenWindow();
  73. extern void NiceCloseWindow();
  74. extern UWORD NiceOpenSpeed, NiceCloseSpeed;
  75.  
  76. /*#include "crawl.h"*/
  77. #include "strfn.h"       /* string functions */
  78.  
  79. /* ---------------------------------------------------------------------- */
  80.  
  81. static char rcs_id[]="$Id: dcmp.c,v 1.51 93/01/17 16:45:27 tf Exp $";
  82. #define BANNER "-- compare two disks block by block"
  83. #define USAGE "USAGE: dcmp [-<options>] <DF0..3> [DF0..3]"
  84. char *whoami; /* argv[0]: (who am I) */
  85. #define DEF_LOGFILE "RAM:dcmp.log"
  86.  
  87. unsigned int language= 0L;    /* 0 == ENGLISH */
  88.  
  89. #include "data.h"        /* global structures (mainly intuition) */
  90. #include "td_support.h"  /* trackdisk support functions */
  91. #include "intuisup.h"    /* intuition support functions */
  92. #include "pointer.h"     /* mouse pointer support */
  93.  
  94. int dcmp_pointer= SMI_PREFS, busybee= SMI_BUSYBEE;  /* (busy) mouse pointer image */
  95.  
  96. #define DEF_ATTEMPTS 2
  97. #define MAX_ATTEMPTS 10
  98.  
  99. FILE *fp; /* file pointer for the logfile */
  100.  
  101. #define well_done    0L
  102. #define warning      1L
  103. #define error_state  2L
  104. #define fatal_error  3L
  105. #define depart       4L
  106.  
  107. #define lental   (history>error_state)
  108. #define danger   (history>warning)
  109. #define mark(x)  history=x
  110.  
  111. int history= well_done;  /* indicates program state */
  112.  
  113. /* flags for the options */
  114.  
  115. #define logfile_open (fp != (FILE *)NULL)
  116.  
  117. static BOOL write_logfile    = FALSE,  /* logfile creation desired */
  118.             write_icon       = FALSE,  /* icon creation for the logfile */
  119.             logdata_added    = FALSE,  /* logfile opened for `a'ppend */
  120.             be_quiet         = FALSE,  /* don't use printf(), puts()... */
  121.             display_window   = FALSE,  /* display data in the window */
  122.             ignore_errors    = TRUE,   /* don't break on errors */
  123.             deep_read        = FALSE;  /* don't read tracks twice */
  124.  
  125. /*
  126.  * I declare this deep_buffer pointer as global since it has to be freed
  127.  * outside of do_dcmp_stuff() in case of a ^C break.
  128.  * It is allocated in open_dcmp_stuff(), used in do_dcmp_stuff() and
  129.  * freed in close_dcmp_stuff().
  130.  */
  131.  
  132. static ULONG *deep_buffer= (ULONG *)NULL;
  133.  
  134. #define CRSR_ON  "\233\40\160\r"
  135. #define CRSR_OFF "\233\60\40\160\r"
  136.  
  137. void _abort(void) /* DICE: set this in main() via onbreak(); */
  138. {
  139.   printf("^C\n\n** BREAK\n" CRSR_ON);
  140.   mark(error_state);
  141.   wrap_up();
  142. }
  143.  
  144. #include <stdarg.h>
  145.  
  146. void inform_user(const char *fmt, ...) /* ellipse declaration */
  147. { static char *answer[]= { "Resume", "Okay", "Continuer", "Continuare" };
  148.   va_list argp;
  149.  
  150.   va_start(argp,fmt); /* name the last known argument */
  151.  
  152.   if(!be_quiet)
  153.   { fprintf(stderr, "\r%s: ",whoami);
  154.     vfprintf(stderr, fmt, argp);
  155.     fprintf(stderr, "\n");
  156.   }
  157.   else
  158.   { char msg[1024]; /* information limited to 1K */
  159.     vsprintf(msg, fmt, argp);
  160.     a_Requester(msg,NULL,answer[language]);
  161.   }
  162.   va_end(argp);   /* just to be sure... */
  163. }
  164.  
  165. /* globals += */
  166.  
  167. static int unit_r = NOUNIT,  /* first unit (read) */
  168.            unit_c = NOUNIT,  /* second unit (compare) */
  169.            start_blk = FIRSTBLOCK,   /* block to start with */
  170.            end_blk   = LASTBLOCK,    /* block to end with */
  171.            attempts  = DEF_ATTEMPTS, /* #of retries to read */
  172.  
  173.            ratt   = 0,   /* #of remaining attempts */
  174.            dblk   = 0,   /* #of differing blocks found */
  175.            dtrk   = 0,   /* ... tracks ... */
  176.            wtrk   = 0,   /* #of weak tracks found */
  177.            errcnt = 0;   /* #of errors found */
  178.  
  179. /*
  180.  * If a block differs I will write its number into this array and check
  181.  * the results later.
  182.  */
  183.  
  184. static int dblk_list[1760];
  185.  
  186. init_global_values()
  187. { int i;
  188.   for(i=0;i<=1759;dblk_list[i]=-1,i++)
  189.     ;
  190.   ratt= attempts;
  191.   dblk= 0;
  192.   dtrk= 0;
  193.   wtrk= 0;
  194.   errcnt= 0;
  195. }
  196.  
  197. /*
  198.  * cleanup procedures
  199.  */
  200.  
  201. void close_window_stuff()
  202. {
  203.   dos_rkcvexit();
  204.   if(Window)
  205.   {  if(MenuFlag) ClearMenuStrip(Window);
  206.      UnsetMouseImage(Window);
  207.      RestoreMouseColors(Window);
  208.      NiceCloseWindow(Window);
  209.   }
  210.   if(TextFont) CloseFont(TextFont);
  211.   if(ReqToolsBase) CloseLibrary(ReqToolsBase);
  212.   else if(ReqBase)
  213.   { MyProcess->pr_WindowPtr=(struct Window *)OldWindowPtr;
  214.     CloseLibrary(ReqBase);
  215.   }
  216.   if(GfxBase) CloseLibrary(GfxBase);
  217.   if(IntuitionBase) CloseLibrary(IntuitionBase);
  218. }
  219.  
  220. void close_logfile(void)
  221. { if(fp) fclose(fp);
  222.   fp= (FILE *)NULL;  /* just to be sure... */
  223. }
  224.  
  225. void close_dcmp_stuff(void)
  226. { if(deep_buffer)
  227.   { FreeMem(deep_buffer, BYTES_PER_TRACK);
  228.     deep_buffer= (ULONG *)NULL; /* just to be sure */
  229.   }
  230.   if(unit_r != NOUNIT)
  231.     close_unit(unit_r);
  232.   if(unit_c != NOUNIT && unit_c != unit_r)
  233.     close_unit(unit_c);
  234. }
  235.  
  236. /*
  237.  * close our stuff and exit()
  238.  */
  239.  
  240. int wrap_up()
  241. { if(danger)
  242.   { if(!be_quiet && history == fatal_error)
  243.       printf("\r%s: this was a fatal error, my friend!\n",whoami);
  244.     if(write_logfile && logfile_open)
  245.       fprintf(fp,"%s terminated abnormally.\n",whoami);
  246.   }
  247.   close_dcmp_stuff();
  248.   if(logfile_open) close_logfile();
  249.   if(display_window) close_window_stuff();
  250.   exit(danger?1:0);
  251. }
  252.  
  253. #define DEFAULT_PEN 1L
  254. #define DIFFER_PEN  2L
  255. #define EQUAL_PEN   3L
  256.  
  257. /*
  258.  * draw_box() -- draw a hires box with double vertical lines
  259.  */
  260.  
  261. void draw_box(rp,x,y,w,h,fpen)
  262. struct RastPort *rp;
  263. UWORD x,y,w,h;
  264. int fpen;
  265. { int dpen; /* old detail pen */
  266.   Move(rp,x,y);
  267.   Draw(rp,x,y+h);
  268.   Draw(rp,x+w,y+h);
  269.   Draw(rp,x+w,y);
  270.   Draw(rp,x+1,y);
  271.   Draw(rp,x+1,y+h);
  272.   Move(rp,x+w-1,y+h);
  273.   Draw(rp,x+w-1,y);
  274.   if(w>4 && h>2)
  275.   { dpen=rp->FgPen; /* save old APen */
  276.     SetAPen(rp,fpen);
  277.     RectFill(rp,x+2,y+1,x+w-2,y+h-1);
  278.     SetAPen(rp,dpen); /* resore it */
  279.   }
  280. }
  281.  
  282. /*
  283.  * draw a grid (track display): x=left edge, y=top edge
  284.  */
  285.  
  286. #define TRACKBOX_W  15L
  287. #define TRACKBOX_H   8L
  288.  
  289. void draw_trackframe(rp, xpos, ypos, head)
  290. struct RastPort *rp;
  291. UWORD xpos, ypos;
  292. int head;
  293. { UWORD x,y;
  294.   UWORD dx,dy;
  295.   static char nums[]= "0123456789", heads[]= "Head 0";
  296.   SetAPen(rp,DEFAULT_PEN);  /* choose a color */
  297.  
  298.   dx= xpos+TextFont->tf_XSize+5; /* xpos + width of textfont + dist. */
  299.   dy= ypos+TextFont->tf_YSize+1; /* ypos + height of textfont */
  300.  
  301.   /* draw vertical lines */
  302.  
  303.   for(x=0;x<=10;x++)
  304.   { Move(rp, dx+(TRACKBOX_W*x), dy);
  305.     Draw(rp, dx+(TRACKBOX_W*x), dy+(TRACKBOX_H*8));
  306.     /*
  307.      * since pixels width is about half of their height, we
  308.      * will draw vertical lines doubled
  309.      */
  310.     Move(rp, dx+1+(TRACKBOX_W*x), dy);
  311.     Draw(rp, dx+1+(TRACKBOX_W*x), dy+(TRACKBOX_H*8));
  312.   }
  313.  
  314.   /* draw horizontal lines */
  315.  
  316.   for(y=0;y<=8;y++)
  317.   { Move(rp, dx, dy+(TRACKBOX_H*y));
  318.     Draw(rp, dx+(TRACKBOX_W*10), dy+(TRACKBOX_H*y));
  319.   }
  320.  
  321.   /* add 3 boxes */
  322.  
  323.   for(x=0;x<3;x++)
  324.   { draw_box(rp, dx+(TRACKBOX_W*x), dy+(TRACKBOX_H*8),
  325.       TRACKBOX_W+1, TRACKBOX_H, 0L);
  326.   }
  327.  
  328.   /* add numbers to the frame */
  329.  
  330.   dx+= 5;  /* add number centering distance */
  331.   dy= ypos+TextFont->tf_Baseline; /* ypos + fontbase correction */
  332.  
  333.   for(x=0;x<=9;x++)
  334.   { Move(rp, dx+(TRACKBOX_W*x),dy);
  335.     Text(rp, &nums[x],1L);
  336.   }
  337.  
  338.   dx= xpos;    /* xpos + centering distance */
  339.   dy+=TextFont->tf_YSize+2;  /* add height of font, centering dist. */
  340.  
  341.   for(y=0;y<=8;y++)
  342.   { Move(rp, dx, dy+(TRACKBOX_H*y));
  343.     Text(rp, &nums[y],1L);
  344.   }
  345.  
  346.   /* add head number */
  347.  
  348.   dx= xpos+TextFont->tf_XSize+4+(TRACKBOX_W*5);
  349.   dy= ypos+TextFont->tf_YSize+3+(TRACKBOX_H*8)+TextFont->tf_Baseline;
  350.  
  351.   heads[5]= (char)('0' + head);
  352.   Move(rp, dx, dy);
  353.   Text(rp, heads, strlen(heads));
  354. }
  355.  
  356. /* changed on Thu Dec 10 02:49:45 1992 to fit in our GIMMEZEROZERO Window */
  357.  
  358. #define TFRAME_Y  (14L-11L)
  359. #define TFRAME0_X (10L-4L)
  360. #define TFRAME1_X (186L-4L)
  361.  
  362. #define INFOBOX_X (366L-4L)
  363. #define INFOBOX_Y (24L-11L)      /* changed on Thu Dec 10 02:49:45 1992 */
  364. #define INFOBOX_W 146L
  365. #define INFOBOX_H  40L
  366.  
  367. #define EQUALBOX_X  (INFOBOX_X+51)
  368. #define DIFFERBOX_X (EQUALBOX_X+54)
  369. #define EQDIFFBOX_Y (INFOBOX_Y-11L)
  370.  
  371. #define ABOUTBOX_X TFRAME0_X
  372. #define ABOUTBOX_Y TFRAME_Y
  373. #define ABOUTBOX_W 341L
  374. #define ABOUTBOX_H 82L
  375.  
  376. /* globals += */
  377.  
  378. BOOL see_about= FALSE;
  379.  
  380. /*
  381.  * Delete the old track grids and overwrite them by empty ones.
  382.  * The RastPort is taken from Window->RPort!
  383.  */
  384.  
  385. void new_trackframes(void)
  386. { struct RastPort *rp= Window->RPort;
  387.   SetAPen(rp,0L);
  388.   RectFill(rp, ABOUTBOX_X, ABOUTBOX_Y,
  389.                ABOUTBOX_X+ABOUTBOX_W, ABOUTBOX_Y+ABOUTBOX_H);
  390.   draw_trackframe(rp, TFRAME0_X, TFRAME_Y, 0L);
  391.   draw_trackframe(rp, TFRAME1_X, TFRAME_Y, 1L);
  392.   see_about= FALSE; /* EITHER trackframes OR about... */
  393. }
  394.  
  395. /*
  396.  * who did it?
  397.  */
  398.  
  399. void about()
  400. { struct RastPort *rp= Window->RPort;
  401.   static char *about_text[]= { "This version is HIGHLY EXPERIMENTAL!",
  402.                                /*"This version of DCMP is SHAREWARE!",*/
  403.                                "Tobias Ferber, Bismarckstraße 22",
  404.                                "W-7570 Baden-Baden, GERMANY"
  405.                              };
  406.   Window->Flags |= RMBTRAP; /* Is this allowed ? */
  407.   if(!see_about) /* I didn't want to write: if(see_about= !see_about) */
  408.   { draw_3d(rp, ABOUTBOX_X, ABOUTBOX_Y, ABOUTBOX_W, ABOUTBOX_H, 0, POS_3D);
  409.     DrawImage(rp, &LogoImage, 100-4, 20-11);
  410.     SetDrMd(rp,JAM1);
  411.     SetAPen(rp,1L);
  412.     WaitBlit(); Move(rp,36-4,64-11); Text(rp,about_text[0],strlen(about_text[0]));
  413.     SetAPen(rp,2L);
  414.     WaitBlit(); Move(rp,34-4,63-11); Text(rp,about_text[0],strlen(about_text[0]));
  415.     SetAPen(rp,3L);
  416.     WaitBlit(); Move(rp,51-4,76-11); Text(rp,about_text[1],strlen(about_text[1]));
  417.     WaitBlit(); Move(rp,71-4,86-11); Text(rp,about_text[2],strlen(about_text[2]));
  418.     see_about= TRUE;
  419.   }
  420.   else new_trackframes(); /* sets see_about to FALSE */
  421.   Window->Flags &= ~RMBTRAP;
  422. }
  423.  
  424. #define INFOTEXT_X (INFOBOX_X+98) /* 186 */
  425. #define INFOTEXT_Y (INFOBOX_Y+11) /* 5 */
  426. #define INFOTEXT_DY 11
  427.  
  428. set_iboxval(start, end, att, err, curr)
  429. int start, end, att, err, curr;
  430. { char s[5];
  431.   struct RastPort *rp= Window->RPort;
  432.   SetAPen(rp,EQUAL_PEN);
  433.   SetDrMd(rp,JAM2);
  434.   if(start >= 0)
  435.   { sprintf(s,"%02d",start);
  436.     Move(rp,INFOTEXT_X,INFOTEXT_Y);
  437.     Text(rp,s,strlen(s));
  438.   }
  439.   if(end >= 0)
  440.   { sprintf(s,"%02d",end);
  441.     Move(rp,INFOTEXT_X+24,INFOTEXT_Y);
  442.     Text(rp,s,strlen(s));
  443.   }
  444.   if(att >= 0)
  445.   { sprintf(s,"%02d",att);
  446.     Move(rp,INFOTEXT_X+8,INFOTEXT_Y+INFOTEXT_DY);
  447.     Text(rp,s,strlen(s));
  448.   }
  449.   if(err >= 0)
  450.   { Move(rp,INFOTEXT_X+32,INFOTEXT_Y+INFOTEXT_DY);
  451.     Text(rp,(ignore_errors)?("i"):("b"),1L);
  452.   }
  453.   if(curr >= 0)
  454.   { sprintf(s,"%03d",curr);
  455.     Move(rp,INFOTEXT_X+16,INFOTEXT_Y+2*INFOTEXT_DY);
  456.     Text(rp,s,strlen(s));
  457.   }
  458. }
  459.  
  460. /*
  461.  * set_trackframe()
  462.  */
  463.  
  464. void set_trackframe(trk, diff, ratt, oper)
  465. int trk, diff, ratt;
  466. char *oper;
  467. { UWORD i,dx,dy;
  468.   char s[6];
  469.   int cyl= trk/2; /* NUMHEADS=2 !!! (TRACKS_PER_CYLINDER) */
  470.   struct RastPort *rp= Window->RPort;
  471.  
  472.   dx= TextFont->tf_XSize+5+(cyl%10)*TRACKBOX_W;
  473.   dy= TFRAME_Y+TextFont->tf_YSize+1+(cyl/10)*TRACKBOX_H;
  474.  
  475.   if(trk%2 == 0) dx+= TFRAME0_X; /* head 0 */
  476.   else dx+= TFRAME1_X; /* head 1 */
  477.  
  478.   if(diff<0) SetAPen(rp,0L);
  479.   else SetAPen(rp,(diff==0)?(EQUAL_PEN):(DIFFER_PEN));
  480.   RectFill(rp, dx+2, dy+1, dx+TRACKBOX_W-1, dy+TRACKBOX_H-1);
  481.  
  482.   if(oper && *oper)
  483.   { SetDrMd(rp,JAM1);
  484.     if(diff<0) SetAPen(rp,DEFAULT_PEN);
  485.     else SetAPen(rp,(diff==0)?(DIFFER_PEN):(EQUAL_PEN));
  486.     Move(rp, dx+4, dy+TextFont->tf_Baseline);
  487.     Text(rp, oper, strlen(oper));
  488.   }
  489.   set_iboxval(-1, -1, ratt, -1, trk);
  490. }
  491.  
  492. /*
  493.  * open_window_stuff()
  494.  */
  495.  
  496. void open_window_stuff(void)
  497. { struct RastPort *rp;
  498.   static char *err_msg[][]= {
  499.     { "You need intuition.library V%ld+",  /* 0 */
  500.       "You need graphics.library V%ld+",   /* 1 */
  501.       "Unable to open window.",            /* 2 */
  502.       "Unable to set menu strip.",         /* 3 */
  503.       "Couldn't open %s {%ld}."            /* 4 */
  504.     },
  505.     { "Sie benötigen die Intuition.library in der Version %ld (oder neuer).",
  506.       "Ich kann die Graphics.library nicht öffnen.",
  507.       "Ich krieg das Fenster nicht auf!",
  508.       "Die Menüzeile weigert sich!",
  509.       "Ich kann den %s {%ld} nicht öffnen!",
  510.     },
  511.     { "Vous avez besoin de l'intuition.library version %ld+",
  512.       "Je ne peux pas ouvrir la graphics.library.",
  513.       "Je ne peux pas ouvrir la fenêtre!",
  514.       "Le MenuStrip ne veut pas!",
  515.       "Je ne peux pas ouvrir le %s {%ld} !",
  516.     },
  517.     { "Avete bisogno della Intuition.library nella versione %ld (o più recente).",
  518.       "Non posso aprire la graphics.library.",
  519.       "Non posso aprire la finestra!",
  520.       "La linea nel menu si rifiuta!",
  521.       "Non posso aprire il %s {%ld}",
  522.     }
  523.   };
  524.  
  525.   IntuitionBase=(struct IntuitionBase *)
  526.     OpenLibrary("intuition.library",LIBRARY_VERSION);
  527.   if(!IntuitionBase)
  528.   { inform_user(err_msg[language][0],LIBRARY_VERSION);
  529.     mark(fatal_error);
  530.     return;
  531.   }
  532.   GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",LIBRARY_VERSION);
  533.   if(!GfxBase)
  534.   { inform_user(err_msg[language][1],LIBRARY_VERSION);
  535.     mark(fatal_error);
  536.     return;
  537.   }
  538.  
  539.   /* init gadgets and menu */
  540.  
  541.   { int i;
  542.     init_DFxInfo(); /* get drive information */
  543.  
  544.     /*
  545.      * I will use the unit counter `i' here instead of extracting
  546.      * the unit number from the text of the drive gadget. I think
  547.      * there is no need to do so, since I don't want to change the
  548.      * sequence DF0: DF1: DF2: DF3:
  549.      * If you want to do so then don't forget to change this in
  550.      * handle_gadget() also and simply replace check_DFxInfo(i) by
  551.      * check_DFxInfo(drive_gadget[i].GadgetText->IText[2]-'0'
  552.      */
  553.  
  554.     for(i=0;i<4;i++)
  555.     { if(check_DFxInfo(i))
  556.       { drive_gadget[i].Flags |= GADGDISABLED;
  557.         Items[language][15+i].Flags &= ~ITEMENABLED;
  558.       }
  559.       else if(i==unit_r || i==unit_c)
  560.       { drive_gadget[i].Flags |= SELECTED;
  561.         Items[language][15+i].Flags |= CHECKED;  /* DF0: ... DF3: */
  562.       }
  563.     }
  564.   }
  565.   if(deep_read)
  566.   { hook_gadget.Flags |= SELECTED;
  567.     Items[language][9].Flags |= CHECKED;  /* Verify tracks */
  568.   }
  569.   if(write_icon) Items[language][3].Flags |= CHECKED;     /* Create logfile icon */
  570.   if(ignore_errors) Items[language][10].Flags |= CHECKED; /* Ignore errors */
  571.     /* the ibox letter will be updated further down... */
  572.   NewWindow.Title= rcs_id;
  573.  
  574.   /*
  575.    * added on Thu Dec 10 03:10:53 1992, modified  Sat Jan 23 13:04:50 1993
  576.    * The window size had initially been written for the 1.3 default values
  577.    * of Window->BorderLeft   = 4,
  578.    *    Window->BorderRight  = 4,
  579.    *    Window->BorderTop    = 11 and
  580.    *    Window->BorderBottom = 2
  581.    * So we have to adjust the width by the current l+r values - (4+4)
  582.    * and the height by the current t+b values - (8+2+1)
  583.    */
  584.  
  585.   { struct Screen scr;
  586.     if(GetScreenData(&scr,sizeof(struct Screen),WBENCHSCREEN,NULL))
  587.     { int hc= scr.WBorLeft + scr.WBorRight,
  588.           vc= scr.WBorTop  + scr.WBorBottom + (scr.Font)->ta_YSize +1;
  589.  
  590.           /* The title bar height of a window is calculated from the
  591.            * screen's WBorTop field, plus the font height, plus one
  592.            */
  593.  
  594.       NewWindow.Width += hc - 8; /* horizontal correction */
  595.       NewWindow.Height+= vc - 13; /* vertical correction */
  596.       if(Window=(struct Window *)NiceOpenWindow(&NewWindow))
  597.       { hc= Window->BorderLeft + Window->BorderRight  - hc;
  598.         vc= Window->BorderTop  + Window->BorderBottom - vc;
  599.         /* Just to be sure having got the correct size: */
  600.         if(hc||vc)
  601.         { BOOL done= FALSE; /* dcmp is waiting for a NEWSIZE message */
  602.           SizeWindow(Window, hc,vc);
  603.           while(!done)
  604.           { Wait(1L<<Window->UserPort->mp_SigBit);
  605.             while(imsg=(struct IntuiMessage *)GetMsg(Window->UserPort))
  606.             { done |= (imsg->Class == NEWSIZE);
  607.               ReplyMsg(imsg);
  608.             }
  609.           }
  610.           RefreshGadgets(Window->FirstGadget, Window, NULL);
  611.           RefreshWindowFrame(Window);
  612.         }
  613.       }
  614.     }
  615.   }
  616.  
  617.   if(!Window)
  618.   { inform_user(err_msg[language][2]);
  619.     mark(fatal_error);
  620.     return;
  621.   }
  622.  
  623.   MenuFlag= SetMenuStrip(Window, MenuStrip[language]);
  624.   if(!MenuFlag) inform_user(err_msg[language][3]);
  625.  
  626.   SaveMouseColors(Window); /* They might change with the pointer... */
  627.   SetMouseImage(Window, dcmp_pointer);
  628.  
  629.   rp= Window->RPort;
  630.  
  631.   TextFont=(struct TextFont *)OpenFont(&TextAttr);
  632.   if(!TextFont)
  633.   { inform_user(err_msg[language][4],TextAttr.ta_Name,TextAttr.ta_YSize);
  634.     mark(fatal_error);
  635.     return;
  636.   }
  637.   SetFont(rp,TextFont);
  638.  
  639.   new_trackframes();
  640.  
  641.   draw_3dgb(rp, NewWindow.FirstGadget); /* We *must* use the NewWindow's GList
  642.                                          * here because we do not want to
  643.                                          * redraw the window's system gadgets...
  644.                                          */
  645.  
  646.   draw_3d(rp, INFOBOX_X,INFOBOX_Y,INFOBOX_W,INFOBOX_H, -1, POS_3D);
  647.   PrintIText(rp, &info_text[0], INFOBOX_X,INFOBOX_Y);
  648.  
  649.   set_iboxval(start_blk / BLOCKS_PER_CYLINDER,
  650.               end_blk / BLOCKS_PER_CYLINDER,
  651.               attempts,
  652.               0,  /* 0 => update `/i' or `/b' */
  653.               0 );
  654.  
  655.   SetAPen(rp,DEFAULT_PEN);
  656.   draw_box(rp, EQUALBOX_X, EQDIFFBOX_Y,TRACKBOX_W+1,TRACKBOX_H,EQUAL_PEN);
  657.   draw_box(rp, DIFFERBOX_X,EQDIFFBOX_Y,TRACKBOX_W+1,TRACKBOX_H,DIFFER_PEN);
  658.  
  659.   Window->Flags &= ~RMBTRAP;  /* is this allowed ? */
  660.  
  661.   ReqToolsBase=(struct ReqToolsBase *)OpenLibrary("reqtools.library", 37L);
  662.   if (!ReqToolsBase)
  663.   { ReqBase=(struct ReqBase *)OpenLibrary("req.library",REQVERSION);
  664.     { if(ReqBase)
  665.       { MyProcess=(struct Process *)FindTask((char *)0L);
  666.         OldWindowPtr=MyProcess->pr_WindowPtr;
  667.         MyProcess->pr_WindowPtr=(APTR)Window;
  668.       }
  669.     }
  670.   }
  671.   if(dos_rkcvinit()) mark(error_state);
  672. }
  673.  
  674. /*
  675.  * hide/show the logfile path
  676.  *
  677.  * I've slightly modified this code on Wed Oct  7 11:01:03 1992 to work with
  678.  * Kickstat V36+.  It seems as if StringInfo.DispPos is ignored now... ?!
  679.  * So instead of scrolling the gadget contents I decided to copy the visible part
  680.  * of the filename into an `overlay_buffer' and display this buffer if the
  681.  * gadget is not active.  If it is active, I'll re-link the logfile_name[].
  682.  */
  683.  
  684. void hide_path()
  685. { char *s= string_info.Buffer;
  686.   static char overlay_buffer[26]; /* 24(25) visible characters */
  687.   int i=0, k=0;
  688.   SHORT pos= RemoveGadget(Window, &string_gadget);
  689.   while(s[i++])
  690.     if(s[i]=='/'||s[i]==':') k= i+1;
  691.  
  692.   /*
  693.    * This is what we did under versions of Kickstart 1.3:
  694.    *
  695.    * string_info.DispPos= k;
  696.    * string_info.BufferPos= k;
  697.    */
  698.  
  699.   strncpy(overlay_buffer, &s[k], 25);      /* now we have to copy the visible part */
  700.   overlay_buffer[25]= '\0';                /* string MUST (!) be null-terminated... */
  701.   string_info.Buffer= &overlay_buffer[0];  /* link our static buffer */
  702.   string_info.DispPos= 0;                  /* scroll to the first character */
  703.   string_info.BufferPos= 0;                /* Kick 1.3 does NOT ignore this ! */
  704.  
  705.   RefreshGList(&string_gadget, Window, NULL, 1L);
  706.   if(pos>=0) /* => we really removed the string_gadget */
  707.     AddGadget(Window, &overlay_gadget, pos);
  708.   /*Window->Flags &= ~RMBTRAP;*/ /* enable menu selections */
  709. }
  710.  
  711. void show_path()
  712. { SHORT pos= RemoveGadget(Window, &overlay_gadget);
  713.   /*Window->Flags |= RMBTRAP;*/ /* disable menu selections */
  714.   string_info.DispPos= 0;
  715.   string_info.BufferPos= 0;
  716.  
  717.   string_info.Buffer= logfile_name;  /* re-link old string buffer */
  718.  
  719.   RefreshGList(&string_gadget,Window, NULL, 1L);
  720.   if(pos>=0) /* => we really removed the overlay_gadget */
  721.     AddGadget(Window, &string_gadget, pos);
  722.   ActivateGadget(&string_gadget, Window, NULL);
  723.   while(imsg=(struct IntuiMessage *)GetMsg(Window->UserPort))
  724.     ReplyMsg(imsg);  /* forget the waiting messages... */
  725. }
  726.  
  727. /*
  728.  * Set the menu's CHECKED marks according to the global settings
  729.  */
  730.  
  731. void update_menu()
  732. { int i;
  733.   if(write_icon) Items[language][3].Flags |= CHECKED;
  734.   else Items[language][3].Flags &= ~CHECKED;
  735.   if(deep_read) Items[language][9].Flags |= CHECKED;
  736.   else Items[language][9].Flags &= ~CHECKED;
  737.   if(ignore_errors) Items[language][10].Flags |= CHECKED;
  738.   else Items[language][10].Flags &= ~CHECKED;
  739.   for(i=0; i<4; i++)
  740.   { if(!(drive_gadget[i].Flags & GADGDISABLED))
  741.     { Items[language][15+i].Flags |= ITEMENABLED;
  742.       if((drive_gadget[i].Flags & SELECTED) == SELECTED)
  743.         Items[language][15+i].Flags |= CHECKED;
  744.       else Items[language][15+i].Flags &= ~CHECKED;
  745.     }
  746.     else Items[language][15+i].Flags &= ~ITEMENABLED;
  747.   }
  748.   for(i=0; i<5; i++) Items[language][29+i].Flags &= ~CHECKED;
  749.   Items[language][29+language].Flags |= CHECKED;
  750. }
  751.  
  752. /*
  753.  * Refresh the dcmp device list and update the gadgets and menu items
  754.  *
  755.  * Note:  There seems to be a bug in OffGadget() that makes the background
  756.  *        of an active TOGGLESELECT boolean gadget disappear...
  757.  *        This stuff will ghost the drive gadgets propperly
  758.  */
  759.  
  760. void refresh_devicelist()
  761. { int i;
  762.   init_DFxInfo();  /* get drive information */
  763.   for(i=0; i<4; i++)
  764.   { if(!check_DFxInfo(i))
  765.     { on_3dg(&drive_gadget[i], Window);
  766.       Items[language][15+i].Flags |= ITEMENABLED;
  767.     }
  768.     else
  769.     { set_gflags(&drive_gadget[i],Window,drive_gadget[i].Flags | GADGDISABLED);
  770.       Items[language][15+i].Flags &= ~ITEMENABLED;
  771.     }
  772.   }
  773. }
  774.  
  775. void handle_gadget(struct Gadget *gadget)
  776. { static char *local_msg[][]= {
  777.     { "Select a Logfile...",                  /*   0 */
  778.       "Too many drives specified.", "I see",  /* 1,2 */
  779.       "No drive(s) specified.", "Continue",   /* 3,4 */
  780.     },
  781.     { "LogFile auswählen...",
  782.       "Sie haben zu viele Laufwerke ausgewählt!", "Stimmt",
  783.       "Wie, kein Laufwerk?!", "Oh!",
  784.     },
  785.     { "Choisir LogFile...",
  786.       "Vous avez choisi trop de drives!", "Ça alors",
  787.       "Comment? Pas des drives?!", "Pardon",
  788.     },
  789.     { "Scegliere LogFile...",
  790.       "Avete scelto troppi Floppies!", "Sì",
  791.       "Come, nessun Floppy?!", "Oh!",
  792.     },
  793.   };
  794.  
  795.   if(gadget)
  796.   { switch(gadget->GadgetID)
  797.     { case LOGFILE_ID:
  798.         a_FileRequester(logfile_name, local_msg[language][0]);
  799.         strcpy(string_info.Buffer, logfile_name);
  800.         hide_path();
  801.         break;
  802.       case STRING_ID:
  803.         hide_path();
  804.         break;
  805.       case HOOK_ID:
  806.         deep_read= ((hook_gadget.Flags & SELECTED) == SELECTED);
  807.       case DRIVE0_ID: case DRIVE1_ID: case DRIVE2_ID: case DRIVE3_ID:
  808.         update_menu();
  809.         break;
  810.       case BEGIN_ID:
  811.         unit_r= unit_c= NOUNIT; /* reset units to `not specified' */
  812.         { int i;
  813.           /*
  814.            * Here is where the counter i and the unit numbers on the
  815.            * gadgets must be equal... ( see open_window_stuff() )
  816.            */
  817.           for(i=0;i<4 && !danger;i++)
  818.           { if((drive_gadget[i].Flags & SELECTED) == SELECTED)
  819.             { if(unit_r == NOUNIT)      unit_r=i; /* get first unit */
  820.               else if(unit_c == NOUNIT) unit_c=i; /* get second unit */
  821.               else
  822.               { a_Requester(local_msg[language][1],local_msg[language][2],NULL);
  823.                 mark(error_state);
  824.               }
  825.             }
  826.           }
  827.           if(unit_r == NOUNIT && unit_c == NOUNIT)
  828.           { a_Requester(local_msg[language][3],local_msg[language][4],NULL);
  829.             mark(error_state);
  830.           }
  831.           else if(unit_c == NOUNIT)
  832.             unit_c= unit_r;  /* one unit -> verify disk */
  833.         }
  834.         write_logfile= (strlen(logfile_name) > 0);
  835.         if(!danger)
  836.         { int i;
  837.           SHORT pos= RemoveGadget(Window, &begin_gadget);
  838.           begin_gadget.GadgetText= &gadget_text[7];  /* Stop! */
  839.           AddGadget(Window, &begin_gadget, pos);
  840.           RefreshGList(&begin_gadget, Window, NULL, 1L);
  841.  
  842.           off_3dg(&hook_gadget, Window);
  843.           off_3dg(&logfile_gadget, Window);
  844.           off_3dg(&string_gadget, Window);
  845.           OffGadget(&overlay_gadget, Window, NULL);
  846.  
  847.           /*
  848.            * I had a problem ghosting my drive gadgets via OffGadget()
  849.            * since it made the background color of the active TOGGLESELECT
  850.            * gadget disappear...
  851.            */
  852.  
  853.           for(i=0;i<4;i++)
  854.           { if(!(drive_gadget[i].Flags & GADGDISABLED))
  855.               set_gflags(&drive_gadget[i],Window,
  856.                           drive_gadget[i].Flags | GADGDISABLED);
  857.           }
  858.           Window->Flags |= RMBTRAP;
  859.           SetMouseImage(Window, busybee);
  860.           new_trackframes();
  861.  
  862.           do_dcmp_stuff();  /* now go ! */
  863.  
  864.           SetMouseImage(Window, dcmp_pointer);
  865.           Window->Flags &= ~RMBTRAP;
  866.           refresh_devicelist(); /* turn on drive gadgets */
  867.           OnGadget(&overlay_gadget, Window, NULL);
  868.           on_3dg(&string_gadget, Window);
  869.           on_3dg(&logfile_gadget, Window);
  870.           on_3dg(&hook_gadget, Window);
  871.  
  872.           pos= RemoveGadget(Window, &begin_gadget);
  873.           begin_gadget.GadgetText= &gadget_text[1];  /* Begin Operation */
  874.           AddGadget(Window, &begin_gadget, pos);
  875.           RefreshGList(&begin_gadget, Window, NULL, 1L);
  876.         }
  877.         break;
  878.     }
  879.   }
  880. }
  881.  
  882. /*
  883.  * Here we handle the RAWKEY events.  A rawkey conversion has to be done
  884.  * before calling this procedure.
  885.  */
  886.  
  887. void handle_keystroke(char key)
  888. { static char *local_msg[][]= {
  889.     { "First Cylinder:",                             /* 0 */
  890.       "Illegal First Cylinder: %ld\n"                /* 1 */
  891.       "#Cylinder sould be in [0..79]",
  892.       "Fine",                                        /* 2 */
  893.       "Last Cylinder:",                              /* 3 */
  894.       "Illegal Last Cylinder: %ld\n"                 /* 4 */
  895.       "#Cylinder sould be in[0..79]",
  896.       "Ooops!",                                      /* 5 */
  897.       "#of Attempts:",                               /* 6 */
  898.       "Illegal #of attempts: %ld\n"                  /* 7 */
  899.       "I think %ld attempts make noise enough!",
  900.       "So it is",                                    /* 8 */
  901.       "No attempts means no reading.\n"              /* 9 */
  902.       "Maybe the closing gadget can satisfy you?",
  903.       "Hmmm...",                                     /* 10 */
  904.       "Illegal #of attempts: %ld\n"                  /* 11 */
  905.       "Think positive, try one of [1..%ld]",
  906.       "I will"                                       /* 12 */
  907.     },
  908.     { "Erster Cylinder:",
  909.       "Na nu? Den Cylinder %ld gibt es ja gar nicht!\n"
  910.       "Ihr Laufwerk kennt nur die Cylinder zwischen 0 und 79!",
  911.       "Ach so",
  912.       "Letzter Cylinder:",
  913.       "Ich kann doch nicht mit dem Cylinder %ld aufhören!\n"
  914.       "Es gibt nur die Cylinder von 0 bis 79!",
  915.       "Hoppla!",
  916.       "Leseversuche:",
  917.       "%ld Leseversuche sind zu viel!\n"
  918.       "Mit %ld Versuchen macht Ihr Laufwerk genug Krach!",
  919.       "Stimmt",
  920.       "Wenn sie mich nicht lesen lassen wollen,\n"
  921.       "sollten Sie vielleicht besser das Programm verlassen?",
  922.       "Ne, ne",
  923.       "Wie? %ld Leseversuche?\n"
  924.       "Wie wäre es mit einer Zahl zwischen 1 und %ld?",
  925.       "Tschuldigung"
  926.     },
  927.     { "Premièr cylindre:",
  928.       "Ça alors, Le cylindre %ld n'existe pas!\n"
  929.       "Votre floppy ne connaît que des cylindres entre 0 et 79!",
  930.       "Bien",
  931.       "Dernier cylindre:",
  932.       "Je ne peux pas finir avec le cylindre %ld!\n"
  933.       "Il n'y a que les cylindres entre 0 et 79!",
  934.       "Olàlà!",
  935.       "#des essaies:",
  936.       "Trop d'essaies: %ld!\n"
  937.       "Avec %ld essaies votre floppy fait assez de bruit!",
  938.       "Croissant",
  939.       "Si vous ne voulez pas me laisser lire,\n"
  940.       "c'est peut-être mieux de quitter le programme?",
  941.       "Non, non",
  942.       "Quoi? %ld essaies?\n"
  943.       "Choisissez un numéro entre 1 et %ld?",
  944.       "Pardon"
  945.     },
  946.     { "Primo cilindro:",
  947.       "Primo cilindro illegale: %ld\n"
  948.       "#Cilindro dovrebbe essere in [0..79]",
  949.       "Bene",
  950.       "Ultimo cilindro:",
  951.       "Ultimo cilindro illegale: %ld\n"
  952.       "#Cilindro dovrebbe essere in [0..79]",
  953.       "Oooh!",
  954.       "Tentativi di lettura:",
  955.       "# dei tentativi illegale: %ld\n"
  956.       "Penso che %ld fanno abbastamza rumore!",
  957.       "È proprio così!",
  958.       "Niente tentativi, niente lettura.\n"
  959.       "Vorreste forse uscire dal programma?",
  960.       "Hmmm...",
  961.       "# dei tentativi illegale: %ld\n"
  962.       "Siate ottimisti, provate uno di [1..%ld]",
  963.       "Lo saro"
  964.     }
  965.   };
  966.  
  967.   switch(key)
  968.   { case 'f': case 'F':
  969.       handle_gadget(&logfile_gadget);
  970.       break;
  971.     case 't': case 'T':
  972.       strcpy(logfile_name, DEF_LOGFILE);
  973.       show_path();
  974.       break;
  975.     case 'l': case 'L':
  976.       show_path();
  977.       break;
  978.     case 'b': case 'B': case 'g': case 'G':
  979.       handle_gadget(&begin_gadget);
  980.       break;
  981.     case 'q': case 'Q': case 'x': case 'X': case '\33': /* ESC */
  982.       mark(depart);
  983.       break;
  984.     case 'r': case 'R': case 'i': case 'I':
  985.       ignore_errors= !ignore_errors;
  986.       set_iboxval(-1,-1,-1,0,-1);
  987.       break;
  988.     case 'v': case 'V': case 'w': case 'W':
  989.       set_gflags(&hook_gadget, Window, hook_gadget.Flags ^ SELECTED);
  990.       deep_read= ((hook_gadget.Flags & SELECTED) == SELECTED);
  991.       break;
  992.     case '0': case '1': case '2': case '3':
  993.       { int i= key-'0';
  994.         if(!(drive_gadget[i].Flags & GADGDISABLED))
  995.           set_gflags(&drive_gadget[i], Window, drive_gadget[i].Flags ^ SELECTED);
  996.       }
  997.       break;
  998.     case 's': case 'S':
  999.       { long scyl;  /* start cylinder */
  1000.         do
  1001.         { scyl= start_blk/BLOCKS_PER_CYLINDER;
  1002.           if(a_GetLongRequester(&scyl,local_msg[language][0],0L,79L))
  1003.           { if(0>scyl || scyl>79)
  1004.             { char response[256];
  1005.               sprintf(response,local_msg[language][1],scyl);
  1006.               a_Requester(response,local_msg[language][2],NULL);
  1007.             }
  1008.             else
  1009.             { start_blk= scyl * BLOCKS_PER_CYLINDER;
  1010.               set_iboxval(scyl, -1, -1, -1, -1);
  1011.             }
  1012.           }
  1013.         } while(0>scyl || scyl>79);
  1014.       }
  1015.       break;
  1016.     case 'e': case 'E':
  1017.       { long ecyl; /* last cylinder */
  1018.         do
  1019.         { ecyl= end_blk/BLOCKS_PER_CYLINDER;
  1020.           if(a_GetLongRequester(&ecyl,local_msg[language][3],0L,79L))
  1021.           { if(0>ecyl || ecyl>79)
  1022.             { char response[256];
  1023.               sprintf(response,local_msg[language][4],ecyl);
  1024.               a_Requester(response,local_msg[language][5],NULL);
  1025.             }
  1026.             else
  1027.             { end_blk= (ecyl+1) * BLOCKS_PER_CYLINDER -1;
  1028.               /* include the last SEC of this CYL */
  1029.               set_iboxval(-1, ecyl, -1, -1, -1);
  1030.             }
  1031.           }
  1032.         } while(0>ecyl || ecyl>79);
  1033.       }
  1034.       break;
  1035.     case 'a': case 'A':
  1036.       { long atps;
  1037.         do
  1038.         { atps= attempts;
  1039.           if(a_GetLongRequester(&atps,local_msg[language][6],1L,MAX_ATTEMPTS))
  1040.           { char response[256];
  1041.             if(atps>MAX_ATTEMPTS)
  1042.             { sprintf(response,local_msg[language][7],atps,MAX_ATTEMPTS);
  1043.               a_Requester(response,local_msg[language][8],NULL);
  1044.             }
  1045.             else if(atps == 0)
  1046.             { sprintf(response,local_msg[language][9]);
  1047.               a_Requester(response,local_msg[language][10],NULL);
  1048.             }
  1049.             else if(atps<0)
  1050.             { sprintf(response,local_msg[language][11],atps,MAX_ATTEMPTS);
  1051.               a_Requester(response,local_msg[language][12],NULL);
  1052.             }
  1053.             else
  1054.             { attempts= atps;
  1055.               set_iboxval(-1, -1, atps, -1, -1);
  1056.             }
  1057.           }
  1058.         } while(1>atps || atps>MAX_ATTEMPTS);
  1059.       }
  1060.       break;
  1061.     case '?': case '_': /* underscore == ? on the US keymap */
  1062.       about();
  1063.       break;
  1064.     case 'd': case 'D': case ' ':
  1065.       refresh_devicelist();  /* refresh dcmp device list via init_DFxInfo()
  1066.                               * and update the menu and gadgets
  1067.                               */
  1068.       break;
  1069.     case 'h': case 'H':
  1070.       dcmp_Request("You will have to register to use this function.",
  1071.                    "Fuck it!", "I will");
  1072.       break;
  1073.     case 'p':
  1074.       FlipPointerX(Window);
  1075.       break;
  1076.     case 'P':
  1077.       FlipPointerY(Window);
  1078.       break;
  1079.     case 'c': case 'C':
  1080.       FlipPointerZ(Window);
  1081.       break;
  1082.     default:
  1083.       DisplayBeep(Window->WScreen);
  1084.       break;
  1085.   }
  1086. }
  1087.  
  1088. /*
  1089.  * Here the MENUPICK messages are handled.  All selections in the menu
  1090.  * are passed over to handle_keystroke().  If a MENUTOGGLE Item was changed
  1091.  * we have to do a post processing to update the gadgets.
  1092.  */
  1093.  
  1094. void handle_menu(USHORT num)
  1095. { struct MenuItem *item;
  1096.   BOOL update= FALSE;
  1097.   while(num != MENUNULL)
  1098.   { struct MenuItem *item= (struct MenuItem *)ItemAddress(MenuStrip[language], num);
  1099.     USHORT menunum= MENUNUM(num),
  1100.            itemnum= ITEMNUM(num),
  1101.            subnum= SUBNUM(num);
  1102.     switch(menunum)
  1103.     { case 0: /* Project */
  1104.         switch(itemnum)
  1105.         { case 0: /* About */
  1106.             handle_keystroke('?');
  1107.             break;
  1108.           case 2: /* Select Logfile */
  1109.             handle_keystroke('f');
  1110.             break;
  1111.           case 3: /* Create logfile icon */
  1112.             update= TRUE;
  1113.             break;
  1114.           case 5: /* Set first cylinder */
  1115.             handle_keystroke('s');
  1116.             break;
  1117.           case 6: /* Set last cylinder */
  1118.             handle_keystroke('e');
  1119.             break;
  1120.           case 7: /* Set #of attempts */
  1121.             handle_keystroke('a');
  1122.             break;
  1123.           case 9: case 10: /* Verify tracks, Ignore Errors */
  1124.             update= TRUE;
  1125.             break;
  1126.           case 12: /* Refresh device list */
  1127.             handle_keystroke('d');
  1128.             break;
  1129.           case 14: /* Quit */
  1130.             handle_keystroke('q');
  1131.             break;
  1132.         }
  1133.         break;
  1134.       case 1: /* Drives */
  1135.         switch(itemnum)
  1136.         { case 0: case 1: case 2: case 3:
  1137.             update= TRUE;
  1138.             break;
  1139.         }
  1140.         break;
  1141.       case 2: /* Information */
  1142.         switch(itemnum)
  1143.         { case 4: /* Copyright */
  1144.             dcmp_Request(info_msg[language][INFO_COPYRIGHT],
  1145.                          info_msg[language][INFO_COPYRIGHT+1],
  1146.                          info_msg[language][INFO_COPYRIGHT+2] );
  1147.             break;
  1148.           case 5: /* Distribution */
  1149.             dcmp_Request(info_msg[language][INFO_DISTRIBUTION],
  1150.                          info_msg[language][INFO_DISTRIBUTION+1],
  1151.                          info_msg[language][INFO_DISTRIBUTION+2] );
  1152.             break;
  1153.           case 6: /* Credits */
  1154.             switch(subnum)
  1155.             { case 0:
  1156.                 dcmp_Request(info_msg[language][INFO_IDEAS],
  1157.                              info_msg[language][INFO_IDEAS+1],
  1158.                              info_msg[language][INFO_IDEAS+2] );
  1159.                 break;
  1160.               case 1:
  1161.                 dcmp_Request(info_msg[language][INFO_LIBRARIES],
  1162.                              info_msg[language][INFO_LIBRARIES+1],
  1163.                              info_msg[language][INFO_LIBRARIES+2] );
  1164.                 break;
  1165.               case 2:
  1166.                 dcmp_Request(info_msg[language][INFO_COMPILER],
  1167.                              info_msg[language][INFO_COMPILER+1],
  1168.                              info_msg[language][INFO_COMPILER+2] );
  1169.                 break;
  1170.               case 3:
  1171.                 dcmp_Request(info_msg[language][INFO_SUPPORT],
  1172.                              info_msg[language][INFO_SUPPORT+1],
  1173.                              info_msg[language][INFO_SUPPORT+2] );
  1174.                 break;
  1175.               case 4:
  1176.                 dcmp_Request(info_msg[language][INFO_LANGUAGE],
  1177.                              info_msg[language][INFO_LANGUAGE+1],
  1178.                              info_msg[language][INFO_LANGUAGE+2] );
  1179.                 break;
  1180.               case 5:
  1181.                 dcmp_Request(info_msg[language][INFO_TESTING],
  1182.                              info_msg[language][INFO_TESTING+1],
  1183.                              info_msg[language][INFO_TESTING+2] );
  1184.                 break;
  1185.             }
  1186.             break;
  1187.           case 7: /* Versions */
  1188.             dcmp_Request(info_msg[language][INFO_VERSIONS],
  1189.                          info_msg[language][INFO_VERSIONS+1],
  1190.                          info_msg[language][INFO_VERSIONS+2] );
  1191.             break;
  1192.         }
  1193.         break;
  1194.       case 3: /* Language */
  1195.         update= TRUE;
  1196.         break;
  1197.     }
  1198. /*
  1199.     printf("MENUNUM= %ld, ITEMNUM= %ld, SUBNUM= %ld\n",
  1200.       MENUNUM(num), ITEMNUM(num), SUBNUM(num) );
  1201.     printf("language= %ld\n",language);
  1202. */
  1203.     if(item->NextSelect != num)
  1204.       num= item->NextSelect;
  1205.     else num= MENUNULL;
  1206.   }
  1207.   /*
  1208.    * Here we perform a post work on the CHECKED marks of the menu.
  1209.    * We have to do so, because the `NextSelect' entry point in the
  1210.    * MenuItem structure is not allowed to be equal to it's own ITEMNUM.
  1211.    * (If it were, collecting the MENUPICK messages could become non-
  1212.    * deterministic!)
  1213.    */
  1214.   if(update) /* update settings according to the menu's CHECKED marks */
  1215.   { int i;
  1216.     write_icon= ((Items[language][3].Flags & CHECKED) == CHECKED); /* no gadget for it */
  1217.     deep_read= ((Items[language][9].Flags & CHECKED) == CHECKED);
  1218.     set_gflags(&hook_gadget, Window,
  1219.                deep_read ? (hook_gadget.Flags | SELECTED):
  1220.                            (hook_gadget.Flags & ~SELECTED) );
  1221.     ignore_errors= ((Items[language][10].Flags & CHECKED) == CHECKED);
  1222.     set_iboxval(-1, -1, -1, 0, -1); /* update `ignore errors' */
  1223.     for(i=0; i<4; i++)
  1224.     { if(!(drive_gadget[i].Flags & GADGDISABLED)) /* => gadget NOT ghosted */
  1225.       { set_gflags(&drive_gadget[i], Window,
  1226.           (Items[language][15+i].Flags & CHECKED)?(drive_gadget[i].Flags | SELECTED)
  1227.                                        :(drive_gadget[i].Flags & ~SELECTED) );
  1228.       }
  1229.     }
  1230.     for(i=0; i<5; i++)
  1231.     {    if( ((Items[language][29+i].Flags & ITEMENABLED) == ITEMENABLED)
  1232.        && ((Items[language][29+i].Flags & CHECKED) == CHECKED) )
  1233.       { if (i != language)
  1234.         { language= i;
  1235.           ClearMenuStrip(Window);
  1236.           SetMenuStrip(Window, MenuStrip[language]);
  1237.           update_menu();
  1238.         }
  1239.       }
  1240.     }
  1241.   }
  1242. }
  1243.  
  1244. void handle_window_stuff(void)
  1245. { ULONG class;
  1246.   USHORT code,qual;
  1247.   APTR address;
  1248.  
  1249.   hide_path();
  1250.  
  1251.   while(!lental)
  1252.   { mark(well_done);  /* loop as long as nothing lental happens */
  1253.     Wait(1L<<Window->UserPort->mp_SigBit);
  1254.     while(imsg=(struct IntuiMessage *)GetMsg(Window->UserPort))
  1255.     { class   = imsg->Class;
  1256.       code    = imsg->Code;
  1257.       qual    = imsg->Qualifier;
  1258.       address = imsg->IAddress;
  1259.       ReplyMsg(imsg);
  1260.  
  1261.       switch(class)
  1262.       { case CLOSEWINDOW:
  1263.           mark(depart);
  1264.           break;
  1265.         case GADGETUP:
  1266.           handle_gadget((struct Gadget *)address);
  1267.           break;
  1268.         case GADGETDOWN:
  1269.         { struct Gadget *gadget= (struct Gadget *)address;
  1270.           if(gadget->GadgetID == OVERLAY_ID)
  1271.             show_path();
  1272.           else if(gadget->GadgetID!=STRING_ID)
  1273.             hide_path();
  1274.           break;
  1275.         }
  1276.         case MOUSEBUTTONS:
  1277.           hide_path();
  1278.           break;
  1279.         case RAWKEY:
  1280.         { char buf[10];
  1281.           if(code==95) /* rawkey code HELP */
  1282.             handle_keystroke('h');
  1283.           else if(dos_rkcv((int)code, (int)qual, &buf[0], 10))
  1284.             handle_keystroke(buf[0]);
  1285.           update_menu();
  1286.           break;
  1287.         }
  1288.         case MENUPICK:
  1289.           handle_menu(code);
  1290.           break;
  1291.       }
  1292.     }
  1293.   }
  1294. }
  1295.  
  1296. write_statistics(FILE *out, int full)
  1297. { static char *local_msg[][]= {
  1298.     { "** Operation terminated abnormally!\n"           /* 0 */
  1299.       "result (so far): ",
  1300.       "Verify", "error", "okay",                        /* 1,2,3 */
  1301.       "total: ",                                        /* 4 */
  1302.       "track differs on", "tracks differ on",           /* 5,6 */
  1303.       "block", "blocks",                                /* 7,8 */
  1304.       "no", "error", "errors",                          /* 9, 10, 11 */
  1305.       ", no ", "weak track", "weak tracks",             /* 12, 13, 14 */
  1306.       "found",                                          /* 15 */
  1307.       "Here is the complete list of differing blocks:", /* 16 */
  1308.       "      %4ld: Track #%03ld, Sector #%02ld\n",      /* 17 */
  1309.       "%4ld..%04ld: Track #%03ld, Sector #%02ld  --  Track #%03ld, Sector #%02ld\n",
  1310.     },
  1311.     { "*** Operation abgebrochen!\n"
  1312.       "Bisher: ",
  1313.       "Überprüfung", "negativ", "positiv",
  1314.       "Insgesamt: ",
  1315.       "unterschiedlicher Track auf",
  1316.       "unterschiedliche Tracks auf",
  1317.       "Block", "Blöcken",
  1318.       "kein", "Fehler", "Fehler",
  1319.       ", keine ", "Weak-Track", "Weak-Tracks",
  1320.       "gefunden",
  1321.       "Hier ist die vollständige Liste der unterschiedlichen Blocks:",
  1322.       "      %4ld: Track #%03ld, Sektor #%02ld\n",
  1323.       "%4ld..%04ld: Track #%03ld, Sektor #%02ld  bis  Track #%03ld, Sektor #%02ld\n",
  1324.     },
  1325.     { "*** Opération interrompue!\n"
  1326.       "Jusqu'à maintenant: ",
  1327.       "Vérification", "negatif", "positif",
  1328.       "Complètement: ",
  1329.       "différent track sur",
  1330.       "différents tracks sur",
  1331.       "bloc", "blocs",
  1332.       "pas", "d'erreur", "d'erreurs",
  1333.       ", pas de ", "Weak-Track", "Weak-Tracks",
  1334.       "trouvés",
  1335.       "Voilà la liste complète des blocs différents:",
  1336.       "      %4ld: track #%03ld, sector #%02ld\n",
  1337.       "%4ld..%04ld: track #%03ld, sector #%02ld  à  track #%03ld, sector #%02ld\n",
  1338.     },
  1339.     { "*** Operazione interrotta!\n"
  1340.       "Fin adesso: ",
  1341.       "Verificazione", "negativo", "positivo",
  1342.       "Totale: ",
  1343.       "Traccia differente su",
  1344.       "Tracce differenti su",
  1345.       "Blocco", "Blocchi",
  1346.       "nessun", "errore", "errori",
  1347.       ", nessuni ", "Weak-Track", "Weak-Tracks",
  1348.       "trovati", /* trovati ist plural, trovato ist 1zahl */
  1349.       "Qui è la lista completa dei blocchi differenti:",
  1350.       "      %4ld: traccia #%03ld, settore #%02ld\n",
  1351.       "%4ld..%04ld: traccia #%03ld, settore #%02ld -- traccia #%03ld, settore #%02ld\n",
  1352.  
  1353.     },
  1354.   };
  1355.  
  1356.   if(danger) fprintf(out,local_msg[language][0]);
  1357.   else
  1358.   { if(unit_r == unit_c)
  1359.     { fprintf(out,"%s %s: ",local_msg[language][1],
  1360.                   (wtrk>0 || errcnt>0)?(local_msg[language][2])
  1361.                                       :(local_msg[language][3]) );
  1362.     }
  1363.     else fprintf(out,local_msg[language][4]);
  1364.   }
  1365.  
  1366.   if(unit_r != unit_c)
  1367.   { fprintf(out,"%ld %s %ld %s, ",dtrk,
  1368.             (dtrk==1)?(local_msg[language][5])
  1369.                      :(local_msg[language][6]),
  1370.                                   dblk,
  1371.             (dblk==1)?(local_msg[language][7])
  1372.                      :(local_msg[language][8]) );
  1373.   }
  1374.  
  1375.   if(errcnt==0) fprintf(out,local_msg[language][9]); /* no */
  1376.   else fprintf(out,"%ld",errcnt);
  1377.   /*
  1378.    * If we are taking italian, we say `nessun errore' instead of `nessuni errori'
  1379.    */
  1380.   if(language==3)
  1381.   { fprintf(out," %s",(errcnt<=1)?(local_msg[3][10])    /* errore */
  1382.                                  :(local_msg[3][11]) ); /* errori */
  1383.   }
  1384.   else
  1385.   { fprintf(out," %s",(errcnt==1)?(local_msg[language][10])
  1386.                                  :(local_msg[language][11]) );
  1387.   }
  1388.   if(deep_read)
  1389.   { if(wtrk==0) fprintf(out,local_msg[language][12]);
  1390.     else fprintf(out,", %ld ",wtrk);
  1391.     fprintf(out, "%s.\n",(wtrk==1)?(local_msg[language][13])
  1392.                                   :(local_msg[language][14]) );
  1393.   }
  1394.   else fprintf(out," %s.\n",local_msg[language][15]);
  1395.  
  1396.   /* dblk can only be >0 if unit_r != unit_c... so: */
  1397.  
  1398.   if(dblk>0 && full)
  1399.   { int s,e=0;
  1400.     fprintf(out,"\n%s\n\n",local_msg[language][16]);
  1401.     while(dblk_list[e]>=0 && e<=1759)
  1402.     { for(s=e;dblk_list[e]==dblk_list[e+1]-1 && e<=1759;e++)
  1403.         ;
  1404.       if(s==e)
  1405.       { fprintf(out,local_msg[language][17], dblk_list[e],
  1406.                                              dblk_list[e]/BLOCKS_PER_TRACK,
  1407.                                              dblk_list[e]%BLOCKS_PER_TRACK);
  1408.       }
  1409.       else
  1410.       { fprintf(out,local_msg[language][18], dblk_list[s],
  1411.                                              dblk_list[e],
  1412.                                              dblk_list[s]/BLOCKS_PER_TRACK,
  1413.                                              dblk_list[s]%BLOCKS_PER_TRACK,
  1414.                                              dblk_list[e]/BLOCKS_PER_TRACK,
  1415.                                              dblk_list[e]%BLOCKS_PER_TRACK);
  1416.       }
  1417.       e++;
  1418.     }
  1419.   }
  1420. }
  1421.  
  1422. /*
  1423.  * open_logfile()  opens the file `logfile_name'.  If it already exists
  1424.  * new data will be `a'ppended, otherwise a ne`w' file will be [created].
  1425.  */
  1426.  
  1427. #include <time.h>
  1428.  
  1429. void open_logfile()
  1430. { static char *local_msg[][]= {
  1431.     { "created",                            /* 0 */
  1432.       "This is %s\n",                       /* 1 */
  1433.       "Verifying drive DF%ld: (%s)\n",      /* 2 */
  1434.       "deeply", "quickly",                  /* 3,4 */
  1435.       "Compare drive DF%ld: with DF%ld:%s", /* 5 */
  1436.       " w/ deep read\n", "\n",              /* 6,7 */
  1437.       "Warning: Not enough memory for weak data detection.  Option ignored.\n",
  1438.       "> Start: Track #%ld, Sector #%ld, Block #%ld\n",    /* 9 */
  1439.       "> End: Track #%ld, Sector #%ld, Block #%ld\n",      /* 10 */
  1440.       "Unable to open logfile.",            /* 11 */
  1441.       "No icon.library - Sorry, no icon"    /* 12 */
  1442.     },
  1443.     { "erstellt",
  1444.       "LogFile von %s\n",
  1445.       "Disk im Laufwerk %ld wird %s überprüft\n",
  1446.       "genau", "gelesen und",
  1447.       "Disk Vergleich DF%ld: mit DF%ld:%s",
  1448.       " (mit Überprüfung)\n", "\n",
  1449.       "Achtung: Nicht genug Speicher für die Überprüfung!  Parameter ignoriert.\n",
  1450.       "> Start: Track #%ld, Sektor #%ld, Block #%ld\n",
  1451.       "> Ende: Track #%ld, Sektor #%ld, Block #%ld\n",
  1452.       "Das LogFile konnte nicht geöffnet werden!",
  1453.       "Keine Icon.library - Sorry, kein Icon"
  1454.     },
  1455.     { "créé",
  1456.       "LogFile de %s\n",
  1457.       "Disque en floppy %ld est vérifié %s\n",
  1458.       "exactement", "en lisant",
  1459.       "Comparaisant les disques DF%ld: avec DF%ld:%s",
  1460.       " (avec mit  vérification)\n", "\n",
  1461.       "Attention: Pas assez de memoire!  Paramètre -v ignoré.\n",
  1462.       "> Départ: track #%ld, sector #%ld, bloc #%ld\n",
  1463.       "> Fin: track #%ld, sector #%ld, bloc #%ld\n",
  1464.       "Le LogFile ne pouvait pas être ouvert!",
  1465.       "Il n'y a pas d'icon.library - malheureusement pas d'icon"
  1466.     },
  1467.     { "creato",
  1468.       "Questo è il LogFile di %s\n",
  1469.       "Disco nel floppy %ld viene letto %s\n",
  1470.       "scrupolosamente", "ed verificato",
  1471.       "Comparazione disco DF%ld: con DF%ld:%s",
  1472.       " (riesaminando)\n", "\n",
  1473.       "Attenzione: Non  c'è abbastanza memoria disponibile per la verifica!  Parameter ignorato.\n",
  1474.       "> Inizio: traccia #%ld, settore #%ld, blocco #%ld\n",
  1475.       "> Fine: traccia #%ld, settore #%ld, blocco #%ld\n",
  1476.       "Il LogFile non poteva essere aperto!",
  1477.       "Non c'è una Icon.library - Mi dispiace, nessuna icona"
  1478.     }
  1479.   };
  1480.  
  1481.   if(write_icon)
  1482.   { IconBase= (struct IconBase *)OpenLibrary(ICONNAME,LIBRARY_VERSION);
  1483.     if(IconBase)
  1484.     { PutDiskObject(logfile_name, &LogIcon);
  1485.       CloseLibrary(IconBase);
  1486.     }
  1487.     else inform_user(local_msg[language][12]);
  1488.   }
  1489.   if(fp=fopen(logfile_name,"r"))  /* check if logfile already exists */
  1490.   { fclose(fp);
  1491.     if(fopen(logfile_name,"a"))   /* reopen logfile for append */
  1492.     { long t;
  1493.       time(&t); /* get #of seconds since 00:00:00 GMT Jan 1,1970 */
  1494.       fprintf(fp,"\n@ %s\n",ctime(&t));
  1495.       logdata_added= TRUE;
  1496.     }
  1497.   }
  1498.   else /* file does *NOT* exist yet */
  1499.   { if(fp=fopen(logfile_name,"w"))  /* create new file */
  1500.     { if(!be_quiet)
  1501.         printf("   %s  [%s]\n",logfile_name,local_msg[language][0]);
  1502.     }
  1503.   }
  1504.   if(fp)  /* okay, we opened this file somehow... */
  1505.   { write_logfile= TRUE;
  1506.     fprintf(fp,local_msg[language][1],rcs_id);
  1507.     if(unit_r == unit_c)
  1508.     { fprintf(fp,local_msg[language][2],unit_r,
  1509.               (deep_read && deep_buffer)?(local_msg[language][3])
  1510.                                         :(local_msg[language][4]) );
  1511.     }
  1512.     else
  1513.     { fprintf(fp,local_msg[language][5],unit_r,unit_c,
  1514.               (deep_read && deep_buffer)?(local_msg[language][6])
  1515.                                         :(local_msg[language][7]) );
  1516.     }
  1517.     if(deep_read &! deep_buffer) fprintf(fp,local_msg[language][8]);
  1518.     fprintf(fp,local_msg[language][9], start_blk/BLOCKS_PER_TRACK,
  1519.                                        start_blk%BLOCKS_PER_TRACK, start_blk);
  1520.     fprintf(fp,local_msg[language][10],end_blk/BLOCKS_PER_TRACK,
  1521.                                        end_blk%BLOCKS_PER_TRACK, end_blk);
  1522.   }
  1523.   else
  1524.   { inform_user(local_msg[language][11]);
  1525.     write_logfile= FALSE;
  1526.     mark(warning);
  1527.   }
  1528. }
  1529.  
  1530. #define PORTNAME_R "dcmp_read.port"
  1531. #define PORTNAME_C "dcmp_compare.port"
  1532. #define PORTNAME_V "dcmp_verify.port"
  1533.  
  1534. /*
  1535.  * open_dcmp_stuff() checks and opens the drive unit(s).
  1536.  *                   returns FALSE in case of an error.
  1537.  */
  1538.  
  1539. int open_dcmp_stuff(void)
  1540. { long err;
  1541.  
  1542.   static char *local_msg[][]= {
  1543.     { "DF%ld: %s.",                                 /* 0 */
  1544.       "%s. Can't access DF%ld:",                    /* 1 */
  1545.       "No disk present in unit %ld.",               /* 2 */
  1546.       "Not enough memory for weak data detection!", /* 3 */
  1547.     },
  1548.     { "Laufwerk DF%ld: %s.",
  1549.       "%s. Laufwerk %ld nicht ansprechbar!",
  1550.       "Die Disk fehlt im Laufwerk %ld.",
  1551.       "Zu wenig Speicher für die Überprüfung!",
  1552.     },
  1553.     { "Floppy DF%ld: %s.",
  1554.       "%s. Floppy %ld inaccessable!",
  1555.       "Pas de disque en floppy %ld.",
  1556.       "Pas assez de memorie pour la vérification!",
  1557.     },
  1558.     { "DF%ld: %s.",
  1559.       "%s. Floppy %ld non accesìbile!",
  1560.       "Nel floppy %ld manca il disco.",
  1561.       "Troppo poca memoria disponibile per la verifica!",
  1562.     },
  1563.   };
  1564.  
  1565.   init_DFxInfo(); /* get drive information */
  1566.  
  1567.   /* open unit_r */
  1568.  
  1569.   if(err= check_DFxInfo(unit_r))
  1570.   { inform_user(local_msg[language][0], unit_r, dfxerr[language][err]);
  1571.     return(FALSE);
  1572.   }
  1573.   if(unit_r != unit_c)
  1574.     err= open_unit(unit_r,PORTNAME_R, BYTES_PER_TRACK);
  1575.   else
  1576.     err= open_unit(unit_r,PORTNAME_V, BYTES_PER_TRACK);
  1577.   if(err)  
  1578.   { inform_user(local_msg[language][1],ouerr[language][err],unit_r);
  1579.     return(FALSE);
  1580.   }
  1581.   if(disk_state(unit_r) <= 0)
  1582.   { inform_user(local_msg[language][2],unit_r);
  1583.     close_unit(unit_r);
  1584.     return(FALSE);
  1585.   }
  1586.  
  1587.   /* open unit_c */
  1588.  
  1589.   if(unit_r != unit_c)
  1590.   { if(err= check_DFxInfo(unit_c))
  1591.     { inform_user(local_msg[language][0], unit_c, dfxerr[language][err]);
  1592.       close_unit(unit_r);
  1593.       return(FALSE);
  1594.     }
  1595.     if(err= open_unit(unit_c, PORTNAME_C, BYTES_PER_TRACK))
  1596.     { inform_user(local_msg[language][1],ouerr[language][err],unit_c);
  1597.       close_unit(unit_r);
  1598.       return(FALSE);
  1599.     }
  1600.     if(disk_state(unit_c) <= 0)
  1601.     { inform_user(local_msg[language][2],unit_c);
  1602.       close_dcmp_stuff();
  1603.       return(FALSE);
  1604.     }
  1605.   }
  1606.  
  1607.   /* allocate deep_buffer */
  1608.  
  1609.   if(deep_read)
  1610.   { deep_buffer= (ULONG *)AllocMem(BYTES_PER_TRACK, MEMF_CHIP);
  1611.     if(!deep_buffer)
  1612.       inform_user(local_msg[language][3]);
  1613.   }
  1614.   return(TRUE);
  1615. }
  1616.  
  1617. /*
  1618.  *  dcmp_read() reads a track and handles the retries and the window stuff.
  1619.  *              If no buffer is given (buffer == NULL), the track will be 
  1620.  *              read into DFxInfo[unit].Buffer.
  1621.  *              (-1) will be returned in case of an error.
  1622.  */
  1623.  
  1624. int dcmp_read(long unit, long trk, ULONG *buffer)
  1625. { int err;
  1626.  
  1627.   static char *local_msg[][]= {
  1628.     { "%s on DF%ld: track %ld, %ld %s failed.",     /* 0 */
  1629.       "Read error",                                 /* 1 */
  1630.       "attempt", "attempts",                        /* 2,3 */
  1631.       "IO Error unit %ld: %s.",                     /* 4 */
  1632.     },
  1633.     { "%s auf DF%ld: Track %ld, %ld %s fehlgeschlagen.",
  1634.       "Lesefehler",
  1635.       "Versuch", "Versuche",
  1636.       "Ein-/Ausgabe Fehler auf Laufwerk %ld: %s.",
  1637.     },
  1638.     { "%s sur DF%ld: track %ld, %ld %s.",
  1639.       "Read error",
  1640.       "essai raté", "essaies ratés",
  1641.       "I/O Error sur floppy %ld: %s.",
  1642.     },
  1643.     { "%s su DF%ld: traccia %ld, %ld %s.",
  1644.       "Sbaglio di lettura",
  1645.       "tentativo fallito", " tentativi falliti",
  1646.       "IO errore su floppy %ld: %s.",
  1647.     }
  1648.   };
  1649.  
  1650.   ratt=attempts;
  1651.   if(!buffer) buffer= DFxInfo[unit].Buffer;
  1652.   do  /* the reading */
  1653.   { err= td_read(DFxInfo[unit].IOExtTD,
  1654.                  trk * BYTES_PER_TRACK,
  1655.                  BYTES_PER_TRACK,
  1656.                  buffer,
  1657.                  NULL );
  1658.                  
  1659.     if(err!=0) /* handle retries */
  1660.     { ratt--;
  1661.       if(display_window)
  1662.         set_trackframe(trk,-1,ratt,"e"); /* e == error */
  1663.     }
  1664.   } while(err!=0 && ratt>0);
  1665.  
  1666.   if(err!=0)  /* couldn't read this block */
  1667.   { char err_msg[128];
  1668.     errcnt++;
  1669.     if(err>0)
  1670.     { sprintf(err_msg,local_msg[language][0],
  1671.               (20<=err && err<=35)?(tderr[language][err-20])
  1672.                                   :(local_msg[language][1]),
  1673.               unit,trk, attempts,
  1674.                      (attempts==1)?(local_msg[language][2])
  1675.                                   :(local_msg[language][3]) );
  1676.     }
  1677.     else /* negative */
  1678.     { if(err<(-7)) err= -8; /* less than (-7) not known (yet) */
  1679.       sprintf(err_msg,local_msg[language][4],unit,ioerr[language][-err]);
  1680.     }
  1681.     if(write_logfile && logfile_open)
  1682.       fprintf(fp,"** %s\n",err_msg);
  1683.     if(!ignore_errors) inform_user(err_msg);
  1684.     else if(!be_quiet && !logfile_open)
  1685.       printf("\r%s\n",err_msg);
  1686.     return(-1);
  1687.   } /* else */
  1688.   return(0);
  1689. }
  1690.  
  1691. /*
  1692.  * log_disktype() tries to get information about the disk in the given
  1693.  * unit and writes them into the logfile.
  1694.  */
  1695.  
  1696. void log_disktype(unit)
  1697. { static char *local_msg[][]= {
  1698.     { " disk in DF%ld:\n",       /* 0 */
  1699.     },
  1700.     { " Diskette im DF%ld:\n",
  1701.     },
  1702.     { " disque dans DF%ld:\n",
  1703.     },
  1704.     { " disco in DF%ld:\n",
  1705.     }
  1706.   };
  1707.  
  1708.   if(fp)
  1709.   { switch(disk_type(unit))
  1710.     { case DRIVE3_5:  fprintf(fp,"3.5\" ");
  1711.                       break;
  1712.       case DRIVE5_25: fprintf(fp,"5.25\" ");
  1713.                       break;
  1714.       case 3:         fprintf(fp,"3.5\" w/ 150 RPM "); /* == DRIVE3_5_150RPM */
  1715.                       break;
  1716.     }
  1717.     if(read_block(unit, 0L) == 0)
  1718.     { long *t= DFxInfo[unit].Buffer; /* get disk type (dos.h) */
  1719.       switch(*t)
  1720.       { case 'KICK':  fprintf(fp,"Kickstart");
  1721.                       break;
  1722.         case 'DOS\0': fprintf(fp,"DOS");
  1723.                       break;
  1724.         case 'DOS\1': fprintf(fp,"FFS");
  1725.                       break;
  1726.         case 'DOS\2': fprintf(fp,"INTER DOS");
  1727.                       break;
  1728.         case 'DOS\3': fprintf(fp,"INTER FFS");
  1729.                       break;
  1730.         case 'DOS\4': fprintf(fp,"FASTDIR DOS");
  1731.                       break;
  1732.         case 'DOS\5': fprintf(fp,"FASTDIR FFS");
  1733.                       break;
  1734.         case 'NDOS':  fprintf(fp,"NDOS (not really DOS)");
  1735.                       break;
  1736.         case 'MSD\0': fprintf(fp,"MS-DOS");
  1737.                       break;
  1738.         default:      fprintf(fp,"????");
  1739.                       break;
  1740.       }
  1741.     }
  1742.     else fprintf(fp,"????");
  1743.     fprintf(fp,local_msg[language][0],unit);
  1744.   }
  1745. }
  1746.  
  1747. /*
  1748.  * dcmp_check_brk() returns TRUE in case of a break
  1749.  */
  1750.  
  1751. BOOL dcmp_check_brk()
  1752. { BOOL brk= FALSE; /* ... we have to collect all the messages */
  1753.  
  1754.   while(imsg=(struct IntuiMessage *)GetMsg(Window->UserPort))
  1755.   { ULONG  class = imsg->Class;
  1756.     USHORT code  = imsg->Code;
  1757.     USHORT qual  = imsg->Qualifier;
  1758.     ReplyMsg(imsg);
  1759.     switch(class)
  1760.     { case CLOSEWINDOW:
  1761.         mark(depart);
  1762.         brk= TRUE;
  1763.         break;
  1764.       case GADGETUP:  /* can only be Stop! */
  1765.         brk= TRUE;
  1766.         break;
  1767.       case RAWKEY:
  1768.       { char buf[10];
  1769.         if(dos_rkcv((int)code,(int)qual, &buf[0], 10))
  1770.         { if(buf[0]=='t' || buf[0]=='T' || buf[0]==' ' || buf[0]=='\33')
  1771.             brk= TRUE;
  1772.         }
  1773.       }
  1774.       break;
  1775.     }
  1776.   }
  1777.   return(brk);
  1778. }
  1779.  
  1780. /*
  1781.  * dcmp_cmptrk() compares the two tracks (in buffer a and b) and returns
  1782.  *               TRUE  if they are *NOT* equal,
  1783.  *               FALSE if they are equal.
  1784.  */
  1785.  
  1786. BOOL dcmp_cmptrk(ULONG *a, ULONG *b)
  1787. { int l; /* long counter */
  1788.   for(l=0; l<(BYTES_PER_TRACK/4); l++)
  1789.   { if(a[l] != b[l])
  1790.       return(TRUE);
  1791.   }
  1792.   return(FALSE);
  1793. }
  1794.  
  1795.  
  1796. /*
  1797.  * do_dcmp_stuff()  (no comment)
  1798.  */
  1799.  
  1800. do_dcmp_stuff()
  1801. { int st,   /* track to start with (first to read) */
  1802.       et,   /* track to end with (last to read) */
  1803.       so,   /* first long to compare (on first track) */
  1804.       eo,   /* last long to compare (on last track) */
  1805.       diff, /* #of differences on a track */
  1806.       trk,  /* track counter */
  1807.       err,  /* error state */
  1808.       b;    /* general counter */
  1809.  
  1810.   ULONG *rb, /* read buffer */
  1811.         *cb; /* compare buffer */
  1812.  
  1813.   static char *weak_fmt[]=
  1814.   { "Warning: Weak data detected on DF%ld: track %ld.",
  1815.     "Achtung: Schwache Magnetisierung auf DF%ld: Track %ld.",
  1816.     "Attention: je ne sais pas?! %ld/%ld.",
  1817.     "Attenzione: magnetizzazione debole su DF%ld: traccia %ld."
  1818.   };
  1819.  
  1820.   if(display_window)  /* otherwise we already checked it */
  1821.   { if(start_blk>end_blk) /* -> swap start/end */
  1822.     { b= start_blk;
  1823.  
  1824.       /* we should start on SEC 00 and end on SEC 10 ... */
  1825.  
  1826.       start_blk= end_blk - (end_blk % BLOCKS_PER_CYLINDER);
  1827.  
  1828.       end_blk= b - (b % BLOCKS_PER_CYLINDER)
  1829.                  + (BLOCKS_PER_CYLINDER - 1);
  1830.  
  1831.       set_iboxval(start_blk / BLOCKS_PER_CYLINDER,
  1832.                   end_blk / BLOCKS_PER_CYLINDER,
  1833.                   -1, -1, -1);
  1834.     }
  1835.   }
  1836.   /* open drive unit(s) */
  1837.  
  1838.   if(open_dcmp_stuff() == FALSE)
  1839.   { mark(error_state);
  1840.     return;
  1841.   }
  1842.  
  1843.   /* open logfile */
  1844.  
  1845.   if(write_logfile)
  1846.   { open_logfile();
  1847.     if(logfile_open)
  1848.     { log_disktype(unit_r); /* write information about the disk type(s) */
  1849.       if(unit_r != unit_c)
  1850.         log_disktype(unit_c);
  1851.     }
  1852.   }
  1853.  
  1854.   init_global_values();
  1855.  
  1856.   rb= DFxInfo[unit_r].Buffer; /* read buffer */
  1857.   if(unit_r != unit_c)
  1858.     cb= DFxInfo[unit_c].Buffer; /* compare buffer */
  1859.   else cb= (ULONG *)NULL;
  1860.  
  1861.   st= start_blk/BLOCKS_PER_TRACK;
  1862.   et= end_blk/BLOCKS_PER_TRACK;
  1863.  
  1864.   so= (start_blk%BLOCKS_PER_TRACK) * (BYTES_PER_BLOCK/4);
  1865.   eo= BYTES_PER_TRACK/4;
  1866.  
  1867.   for(trk=st; trk<=et && !danger; trk++)
  1868.   {
  1869.     if(!be_quiet)
  1870.     { printf("\r%ld",trk);
  1871.       fflush(stdout);
  1872.     }
  1873.     diff= 0; /* no differences (yet) */
  1874.  
  1875.     /* read track into DFxInfo[unit_r].Buffer */
  1876.  
  1877.     if(display_window) set_trackframe(trk,-1,ratt,"r");
  1878.     err= dcmp_read(unit_r, trk, rb); /* read track into rb */
  1879.     if(err)
  1880.     { if(!ignore_errors)
  1881.         mark(error_state);
  1882.     }
  1883.  
  1884.     /* deep read for unit_r */
  1885.  
  1886.     else if(deep_read && deep_buffer)
  1887.     { if(display_window && (unit_r == unit_c))
  1888.         set_trackframe(trk,-1,ratt,"v");
  1889.       do_command(DFxInfo[unit_r].IOExtTD, CMD_CLEAR);
  1890.          /* force the current track to be re-read */
  1891.       err= dcmp_read(unit_r, trk, deep_buffer);
  1892.       if(err)
  1893.       { if(!ignore_errors)
  1894.           mark(error_state);
  1895.       }
  1896.       else if(dcmp_cmptrk(rb, deep_buffer))
  1897.       { char weak_msg[128];
  1898.         sprintf(weak_msg, weak_fmt[language], unit_r, trk);
  1899.         if(write_logfile && logfile_open)
  1900.           fprintf(fp,"** %s\n",weak_msg);
  1901.         if(!be_quiet) printf("\r%s\n",weak_msg);
  1902.         wtrk++; /* increase #of weak tracks */
  1903.         if(display_window) /* w == weak */
  1904.         { set_trackframe(trk,(unit_r==unit_c)?(1):(-1),ratt,"w");
  1905.           err++; /* don't change trackframe/compare */
  1906.         }
  1907.       }
  1908.     }
  1909.  
  1910.     if(!err && (unit_r != unit_c))   /* only if 00,ok,00,00 */
  1911.     {
  1912.       /* read track into DFxInfo[unit_c].Buffer */
  1913.  
  1914.       if(display_window) set_trackframe(trk,-1,ratt,"c");
  1915.       err= dcmp_read(unit_c, trk, cb); /* read track into rb */
  1916.       if(err)
  1917.       { if(!ignore_errors)
  1918.           mark(error_state);
  1919.       }
  1920.  
  1921.       /* deep read for unit_c */
  1922.  
  1923.       else if(deep_read && deep_buffer)
  1924.       { do_command(DFxInfo[unit_c].IOExtTD, CMD_CLEAR);
  1925.            /* force the current track to be re-read */
  1926.         err= dcmp_read(unit_c, trk, deep_buffer);
  1927.         if(err)
  1928.         { if(!ignore_errors)
  1929.             mark(error_state);
  1930.         }
  1931.         else if(dcmp_cmptrk(cb, deep_buffer))
  1932.         { char weak_msg[128];
  1933.           sprintf(weak_msg, weak_fmt[language], unit_c, trk);
  1934.           if(write_logfile && logfile_open)
  1935.             fprintf(fp,"** %s\n",weak_msg);
  1936.           if(!be_quiet) printf("\r%s\n",weak_msg);
  1937.           wtrk++; /* increase #of weak tracks */
  1938.           if(display_window)
  1939.           { set_trackframe(trk,-1,ratt,"w"); /* w == weak */
  1940.             err++;
  1941.           }
  1942.         }
  1943.       }
  1944.  
  1945.       if(!err) /* both tracks successfully read */
  1946.       { int lw;  /* longword counter */
  1947.         if(trk == et)
  1948.           eo= (1+(end_blk%BLOCKS_PER_TRACK)) * (BYTES_PER_BLOCK/4);
  1949.           /* maybe we are not to compare the last track fully... */
  1950.         for(lw=so; lw<eo; lw++)
  1951.         { if(rb[lw] != cb[lw])
  1952.           { int sec= lw / (BYTES_PER_BLOCK/4); /* actual sector */
  1953.             dblk_list[dblk]=(trk*BLOCKS_PER_TRACK)+sec;
  1954.             dblk++; /* increase #of differing blocks found */
  1955.             lw= (sec+1) * (BYTES_PER_BLOCK/4); /* seek to next block */
  1956.             diff++; /* another difference on this track */
  1957.           }
  1958.         }
  1959.         if(diff>0) dtrk++; /* increase #of differing tracks */
  1960.         so=0; /* from now on we start comparing with the first long */
  1961.       }
  1962.     }
  1963.  
  1964.     if(display_window)   /* display the result in the trackframes */
  1965.     { if(err == 0) /* otherwise we already displayed it */
  1966.         set_trackframe(trk,diff,ratt,NULL); /* NULL == ' ' */
  1967.       if(dcmp_check_brk())  /* check the gadgets */
  1968.       { if(!danger)
  1969.           mark(error_state); /* otherwise it might be lenthal... */
  1970.       }
  1971.     }
  1972.   }
  1973.  
  1974.   if(logfile_open)
  1975.   { if(write_logfile)
  1976.       write_statistics(fp,1); /* 1 == full statistics */
  1977.     close_logfile();
  1978.   }
  1979.   close_dcmp_stuff();
  1980. }
  1981.  
  1982. /*
  1983.  * Information when started from CLI/Shell (How to use)
  1984.  */
  1985.  
  1986. static char *howtouse[]=
  1987. { "\nLegal options are:\n",
  1988.   "-t              write transcript to `dcmp.log'",
  1989.   "-l <LogFile>    write extended transcript to `LogFile'",
  1990.   "-i              create project icon with logfile",
  1991.   "-v              verify tracks after read (detect weak data)",
  1992.   "-w              display information in a window",
  1993.   "-a (-r)         set #of attempts to read (retries)",
  1994.   "-b              break on (read) errors.",
  1995.   "-sc <cylinder>  start with cylinder #<cylinder> sector #0",
  1996.   "-st <track>     start with track #<track> sector #0",
  1997.   "-ss <sector>    start with sector #<sector>",
  1998.   "-sb <block>     start with block #<block>",
  1999.   "-ec <cylinder>  end with last cylinder #<cylinder> sector #0",
  2000.   "-et <track>     end with last track #<track> sector #0",
  2001.   "-es <sector>    end with last sector #<sector>",
  2002.   "-eb <block>     end with last block #<block>",
  2003.   "\nALL THIS IS HIGHLY EXPERIMENTAL !!! TAKE GREAT CARE !!!",
  2004.   "",
  2005.   /* end of `how to use' */
  2006. };
  2007.  
  2008. /* --------------------------- P R I V A T E ------------------------------ */
  2009.  
  2010. #include <time.h>
  2011.  
  2012. void dcmp_private()
  2013. { struct tm *lt;
  2014.   long t;
  2015.  
  2016.   static char *private_msg[][]= {
  2017.     { "Today is a very special day! It's the author's birthday !\n"
  2018.       "So if you did not already make your greetings-card pop through\n"
  2019.       "my letter-box yet then do so (hurry up)!"
  2020.       ,"happy","birthday",
  2021.       "It seems as if your internal clock is not set correctly!\n"
  2022.       "I strongly recommend to adjust this!"
  2023.       ,"","Oh, thanks!"
  2024.     },
  2025.     { "Heute ist ein ganz besonderer Tag!  Heute hat nämlich der\n"
  2026.       "Autor von DCMP Geburtstag !  Wenn Sie mir also noch keine\n"
  2027.       "Karte geschrieben haben, wird's jetzt aber höchste Zeit!"
  2028.       ,"Herzlichen", "Glückwunsch",
  2029.       "Was ist denn mit Ihrer Uhr los?  Das Datum geht nach!"
  2030.       ,"Oh, Mist", "Leck' mich",
  2031.     },
  2032.     { "Aujourd'hui c'est un jour magnifique. C'est aujourd'hui que\n"
  2033.       "l'auteur de DCMP a son jour d'anniversaire.  Si vous n'avez\n"
  2034.       "pas écrit de carte, dépêchez-vous!"
  2035.       ,"", "Bon anniversaire",
  2036.       "Qu'est-ce qui se passe avec votre montre?\n"
  2037.       "La date n'est pas correcte"
  2038.       ,"", "Chiure",  /* <- Fliegendreck! */
  2039.     },
  2040.     { "Oggi è festa! Sì, è il compleanno! (Pure l'autore del\n"
  2041.       "programma sta invecchiando, poverino!) Se non avete ancora\n"
  2042.       "mandato una cartolina, fatelo adesso per consolarlo\n"
  2043.       ,"","Tanti auguri!",
  2044.       "Non funziona più l'orologio? Bisogna mettere a posto la data!\n"
  2045.       ,"", "Porca miseria!",
  2046.     }
  2047.   };
  2048.  
  2049.   time(&t);
  2050.   lt= localtime(&t);
  2051.  
  2052.   if(lt->tm_year < 93)
  2053.     dcmp_Request(private_msg[language][3],
  2054.                  private_msg[language][4],
  2055.                  private_msg[language][5] );
  2056.  
  2057.   else if(lt->tm_mday == 27 && lt->tm_mon == 8) /* 27.09. */
  2058.     dcmp_Request(private_msg[language][0],
  2059.                  private_msg[language][1],
  2060.                  private_msg[language][2] );
  2061.  
  2062.  
  2063. }
  2064.  
  2065. /* ------------------------------------------------------------------------ */
  2066.  
  2067. /*
  2068.  * main()
  2069.  */
  2070.  
  2071. main(int argc, char *argv[])
  2072. { char *arg;  /* parsed argument */
  2073.   int i;      /* general counter */
  2074.  
  2075.   BOOL do_about= FALSE; /* see about message in the window */
  2076.  
  2077.   onbreak(_abort);  /* this is DICE */
  2078.   whoami=argv[0];   /* and this is me */
  2079.  
  2080.   dcmp_private();
  2081.  
  2082.   puts(rcs_id);
  2083.   if(argc==2 && (argv[1][0]=='?'||argv[1][0]=='.'))
  2084.   { puts(BANNER);
  2085.     puts(USAGE);
  2086.     for(i=0;*howtouse[i];puts(howtouse[i++]));  /* how to use */
  2087.     exit(0);
  2088.   }
  2089.  
  2090.   /* parse args */
  2091.  
  2092.   argc--;
  2093.   argv++;
  2094.  
  2095.   while(argc>0 && !danger)
  2096.   { arg=argv[0];
  2097.     if(*arg=='-')
  2098.     { arg++;
  2099.       switch(*arg)
  2100.       { case 'l': case 'L': case 'o': case 'O':
  2101.           if(arg[1]) strcpy(logfile_name,arg+1);
  2102.           else
  2103.           { argv++;
  2104.             argc--;
  2105.             strcpy(logfile_name,argv[0]);
  2106.           }
  2107.           write_logfile= TRUE;
  2108.           break;
  2109.         case 't': case 'T':
  2110.           strcpy(logfile_name, DEF_LOGFILE);
  2111.           write_logfile= TRUE;
  2112.           break;
  2113.         case 'i': case 'I':
  2114.           write_icon= TRUE; /* note: no logfile -> no icon! */
  2115.           break;
  2116.         case 'v': case 'V': case 'd': case 'D':
  2117.           deep_read= TRUE;
  2118.           break;
  2119.         case 'a': case 'A':  case 'r': case 'R':
  2120.           if(arg[1]) attempts=atoi(arg+1);
  2121.           else
  2122.           { argv++;
  2123.             argc--;
  2124.             attempts=atoi(argv[0]);
  2125.           }
  2126.           if(0>=attempts||attempts>MAX_ATTEMPTS)
  2127.           { printf("Illegal #of attempts: %ld.  Must be in [1..10].\n",attempts);
  2128.             mark(error_state);
  2129.           }
  2130.           break;
  2131.         case 's': case 'S':
  2132.           switch(*++arg)
  2133.           {  case 'b': case'B':
  2134.               if(arg[1]) start_blk=atoi(arg+1);
  2135.               else
  2136.               { argv++;
  2137.                 argc--;
  2138.                 start_blk=atoi(argv[0]);
  2139.               }
  2140.               if(start_blk<FIRSTBLOCK||start_blk>LASTBLOCK)
  2141.               { printf("Illegal block number: %ld.  Must be in [0..1759].\n",start_blk);
  2142.                 mark(error_state);
  2143.               }
  2144.               break;
  2145.             case 'c': case 'C':
  2146.               if(arg[1]) i=atoi(arg+1);
  2147.               else
  2148.               { argv++;
  2149.                 argc--;
  2150.                 i=atoi(argv[0]);
  2151.               }
  2152.               if(0<=i&&i<=79) start_blk=i*BLOCKS_PER_CYLINDER;
  2153.               else
  2154.               { printf("Illegal cylinder number: %ld.  Must be in [0..79].\n",i);
  2155.                 mark(error_state);
  2156.               }
  2157.               break;
  2158.             case 't': case 'T':
  2159.               if(arg[1]) i=atoi(arg+1);
  2160.               else
  2161.               { argv++;
  2162.                 argc--;
  2163.                 i=atoi(argv[0]);
  2164.               }
  2165.               if(0<=i&&i<=159) start_blk=i*BLOCKS_PER_TRACK;
  2166.               else
  2167.               { printf("Illegal track number: %ld.  Must be in [0..159].\n",i);
  2168.                 mark(error_state);
  2169.               }
  2170.               break;
  2171.             case 's': case 'S':
  2172.               if(arg[1]) i=atoi(arg+1);
  2173.               else
  2174.               { argv++;
  2175.                 argc--;
  2176.                 i=atoi(argv[0]);
  2177.               }
  2178.               if(0<=i&&i<=10)
  2179.               { i-= (start_blk%BLOCKS_PER_TRACK);
  2180.                 start_blk+=i;
  2181.               }
  2182.               else
  2183.               { printf("Illegal sector number: %ld.  Must be in [0..10].\n",i);
  2184.                 mark(error_state);
  2185.               }
  2186.               break;
  2187.             default:
  2188.               printf("Illegal start option `-s%c'.  Try -sc,-st,-sb,-ss\n",*arg);
  2189.               mark(error_state);
  2190.           }
  2191.           break;
  2192.         case 'e': case 'E':
  2193.           switch(*++arg)
  2194.           { case 'b': case 'B':
  2195.               if(arg[1]) end_blk=atoi(arg+1);
  2196.               else
  2197.               { argv++;
  2198.                 argc--;
  2199.                 end_blk=atoi(argv[0]);
  2200.               }
  2201.               if(end_blk<FIRSTBLOCK||end_blk>LASTBLOCK)
  2202.               { printf("Illegal block number: %ld.  Must be in [0..1759].\n",end_blk);
  2203.                 mark(error_state);
  2204.               }
  2205.               break;
  2206.             case 'c': case 'C':
  2207.               if(arg[1]) i=atoi(arg+1);
  2208.               else
  2209.               { argv++;
  2210.                 argc--;
  2211.                 i=atoi(argv[0]);
  2212.               }
  2213.               if(0<=i&&i<=79) end_blk=i*BLOCKS_PER_CYLINDER;
  2214.               else
  2215.               { printf("Illegal cylinder number: %ld.  Must be in [0..79].\n",i);
  2216.                 mark(error_state);
  2217.               }
  2218.               break;
  2219.             case 't': case 'T':
  2220.               if(arg[1]) i=atoi(arg+1);
  2221.               else
  2222.               { argv++;
  2223.                 argc--;
  2224.                 i=atoi(argv[0]);
  2225.               }
  2226.               if(0<=i&&i<=159) end_blk=i*BLOCKS_PER_TRACK;
  2227.               else
  2228.               { printf("Illegal track number: %ld.  Must be in [0..159].\n",i);
  2229.                 mark(error_state);
  2230.               }
  2231.               break;
  2232.             case 's': case 'S':
  2233.               if(arg[1]) i=atoi(arg+1);
  2234.               else
  2235.               { argv++;
  2236.                 argc--;
  2237.                 i=atoi(argv[0]);
  2238.               }
  2239.               if(0<=i&&i<=10)
  2240.               { i-= (end_blk%BLOCKS_PER_TRACK);
  2241.                 end_blk+= i;
  2242.               }
  2243.               else
  2244.               { printf("Illegal sector number: %ld.  Must be in [0..10].\n",i);
  2245.                 mark(error_state);
  2246.               }
  2247.               break;
  2248.             default:
  2249.               printf("Illegal end option `-e%c'.  Try -ec,-et,-eb,-es\n",*arg);
  2250.               mark(error_state);
  2251.           }
  2252.           break;
  2253.         case 'w': case 'W':
  2254.           display_window= TRUE;
  2255.           break;
  2256.         case 'b': case 'B':
  2257.           ignore_errors= FALSE;
  2258.           break;
  2259.         case '?':
  2260.           do_about= TRUE;
  2261.           break;
  2262.         default:
  2263.           printf("Illegal option: -%s !\n",arg);
  2264.           mark(error_state);
  2265.       }
  2266.     }
  2267.     /*
  2268.      * parse drive unit
  2269.      */
  2270.     else if((arg[0]=='D'||arg[0]=='d')&&(arg[1]=='F'||arg[1]=='f'))
  2271.     { i=(int)(arg[2]-'0');
  2272.       if(0>i||i>3)
  2273.       { puts("Illegal drive unit.  Try DF0..DF3.");
  2274.         mark(error_state);
  2275.       }
  2276.       else if(unit_r<0) unit_r=unit_c=i;  /* one given unit# fills both */
  2277.       else unit_c=i;
  2278.     }
  2279.     argc--;
  2280.     argv++;
  2281.   }
  2282.  
  2283.   if(!danger && !display_window && unit_r<0 && unit_c<0)
  2284.   { puts("\rNo drive(s) specified.");
  2285.     puts(USAGE);    /* we need at least *one* unit# without window */
  2286.     mark(error_state);
  2287.   }
  2288.  
  2289.   if(!danger)
  2290.   {
  2291.     if(start_blk > end_blk) /* -> swap start and end */
  2292.     { i=start_blk;
  2293.       start_blk=end_blk;
  2294.       end_blk=i;
  2295.     }
  2296.  
  2297.     if(!display_window)
  2298.     { printf(CRSR_OFF); /* no cursor! */
  2299.       if(unit_r == unit_c)
  2300.       { printf("Checking Disk in DF%ld: (block %ld to %ld).\n",
  2301.                 unit_r,start_blk,end_blk);
  2302.       }
  2303.       else
  2304.       { printf("Comparing DF%ld: with DF%ld: (block %ld to %ld).\n",
  2305.                 unit_r,unit_c,start_blk,end_blk);
  2306.       }
  2307.       do_dcmp_stuff();
  2308.       printf(CRSR_ON); /* cursor on! */
  2309.       write_statistics(stdout,0); /* 0 = results only */
  2310.       if(write_logfile)
  2311.       { printf("\rtranscript %s %s%s",
  2312.                 (logdata_added)?("appended to"):("written on"),
  2313.                 logfile_name,
  2314.                 (write_icon)?(" w/ icon\n"):("\n") );
  2315.       }
  2316.     }
  2317.     else
  2318.     { open_window_stuff();
  2319.       if(!danger)
  2320.       { be_quiet= TRUE;  /* since we've got a window... */
  2321.         if(do_about) about();
  2322.         handle_window_stuff();
  2323.       }
  2324.     }
  2325.     wrap_up();
  2326.   }
  2327. }
  2328.  
  2329. /* legal ToolTypes are: */
  2330.  
  2331. #define TT_NAME         "NAME"
  2332. #define TT_FIRSTCYL     "FIRST CYL"
  2333. #define TT_LASTCYL      "LAST CYL"
  2334. #define TT_ATTEMPTS     "ATTEMPTS"
  2335. #define TT_LOGFILE      "LOGFILE"
  2336. #define TT_LOGICON      "LOGICON"
  2337. #define TT_DEFAULTTOOL  "DEFAULT TOOL"
  2338. #define TT_IGNOREERRORS "IGNORE ERRORS"
  2339. #define TT_DEEPREAD     "DEEP READ"
  2340. #define TT_LANGUAGE     "LANGUAGE"
  2341. #define TT_MOUSEPOINTER "MOUSEPOINTER"
  2342. #define TT_BUSYBEE      "WAITPOINTER"
  2343.  
  2344. wbmain(struct WBStartup *WBStartup)
  2345. {
  2346.   static char *err_msg[][]= {
  2347.     { "Unable to open icon.library (hey, why?!)", "", "Oh shit!", /* 0,1,2 */
  2348.       "Can't open dcmp's window stuff!", "", "Fuck it"            /* 3,4,5 */
  2349.     },
  2350.     { "Ich kann die icon.library nicht öffnen!", "", "Sowas Dummes",
  2351.       "Das Fenster mag sich nicht öffnen lassen","","Schade"
  2352.     },
  2353.     { "Pas d'icon.library!?", "", "Quoi?",
  2354.       "Je ne peux pas ouvrir la fenêtre!", "", "Comment, pas?"
  2355.     },
  2356.     { "Non posso aprire l'icon.library!", "", "Peccato",
  2357.       "La finestra non si fa aprire","","Come, non aprire?"
  2358.     },
  2359.   };
  2360.  
  2361.   be_quiet= TRUE;  /* IMPORTANT!!! */
  2362.   display_window= TRUE;
  2363.  
  2364.   IconBase= (struct IconBase *)OpenLibrary(ICONNAME,LIBRARY_VERSION);
  2365.   if(IconBase)
  2366.   { struct WBArg *wbarg= WBStartup->sm_ArgList;
  2367.     struct DiskObject *icon;
  2368.     whoami= wbarg->wa_Name;
  2369.     CurrentDir(wbarg->wa_Lock);
  2370.     icon= GetDiskObject(wbarg->wa_Name);
  2371.     if(icon)
  2372.     { char *ttv, **tt= icon->do_ToolTypes;
  2373.  
  2374. /* --------------------------- P R I V A T E ------------------------------ */
  2375.  
  2376.       ttv= FindToolType(tt, TT_NAME);
  2377.       if(ttv)
  2378.       { if(MatchToolValue(ttv,"Mike"))   /* Mike's settings */
  2379.         { unit_r= 0; unit_c= 0;
  2380.           strcpy(logfile_name,DEF_LOGFILE); write_logfile= TRUE;
  2381.           strcpy(DefaultTool,"c:MuchMore"); write_icon= TRUE;
  2382.           start_blk= 0; end_blk= 1759; attempts= 2;
  2383.           language=1; ignore_errors= TRUE; deep_read= TRUE;
  2384.         }
  2385.         else if(MatchToolValue(ttv,"Harald"))
  2386.         { dcmp_pointer= SMI_NONE;
  2387.           busybee= SMI_STOPWATCH;
  2388.         }
  2389.         else if(MatchToolValue(ttv,"Tobias"))
  2390.         { dcmp_pointer= SMI_KLONDIKE;
  2391.           busybee= SMI_SLEEPGLOVE;
  2392.         }
  2393.         else if(MatchToolValue(ttv,"Angela")) dcmp_pointer= SMI_NESSIE;
  2394.       }
  2395. /* ------------------------------------------------------------------------ */
  2396.  
  2397.       ttv= FindToolType(tt, TT_FIRSTCYL);
  2398.       if(ttv)
  2399.       { int c= atoi(ttv);
  2400.         if(c<0) c=0;
  2401.         else if(c>79) c=79;
  2402.         start_blk= c*BLOCKS_PER_CYLINDER;
  2403.       }
  2404.       ttv= FindToolType(tt, TT_LASTCYL);
  2405.       if(ttv)
  2406.       { int c= atoi(ttv);
  2407.         if(c<0) c=0;
  2408.         else if(c>79) c=79;
  2409.         end_blk= c*BLOCKS_PER_CYLINDER + BLOCKS_PER_CYLINDER -1;
  2410.       }
  2411.       ttv= FindToolType(tt, TT_ATTEMPTS);
  2412.       if(ttv)
  2413.       { attempts= atoi(ttv);
  2414.         if(attempts<1) attempts= 1;
  2415.         else if(attempts>MAX_ATTEMPTS) attempts= MAX_ATTEMPTS;
  2416.       }
  2417.       ttv= FindToolType(tt, TT_LOGFILE);
  2418.       if(ttv)
  2419.       { strcpy(logfile_name, ttv);
  2420.         write_logfile= TRUE;
  2421.       }
  2422.       ttv= FindToolType(tt, TT_LOGICON);
  2423.       if(ttv) write_icon= MatchToolValue(ttv,"ON");
  2424.       ttv= FindToolType(tt, TT_DEFAULTTOOL);
  2425.       if(ttv) strcpy(DefaultTool, ttv);
  2426.       ttv= FindToolType(tt, TT_IGNOREERRORS);
  2427.       if(ttv) ignore_errors= MatchToolValue(ttv,"ON");
  2428.       ttv= FindToolType(tt, TT_DEEPREAD);
  2429.       if(ttv) deep_read= MatchToolValue(ttv,"ON");
  2430.       ttv= FindToolType(tt, TT_LANGUAGE);
  2431.       if(ttv)
  2432.       { if(MatchToolValue(ttv,"ENGLISH")) language= 0;
  2433.         else if(MatchToolValue(ttv,"ENGLISCH")) language= 0;
  2434.         else if(MatchToolValue(ttv,"GERMAN")) language= 1;
  2435.         else if(MatchToolValue(ttv,"DEUTSCH")) language= 1;
  2436.         else if(MatchToolValue(ttv,"FRENCH")) language= 2;
  2437.         else if(MatchToolValue(ttv,"FRANZÖSISCH")) language= 2;
  2438.         else if(MatchToolValue(ttv,"FRANCAIS")) language= 2;
  2439.         else if(MatchToolValue(ttv,"FRANÇAIS")) language= 2;
  2440.         else if(MatchToolValue(ttv,"ITALIEN")) language= 3;
  2441.         else if(MatchToolValue(ttv,"ITALIENISCH")) language= 3;
  2442.         else if(MatchToolValue(ttv,"ITALIANO")) language= 3;
  2443.         else if(MatchToolValue(ttv,"ASYL")) language= 3; /* not ready yet...*/
  2444.       }
  2445.       ttv= FindToolType(tt, TT_MOUSEPOINTER);
  2446.       if(ttv)
  2447.       { if(MatchToolValue(ttv,"PREFSPOINTER")) dcmp_pointer= SMI_PREFS;
  2448.         else if(MatchToolValue(ttv,"DEFAULT")) dcmp_pointer= SMI_NONE;
  2449.         else if(MatchToolValue(ttv,"KLONDIKE")) dcmp_pointer= SMI_KLONDIKE;
  2450.         else if(MatchToolValue(ttv,"NESSIE")) dcmp_pointer= SMI_NESSIE;
  2451.         else if(MatchToolValue(ttv,"DOTTY")) dcmp_pointer= SMI_DOTTY;
  2452.         else if(MatchToolValue(ttv,"STANDARD20")) dcmp_pointer=SMI_STANDARD20;
  2453.         else if(MatchToolValue(ttv,"STANDARD2.0")) dcmp_pointer=SMI_STANDARD20;
  2454.         else if(MatchToolValue(ttv,"CROSSHAIR")) dcmp_pointer=SMI_CROSSHAIR;
  2455.         else if(MatchToolValue(ttv,"TINY")) dcmp_pointer=SMI_TINY;
  2456.       }
  2457.       ttv= FindToolType(tt, TT_BUSYBEE);
  2458.       if(ttv)
  2459.       { if(MatchToolValue(ttv,"OFF")) busybee= SMI_NONE;
  2460.         else if(MatchToolValue(ttv,"BUSYBEE")) busybee= SMI_BUSYBEE;
  2461.         else if(MatchToolValue(ttv,"ZZBUBBLE")) busybee= SMI_ZZBUBBLE;
  2462.         else if(MatchToolValue(ttv,"STOPWATCH")) busybee= SMI_STOPWATCH;
  2463.         else if(MatchToolValue(ttv,"HOURGLASS")) busybee= SMI_HOURGLASS;
  2464.         else if(MatchToolValue(ttv,"SLEEPGLOVE")) busybee= SMI_SLEEPGLOVE;
  2465.       }
  2466.  
  2467.       /* EXPERIMENTAL STUFF !!! */
  2468.  
  2469.       ttv= FindToolType(tt, "NICEOPENSPEED");
  2470.       if(ttv) { NiceOpenSpeed= atoi(ttv); if(NiceOpenSpeed > 20) NiceOpenSpeed= 20; }
  2471.       ttv= FindToolType(tt, "NICECLOSESPEED");
  2472.       if(ttv) { NiceCloseSpeed= atoi(ttv); if(NiceCloseSpeed > 20) NiceCloseSpeed= 20; }
  2473.  
  2474.       FreeDiskObject(icon);
  2475.     }
  2476.     /* else (we got no icon) -> we were not started from Workbench */
  2477.     CloseLibrary(IconBase);
  2478.   }
  2479.   else dcmp_Request(err_msg[language][0],err_msg[language][1],err_msg[language][2]);
  2480.  
  2481.   dcmp_private();
  2482.  
  2483.   open_window_stuff();
  2484.   if(!danger) handle_window_stuff();
  2485.   else dcmp_Request(err_msg[language][3],err_msg[language][4],err_msg[language][5]);
  2486.   wrap_up();
  2487. }
  2488.