home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / ENTERPRS / CPM / UTILS / A / ANYDISK.ZIP / ANYDISK.C next >
Text File  |  1990-11-24  |  16KB  |  785 lines

  1. /*
  2.     Disk Utility Program for CP/M version 2.x
  3.  
  4.     Original May, 1980    by Richard Damon
  5.     Modified Sept 9, 1981    by Robert Ward
  6.     Modified July, 1982    by Edward K. Ream
  7.  
  8.     Please send all reports of bugs to:
  9.  
  10.         Edward K. Ream
  11.         1850 Summit Ave.
  12.         Madison, WI 53705
  13.         (608) 231 - 2952
  14.  
  15.     See the file anydisk.doc for documentation.
  16.  
  17. */
  18.  
  19. #define VERSION "\nJuly 27, 1982\n\n"
  20.  
  21.  
  22. /*
  23.     Define the data structures pointed to by
  24.     the BIOS select disk function.
  25. */
  26.  
  27.  
  28. /* DPH -- Disk Parameter Header.  One for each disk */
  29.  
  30. struct DPH {
  31.  
  32.     /* XLT: address of translation table.    */
  33.     /* one table for each TYPE of disk    */
  34.     char *    d_XLT;
  35.  
  36.     /* scratchpad area for BDOS use only    */
  37.     int    d_TEMP1;
  38.     int    d_TEMP2;
  39.     int    d_TEMP3;
  40.  
  41.     /* DIRBUF: address of 128-byte directory buffer    */
  42.     /* all disks use the same buffer        */
  43.     char *    d_DIRBUF;
  44.  
  45.     /* DPB: address of DPB. One for each type of drive */
  46.     char *    d_DPB;
  47.  
  48.     /* CSV:    address of changed-disk check buffer    */
  49.     /* one for each drive                */
  50.     /* size of buffer is DPB -> CSK bytes        */
  51.     char *    d_CSV;
  52.  
  53.     /* ALV: address of allocation buffer        */
  54.     /* one for each drive                */
  55.     /* size of buffer is (DPB -> DSM / 8) + 1 bytes    */
  56.     char *    d_ALV;
  57.  
  58. };
  59.  
  60.  
  61. /*
  62.     DPB -- Disk Parameter Block
  63.     One for each TYPE of disk
  64. */
  65.  
  66. struct DPB {
  67.  
  68.     /* sector per track */
  69.     int    d_SPT;
  70.  
  71.     /* BSH: block shift factor        */
  72.     /* BLM = (2 ** BSH) - 1            */
  73.  
  74.     /* BLS: block size. Note size VARIES    */
  75.     /* BLS = (BLM + 1) * 128        */
  76.     char    d_BSH;
  77.     char    d_BLM;
  78.  
  79.     /* EXM: extent mask */
  80.     /* if DSM > = 256 then block numbers take two bytes */
  81.     /* Thus, each extent can hold only 8 block numbers */
  82.     char    d_EXM;
  83.  
  84.     /* DSM maximum disk BLOCK number        */
  85.     /* BLOCKS numbered starting at zero        */
  86.     /* (DSM + 1) * BLS = # of bytes per drive    */
  87.     int    d_DSM;
  88.  
  89.     /* DRM:    directory max. directory entries 0 -- DRM */
  90.     int    d_DRM;
  91.  
  92.     /* AL0, AL1:  allocation vector for directory    */
  93.     /* each bit reserves one BLOCK            */
  94.     char    d_AL0;    /* high bit = block 0 */
  95.     char    d_AL1;    /* high bit = block 8 */
  96.  
  97.     /* CKS: size of directory check vector (or 0)    */
  98.     /* fixed media:        CKS = 0            */
  99.     /* removeable media:    CKS = (DRM + 1)/4    */
  100.     int    d_CKS;
  101.  
  102.     /* OFF: track offset.  number of skipped tracks */
  103.     int    d_OFF;
  104. };
  105.  
  106.  
  107. /* Define BIOS entry points. */
  108.  
  109. #define SELDSK    9
  110. #define SETTRK    10
  111. #define SETSEC    11
  112. #define SETDMA    12
  113. #define RDSEC    13
  114. #define WTSEC    14
  115. #define    SECTRAN    16    /* BE = logical sec # */
  116.             /* DE = address of translation table */
  117.  
  118.  
  119. /* Set this constant to the number of drives you have. */
  120.  
  121. #define NDRVS 5
  122.  
  123. /*
  124.     Set BBUFSIZ to the size of the largest block
  125.     that any of your disks use.
  126.  
  127.     Set MBUFSIZ to the largest number of directory
  128.     entries that are placed on any of your disks.
  129.  
  130.     There is code (in the select routine) which
  131.     makes sure that these constants are, in fact,
  132.     large enough.  If not,  a message is issued and
  133.     the program aborts, so you shouldn't be able to
  134.     bomb the program (or your disks).
  135. */
  136.  
  137. #define BBUFSIZ 4096
  138. #define MBUFSIZ 4096
  139.  
  140. /* Do not change ANY of the following constants. */
  141.  
  142. #define PHYS 0
  143. #define LOG 1
  144. #define YES 1
  145. #define NO  0
  146. #define SECSIZE    128
  147. #define table TXTABLE
  148.  
  149.  
  150. /* Define global constants set by the select() routine. */
  151.  
  152. struct DPH * d_header;    /* pointer to DPH        */
  153. struct DPB * d_disk;    /* pointer to DPB        */
  154.  
  155. int    TPD;        /* tracks  per disk        */
  156. int    SPT;        /* sectors per track        */
  157. int    BPD;        /* blocks  per disk        */
  158. int    SPB;        /* sectors per block        */
  159. char *    TXTABLE;    /* pointer to translate table    */
  160. int    DIRBLKS;    /* blocks in the directory    */
  161. int    DIRSIZE;    /* entries in the directory    */
  162. int    OFFSET;        /* offset of first track    */
  163.  
  164.  
  165. main()
  166. {
  167.     char buffer [BBUFSIZ];
  168.     char buff[80], *bufp, c;
  169.     char *temp;
  170.     int mode, nsects, disk, b, i, j;
  171.     int block, track, sector;
  172.  
  173.     /* Sign on. */
  174.     printf("Welcome to ddndisk version 3:  ");
  175.     printf(VERSION);
  176.  
  177.     /* Initialize */
  178.     track    = 0;
  179.     sector    = 0;
  180.     block    = 0;
  181.     mode    = PHYS;
  182.     nsects    = 1;
  183.  
  184.     /* The default drive is drive A: */
  185.     disk  = 0;
  186.     select(disk);
  187.  
  188.     for (;;) {
  189.         bufp = gets(buff);
  190.  
  191.         /* The 'X' request must be the only thing on a line. */
  192.         if (tolower(*bufp) == 'x' && *(bufp + 1) == '\0') {
  193.             break;
  194.         }
  195.  
  196.         while (c = *bufp++) switch (toupper(c)) {
  197.  
  198.     case 'B':
  199.         mode   = LOG;
  200.         nsects = SPB;
  201.  
  202.         /* Get block number from the user. */
  203.         block = getnum(&bufp, 0, BPD-1 ,16);
  204.  
  205.         /*
  206.             Convert block number to track/sector.
  207.             A loop is used to avoid overflow.
  208.         */
  209.         track = sector = 0;
  210.         for(b = block; b; b--) {
  211.             sector += SPB;
  212.             if (sector >= SPT) {
  213.                 track++;
  214.                 sector -= SPT;
  215.             }
  216.         }
  217.         break;
  218.  
  219.     case 'C':
  220.         /* Fill the buffer with a signed constant. */
  221.         temp = getnum(&bufp, -32765, 32765, 16);
  222.         for(i = 0; i < nsects * SECSIZE; i++) {
  223.             buffer[i] = temp[i];
  224.         }
  225.         break;
  226.  
  227.     case 'D':
  228.         /* Select the disk and print disk info. */
  229.         disk = getnum(&bufp, 0, NDRVS-1, 10);
  230.         select(disk);
  231.         info();
  232.         break;
  233.  
  234.     case 'E':
  235.         /* Patch the buffer with a list of chars. */
  236.         i = getnum(&bufp, 0, nsects*SECSIZE-1, 16);
  237.         while(*bufp ==' ') {    
  238.             buffer [i++] = getnum(&bufp,0,255,16);
  239.             if(i >= nsects*SECSIZE) {
  240.                 break;
  241.             }
  242.         }
  243.         break;
  244.  
  245.     case 'F':
  246.         /* Fill the buffer with an unsigned constant */
  247.         i = getnum(&bufp, 0, 255, 16);
  248.         for(j = 0; j < nsects*SECSIZE; j++) {
  249.             buffer [j] = i;
  250.         }
  251.         break;
  252.  
  253.     case 'H':
  254.         /* Print a help message. */
  255.         help();
  256.         break;
  257.  
  258.     case 'I':
  259.         /* Enter track/sector mode. */
  260.         if (mode != PHYS) {
  261.             mode = PHYS;
  262.             nsects = 1;
  263.  
  264.             /* Convert block to track/sector. */
  265.             track = sector = 0;
  266.             for (b = block; b; b--) {
  267.                 sector += SPB;
  268.                 if (sector >= SPT) {
  269.                     track++;
  270.                     sector -= SPT;
  271.                 }
  272.             }
  273.             track += OFFSET;
  274.         }
  275.         break;
  276.  
  277.     case 'M':
  278.         /* Print the directory and allocation map. */
  279.         ptmap(disk, table);
  280.         break;
  281.  
  282.     case 'N':
  283.         /* Go to next sector or block. */
  284.         if (mode == LOG) {
  285.             block++;
  286.             sector += SPB;
  287.         }
  288.         else {
  289.             sector++;
  290.         }
  291.  
  292.         if (sector >= SPT) {
  293.             track++;
  294.             sector -= SPT;
  295.             if (track >= TPD) {
  296.                 /* Stop the scan. */
  297.                 *bufp = '\0';
  298.                 printf("No next sector.\n");
  299.             }
  300.         }
  301.         break;
  302.  
  303.     case 'P':
  304.         /* Print the buffer. */
  305.         dmpbuff    (buffer, nsects, mode, disk,
  306.         block, track, sector, table);
  307.         break;
  308.  
  309.     case 'R':
  310.         /* Read a block or sector into the buffer. */
  311.         rdbuff    (buffer, nsects, mode, disk,
  312.         block, track, sector, table);
  313.         break;
  314.  
  315.     case 'S':
  316.         /*
  317.             Set LOGICAL sector #.
  318.             Enter track/sector mode.
  319.         */
  320.         if (mode == LOG) {
  321.             mode = PHYS;
  322.             track = OFFSET;
  323.         }
  324.         nsects = 1;
  325.         sector = getnum(&bufp, 0, SPT - 1, 10);
  326.         break;
  327.  
  328.     case 'T':
  329.         if (mode == LOG) {
  330.             mode = PHYS;
  331.             sector = 0;
  332.         }
  333.         nsects = 1;
  334.         track = getnum(&bufp, 0, TPD - 1, 10);
  335.         break;
  336.  
  337.     case 'W':
  338.         /* Write the buffer to the disk. */
  339.         wrbuff    (buffer, nsects, mode, disk,
  340.         block, track, sector, table);
  341.         break;
  342.  
  343.     case ' ':
  344.         /* Ignore spaces. */
  345.         break;
  346.  
  347.     default:
  348.         /* Unknown request. */
  349.         printf("%c ?????\n",c);
  350.         *bufp = '\0';
  351.         break;
  352.  
  353.     } /* end switch */
  354.  
  355.     if(kbhit()) getchar();
  356.     }
  357. }
  358.  
  359.  
  360. /* Call Bios.  Return a word, not just a byte. */
  361.  
  362. bioshl(function, bc, de)
  363. int function, bc, de;
  364. {
  365.     int * p;
  366.     int q;
  367.  
  368.     /* get address of BIOS jump table */
  369.     p = 0x0001;
  370.     q = *p + (3*function - 3);
  371.  
  372.     /* go to BIOS */
  373.     return call(q,0,0,bc,de);
  374. }
  375.  
  376.  
  377. /* Dump out the buffer in hex and in ascii. */
  378.  
  379. dmpbuff(pntr, nsects, mode, disk, block, track, sector, table)
  380. char *pntr;
  381. int nsects, mode, disk, block, track, sector;
  382. char *table;
  383. {
  384.     int i,j,lchar;
  385.  
  386.     prthdr(mode,nsects,disk,block,track,sector,table);
  387.  
  388.     for (i = 0; i < nsects * SECSIZE; i += 16) {
  389.  
  390.         if(i % SECSIZE == 0 && mode == LOG) {
  391.             printf("\n\nRecord %d\n", i/SECSIZE);
  392.         }
  393.         printf("\n%04x ", i);
  394.  
  395.         for (j = 0; j < 16; j++){
  396.             if(j%4 == 0) {
  397.                 printf(" ");
  398.             }
  399.             if (j%8 == 8) {
  400.                 printf(" ");
  401.             }
  402.             printf("%02x", pntr [i+j]);
  403.         }
  404.  
  405.         printf("  ");
  406.         for (j = 0; j < 16; j++) {
  407.             lchar = pntr [i+j];
  408.             if (lchar < 0x1f || lchar > 0x7d) {
  409.                 printf(".");
  410.             }
  411.             else {
  412.                 printf("%c",lchar);
  413.             }
  414.         }
  415.         if (kbhit()) break;
  416.     }
  417.     printf("\n");
  418. }
  419.  
  420.  
  421. /* Get a number from the keyboard. */
  422.  
  423. getnum(pntr, low, high, base)
  424. int low, high, base;
  425. char **pntr;
  426. {
  427.     int number;
  428.     char c, buffer[50], *bp;
  429.  
  430.     number = 0;
  431.     while(**pntr == ' ') (*pntr)++;
  432.     while((c = toupper(*(*pntr)++))>='0' && c<= '9' ||
  433.     base ==16 && (c-=7) > '9' && c<= ('F'-7))
  434.         number = base*number+c-'0';
  435.     (*pntr)--;
  436.  
  437.     if (number < low || number > high) {
  438.         if (base == 16) {
  439.             printf("%x is out of range.\n",number);
  440.             printf("Enter a hex number between ");
  441.             printf("%x and %x:  ", low, high);
  442.         }
  443.         else {
  444.             printf("%d is out of range.\n",number);
  445.             printf("Enter a decimal number ");
  446.             printf("between %d and %d:  ",
  447.             low, high);
  448.         }
  449.         bp = gets(buffer);
  450.         number = getnum(&bp, low, high, base);
  451.     }
  452.     return number;
  453. }
  454.  
  455.  
  456. /* Print a helpful message. */
  457.  
  458. help()
  459. {
  460.     printf("Commands are...\n\n");
  461.     printf("Bn  enter block mode and set block n.\n");
  462.     printf("Cn  fill buffer with short n.\n");
  463.     printf("Dn  set disk to n and print disk info.\n");
  464.     printf("Ea n1 n2 ...  edit buffer[a] with n1 n2 ...\n");
  465.     printf("Fn  fill buffer with unsigned n.\n");
  466.     printf("H   print this message.\n");
  467.     printf("I   enter track/sector mode.\n");
  468.     printf("M   print disk allocation map.\n");
  469.     printf("N   go to next block or track/sector.\n");
  470.     printf("P   print buffer.\n");
  471.     printf("R   read sector or block into buffer.\n");
  472.     printf("Sn  set current sector to n (first sector is 0).\n");
  473.     printf("Tn  set current track  to n (first track  is 0).\n");
  474.     printf("W   write sector or block from buffer.\n");
  475.     printf("X   exit program (must be alone on line).\n");
  476. }
  477.  
  478.  
  479. /* Print information about the selected disk. */
  480.  
  481. info()
  482. {
  483.     printf("Disk Parameter Header  = %x (hex)\n", d_header);
  484.     printf("Disk Parameter Block   = %x (hex)\n", d_disk);
  485.     printf("Sector Translate Table = %x (hex)\n", TXTABLE);
  486.     printf("Track offset:      %d\n", OFFSET);
  487.     printf("Tracks  per disk:  %d\n", TPD);
  488.     printf("Blocks  per disk:  %d, %x (hex)\n", BPD, BPD);
  489.     printf("Sectors per track: %d\n", SPT);
  490.     printf("Sectors per block: %d\n", SPB);
  491.     printf("Chars   per block: %d\n", SPB * SECSIZE);
  492.     printf("Directory blocks:  %d\n", DIRBLKS);
  493.     printf("Directory entries: %d\n", DIRSIZE);
  494.     printf("\n");
  495. }
  496.  
  497.  
  498. /* Print the header message of a dump. */
  499.  
  500. prthdr(mode, nsects, disk, block, track, sector, table)
  501. int nsects, mode, disk, block, track, sector;
  502. char *table;
  503. {
  504.     printf("\ndisk %c, ", disk + 'A');
  505.     if (mode == LOG) {
  506.         printf("block %d, ", block);
  507.     }
  508.     printf("track %d, ",
  509.     track + (mode == LOG ? OFFSET : 0));
  510.     printf("physical sector %d, ",
  511.     bioshl(SECTRAN, sector, table));
  512.     printf("logical sector %d", sector);
  513.     printf("\n");
  514. }
  515.  
  516.  
  517. /* Print the directory and a disk allocation map. */
  518.  
  519. #define M1COL 3        /* Entries/line:  directory    */
  520. #define M2COL 16    /* Entries/line:  alloc map    */
  521.  
  522. ptmap(disk, table)
  523. int disk;
  524. char *table;
  525. {
  526.     int count, i, j, k;
  527.     int track, sector, d, ex;
  528.     char dir[BBUFSIZ];    /* Current directory bloc. */
  529.     int  map[MBUFSIZ];    /* The disk allocation map. */
  530.     int *intdir, id;
  531.  
  532.     intdir = dir;
  533.  
  534.     /* Clear the map. */
  535.     setmem(&map, 2*MBUFSIZ, 0);
  536.  
  537.  
  538.     printf("The directory is...\n");
  539.  
  540.     track = sector = 0;
  541.     for (count = i = 0; i < DIRSIZE; i++) {
  542.  
  543.         if (i%(4*SPB) == 0) {
  544.             /* Read the next next block. */
  545.             rdbuff    (dir, SPB, LOG, disk,
  546.             0, track, sector, table);
  547.             sector += SPB;
  548.             if (sector >= SPT) {
  549.                 track++;
  550.                 sector -= SPT;
  551.             }
  552.             j = 0;
  553.         }
  554.         else {
  555.             j += 32;
  556.         }
  557.  
  558.         /* Skip never allocated entries completely. */
  559.         if (dir [j+1] == 0xe5) {
  560.             continue;
  561.         }
  562.  
  563.         /* Print M1COL entries per line. */
  564.         if (count%M1COL == 0) {
  565.             putchar('\n');
  566.         }
  567.         count++;
  568.  
  569.         /* Print directory number. */
  570.         printf("%3x", i);
  571.  
  572.         /* Print '=' for nondeleted extents */
  573.         printf("%s",  dir[j]==0 ? " = " : " * ");
  574.  
  575.         /* Save extent number. */
  576.         ex = dir [j + 12];
  577.  
  578.         /* Print the file name and extent. */
  579.         dir [j + 12] = 0;
  580.         printf("%s:%x  ", &dir [j+1], ex);
  581.  
  582.         /* Skip deleted blocks. */
  583.         if (dir [j] == 0xe5) {
  584.             continue;
  585.         }
  586.  
  587.         /* See whether block # fits in 8 bits. */
  588.         if (BPD <= 256){
  589.             for(k = 16; k < 32 && dir [j+k]; k++) {
  590.                 d = dir [j + k];
  591.                 if (d) {
  592.                     map [d] = i;
  593.                 }
  594.                 else {
  595.                     break;
  596.                 }
  597.             }
  598.         }
  599.         else {
  600.             for(k = 8; k<16 && intdir[j/2 + k]; k++){
  601.                 id = intdir [j/2 + k];
  602.                 if (id) {
  603.                     map [id] = i;
  604.                 }
  605.                 else {
  606.                     break;
  607.                 }
  608.             }
  609.         }
  610.     }
  611.  
  612.     printf("\n\nThe disk map is...\n\n");
  613.  
  614.     for(i = 0; i < BPD; i++) {
  615.  
  616.         if (i%M2COL == 0) {
  617.             printf("%3x: ", i);
  618.         }
  619.  
  620.         if (map [i]) {
  621.             printf("%3x ", map [i]);
  622.         }
  623.         else {
  624.             printf("... ");
  625.         }
  626.  
  627.         if(i%M2COL == M2COL-1) {
  628.             putchar('\n');
  629.         }
  630.     }
  631.     putchar('\n');
  632. }
  633.  
  634. #undef M1COL
  635. #undef M2COL
  636.  
  637.  
  638. /* Read a block or sector into the buffer. */
  639.  
  640. rdbuff(pntr, nsects, mode, disk, block, track, sector, table)
  641. char *pntr;
  642. int nsects, mode, disk, block, track, sector;
  643. char *table;
  644. {
  645.     int i;
  646.     int s;
  647.  
  648.     bios(SELDSK, disk);
  649.     for (i = 0; i < nsects; i++, sector++){
  650.         if (sector >= SPT) {
  651.             track++;
  652.             sector = 0;
  653.         }
  654.         if (track >= TPD) {
  655.             printf("Read truncated!\n");
  656.             return;
  657.         }
  658.         bios(SETTRK, track + (mode==LOG ? OFFSET : 0));
  659.         s = bioshl(SECTRAN, sector, table);
  660.         bios(SETSEC, s);
  661.         bios(SETDMA, pntr + (i * SECSIZE));
  662.         bios(RDSEC);
  663.     }    
  664. }
  665.  
  666.  
  667. /*
  668.     Select a drive for all future disk operations.
  669.     drive is 0 for drive A:, 1 for drive B:, etc.
  670. */
  671.  
  672. select (drive)
  673. char drive;
  674. {
  675.     int alloc, i, nsectors;
  676.  
  677.     printf("select drive = %c\n", drive + 'A');
  678.  
  679.     /* Point at the DPH and DPB. */
  680.     d_header = bioshl(SELDSK, drive, 0);
  681.     if (d_header == 0) {
  682.         printf("Select failed!\n");
  683.         exit();
  684.     }
  685.     d_disk = d_header -> d_DPB;
  686.  
  687.     /* calculate global constants for this drive */
  688.     TXTABLE = d_header -> d_XLT;
  689.     SPB = d_disk   -> d_BLM + 1;
  690.     BPD = d_disk   -> d_DSM + 1;
  691.     SPT     = d_disk   -> d_SPT;
  692.     OFFSET  = d_disk   -> d_OFF;
  693.  
  694.     /*
  695.         Compute number of logical tracks on the disk.
  696.         For hard disks nsectors can overflow.
  697.         thus, we must use a for loop instead of:
  698.      */
  699.  
  700.     /* comment out -----
  701.         nsectors = SPB * BPD;
  702.         ntracks  = nsectors / SPT;
  703.         if (nsectors % SPT != 0) {
  704.             TPD++;
  705.         }
  706.     ----- end comment out */
  707.  
  708.     nsectors = 0;
  709.     TPD  = 1;
  710.     for (i = 0; i < BPD; i++) {
  711.         nsectors += SPB;
  712.         if (nsectors > SPT) {
  713.             nsectors -= SPT;
  714.             TPD++;
  715.         }
  716.     }
  717.  
  718.     /* Add the number of hidden tracks. */
  719.     TPD += OFFSET;
  720.  
  721.     /* Compute the number of blocks in the directory. */
  722.     alloc = ((d_disk -> d_AL0) << 8) | (d_disk -> d_AL1);
  723.     DIRBLKS = 0;
  724.     for (i = 0; i < 16; i++) {
  725.         if ((alloc & 1) != 0) {
  726.             DIRBLKS++;
  727.         }
  728.         alloc = alloc >> 1;
  729.     }
  730.  
  731.     /*
  732.         Compute the number of entries in the directory.
  733.         There are 4 entries in each 128-byte sector.
  734.     */
  735.  
  736.     DIRSIZE = DIRBLKS * SPB * 4;
  737.  
  738.     /* Make sure the directory buffer is big enough. */
  739.     if (SPB * SECSIZE > BBUFSIZ) {
  740.         printf("Block buffer is too small.\n");
  741.         exit();
  742.     }
  743.  
  744.     /* Make sure the map buffer is big enough. */
  745.     if (DIRSIZE > MBUFSIZ) {
  746.         printf("Map buffer is too small.\n");
  747.         exit();
  748.     }
  749. }
  750.  
  751.  
  752. /* Write the buffer to the disk. */
  753.  
  754. wrbuff(pntr, nsects, mode, disk, block, track, sector, table)
  755. char *pntr;
  756. int nsects, mode, disk, block, track, sector;
  757. char *table;
  758. {
  759.     int i;
  760.     int s;
  761.  
  762.     bios (SELDSK, disk);
  763.     for (i = 0; i < nsects; i++, sector++) {
  764.         if (sector >= SPT) {
  765.             sector = 0;
  766.             track++;
  767.         }
  768.         if (track >= TPD) {
  769.             printf("Write truncated!\n");
  770.             return;
  771.         }
  772.         bios(SETTRK, track + (mode==LOG ? OFFSET : 0));
  773.         s = bioshl(SECTRAN, sector, table);
  774.         bios(SETSEC, s);
  775.         bios(SETDMA, pntr + (i * SECSIZE));
  776.  
  777.         /* Force immediate write. */
  778.         bios(WTSEC, 1);
  779.     }
  780. }
  781. able);
  782.         bios(SETSEC, s);
  783.         bios(SETDMA, pntr + (i * SECSIZE));
  784.  
  785.         /* Force immediate write. *