Version 0.6.12 release; mostly changes in support for disks with other
than 512-byte sectors.
diff --git a/NEWS b/NEWS
index a2afa17..f941e24 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,26 @@
+0.6.12 (10/7/2010):
+-------------------
+
+- Adjusted alignment code to use 1 MiB alignment by default for drives with
+  other than 512-byte sector sizes. (Previous versions increased this --
+  for instance, to 4 MiB for drives with 2048-byte logical sector size.)
+
+- Entry of non-hexadecimal value for partition type code now causes
+  re-prompting for a new value, fixing a recently-introduced minor bug.
+
+- Fixed bug in sector entry using K/M/G/T/P suffixes on disks with
+  other-than-512-byte sector numbers.
+
+- Added "P" (PiB, pebibyte) suffix to suffixes accepted in entering
+  partition sizes.
+
+- Fixed bug that caused sgdisk to segfault if fed the (invalid)
+  "-A show" parameter. Now it terminates with a complaint about an invalid
+  partition number 0.
+
+- Removed warning when running on big-endian hardware, since this
+  support has been present for quite a while with no bug reports.
+
 0.6.11 (9/25/2010):
 -------------------
 
diff --git a/attributes.cc b/attributes.cc
index f068e6d..07f909a 100644
--- a/attributes.cc
+++ b/attributes.cc
@@ -19,11 +19,33 @@
 using namespace std;
 
 string Attributes::atNames[NUM_ATR];
-Attributes::staticInit Attributes::staticInitializer;
+int Attributes::numAttrs = 0;
+//Attributes::staticInit Attributes::staticInitializer;
 
-Attributes::staticInit::staticInit (void) {
+// Default constructor
+Attributes::Attributes(void) {
+   numAttrs++;
+   if (numAttrs == 1)
+      Setup();
+   attributes = 0;
+} // constructor
+
+// Alternate constructor
+Attributes::Attributes(const uint64_t a) {
+   numAttrs++;
+   if (numAttrs == 1)
+      Setup();
+   attributes = a;
+} // alternate constructor
+
+// Destructor.
+Attributes::~Attributes(void) {
+   numAttrs--;
+} // Attributes destructor
+
+void Attributes::Setup(void) {
    ostringstream temp;
- 
+
    // Most bits are undefined, so start by giving them an
    // appropriate name
    for (int i = 0; i < NUM_ATR; i++) {
@@ -33,17 +55,13 @@
    } // for
 
    // Now reset those names that are defined....
-   Attributes::atNames[0] = "system partition"; // required for computer to operate
-   Attributes::atNames[1] = "hide from EFI";
-   Attributes::atNames[2] = "legacy BIOS bootable";
-   Attributes::atNames[60] = "read-only";
-   Attributes::atNames[62] = "hidden";
-   Attributes::atNames[63] = "do not automount";
-}  // Attributes::staticInit::staticInit
-
-// Destructor.
-Attributes::~Attributes(void) {
-} // Attributes destructor
+   atNames[0] = "system partition"; // required for computer to operate
+   atNames[1] = "hide from EFI";
+   atNames[2] = "legacy BIOS bootable";
+   atNames[60] = "read-only";
+   atNames[62] = "hidden";
+   atNames[63] = "do not automount";
+}  // Attributes::Setup()
 
 // Display current attributes to user
 void Attributes::DisplayAttributes(void) {
@@ -57,7 +75,7 @@
    cout << hex << attributes << dec << ". Set fields are:\n";
    for (i = 0; i < NUM_ATR; i++) {
       if ((UINT64_C(1) << i) & attributes) {
-         cout << i << " (" << Attributes::GetAttributeName(i) << ")" << "\n";
+         cout << i << " (" << GetAttributeName(i) << ")" << "\n";
          numSet++;
       } // if
    } // for
@@ -67,6 +85,21 @@
    cout << "\n";
 } // Attributes::DisplayAttributes()
 
