home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 331.lha / Lhwarp_v1.11 / Lhwarp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-01-08  |  37.8 KB  |  1,429 lines

  1. /* LHwarp 1.11, written by Jonathan Forbes */
  2. /* Copyright © Xenomiga Technology, 1990   */
  3.  
  4. #include <exec/types.h>
  5. #include <exec/memory.h>
  6. #include <exec/io.h>
  7. #include <devices/trackdisk.h>
  8. #include <libraries/dos.h>
  9. #include <libraries/dosextens.h>
  10. #include <stdlib.h>
  11. #include <stdio.h>
  12. #include <proto/exec.h>
  13. #include <proto/dos.h>
  14. #include "LHcrc.h"
  15.  
  16.  
  17. /* LHwarp version 1.11 */
  18. #define MAJOR_VERSION 1
  19. #define MINOR_VERSION 1
  20. #define DECIMAL_VERSION 1
  21.  
  22.  
  23. /* Trackdisk information */
  24. #define NUM_HEADS 2
  25. #define TRACK_SIZE   (TD_SECTOR * NUMSECS * NUM_HEADS)
  26. #define LABEL_LENGTH (16 * NUMSECS * NUM_HEADS)
  27. #define NUM_CYLS     80
  28. #define BLOCK_SIZE   TD_SECTOR
  29. #define NUM_BLOCKS   (NUM_CYLS * NUM_HEADS * NUMSECS)
  30. #define ROOT_BLOCK   (NUM_BLOCKS / 2)
  31. #define BITMAP_INDEX 79
  32. #define NUM_LONGS    (NUM_BLOCKS / 32)
  33.  
  34.  
  35. /* File i/o information */
  36. #define SEEK_SET 0
  37. #define SEEK_CUR 1
  38. #define SEEK_END 2
  39.  
  40.  
  41. /* LHwarp commands */
  42. #define WARP_READ 1
  43. #define WARP_WRITE 2
  44.  
  45.  
  46. /* For buffered i/o */
  47. #define IN_BUFFER_SIZE 16384
  48. #define OUT_BUFFER_SIZE 16384
  49.  
  50.  
  51. /* Only LZHUF is supported at the moment */
  52. #define COMPTYPE_LHARC 0
  53. #define COMPTYPE_NONE 1
  54.  
  55.  
  56. /* Track data types */
  57. #define DATATYPE_NORMAL 0
  58. #define DATATYPE_RAW 1
  59. #define DATATYPE_NORMAL_BLANK 2
  60.  
  61.  
  62. /* CRC-32 macro */
  63. #define UPDC32(b, c) (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF))
  64.  
  65.  
  66. struct WarpHeader
  67.    {
  68.       UBYTE  MajorVersion;
  69.       UBYTE  MinorVersion;
  70.       UBYTE  DecimalVersion;
  71.       UBYTE  Reserved;
  72.       USHORT StartTrack;
  73.       USHORT EndTrack;
  74.       ULONG  TextLength;
  75.       ULONG  CompressedTextLength;
  76.    };
  77.  
  78.  
  79. struct CompHeader101
  80.    {
  81.       UBYTE  CompressionType;
  82.       UBYTE  DataType;
  83.       UBYTE  TrackNumber;
  84.       UBYTE  Unused;
  85.       ULONG  FullLength;
  86.       ULONG  CompressedLength;
  87.    };
  88.  
  89.  
  90. struct CompHeader102
  91.    {
  92.       UBYTE  CompressionType;
  93.       UBYTE  DataType;
  94.       UBYTE  TrackNumber;
  95.       UBYTE  Unused;
  96.       ULONG  FullLength;
  97.       ULONG  CompressedLength;
  98.       ULONG  CheckSum;
  99.    };
  100.  
  101.  
  102. struct CompHeader110
  103.    {
  104.       UBYTE  CompressionType;
  105.       UBYTE  DataType;
  106.       UBYTE  TrackNumber;
  107.       UBYTE  Unused;
  108.       ULONG  SectorMask;
  109.       ULONG  FullLength;
  110.       ULONG  CompressedLength;
  111.       ULONG  CRC;
  112.    };
  113.  
  114.  
  115. UBYTE          *iotd_SecLabel = NULL;
  116.  
  117.  
  118. struct WarpHeader WHeader;
  119. struct IOExtTD   *ReadMsg   = NULL;
  120. struct IOExtTD   *WriteMsg  = NULL;
  121. struct MsgPort   *ReadPort  = NULL;
  122. struct MsgPort   *WritePort = NULL;
  123. long              GlobalTrack;
  124. long              GlobalSector;
  125. ULONG             GlobalSectorMap;
  126.  
  127.  
  128. extern FILE      *infile;            /* Input file handle  */
  129. extern FILE      *outfile;           /* Output file handle */
  130. extern UBYTE     *FilePosition;      /* For memory getc() and putc() functions */
  131. extern UBYTE     *EndOfFilePosition; /* For memory getc() and putc() functions */
  132. extern UBYTE     *PutFilePosition;   /* For memory getc() and putc() functions */
  133. extern long       cr3tab[];          /* External CRC-32 table */
  134.  
  135.  
  136. /* LZHUF defines and externs */
  137. #define N        4096    /* Size of string buffer */
  138. #define F        60       /* Size of look-ahead buffer */
  139. #define THRESHOLD    2
  140. #define NIL        N       /* End of tree's node  */
  141.  
  142.  
  143. extern unsigned char *text_buf;
  144. extern short         *lson, *rson, *dad;
  145.  
  146.  
  147. struct CompHeader101 CHeader101; /* Version 1.01      */
  148. struct CompHeader102 CHeader102; /* Version 1.02/1.03 */
  149. struct CompHeader110 CHeader110; /* Version 1.10/1.11 */
  150.  
  151.  
  152. char                 FileName[256];
  153. char                 TextFileName[256];
  154. UBYTE                Command;
  155. UBYTE                AppendTextFile;
  156.  
  157. USHORT               Version;
  158.  
  159. UBYTE                UseBitMap;
  160. BPTR                 FHandle;
  161. ULONG                StartTrack;
  162. ULONG                EndTrack;
  163. ULONG                Unit;
  164. APTR                 DataBlock = NULL;
  165. APTR                 NewBlock = NULL;
  166. APTR                 TrackdiskBlock = NULL;
  167. UBYTE                BitMapAllocation[NUM_CYLS][NUMSECS * NUM_HEADS];
  168.  
  169.  
  170. /* __regargs ... Isn't Lattice C amazing? */
  171. long  __regargs GetFileLength(char *FileToOpen);   /* Find file length    */
  172. ULONG __regargs DoSum(UBYTE *Block, ULONG Length); /* Checksum-32 routine */
  173. ULONG __regargs DoCRC(UBYTE *Block, ULONG Length); /* Fast CRC-32 routine */
  174. void  __regargs Decode(ULONG Size);                /* Uncompress data     */
  175. UBYTE           ReadCHeader();                     /* Read compression header */
  176.  
  177.  
  178. void main(int argc, char **argv)
  179. {
  180.    /* Make sure the user supplied the correct number of arguments */
  181.    if (argc != 2 && argc != 4 && argc != 6 && argc != 7)
  182.       {
  183.          Title();
  184.          exit (1);
  185.       }
  186.  
  187.    BuildFileName(argv);
  188.  
  189.    if (!stricmp(argv[1], "READ"))
  190.       {
  191.          DoReadInit();
  192.          UseBitMap = 1;
  193.       }
  194.    else if (!stricmp(argv[1], "WRITE"))
  195.       {
  196.          Command = WARP_WRITE;
  197.       }
  198.    else if (!stricmp(argv[1], "NOMAP"))
  199.       {
  200.          DoReadInit();
  201.          UseBitMap = 0;
  202.       }
  203.    else
  204.       {
  205.          puts("\nUnknown command\n");
  206.          exit(1);
  207.       }
  208.  
  209.    if (argc < 6 && (Command == WARP_READ))
  210.       {
  211.          Title();
  212.          exit (1);
  213.       }
  214.  
  215.    if (argc == 7)
  216.       {
  217.          strcpy(TextFileName, argv[6]);
  218.          AppendTextFile = 1;
  219.       }
  220.    else
  221.       {
  222.          AppendTextFile = 0;
  223.       }
  224.  
  225.    /* Get the unit number */
  226.    Unit       = atoi(argv[2]);
  227.  
  228.    /* Get the start and end tracks */
  229.    if (argc > 5)
  230.       {
  231.          StartTrack = atoi(argv[4]);
  232.          EndTrack   = atoi(argv[5]);
  233.       }
  234.  
  235.    if (StartTrack > EndTrack)
  236.       {
  237.          puts("Start track is greater than end track\n");
  238.          exit (1);
  239.       }
  240.  
  241.    Init();
  242.  
  243.    if (Command == WARP_WRITE)
  244.       {
  245.          WriteData();
  246.       }
  247.    else
  248.       {
  249.          ReadData();
  250.       }
  251. }
  252.  
  253.  
  254. Init()
  255. {
  256.    text_buf = NULL;
  257.    lson     = NULL;
  258.    rson     = NULL;
  259.    dad      = NULL;
  260.  
  261.    if (!(ReadPort = CreatePort(0L, 0L)))
  262.       {
  263.          puts("Couldn't create read port");
  264.          exit (1);
  265.       }
  266.  
  267.    if (!(WritePort = CreatePort(0L, 0L)))
  268.       {
  269.          puts("Couldn't create write port");
  270.          CleanUp();
  271.          exit (1);
  272.       }
  273.  
  274.    if (!(ReadMsg = (struct IOExtTD *) CreateExtIO(ReadPort, (long) sizeof(struct IOExtTD))))
  275.       {
  276.          puts("Couldn't create i/o read request");
  277.          CleanUp();
  278.          exit (1);
  279.       }
  280.  
  281.    if (!(WriteMsg = (struct IOExtTD *) CreateExtIO(WritePort, (long) sizeof(struct IOExtTD))))
  282.       {
  283.          puts("Couldn't create i/o write request");
  284.          CleanUp();
  285.          exit (1);
  286.       }
  287.  
  288.    ReadMsg->iotd_Req.io_Command = ETD_READ;
  289.    WriteMsg->iotd_Req.io_Command = ETD_WRITE;
  290.  
  291.    if (OpenDevice(TD_NAME, Unit, (struct IORequest *) ReadMsg, 0L))
  292.       {
  293.          puts("Couldn't open trackdisk.device for reading");
  294.          CleanUp();
  295.          exit (1);
  296.       }
  297.  
  298.    if (OpenDevice(TD_NAME, Unit, (struct IORequest *) WriteMsg, 0L))
  299.       {
  300.          puts("Couldn't open trackdisk.device for writing");
  301.          CleanUp();
  302.          exit (1);
  303.       }
  304.  
  305.    if (!(DataBlock = AllocMem((ULONG) TRACK_SIZE + (ULONG) LABEL_LENGTH, MEMF_PUBLIC)))
  306.       {
  307.          puts("Couldn't allocate trackdisk memory buffer");
  308.          CleanUp();
  309.          exit (1);
  310.       }
  311.  
  312.    if (!(NewBlock = AllocMem((ULONG) TRACK_SIZE + (ULONG) LABEL_LENGTH, MEMF_PUBLIC)))
  313.       {
  314.          puts("Couldn't allocate trackdisk memory buffer");
  315.          CleanUp();
  316.          exit (1);
  317.       }
  318.  
  319.    if (!(TrackdiskBlock = AllocMem((ULONG) TRACK_SIZE + (ULONG) LABEL_LENGTH, MEMF_CHIP)))
  320.       {
  321.          puts("Couldn't allocate trackdisk memory buffer");
  322.          CleanUp();
  323.          exit (1);
  324.       }
  325.  
  326.    if (!(iotd_SecLabel = AllocMem((ULONG) LABEL_LENGTH, MEMF_CHIP)))
  327.       {
  328.          puts("Couldn't allocate trackdisk extended memory buffer");
  329.          CleanUp();
  330.          exit (1);
  331.       }
  332.  
  333.    if (!(text_buf = AllocMem((ULONG) (N + F - 1), MEMF_PUBLIC)))
  334.       {
  335.          puts("Out of memory");
  336.          CleanUp();
  337.          exit (1);
  338.       }
  339.  
  340.    if (!(lson = AllocMem((ULONG) (N + 1) * (ULONG) (sizeof(short)), MEMF_PUBLIC)))
  341.       {
  342.          puts("Out of memory");
  343.          CleanUp();
  344.          exit (1);
  345.       }
  346.  
  347.    if (!(rson = AllocMem((ULONG) (N + 257) * (ULONG) (sizeof(short)), MEMF_PUBLIC)))
  348.       {
  349.          puts("Out of memory");
  350.          CleanUp();
  351.          exit (1);
  352.       }
  353.  
  354.    if (!(dad = AllocMem((ULONG) (N + 1) * (ULONG) (sizeof(short)), MEMF_PUBLIC)))
  355.       {
  356.          puts("Out of memory");
  357.          CleanUp();
  358.          exit (1);
  359.       }
  360. }
  361.  
  362.  
  363. Archive(USHORT Track, ULONG DataSize)
  364. {
  365.    register UBYTE   *OutBuffer;
  366.    UBYTE             CanSetBuffer;
  367.    ULONG             CurrentPosition;
  368.    ULONG             AfterEncodeLength;
  369.    ULONG             TotalEncodeLength;
  370.    register BPTR     outfp;
  371.  
  372.    /* Allocate a file buffer if we can */
  373.    if (OutBuffer = AllocMem((ULONG) OUT_BUFFER_SIZE, MEMF_PUBLIC))
  374.       {
  375.          CanSetBuffer = 1;
  376.       }
  377.    else
  378.       {
  379.          CanSetBuffer = 0;
  380.       }
  381.  
  382.    CurrentPosition = GetFileLength(FileName);
  383.  
  384.    /* Lhwarp to a file; this way, if the output is larger than the input */
  385.    /* we won't crash the machine */
  386.    if (!(outfile = fopen(FileName, "a+b")))
  387.       {
  388.          printf("Couldn't open temporary file for output\n");
  389.  
  390.          if (CanSetBuffer)
  391.             {
  392.                FreeMem(OutBuffer, (ULONG) OUT_BUFFER_SIZE);
  393.             }
  394.  
  395.          CleanUp();
  396.          exit (1);
  397.       }
  398.  
  399.    if (CanSetBuffer)
  400.       {
  401.          setvbuf(outfile, OutBuffer, _IOFBF, (long) OUT_BUFFER_SIZE);
  402.       }
  403.  
  404.    /* Write out a dummy file compression header */
  405.    fwrite(&CHeader110, sizeof(struct CompHeader110), 1, outfile);
  406.  
  407.    GlobalTrack  = Track;
  408.    GlobalSector = 0;
  409.  
  410.    Encode((ULONG) (DataSize));
  411.  
  412.    fclose(outfile);
  413.  
  414.    if (CanSetBuffer)
  415.       {
  416.          FreeMem(OutBuffer, (ULONG) OUT_BUFFER_SIZE);
  417.       }
  418.  
  419.    AfterEncodeLength = GetFileLength(FileName);
  420.    TotalEncodeLength = AfterEncodeLength - CurrentPosition - sizeof(struct CompHeader110);
  421.  
  422.    if (!(outfp = (BPTR) Open(FileName, (long) MODE_READWRITE)))
  423.       {
  424.          printf("Couldn't open temporary file for output\n\n");
  425.  
  426.          if (CanSetBuffer)
  427.             {
  428.                FreeMem(OutBuffer, (ULONG) OUT_BUFFER_SIZE);
  429.             }
  430.  
  431.          CleanUp();
  432.          exit (1);
  433.       }
  434.  
  435.    /* Seek back to the CompHeader section */
  436.    Seek((BPTR) outfp, (long) CurrentPosition, (long) OFFSET_BEGINNING);
  437.  
  438.    CHeader110.CompressedLength = TotalEncodeLength;
  439.    CHeader110.FullLength       = DataSize;
  440.    CHeader110.TrackNumber      = (UBYTE) Track;
  441.    CHeader110.CompressionType  = COMPTYPE_LHARC;
  442.    CHeader110.DataType         = DATATYPE_NORMAL;
  443.  
  444.    /* Checksum the block */
  445.    CHeader110.CRC = (ULONG) DoCRC(NewBlock, (ULONG) CHeader110.FullLength);
  446.  
  447.    /* Write it to disk */
  448.    Write((BPTR) outfp, &CHeader110, (long) sizeof(struct CompHeader110));
  449.  
  450.    /* Close the file */
  451.    Close((BPTR) outfp);
  452. }
  453.  
  454.  
  455. WriteData()
  456. {
  457.    ULONG           j;
  458.    ULONG           Track;
  459.    UBYTE          *TextMemory;
  460.    UBYTE          *TextCompMemory;
  461.    UBYTE          *ExtendedDataBlock;
  462.    ULONG           CheckSum;
  463.    ULONG           TracksWritten = 0L;
  464.    long            Error;
  465.    long            z;
  466.    register UBYTE *WriteLocation;
  467.    register UBYTE *TrackdiskBlockLoc;
  468.  
  469.    printf("\nLHWARP %d.%d%d - Amiga disk tracker - Written by Jonathan Forbes @ 1:250/642\n", (UBYTE) MAJOR_VERSION, (UBYTE) MINOR_VERSION, (UBYTE) DECIMAL_VERSION);
  470.    puts("Copyright © Xenomiga Technology, 1990.\n");
  471.  
  472.    printf("Insert destination disk in drive %ld and press RETURN when ready", Unit);
  473.    fflush(stdout);
  474.  
  475.    while (getc(stdin) != 10)
  476.       {
  477.       }
  478.  
  479.    puts("");
  480.  
  481.    printf("Writing to disk in drive %ld from file %s\n", Unit, FileName);
  482.  
  483.    /* Set up the write request */
  484.    WriteMsg->iotd_Req.io_Command = ETD_FORMAT;
  485.  
  486.    if (!(infile = fopen(FileName, "r")))
  487.       {
  488.          printf("Cannot open %s for input\n", FileName);
  489.          CleanUp();
  490.          exit (1);
  491.       }
  492.  
  493.    /* Read the Warp header */
  494.    fread(&WHeader, sizeof(struct WarpHeader), 1, infile);
  495.  
  496.    /* Get the version number */
  497.    Version = (WHeader.MajorVersion * 100) + (WHeader.MinorVersion * 10) + WHeader.DecimalVersion;
  498.  
  499.    /* What version of Lhwarp was used to compress the disk? */
  500.    if (WHeader.MajorVersion == 1 && WHeader.MinorVersion == 0 && WHeader.DecimalVersion == 1)
  501.       {
  502.          printf("Disk was compressed using Lhwarp 1.01\n\n");
  503.       }
  504.    else
  505.       {
  506.          printf("Disk was compressed using Lhwarp %d.%d%d\n\n", WHeader.MajorVersion, WHeader.MinorVersion, WHeader.DecimalVersion);
  507.       }
  508.  
  509.    if ((WHeader.MajorVersion > MAJOR_VERSION) ||
  510.        (WHeader.MajorVersion == MAJOR_VERSION && WHeader.MinorVersion > MINOR_VERSION))
  511.       {
  512.          printf("Sorry, this file was Lhwarp'd with Lhwarp V%d.%d%d\n",
  513.             WHeader.MajorVersion, WHeader.MinorVersion, WHeader.DecimalVersion);
  514.  
  515.          printf("You are using Lhwarp V%d.%d%d\n",
  516.             MAJOR_VERSION, MINOR_VERSION, DECIMAL_VERSION);
  517.  
  518.          CleanUp();
  519.          exit(1);
  520.       }
  521.  
  522.    if (WHeader.TextLength)
  523.       {
  524.          if (!(TextMemory = AllocMem((ULONG) WHeader.TextLength+1, MEMF_PUBLIC)))
  525.             {
  526.                printf("Insufficient memory (%ld bytes required) to read compressed text\n", (ULONG) WHeader.TextLength+1);
  527.                CleanUp();
  528.                exit(1);
  529.             }
  530.  
  531.          if (!(TextCompMemory = AllocMem((ULONG) WHeader.CompressedTextLength, MEMF_PUBLIC)))
  532.             {
  533.                printf("Insufficient memory (%ld bytes required) to decompress text\n", (ULONG) WHeader.CompressedTextLength);
  534.                FreeMem(TextMemory, (ULONG) WHeader.TextLength+1);
  535.                CleanUp();
  536.                exit(1);
  537.             }
  538.  
  539.          fread(TextCompMemory, (ULONG) WHeader.CompressedTextLength, 1, infile);
  540.  
  541.          FilePosition = (UBYTE *) TextCompMemory;
  542.  
  543.          /* Arbitrary number; just make it greater than TextLength */
  544.          EndOfFilePosition = (UBYTE *) ( ((UBYTE *) TextCompMemory) + (WHeader.CompressedTextLength));
  545.  
  546.          PutFilePosition = (UBYTE *) TextMemory;
  547.  
  548.          /* Don't display '.' and 'o' when decompressing text */
  549.          GlobalTrack = 0;
  550.  
  551.          Decode((ULONG) WHeader.TextLength);
  552.  
  553.          /* Make sure the text has a null terminator */
  554.          TextMemory[WHeader.TextLength] = 0;
  555.  
  556.          puts("\n----\n");
  557.          puts(TextMemory);
  558.          puts("----\n");
  559.  
  560.          FreeMem(TextMemory, (ULONG) WHeader.TextLength+1);
  561.          FreeMem(TextCompMemory, (ULONG) WHeader.CompressedTextLength);
  562.       }
  563.  
  564.    /* Start writing tracks */
  565.    for (;;)
  566.       {
  567.          /* If there are no more tracks to be written, exit */
  568.          if (ReadCHeader())
  569.             {
  570.                break;
  571.             }
  572.  
  573.          FilePosition = (UBYTE *) DataBlock;
  574.          PutFilePosition = (UBYTE *) NewBlock;
  575.  
  576.          if (Version == 101)
  577.             {
  578.                EndOfFilePosition = (UBYTE *) ( ((UBYTE *) DataBlock) + CHeader101.CompressedLength);
  579.                fread(DataBlock, (long) CHeader101.CompressedLength, 1, infile);
  580.  
  581.                /* Version 1.01 didn't support individual sectors */
  582.                GlobalTrack = 0;
  583.                Decode((ULONG) CHeader101.FullLength);
  584.  
  585.                Track = (ULONG) CHeader101.TrackNumber;
  586.  
  587.                /* Copy data into CHIP RAM */
  588.                CopyMem(NewBlock, TrackdiskBlock, (ULONG) TRACK_SIZE + (ULONG) LABEL_LENGTH);
  589.  
  590.                ExtendedDataBlock = (UBYTE *) ( ((UBYTE *) NewBlock) + ((ULONG) TRACK_SIZE));
  591.                CopyMem(ExtendedDataBlock, (UBYTE *) &iotd_SecLabel[0], (ULONG) LABEL_LENGTH);
  592.  
  593.                printf("Writing track %2ld\r", (ULONG) (Track));
  594.                fflush(stdout);
  595.             }
  596.          else if ((Version == 110 || Version == 111) && CHeader110.DataType == DATATYPE_NORMAL_BLANK)
  597.             {
  598.                Track = (ULONG) CHeader110.TrackNumber;
  599.                ClearMem(TrackdiskBlock, (ULONG) TRACK_SIZE);
  600.                ClearMem(&iotd_SecLabel[0], (ULONG) LABEL_LENGTH);
  601.  
  602.                WriteMsg->iotd_Req.io_Offset = (long) (TRACK_SIZE * Track);
  603.                WriteMsg->iotd_Req.io_Data   = (APTR) TrackdiskBlock;
  604.                WriteMsg->iotd_Req.io_Length = (ULONG) TRACK_SIZE;
  605.                WriteMsg->iotd_SecLabel      = (ULONG) &iotd_SecLabel[0];
  606.                WriteMsg->iotd_Count         = 0xFFFFFFFF;
  607.  
  608.                printf("Writing track %2ld: ______________________\r", (ULONG) (Track));
  609.                fflush(stdout);
  610.  
  611.                if (Error = DoIO((struct IORequest *) WriteMsg))
  612.                   {
  613.                      fclose(infile);
  614.                      printf("Fatal error %ld writing to disk in unit %ld -terminating\n\n", Error, Unit);
  615.                      MotorOff();
  616.                      CleanUp();
  617.                      exit (1);
  618.                   }
  619.             }
  620.          else if (Version == 102 || Version == 103)
  621.             {
  622.                EndOfFilePosition = (UBYTE *) ( ((UBYTE *) DataBlock) + CHeader102.CompressedLength);
  623.                fread(DataBlock, (long) CHeader102.CompressedLength, 1, infile);
  624.  
  625.                /* Versions 1.02 and 1.03 didn't support individual sectors */
  626.                GlobalTrack = 0;
  627.                Decode((ULONG) CHeader102.FullLength);
  628.  
  629.                Track = (ULONG) CHeader102.TrackNumber;
  630.  
  631.                CheckSum = (ULONG) DoSum(NewBlock, (ULONG) CHeader102.FullLength);
  632.  
  633.                if (CheckSum != CHeader102.CheckSum)
  634.                   {
  635.                      printf("Warning: Track %ld fails checksum\n", Track);
  636.                   }
  637.  
  638.                /* Copy data into CHIP RAM */
  639.                CopyMem(NewBlock, TrackdiskBlock, (ULONG) TRACK_SIZE + (ULONG) LABEL_LENGTH);
  640.  
  641.                ExtendedDataBlock = (UBYTE *) ( ((UBYTE *) NewBlock) + ((ULONG) TRACK_SIZE));
  642.                CopyMem(ExtendedDataBlock, (UBYTE *) &iotd_SecLabel[0], (ULONG) LABEL_LENGTH);
  643.  
  644.                printf("Writing track %2ld", (ULONG) (Track));
  645.                fflush(stdout);
  646.             }
  647.          else if (Version == 110 || Version == 111)
  648.             {
  649.                Track = (ULONG) CHeader110.TrackNumber;
  650.  
  651.                if (Track)
  652.                   {
  653.                      printf("Writing track %2ld: ", (ULONG) (Track));
  654.  
  655.                      /* Display the sectors which are to be decompressed */
  656.                      for (z = 0; z < (NUMSECS * NUM_HEADS); z++)
  657.                         {
  658.                            putc((UBYTE) Bit(&CHeader110.SectorMask, (UBYTE) z) ? '.' : '_', stdout);
  659.                         }
  660.  
  661.                      printf("D");
  662.                      fflush(stdout);
  663.                   }
  664.  
  665.                EndOfFilePosition = (UBYTE *) ( ((UBYTE *) DataBlock) + CHeader110.CompressedLength);
  666.                fread(DataBlock, (long) CHeader110.CompressedLength, 1, infile);
  667.  
  668.                /* Tell Decode() which sectors are to be decompressed */
  669.                /* so it can display '.' and 'o' properly */
  670.                GlobalTrack     = CHeader110.TrackNumber;
  671.                GlobalSectorMap = CHeader110.SectorMask;
  672.                GlobalSector    = 0;
  673.                Decode((ULONG) CHeader110.FullLength);
  674.  
  675.                if (DoCRC(NewBlock, (ULONG) CHeader110.FullLength) != CHeader110.CRC)
  676.                   {
  677.                      printf("Warning: Track %ld fails CRC\n", Track);
  678.                   }
  679.  
  680.                WriteLocation     = (UBYTE *) NewBlock;
  681.                TrackdiskBlockLoc = (UBYTE *) TrackdiskBlock;
  682.  
  683.                if (!Track)
  684.                   {
  685.                      puts("Disk contains the following bootblock:\n");
  686.                      DisplayBootBlock(NewBlock);
  687.                   }
  688.  
  689.                for (j=0; j < (NUMSECS * NUM_HEADS); j++)
  690.                   {
  691.                      if (Bit(&CHeader110.SectorMask, (UBYTE) j))
  692.                         {
  693.                            CopyMem(WriteLocation, TrackdiskBlockLoc, (ULONG) (TD_SECTOR));
  694.                            CopyMem((long) WriteLocation + (long) TD_SECTOR, &iotd_SecLabel[j * 16], (long) 16);
  695.                            WriteLocation = WriteLocation + (TD_SECTOR + 16);
  696.                            TrackdiskBlockLoc = TrackdiskBlockLoc + (long) TD_SECTOR;
  697.                          }
  698.                      else
  699.                         {
  700.                            ClearMem(TrackdiskBlockLoc, (ULONG) (TD_SECTOR));
  701.                            ClearMem(&iotd_SecLabel[j * 16], (long) 16);
  702.                            TrackdiskBlockLoc = TrackdiskBlockLoc + (long) TD_SECTOR;
  703.                         }
  704.                   }
  705.  
  706.                WriteMsg->iotd_Req.io_Offset = (long) (TRACK_SIZE * Track);
  707.                WriteMsg->iotd_Req.io_Data   = (APTR) TrackdiskBlock;
  708.                WriteMsg->iotd_Req.io_Length = (ULONG) TRACK_SIZE;
  709.                WriteMsg->iotd_SecLabel      = (ULONG) &iotd_SecLabel[0];
  710.                WriteMsg->iotd_Count         = 0xFFFFFFFF;
  711.  
  712.                if (Error = DoIO((struct IORequest *) WriteMsg))
  713.                   {
  714.                      fclose(infile);
  715.                      printf("Fatal error %ld writing to disk in unit %ld -terminating\n\n", Error, Unit);
  716.                      MotorOff();
  717.                      CleanUp();
  718.                      exit (1);
  719.                   }
  720.             }
  721.  
  722.          if (Version == 101 || Version == 102 || Version == 103)
  723.             {
  724.                if (!Track)
  725.                   {
  726.                      puts("Disk contains the following bootblock:\n");
  727.                      DisplayBootBlock(NewBlock);
  728.                   }
  729.  
  730.                WriteMsg->iotd_Req.io_Offset = (long) TRACK_SIZE * Track;
  731.                WriteMsg->iotd_Req.io_Data   = (APTR) TrackdiskBlock;
  732.                WriteMsg->iotd_Req.io_Length = (long) TRACK_SIZE;
  733.                WriteMsg->iotd_SecLabel      = (ULONG) &iotd_SecLabel[0];
  734.                WriteMsg->iotd_Count         = 0xFFFFFFFF;
  735.  
  736.                printf("Writing track %2ld", (ULONG) (Track));
  737.                fflush(stdout);
  738.  
  739.                if (DoIO((struct IORequest *) WriteMsg))
  740.                   {
  741.                      fclose(infile);
  742.                      printf("Fatal error writing to disk in unit %ld -terminating\n\n", Unit);
  743.                      MotorOff();
  744.                      CleanUp();
  745.                      exit (1);
  746.                   }
  747.             }
  748.  
  749.          printf("\r");
  750.          fflush(stdout);
  751.  
  752.          TracksWritten++;
  753.       }
  754.  
  755.    /* Push all trackdisk buffers onto the disk */
  756.    WriteMsg->iotd_Req.io_Length  = 0L;
  757.    WriteMsg->iotd_Req.io_Command = CMD_UPDATE;
  758.    DoIO((struct IORequest *) WriteMsg);
  759.  
  760.    MotorOff();
  761.  
  762.    WriteMsg->iotd_Req.io_Length  = 0L;
  763.    WriteMsg->iotd_Req.io_Command = CMD_FLUSH;
  764.    DoIO((struct IORequest *) WriteMsg);
  765.  
  766.    fclose(infile);
  767.  
  768.    printf("\n\nFinished writing %ld tracks\n\n", TracksWritten);
  769.    printf("Please remove and re-insert destination disk, to use\n\n");
  770.  
  771.    CleanUp();
  772. }
  773.  
  774.  
  775. MotorOff()
  776. {
  777.    WriteMsg->iotd_Req.io_Length  = 0L;
  778.    WriteMsg->iotd_Req.io_Command = TD_MOTOR;
  779.    DoIO((struct IORequest *) WriteMsg);
  780. }
  781.  
  782.  
  783. DisplayBootBlock(UBYTE *Data)
  784. {
  785.    char           Line[76];
  786.    UBYTE          i;
  787.    register UBYTE j;
  788.    register UBYTE c;
  789.  
  790.    /* End of the line to be displayed */
  791.    Line[73] = 0;
  792.  
  793.    for (i=0; i<14; i++)
  794.       {
  795.          for (j=0; j<73; j++)
  796.             {
  797.                c = *((UBYTE *) ( ((UBYTE *) Data) + (ULONG) (i * 64) + j));
  798.  
  799.                if (c < 32 || c > 126)
  800.                   {
  801.                      c = '.';
  802.                   }
  803.  
  804.                Line[j] = c;
  805.             }
  806.  
  807.          puts(Line);
  808.       }
  809.  
  810.    puts("");
  811. }
  812.  
  813.  
  814. ReadSector(ULONG Sector)
  815. {
  816.    ULONG Error;
  817.  
  818.    ReadMsg->iotd_Req.io_Command = CMD_READ;
  819.    ReadMsg->iotd_Req.io_Offset  = (long) BLOCK_SIZE * Sector;
  820.    ReadMsg->iotd_Req.io_Data    = (APTR) TrackdiskBlock;
  821.    ReadMsg->iotd_Req.io_Length  = (long) BLOCK_SIZE;
  822.  
  823.    if (Error = DoIO((struct IORequest *) ReadMsg))
  824.       {
  825.          printf("Error %d reading from trackdisk.device\n", Error);
  826.          CleanUp();
  827.          exit (1);
  828.       }
  829. }
  830.  
  831.  
  832. GetBitMap()
  833. {
  834.    int   BitMapSector;
  835.    ULONG i;
  836.    ULONG j;
  837.    ULONG Mask;
  838.    ULONG BlockNumber;
  839.    ULONG TrackNumber;
  840.    ULONG SectorNumber;
  841.  
  842.    for (i=1; i<NUM_CYLS; i++)
  843.       {
  844.          for (j=0; j<(NUMSECS * NUM_HEADS); j++)
  845.             {
  846.                BitMapAllocation[i][j] = 0;
  847.             }
  848.       }
  849.  
  850.    /* Track zero and the root track must always be sent */
  851.    BitMapAllocation[0][0] = 1;
  852.    BitMapAllocation[0][1] = 1;
  853.  
  854.    BitMapAllocation[(ROOT_BLOCK / 22)][0] = 1;
  855.  
  856.    ReadSector((ULONG) ROOT_BLOCK);
  857.    BitMapSector = (int) *((ULONG *) TrackdiskBlock + BITMAP_INDEX);
  858.  
  859.    ReadSector((long) BitMapSector);
  860.  
  861.    for (i = 1; i <= NUM_LONGS; i++)
  862.       {
  863.          Mask = (ULONG) TrackdiskBlock[i];
  864.  
  865.          for (j = 0; j < 32; j++)
  866.             {
  867.                if (i < NUM_LONGS || j < 30)
  868.                   {
  869.                      if (~Mask & 1)
  870.                         {
  871.                            BlockNumber  = ((i-1) * 32) + j + 2;
  872.                            TrackNumber  = (BlockNumber / 22);
  873.                            SectorNumber = (BlockNumber % 22);
  874.  
  875.                            BitMapAllocation[TrackNumber][SectorNumber] = 1;
  876.                         }
  877.  
  878.                      Mask >>= 1;
  879.                   }
  880.             }
  881.       }
  882. }
  883.  
  884.  
  885. ReadData()
  886. {
  887.    ULONG  AfterEncodeLength;
  888.    ULONG  TotalEncodeLength;
  889.    ULONG  TextLength;
  890.    ULONG  i;
  891.    ULONG  j;
  892.    ULONG  SecsRead;
  893.    ULONG  FileLength;
  894.    ULONG  OriginalLength = 0L;
  895.    BPTR   OutputFile;
  896.    BPTR   outfp;
  897.    ULONG  Error;
  898.    ULONG  DataSize;
  899.    FILE  *TextInFile;
  900.    UBYTE *TextMemory;
  901.    UBYTE *ReadLocation;
  902.  
  903.    printf("\nLHWARP %d.%d%d - Amiga disk tracker - Written by Jonathan Forbes @ 1:250/642\n", (UBYTE) MAJOR_VERSION, (UBYTE) MINOR_VERSION, (UBYTE) DECIMAL_VERSION);
  904.    puts("Copyright © Xenomiga Technology, 1990.\n");
  905.  
  906.    printf("Insert source disk in drive %ld and press RETURN when ready", Unit);
  907.    fflush(stdout);
  908.  
  909.    while (getc(stdin) != 10)
  910.       {
  911.       }
  912.  
  913.    puts("");
  914.  
  915.    if (UseBitMap)
  916.       {
  917.          GetBitMap();
  918.          printf("Using disk bitmap to skip unused sectors\n\n");
  919.       }
  920.  
  921.    printf("Reading from disk in drive %ld to file %s\n", Unit, FileName);
  922.  
  923.    /* Set up the read request */
  924.    ReadMsg->iotd_Req.io_Command = ETD_READ;
  925.    ReadMsg->iotd_Count          = 0xFFFFFFFF;
  926.  
  927.    /* If we start at track zero, check the boot block */
  928.    if (!StartTrack)
  929.       {
  930.          ReadMsg->iotd_Req.io_Offset = (long) 0L;
  931.          ReadMsg->iotd_Req.io_Data   = (APTR) TrackdiskBlock;
  932.  
  933.          /* Only get the first two sectors */
  934.          ReadMsg->iotd_Req.io_Length = (long) 1024L;
  935.  
  936.          if (Error = DoIO((struct IORequest *) ReadMsg))
  937.             {
  938.                printf("Error %d reading from trackdisk.device\n", Error);
  939.                CleanUp();
  940.                exit (1);
  941.             }
  942.  
  943.          printf("\nBoot block of floppy disk in drive %d:\n\n", Unit);
  944.          DisplayBootBlock(TrackdiskBlock);
  945.       }
  946.  
  947.    if (AppendTextFile)
  948.       {
  949.          TextLength = GetFileLength(TextFileName);
  950.  
  951.          if (!TextLength)
  952.             {
  953.                puts("Text file missing or zero length\n");
  954.                CleanUp();
  955.                exit (1);
  956.             }
  957.  
  958.          WHeader.TextLength = TextLength;
  959.       }
  960.    else
  961.       {
  962.          WHeader.TextLength = 0L;
  963.       }
  964.  
  965.    /* Build the Warp header */
  966.    WHeader.StartTrack = StartTrack;
  967.    WHeader.EndTrack   = EndTrack;
  968.  
  969.    /* Version 1.11 */
  970.    WHeader.MajorVersion = (UBYTE) MAJOR_VERSION;
  971.    WHeader.MinorVersion = (UBYTE) MINOR_VERSION;
  972.    WHeader.DecimalVersion = (UBYTE) DECIMAL_VERSION;
  973.  
  974.    /* Write out the Warp header */
  975.    if (!(OutputFile = Open(FileName, MODE_NEWFILE)))
  976.       {
  977.          printf("Couldn't open output file\n");
  978.          CleanUp();
  979.          exit (1);
  980.       }
  981.  
  982.    Write(OutputFile, &WHeader, (long) sizeof(struct WarpHeader));
  983.    Close(OutputFile);
  984.  
  985.    if (AppendTextFile)
  986.       {
  987.          printf("Compressing text ... ");
  988.          fflush(stdout);
  989.  
  990.          if (!(TextInFile = fopen(TextFileName, "r")))
  991.             {
  992.                printf("Can't open %s for input\n", TextInFile);
  993.                CleanUp();
  994.                exit(1);
  995.             }
  996.  
  997.          if (!(TextMemory = AllocMem((ULONG) TextLength, MEMF_PUBLIC)))
  998.             {
  999.                puts("Couldn't allocate text memory buffer");
  1000.                CleanUp();
  1001.                exit(1);
  1002.             }
  1003.  
  1004.          fread(TextMemory, (ULONG) TextLength, 1, TextInFile);
  1005.          fclose(TextInFile);
  1006.  
  1007.          if (!(outfile = fopen(FileName, "a")))
  1008.             {
  1009.                printf("Can't open %s for append\n", FileName);
  1010.                FreeMem(TextMemory, (ULONG) TextLength);
  1011.                CleanUp();
  1012.                exit(1);
  1013.             }
  1014.  
  1015.          FilePosition = (UBYTE *) TextMemory;
  1016.          EndOfFilePosition = (UBYTE *) ( ((UBYTE *) TextMemory) + (TextLength));
  1017.  
  1018.          GlobalTrack = -1;
  1019.  
  1020.          Encode((ULONG) (TextLength));
  1021.          fclose(outfile);
  1022.  
  1023.          FreeMem(TextMemory, (ULONG) TextLength);
  1024.  
  1025.          AfterEncodeLength = GetFileLength(FileName);
  1026.          TotalEncodeLength = AfterEncodeLength - (ULONG) sizeof(struct WarpHeader);
  1027.  
  1028.          WHeader.CompressedTextLength = TotalEncodeLength;
  1029.  
  1030.          if (!(outfile = fopen(FileName, "r+w")))
  1031.             {
  1032.                printf("Can't open %s for append\n", FileName);
  1033.                CleanUp();
  1034.                exit(1);
  1035.             }
  1036.  
  1037.          fwrite(&WHeader, sizeof(struct WarpHeader), 1, outfile);
  1038.          fclose(outfile);
  1039.  
  1040.          printf("done\n\n");
  1041.       }
  1042.  
  1043.    if (StartTrack)
  1044.       {
  1045.          puts("");
  1046.       }
  1047.  
  1048.    /* Start reading tracks */
  1049.    for (i = StartTrack; i <= EndTrack; i++)
  1050.       {
  1051.          for (j = 0; j < NUMSECS * NUM_HEADS; j++)
  1052.             {
  1053.                if (BitMapAllocation[i][j])
  1054.                   {
  1055.                      break;
  1056.                   }
  1057.             }
  1058.  
  1059.          if (UseBitMap && j >= (NUMSECS * NUM_HEADS))
  1060.             {
  1061.                printf("Reading track %2ld: ______________________\r", (ULONG) i);
  1062.                fflush(stdout);
  1063.  
  1064.                CHeader110.CompressedLength = 0L;
  1065.                CHeader110.FullLength       = 0L;
  1066.                CHeader110.TrackNumber      = (UBYTE) i;
  1067.                CHeader110.CompressionType  = COMPTYPE_NONE;
  1068.                CHeader110.DataType         = DATATYPE_NORMAL_BLANK;
  1069.                CHeader110.CRC              = 0L;
  1070.                CHeader110.SectorMask       = 0L;
  1071.  
  1072.                /* Write it to disk */
  1073.                if (!(outfp = (BPTR) Open(FileName, (long) MODE_READWRITE)))
  1074.                   {
  1075.                      printf("Couldn't open %s for output\n\n", FileName);
  1076.                      CleanUp();
  1077.                      exit(1);
  1078.                    }
  1079.  
  1080.                Seek((BPTR) outfp, (long) 0L, (long) OFFSET_END);
  1081.                Write((BPTR) outfp, &CHeader110, (long) sizeof(struct CompHeader110));
  1082.                Close((BPTR) outfp);
  1083.             }
  1084.          else
  1085.             {
  1086.                DataSize          = 0L;
  1087.                ReadLocation      = (UBYTE *) NewBlock;
  1088.  
  1089.                printf("Reading track %2ld:                          D", (ULONG) (i));
  1090.                fflush(stdout);
  1091.  
  1092.                SecsRead = 0;
  1093.  
  1094.                for (j=0; j<(NUMSECS * NUM_HEADS); j++)
  1095.                   {
  1096.                      if ((!UseBitMap) || BitMapAllocation[i][j])
  1097.                         {
  1098.                            putc('.', stdout);
  1099.  
  1100.                            ReadMsg->iotd_Req.io_Offset = (long) (TRACK_SIZE * i) + (j * TD_SECTOR);
  1101.                            ReadMsg->iotd_Req.io_Data   = (APTR) TrackdiskBlock;
  1102.                            ReadMsg->iotd_Req.io_Length = (long) TD_SECTOR;
  1103.                            ReadMsg->iotd_SecLabel      = (UBYTE *) TrackdiskBlock + TD_SECTOR;
  1104.                            ReadMsg->iotd_Count         = 0xFFFFFFFF;
  1105.  
  1106.                            DoIO((struct IORequest *) ReadMsg);
  1107.  
  1108.                            CopyMem(TrackdiskBlock, ReadLocation, (ULONG) (TD_SECTOR + 16));
  1109.                            ReadLocation = ReadLocation + (TD_SECTOR + 16);
  1110.  
  1111.                            SecsRead++;
  1112.                            DataSize = DataSize + (TD_SECTOR + 16);
  1113.  
  1114.                            SetBit(&CHeader110.SectorMask, (UBYTE) j, (UBYTE) 1);
  1115.                         }
  1116.                      else
  1117.                         {
  1118.                            putc('_', stdout);
  1119.  
  1120.                            SetBit(&CHeader110.SectorMask, (UBYTE) j, (UBYTE) 0);
  1121.                         }
  1122.                   }
  1123.  
  1124.                printf("D");
  1125.                fflush(stdout);
  1126.  
  1127.                FilePosition = (UBYTE *) NewBlock;
  1128.                EndOfFilePosition = (UBYTE *) ( ((UBYTE *) NewBlock) + (DataSize));
  1129.  
  1130.                Archive(i, DataSize);
  1131.  
  1132.                putc('\r', stdout);
  1133.                fflush(stdout);
  1134.  
  1135.                OriginalLength += (DataSize);
  1136.             }
  1137.       }
  1138.  
  1139.    ReadMsg->iotd_Req.io_Length  = 0;
  1140.    ReadMsg->iotd_Req.io_Command = TD_MOTOR;
  1141.    DoIO((struct IORequest *) ReadMsg);
  1142.  
  1143.    FileLength = GetFileLength(FileName);
  1144.  
  1145.    printf("\n\nFinished reading tracks %d to %d (%d total)\n", WHeader.StartTrack, WHeader.EndTrack, WHeader.EndTrack - WHeader.StartTrack + 1);
  1146.    printf(" Input file: %ld bytes\n", OriginalLength);
  1147.    printf("Output file: %ld bytes\n\n", FileLength);
  1148.  
  1149.    CleanUp();
  1150. }
  1151.  
  1152.  
  1153. CleanUp()
  1154. {
  1155.    if (ReadMsg)
  1156.       {
  1157.          CloseDevice((struct IORequest *) ReadMsg);
  1158.          DeleteExtIO((struct IORequest *) ReadMsg, (long) sizeof(struct IOExtTD));
  1159.       }
  1160.  
  1161.    if (WriteMsg)
  1162.       {
  1163.          CloseDevice((struct IORequest *) WriteMsg);
  1164.          DeleteExtIO((struct IORequest *) WriteMsg, (long) sizeof(struct IOExtTD));
  1165.       }
  1166.  
  1167.    if (ReadPort)
  1168.       {
  1169.          DeletePort(ReadPort);
  1170.       }
  1171.  
  1172.    if (WritePort)
  1173.       {
  1174.          DeletePort(WritePort);
  1175.       }
  1176.  
  1177.    if (DataBlock)
  1178.       {
  1179.          FreeMem(DataBlock, (ULONG) TRACK_SIZE + (ULONG) LABEL_LENGTH);
  1180.       }
  1181.  
  1182.    if (NewBlock)
  1183.       {
  1184.          FreeMem(NewBlock, (ULONG) TRACK_SIZE + (ULONG) LABEL_LENGTH);
  1185.       }
  1186.  
  1187.    if (TrackdiskBlock)
  1188.       {
  1189.          FreeMem(TrackdiskBlock, (ULONG) TRACK_SIZE + (ULONG) LABEL_LENGTH);
  1190.       }
  1191.  
  1192.    if (iotd_SecLabel)
  1193.       {
  1194.          FreeMem(iotd_SecLabel, (ULONG) LABEL_LENGTH);
  1195.       }
  1196.  
  1197.    if (text_buf)
  1198.       {
  1199.          FreeMem(text_buf, (ULONG) (N + F - 1));
  1200.       }
  1201.  
  1202.    if (lson)
  1203.       {
  1204.          FreeMem(lson, (ULONG) (N + 1) * (ULONG) (sizeof(short)));
  1205.       }
  1206.  
  1207.    if (rson)
  1208.       {
  1209.          FreeMem(rson, (ULONG) (N + 257) * (ULONG) (sizeof(short)));
  1210.       }
  1211.  
  1212.    if (dad)
  1213.       {
  1214.          FreeMem(dad, (ULONG) (N + 1) * (ULONG) (sizeof(short)));
  1215.       }
  1216. }
  1217.  
  1218.  
  1219. Title()
  1220. {
  1221.    printf("\nLHWARP %d.%d%d - Amiga disk tracker - Written by Jonathan Forbes @ 1:250/642\n", (UBYTE) MAJOR_VERSION, (UBYTE) MINOR_VERSION, (UBYTE) DECIMAL_VERSION);
  1222.    puts("Copyright © Xenomiga Technology, 1990.\n");
  1223.  
  1224.    puts("Usage: LHWARP <Command> <Unit> <Filename> <StartTrack> <EndTrack> <TextFile>\n");
  1225.  
  1226.    puts("<Command>    Read, NoMap, or Write");
  1227.    puts("<Unit>       Drive number (0 for internal, 1 ... 3 for external)");
  1228.    puts("<Filename>   Output or input filename");
  1229.    puts("<StartTrack> Track number (0 ... 79) [valid only in read mode]");
  1230.    puts("<EndTrack>   Track number (0 ... 79) [valid only in read mode]");
  1231.    puts("<TextFile>   Attach text in <TextFile> to output file (optional)\n");
  1232. }
  1233.  
  1234.  
  1235. long __regargs GetFileLength(char *FileToOpen)
  1236. {
  1237.    FILE  *fp;
  1238.    long  Length;
  1239.  
  1240.    if (!(fp = fopen(FileToOpen, "r")))
  1241.       {
  1242.          return (NULL);
  1243.       }
  1244.  
  1245.    fseek(fp, 0L, SEEK_END);
  1246.    Length = ftell(fp);
  1247.    fclose(fp);
  1248.  
  1249.    return (Length);
  1250. }
  1251.  
  1252.  
  1253. /* If the user presses ^C */
  1254. int CXBRK()
  1255. {
  1256.    if (WriteMsg)
  1257.       {
  1258.          WriteMsg->iotd_Req.io_Length  = 0L;
  1259.          WriteMsg->iotd_Req.io_Command = TD_MOTOR;
  1260.          DoIO((struct IORequest *) WriteMsg);
  1261.       }
  1262.  
  1263.    if (ReadMsg)
  1264.       {
  1265.          ReadMsg->iotd_Req.io_Length  = 0L;
  1266.          ReadMsg->iotd_Req.io_Command = TD_MOTOR;
  1267.          DoIO((struct IORequest *) ReadMsg);
  1268.       }
  1269.  
  1270.    CleanUp();
  1271.    return (-1);
  1272. }
  1273.  
  1274.  
  1275. ULONG __regargs DoSum(UBYTE *Block, ULONG Length)
  1276. {
  1277.    register ULONG Sum = 0;
  1278.    register ULONG i;
  1279.  
  1280.    for (i = 0; i < Length; i++)
  1281.       {
  1282.          Sum = Sum + Block[i];
  1283.       }
  1284.  
  1285.    return (Sum);
  1286. }
  1287.  
  1288.  
  1289. ULONG __regargs DoCRC(UBYTE *Block, ULONG Length)
  1290. {
  1291.    register ULONG CRC = 0;
  1292.    register ULONG i;
  1293.  
  1294.    for (i = 0; i < Length; i++)
  1295.       {
  1296.          CRC = UPDC32(Block[i], CRC);
  1297.       }
  1298.  
  1299.    return (CRC);
  1300. }
  1301.  
  1302.  
  1303. BuildFileName(char **argv)
  1304. {
  1305.    /* Get the file name */
  1306.    strcpy(FileName, argv[3]);
  1307.    strupr(FileName);
  1308.  
  1309.    /* Append .LHW if necessary */
  1310.    if (strcmp(FileName, ".LHW"))
  1311.       {
  1312.          if (strlen(FileName) > 4)
  1313.             {
  1314.                if (strcmp(&FileName[strlen(FileName)-4], ".LHW"))
  1315.                   {
  1316.                      strcat(FileName, ".LHW");
  1317.                   }
  1318.             }
  1319.          else
  1320.             {
  1321.                strcat(FileName, ".LHW");
  1322.             }
  1323.       }
  1324. }
  1325.  
  1326.  
  1327. Caution()
  1328. {
  1329.    UBYTE c;
  1330.  
  1331.    printf("\nLHWARP %d.%d%d - Amiga disk tracker - Written by Jonathan Forbes @ 1:250/642\n", (UBYTE) MAJOR_VERSION, (UBYTE) MINOR_VERSION, (UBYTE) DECIMAL_VERSION);
  1332.    puts("Copyright © Xenomiga Technology, 1990.\n");
  1333.  
  1334.    printf("Caution: File %s already exists.  Remove it? (y/n) ", FileName);
  1335.    fflush(stdout);
  1336.  
  1337.    while (toupper(c = getc(stdin)) != 'Y' && toupper(c) != 'N')
  1338.       {
  1339.       }
  1340.  
  1341.    if (toupper(c) == 'N')
  1342.       {
  1343.          puts("\n");
  1344.          CleanUp();
  1345.          exit(1);
  1346.       }
  1347.  
  1348.    /* Get rid of the 'return' character */
  1349.    getc(stdin);
  1350. }
  1351.  
  1352.  
  1353. DoReadInit()
  1354. {
  1355.    if (!access(FileName, 0))
  1356.       {
  1357.          Caution();
  1358.  
  1359.          /* Remove the file if it was already there */
  1360.          remove(FileName);
  1361.  
  1362.          Command = WARP_READ;
  1363.       }
  1364. }
  1365.  
  1366.  
  1367. ClearMem(register UBYTE *source, register ULONG size)
  1368. {
  1369.    do
  1370.       {
  1371.          *source = 0;
  1372.          source++;
  1373.          size--;
  1374.       } while (size);
  1375. }
  1376.  
  1377.  
  1378. Bit(register UBYTE *StartByte, register UBYTE Position)
  1379. {
  1380.    register UBYTE WhichByte;
  1381.    register UBYTE WhichBit;
  1382.  
  1383.    WhichByte = Position / 8;
  1384.    WhichBit  = Position % 8;
  1385.  
  1386.    return (StartByte[WhichByte] & (1 << WhichBit));
  1387. }
  1388.  
  1389.  
  1390. SetBit(register UBYTE *StartByte, register UBYTE Position, register UBYTE Value)
  1391. {
  1392.    register UBYTE WhichByte;
  1393.    register UBYTE WhichBit;
  1394.  
  1395.    WhichByte = Position / 8;
  1396.    WhichBit  = Position % 8;
  1397.  
  1398.    StartByte[WhichByte] = Value ?
  1399.       (StartByte[WhichByte] | (1 << WhichBit)) : (StartByte[WhichByte] & (~(1 << WhichBit)));
  1400. }
  1401.  
  1402.  
  1403. UBYTE ReadCHeader()
  1404. {
  1405.    if (Version == 101)
  1406.       {
  1407.          if (!(fread(&CHeader101, sizeof(struct CompHeader101), 1, infile)))
  1408.             {
  1409.                return (1);
  1410.             }
  1411.       }
  1412.    else if (Version == 102 || Version == 103)
  1413.       {
  1414.          if (!(fread(&CHeader102, sizeof(struct CompHeader102), 1, infile)))
  1415.             {
  1416.                return (1);
  1417.             }
  1418.       }
  1419.    else
  1420.       {
  1421.          if (!(fread(&CHeader110, sizeof(struct CompHeader110), 1, infile)))
  1422.             {
  1423.                return (1);
  1424.             }
  1425.       }
  1426.  
  1427.    return (0);
  1428. }
  1429.