home *** CD-ROM | disk | FTP | other *** search
/ ftp.ee.pdx.edu / 2014.02.ftp.ee.pdx.edu.tar / ftp.ee.pdx.edu / pub / users / Harry / Blitz / BlitzSrc / diskUtil.c < prev    next >
C/C++ Source or Header  |  2007-09-20  |  46KB  |  1,526 lines

  1. /* BLITZ Disk Utility for "Stub File System"
  2. **
  3. ** Copyright 2004-2007, Harry H. Porter III
  4. **
  5. ** This file may be freely copied, modified and compiled, on the sole
  6. ** conditions that if you modify it...
  7. **
  8. **   (1) Your name and the date of modification is added to this comment
  9. **       under "Modifications by", and
  10. **
  11. **   (2) Your name and the date of modification is added to the
  12. **       "commandLineHelp()" routine under "Modifications by".
  13. **
  14. ** Original Author:
  15. **   10/07/04 - Harry H. Porter III
  16. **
  17. ** Modifications by:
  18. **   04/30/07 - Harry H. Porter III - Support for little endian added
  19. **
  20. ** Please respect the coding and commenting style of this program.
  21. **
  22. **
  23. ** The BLITZ emulator simulates the BLITZ disk using a Unix file on the host
  24. ** machine.  This program allows that file to be manipulated.  For example,
  25. ** it can be used to copy an executable file containing a user program to the
  26. ** BLITZ disk so that the BLITZ OS kernel can then access, load, and run it.
  27. **
  28. ** The BLITZ DISK is organized as follows.  The disk contains a single directory
  29. ** and this is kept in sector 0.  The files are placed sequentially on the
  30. ** disk, one after the other.  Each file will take up an integral number of
  31. ** sectors.  Each file has an entry in the directory.  Each entry contains
  32. **      (1)  The starting sector
  33. **      (2)  The file length, in bytes (possibly zero)
  34. **      (3)  The number of characters in the file name
  35. **      (4)  The file name
  36. ** The directory begins with three numbers:
  37. **      (1)  Magic Number (0x73747562 = "stub")
  38. **      (2)  Number of files (possibly zero)
  39. **      (3)  Number of the next free sector
  40. ** These are followed by the entries for each file.
  41. **
  42. ** Once created, a BLITZ file may not have its size increased.  When a file is
  43. ** removed, the free sectors become unusable; there is no compaction or any
  44. ** attempt to reclaim the lost space.
  45. **
  46. ** Each time this program is run, it performs one of the following functions:
  47. **       Initialize  set up a new file system on the BLITZ disk
  48. **       List        list the directory on the BLITZ disk
  49. **       Create      create a new file of a given size
  50. **       Remove      remove a file
  51. **       Add         copy a file from Unix to BLITZ
  52. **       Extract     copy a file from BLITZ to Unix
  53. **       Write       write sectors from a Unix file to the BLITZ disk
  54. **
  55. ** For further info, see the function "commandLineHelp" or run the program:
  56. **      diskUtil -h
  57. */
  58.  
  59. #include <stdlib.h>
  60. #include <stdio.h>
  61. #include <stdarg.h>
  62. #include <string.h>
  63. #include <errno.h>
  64.  
  65.  
  66. /* SWAP_BYTES (int)  -->  int
  67. **
  68. ** This macro is used to swap the bytes in a 32-bit int from Big Endian order
  69. ** to Little Endian order, or vice-versa.
  70. **
  71. ** For example:
  72. **     i = SWAP_BYTES (i);
  73. **
  74. ** This program was originally written for a Big Endian architecture so swapping
  75. ** bytes was never necessary.  When compiled on a Big Endian computer, this macro
  76. ** is a no-op; when compiled on a Little Endian machine, it will swap the bytes.
  77. **
  78. */
  79. #ifdef BLITZ_HOST_IS_LITTLE_ENDIAN
  80. #define SWAP_BYTES(x) \
  81.     ((int)((((int)(x) & 0xff000000) >> 24) | \
  82.            (((int)(x) & 0x00ff0000) >>  8) | \
  83.            (((int)(x) & 0x0000ff00) <<  8) | \
  84.            (((int)(x) & 0x000000ff) << 24)))
  85. #else
  86. #define SWAP_BYTES(x) (x)
  87. #endif
  88.  
  89.  
  90.  
  91. #define SECTORS_PER_TRACK      16
  92. #define PAGE_SIZE              8192            /* Page Size (8K) */
  93. #define MAX 2147483647
  94.  
  95.  
  96.  
  97. /*****  Global variables *****/
  98.  
  99. int commandOptionI = 0;           /* The -i option */
  100. int commandOptionL = 0;           /* The -l option */
  101. int commandOptionC = 0;           /* The -c option */
  102. int commandOptionR = 0;           /* The -r option */
  103. int commandOptionA = 0;           /* The -a option */
  104. int commandOptionE = 0;           /* The -e option */
  105. int commandOptionW = 0;           /* The -w option */
  106. int commandOptionV = 0;           /* The -v option */
  107. char * diskFileName = NULL;       /* The DISK filename */
  108. FILE * diskFile = NULL;           /* The DISK file, possibly NULL */
  109. char * unixFileName = NULL;       /* The UNIX filename */
  110. FILE * unixFile = NULL;           /* The UNIX file descriptor, possibly NULL */
  111. char * blitzFileName = NULL;      /* The BLITZ filename */
  112. int startingSectorNumber = -1;    /* From the command line */
  113. int sizeInBytes = -1;             /* From the command line */
  114. int numberSectorsOnDisk = -1;     /* Number of sectors on the DISK file */
  115. int dirMagic = -1;                /* Magic number "stub" */
  116. int numberOfFiles = -1;           /* Number of files in directory */
  117. int nextFreeSector = -1;          /* Next free sector on disk */
  118. int sizeOfDirectoryInBytes = -1;  /* The number of bytes consumed in sector 0 */
  119. int thisFileSizeInBytes = -1;     /* The size of the selected file */
  120. int thisFileStartingSector = -1;  /* The starting sector of this file */
  121.  
  122. typedef struct Entry Entry;
  123.  
  124. struct Entry {
  125.   Entry * next;
  126.   int startingSector;
  127.   int sizeInBytes;
  128.   int lengthOfName;
  129.   char * name;
  130. };
  131.  
  132. Entry * firstEntry = 0;
  133. Entry * lastEntry = 0;
  134.  
  135.  
  136. /*****  Function prototypes  *****/
  137.  
  138. int main (int argc, char ** argv);
  139. void closeFiles ();
  140. void openDiskFile (int existing);
  141. void writeCommand ();
  142. void initializeCommand ();
  143. void listCommand ();
  144. void createCommand ();
  145. void removeCommand ();
  146. void addCommand ();
  147. void extractCommand ();
  148. void checkHostCompatibility ();
  149. void checkArithmetic ();
  150. void processCommandLine (int argc, char ** argv);
  151. void badOption (char * msg);
  152. void fatalError (char * msg);
  153. void commandLineHelp ();
  154. int readInteger ();
  155. void writeInteger (int i);
  156. void writeString (char * str, int len);
  157. char * readString (int len);
  158. Entry * findFile (char * str);
  159. void seekTo (int i);
  160. void printDirectory ();
  161. void writeDirectory ();
  162.  
  163.  
  164.  
  165. /* main ()
  166. **
  167. ** Scan the command line arguments, then enter into the command loop.
  168. */
  169. main (int argc, char ** argv) {
  170.   checkHostCompatibility ();
  171.   checkArithmetic ();
  172.   processCommandLine (argc, argv);
  173.  
  174.   /* If the "write" option (-w) was given, write a file to the DISK. */
  175.   if (commandOptionW) {
  176.     writeCommand ();
  177.   } else if (commandOptionI) {
  178.     initializeCommand ();
  179.   } else if (commandOptionL) {
  180.     listCommand ();
  181.   } else if (commandOptionC) {
  182.     createCommand ();
  183.   } else if (commandOptionR) {
  184.     removeCommand ();
  185.   } else if (commandOptionA) {
  186.     addCommand ();
  187.   } else if (commandOptionE) {
  188.     extractCommand ();
  189.   } else {
  190.     fatalError ("No commands given; Use -h for help display");
  191.   }
  192. }
  193.  
  194.  
  195.  
  196. /* initializeCommand ()
  197. **
  198. ** Initialize the BLITZ DISK file by writing out an empty directory.
  199. */
  200. void initializeCommand () {
  201.   long longLength;
  202.   int diskFileLength, diskMagic;
  203.  
  204.   if (commandOptionV) printf ("INITIALIZING THE FILE SYSTEM...\n");
  205.  
  206.   openDiskFile (0);               /* Existing = false */
  207.  
  208.   seekTo (4);                     /* Skip past "BLZd" magic number */
  209.   writeInteger (0x73747562);      /* Magic number = "stub" */
  210.   writeInteger (0);               /* Number of file */
  211.   writeInteger (1);               /* Next Free Sector */
  212.  
  213.   if (commandOptionV) printf ("Number of files on disk = 0\n");
  214.   if (commandOptionV) printf ("Next free sector = 1\n");
  215.   if (commandOptionV) printf ("Number of available sectors = %d\n", numberSectorsOnDisk-1);
  216.  
  217.   closeFiles ();
  218. }
  219.  
  220.  
  221.  
  222. /* openDiskFile (existing)
  223. **
  224. ** Open the BLITZ DISK file and read in some info.  If "existing" is true,
  225. ** then also read in the directory info and make sure things look right.
  226. */
  227. void openDiskFile (int existing) {
  228.   long longLength;
  229.   int diskFileLength, diskMagic, i;
  230.   Entry * ent;
  231.  
  232.   if (commandOptionV) printf ("Opening the DISK file...\n");
  233.  
  234.   // Open the DISK file for updating...
  235.   errno = 0;
  236.   diskFile = fopen (diskFileName, "r+");
  237.   if (errno) {
  238.     perror ("Error on DISK file");
  239.     fatalError ("The DISK file could not be opened for updating");
  240.   }
  241.  
  242. // qqqqq  PREVIOUSLY THE FOLLOWING PRINT WAS DISABLED FOR AUTOMATED TESTING...
  243.   if (commandOptionV) printf ("  The DISK file \"%s\" has been opened successfully.\n", diskFileName);
  244.  
  245.   /* Get the size of the DISK file... */
  246.   errno = 0;
  247.   fseek (diskFile, 0l, SEEK_END);
  248.   if (errno) {
  249.     perror ("Error on DISK file");
  250.     fatalError ("Error during call to fseek");
  251.   }
  252.   longLength = ftell (diskFile);
  253.  
  254.   /* Check to see if the file is too big... */
  255.   if (longLength > ((long) MAX)) {
  256.     printf ("The maximum integer is %d\n", MAX);
  257.     fatalError ("Error in DISK File: The DISK file size exceeds the maximum");
  258.   }
  259.  
  260.   /* Print the length of the DISK file */
  261.   diskFileLength = (int) longLength;
  262.   if (commandOptionV) printf ("  The length of the DISK file is %d bytes.\n", diskFileLength);
  263.   numberSectorsOnDisk = (diskFileLength - 4) / PAGE_SIZE;
  264.   if (commandOptionV) printf ("  The number of sectors on the DISK = %d\n", numberSectorsOnDisk);
  265.  
  266.   /* Reposition the DISK file to the beginning. */
  267.   seekTo (0);
  268.  
  269.   /* Check the DISK magic number. */
  270.   diskMagic = readInteger ();
  271.   if (diskMagic != 0x424C5A64) {
  272.     fatalError ("Error in DISK File: Magic number is not 'BLZd'");
  273.   }
  274.  
  275.   /* Read the "Stub file system directory" magic number. */
  276.   dirMagic = readInteger ();
  277.   // printf ("  dirMagic = 0x%08x\n", dirMagic);
  278.  
  279.   /* Read the number of files. */
  280.   numberOfFiles = readInteger ();
  281.  
  282.   /* Read the next free sector. */
  283.   nextFreeSector = readInteger ();
  284.  
  285.   if (!existing) {
  286.     return;
  287.   }
  288.  
  289.   sizeOfDirectoryInBytes = 16;        /* Magic "BLZd", Magic "stub", int, int */
  290.  
  291.   /* Check the directory magic number */
  292.   if (dirMagic != 0x73747562) {
  293.     printf ("The directory magic number is not 0x73747562 = \"stub\"\n");
  294.     fatalError ("Error in DISK File: No file system found; see the -i option");
  295.   }
  296.  
  297.   /* Check nextFreeSector */
  298.   if (nextFreeSector < 1 || nextFreeSector > numberSectorsOnDisk) {
  299.     fatalError ("Error in DISK File: The 'nextFreeSector' is incorrect");
  300.   }
  301.  
  302.   /* Check numberOfFiles */
  303.   if (numberOfFiles < 0 || numberOfFiles > 1000) {
  304.     fatalError ("Error in DISK File: The 'numberOfFiles' is incorrect");
  305.   }
  306.  
  307.   if (commandOptionV) printf ("  The number of files = %d\n", numberOfFiles);
  308.   if (commandOptionV) printf ("  The next free sector = %d\n", nextFreeSector);
  309.  
  310.   /* Read in the files and allocate the directory structures. */
  311.   firstEntry = 0;
  312.   lastEntry = 0;
  313.   for (i = numberOfFiles; i > 0; i--) {
  314.     ent = (Entry *) calloc (1, sizeof (Entry));
  315.     ent->startingSector = readInteger ();
  316.     ent->sizeInBytes = readInteger ();
  317.     ent->lengthOfName = readInteger ();
  318.     ent->name = readString (ent->lengthOfName);
  319.     ent->next = 0;
  320.     if (firstEntry) {
  321.       lastEntry->next = ent;
  322.       lastEntry = ent;
  323.     } else {
  324.       firstEntry = ent;
  325.       lastEntry = ent;
  326.     }
  327.     sizeOfDirectoryInBytes += 12 + ent->lengthOfName;
  328.   }
  329.  
  330.   if (commandOptionV) printf ("  The size of the directory = %d bytes\n", sizeOfDirectoryInBytes);
  331. }
  332.  
  333.  
  334.  
  335. /* closeFiles ()
  336. **
  337. ** Close all open files and exit.
  338. */
  339. void closeFiles () {
  340.  
  341.   /* Close the DISK file if open. */
  342.   if (diskFile) {
  343.     errno = 0;
  344.     fclose (diskFile);
  345.     if (errno) {
  346.       perror ("Error on BLITZ DISK file");
  347.       fatalError ("The BLITZ DISK file could not be closed");
  348.     }
  349.     if (commandOptionV) printf ("The BLITZ DISK file was closed successfully.\n");
  350.   }
  351.  
  352.   /* Close the UNIX file if open. */
  353.   if (unixFile) {
  354.     errno = 0;
  355.     fclose (unixFile);
  356.     if (errno) {
  357.       perror ("Error on UNIX file");
  358.       fatalError ("The UNIX file could not be closed");
  359.     }
  360.     if (commandOptionV) printf ("The UNIX file was closed successfully.\n");
  361.   }
  362.  
  363.   /* Return no error */
  364.   exit (0);
  365. }
  366.  
  367.  
  368.  
  369. /* listCommand ()
  370. **
  371. ** Print the directory contents.
  372. */
  373. void listCommand () {
  374.   if (commandOptionV) printf ("LISTING DIRECTORY...\n");
  375.   openDiskFile (1);         /* existing = true */
  376.   printDirectory ();
  377.   closeFiles ();
  378. }
  379.  
  380.  
  381.  
  382. /* createCommand ()
  383. **
  384. ** Create a new file on the BLITZ DISK.
  385. */
  386. void createCommand () {
  387.   Entry * ent;
  388.   int sizeInSectors;
  389.   if (commandOptionV) printf ("CREATING A NEW FILE...\n");
  390.   if (commandOptionV) printf ("  blitzFileName = \'%s\'\n", blitzFileName);
  391.   if (commandOptionV) printf ("  sizeInBytes = %d\n", sizeInBytes);
  392.  
  393.   openDiskFile (1);         /* existing = true */
  394.  
  395.   if (findFile (blitzFileName)) {
  396.     fatalError ("A file with this name already exists on the BLITZ DISK");
  397.   }
  398.  
  399.   /* Create a new entry */
  400.   ent = (Entry *) calloc (1, sizeof (Entry));
  401.   ent->startingSector = nextFreeSector;
  402.   ent->sizeInBytes = sizeInBytes;
  403.   ent->lengthOfName = strlen (blitzFileName);
  404.   ent->name = blitzFileName;
  405.  
  406.   /* Add it to the list */
  407.   ent->next = 0;
  408.   if (firstEntry) {
  409.     lastEntry->next = ent;
  410.     lastEntry = ent;
  411.   } else {
  412.     firstEntry = ent;
  413.     lastEntry = ent;
  414.   }
  415.  
  416.   /* Adjust the file statistics */
  417.   sizeInSectors = (sizeInBytes + PAGE_SIZE-1) / PAGE_SIZE;
  418.   nextFreeSector = nextFreeSector + sizeInSectors;
  419.   numberOfFiles ++;
  420.   sizeOfDirectoryInBytes += 12 + ent->lengthOfName;
  421.  
  422.   /* Make sure the directory has not grown too large to fit into sector 0. */
  423.   if (sizeOfDirectoryInBytes > PAGE_SIZE) {
  424.     fatalError ("The directory has grown too large to fit into sector 0");
  425.   }
  426.  
  427.   /* Make sure this file will fit on the disk. */
  428.   if (nextFreeSector > numberSectorsOnDisk) {
  429.     fatalError ("This file will not fit onto the disk");
  430.   }
  431.  
  432.   if (commandOptionV) {
  433.     printf ("Size of directory info = %d bytes\n", sizeOfDirectoryInBytes);
  434.     printf ("Size of this file = %d sectors\n", sizeInSectors);
  435.     printf ("New total number of sectors used = %d\n", nextFreeSector);
  436.     printf ("Number of free sectors left = %d\n", numberSectorsOnDisk - nextFreeSector);
  437.     printf ("New number of files = %d\n", numberOfFiles);
  438.  
  439.     /* Print the new directory */
  440.     printDirectory ();
  441.   }
  442.  
  443.   /* Write out the new directory */
  444.   writeDirectory ();
  445.  
  446.   closeFiles ();
  447. }
  448.  
  449.  
  450.  
  451. /* removeCommand ()
  452. **
  453. ** Remove a file from the BLITZ DISK file.
  454. */
  455. void removeCommand () {
  456.   Entry * ent, * prev;
  457.  
  458.   if (commandOptionV) {
  459.     printf ("REMOVING A FILE...\n");
  460.     printf ("  blitzFileName = \'%s\'\n", blitzFileName);
  461.   }
  462.  
  463.   openDiskFile (1);         /* existing = true */
  464.  
  465.   /* Set ent to point to the entry to delete;
  466.      set prev to point to the entry before it (or null). */
  467.   ent = firstEntry;
  468.   prev = NULL;
  469.   while (1) {
  470.     if (ent == NULL) {
  471.       fatalError ("This file does not exist on the BLITZ DISK");
  472.     }
  473.     if (strcmp (ent->name, blitzFileName) == 0) {
  474.       break;
  475.     }
  476.     prev = ent;
  477.     ent = ent->next;
  478.   }
  479.  
  480.   /* Remove the entry */
  481.   if (lastEntry == ent) {
  482.     lastEntry = prev;
  483.   }
  484.   if (firstEntry == ent) {
  485.     firstEntry = ent->next;
  486.   }
  487.   if (prev) {
  488.     prev->next = ent->next;
  489.   }
  490.  
  491.   /* Adjust the file statistics */
  492.   numberOfFiles--;
  493.  
  494.   if (commandOptionV) {
  495.     printf ("The file has been removed.\n");
  496.     printf ("  New number of files = %d\n", numberOfFiles);
  497.     printf ("  Total number of sectors used = %d\n", nextFreeSector);
  498.     printf ("  Number of free sectors left = %d\n", numberSectorsOnDisk - nextFreeSector);
  499.     printDirectory ();
  500.   }
  501.  
  502.   /* Write out the new directory */
  503.   writeDirectory ();
  504. }
  505.  
  506.  
  507.  
  508. /* addCommand ()
  509. **
  510. ** Copy a UNIX file to the BLITZ DISK file.
  511. */
  512. void addCommand () {
  513.   long longLength;
  514.   Entry * ent;
  515.   int unixFileSizeInBytes, unixFileSizeInSectors, s, i;
  516.   char * memory;
  517.  
  518.   if (commandOptionV) {
  519.     printf ("ADD A UNIX FILE TO THE BLITZ DISK...\n");
  520.     printf ("  unixFileName = \'%s\'\n", unixFileName);
  521.     printf ("  blitzFileName = \'%s\'\n", blitzFileName);
  522.   }
  523.  
  524.   openDiskFile (1);         /* existing = true */
  525.  
  526.   // Open the UNIX file for reading...
  527.   errno = 0;
  528.   unixFile = fopen (unixFileName, "r");
  529.   if (errno) {
  530.     perror ("Error on UNIX file");
  531.     fatalError ("The UNIX file could not be opened for reading");
  532.   }
  533.  
  534.   if (commandOptionV) printf ("The UNIX file \"%s\" has been opened successfully.\n", unixFileName);
  535.  
  536.   /* Get the size of the UNIX file... */
  537.   errno = 0;
  538.   fseek (unixFile, 0l, SEEK_END);
  539.   if (errno) {
  540.     perror ("Error on UNIX file");
  541.     fatalError ("Error during call to fseek");
  542.   }
  543.   longLength = ftell (unixFile);
  544.  
  545.   /* Check to see if the file is too big... */
  546.   if (longLength > ((long) MAX)) {
  547.     printf ("The maximum integer is %d\n", MAX);
  548.     fatalError ("Error in UNIX File: The UNIX file size exceeds the maximum");
  549.   }
  550.  
  551.   /* Print the length of the UNIX file */
  552.   unixFileSizeInBytes = (int) longLength;
  553.   unixFileSizeInSectors = (unixFileSizeInBytes + PAGE_SIZE-1) / PAGE_SIZE;
  554.   if (commandOptionV) {
  555.     printf ("The length of the UNIX file = %d bytes.\n", unixFileSizeInBytes);
  556.     printf ("                            = %d sectors.\n", unixFileSizeInSectors);
  557.   }
  558.  
  559.   ent = findFile (blitzFileName);
  560.  
  561.   if (ent) {
  562.     if (commandOptionV) printf ("A file with this name already exists; updating it.\n");
  563.     // We have now set "thisFileSizeInBytes" and "thisFileStartingSector"
  564.  
  565.     /* Make sure this file will fit into the space allocated on BLITZ disk. */
  566.     s = ((ent->sizeInBytes) + PAGE_SIZE-1) / PAGE_SIZE;
  567.     if (commandOptionV) printf ("The size of the BLITZ file = %d sectors.\n", s);
  568.     if (s < unixFileSizeInSectors) {
  569.       fatalError ("The existing file is too small; please delete it and re-add it");
  570.     }
  571.  
  572.   } else {
  573.     if (commandOptionV) printf ("A file with this name does not already exist; creating new file.\n");
  574.  
  575.     /* Create a new entry */
  576.     ent = (Entry *) calloc (1, sizeof (Entry));
  577.     ent->startingSector = nextFreeSector;
  578.     ent->sizeInBytes = unixFileSizeInBytes;
  579.     ent->lengthOfName = strlen (blitzFileName);
  580.     ent->name = blitzFileName;
  581.  
  582.     /* Add it to the list */
  583.     ent->next = 0;
  584.     if (firstEntry) {
  585.       lastEntry->next = ent;
  586.       lastEntry = ent;
  587.     } else {
  588.       firstEntry = ent;
  589.       lastEntry = ent;
  590.     }
  591.  
  592.     /* Adjust the file statistics */
  593.     nextFreeSector = nextFreeSector + unixFileSizeInSectors;
  594.     numberOfFiles ++;
  595.     sizeOfDirectoryInBytes += 12 + ent->lengthOfName;
  596.  
  597.     /* Make sure the directory has not grown too large to fit into sector 0. */
  598.     if (sizeOfDirectoryInBytes > PAGE_SIZE) {
  599.       fatalError ("The directory has grown too large to fit into sector 0");
  600.     }
  601.  
  602.     /* Make sure this file will fit on the disk. */
  603.     if (nextFreeSector > numberSectorsOnDisk) {
  604.       fatalError ("This file will not fit onto the disk");
  605.     }
  606.  
  607.     if (commandOptionV) {
  608.       printf ("Size of directory info = %d bytes\n", sizeOfDirectoryInBytes);
  609.       printf ("Size of this file = %d sectors\n", unixFileSizeInSectors);
  610.       printf ("New total number of sectors used = %d\n", nextFreeSector);
  611.       printf ("Number of free sectors left = %d\n", numberSectorsOnDisk - nextFreeSector);
  612.       printf ("New number of files = %d\n", numberOfFiles);
  613.       printDirectory ();
  614.     }
  615.  
  616.     /* Write out the new directory */
  617.     writeDirectory ();
  618.   }
  619.  
  620.   /* Allocate a chunk of memory big enough to hold all of the source file. */
  621.   memory = (char *) calloc (1, unixFileSizeInBytes);
  622.   if (memory == 0) {
  623.     fatalError ("Unable to allocate enough memory to hold the entire source file");
  624.   }
  625.  
  626.   /* Reposition the source file to the beginning. */
  627.   errno = 0;
  628.   fseek (unixFile, 0l, SEEK_SET);
  629.   if (errno) {
  630.     perror ("Error on Unix file");
  631.     fatalError ("The Unix file could not be repositioned");
  632.   }
  633.  
  634.   /* Read the Unix file entirely into memory. */
  635.   errno = 0;
  636.   i = fread (memory, 1, unixFileSizeInBytes, unixFile);
  637.   if (i != unixFileSizeInBytes) {
  638.     if (errno) perror ("Error reading from Unix file");
  639.     fatalError ("Problems reading from Unix file");
  640.   }
  641.  
  642.   seekTo (4 + PAGE_SIZE * ent->startingSector);
  643.   
  644.   /* Write the data to the DISK file. */
  645.   if (commandOptionV) printf ("Writing to DISK file (sector = %d)\n", ent->startingSector);
  646.   errno = 0;
  647.   i = fwrite (memory, 1, unixFileSizeInBytes, diskFile);
  648.   if (i != unixFileSizeInBytes) {
  649.     if (errno) perror ("Error writing to DISK file");
  650.     fatalError ("Problems writing to DISK file");
  651.   }
  652.  
  653.   closeFiles ();
  654. }
  655.  
  656.  
  657.  
  658. /* extractCommand ()
  659. **
  660. ** Copy a file from the BLITZ DISK file into a Unix file.
  661. */
  662. void extractCommand () {
  663.   Entry * ent;
  664.   int i;
  665.   char * memory;
  666.  
  667.   if (commandOptionV) {
  668.     printf ("EXTRACTING A FILE FROM THE BLITZ DISK...\n");
  669.     printf ("  blitzFileName = \'%s\'\n", blitzFileName);
  670.     printf ("  unixFileName = \'%s\'\n", unixFileName);
  671.   }
  672.  
  673.   openDiskFile (1);         /* existing = true */
  674.  
  675.   ent = findFile (blitzFileName);
  676.  
  677.   if (ent == NULL) {
  678.     fatalError ("There is no file with this name on the BLITZ DISK");
  679.   }
  680.  
  681.   if (commandOptionV) {
  682.     printf ("This file starts at sector %d\n", ent->startingSector);
  683.     printf ("Size of this file = %d bytes\n", ent->sizeInBytes);
  684.   }
  685.  
  686.   // Open the UNIX file for updating...
  687.   errno = 0;
  688.   unixFile = fopen (unixFileName, "wa");
  689.   if (errno) {
  690.     perror ("Error on UNIX file");
  691.     fatalError ("The UNIX file could not be opened for updating");
  692.   }
  693.  
  694.   if (commandOptionV) printf ("The UNIX file \"%s\" has been opened successfully.\n", unixFileName);
  695.  
  696.   /* Allocate a chunk of memory big enough to hold all of the file. */
  697.   memory = (char *) calloc (1, ent->sizeInBytes);
  698.   if (memory == 0) {
  699.     fatalError ("Unable to allocate enough memory to hold the entire file");
  700.   }
  701.  
  702.   /* Reposition the UNIX file to the beginning. */
  703.   errno = 0;
  704.   fseek (unixFile, 0l, SEEK_SET);
  705.   if (errno) {
  706.     perror ("Error on UNIX file");
  707.     fatalError ("The UNIX file could not be repositioned");
  708.   }
  709.  
  710.   /* Reposition the BLITZ file to the correct sector. */
  711.   seekTo (4 + PAGE_SIZE * ent->startingSector);
  712.  
  713.   /* Read the BLITZ file entirely into memory. */
  714.   errno = 0;
  715.   i = fread (memory, 1, ent->sizeInBytes, diskFile);
  716.   if (i != ent->sizeInBytes) {
  717.     if (errno) perror ("Error reading from BLITZ DISK file");
  718.     fatalError ("Problems reading from BLITZ DISK file");
  719.   }
  720.   
  721.   /* Write the data to the UNIX file. */
  722.   if (commandOptionV) printf ("Writing to DISK file.\n");
  723.   errno = 0;
  724.   i = fwrite (memory, 1, ent->sizeInBytes, unixFile);
  725.   if (i != ent->sizeInBytes) {
  726.     if (errno) perror ("Error writing to UNIX file");
  727.     fatalError ("Problems writing to UNIX file");
  728.   }
  729.  
  730.   closeFiles ();
  731.  
  732. }
  733.  
  734.  
  735.  
  736. /* writeCommand ()
  737. **
  738. ** Write data from a Unix file straight to some sectors on the BLITZ DISK.
  739. */
  740. void writeCommand () {
  741.   char * memory = NULL;             /* Pointer to a chunk of memory */
  742.   int i, magic, unixFileLength, where, diskFileLength;
  743.   long longLength;
  744.  
  745.   if (commandOptionV) {
  746.     printf ("WRITING SECTORS TO THE BLITZ DISK...\n");
  747.     printf ("  diskFileName = \'%s\'\n", diskFileName);
  748.     printf ("  unixFileName = \'%s\'\n", unixFileName);
  749.     printf ("  startingSectorNumber = %d\n", startingSectorNumber);
  750.   }
  751.  
  752.   // Open the DISK file for updating...
  753.   errno = 0;
  754.   diskFile = fopen (diskFileName, "r+");
  755.   if (errno) {
  756.     perror ("Error on DISK file");
  757.     fatalError ("The DISK file could not be opened for updating");
  758.   }
  759.  
  760. // qqqqq  PREVIOUSLY THE FOLLOWING PRINT WAS DISABLED FOR AUTOMATED TESTING...
  761.   if (commandOptionV) printf ("The DISK file \"%s\" has been opened successfully.\n", diskFileName);
  762.  
  763.   /* Get the size of the DISK file... */
  764.   errno = 0;
  765.   fseek (diskFile, 0l, SEEK_END);
  766.   if (errno) {
  767.     perror ("Error on DISK file");
  768.     fatalError ("Error during call to fseek");
  769.   }
  770.   longLength = ftell (diskFile);
  771.  
  772.   /* Check to see if the file is too big... */
  773.   if (longLength > ((long) MAX)) {
  774.     printf ("The maximum integer is %d\n", MAX);
  775.     fatalError ("Error in DISK File: The DISK file size exceeds the maximum");
  776.   }
  777.  
  778.   /* Print the length of the DISK file */
  779.   diskFileLength = (int) longLength;
  780.   if (commandOptionV) printf ("The length of the DISK file is %d bytes.\n", diskFileLength);
  781.  
  782.   /* Check for a file that is too short... */
  783.   if (diskFileLength < (SECTORS_PER_TRACK * PAGE_SIZE + 4)) {
  784.     /*  printf ("The minimum DISK file size is 1 track + 4 bytes
  785.                 (where PageSize = %d bytes and SectorsPerTrack = %d).\n",
  786.                 PAGE_SIZE, SECTORS_PER_TRACK);  */
  787.     fatalError ("Error in DISK file length: The file must be large enough for at least 1 track");
  788.   }
  789.  
  790.   /* Check for bad file length... */
  791.   numberSectorsOnDisk = (diskFileLength - 4) / PAGE_SIZE;
  792.   if (numberSectorsOnDisk * PAGE_SIZE + 4 != diskFileLength) {
  793.     /* printf ("PageSize = %d bytes, SectorsPerTrack = %d, DISK file size = %d.\n",
  794.                 PAGE_SIZE, SECTORS_PER_TRACK, diskFileLength);  */
  795.     fatalError ("Error in DISK file length: The file size is not an even number of tracks plus 4 bytes");
  796.   }
  797.  
  798.   if (commandOptionV) printf ("The number of sectors on the DISK = %d\n", numberSectorsOnDisk);
  799.  
  800.   /* Reposition the DISK file to the beginning. */
  801.   errno = 0;
  802.   fseek (diskFile, 0l, SEEK_SET);
  803.   if (errno) {
  804.     perror ("Error on DISK file");
  805.     fatalError ("The DISK file could not be repositioned");
  806.   }
  807.  
  808.   /* Check the magic number. */
  809.   magic = readInteger ();
  810.   if (magic != 0x424C5A64) {
  811.     fatalError ("Error in DISK File: Magic number is not 'BLZd'");
  812.   }
  813.  
  814.   // Open the source file for updating...
  815.   errno = 0;
  816.   unixFile = fopen (unixFileName, "r");
  817.   if (errno) {
  818.     perror ("Error on source file");
  819.     fatalError ("The source file could not be opened for reading");
  820.   }
  821.  
  822.   if (commandOptionV) printf ("The source file \"%s\" has been opened successfully.\n", unixFileName);
  823.  
  824.   /* Get the size of the source file... */
  825.   errno = 0;
  826.   fseek (unixFile, 0l, SEEK_END);
  827.   if (errno) {
  828.     perror ("Error on source file");
  829.     fatalError ("Error during call to fseek");
  830.   }
  831.   longLength = ftell (unixFile);
  832.  
  833.   /* Check to see if the file is too big... */
  834.   if (longLength > ((long) MAX)) {
  835.     printf ("The maximum integer is %d\n", MAX);
  836.     fatalError ("Error in source File: The source file size exceeds the maximum");
  837.   }
  838.  
  839.   /* Print the length of the source file */
  840.   unixFileLength = (int) longLength;
  841.   if (commandOptionV) printf ("The length of the source file is %d bytes.\n", unixFileLength);
  842.  
  843.   /* Allocate a chunk of memory big enough to hold all of the source file. */
  844.   memory = (char *) calloc (1, unixFileLength);
  845.   if (memory == 0) {
  846.     fatalError ("Unable to allocate enough memory to hold the entire source file");
  847.   }
  848.  
  849.   /* Reposition the source file to the beginning. */
  850.   errno = 0;
  851.   fseek (unixFile, 0l, SEEK_SET);
  852.   if (errno) {
  853.     perror ("Error on source file");
  854.     fatalError ("The source file could not be repositioned");
  855.   }
  856.  
  857.   /* Read the source file entirely into memory. */
  858.   errno = 0;
  859.   i = fread (memory, 1, unixFileLength, unixFile);
  860.   if (i != unixFileLength) {
  861.     if (errno) perror ("Error reading from source file");
  862.     fatalError ("Problems reading from source file");
  863.   }
  864.  
  865.   /* Compute where in the DISK file to write the data. */
  866.   where = 4 + (startingSectorNumber * PAGE_SIZE);
  867.  
  868.   /* Check to see if this write will exceed the DISK file's length. */
  869.   if (where + unixFileLength > diskFileLength) {
  870.     fatalError ("The DISK file is not large enough to accomodate this write");
  871.   }
  872.  
  873.   /* Reposition the DISK file to "where". */
  874.   errno = 0;
  875.   fseek (diskFile, (long) where, SEEK_SET);
  876.   if (errno) {
  877.     perror ("Error on DISK file");
  878.     fatalError ("The DISK file could not be could be repositioned");
  879.   }
  880.  
  881.   /* Write the data to the DISK file. */
  882.   if (commandOptionV) printf ("Writing to DISK file (address = %d)\n", where);
  883.   errno = 0;
  884.   i = fwrite (memory, 1, unixFileLength, diskFile);
  885.   if (i != unixFileLength) {
  886.     if (errno) perror ("Error writing to DISK file");
  887.     fatalError ("Problems writing to DISK file");
  888.   }
  889.  
  890.   /* Print how many sectors were involved. */
  891.   if (commandOptionV) printf ("Number of sectors modified = %d\n", (unixFileLength + PAGE_SIZE-1) / PAGE_SIZE);
  892.  
  893.   /* Close the DISK file */
  894.   errno = 0;
  895.   fclose (diskFile);
  896.   if (errno) {
  897.     perror ("Error on DISK file");
  898.     fatalError ("The DISK file could not be closed");
  899.   }
  900.   if (commandOptionV) printf ("The DISK file has been closed successfully.\n");
  901.  
  902.   /* Close the source file */
  903.   errno = 0;
  904.   fclose (unixFile);
  905.   if (errno) {
  906.     perror ("Error on source file");
  907.     fatalError ("The source file could not be closed");
  908.   }
  909.   if (commandOptionV) printf ("The source file has been closed successfully.\n");
  910.  
  911.   /* Return no error */
  912.   exit (0);
  913.  
  914. }
  915.  
  916.  
  917.  
  918. /* readInteger ()
  919. **
  920. ** Read an integer (4-bytes, binary) from the BLITZ DISK file and return it.
  921. */
  922. int readInteger () {
  923.   int i, numItemsRead;
  924.   errno = 0;
  925.   numItemsRead = fread (&i, 4, 1, diskFile);
  926.   if (numItemsRead != 1) {
  927.     if (errno) perror ("Error when reading from file");
  928.     fatalError ("Problem reading from file");
  929.   }
  930.   return SWAP_BYTES (i);
  931. }
  932.  
  933.  
  934.  
  935. /* writeInteger (x)
  936. **
  937. ** Write an integer (4-bytes, binary) to the BLITZ DISK file.
  938. */
  939. void writeInteger (int x) {
  940.   int i, x2;
  941.   x2 = SWAP_BYTES (x);
  942.   errno = 0;
  943.   i = fwrite (&x2, 1, 4, diskFile);
  944.   if (i != 4) {
  945.     if (errno) perror ("Error writing to BLITZ DISK file");
  946.     fatalError ("Problems writing to BLITZ DISK file");
  947.   }
  948. }
  949.  
  950.  
  951.  
  952. /* writeString (str, len)
  953. **
  954. ** Write "len" chartacters to the BLITZ DISK file.
  955. */
  956. void writeString (char * str, int len) {
  957.   int i;
  958.   while (len) {
  959.     errno = 0;
  960.     i = fwrite (str, 1, 1, diskFile);
  961.     if (i != 1) {
  962.       if (errno) perror ("Error writing to BLITZ DISK file");
  963.       fatalError ("Problems writing to BLITZ DISK file");
  964.     }
  965.     len--;
  966.     str++;
  967.   }
  968. }
  969.  
  970.  
  971.  
  972. /* readString (len) --> ptr to string
  973. **
  974. ** Read "len" chartacters from the BLITZ DISK file.  Allocate memory;
  975. ** store the characters, and return a pointer to the memory.
  976. */
  977. char * readString (int len) {
  978.   int i;
  979.   char * str = (char *) calloc (1, len+1);
  980.   char * next = str;
  981.   while (len) {
  982.     errno = 0;
  983.     i = fread (next, 1, 1, diskFile);
  984.     if (i != 1) {
  985.       if (errno) perror ("Error reading from BLITZ DISK file");
  986.       fatalError ("Problems reading from BLITZ DISK file");
  987.     }
  988.     len--;
  989.     next++;
  990.   }
  991.   *next = '\0';
  992.   return str;
  993. }
  994.  
  995.  
  996.  
  997. /* findFile (str) --> ent
  998. **
  999. ** Look in the directory info and find this file.  Return a pointer to
  1000. ** the entry, or NULL if not found.
  1001. */
  1002. Entry * findFile (char * str) {
  1003.   Entry * ent = firstEntry;
  1004.   while (ent) {
  1005.     if (0 == strcmp (ent->name, str)) {
  1006.       return ent;
  1007.     }
  1008.     ent = ent->next;
  1009.   }
  1010.   return NULL;
  1011. }
  1012.  
  1013.  
  1014.  
  1015. /* seekTo (i)
  1016. **
  1017. ** Seek to the given location on the BLITZ DISK file.
  1018. */
  1019. void seekTo (int where) {
  1020.   errno = 0;
  1021.   fseek (diskFile, (long) where, SEEK_SET);
  1022.   if (errno) {
  1023.     perror ("Error on BLITZ DISK file");
  1024.     fatalError ("The BLITZ DISK file could not be could be repositioned");
  1025.   }
  1026. }
  1027.  
  1028.  
  1029.  
  1030. /* printDirectory ()
  1031. **
  1032. ** Print the linked list of entries.
  1033. */
  1034. void printDirectory () {
  1035.   Entry * e = firstEntry;
  1036.   printf ("   StartingSector   SizeInSectors    SizeInBytes        FileName\n");
  1037.   printf ("   ==============   =============    ===========    =====================\n");
  1038.   printf ("\t0\t\t1\t\t8192\t\t< directory >\n");
  1039.   while (e) {
  1040.     printf ("\t%d\t\t%d\t\t%d\t\t%s\n",
  1041.             e->startingSector,
  1042.             (e->sizeInBytes + PAGE_SIZE-1) / PAGE_SIZE,
  1043.             e->sizeInBytes,
  1044.             // e->lengthOfName,
  1045.             e->name);
  1046.     e = e->next;
  1047.   }
  1048. }
  1049.  
  1050.  
  1051.  
  1052. /* writeDirectory ()
  1053. **
  1054. ** Print the directory back to the BLITZ DISK.
  1055. */
  1056. void writeDirectory () {
  1057.   Entry * e = firstEntry;
  1058.   seekTo (8);
  1059.   writeInteger (numberOfFiles);
  1060.   writeInteger (nextFreeSector);
  1061.   while (e) {
  1062.     // printf ("writing next entry...\n");
  1063.     // printf ("\t%d\t\t%d\t\t%d\t\t%s\n",
  1064.     //         e->startingSector,
  1065.     //         e->sizeInBytes,
  1066.     //         e->lengthOfName,
  1067.     //         e->name);
  1068.     writeInteger (e->startingSector);
  1069.     writeInteger (e->sizeInBytes);
  1070.     writeInteger (e->lengthOfName);
  1071.     writeString (e->name, e->lengthOfName);
  1072.     e = e->next;
  1073.   }
  1074. }
  1075.  
  1076.  
  1077.  
  1078. // checkHostCompatibility ()
  1079. //
  1080. // This routine checks that the host implementation of C++ meets certain
  1081. // requirements.
  1082. //
  1083. // (1) This routine checks that integers are represented using exactly 4
  1084. // bytes.
  1085. //
  1086. // (2) This routine checks that integers are stored in the expected
  1087. // Big or Little Endian order.
  1088. //
  1089. // (3) This routine checks that integer overflow behavior is as expected
  1090. // with two's complement arithmetic.
  1091. //
  1092. // (4) This routine checks that doubles are implemented using 8-bytes in
  1093. // the IEEE standard, with the bytes in correct Big/Little Endian order.
  1094. //
  1095. // (5) This routine checks that the double->int conversion works as
  1096. // expected.  If this is not the case, then truncateToInt() will need to
  1097. // be changed.
  1098. //
  1099. void checkHostCompatibility () {
  1100.   union fourBytes {
  1101.     char chars [4];
  1102.     unsigned int i;
  1103.   } fourBytes;
  1104.   double d;
  1105.   char * p, * q;
  1106.   int i, i1, i2, i3;
  1107.  
  1108.   // Check that ints are in the expected Big/Little Endian order.
  1109.   fourBytes.chars[0] = 0x12;
  1110.   fourBytes.chars[1] = 0x34;
  1111.   fourBytes.chars[2] = 0x56;
  1112.   fourBytes.chars[3] = 0x78;
  1113.   if (SWAP_BYTES(fourBytes.i) != 0x12345678) {
  1114.     fatalError ("There is a big/little endian byte ordering problem.");
  1115.   }
  1116.  
  1117.   // Check that we have at least 4 bytes of precision.
  1118.   i = 0x00000001;
  1119.   i <<= 20;
  1120.   i <<= 10;
  1121.   i >>= 20;
  1122.   i >>= 10;
  1123.   if (i != 0x00000001) {
  1124.     fatalError ("This program only runs on computers with 4 byte integers - 1");
  1125.   }
  1126.  
  1127.   // Check that we have no more than 4 bytes of precision.
  1128.   i = 0x00000001;
  1129.   i <<= 20;
  1130.   i <<= 13;   // Some compilers treat <<33 as a nop!
  1131.   i >>= 20;
  1132.   i >>= 13;
  1133.   if (i != 0x00000000) {
  1134.     fatalError ("This program only runs on computers with 4 byte integers - 2");
  1135.   }
  1136.  
  1137.   // Check that we have the expected overflow behavior for ints.
  1138.   i = -2147483647;
  1139.   i = i - 2;
  1140.   if (i != 2147483647) {
  1141.     fatalError ("This program only runs on computers with 4 byte integers - 3");
  1142.   }
  1143.  
  1144.   // Check that doubles are represented as we expect.
  1145.   d = 123.456e37;
  1146.   p = (char *) &d;
  1147.   q = p;
  1148.   // If doubles are stored in Big Endian byte order....
  1149.   if ((*p++ == '\x48') &&
  1150.       (*p++ == '\x0d') &&
  1151.       (*p++ == '\x06') &&
  1152.       (*p++ == '\x3c') &&
  1153.       (*p++ == '\xdb') &&
  1154.       (*p++ == '\x93') &&
  1155.       (*p++ == '\x27') &&
  1156.       (*p++ == '\xcf')) {
  1157. #ifdef BLITZ_HOST_IS_LITTLE_ENDIAN
  1158.     fatalError ("There is a big/little endian byte ordering problem with doubles - 1.");
  1159. #endif
  1160.  
  1161.   // Else, if doubles are stored in Little Endian byte order...
  1162.   } else if ((*q++ == '\xcf') &&
  1163.              (*q++ == '\x27') &&
  1164.              (*q++ == '\x93') &&
  1165.              (*q++ == '\xdb') &&
  1166.              (*q++ == '\x3c') &&
  1167.              (*q++ == '\x06') &&
  1168.              (*q++ == '\x0d') &&
  1169.              (*q++ == '\x48')) {
  1170. #ifdef BLITZ_HOST_IS_LITTLE_ENDIAN
  1171.  
  1172. #else
  1173.     fatalError ("There is a big/little endian byte ordering problem with doubles - 2.");
  1174. #endif
  1175.  
  1176.   // Else, if doubles are stored in some other way...
  1177.   } else {
  1178.     fatalError ("The host implementation of 'double' is not what I expect.");
  1179.   }
  1180.  
  1181.   // There is variation in the way different hosts handle double->int conversion
  1182.   // when the double is too large to represent as an integer.  When checking
  1183.   // we must do the conversion in two steps, since some compilers perform the
  1184.   // conversion at compile time, and will do the conversion differently than
  1185.   // the host machine.  Truly appalling, isn't it!
  1186.   //   On PPC,   (int) 9e99 is 0x7fffffff
  1187.   //   On PPC,   (int) d    is 0x7fffffff
  1188.   //   On Intel, (int) 9e99 is 0x7fffffff
  1189.   //   On Intel, (int) d    is 0x80000000
  1190.   //
  1191.   i = (int) 9e99;
  1192.   // printf ("(int) 9e99 is 0x%08x\n", i);
  1193.   d = 9e99;
  1194.   i = (int) d;  // Note: ((int) 9e99 == 0 while ((int) d) == 2147483647)!!!
  1195.   // printf ("(int) d is 0x%08x\n", i);
  1196.  
  1197.   // Check that double->int conversion works as expected.
  1198.   d = 4.9;
  1199.   i1 = (int) d;
  1200.   d = -4.9;
  1201.   i2 = (int) d;
  1202.   d = -9e99;
  1203.   i3 = (int) d;
  1204.   if ((i1 !=  4) ||
  1205.       (i2 != -4) ||
  1206.       (i3 != 0x80000000)) {
  1207.     printf ("%d %d %d %d\n", i1, i2, i3);
  1208.     fatalError ("The host implementation of double->int casting is not what I expect.");
  1209.   }
  1210.  
  1211. }
  1212.  
  1213.  
  1214.  
  1215. /* checkArithmetic ()
  1216. **
  1217. ** This routine checks to make sure the machine running this
  1218. ** programs implements "int" integers with 32 bit arithmetic and
  1219. ** doubles with 64 bit floating-point numbers.
  1220. */
  1221. void checkArithmetic () {
  1222.   int x;
  1223.   x = 0x00005678;
  1224.   x = x << 16;
  1225.   x = x >> 16;
  1226.   if (x != 0x00005678) {
  1227.     fatalError ("This machine does not support 32 bit integer arithmetic");
  1228.   }
  1229.   if (sizeof(int) != 4) {
  1230.     fatalError ("This machine does not support 32 bit integer arithmetic");
  1231.   }
  1232.   if (sizeof(double) != 8) {
  1233.     fatalError ("This machine does not support 64 bit double precision");
  1234.   }
  1235. }
  1236.  
  1237.  
  1238.  
  1239. /* processCommandLine (argc, argv)
  1240. **
  1241. ** This routine processes the command line options.
  1242. */
  1243. void processCommandLine (int argc, char ** argv) {
  1244.   int argCount;
  1245.   int len;
  1246.   int gotGOption = 0;
  1247.   int gotRawOption = 0;
  1248.   int gotRandOption = 0;
  1249.  
  1250.   /* Each iteration of this loop looks at the next argument.  In some
  1251.      cases (like "-o a.out") one iteration will scan two tokens. */
  1252.   for (argc--, argv++; argc > 0; argc -= argCount, argv += argCount) {
  1253.     argCount = 1;
  1254.  
  1255.     /* Scan the -h option */
  1256.     if (!strcmp (*argv, "-h")) {
  1257.       commandLineHelp ();
  1258.       exit (1);
  1259.  
  1260.     /* Scan the -d option, which should be followed by a file name */
  1261.     } else if (!strcmp (*argv, "-d")) {
  1262.       if (argc <= 1) {
  1263.         badOption ("Expecting filename after -d option");
  1264.       } else {
  1265.         argCount++;
  1266.         if (diskFileName == NULL) {
  1267.           diskFileName = *(argv+1);
  1268.         } else {
  1269.           badOption ("Invalid command line - multiple DISK files");
  1270.         }
  1271.       }
  1272.  
  1273.     /* Scan the -w option, which should be followed by a file name and an integer */
  1274.     } else if (!strcmp (*argv, "-w")) {
  1275.       if (commandOptionW) {
  1276.         badOption ("Invalid command line - multiple occurences of -w");
  1277.       } else {
  1278.         commandOptionW = 1;
  1279.         if (argc <= 1) {
  1280.           badOption ("Expecting UnixFileName after -w option");
  1281.         } else if (argc <= 2) {
  1282.           badOption ("Expecting SectorNumber after -w UnixFileName");
  1283.         } else {
  1284.           argCount++;
  1285.           argCount++;
  1286.           unixFileName = *(argv+1);
  1287.           startingSectorNumber = atoi (*(argv+2));  /* Extra chars after int ignored */
  1288.         }
  1289.       }
  1290.  
  1291.     /* Scan the -c option, which should be followed by a file name and an integer */
  1292.     } else if (!strcmp (*argv, "-c")) {
  1293.       if (commandOptionC) {
  1294.         badOption ("Invalid command line - multiple occurences of -c");
  1295.       } else {
  1296.         commandOptionC = 1;
  1297.         if (argc <= 1) {
  1298.           badOption ("Expecting BlitzFileName after -c option");
  1299.         } else if (argc <= 2) {
  1300.           badOption ("Expecting an integer (the size in bytes) after -c BlitzFileName");
  1301.         } else {
  1302.           argCount++;
  1303.           argCount++;
  1304.           blitzFileName = *(argv+1);
  1305.           sizeInBytes = atoi (*(argv+2));  /* Extra chars after int ignored */
  1306.         }
  1307.       }
  1308.  
  1309.     /* Scan the -a option, which should be followed by two file names */
  1310.     } else if (!strcmp (*argv, "-a")) {
  1311.       if (commandOptionA) {
  1312.         badOption ("Invalid command line - multiple occurences of -a");
  1313.       } else {
  1314.         commandOptionA = 1;
  1315.         if (argc <= 1) {
  1316.           badOption ("Expecting UnixFileName after -a option");
  1317.         } else if (argc <= 2) {
  1318.           badOption ("Expecting BlitzFileName after -a UnixFileName");
  1319.         } else {
  1320.           argCount++;
  1321.           argCount++;
  1322.           unixFileName = *(argv+1);
  1323.           blitzFileName = *(argv+2);
  1324.         }
  1325.       }
  1326.  
  1327.     /* Scan the -e option, which should be followed by two file names */
  1328.     } else if (!strcmp (*argv, "-e")) {
  1329.       if (commandOptionE) {
  1330.         badOption ("Invalid command line - multiple occurences of -e");
  1331.       } else {
  1332.         commandOptionE = 1;
  1333.         if (argc <= 1) {
  1334.           badOption ("Expecting BlitzFileName after -e option");
  1335.         } else if (argc <= 2) {
  1336.           badOption ("Expecting UnixFileName after -e BlitzFileName");
  1337.         } else {
  1338.           argCount++;
  1339.           argCount++;
  1340.           blitzFileName = *(argv+1);
  1341.           unixFileName = *(argv+2);
  1342.         }
  1343.       }
  1344.  
  1345.     /* Scan the -r option, which should be followed by a file name */
  1346.     } else if (!strcmp (*argv, "-r")) {
  1347.       if (commandOptionR) {
  1348.         badOption ("Invalid command line - multiple occurences of -r");
  1349.       } else {
  1350.         commandOptionR = 1;
  1351.         if (argc <= 1) {
  1352.           badOption ("Expecting FileName after -r option");
  1353.         } else {
  1354.           argCount++;
  1355.           blitzFileName = *(argv+1);
  1356.         }
  1357.       }
  1358.  
  1359.     /* Scan the -l option */
  1360.     } else if (!strcmp (*argv, "-l")) {
  1361.       if (commandOptionL) {
  1362.         badOption ("Invalid command line - multiple occurences of -l");
  1363.       } else {
  1364.         commandOptionL = 1;
  1365.       }
  1366.  
  1367.     /* Scan the -v option */
  1368.     } else if (!strcmp (*argv, "-v")) {
  1369.       if (commandOptionV) {
  1370.         badOption ("Invalid command line - multiple occurences of -v");
  1371.       } else {
  1372.         commandOptionV = 1;
  1373.       }
  1374.  
  1375.     /* Scan the -i option */
  1376.     } else if (!strcmp (*argv, "-i")) {
  1377.       if (commandOptionI) {
  1378.         badOption ("Invalid command line - multiple occurences of -i");
  1379.       } else {
  1380.         commandOptionI = 1;
  1381.       }
  1382.  
  1383.     /* Anything remaining else on the command line is invalid */
  1384.     } else {
  1385.       fprintf (
  1386.         stderr,
  1387.         "BLITZ Disk Utility Error: Invalid command line option (%s); Use -h for help display\n",
  1388.         *argv);
  1389.       exit (1);
  1390.  
  1391.     }
  1392.   }
  1393.  
  1394.   /* Figure out the name of the DISK file. */
  1395.   if (diskFileName == NULL) {
  1396.     diskFileName = "DISK";
  1397.   }
  1398.  
  1399.   /* Make sure that only one of -i, -l, -c, -r, -a, -e, -w was used. */
  1400.   if (commandOptionI +
  1401.       commandOptionL +
  1402.       commandOptionC +
  1403.       commandOptionR +
  1404.       commandOptionA +
  1405.       commandOptionE +
  1406.       commandOptionW != 1) {
  1407.     badOption ("Invalid command line - Must use exactly one of -i, -l, -c, -r, -a, -e, -w");
  1408.   }
  1409.  
  1410. }
  1411.  
  1412.  
  1413.  
  1414. /* badOption (msg)
  1415. **
  1416. ** This routine prints a message on stderr and then aborts this program.
  1417. */
  1418. void badOption (char * msg) {
  1419.   fprintf (stderr, "BLITZ Disk Utility Error: %s;  Use -h for help display\n", msg);
  1420.   exit (1);
  1421. }
  1422.  
  1423.  
  1424.  
  1425. /* fatalError (msg)
  1426. **
  1427. ** This routine prints the given error message on stderr and calls exit(1).
  1428. */
  1429. void fatalError (char * msg) {
  1430.   fprintf (stderr, "\nBLITZ Disk Utility Error: %s\n", msg);
  1431.   exit (1);
  1432. }
  1433.  
  1434.  
  1435.  
  1436. /* commandLineHelp ()
  1437. **
  1438. ** This routine prints some documentation.  It is invoked whenever
  1439. ** the -h option is used on the command line.
  1440. */
  1441. void commandLineHelp () {
  1442.   printf (
  1443. "========================================\n"
  1444. "=====                              =====\n"
  1445. "=====  The BLITZ Disk Utility      =====\n"
  1446. "=====                              =====\n"
  1447. "========================================\n"
  1448. "\n"
  1449. "Copyright 2004-2007, Harry H. Porter III\n"
  1450. "========================================\n"
  1451. "  Original Author:\n"
  1452. "    10/07/04 - Harry H. Porter III\n"
  1453. "  Modifications by:\n"
  1454. "    04/30/07 - Harry H. Porter III - Support for little endian added\n"
  1455. "\n"
  1456. "This command can be used to manipulate the BLITZ \"DISK\" file.\n"
  1457. "\n"
  1458. "The BLITZ emulator simulates the BLITZ disk using a Unix file on the host\n"
  1459. "machine.  This program allows that file to be manipulated.  For example,\n"
  1460. "it can be used to copy an executable file containing a user program to the\n"
  1461. "BLITZ disk so that the BLITZ OS kernel can then access, load, and run it.\n"
  1462. "\n"
  1463. "The BLITZ DISK is organized as follows.  The disk contains a single directory\n"
  1464. "and this is kept in sector 0.  The files are placed sequentially on the\n"
  1465. "disk, one after the other.  Each file will take up an integral number of\n"
  1466. "sectors.  Each file has an entry in the directory.  Each entry contains\n"
  1467. "     (1)  The starting sector\n"
  1468. "     (2)  The file length, in bytes (possibly zero)\n"
  1469. "     (3)  The number of characters in the file name\n"
  1470. "     (4)  The file name\n"
  1471. "The directory begins with three numbers:\n"
  1472. "     (1)  Magic Number (0x73747562 = \"stub\")\n"
  1473. "     (2)  Number of files (possibly zero)\n"
  1474. "     (3)  Number of the next free sector\n"
  1475. "These are followed by the entries for each file.\n"
  1476. "\n"
  1477. "Once created, a BLITZ file may not have its size increased.  When a file is\n"
  1478. "removed, the free sectors become unusable; there is no compaction or any\n"
  1479. "attempt to reclaim the lost space.\n"
  1480. "\n"
  1481. "Each time this program is run, it performs one of the following functions:\n"
  1482. "      Initialize  set up a new file system on the BLITZ disk\n"
  1483. "      List        list the directory on the BLITZ disk\n"
  1484. "      Create      create a new file of a given size\n"
  1485. "      Remove      remove a file\n"
  1486. "      Add         copy a file from Unix to BLITZ\n"
  1487. "      Extract     copy a file from BLITZ to Unix\n"
  1488. "      Write       write sectors from a Unix file to the BLITZ disk\n"
  1489. "\n"
  1490. "The following command line options tell which function is to be performed:\n"
  1491. "\n"
  1492. "  -h\n"
  1493. "        Print this help info.  Ignore other options and exit.\n"
  1494. "  -d DiskFileName\n"
  1495. "        The file used to emulate the BLITZ disk.  If missing, \"DISK\" will be used.\n"
  1496. "  -i\n"
  1497. "        Initialize the file system on the BLITZ \"DISK\" file.  This will\n"
  1498. "        effectively remove all files on the BLITZ disk and reclaim all available\n"
  1499. "        space.\n"
  1500. "  -l\n"
  1501. "        List the directory on the BLITZ disk.\n"
  1502. "  -c BlitzFileName SizeInBytes\n"
  1503. "        Create a file of the given size on the BLITZ disk.  The BLITZ\n"
  1504. "        disk must not already contain a file with this name.  Only the\n"
  1505. "        directory will be modified; the actual data in the file will be\n"
  1506. "        whatever bytes happened to be on the disk already.\n"
  1507. "  -r BlitzFileName\n"
  1508. "        Remove the file with the given name from the directory on the BLITZ disk.\n"
  1509. "  -a UnixFilename BlitzFileName\n"
  1510. "        Copy a file from Unix to the BLITZ disk.  If BlitzFileName already\n"
  1511. "        exists, it must be large enough to accomodate the new data.\n"
  1512. "  -e BlitzFileName UnixFileName\n"
  1513. "        Extract a file from the BLITZ disk to Unix.  This command will copy\n"
  1514. "        the data from the BLITZ disk to a Unix file.  The Unix file may or may\n"
  1515. "        not already exist; its size will be shortened or lengthened as necessary.\n"
  1516. "  -w UnixFileName SectorNumber\n"
  1517. "        The UnixFileName must be an existing Unix file. The SectorNumber is an\n"
  1518. "        integer.  The Unix file data will be  written to the BLITZ disk, starting\n"
  1519. "        at sector SectorNumber.  The directory will not be modified.\n"
  1520. "  -v\n"
  1521. "        Verbose; print lots of messages.\n"
  1522. "\n"
  1523. "Only one of -i, -l, -c, -r, -a, -e, or -w may be used at a time.\n");
  1524.  
  1525. }
  1526.