sgdisk program, misc. bug fixes
diff --git a/gpt.cc b/gpt.cc
index 7352edc..7788aa8 100644
--- a/gpt.cc
+++ b/gpt.cc
@@ -48,6 +48,8 @@
    apmFound = 0;
    bsdFound = 0;
    sectorAlignment = 8; // Align partitions on 4096-byte boundaries by default
+   beQuiet = 0;
+   whichWasUsed = use_new;
    srand((unsigned int) time(NULL));
    mainHeader.numParts = 0;
    SetGPTSize(NUM_GPT_ENTRIES);
@@ -68,6 +70,8 @@
    apmFound = 0;
    bsdFound = 0;
    sectorAlignment = 8; // Align partitions on 4096-byte boundaries by default
+   beQuiet = 0;
+   whichWasUsed = use_new;
    srand((unsigned int) time(NULL));
    mainHeader.numParts = 0;
    LoadPartitions(filename);
@@ -499,22 +503,22 @@
 // the results.
 void GPTData::PartitionScan(int fd) {
    BSDData bsdDisklabel;
-//   int bsdFound;
-
-   printf("Partition table scan:\n");
 
    // Read the MBR & check for BSD disklabel
    protectiveMBR.ReadMBRData(fd);
-   protectiveMBR.ShowState();
    bsdDisklabel.ReadBSDData(fd, 0, diskSize - 1);
-   bsdFound = bsdDisklabel.ShowState();
-//   bsdDisklabel.DisplayBSDData();
 
    // Load the GPT data, whether or not it's valid
    ForceLoadGPTData(fd);
-   ShowAPMState(); // Show whether there's an Apple Partition Map present
-   ShowGPTState(); // Show GPT status
-   printf("\n");
+
+   if (!beQuiet) {
+      printf("Partition table scan:\n");
+      protectiveMBR.ShowState();
+      bsdDisklabel.ShowState();
+      ShowAPMState(); // Show whether there's an Apple Partition Map present
+      ShowGPTState(); // Show GPT status
+      printf("\n");
+   } // if
 
    if (apmFound) {
       printf("\n*******************************************************************\n");
@@ -549,9 +553,10 @@
       blockSize = (uint32_t) GetBlockSize(fd);
       sectorAlignment = FindAlignment(fd);
       strcpy(device, deviceFilename);
-      PartitionScan(fd); // Check for partition types & print summary
+      PartitionScan(fd); // Check for partition types, load GPT, & print summary
 
-      switch (UseWhichPartitions()) {
+      whichWasUsed = UseWhichPartitions();
+      switch (whichWasUsed) {
          case use_mbr:
             XFormPartitions();
             break;
@@ -696,7 +701,7 @@
            (secondPartsCrcOk == 0)) {
          printf("Warning! One or more CRCs don't match. You should repair the disk!\n");
          state = gpt_corrupt;
-           } // if
+      } // if
    } else {
       state = gpt_invalid;
    } // if/else
@@ -763,7 +768,7 @@
 
 // Writes GPT (and protective MBR) to disk. Returns 1 on successful
 // write, 0 if there was a problem.
-int GPTData::SaveGPTData(void) {
+int GPTData::SaveGPTData(int quiet) {
    int allOK = 1;
    char answer, line[256];
    int fd;
@@ -799,7 +804,7 @@
    } // if
    // Check that second header is properly placed. Warn and ask if this should
    // be corrected if the test fails....
-   if (mainHeader.backupLBA < (diskSize - UINT64_C(1))) {
+   if ((mainHeader.backupLBA < (diskSize - UINT64_C(1))) && (quiet == 0)) {
       printf("Warning! Secondary header is placed too early on the disk! Do you want to\n"
              "correct this problem? ");
       if (GetYN() == 'Y') {
@@ -833,7 +838,7 @@
    } // if
    RecomputeCRCs();
 
-   if (allOK) {
+   if ((allOK) && (!quiet)) {
       printf("\nFinal checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING\n");
       printf("MBR PARTITIONS!! THIS PROGRAM IS BETA QUALITY AT BEST. IF YOU LOSE ALL YOUR\n");
       printf("DATA, YOU HAVE ONLY YOURSELF TO BLAME IF YOU ANSWER 'Y' BELOW!\n\n");
@@ -1251,36 +1256,24 @@
       } while (IsFree(sector) == 0);
       lastBlock = sector;
 
-      partitions[partNum].SetFirstLBA(firstBlock);
-      partitions[partNum].SetLastLBA(lastBlock);
-
-      partitions[partNum].SetUniqueGUID(1);
+      firstFreePart = CreatePartition(partNum, firstBlock, lastBlock);
       partitions[partNum].ChangeType();
       partitions[partNum].SetName((unsigned char*) partitions[partNum].GetNameType(prompt));
-         } else {
-            printf("No free sectors available\n");
-         } // if/else
+   } else {
+      printf("No free sectors available\n");
+   } // if/else
 } // GPTData::CreatePartition()
 
 // Interactively delete a partition (duh!)
 void GPTData::DeletePartition(void) {
    int partNum;
    uint32_t low, high;
-   uint64_t startSector, length;
    char prompt[255];
 
    if (GetPartRange(&low, &high) > 0) {
       sprintf(prompt, "Partition number (%d-%d): ", low + 1, high + 1);
       partNum = GetNumber(low + 1, high + 1, low, prompt);
-
-      // In case there's a protective MBR, look for & delete matching
-      // MBR partition....
-      startSector = partitions[partNum - 1].GetFirstLBA();
-      length = partitions[partNum - 1].GetLengthLBA();
-      protectiveMBR.DeleteByLocation(startSector, length);
-
-      // Now delete the GPT partition
-      partitions[partNum - 1].BlankPartition();
+      DeletePartition(partNum - 1);
    } else {
       printf("No partitions\n");
    } // if/else
@@ -1315,6 +1308,8 @@
 // user confirms destruction, 0 if the user aborts.
 // If prompt == 0, don't ask user about proceeding and do NOT wipe out
 // MBR. (Set prompt == 0 when doing a GPT-to-MBR conversion.)
+// If prompt == -1, don't ask user about proceeding and DO wipe out
+// MBR.
 int GPTData::DestroyGPT(int prompt) {
    int fd, i, sum, tableSize;
    char blankSector[512], goOn = 'Y', blank = 'N';
@@ -1324,11 +1319,11 @@
       blankSector[i] = '\0';
    } // for
 
-   if (((apmFound) || (bsdFound)) && prompt) {
+   if (((apmFound) || (bsdFound)) && (prompt > 0)) {
       printf("WARNING: APM or BSD disklabel structures detected! This operation could\n"
              "damage any APM or BSD partitions on this disk!\n");
    } // if APM or BSD
-   if (prompt) {
+   if (prompt > 0) {
       printf("\a\aAbout to wipe out GPT on %s. Proceed? ", device);
       goOn = GetYN();
    } // if
@@ -1361,16 +1356,16 @@
          if (myWrite(fd, blankSector, 512) != 512) { // blank it out
             fprintf(stderr, "Warning! GPT backup header not overwritten! Error is %d\n", errno);
          } // if
-         if (prompt) {
+         if (prompt > 0) {
             printf("Blank out MBR? ");
             blank = GetYN();
-         }// if
+         } // if
          // Note on below: Touch the MBR only if the user wants it completely
          // blanked out. Version 0.4.2 deleted the 0xEE partition and re-wrote
          // the MBR, but this could wipe out a valid MBR that the program
          // had subsequently discarded (say, if it conflicted with older GPT
          // structures).
-         if (blank == 'Y') {
+         if ((blank == 'Y') || (prompt < 0)) {
             lseek64(fd, 0, SEEK_SET);
             if (myWrite(fd, blankSector, 512) != 512) { // blank it out
                fprintf(stderr, "Warning! MBR not overwritten! Error is %d!\n", errno);
@@ -1681,6 +1676,7 @@
       printf("\nCreating entry for partition #%d\n", j + 1);
       numConverted += OnePartToMBR(j, i);
    } // for
+   printf("MBR writing returned %d\n", protectiveMBR.WriteMBRData(device));
    return numConverted;
 } // GPTData::XFormToMBR()
 
@@ -1774,7 +1770,8 @@
  **********************************************************************/
 
 // Resizes GPT to specified number of entries. Creates a new table if
-// necessary, copies data if it already exists.
+// necessary, copies data if it already exists. Returns 1 if all goes
+// well, 0 if an error is encountered.
 int GPTData::SetGPTSize(uint32_t numEntries) {
    struct GPTPart* newParts;
    struct GPTPart* trash;
@@ -1844,6 +1841,51 @@
    } // for
 } // GPTData::BlankPartitions()
 
+// Delete a partition by number. Returns 1 if successful,
+// 0 if there was a problem. Returns 1 if partition was in
+// range, 0 if it was out of range.
+int GPTData::DeletePartition(uint32_t partNum) {
+   uint64_t startSector, length;
+   uint32_t low, high, numParts, retval = 1;;
+
+   numParts = GetPartRange(&low, &high);
+   if ((numParts > 0) && (partNum >= low) && (partNum <= high)) {
+      // In case there's a protective MBR, look for & delete matching
+      // MBR partition....
+      startSector = partitions[partNum].GetFirstLBA();
+      length = partitions[partNum].GetLengthLBA();
+      protectiveMBR.DeleteByLocation(startSector, length);
+
+      // Now delete the GPT partition
+      partitions[partNum].BlankPartition();
+   } else {
+      fprintf(stderr, "Partition number %d out of range!\n", partNum + 1);
+      retval = 0;
+   } // if/else
+   return retval;
+} // GPTData::DeletePartition(uint32_t partNum)
+
+// Non-interactively create a partition. Note that this function is overloaded
+// with another of the same name but different parameters; that one prompts
+// the user for data. This one returns 1 if the operation was successful, 0
+// if a problem was discovered.
+int GPTData::CreatePartition(uint32_t partNum, uint64_t startSector, uint64_t endSector) {
+   int retval = 1; // assume there'll be no problems
+
+   if (IsFreePartNum(partNum)) {
+      Align(&startSector); // Align sector to correct multiple
+      if (IsFree(startSector) && (startSector <= endSector)) {
+         if (FindLastInFree(startSector) >= endSector) {
+            partitions[partNum].SetFirstLBA(startSector);
+            partitions[partNum].SetLastLBA(endSector);
+            partitions[partNum].SetType(0x0700);
+            partitions[partNum].SetUniqueGUID(1);
+         } else retval = 0; // if free space until endSector
+      } else retval = 0; // if startSector is free
+   } else retval = 0; // if legal partition number
+   return retval;
+} // GPTData::CreatePartition(partNum, startSector, endSector)
+
 // Sort the GPT entries, eliminating gaps and making for a logical
 // ordering. Relies on QuickSortGPT() for the bulk of the work
 void GPTData::SortGPT(void) {
@@ -1934,10 +1976,13 @@
    secondHeader.partitionEntriesLBA = secondHeader.lastUsableLBA + UINT64_C(1);
 } // GPTData::FixSecondHeaderLocation()
 
-void GPTData::SetName(uint32_t partNum, char* theName) {
-   if ((partNum >= 0) && (partNum < mainHeader.numParts))
-      if (partitions[partNum].GetFirstLBA() > 0)
-         partitions[partNum].SetName((unsigned char*) theName);
+int GPTData::SetName(uint32_t partNum, char* theName) {
+   int retval = 1;
+   if (!IsFreePartNum(partNum))
+      partitions[partNum].SetName((unsigned char*) theName);
+   else retval = 0;
+
+   return retval;
 } // GPTData::SetName
 
 // Set the disk GUID to the specified value. Note that the header CRCs must
@@ -1962,6 +2007,17 @@
    return retval;
 } // GPTData::SetPartitionGUID()
 
+// Change partition type code non-interactively. Returns 1 if
+// successful, 0 if not....
+int GPTData::ChangePartType(uint32_t partNum, uint16_t hexCode) {
+   int retval = 1;
+
+   if (!IsFreePartNum(partNum)) {
+      partitions[partNum].SetType(hexCode);
+   } else retval = 0;
+   return retval;
+} // GPTData::ChangePartType()
+
 // Adjust sector number so that it falls on a sector boundary that's a
 // multiple of sectorAlignment. This is done to improve the performance
 // of Western Digital Advanced Format disks and disks with similar
@@ -2015,8 +2071,10 @@
       // Otherwise, notify the user that it couldn't be done....
       if (sectorOK == 1) {
          printf("Information: Moved requested sector from %llu to %llu for\n"
-                "alignment purposes. Use 'l' on the experts' menu to adjust alignment.\n",
+                "alignment purposes.\n",
                 (unsigned long long) original, (unsigned long long) *sector);
+         if (!beQuiet)
+            printf("Use 'l' on the experts' menu to adjust alignment\n");
       } else {
          printf("Information: Sector not aligned on %d-sector boundary and could not be moved.\n"
                 "If you're using a Western Digital Advanced Format or similar disk with\n"
@@ -2227,6 +2285,20 @@
         return (isFree);
 } // GPTData::IsFree()
 
+// Returns 1 if partNum is unused.
+int GPTData::IsFreePartNum(uint32_t partNum) {
+   int retval = 1;
+
+   if ((partNum >= 0) && (partNum < mainHeader.numParts)) {
+      if ((partitions[partNum].GetFirstLBA() != UINT64_C(0)) ||
+          (partitions[partNum].GetLastLBA() != UINT64_C(0))) {
+         retval = 0;
+      } // if partition is in use
+   } else retval = 0;
+
+   return retval;
+} // GPTData::IsFreePartNum()
+
 /********************************
  *                              *
  * Endianness support functions *