home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 307_01 / adu.c < prev    next >
C/C++ Source or Header  |  1990-03-20  |  56KB  |  1,591 lines

  1.  
  2.  
  3. /*===========================================================
  4.  
  5.             ADAPTABLE DISK UTILITY.
  6.  
  7.  
  8. Copyright (c) 1988.  This software is for non commercial
  9. use only.
  10.  
  11. ADU is and disk utility programme designed to work with both
  12. IBM PC standard and non IBM PC disk formats.  It has been
  13. written to be user configurable such that the disk parameters
  14. can be adapted to almost any conceivable disk format.  The
  15. initial Alien disk parameters are derived be scanning the
  16. disk and building up a disk_base table, which then may be
  17. modified by the user.
  18.  
  19. To Compile and Link you under Turbo C V2.0 or V1.5 create a project
  20. file ADU.PRJ containing;
  21.  
  22.         adu.c
  23.         disk_io.c
  24.         video_io.c
  25.  
  26.  
  27. User Notes: 0. Function key F1 gives help, F3 repeats the command
  28.                string without a CR, and F4 repeats the command.
  29.  
  30.             1. Numbers may be separated by either space or commas.
  31.  
  32.             2. When copying blocks you may specify a contiguous
  33.                sequence using the shorthand notation 2/22 say,
  34.                which will copy blocks 2 to 22.
  35.  
  36.             3. If you don't want to work in 'blocks' and would prefer
  37.                sectors, then set the sectors/block variable using
  38.                vb.  e.g vb = 1 and the command >>c a:fn 1/100 would
  39.                copy sectors 1 to 100 to file fn on drive a:. Note
  40.                however the Block Start refers to the track offset
  41.                from track 0, thus if Block Start equals 2 then block
  42.                1 will begin  at sector 1, track 2, side 0.
  43.  
  44.             4. If ADU returns a BIOS TIMEOUT during a diskcopying
  45.                command, it may be either due to an incorrect sector
  46.                or format skew or bad gap values. Adjusting these
  47.                should cure the problem.
  48.  
  49.             5. Commands may consist of either a single or double
  50.                letter sequence  Press F1 to get the help menu
  51.                which will indicate, in capitals the number of
  52.                significant letters.
  53.  
  54.             6. Commands may be separated by a semicolon,
  55.                for example >>+s;r;e will increment the sector, read
  56.                it in to memory and then place the user into the editor.
  57.                For example, searching for data or strings on the disk
  58.                may be facilitated by issuing the command +s;r;d. While
  59.                the sector's data is being dumped, if the required data
  60.                does not appear to be present; press F4.  Pressing F4
  61.                will interrupt the 'dump' and also, because F4 has the
  62.                effect of repeating the command then the sector number
  63.                will be incremented, read, and then dumped to the screen
  64.                - etc.
  65.  
  66.  
  67.             7. Colour codes can be found in either the XT technical
  68.                reference or various other publications.  I have chosen
  69.                the colours I find suitable. Vary the codes to either
  70.                remove the colour or adjust to suit your requirements.
  71.  
  72.             8. The inbuilt editor is not extensive and uses only some
  73.                of the cusor control keys, however it is useful.  After
  74.                completing an editing session, press the ESC key to exit
  75.                the editor and then issue the >>w command to write out
  76.                the sector.  The editor will highlight the bytes you
  77.                have changed!
  78.  
  79. =============================================================*/
  80.  
  81. #include <dos.h>
  82. #include <stdio.h>
  83. #include <conio.h>
  84. #include <ctype.h>      /* for toupper */
  85. #include <alloc.h>  /*malloc*/
  86.  
  87. #define TITLE       putfa(2,1," Adaptable Disk Utility. Version 1.6",NULL,0x07);
  88. #define AUTHOR      putfa(2,2," Copyright (c) 1988.  AME Systems",NULL,0x07);
  89.  
  90. #define BLANK       32
  91. #define FALSE       0
  92. #define TRUE        1
  93. /* #define NULL     0 */    /* Must declare this if putfa is not decalared */
  94.                             /* as a function prototype .  Anyone know why? */
  95. #define YES         1
  96. #define NO          0
  97. #define UP          6       /* used in window scroll commands */
  98. #define DOWN        7       /* used in window scroll commands */
  99. #define ERROR       -1
  100. #define LINLEN      75      /* max characters allowable in command */
  101. #define BUFFSIZ     8196        /* the largest disk buffer likely  */
  102. #define MEMLIMIT    65536       /* Allow 64k limit for malloc */
  103. #define MAX_DRIVES  6
  104. #define COLSIZ      79      /* display row and column sizes */
  105. #define ROWSIZ      24
  106. #define CURSOR_OFF  (gotoxy(0,25))  /* macro to turn cursor off */
  107. #define YELLOW_RED  0x1c        /* screen attribute for yellow on red */
  108.  
  109. /* Disk utility commands */
  110.  
  111. #define READ        1
  112. #define LOG         2
  113. #define INCSECT     3
  114. #define INCTRACK    4
  115. #define DECSECT     5
  116. #define DECTRACK    6
  117. #define COMMA       7
  118. #define END_LIN     8
  119. #define HELP        9
  120. #define DUMP        10
  121. #define QUIT        11
  122. #define COPY        12
  123. #define WRITE       13
  124. #define EDIT        14
  125. #define SHEAD       15
  126. #define SBLOCK      16
  127. #define STRACK      17
  128. #define SSECTOR     18
  129. #define VOFFSET     19
  130. #define VHEADS      20
  131. #define VBLOCKS     21
  132. #define VTRACKS     22
  133. #define VEOT        23
  134. #define VSIZE       24
  135. #define DISKCOPY    25
  136. #define SECTXLAT    26
  137. #define FMTSKEW     27
  138. #define VDRIVES     28
  139. #define DISKBASE    29
  140.  
  141. FILE *fd;                       /* General file descriptor */
  142. union REGS inregs,outregs;      /* DOS and BIOS registers */
  143.  
  144. int     drive,track,sector,head,dflag;  /* global disk parameters  */
  145. int     spb,offset,sect_size,disk_blocks,last_drive;
  146. int     evalerr;                /* getnum error flag     */
  147. int     first_sector;           /* first sector on disk */
  148. char    *linptr, linbuf[LINLEN]; /* input command line buffer etc */
  149. char    sect_buf[BUFFSIZ];      /* sectors worth of data buffer  */
  150. char    out_buf[BUFFSIZ];       /* scratch buffer for any output */
  151. int     sect_xlat[40];          /* soft sector translate table   */
  152. int     fmt_skew[40];           /* hard/format sector skew table */
  153. char    *bufptr;                /* general buffer pointer    */
  154. char    *trackbuf;              /* general pointer for diskcopy etc */
  155.  
  156. char    sbuf[20],*sptr;         /* required for itoa calls   */
  157. int     block,saddr,laddr,snum;
  158. int     lnum,eol,numflag;
  159. int     col,lin;                /* column and line variables */
  160.  
  161. /*
  162.  Define the disk_base structure.
  163. */
  164.  
  165.  
  166. typedef struct {                /* Standard IBM PC Disk Base */
  167.     unsigned char srt;          /* structure.  See IBM Tech  */
  168.     unsigned char hld;          /* reference manual for more */
  169.     unsigned char motor_wait;   /* detail.                   */
  170.     unsigned char bytes_sect;
  171.     unsigned char eot;
  172.     unsigned char rw_gap;
  173.     unsigned char dtl;
  174.     unsigned char format_gap;
  175.     unsigned char format_fill;
  176.     unsigned char hs;
  177.     unsigned char motor_start;
  178.     unsigned char sides;
  179.     unsigned char tracks;
  180.  
  181.  
  182. } disk_base;
  183.  
  184.  
  185. union {                             /* This union gives access to structure */
  186.                                     /* parameters*/
  187.     disk_base      base;
  188.     unsigned char  parm[13];
  189.  
  190. } dos;                              /* Dos disk base */
  191.  
  192.  
  193. union {
  194.  
  195.     disk_base      base;
  196.     unsigned char  parm[13];
  197.  
  198. } alien;                            /* alien disk base */
  199.  
  200. disk_base       far *pc_disk_vector;        /* declare pointers to both the  */
  201. disk_base       far *alien_disk_vector;  /* standard and alien disk bases */
  202.  
  203.  
  204.  
  205. /*--------------------Function Prototypes----------------------------*/
  206.  
  207. char        *itoa(int, char *, int);
  208. char        far *get_disk_vectors( void );
  209. int         check_sectors(int);
  210. int         check_head(int);
  211. int         disk_format(int,int,int *,int,int,int,int);
  212. int         putfa(int,int,char *,int,int);
  213. disk_base   far *get_disk_vector( void );
  214. void        put_string(char *, int);
  215. void        prompt( void );
  216. void        do_beep( void );
  217. void        getname(char *);
  218. void        dump_line(int, char *);
  219. void        header( void );
  220. void        status(char *,char *, int);
  221. void        disk_data( void );
  222. void        disk_data( void );
  223. void        disk_data_c( void );
  224. void        disk_data_v( void );
  225. void        zero_buffer(char *, int);
  226. void        block_to_tsh( void );
  227. void        next_sector( void );
  228. void        help( void );
  229. void        log_disk( void );
  230. void        init_disk_globals( void );
  231. void        identify(int);
  232. void        set_alien_parms( void );
  233.  
  234. /*-------------------------------------------------------------------*/
  235.  
  236.  
  237. main() {
  238.  
  239. char        fname[32];
  240. char        c,ch;                   /* general character declarations */
  241. int         nibble;
  242. int         i,j,jm,k,t,item,nsect;      /* general loop/buffer variables */
  243. int         x,y,ym,xoff,yoff,xl;    /* screen variables     */
  244. unsigned    int msize;              /* used to allocate memory buffer sizes */
  245.  
  246. /*
  247.  Main loop
  248. */
  249.  
  250. pc_disk_vector = get_disk_vector(); /* catch the original PC disk vector */
  251. clrscrn();                      /* clear the screen */
  252. prompt();                       /* prompt user to insert disk */
  253. clrscrn();
  254. header();                       /* place the header info on screen */
  255. init_disk_globals();            /* initialise all global variables */
  256. drive = 0;                      /* default to the a: drive  */
  257. last_drive = 2;
  258. first_sector = 0;
  259. set_alien_parms();              /* set up the alien disk base */
  260. zero_buffer(sect_buf,BUFFSIZ);  /* zero the disk buffer     */
  261. xoff = 6; yoff = 5;             /* set the screen edit variables */
  262. numflag = FALSE;                /* initialise getnum() and getitem() stuff */
  263. eol = TRUE;
  264. clr_window(0,3,COLSIZ,3,7);     /* clear status line */
  265. while(TRUE) {
  266.     set_disk_vector(pc_disk_vector);/* force this for safety reasons */
  267.                                 /* use alien vector only when required */
  268.     evalerr = FALSE;
  269.     disk_data_c();              /* update display areas */
  270.     disk_data_v();
  271.     if (eol == TRUE) {
  272.        gotoxy(0,23);
  273.        scroll_window(0,yoff-1,COLSIZ,ROWSIZ,UP);   /* main display area */
  274.        printf(">>");
  275.        get_string(linbuf);
  276.        linptr = linbuf;
  277.        eol = FALSE;             /* reset true end of line flag */
  278.        clr_window(0,3,COLSIZ,3,7);  /* clear status line */
  279.     }
  280.     item = getitem();
  281.     switch(item) {
  282.  
  283.         case DUMP:
  284.             clr_window(0,4,COLSIZ,ROWSIZ,7);    /* clear display area */
  285.             putfa(0,4," Press 'P' to pause the display. Any other key to exit ",NULL,0x4e);
  286.             jm = sect_size/16 - 1;              /* number of paragraphs in buffer */
  287.             gotoxy(0,yoff);
  288.             for (i = 0; i <= jm; i++) {
  289.                 gotoxy(0,yoff+i);
  290.                 if (kbhit()) {
  291.                     c = getch();
  292.                     if ('P' == toupper(c)) {
  293.                         while(!kbhit());        /* wait for next keystroke */
  294.                         getch();                /* before continuing dump  */
  295.                     }
  296.                     else {
  297.                         if (c == 0) c = getch();    /* If function key hit - clear it */
  298.                         break;
  299.                     }
  300.                 }
  301.                 if (i > yoff + 14) {            /* bottom of dump page  */
  302.                     scroll_window(0,yoff,COLSIZ,ROWSIZ,UP);
  303.                     gotoxy(0,23);
  304.                 }
  305.                 dump_line(i*16,sect_buf);
  306.             }
  307.             break;
  308.  
  309.         case EDIT:
  310.             /* i,j are the buffer variables */
  311.             /* x,y are the screen variables */
  312.             /* xl points to the left nibble */
  313.             /* jm,ym are the maxima values of j,y */
  314.             /* xoff,yoff are the screen reference points */
  315.             /* c is the entered character   */
  316.             /* ch is the buffer character   */
  317.  
  318.             clr_window(0,4,COLSIZ,ROWSIZ,7);    /* clear display area */
  319.             putfa(0,4," ESC to exit.  F6 (Read sector). F5 (Write sector) ",NULL,0x4e);
  320.             gotoxy(0,yoff);
  321.             ym = 15 + yoff;                     /* allow 16 lines to be displayed */
  322.             jm = sect_size/16 - 1;              /* number of paragraphs in buffer */
  323.             for (i = 0; i <= jm && i < 16; i++) {
  324.                 gotoxy(0,yoff+i);
  325.                 dump_line(i*16,sect_buf);
  326.             }
  327.             i = 0; j = 0;
  328.             x = xoff; y = yoff;
  329.             xl = x;                             /* used as left char marker */
  330.             gotoxy(x,y);
  331.             while (TRUE) {
  332.                 if (x <= xoff) {
  333.                     x = xoff;
  334.                     xl = x;
  335.                     i = 0;
  336.                 }
  337.                 if (x > 53) {                   /* position of last char */
  338.                     x = xoff; y++;
  339.                     xl = x;
  340.                     i = 0; j++;
  341.                 }
  342.                 if ( y > ym ) {
  343.                     y = ym;
  344.                     if ( j <= jm ) {
  345.                         scroll_window(0,yoff,COLSIZ,ROWSIZ,UP);
  346.                         gotoxy(0,ym);
  347.                         dump_line(j*16,sect_buf);
  348.                     }
  349.                     else j = jm;
  350.                 }
  351.                 if ( y < yoff ) {
  352.                     y = yoff;
  353.                     if (j >= 0) {
  354.                         scroll_window(0,yoff,COLSIZ,ym,DOWN);
  355.                         gotoxy(0,yoff);
  356.                         dump_line(j*16,sect_buf);
  357.                     }
  358.                     else j = 0;
  359.                 }
  360.                 if (x == xl) nibble = 0;
  361.                 else        nibble = 1;
  362.                 gotoxy(x,y);
  363.                 c = getch();            /* get character from keyboard */
  364.                 if (c == 0x1b) break;   /* esc */
  365.                 if (c == 0) {
  366.                     c = getch();        /* get extended char */
  367.                                         /* if extended perform limited process */
  368.                     switch (c) {        /* now look for cursor keys etc.   */
  369.  
  370.  
  371.                         case 63: /** F5 - Write **/
  372.                                 set_disk_vector(alien_disk_vector);
  373.                                 bufptr = sect_buf;
  374.                                 status("Writing sector buffer to disk. ","",NO);
  375.                                 dflag = disk_write(drive,track,sector,head,bufptr,1);
  376.                                 if (dflag) {
  377.                                     *((sptr = itoa(dflag,out_buf,2)) + 8) = '\0';   /* NULL terminate */
  378.                                     status("Write error to Disk. BIOS code = ",sptr,YES);
  379.                                 }
  380.                                 clr_window(0,3,COLSIZ,3,7);     /* clear status line */
  381.                                 continue;
  382.  
  383.                         case 64: /** F6 - Read **/
  384.                                 set_disk_vector(alien_disk_vector);     /* put the alien disk_base in place */
  385.                                 bufptr = sect_buf;
  386.                                 status("Reading sector into buffer. ","",NO);
  387.                                 dflag = disk_read(drive,track,sector,head,bufptr,1);
  388.                                 if (dflag) {
  389.                                     *((sptr = itoa(dflag,out_buf,2)) + 8) = '\0';   /* NULL terminate */
  390.                                     status("Read error on Disk. BIOS code = ",sptr,YES);
  391.                                 }
  392.                                 clr_window(0,3,COLSIZ,3,7);     /* clear status line */
  393.  
  394.                                 /* fall through to home function */
  395.  
  396.                         case 71: /** Home **/
  397.                                 clr_window(0,5,COLSIZ,ROWSIZ,7);    /* clear display area */
  398.                                 gotoxy(0,yoff);
  399.                                 for (i = 0; i <= jm && i < 16; i++){
  400.                                     gotoxy(0,yoff+i);
  401.                                     dump_line(i*16,sect_buf);
  402.                                 }
  403.                                 y = yoff; x = xoff;
  404.                                 i = 0; j = 0;
  405.                                 xl = x;
  406.                                 continue;
  407.  
  408.                         case 72: /** Up arrow **/
  409.                                 y--; j--;
  410.                                 continue;
  411.  
  412.                         case 75: /** Left arrow **/
  413.                                 x--;
  414.                                 if (x == xl - 1) {
  415.                                     x--; xl = x-1;
  416.                                     i--;
  417.                                 }
  418.                                 continue;
  419.  
  420.                         case 77: /** Right arrow **/
  421.                                 x++;
  422.                                 if (x == xl + 2) {
  423.                                     x++; xl = x;
  424.                                     i++;
  425.                                 }
  426.                                 continue;
  427.  
  428.                         case 79:  /** End **/
  429.                                 clr_window(0,5,COLSIZ,ROWSIZ,7);    /* clear display area */
  430.                                 gotoxy(0,yoff);
  431.                                 if (sect_size == 128) continue;
  432.                                 j = jm - 15;
  433.                                 for (i = j,k = 0; i <= jm; i++,k++){
  434.                                     gotoxy(0,yoff+k);
  435.                                     dump_line(i*16,sect_buf);
  436.                                 }
  437.                                 y = ym; x = xoff;
  438.                                 i = 0; j = jm;
  439.                                 xl = x;
  440.                                 continue;
  441.  
  442.                         case 80:  /** Down arrow **/
  443.                                 j++;y++;
  444.                                 continue;
  445.                     }
  446.  
  447.                 }
  448.                 gotoxy(x,y);                /* position for put_char */
  449.                 k = i + (j * 16);           /* buffer position */
  450.                 ch = sect_buf[k];           /* ch is the buffer character */
  451.                 c = toupper(c);             /* convert charcter to upper */
  452.                 if (isxdigit(c)) {          /* check for hex range */
  453.                     put_char(c,0x12);
  454.                     gotoxy(51+i+xoff,y);    /* point to ascii dump */
  455.                     if (isdigit(c))
  456.                         c -= '0';
  457.                     else
  458.                         c += -'@' + 9;
  459.                     if (!nibble) {
  460.                         ch &= 0x0f;
  461.                         c = (c << 4) | ch;
  462.                         x++;
  463.                         }
  464.                     else {
  465.                         ch &= 0xf0;         /* mask high nibble of buffer char */
  466.                         c |= ch;
  467.                         x += 2;             /* realign to next char */
  468.                         xl = x;
  469.                         i++;
  470.                     }
  471.                     sect_buf[k] = c;        /* place char in buffer */
  472.                     if ((c > ' ') && (c < 0x7f))
  473.                         put_char(c,0x12);   /* highlight the char */
  474.                     else
  475.                         put_char('.',0x12);
  476.                 }
  477.                 else status("Invalid key ..","",YES);
  478.                 clr_window(0,3,COLSIZ,3,7); /* clear status line */
  479.             }
  480.             break;
  481.  
  482.         case READ:
  483.                 switch(getitem()){
  484.  
  485.                     case BLANK:
  486.                             t = getnum();
  487.                             if (check_track(t))  continue;
  488.                             track = t;
  489.                             t = getnum();
  490.                             if (check_sector(t)) continue;
  491.                             sector = t;
  492.                             t = getnum();
  493.                             if (check_head(t))  continue;
  494.                             head = t;
  495.                             break;
  496.  
  497.                     case END_LIN:
  498.                             break;
  499.  
  500.                     default:    continue;
  501.  
  502.                 }
  503.                 set_disk_vector(alien_disk_vector);     /* put the alien disk_base in place */
  504.                 bufptr = sect_buf;
  505.                 dflag = disk_read(drive,track,sector,head,bufptr,1);
  506.                 if (dflag) {
  507.                     *((sptr = itoa(dflag,out_buf,2)) + 8) = '\0';   /* NULL terminate */
  508.                     status("Read error on Alien Disk. BIOS code = ",sptr,YES);
  509.                 }
  510.                 break;
  511.  
  512.         case WRITE:
  513.                 switch(getitem()){
  514.  
  515.                     case BLANK:
  516.                             t = getnum();
  517.                             if (check_track(t)) continue;
  518.                             track = t;
  519.                             t = getnum();
  520.                             if (check_sector(t)) continue;
  521.                             sector = t;
  522.                             t = getnum();
  523.                             if (check_head(t))   continue;
  524.                             head = t;
  525.                             break;
  526.  
  527.                 case END_LIN:   break;
  528.  
  529.                 default:        continue;
  530.  
  531.                 }
  532.                 set_disk_vector(alien_disk_vector);
  533.                 bufptr = sect_buf;
  534.                 dflag = disk_write(drive,track,sector,head,bufptr,1);
  535.                 if (dflag) {
  536.                     *((sptr = itoa(dflag,out_buf,2)) + 8) = '\0';   /* NULL terminate */
  537.                     status("Write error on Alien Disk. BIOS code = ",sptr,YES);
  538.                 }
  539.                 break;
  540.  
  541.         case SECTXLAT:
  542.  
  543.                 switch(getitem()){
  544.  
  545.                     case BLANK:
  546.  
  547.                             i = first_sector; t = getnum();
  548.                             while (evalerr != TRUE) {
  549.                                 if (check_sector(t)) {
  550.                                     eol = TRUE;         /* terminate processing */
  551.                                     return;
  552.                                 }
  553.                                 sect_xlat[i++] = t;     /* note - we don't use offset 0 */
  554.                                 t = getnum();
  555.                             }
  556.  
  557.                    case END_LIN:
  558.  
  559.                             putfa(0,3,"Sector Translate Table: ",NULL,0x4e);
  560.                             for (i = first_sector; i <= alien.base.eot; i++) {
  561.                                 getxy(&x,&y);
  562.                                 putfa(x,y,"%d ",sect_xlat[i],0x4e);
  563.                             }
  564.                 }
  565.                 break;
  566.  
  567.         case FMTSKEW:
  568.  
  569.                 switch(getitem()){
  570.  
  571.                     case BLANK:
  572.  
  573.                             i = first_sector; t = getnum();
  574.                             while (evalerr != TRUE) {
  575.                                 if (check_sector(t)) {
  576.                                     eol = TRUE;
  577.                                     return;
  578.                                 }
  579.                                 fmt_skew[i++] = t;
  580.                                 t = getnum();
  581.                             }
  582.  
  583.                     case END_LIN:
  584.  
  585.                         putfa(0,3,"Format Skew Table: ",NULL,0x4e);
  586.                         for (i = first_sector; i <= alien.base.eot; i++) {
  587.                             getxy(&x,&y);
  588.                             putfa(x,y,"%d ",fmt_skew[i],0x4e);
  589.                         }
  590.                 }
  591.                 break;
  592.  
  593.         case DISKBASE:
  594.  
  595.                 switch(getitem()){
  596.  
  597.                     case BLANK:
  598.  
  599.                             i = 0;
  600.                             t = getnum();
  601.                             while (evalerr != TRUE && i < 11) {
  602.                                 alien.parm[i++] = t;
  603.                                 t = getnum();
  604.                             }
  605.  
  606.                     case END_LIN:
  607.  
  608.                             putfa(0,3,"PC's Disk Base Table is (in HEX): ",NULL,0x4e);
  609.                             for (i = 0; i <= 10; i++) {
  610.                                 getxy(&x,&y);
  611.                                 putfa(x,y,"%02X ",alien.parm[i],0x4e);
  612.                             }
  613.                     }
  614.                     break;
  615.  
  616.         case COPY:
  617.  
  618.                 msize = sect_size*spb;      /* determine memory required first */
  619.                 if ((trackbuf = malloc(msize)) == NULL){
  620.                     status(" Insufficient Memory: ","",YES);
  621.                     goto label_0;
  622.                 }
  623.                 getname(fname);         /* get destination file name and open */
  624.                 set_disk_vector(pc_disk_vector);
  625.                 if ((fd = fopen(fname,"w")) == NULL) {
  626.                     status(" Can't open ",fname,YES);
  627.                     fclose(fd);
  628.                     break;
  629.                 }
  630.                 evalerr = FALSE;            /* evalerr signals end of processing */
  631.                 block = getnum();
  632.                     while (evalerr != TRUE) {
  633.                         if (check_block(block)) break;
  634.                         sptr = itoa(block,sbuf,10);
  635.                         status(" Reading block: ",sptr,NO);
  636.                         block_to_tsh();         /* get track sector head */
  637.                         bufptr = trackbuf;
  638.                         set_disk_vector(alien_disk_vector);
  639.                         for (i = 0; i < spb; i++) {     /* copy a block at a time */
  640.                             disk_data_v();
  641.                             t = sect_xlat[sector];
  642.                             dflag =  disk_read(drive,track,t,head,bufptr,1);
  643.                             if (dflag) {
  644.                                 *((sptr = itoa(dflag,sbuf,2)) + 8) = '\0';
  645.                                 status("Read error on Alien Disk. BIOS code = ",sptr,YES);
  646.                                 goto label_0;
  647.                             }
  648.                             next_sector();      /* find next track and logical sector */
  649.                             bufptr += sect_size;
  650.                         }
  651.                         bufptr = trackbuf;
  652.                         set_disk_vector(pc_disk_vector);     /* restore dos vector */
  653.                         for (j = 0; j < msize; j++) {
  654.                             fputc(*(bufptr+j),fd);
  655.                             if (ferror(fd)) {
  656.                                 clearerr(fd);
  657.                                 status ("Write error to DOS file: ",fname,YES);
  658.                                 goto label_0;
  659.                             }
  660.                         }
  661.                         block = getnum();
  662.                 }
  663.  
  664.         label_0:
  665.                 if (trackbuf != NULL) free(trackbuf);   /* give back the memory */
  666.                 set_disk_vector(pc_disk_vector);
  667.                 fclose(fd);
  668.                 break;
  669.  
  670.         case DISKCOPY:
  671.  
  672.                 if (drive != 0) {
  673.                     status (" Must copy from Drive A to B. ","",YES);
  674.                     break;
  675.                 }
  676.                 status(" Disk in B: will be reformatted... Continue (Y/N)?","",YES);
  677.                 while (!kbhit());
  678.                 if (toupper(c = getch()) != 'Y') break;
  679.                 set_disk_vector(alien_disk_vector);
  680.                 disk_reset();
  681.                 nsect = alien.base.eot + 1 - first_sector;  /* number of sectors */
  682.                 msize = alien.base.sides*nsect*sect_size; /* bytes on cylinder */
  683.                 if ((trackbuf = malloc(msize)) == NULL){
  684.                     status(" Insufficient Memory: ","",YES);
  685.                     goto label_1;
  686.                 }
  687.                 for (track = 0; track < alien.base.tracks; track++) {
  688.                     sptr = itoa(track,sbuf,10);
  689.                     status(" Copying Track: ",sptr,NO);
  690.                     bufptr = trackbuf;
  691.                     for ( head = 0; head < alien.base.sides; head++) {
  692.                         disk_data_v();
  693.                         dflag = disk_read(drive,track,first_sector,head,bufptr,nsect);
  694.                         if (dflag) {
  695.                             *((sptr = itoa(dflag,sbuf,2)) + 8) = '\0';
  696.                             status("Read error. BIOS code = ",sbuf,YES);
  697.                             goto label_1;
  698.                         }
  699.                         bufptr += msize/2;  /* next side if necessary */
  700.                     }
  701.                     bufptr = trackbuf;      /* re-initalise pointer */
  702.                     for ( head = 0; head < alien.base.sides; head++) {
  703.                         sptr = itoa(track,sbuf,10);
  704.                         status(" Formating Track: ",sptr,NO);
  705.                         if (first_sector == 0) alien.base.eot++;        /* format requires this */
  706.                         dflag = disk_format(drive+1,track,fmt_skew,head,
  707.                         alien.base.bytes_sect,first_sector,nsect);
  708.                         if (dflag) {
  709.                             *((sptr = itoa(dflag,sbuf,2)) + 8) = '\0';
  710.                             status("Format error. BIOS code = ",sptr,YES);
  711.                             goto label_1;
  712.                         }
  713.                         if (first_sector == 0) alien.base.eot--;
  714.                         disk_data_v();      /* keep track of position */
  715.                         sptr = itoa(track,sbuf,10);
  716.                         status(" Writing Track: ",sptr,NO);
  717.                         dflag = disk_write(drive+1,track,first_sector,head,bufptr,nsect);
  718.                         if (dflag) {
  719.                             *((sptr = itoa(dflag,sbuf,2)) + 8) = '\0';
  720.                             status ("Write error on B:.  BIOS code = ",sptr,YES);
  721.                             goto label_1;
  722.                         }
  723.                         bufptr += msize/2;      /* next side if necessary */
  724.                     }
  725.                 }
  726.  
  727.         label_1:
  728.  
  729.                 if (trackbuf != NULL) free(trackbuf);   /* give back the memory */
  730.                 disk_reset();
  731.                 disk_recal(drive);
  732.                 disk_data_v();
  733.                 set_disk_vector(pc_disk_vector);
  734.                 break;
  735.  
  736.         case LOG:
  737.  
  738.                 switch(getitem()){
  739.                     case BLANK:
  740.                             drive = getnum();
  741.                             if (drive >= last_drive) {
  742.                                 status(" Select error","",YES);
  743.                                 break;
  744.                             }
  745.  
  746.                     case END_LIN:
  747.                             clrscrn();
  748.                             zero_buffer(sect_buf,BUFFSIZ);
  749.                             header();
  750.                             disk_blocks = 0;
  751.                             alien.base.tracks = 0;
  752.                             alien.base.eot = 0;
  753.                             init_disk_globals();                    /* initialise all global variables */
  754.                             set_alien_parms();
  755.                             alien_disk_vector = &alien.base;
  756.                             set_disk_vector(alien_disk_vector);     /* set t    he alien disk base */
  757.                             log_disk();
  758.                 }
  759.                 break;
  760.  
  761.         case VBLOCKS:
  762.  
  763.                 t = getnum();
  764.                 if (evalerr || (t > MEMLIMIT/sect_size)) {  /* keep 64k limit */
  765.                     status("Invalid Block Number","",YES);
  766.                     break;
  767.                 }
  768.                 spb = t;
  769.                 disk_blocks = blocks_on_disk();
  770.                 break;
  771.  
  772.         case VOFFSET:
  773.  
  774.                 t = getnum();
  775.                 if (evalerr) {
  776.                     status("Invalid Offset Number","",YES);
  777.                     break;
  778.                 }
  779.                 offset = t;
  780.                 disk_blocks = blocks_on_disk();
  781.                 break;
  782.  
  783.         case VHEADS:
  784.  
  785.                 t = getnum();
  786.                 if (evalerr || t > 2) {
  787.                     status("Invalid number ","",YES);
  788.                     break;
  789.                 }
  790.                 alien.base.sides = t;
  791.                 disk_blocks = blocks_on_disk();
  792.                 break;
  793.  
  794.         case VDRIVES:
  795.  
  796.                 t = getnum();
  797.                 if (evalerr || t > MAX_DRIVES) {
  798.                     status ("Maximum number of drives exceeded ","",YES);
  799.                     break;
  800.                 }
  801.                 last_drive = t;
  802.                 break;
  803.  
  804.         case VTRACKS:
  805.  
  806.                 t = getnum();
  807.                 if (evalerr || t > 80) {
  808.                     status("Invalid number ","",YES);
  809.                     break;
  810.                 }
  811.                 alien.base.tracks = t;
  812.                 disk_blocks = blocks_on_disk();
  813.                 break;
  814.  
  815.         case VEOT:
  816.  
  817.                 t = getnum();
  818.                 if (evalerr || t > 40) {
  819.                     status("Invalid number ","",YES);
  820.                     break;
  821.                 }
  822.                 alien.base.eot = t;
  823.                 disk_blocks = blocks_on_disk();
  824.                 break;
  825.  
  826.         case VSIZE:
  827.  
  828.                 t = getnum();
  829.                 if (evalerr || t > BUFFSIZ)  {
  830.                     status("Invalid number ","",YES);
  831.                     break;
  832.                 }
  833.                 sect_size = t;
  834.                 t = t >> 7;                     /* shift for 128 base */
  835.                 i = 0;
  836.                 while ((t = t >> 1) != 0) i++;  /* i represents sector size */
  837.                 alien.base.bytes_sect =  i;
  838.                 break;
  839.  
  840.         case SSECTOR:
  841.  
  842.                 t = getnum();                   /* else go to specific head number */
  843.                 if (evalerr) {
  844.                     status("Invalid number ","",YES);
  845.                     break;
  846.                 }
  847.                 if (check_sector(t)) break;
  848.                 sector = t;
  849.                 break;
  850.  
  851.         case STRACK:
  852.  
  853.                 t = getnum();
  854.                 if (evalerr) {
  855.                     status("Invalid number ","",YES);
  856.                     break;
  857.                 }
  858.                 if (check_track(t)) break;
  859.                 track = t;
  860.                 break;
  861.  
  862.         case SBLOCK:
  863.  
  864.                 t = getnum();
  865.                 if (evalerr) {
  866.                     status("Invalid number ","",YES);
  867.                     break;
  868.                 }
  869.                 if (check_block(t)) break;
  870.                 block = t;
  871.                 block_to_tsh();
  872.                 break;
  873.  
  874.         case SHEAD:
  875.  
  876.                 t = getnum();
  877.                 if (evalerr) {
  878.                     status("Invalid number ","",YES);
  879.                     break;
  880.                 }
  881.                 if (!check_head(t)) head = t;
  882.                 break;
  883.  
  884.         case INCTRACK:
  885.  
  886.                 if (check_track(++track)) --track;
  887.                 break;
  888.  
  889.         case INCSECT:
  890.  
  891.                 if (check_sector(++sector)) --sector;
  892.                 break;
  893.  
  894.         case DECTRACK:
  895.  
  896.                 if (check_track(--track)) ++track;
  897.                 break;
  898.  
  899.         case DECSECT:
  900.  
  901.                 if (check_sector(--sector)) ++sector;
  902.                 break;
  903.  
  904.         case HELP:
  905.  
  906.                 help();
  907.                 break;
  908.  
  909.         case QUIT:
  910.  
  911.                 set_disk_vector(pc_disk_vector);
  912.                 disk_reset();
  913.                 clrscrn();                                      /* clear the screen */
  914.                 exit();         /* good bye */
  915.  
  916.         case END_LIN:
  917.  
  918.                 break;
  919.  
  920.         default:
  921.  
  922.                 status(" Invalid Command..","",YES);
  923.                 break;
  924.         }
  925.     }
  926. }
  927.  
  928. /*
  929.  Function to display user help menu.
  930. */
  931. void help() {
  932.  
  933.     clr_window(0,4,COLSIZ,ROWSIZ,7);            /* clear display area */
  934.     gotoxy(0,5);
  935.     puts("ADAPTABLE DISK UTILITY: The following commands are allowed:\n");
  936.     puts("Dump:                   Hex dump the buffer to the screen.");
  937.     puts("Edit:                   Edit the current sector.");
  938.     puts("Read  [T  S  H]:        Read in sectors worth of data.");
  939.     puts("Write [T  S  H]:        Write out sectors worth of data.");
  940.     puts("F1/F3/F4:               Help, Reissue/Repeat Command.");
  941.     puts("+/-Sector:              Increment/decrement sector");
  942.     puts("+/-Track:               Increment/decrement track");
  943.     puts("Sb/St/Ss/Sh N:          Set Block,Track, Sector or Head.");
  944.     puts("Vb/Vt/Vz/Ve/Vh/Vo/Vd N: Vary configuration parameters");
  945.     puts("FS/SX [n1,n2..]:        Vary both sector xlat and fmt skew");
  946.     puts("DB [p1,p2...]           Change PC Disk Base parameters");
  947.     puts("Log [Drive]:            Log disk in drive (0,1).");
  948.     puts("Copy N:fn Blocks:       Copy Blocks to DOS Disk in Drive N:");
  949.     puts("DC                      Disk copy - Make a copy of the Alien Disk onto A:");
  950.     puts("Quit:                   Quit - restoring MS DOS environment.");
  951.     puts("?:                      Re-display main menu.");
  952.     puts(" (Note: hex numbers are entered as 0x31 etc)");
  953.  
  954. }
  955. /*
  956. **  Log the current drive.
  957. */
  958.  
  959. void log_disk() {
  960.  
  961.     status (" Analysing disk . . .","",NO);
  962.     disk_reset();
  963.     disk_recal(drive);
  964.     identify(drive);
  965.     set_alien_parms();              /* Up date alien disk table */
  966.     disk_reset();
  967.     track = 0; sector = first_sector; head = 0;
  968.     disk_recal(drive);
  969.     disk_data_c();
  970.     disk_data_v();
  971.     clr_window(0,3,COLSIZ,3,7);     /* clear status line */
  972. }
  973.  
  974. /*
  975. **  Check for valid sector range.
  976. */
  977. int check_sector(s) int s; {
  978.     if (s > alien.base.eot || s < first_sector){
  979.        status("Invalid sector..","",YES);
  980.        return TRUE;
  981.     }
  982.     return FALSE;
  983. }
  984. /*
  985. **  Check for a valid track.
  986. */
  987.  
  988. int check_track(trk) int trk; {
  989.  
  990.     if (trk >= alien.base.tracks || trk < 0){
  991.        status("Invalid track","",YES);
  992.        return TRUE;
  993.     }
  994.     return FALSE;
  995. }
  996.  
  997. /*
  998. ** Check the requested block number against the system
  999. ** number.
  1000. */
  1001. int check_block(blk) int blk; {
  1002.  
  1003.     if (blk >= disk_blocks){
  1004.        status("Invalid block","",YES);
  1005.        return TRUE;
  1006.     }
  1007.     return FALSE;
  1008. }
  1009. /*
  1010. ** Check the requested head against the system
  1011. ** number.
  1012. */
  1013. int check_head(head_no) int head_no; {
  1014.  
  1015.     if (head_no + 1 > alien.base.sides){
  1016.        status ("Invalid head","",YES);
  1017.        return TRUE;
  1018.     }
  1019.     return FALSE;
  1020. }
  1021.  
  1022. /*
  1023. ** Calculate number of blocks on disk
  1024. */
  1025. int blocks_on_disk() {
  1026. unsigned int bm;
  1027.  
  1028.     if (alien.base.tracks < offset)
  1029.     return (0);
  1030.     bm = (alien.base.tracks-offset)*alien.base.eot/spb; /* maximum blocks per disk */
  1031.     return ( bm*alien.base.sides );                     /* Blocks per disk */
  1032. }
  1033.  
  1034. /*
  1035. ** Place the basic header data on the system screen area.
  1036. */
  1037. void header() {
  1038.  
  1039.     clr_window(0,0,COLSIZ,2,0x10);          /* blue background */
  1040.     putfa(0,0,"Tracks:     ",NULL,0x1e);    /* blue background green forground */
  1041.     putfa(12,0,"Last Sector on Track:    ",NULL,0x1e);
  1042.     putfa(38,0,"Sector size:    ",NULL,0x1e);
  1043.     putfa(58,0,"Sides:  ",NULL,0x1e);
  1044.     putfa(0,1,"Block size:    ",NULL,0x1e);
  1045.     putfa(16,1,"Block start:   ",NULL,0x1e);
  1046.     putfa(35,1,"Blocks on disk:  ",NULL,0x1e);
  1047.     putfa(58,1,"Number of Drives: ",NULL,0x1e);
  1048.     putfa(0,2,"Current Drive:  ",NULL,0x1e);
  1049.     putfa(18,2,"Current Disk Position: ",NULL,0x1e);
  1050.     putfa(41,2,"Track   ",NULL,0x1e);
  1051.     putfa(51,2,"Sector   ",NULL,0x1e);
  1052.     putfa(63,2,"Head   ",NULL,0x1e);
  1053.  
  1054.  
  1055. }
  1056.  
  1057. /*
  1058. ** data_c refers to data which is generally constant.
  1059. */
  1060.  
  1061. void disk_data_c() {
  1062.  
  1063.     putfa(8,0, "%3d",alien.base.tracks,YELLOW_RED);
  1064.     putfa(33,0,"%3d",alien.base.eot,YELLOW_RED);
  1065.     putfa(51,0,"%4d",sect_size,YELLOW_RED);         /* sector size */
  1066.     putfa(65,0,"%1d",alien.base.sides,YELLOW_RED);  /* number of sides */
  1067.     putfa(12,1,"%3d",spb,YELLOW_RED);               /* sectors per block */
  1068.     putfa(31,1,"%3d",offset,YELLOW_RED);            /* start block offset */
  1069.     putfa(52,1,"%4d",disk_blocks,YELLOW_RED);
  1070.     putfa(76,1,"%1d",last_drive,YELLOW_RED);        /* last allowed drive */
  1071. }
  1072.  
  1073. /*
  1074. ** data_v refers to variable data to reduce screen update time
  1075. */
  1076.  
  1077. void disk_data_v() {
  1078.  
  1079.     putfa(16,2,"%1d",drive,YELLOW_RED);     /* Current drive  */
  1080.     putfa(58,2,"%4d",sector,YELLOW_RED);    /* Current sector */
  1081.     putfa(46,2,"%4d",track,YELLOW_RED);     /* Current track  */
  1082.     putfa(69,2,"%1d",head,YELLOW_RED);      /* Current head   */
  1083. }
  1084.  
  1085. /*
  1086. ** Get next item off the command line.
  1087. */
  1088. int getitem() {
  1089. char token[32];
  1090.  
  1091.     if(*linptr == BLANK){
  1092.         while(*linptr == BLANK) linptr++;
  1093.         return BLANK;
  1094.     }
  1095.     if (*linptr == ';') {       /* allow more than one command per line */
  1096.         eol = FALSE;
  1097.         linptr++;
  1098.         while (*linptr == BLANK) linptr++;  /* skip the blanks */
  1099.         return END_LIN;
  1100.     }
  1101.     if ((*linptr == '\n') || (*linptr == '\0')){
  1102.         eol = TRUE;
  1103.         return END_LIN;
  1104.     }
  1105.     getname(token);
  1106.     if(amatch("VH",token,2)) return VHEADS;
  1107.     if(amatch("VB",token,2)) return VBLOCKS;
  1108.     if(amatch("VO",token,2)) return VOFFSET;
  1109.     if(amatch("VZ",token,2)) return VSIZE;
  1110.     if(amatch("VE",token,2)) return VEOT;
  1111.     if(amatch("VT",token,2)) return VTRACKS;
  1112.     if(amatch("VD",token,2)) return VDRIVES;
  1113.     if(amatch("ST",token,2)) return STRACK;
  1114.     if(amatch("SS",token,2)) return SSECTOR;
  1115.     if(amatch("SB",token,2)) return SBLOCK;
  1116.     if(amatch("SH",token,2)) return SHEAD;
  1117.     if(amatch("DC",token,2)) return DISKCOPY;
  1118.     if(amatch("DB",token,2)) return DISKBASE;
  1119.     if(amatch("DUMP",token,1)) return DUMP;
  1120.     if(amatch("EDIT",token,1)) return EDIT;
  1121.     if(amatch("READ",token,1)) return READ;
  1122.     if(amatch("WRITE",token,1)) return WRITE;
  1123.     if(amatch("COPY",token,1)) return COPY;
  1124.     if(amatch("LOG",token,1))  return LOG;
  1125.     if(amatch("+TRACK",token,2)) return INCTRACK;
  1126.     if(amatch("+SECTOR",token,2)) return INCSECT;
  1127.     if(amatch("-TRACK",token,2)) return DECTRACK;
  1128.     if(amatch("-SECTOR",token,2)) return DECSECT;
  1129.     if(amatch("SX",token,2)) return SECTXLAT;
  1130.     if(amatch("FS",token,2)) return FMTSKEW;
  1131.     if(amatch("QUIT",token,1)) return QUIT;
  1132.     if(amatch("?",token,1)) return HELP;
  1133.     return -1;
  1134. }
  1135.  
  1136. /*
  1137. ** Get a name symbol etc form the command line
  1138. */
  1139. void getname(buffer) char *buffer; {
  1140. char c,count;
  1141.  
  1142.     while( *linptr == BLANK) linptr++;
  1143.     c = *linptr++;
  1144.     count = 1;
  1145.     while ( isalpha(c) || isdigit(c) || (c == '?') || (c == ':')
  1146.         || (c == '-') || (c == '.') || (c == '+') || (c == '\\')) {
  1147.  
  1148.         if(count < 32) *buffer++ = c;
  1149.         count++;
  1150.         c = *linptr++;
  1151.     }
  1152.     --linptr;
  1153.     *buffer = '\0';     /* null terminate */
  1154. }
  1155.  
  1156. /*
  1157. ** Get a numeric value off the line.  Sequences may be as follows:
  1158. **   num1 num2 ....
  1159. **   num1,num2.....
  1160. **   num1/numN.....   this represents are short hand sequence to
  1161. **                      specify the range num1 to numN.
  1162. */
  1163. int getnum() {
  1164. int val;
  1165. char c;
  1166.  
  1167.     evalerr = FALSE;
  1168.     if (numflag == TRUE) {          /* if true look for short hand sequence */
  1169.        if (snum <= lnum) {
  1170.         val = snum++;
  1171.         return val;
  1172.        }
  1173.        numflag = FALSE;         /* indicate we're back to normal */
  1174.     }
  1175.     val = 0;
  1176.     while (( c = *linptr) == '\t' || c == ' ' || c == ',')
  1177.          ++linptr;
  1178.     if (!isdigit(c = *linptr)) {
  1179.         evalerr = TRUE;
  1180.         return (NULL);
  1181.     }
  1182.     while (isdigit(c = *linptr++)) val = val * 10 + c - '0';
  1183.     if ( toupper(*(linptr-1)) == 'X' && val == 0) {     /* i.e.  true if 0x found */
  1184.         while ((isxdigit(c = toupper(*linptr++)))) {
  1185.             if (isalpha(c)) c += -'@'+ 9;
  1186.             else            c -= '0';
  1187.             val = val * 16 + c;
  1188.         }
  1189.     }
  1190.     --linptr;
  1191. /*
  1192. ** Check to see if there is a short hand sequence
  1193. */
  1194.     if (*linptr == '/') {
  1195.         snum = val+1;           /* saddr must start after val */
  1196.         lnum = 0;
  1197.         linptr++;
  1198.         while ( isdigit(c = *linptr++)) lnum = lnum * 10 + c - '0';
  1199.         if ( toupper(*(linptr-1)) == 'X' && lnum == 0) {        /* i.e.  true if 0x found */
  1200.             while ((isxdigit(c = toupper(*linptr++)))) {
  1201.                 if ( isalpha(c)) c += -'@' + 9;
  1202.                 else             c -= '0';
  1203.                 lnum = lnum * 16 + c;
  1204.             }
  1205.         }
  1206.         --linptr;
  1207.         if (snum > lnum ) evalerr = TRUE;
  1208.         numflag = TRUE;                 /* flag this for next time getnum() is called */
  1209.     }
  1210.     return val;
  1211. }
  1212.  
  1213. /*
  1214. ** match a null terminated string
  1215. **  s     -> source string;
  1216. **  t     -> string to match;
  1217. **  count -> characters to match
  1218. */
  1219. int amatch(s,t,count) char s[],t[]; int  count; {
  1220. int i;
  1221.  
  1222.     i=0;
  1223.     while ( t[i] ) {
  1224.         if( s[i] != toupper(t[i])) return 0;
  1225.         i++;
  1226.     }
  1227.     return (count == i) ? count : 0;        /* return number of matches */
  1228. }
  1229.  
  1230. /*
  1231.  This function displays, on the status line, user prompts
  1232.  or errors.  If the beep parameter is YES then status will
  1233.  output an audible prompt.
  1234. */
  1235. void status(s,s2,beep) char *s,*s2; int beep; {
  1236. int attr;
  1237.  
  1238.     attr = 0x4e;                    /* red background yellow foreground */
  1239.     clr_window(0,3,COLSIZ,3,attr);
  1240.     gotoxy(4,3);
  1241.     put_string(s,attr);
  1242.     put_string(s2,attr);
  1243.     if (beep) {
  1244.         do_beep();
  1245.         eol = TRUE;                 /* stop all processing */
  1246.     }
  1247. }
  1248. /*
  1249. ** Dump a line of buffer at the current cursor position.
  1250. */
  1251.  
  1252. void dump_line(saddr,buff) int saddr; char *buff; {
  1253. int  i;
  1254. char c;
  1255. char *bptr;
  1256.  
  1257.     bptr = out_buf;
  1258.     bptr += sprintf(bptr,"%04x: ",saddr);           /* address offset */
  1259.     for(i = saddr; i <= saddr + 15; i++)
  1260.         bptr += sprintf(bptr,"%02x ",0xff & buff[i]);   /* hex data */
  1261.     bptr += sprintf(bptr,"  |");
  1262.     for(i = saddr; i <= saddr + 15; i++){
  1263.         c = buff[i];
  1264.         if ((c > ' ') && (c < 0x7f))              /* show in ascii format */
  1265.             *bptr++ = c;
  1266.         else
  1267.             *bptr++ = '.';
  1268.     }
  1269.     *bptr++ =  '|';
  1270.     *bptr = '\0';
  1271.     put_string(out_buf,0x07);
  1272.  
  1273. }
  1274.  
  1275. /*
  1276. **  Flush to zero the buffer contents.
  1277. */
  1278.  
  1279. void zero_buffer(buff,size) char *buff; int size; {
  1280. int  i;
  1281.  
  1282.     for(i = 0; i < size; i++)
  1283.         buff[i] = '\0';
  1284. }
  1285.  
  1286. /*
  1287. ** See IBM XT Technical reference manual page 5-98.
  1288. */
  1289.  
  1290. void do_beep() {
  1291. int  i,timer,port_b,mode,count_l,count_h,mask;
  1292.  
  1293.     timer = 0x40;
  1294.     mode = 0xb6;
  1295.     port_b = 0x61;
  1296.     outp(timer+3,mode);
  1297.     count_l =  0x33;            /* lsb of count */
  1298.     count_h = 0x05;             /* msb of count */
  1299.     outp(timer+2,count_l);
  1300.     outp(timer+2,count_h);
  1301.     mask = inp(port_b);         /* save current settings */
  1302.     outp(port_b,mask | 0x03);       /* turn speaker on  */
  1303.     for (i = 0; i < 15000; i++);        /* delay loop       */
  1304.     outp(port_b,mask);          /* restore original settings */
  1305. }
  1306.  
  1307. void prompt() {
  1308.  
  1309.     TITLE;
  1310.     AUTHOR;
  1311.     putfa(25,15," RETURN WHEN READY ",NULL,0xf0);
  1312.     CURSOR_OFF;
  1313.     do_beep();
  1314.     while (!kbhit());
  1315.     getch();                    /* flush character */
  1316. }
  1317. /*
  1318.  Translate the current block number 'block' to
  1319.  track, sector and head values.
  1320. */
  1321. void block_to_tsh() {
  1322.  
  1323.     track = block*spb/alien.base.eot;
  1324.     if (alien.base.sides == 2)
  1325.         head = track%2;
  1326.     track /= alien.base.sides;
  1327.     track += offset;
  1328.     sector = (block*spb%alien.base.eot) + 1;
  1329. }
  1330.  
  1331. /*
  1332.   Get next sector.  Also bump track if necessary.
  1333. */
  1334.  
  1335. void next_sector()  {
  1336.  
  1337.     sector++;
  1338.     if (sector > alien.base.eot) {
  1339.         if (alien.base.sides == 2){
  1340.             if (head == 1) track++;
  1341.             head ^= 1;
  1342.         }
  1343.         else track++;
  1344.         sector = 1;
  1345.    }
  1346. }
  1347.  
  1348. /*
  1349.  Initialise all the global disk parameters
  1350. */
  1351.  
  1352. void init_disk_globals() {
  1353. int i;
  1354.  
  1355.     disk_blocks = 0;
  1356.     sect_size = 0;
  1357.     spb = 8; offset = 2;
  1358.     for (i = 0; i < 40; i++){
  1359.         sect_xlat[i] = i;       /* initialise with non interlaced sectors */
  1360.         fmt_skew[i] = i;        /* initialise to zero format skew  */
  1361.     }
  1362. }
  1363.  
  1364. /*
  1365.  Get the current disk vector by asking DOS
  1366.  to fetch the interrupt vector from 0x1E.  The
  1367.  pointer is returned, as is saved by the calling
  1368.  module.
  1369. */
  1370.  
  1371. disk_base far *get_disk_vector() {
  1372. struct SREGS segregs;
  1373. disk_base far *longptr;
  1374. unsigned long ls,lo;
  1375.  
  1376.     inregs.h.ah = 0x35;                     /* DOS function number */
  1377.     inregs.h.al = 0x1E;                     /* Disk vector number */
  1378.     intdosx (&inregs,&outregs,&segregs);
  1379.     ls = (unsigned long)(segregs.es << 16);
  1380.     lo = (unsigned long)outregs.x.bx;
  1381.     longptr = (disk_base far *)(ls | lo);   /* convert to the correst pointer type */
  1382.     return (longptr);
  1383. }
  1384. /*
  1385.  
  1386.  Replace current disk vector with the value
  1387.  pointed to by vectptr.  This routine is normally
  1388.  used to swap between the Alien and PC disk vectors.
  1389.  
  1390. */
  1391.  
  1392. int set_disk_vector(vectptr) disk_base far *vectptr; {
  1393. struct SREGS segregs;
  1394.  
  1395.     inregs.h.ah = 0x25;
  1396.     inregs.h.al = 0x1E;
  1397.     inregs.x.dx = FP_OFF(vectptr);
  1398.     segregs.ds  = FP_SEG(vectptr);
  1399.     intdosx (&inregs,&outregs,&segregs);
  1400.     return outregs.x.ax;
  1401. }
  1402.  
  1403. /*
  1404. ** Routine to step through all combinations of
  1405. ** head, sector and track building up the disk
  1406. ** parameters as it goes.
  1407. */
  1408.  
  1409. void identify(drive) int drive; {
  1410. int ssize;
  1411.  
  1412. /* first find bytes per sector */
  1413.  
  1414.     outregs.x.cflag = 1;
  1415.     head = 0; track = 0; sector = 0; ssize = 0;
  1416.  
  1417.     while (outregs.x.cflag && sector < 40) {        /* some formats start at high sector numbers */
  1418.         while (outregs.x.cflag && ssize < 8) {
  1419.             alien.base.bytes_sect = ssize++;
  1420.             sect_size = (128 << alien.base.bytes_sect); /* a global variable */
  1421.             disk_test(drive,head,track,sector); /* returns status in outregs.x.cflag */
  1422.         }
  1423.         sector++;
  1424.         ssize = 0;
  1425.     }
  1426.     if (outregs.x.cflag) {
  1427.         status("Can't figure this disk format out. Vary parameters ","",YES);
  1428.         return;
  1429.     }
  1430.     sect_size = (128 << alien.base.bytes_sect); /* a global variable */
  1431.     first_sector = --sector;            /* this is the first sector on disk */
  1432.  
  1433.  
  1434. /* up to here we know sector size  */
  1435. /* now try to find out how many sectors */
  1436.  
  1437.     head = 0; sector = first_sector;        /* begin at sector we found previously  */
  1438.     outregs.x.cflag = 0;
  1439.     alien.base.eot = 1;             /* assume at least 2 sector per track */
  1440.     while (!outregs.x.cflag && sector < 40) {
  1441.         disk_test(drive,head ,track,++sector); /* returns status in outregs.x.cflag */
  1442.         alien.base.eot = sector - 1;
  1443.         disk_data_c();                      /* keep track of the parameters */
  1444.     }
  1445.     alien.base.eot = --sector;
  1446.     disk_data_c();
  1447.     disk_data_v();
  1448.  
  1449. /* search for second side */
  1450.  
  1451.     alien.base.sides = 1;               /* assume single side */
  1452.     head = 1; ssize = alien.base.bytes_sect;
  1453.     sector = first_sector;
  1454.     disk_test(drive,head,track,sector);  /* returns status in outregs.x.cflag */
  1455.     if (!outregs.x.cflag ) {
  1456.         sector = alien.base.eot;
  1457.         disk_test(drive,head,track,sector);  /* returns status in outregs.x.cflag */
  1458.         if (!outregs.x.cflag)
  1459.             alien.base.sides = 2;
  1460.     }
  1461.     sector = alien.base.eot + 1;                /* sectors may continue on other side */
  1462.     disk_test(drive,head,track,sector);  /* returns status in outregs.x.cflag */
  1463.     if (!outregs.x.cflag ) {
  1464.         sector = 2*alien.base.eot + 1 + first_sector;
  1465.         disk_test(drive,head,track,sector);  /* returns status in outregs.x.cflag */
  1466.         if (!outregs.x.cflag)
  1467.             alien.base.sides = 2;
  1468.     }
  1469.     sector = first_sector;
  1470.     disk_data_c();                      /* do a partial summary here */
  1471.  
  1472.  
  1473. /* Now determine how many tracks are on the disk */
  1474.  
  1475.     outregs.x.cflag = 0; track = 0;
  1476.     while (!outregs.x.cflag && track < 80) {
  1477.         for ( head = 0; head < alien.base.sides; head++)        /* check both sides */
  1478.             disk_test(drive,head ,track,sector); /* returns status in outregs.x.cflag */
  1479.         track++;
  1480.         alien.base.tracks = track-1;
  1481.         disk_blocks = blocks_on_disk();     /* keep track of blocks */
  1482.         disk_data_c();                      /* display data on screen */
  1483.     }
  1484.     disk_reset();
  1485. }
  1486.  
  1487. /*
  1488.  Initialise all default variable settings.  Used
  1489.  during initial programme activation and during logs.
  1490. */
  1491. void set_alien_parms() {
  1492. int standard,gap;
  1493.  
  1494. /* standard dos disk */
  1495.  
  1496.     dos.base.srt =         0xcf;
  1497.     dos.base.hld =         2;
  1498.     dos.base.motor_wait =  25;
  1499.     dos.base.bytes_sect =  2;
  1500.     dos.base.eot =         8;
  1501.     dos.base.rw_gap =      0x2a;
  1502.     dos.base.dtl =         0xff;
  1503.     dos.base.format_gap =  0x50;
  1504.     dos.base.format_fill = 0xf6;
  1505.     dos.base.hs =          25;
  1506.     dos.base.motor_start = 4;
  1507.     dos.base.sides =       2;
  1508.     dos.base.tracks =      40;
  1509.  
  1510. /*
  1511.  Basic ALIEN disk data.  Most parametes are
  1512.  modified on the fly during the disk
  1513.  identification process.
  1514. */
  1515.  
  1516.     alien.base.srt =         0xcf;
  1517.     alien.base.hld =         2;
  1518.     alien.base.motor_wait =  0x25;
  1519.     alien.base.dtl =         0xff;
  1520.     alien.base.rw_gap =      0x05;
  1521.     alien.base.format_gap =  0x08;
  1522.     alien.base.format_fill = 0xf6;
  1523.     alien.base.hs =          25;
  1524.     alien.base.motor_start = 4;
  1525.  
  1526. /*
  1527.    Fill in the format stuff here ( See 8272 data sheet
  1528.    for the standard/recommended values).
  1529.    The 'read/write' gaps, defined by alien.base.gap
  1530.    may have to be ajusted to suit some special formats.
  1531.    These gaps are related to the VCO 'idle' period.  Hence
  1532.    if too large the VCO will idle straight across the ID/data
  1533.    fields.  As a consequence BIOS will time out while looking
  1534.    for particular sectors.
  1535. */
  1536.  
  1537.     switch (sect_size) {
  1538.  
  1539.  
  1540.  
  1541.         case 256:   if ( alien.base.eot <= 0x10) {
  1542.                         alien.base.rw_gap = 0x20;
  1543.                         alien.base.format_gap = 0x32;
  1544.                     }
  1545.                     else {
  1546.                         alien.base.rw_gap = 0x0a;
  1547.                         alien.base.format_gap = 0x10;
  1548.                     }
  1549.                     break;
  1550.  
  1551.         case 512:
  1552.                     if (alien.base.eot <= 9) {              /* standard format */
  1553.                         alien.base.rw_gap =  0x2a;
  1554.                         alien.base.format_gap = 0x50;
  1555.                     }
  1556.                     else {
  1557.                         alien.base.rw_gap = 0x09;
  1558.                         alien.base.format_gap = 0x1e;
  1559.                     }
  1560.                     break;
  1561.         case 1024:
  1562.                     if (alien.base.eot <= 4){               /* standard values */
  1563.                         alien.base.rw_gap = 0x80;
  1564.                         alien.base.format_gap = 0xf0;
  1565.                     }
  1566.                     else {
  1567.                         alien.base.rw_gap = 0x30;           /* non standard values */
  1568.                         alien.base.format_gap = 0x40;
  1569.                     }
  1570.                     break;
  1571.  
  1572.         case 2048:
  1573.         case 4096:
  1574.                     if (alien.base.eot <= 2){               /* standard values */
  1575.                         alien.base.rw_gap = 0xc8;
  1576.                         alien.base.format_gap = 0xff;
  1577.                     }
  1578.                     else {
  1579.                         alien.base.rw_gap = 0xd0;           /* non standard values */
  1580.                         alien.base.format_gap = 0xff;
  1581.                     }
  1582.                     break;
  1583.  
  1584.         default:
  1585.                 alien.base.rw_gap = 0x05;
  1586.                 alien.base.format_gap = 0x08;
  1587.                 break;
  1588.  
  1589.     }
  1590. }
  1591.