+// Display attributes for a partition. Note that partNum is just passed for
+// immediate display; it's not used to access a particular partition.
+void Attributes::ShowAttributes(const uint32_t partNum) {
+   uint32_t bitNum;
+   bool bitset;
+
+   for (bitNum = 0; bitNum < 64; bitNum++) {
+      bitset = (UINT64_C(1) << bitNum) & attributes;
+      if (bitset) {
+         cout << partNum+1 << ":" << bitNum << ":" << bitset
+         << " (" << GetAttributeName(bitNum) << ")" << endl;
+      } // if
+   } // for
+} // Attributes::ShowAttributes
+
 // Prompt user for attribute changes
 void Attributes::ChangeAttributes(void) {
    int response;
@@ -78,7 +111,8 @@
 
    do {
       DisplayAttributes();
-      response = GetNumber(0, NUM_ATR, -1, "Toggle which attribute field (0-63, 64 to exit): ");
+      response = GetNumber(0, NUM_ATR, 64,
+                           "Toggle which attribute field (0-63, 64 or <Enter> to exit): ");
       if (response != 64) {
          bitValue = UINT64_C(1) << response; // Find the integer value of the bit
          if (bitValue & attributes) { // bit is set
@@ -104,19 +138,6 @@
    } // for
 } // Attributes::ListAttributes
 
-void Attributes::ShowAttributes(const uint32_t partNum) {
-   uint32_t bitNum;
-   bool bitset;
-
-   for (bitNum = 0; bitNum < 64; bitNum++) {
-      bitset = (UINT64_C(1) << bitNum) & attributes;
-      if (bitset) {
-         cout << partNum+1 << ":" << bitNum << ":" << bitset
-              << " (" << Attributes::GetAttributeName(bitNum) << ")" << endl;
-      } // if
-   } // for
-} // Attributes::ShowAttributes
-
 // multifaceted attributes access
 // returns true upon success, false upon failure
 bool Attributes::OperateOnAttributes(const uint32_t partNum, const string& attributeOperator, const string& attributeBits) {
@@ -190,3 +211,15 @@
 
    return true;
 } // Attributes::OperateOnAttributes()
+
+/*******************************
+*                             *
+* Non-class support functions *
+*                             *
+*******************************/
+
+// Display attributes
+ostream & operator<<(ostream & os, const Attributes & data) {
+   os << data.GetAttributes();
+   return os;
+} // operator<<()
\ No newline at end of file
diff --git a/attributes.h b/attributes.h
index 34cf258..0ae4487 100644
--- a/attributes.h
+++ b/attributes.h
@@ -13,27 +13,29 @@
 using namespace std;
 
 class Attributes {
-
-private:
-   class staticInit {public: staticInit (void);};
-   static string atNames[NUM_ATR];
-   static Attributes::staticInit staticInitializer;
-
 protected:
+   static string atNames[NUM_ATR];
+   static int numAttrs;
+   void Setup(void);
    uint64_t attributes;
 
 public:
-   Attributes(const uint64_t a = 0) {SetAttributes (a);}
+   Attributes(void);
+   Attributes(const uint64_t a);
    ~Attributes(void);
-   void SetAttributes(const uint64_t a) {attributes = a;}
-   uint64_t GetAttributes(void) {return attributes;}
+   void operator=(uint64_t a) {attributes = a;}
+
+   uint64_t GetAttributes(void) const {return attributes;}
    void DisplayAttributes(void);
-   void ChangeAttributes(void);
    void ShowAttributes(const uint32_t partNum);
+
+   void ChangeAttributes(void);
    bool OperateOnAttributes(const uint32_t partNum, const string& attributeOperator, const string& attributeBits);
 
    static const string& GetAttributeName(const uint32_t bitNum) {return atNames [bitNum];}
    static void ListAttributes(void);
 }; // class Attributes
 
+ostream & operator<<(ostream & os, const Attributes & data);
+
 #endif
diff --git a/current.spec b/current.spec
index 6aed76f..650c167 100644
--- a/current.spec
+++ b/current.spec
@@ -1,11 +1,11 @@
 Summary: An fdisk-like partitioning tool for GPT disks
 Name: gdisk
-Version: 0.6.11
+Version: 0.6.12
 Release: 1%{?dist}
 License: GPLv2
 URL: http://www.rodsbooks.com/gdisk
 Group: Applications/System
-Source: http://www.rodsbooks.com/gdisk/gdisk-0.6.11.tgz
+Source: http://www.rodsbooks.com/gdisk/gdisk-0.6.12.tgz
 BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
 
 %description
@@ -40,5 +40,5 @@
 %doc %{_mandir}/man8*
 
 %changelog
-* Sat Sep 25 2010 R Smith <rodsmith@rodsbooks.com> - 0.6.11
-- Created spec file for 0.6.11 release
+* Thu Oct 7 2010 R Smith <rodsmith@rodsbooks.com> - 0.6.12
+- Created spec file for 0.6.12 release
diff --git a/gdisk.8 b/gdisk.8
index cab2654..7409f68 100644
--- a/gdisk.8
+++ b/gdisk.8
@@ -1,6 +1,6 @@
 .\" Copyright 2010 Roderick W. Smith (rodsmith@rodsbooks.com)
 .\" May be distributed under the GNU General Public License
-.TH "GDISK" "8" "0.6.11" "Roderick W. Smith" "GPT fdisk Manual"
+.TH "GDISK" "8" "0.6.12" "Roderick W. Smith" "GPT fdisk Manual"
 .SH "NAME"
 gdisk \- Interactive GUID partition table (GPT) manipulator
 .SH "SYNOPSIS"
@@ -197,15 +197,16 @@
 \fBfdisk\fR option, although some differences exist. You enter a partition
 number, starting sector, and an ending sector. Both start and end sectors
 can be specified in absolute terms as sector numbers or as positions
-measured in kilobytes (K), megabytes (M), gigabytes (G), or terabytes (T);
-for instance, \fI\fB40M\fR\fR specifies a position 40MiB from the start of
-the disk. You can specify locations relative to the start or end of the
-specified default range by preceding the number by a '+' or '\-' symbol, as
-in \fI\fB+2G\fR\fR to specify a point 2GiB after the default start sector,
-or \fI\fB\-200M\fR\fR to specify a point 200MiB before the last available
-sector. Pressing the Enter key with no input specifies the default value,
-which is the start of the largest available block for the start sector and
-the end of the same block for the end sector.
+measured in kibibytes (K), mebibytes (M), gibibytes (G), tebibytes (T), or
+pebibytes (P); for instance, \fI\fB40M\fR\fR specifies a position 40MiB
+from the start of the disk. You can specify locations relative to the start
+or end of the specified default range by preceding the number by a '+' or
+'\-' symbol, as in \fI\fB+2G\fR\fR to specify a point 2GiB after the
+default start sector, or \fI\fB\-200M\fR\fR to specify a point 200MiB
+before the last available sector. Pressing the Enter key with no input
+specifies the default value, which is the start of the largest available
+block for the start sector and the end of the same block for the end
+sector.
 
 .TP 
 .B o
diff --git a/gpt.cc b/gpt.cc
index be3373d..3c9b843 100644
--- a/gpt.cc
+++ b/gpt.cc
@@ -58,7 +58,7 @@
    secondPartsCrcOk = 0;
    apmFound = 0;
    bsdFound = 0;
-   sectorAlignment = 8; // Align partitions on 4096-byte boundaries by default
+   sectorAlignment = MIN_AF_ALIGNMENT; // Align partitions on 4096-byte boundaries by default
    beQuiet = 0;
    whichWasUsed = use_new;
    srand((unsigned int) time(NULL));
@@ -81,7 +81,7 @@
    secondPartsCrcOk = 0;
    apmFound = 0;
    bsdFound = 0;
-   sectorAlignment = 8; // Align partitions on 4096-byte boundaries by default
+   sectorAlignment = MIN_AF_ALIGNMENT; // Align partitions on 4096-byte boundaries by default
    beQuiet = 0;
    whichWasUsed = use_new;
    srand((unsigned int) time(NULL));
@@ -248,9 +248,9 @@
    if (problems == 0) {
       totalFree = FindFreeBlocks(&numSegments, &largestSegment);
       cout << "No problems found. " << totalFree << " free sectors ("
-           << BytesToSI(totalFree * (uint64_t) blockSize) << ") available in "
+           << BytesToSI(totalFree, blockSize) << ") available in "
            << numSegments << "\nsegments, the largest of which is "
-           << largestSegment << " (" << BytesToSI(largestSegment * (uint64_t) blockSize)
+           << largestSegment << " (" << BytesToSI(largestSegment, blockSize)
            << ") in size.\n";
    } else {
       cout << "\nIdentified " << problems << " problems!\n";
@@ -551,7 +551,7 @@
       } // if
       if (partitions[i].GetLastLBA() >= diskSize) {
          problems++;
-      cout << "\nProblem: partition " << i + 1<< " is too big for the disk.\n";
+      cout << "\nProblem: partition " << i + 1 << " is too big for the disk.\n";
       } // if
    } // for
    return problems;
@@ -876,11 +876,10 @@
    int allOK = 1, littleEndian;
    char answer;
 
-   if (filename == "")
-      filename = device;
-
    littleEndian = IsLittleEndian();
 
+   if (filename == "")
+      filename = device;
    if (filename == "") {
       cerr << "Device not defined.\n";
    } // if
@@ -1113,16 +1112,12 @@
       if ((val = CheckHeaderValidity()) > 0) {
          if (val == 2) { // only backup header seems to be good
             SetGPTSize(secondHeader.numParts);
-//            numParts = secondHeader.numParts;
             sizeOfEntries = secondHeader.sizeOfPartitionEntries;
          } else { // main header is OK
             SetGPTSize(mainHeader.numParts);
-//            numParts = mainHeader.numParts;
             sizeOfEntries = mainHeader.sizeOfPartitionEntries;
          } // if/else
 
-//         SetGPTSize(numParts);
-
          if (secondHeader.currentLBA != diskSize - UINT64_C(1)) {
             cout << "Warning! Current disk size doesn't match that of the backup!\n"
                  << "Adjusting sizes to match, but subsequent problems are possible!\n";
@@ -1266,7 +1261,7 @@
    uint64_t temp, totalFree;
 
    cout << "Disk " << device << ": " << diskSize << " sectors, "
-        << BytesToSI(diskSize * blockSize) << "\n";
+        << BytesToSI(diskSize, blockSize) << "\n";
    cout << "Logical sector size: " << blockSize << " bytes\n";
    cout << "Disk identifier (GUID): " << mainHeader.diskGUID << "\n";
    cout << "Partition table holds up to " << numParts << " entries\n";
@@ -1275,7 +1270,7 @@
    totalFree = FindFreeBlocks(&i, &temp);
    cout << "Partitions will be aligned on " << sectorAlignment << "-sector boundaries\n";
    cout << "Total free space is " << totalFree << " sectors ("
-        << BytesToSI(totalFree * (uint64_t) blockSize) << ")\n";
+        << BytesToSI(totalFree, blockSize) << ")\n";
    cout << "\nNumber  Start (sector)    End (sector)  Size       Code  Name\n";
    for (i = 0; i < numParts; i++) {
       partitions[i].ShowSummary(i, blockSize);
@@ -1284,7 +1279,7 @@
 
 // Show detailed information on the specified partition
 void GPTData::ShowPartDetails(uint32_t partNum) {
-   if (partitions[partNum].GetFirstLBA() != 0) {
+   if (!IsFreePartNum(partNum)) {
       partitions[partNum].ShowDetails(blockSize);
    } else {
       cout << "Partition #" << partNum + 1 << " does not exist.";
@@ -1780,7 +1775,10 @@
    for (i = 0; i < GPT_RESERVED; i++) {
       mainHeader.reserved2[i] = '\0';
    } // for
-   sectorAlignment = DEFAULT_ALIGNMENT;
+   if (blockSize > 0)
+      sectorAlignment = DEFAULT_ALIGNMENT * SECTOR_SIZE / blockSize;
+   else
+      sectorAlignment = DEFAULT_ALIGNMENT;
 
    // Now some semi-static items (computed based on end of disk)
    mainHeader.backupLBA = diskSize - UINT64_C(1);
@@ -2174,31 +2172,37 @@
 // Set partition alignment value; partitions will begin on multiples of
 // the specified value
 void GPTData::SetAlignment(uint32_t n) {
-   sectorAlignment = n;
+   if (n > 0)
+      sectorAlignment = n;
+   else
+      cerr << "Attempt to set partition alignment to 0!\n";
 } // GPTData::SetAlignment()
 
 // Compute sector alignment based on the current partitions (if any). Each
 // partition's starting LBA is examined, and if it's divisible by a power-of-2
-// value less than or equal to the DEFAULT_ALIGNMENT value, but not by the
-// previously-located alignment value, then the alignment value is adjusted
-// down. If the computed alignment is less than 8 and the disk is bigger than
-// SMALLEST_ADVANCED_FORMAT, resets it to 8. This is a safety measure for WD
-// Advanced Format and similar drives. If no partitions are defined, the
-// alignment value is set to DEFAULT_ALIGNMENT (2048). The result is that new
+// value less than or equal to the DEFAULT_ALIGNMENT value (adjusted for the
+// sector size), but not by the previously-located alignment value, then the
+// alignment value is adjusted down. If the computed alignment is less than 8
+// and the disk is bigger than SMALLEST_ADVANCED_FORMAT, resets it to 8. This
+// is a safety measure for WD Advanced Format and similar drives. If no partitions
+// are defined, the alignment value is set to DEFAULT_ALIGNMENT (2048) (or an
+// adjustment of that based on the current sector size). The result is that new
 // drives are aligned to 2048-sector multiples but the program won't complain
 // about other alignments on existing disks unless a smaller-than-8 alignment
-// is used on small disks (as safety for WD Advanced Format drives).
+// is used on big disks (as safety for WD Advanced Format drives).
 // Returns the computed alignment value.
 uint32_t GPTData::ComputeAlignment(void) {
    uint32_t i = 0, found, exponent = 31;
    uint32_t align = DEFAULT_ALIGNMENT;
 
-   exponent = (uint32_t) log2(DEFAULT_ALIGNMENT);
+   if (blockSize > 0)
+      align = DEFAULT_ALIGNMENT * SECTOR_SIZE / blockSize;
+   exponent = (uint32_t) log2(align);
    for (i = 0; i < numParts; i++) {
       if (partitions[i].IsUsed()) {
          found = 0;
          while (!found) {
-            align = UINT64_C(1)<<exponent;
+            align = UINT64_C(1) << exponent;
             if ((partitions[i].GetFirstLBA() % align) == 0) {
                found = 1;
             } else {
@@ -2207,9 +2211,9 @@
          } // while
       } // if
    } // for
-   if ((align < 8) && (diskSize >= SMALLEST_ADVANCED_FORMAT))
-      align = 8;
-   SetAlignment(align);
+   if ((align < MIN_AF_ALIGNMENT) && (diskSize >= SMALLEST_ADVANCED_FORMAT))
+      align = MIN_AF_ALIGNMENT;
+   sectorAlignment = align;
    return align;
 } // GPTData::ComputeAlignment()
 
@@ -2296,14 +2300,12 @@
 
 // Show all attributes for a specified partition....
 void GPTData::ShowAttributes(const uint32_t partNum) {
-   Attributes theAttr (partitions[partNum].GetAttributes());
-   theAttr.ShowAttributes(partNum);
+   partitions[partNum].ShowAttributes(partNum);
 } // GPTData::ShowAttributes
 
 // Show whether a single attribute bit is set (terse output)...
 void GPTData::GetAttribute(const uint32_t partNum, const string& attributeBits) {
-   Attributes theAttr (partitions[partNum].GetAttributes());
-   theAttr.OperateOnAttributes(partNum, "get", attributeBits);
+   partitions[partNum].GetAttributes().OperateOnAttributes(partNum, "get", attributeBits);
 } // GPTData::GetAttribute
 
 
@@ -2361,10 +2363,10 @@
       allOK = 0;
    } // if
    // Determine endianness; warn user if running on big-endian (PowerPC, etc.) hardware
-   if (IsLittleEndian() == 0) {
-      cerr << "\aRunning on big-endian hardware. Big-endian support is new and poorly"
-            " tested!\n";
-   } // if
+//   if (IsLittleEndian() == 0) {
+//      cerr << "\aRunning on big-endian hardware. Big-endian support is new and poorly"
+//            " tested!\n";
+//   } // if
    return (allOK);
 } // SizesOK()
 
diff --git a/gpt.h b/gpt.h
index d23801f..9820cae 100644
--- a/gpt.h
+++ b/gpt.h
@@ -16,7 +16,7 @@
 #ifndef __GPTSTRUCTS
 #define __GPTSTRUCTS
 
-#define GPTFDISK_VERSION "0.6.11"
+#define GPTFDISK_VERSION "0.6.12"
 
 // Constants used by GPTData::PartsToMBR(). MBR_EMPTY must be the lowest-
 // numbered value to refer to partition numbers. (Most will be 0 or positive,
@@ -27,11 +27,10 @@
 // Default values for sector alignment
 #define DEFAULT_ALIGNMENT 2048
 #define MAX_ALIGNMENT 65536
+#define MIN_AF_ALIGNMENT 8
 
-// Below constant corresponds to an 800GB disk -- a somewhat arbitrary
-// cutoff
-//#define SMALLEST_ADVANCED_FORMAT UINT64_C(1677721600)
-// Now ~596GiB (640MB), since WD has introduced a smaller Advanced Format drive
+// Below constant corresponds to a ~596GiB (640MB) disk, since WD has
+// introduced a smaller Advanced Format drive
 #define SMALLEST_ADVANCED_FORMAT UINT64_C(1250263728)
 
 using namespace std;
@@ -90,7 +89,7 @@
    int secondPartsCrcOk;
    int apmFound; // set to 1 if APM detected
    int bsdFound; // set to 1 if BSD disklabel detected in MBR
-   uint32_t sectorAlignment; // Start & end partitions at multiples of sectorAlignment
+   uint32_t sectorAlignment; // Start partitions at multiples of sectorAlignment
    int beQuiet;
    WhichToUse whichWasUsed;
 
diff --git a/gptpart.cc b/gptpart.cc
index 7be3740..2af5db7 100644
--- a/gptpart.cc
+++ b/gptpart.cc
@@ -150,7 +150,7 @@
    int i;
 
    if (firstLBA != 0) {
-      sizeInSI = BytesToSI(blockSize * (lastLBA - firstLBA + 1));
+      sizeInSI = BytesToSI(lastLBA - firstLBA + 1, blockSize);
       cout.fill(' ');
       cout.width(4);
       cout << partNum + 1 << "  ";
@@ -158,7 +158,7 @@
       cout << firstLBA << "  ";
       cout.width(14);
       cout << lastLBA  << "   ";
-      cout << BytesToSI(blockSize * (lastLBA - firstLBA + 1)) << "  ";
+      cout << BytesToSI(lastLBA - firstLBA + 1, blockSize) << "  ";
       for (i = 0; i < 10 - (int) sizeInSI.length(); i++)
          cout << " ";
       cout.fill('0');
@@ -182,12 +182,12 @@
       cout << "Partition unique GUID: " << uniqueGUID << "\n";
 
       cout << "First sector: " << firstLBA << " (at "
-            << BytesToSI(firstLBA * blockSize) << ")\n";
+            << BytesToSI(firstLBA, blockSize) << ")\n";
       cout << "Last sector: " << lastLBA << " (at "
-            << BytesToSI(lastLBA * blockSize) << ")\n";
+            << BytesToSI(lastLBA, blockSize) << ")\n";
       size = (lastLBA - firstLBA + 1);
       cout << "Partition size: " << size << " sectors ("
-            << BytesToSI(size * ((uint64_t) blockSize)) << ")\n";
+            << BytesToSI(size, blockSize) << ")\n";
       cout << "Attribute flags: ";
       cout.fill('0');
       cout.width(16);
diff --git a/gptpart.h b/gptpart.h
index 7ed6702..25da6df 100644
--- a/gptpart.h
+++ b/gptpart.h
@@ -21,6 +21,7 @@
 #include "support.h"
 #include "parttypes.h"
 #include "guid.h"
+#include "attributes.h"
 
 using namespace std;
 
@@ -43,7 +44,8 @@
       GUIDData uniqueGUID;
       uint64_t firstLBA;
       uint64_t lastLBA;
-      uint64_t attributes;
+      Attributes attributes;
+//      uint64_t attributes;
       unsigned char name[NAME_SIZE];
    public:
       GPTPart(void);
@@ -57,7 +59,8 @@
       uint64_t GetFirstLBA(void) const {return firstLBA;}
       uint64_t GetLastLBA(void) const {return lastLBA;}
       uint64_t GetLengthLBA(void);
-      uint64_t GetAttributes(void) {return attributes;}
+      Attributes GetAttributes(void) {return attributes;}
+      void ShowAttributes(uint32_t partNum) {attributes.ShowAttributes(partNum);}
       string GetDescription(void);
       int IsUsed(void);
 
@@ -69,6 +72,7 @@
       void SetFirstLBA(uint64_t f) {firstLBA = f;}
       void SetLastLBA(uint64_t l) {lastLBA = l;}
       void SetAttributes(uint64_t a) {attributes = a;}
+      void SetAttributes(void) {attributes.ChangeAttributes();}
       void SetName(const string & n);
       void SetDefaultDescription(void);
 
diff --git a/gpttext.cc b/gpttext.cc
index b9039d3..69c2a6c 100644
--- a/gpttext.cc
+++ b/gpttext.cc
@@ -207,9 +207,9 @@
 
       // Get first block for new partition...
       prompt2 << "First sector (" << firstBlock << "-" << lastBlock << ", default = "
-              << firstInLargest << ") or {+-}size{KMGT}: ";
+              << firstInLargest << ") or {+-}size{KMGTP}: ";
       do {
-         sector = GetSectorNum(firstBlock, lastBlock, firstInLargest, prompt2.str());
+         sector = GetSectorNum(firstBlock, lastBlock, firstInLargest, blockSize, prompt2.str());
       } while (IsFree(sector) == 0);
       origSector = sector;
       if (Align(&sector)) {
@@ -225,9 +225,9 @@
       // Get last block for new partitions...
       lastBlock = FindLastInFree(firstBlock);
       prompt3 << "Last sector (" << firstBlock << "-" << lastBlock << ", default = "
-            << lastBlock << ") or {+-}size{KMGT}: ";
+            << lastBlock << ") or {+-}size{KMGTP}: ";
       do {
-         sector = GetSectorNum(firstBlock, lastBlock, lastBlock, prompt3.str());
+         sector = GetSectorNum(firstBlock, lastBlock, lastBlock, blockSize, prompt3.str());
       } while (IsFree(sector) == 0);
       lastBlock = sector;
 
@@ -271,11 +271,13 @@
 // Partition attributes seem to be rarely used, but I want a way to
 // adjust them for completeness....
 void GPTDataTextUI::SetAttributes(uint32_t partNum) {
-   Attributes theAttr;
+//   Attributes theAttr;
 
-   theAttr.SetAttributes(partitions[partNum].GetAttributes());
+   partitions[partNum].SetAttributes();
+/*   theAttr = partitions[partNum].GetAttributes();
+//   theAttr.SetAttributes(partitions[partNum].GetAttributes());
    theAttr.ChangeAttributes();
-   partitions[partNum].SetAttributes(theAttr.GetAttributes());
+   partitions[partNum].SetAttributes(theAttr.GetAttributes()); */
 } // GPTDataTextUI::SetAttributes()
 
 // Ask user for two partition numbers and swap them in the table. Note that
diff --git a/guid.cc b/guid.cc
index 63aca2f..8e4d7dd 100644
--- a/guid.cc
+++ b/guid.cc
@@ -202,7 +202,7 @@
 
 // Display a GUID as a string....
 ostream & operator<<(ostream & os, const GUIDData & data) {
-   string asString;
+//   string asString;
 
    os << data.AsString();
    return os;
diff --git a/mbr.cc b/mbr.cc
index e0e92a3..782fd81 100644
--- a/mbr.cc
+++ b/mbr.cc
@@ -444,7 +444,7 @@
       cout.fill(' ');
    } // for
    cout << "\nDisk size is " << diskSize << " sectors ("
-        << BytesToSI(diskSize * (uint64_t) blockSize) << ")\n";
+        << BytesToSI(diskSize, blockSize) << ")\n";
 } // MBRData::DisplayMBRData()
 
 // Displays the state, as a word, on stdout. Used for debugging & to
diff --git a/partnotes.cc b/partnotes.cc
index 1edd5b8..bbb38f3 100644
--- a/partnotes.cc
+++ b/partnotes.cc
@@ -600,8 +600,8 @@
                cout << "   *    ";
             else
                cout << "        ";
-            sizeInSI = BytesToSI(blockSize * (gptParts[theNote->gptPartNum].GetLastLBA() -
-                                 gptParts[theNote->gptPartNum].GetFirstLBA() + 1));
+            sizeInSI = BytesToSI((gptParts[theNote->gptPartNum].GetLastLBA() -
+                                 gptParts[theNote->gptPartNum].GetFirstLBA() + 1), blockSize);
             cout << " " << sizeInSI;
             for (j = 0; j < 12 - (int) sizeInSI.length(); j++)
                cout << " ";
diff --git a/parttypes.cc b/parttypes.cc
index 37f47a7..d8d8624 100644
--- a/parttypes.cc
+++ b/parttypes.cc
@@ -192,13 +192,16 @@
 
 // Assignment operator by string. If the original string is short,
 // interpret it as a gdisk hex code; if it's longer, interpret it as
-// a direct entry of a GUID value....
+// a direct entry of a GUID value. If a short string isn't a hex
+// number, do nothing.
 PartType & PartType::operator=(const string & orig) {
    uint32_t hexCode;
 
    if (orig.length() < 32) {
-      sscanf(orig.c_str(), "%x", &hexCode);
-      *this = hexCode;
+      if (IsHex(orig)) {
+         sscanf(orig.c_str(), "%x", &hexCode);
+         *this = hexCode;
+      } // if
    } else {
       GUIDData::operator=(orig);
    } // if/else hexCode or GUID
diff --git a/sgdisk.8 b/sgdisk.8
index e44079b..2a9560e 100644
--- a/sgdisk.8
+++ b/sgdisk.8
@@ -1,6 +1,6 @@
 .\" Copyright 2010 Roderick W. Smith (rodsmith@rodsbooks.com)
 .\" May be distributed under the GNU General Public License
-.TH "SGDISK" "8" "0.6.11" "Roderick W. Smith" "GPT fdisk Manual"
+.TH "SGDISK" "8" "0.6.12" "Roderick W. Smith" "GPT fdisk Manual"
 .SH "NAME"
 sgdisk \- Command\-line GUID partition table (GPT) manipulator for Linux and Unix
 .SH "SYNOPSIS"
@@ -314,12 +314,12 @@
 
 .TP 
 .B \-n, \-\-new=partnum:start:end
-Create a new partition. You enter a partition
-number, starting sector, and an ending sector. Both start and end sectors
-can be specified in absolute terms as sector numbers or as positions
-measured in kilobytes (K), megabytes (M), gigabytes (G), or terabytes (T);
-for instance, \fI\fB40M\fR\fR specifies a position 40MiB from the start of
-the disk. You can specify locations relative to the start or end of the
+Create a new partition. You enter a partition number, starting sector, and
+an ending sector. Both start and end sectors can be specified in absolute
+terms as sector numbers or as positions measured in kibibytes (K),
+mebibytes (M), gibibytes (G), tebibytes (T), or pebibytes (P); for
+instance, \fI\fB40M\fR\fR specifies a position 40MiB from the start of the
+disk. You can specify locations relative to the start or end of the
 specified default range by preceding the number by a '+' or '\-' symbol, as
 in \fI\fB+2G\fR\fR to specify a point 2GiB after the default start sector,
 or \fI\fB\-200M\fR\fR to specify a point 200MiB before the last available
diff --git a/sgdisk.cc b/sgdisk.cc
index 7b88f71..b0959a5 100644
--- a/sgdisk.cc
+++ b/sgdisk.cc
@@ -136,20 +136,26 @@
                case 'A': {
                   if (cmd != "list") {
                      partNum = (int) GetInt(attributeOperation, 1) - 1;
-                     switch (theGPT.ManageAttributes(partNum, GetString(attributeOperation, 2),
-                           GetString(attributeOperation, 3))) {
-                        case -1:
-                           saveData = 0;
-                           neverSaveData = 1;
-                           break;
-                        case 1:
-                           theGPT.JustLooking(0);
-                           saveData = 1;
-                           break;
-                        default:
-                           break;
-                     } // switch
-                  } // if
+                     if ((partNum >= 0) && (partNum < (int) theGPT.GetNumParts())) {
+                        switch (theGPT.ManageAttributes(partNum, GetString(attributeOperation, 2),
+                              GetString(attributeOperation, 3))) {
+                           case -1:
+                              saveData = 0;
+                              neverSaveData = 1;
+                              break;
+                           case 1:
+                              theGPT.JustLooking(0);
+                              saveData = 1;
+                              break;
+                           default:
+                              break;
+                        } // switch
+                     } else {
+                        cerr << "Error: Invalid partition number " << partNum + 1 << "\n";
+                        saveData = 0;
+                        neverSaveData = 1;
+                     } // if/else reasonable partition #
+                  } // if (cmd != "list")
                   break;
                } // case 'A':
                case 'a':
diff --git a/support.cc b/support.cc
index 7db2f06..6211fdb 100644
--- a/support.cc
+++ b/support.cc
@@ -41,8 +41,7 @@
    char line[255];
 
    if (low != high) { // bother only if low and high differ...
-      response = low - 1; // force one loop by setting response outside range
-      while ((response < low) || (response > high)) {
+      do {
          cout << prompt;
          cin.getline(line, 255);
          num = sscanf(line, "%d", &response);
@@ -52,7 +51,7 @@
          } else { // user hit enter; return default
             response = def;
          } // if/else
-      } // while
+      } while ((response < low) || (response > high));
    } else { // low == high, so return this value
       cout << "Using " << low << "\n";
       response = low;
@@ -63,33 +62,40 @@
 // Gets a Y/N response (and converts lowercase to uppercase)
 char GetYN(void) {
    char line[255];
-   char response = '\0';
+   char response;
    char *junk;
 
-   while ((response != 'Y') && (response != 'N')) {
+   do {
       cout << "(Y/N): ";
       junk = fgets(line, 255, stdin);
       sscanf(line, "%c", &response);
-      if (response == 'y') response = 'Y';
-      if (response == 'n') response = 'N';
-   } // while
+      if (response == 'y')
+         response = 'Y';
+      if (response == 'n')
+         response = 'N';
+   } while ((response != 'Y') && (response != 'N'));
    return response;
 } // GetYN(void)
 
 // Obtains a sector number, between low and high, from the
 // user, accepting values prefixed by "+" to add sectors to low,
-// or the same with "K", "M", "G", or "T" as suffixes to add
-// kilobytes, megabytes, gigabytes, or terabytes, respectively.
-// If a "-" prefix is used, use the high value minus the user-
-// specified number of sectors (or KiB, MiB, etc.). Use the def
- //value as the default if the user just hits Enter
-uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, const string & prompt) {
-   uint64_t response, mult = 1;
+// or the same with "K", "M", "G", "T", or "P" as suffixes to add
+// kilobytes, megabytes, gigabytes, terabytes, or petabytes,
+// respectively. If a "-" prefix is used, use the high value minus
+// the user-specified number of sectors (or KiB, MiB, etc.). Use the
+// def value as the default if the user just hits Enter. The sSize is
+// the sector size of the device.
+uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, uint64_t sSize, const string & prompt) {
+   uint64_t response, mult = 1, divide = 1;
    int plusFlag = 0;
    char suffix, line[255];
 
-   response = low - 1; // Ensure one pass by setting a too-low initial value
-   while ((response < low) || (response > high)) {
+   if (sSize == 0) {
+      sSize = SECTOR_SIZE;
+      cerr << "Bug: Sector size invalid in GetSectorNum()!\n";
+   } // if
+
+   do {
       cout << prompt;
       cin.getline(line, 255);
 
@@ -124,26 +130,36 @@
       switch (suffix) {
          case 'K':
          case 'k':
-            mult = (uint64_t) 1024 / SECTOR_SIZE;
+            mult = UINT64_C(1024) / sSize;
+            divide = sSize / UINT64_C(1024);
+            break;
 	    break;
          case 'M':
-	 case 'm':
-	    mult = (uint64_t) 1048576 / SECTOR_SIZE;
+	      case 'm':
+            mult = UINT64_C(1048576) / sSize;
+            divide = sSize / UINT64_C(1048576);
             break;
          case 'G':
          case 'g':
-            mult = (uint64_t) 1073741824 / SECTOR_SIZE;
+            mult = UINT64_C(1073741824) / sSize;
             break;
          case 'T':
-	 case 't':
-            mult = ((uint64_t) 1073741824 * (uint64_t) 1024) / (uint64_t) SECTOR_SIZE;
+	      case 't':
+            mult = UINT64_C(1099511627776) / sSize;
+            break;
+         case 'P':
+         case 'p':
+            mult = UINT64_C(1125899906842624) / sSize;
             break;
          default:
             mult = 1;
       } // switch
 
       // Adjust response based on multiplier and plus flag, if present
-      response *= mult;
+      if (mult > 1)
+         response *= mult;
+      else if (divide > 1)
+         response /= divide;
       if (plusFlag == 1) {
          // Recompute response based on low part of range (if default = high
          // value, which should be the case when prompting for the end of a
@@ -157,19 +173,20 @@
       if (plusFlag == -1) {
          response = high - response;
       } // if
-   } // while
+   } while ((response < low) || (response > high));
    return response;
 } // GetSectorNum()
 
-// Takes a size in bytes (in size) and converts this to a size in
-// SI units (KiB, MiB, GiB, TiB, or PiB), returned in C++ string
-// form
-string BytesToSI(uint64_t size) {
+// Takes a size and converts this to a size in SI units (KiB, MiB, GiB,
+// TiB, or PiB), returned in C++ string form. The size is either in units
+// of the sector size or, if that parameter is omitted, in bytes.
+// (sectorSize defaults to 1).
+string BytesToSI(uint64_t size, uint32_t sectorSize) {
    string units;
    ostringstream theValue;
    float sizeInSI;
 
-   sizeInSI = (float) size;
+   sizeInSI = (float) size * (float) sectorSize;
    units = " bytes";
    if (sizeInSI > 1024.0) {
       sizeInSI /= 1024.0;
@@ -215,6 +232,29 @@
    return retval;
 } // StrToHex()
 
+// Returns 1 if input can be interpreted as a hexadecimal number --
+// all characters must be spaces, digits, or letters A-F (upper- or
+// lower-case), with at least one valid hexadecimal digit; otherwise
+// returns 0.
+int IsHex(const string & input) {
+   int isHex = 1, foundHex = 0, i;
+
+   for (i = 0; i < (int) input.length(); i++) {
+      if ((input[i] < '0') || (input[i] > '9')) {
+         if ((input[i] < 'A') || (input[i] > 'F')) {
+            if ((input[i] < 'a') || (input[i] > 'f')) {
+               if ((input[i] != ' ') && (input[i] != '\n')) {
+                  isHex = 0;
+               }
+            } else foundHex = 1;
+         } else foundHex = 1;
+      } else foundHex = 1;
+   } // for
+   if (!foundHex)
+      isHex = 0;
+   return isHex;
+} // IsHex()
+
 // Return 1 if the CPU architecture is little endian, 0 if it's big endian....
 int IsLittleEndian(void) {
    int littleE = 1; // assume little-endian (Intel-style)
diff --git a/support.h b/support.h
index be55294..3ae2d9f 100644
--- a/support.h
+++ b/support.h
@@ -2,7 +2,6 @@
   under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
 
 #include <stdint.h>
-//#include <unistd.h>
 #include <stdlib.h>
 #include <string>
 
@@ -50,9 +49,10 @@
 
 int GetNumber(int low, int high, int def, const string & prompt);
 char GetYN(void);
-uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, const string & prompt);
-string BytesToSI(uint64_t size);
+uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, uint64_t sSize, const std::string& prompt);
+string BytesToSI(uint64_t size, uint32_t sectorSize = 1);
 unsigned char StrToHex(const string & input, unsigned int position);
+int IsHex(const string & input); // Returns 1 if input can be hexadecimal number....
 int IsLittleEndian(void); // Returns 1 if CPU is little-endian, 0 if it's big-endian
 void ReverseBytes(void* theValue, int numBytes); // Reverses byte-order of theValue