Revisions for 0.6.10 release
diff --git a/NEWS b/NEWS
index 26c666b..777bb8e 100644
--- a/NEWS
+++ b/NEWS
@@ -1,8 +1,22 @@
-0.6.10 (??/??/2010):
---------------------
+0.6.10 (8/22/2010):
+-------------------
 
-- Added ability to save partition table from one device to another
-  (gdisk: 'u' on experts' menu; sgdisk: -R or --replicate option)
+- Enable disk-wipe (-z and -Z) and verification (-v) operations in
+  sgdisk even if the disk is badly damaged.
+
+- Added support for setting attributes in sgdisk (-A/--attributes option)
+  in sgdisk.
+
+- Fixed bug that created backwards attribute field values (bit #2 was
+  entered as bit #61, etc.).
+
+- Fixed bug that caused creation of hybrid MBR to wipe out the MBR's boot
+  code.
+
+- Added ability to save partition table from one device to another (gdisk:
+  'u' on experts' menu; sgdisk: -R or --replicate option).
+
+- Fixed inaccessible -C/--recompute-chs option in sgdisk.
 
 0.6.9 (7/4/2010):
 ------------------
diff --git a/attributes.cc b/attributes.cc
index 527dc87..c9c1d23 100644
--- a/attributes.cc
+++ b/attributes.cc
@@ -8,36 +8,38 @@
 #define __STDC_LIMIT_MACROS
 #define __STDC_CONSTANT_MACROS
 
-#include <string.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <iostream>
 #include <sstream>
+
 #include "attributes.h"
+#include "support.h"
 
 using namespace std;
 
-// Constructor. Its main task is to initialize the attribute name
-// data.
-Attributes::Attributes(void) {
-   int i;
-   ostringstream temp;
+string Attributes::atNames[NUM_ATR];
+Attributes::staticInit Attributes::staticInitializer;
 
+Attributes::staticInit::staticInit (void) {
+   ostringstream temp;
+ 
    // Most bits are undefined, so start by giving them an
    // appropriate name
-   for (i = 1; i < NUM_ATR; i++) {
+   for (int i = 0; i < NUM_ATR; i++) {
+      temp.str("");
       temp << "Undefined bit #" << i;
-	  atNames[i] = temp.str();
+      Attributes::atNames[i] = temp.str();
    } // for
 
    // Now reset those names that are defined....
-   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 constructor
+   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) {
@@ -45,7 +47,8 @@
 
 // Display current attributes to user
 void Attributes::DisplayAttributes(void) {
-   int i;
+   uint32_t i;
+   int numSet = 0;
 
    cout << "Attribute value is ";
    cout.setf(ios::uppercase);
@@ -53,37 +56,137 @@
    cout.width(16);
    cout << hex << attributes << dec << ". Set fields are:\n";
    for (i = 0; i < NUM_ATR; i++) {
-      if (((attributes >> i) % 2) == 1) { // bit is set
-         if (atNames[NUM_ATR - i - 1].substr(0, 9) != "Undefined")
-            cout << atNames[NUM_ATR - i - 1] << "\n";
+      if ((UINT64_C(1) << i) & attributes) {
+         cout << i << " (" << Attributes::GetAttributeName(i) << ")" << "\n";
+         numSet++;
       } // if
    } // for
    cout.fill(' ');
+   if (numSet == 0)
+      cout << "  No fields set\n";
+   cout << "\n";
 } // Attributes::DisplayAttributes()
 
 // Prompt user for attribute changes
 void Attributes::ChangeAttributes(void) {
-   int response, i;
+   int response;
    uint64_t bitValue;
 
    cout << "Known attributes are:\n";
-   for (i = 0; i < NUM_ATR; i++) {
-      if (atNames[i].substr(0, 9) != "Undefined")
-         cout << i << " - " << atNames[i] << "\n";
-   } // for
+   ListAttributes();
+   cout << "\n";
 
    do {
-      response = GetNumber(0, 64, -1, (string) "Toggle which attribute field (0-63, 64 to exit): ");
+      DisplayAttributes();
+      response = GetNumber(0, NUM_ATR, -1, "Toggle which attribute field (0-63, 64 to exit): ");
       if (response != 64) {
-         bitValue = PowerOf2(uint32_t (NUM_ATR - response - 1)); // Find the integer value of the bit
-         if ((bitValue & attributes) == bitValue) { // bit is set
-            attributes -= bitValue; // so unset it
-	    cout << "Have disabled the '" << atNames[response] << "' attribute.\n";
+         bitValue = UINT64_C(1) << response; // Find the integer value of the bit
+         if (bitValue & attributes) { // bit is set
+            attributes &= ~bitValue; // so unset it
+	         cout << "Have disabled the '" << atNames[response] << "' attribute.\n";
          } else { // bit is not set
-            attributes += bitValue; // so set it
+            attributes |= bitValue; // so set it
             cout << "Have enabled the '" << atNames[response] << "' attribute.\n";
          } // if/else
       } // if
    } while (response != 64);
 } // Attributes::ChangeAttributes()
 
+// Display all defined attributes on the screen (omits undefined bits).
+void Attributes::ListAttributes(void) {
+   uint32_t bitNum;
+   string tempAttr;
+
+   for (bitNum = 0; bitNum < NUM_ATR; bitNum++) {
+      tempAttr = GetAttributeName(bitNum);
+      if (tempAttr.substr(0, 15) != "Undefined bit #" )
+         cout << bitNum << ": " << Attributes::GetAttributeName(bitNum) << "\n";
+   } // 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) {
+
+   // attribute access opcode
+   typedef enum {
+      ao_or, ao_nand, ao_xor, ao_assignall,  // operate on all attributes (bitmask)
+      ao_unknown, // must be after bitmask operators and before bitnum operators
+      ao_set, ao_clear, ao_toggle, ao_get    // operate on a single attribute (bitnum)
+   } attribute_opcode_t; // typedef enum
+
+   // translate attribute operator into an attribute opcode
+   attribute_opcode_t attributeOpcode = ao_unknown; { // opcode is not known yet
+      if      (attributeOperator == "or")      attributeOpcode = ao_or;
+      else if (attributeOperator == "nand")    attributeOpcode = ao_nand;
+      else if (attributeOperator == "xor")     attributeOpcode = ao_xor;
+      else if (attributeOperator == "=")       attributeOpcode = ao_assignall;
+      else if (attributeOperator == "set")     attributeOpcode = ao_set;
+      else if (attributeOperator == "clear")   attributeOpcode = ao_clear;
+      else if (attributeOperator == "toggle")  attributeOpcode = ao_toggle;
+      else if (attributeOperator == "get")     attributeOpcode = ao_get;
+      else {
+         cerr << "Unknown attributes operator: " << attributeOperator << endl;
+         return false;
+      } // else
+   } // attributeOpcode
+
+   // get bit mask if operating on entire attribute set
+   uint64_t attributeBitMask; { if (attributeOpcode < ao_unknown) {
+      if (1 != sscanf (attributeBits.c_str(), "%qx", (long long unsigned int*) &attributeBitMask)) {
+         cerr << "Could not convert hex attribute mask" << endl;
+         return false;
+      } // if
+   }} // attributeBitMask, if
+
+   // get bit number and calculate bit mask if operating on a single attribute
+   int bitNum; { if (attributeOpcode > ao_unknown) {
+      if (1 != sscanf (attributeBits.c_str(), "%d", &bitNum)) {
+         cerr << "Could not convert bit number" << endl;
+         return false;
+      } // if
+      const uint64_t one = 1;
+      attributeBitMask = one << bitNum;
+   }} // bitNum, if
+
+   switch (attributeOpcode) {
+      // assign all attributes at once
+      case ao_assignall:  attributes = attributeBitMask;    break;
+
+      // set individual attribute(s)
+      case ao_set:
+      case ao_or:         attributes |= attributeBitMask;   break;
+
+      // clear individual attribute(s)
+      case ao_clear:
+      case ao_nand:       attributes &= ~attributeBitMask;  break;
+
+      // toggle individual attribute(s)
+      case ao_toggle:
+      case ao_xor:        attributes ^= attributeBitMask;   break;
+
+      // display a single attribute
+      case ao_get: {
+         cout << partNum+1 << ":" << bitNum << ":" <<
+              bool (attributeBitMask & attributes) << endl;
+         break;
+      } // case ao_get
+
+      default: break; // will never get here
+   } // switch
+
+   return true;
+} // Attributes::OperateOnAttributes()
diff --git a/attributes.h b/attributes.h
index ab8cb14..34cf258 100644
--- a/attributes.h
+++ b/attributes.h
@@ -2,10 +2,7 @@
   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.h>
-#include "support.h"
+#include <string>
 
 #ifndef __GPT_ATTRIBUTES
 #define __GPT_ATTRIBUTES
@@ -16,16 +13,27 @@
 using namespace std;
 
 class Attributes {
+
+private:
+   class staticInit {public: staticInit (void);};
+   static string atNames[NUM_ATR];
+   static Attributes::staticInit staticInitializer;
+
 protected:
    uint64_t attributes;
-   string atNames[NUM_ATR];
+
 public:
-   Attributes(void);
+   Attributes(const uint64_t a = 0) {SetAttributes (a);}
    ~Attributes(void);
-   void SetAttributes(uint64_t a) {attributes = a;}
+   void SetAttributes(const uint64_t a) {attributes = a;}
    uint64_t GetAttributes(void) {return attributes;}
    void DisplayAttributes(void);
    void ChangeAttributes(void);
+   void ShowAttributes(const uint32_t partNum);
+   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
 
 #endif
diff --git a/current.spec b/current.spec
index 600c21b..009de63 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.9
+Version: 0.6.10
 Release: 1%{?dist}
 License: GPLv2
 URL: http://www.rodsbooks.com/gdisk
 Group: Applications/System
-Source: http://www.rodsbooks.com/gdisk/gdisk-0.6.9.tgz
+Source: http://www.rodsbooks.com/gdisk/gdisk-0.6.10.tgz
 BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
 
 %description
@@ -23,9 +23,9 @@
 
 %install
 rm -rf $RPM_BUILD_ROOT
-mkdir -p $RPM_BUILD_ROOT/sbin
-install -Dp -m0755 gdisk $RPM_BUILD_ROOT/sbin
-install -Dp -m0755 sgdisk $RPM_BUILD_ROOT/sbin
+mkdir -p $RPM_BUILD_ROOT/usr/sbin
+install -Dp -m0755 gdisk $RPM_BUILD_ROOT/usr/sbin
+install -Dp -m0755 sgdisk $RPM_BUILD_ROOT/usr/sbin
 install -Dp -m0644 gdisk.8 $RPM_BUILD_ROOT/%{_mandir}/man8/gdisk.8
 install -Dp -m0644 sgdisk.8 $RPM_BUILD_ROOT/%{_mandir}/man8/sgdisk.8
 
@@ -35,10 +35,10 @@
 %files
 %defattr(-,root,root -)
 %doc NEWS COPYING README
-/sbin/gdisk
-/sbin/sgdisk
+/usr/sbin/gdisk
+/usr/sbin/sgdisk
 %doc %{_mandir}/man8*
 
 %changelog
-* Sun Jul 4 2010 R Smith <rodsmith@rodsbooks.com> - 0.6.9
-- Created spec file for 0.6.9 release
+* Sun Aug 22 2010 R Smith <rodsmith@rodsbooks.com> - 0.6.10
+- Created spec file for 0.6.10 release
diff --git a/gdisk.8 b/gdisk.8
index e11df37..76600fc 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.9" "Roderick W. Smith" "GPT fdisk Manual"
+.TH "GDISK" "8" "0.6.10" "Roderick W. Smith" "GPT fdisk Manual"
 .SH "NAME"
 gdisk \- Interactive GUID partition table (GPT) manipulator
 .SH "SYNOPSIS"
@@ -524,6 +524,15 @@
 partitions in this way has no effect on their disk space allocation; it
 only alters their order in the partition table.
 
+.TP
+.B u
+Replicate the current device's partition table on another device. You will
+be prompted to type the new device's filename. After the write operation
+completes, you can continue editing the original device's partition table.
+Note that the replicated partition table is an exact copy, including all
+GUIDs; if the device should have its own unique GUIDs, you should use the
+\fBf\fR option on the new disk.
+
 .TP 
 .B v
 Verify disk. This option is identical to the 'v' option in the main menu.
diff --git a/gpt.cc b/gpt.cc
index 9bebb12..7dcbc86 100644
--- a/gpt.cc
+++ b/gpt.cc
@@ -645,7 +645,7 @@
             break;
          case use_abort:
             allOK = 0;
-            cerr << "Aborting because of invalid partition data!\n";
+            cerr << "Invalid partition data!\n";
             break;
       } // switch
 
@@ -1510,7 +1510,7 @@
    int mbrNum = 0, numConverted = 0;
    struct PartInfo convInfo;
 
-   protectiveMBR.EmptyMBR();
+   protectiveMBR.EmptyMBR(0);
    protectiveMBR.SetDiskSize(diskSize);
    notes.Rewind();
    while (notes.GetNextInfo(&convInfo) >= 0) {
@@ -2205,7 +2205,7 @@
       if (partitions[i].IsUsed()) {
          found = 0;
          while (!found) {
-            align = PowerOf2(exponent);
+            align = UINT64_C(1)<<exponent;
             if ((partitions[i].GetFirstLBA() % align) == 0) {
                found = 1;
             } else {
@@ -2252,6 +2252,53 @@
    } // for
 } // GPTData::ReversePartitionBytes()
 
+// Validate partition number
+bool GPTData::ValidPartNum (const uint32_t partNum) {
+   if (partNum >= numParts) {
+      cerr << "Partition number out of range: " << (signed) partNum << endl;
+      return false;
+   } // if
+   return true;
+} // GPTData::ValidPartNum
+
+// Manage attributes for a partition, based on commands passed to this function.
+// (Function is non-interactive.)
+// Returns 1 if a modification command succeeded, 0 if the command should not have
+// modified data, and -1 if a modification command failed.
+int GPTData::ManageAttributes(int partNum, const string & command, const string & bits) {
+   int retval = 0;
+   Attributes theAttr;
+
+   if (command == "show") {
+      ShowAttributes(partNum);
+   } else if (command == "get") {
+      GetAttribute(partNum, bits);
+   } else {
+      theAttr = partitions[partNum].GetAttributes();
+      if (theAttr.OperateOnAttributes(partNum, command, bits)) {
+         partitions[partNum].SetAttributes(theAttr.GetAttributes());
+         retval = 1;
+      } else {
+         retval = -1;
+      } // if/else
+   } // if/elseif/else
+
+   return retval;
+} // GPTData::ManageAttributes()
+
+// Show all attributes for a specified partition....
+void GPTData::ShowAttributes(const uint32_t partNum) {
+   Attributes theAttr (partitions[partNum].GetAttributes());
+   theAttr.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);
+} // GPTData::GetAttribute
+
+
 /******************************************
  *                                        *
  * Additional non-class support functions *
diff --git a/gpt.h b/gpt.h
index 4ead25a..4f0ccf7 100644
--- a/gpt.h
+++ b/gpt.h
@@ -16,7 +16,7 @@
 #ifndef __GPTSTRUCTS
 #define __GPTSTRUCTS
 
-#define GPTFDISK_VERSION "0.6.10-pre1"
+#define GPTFDISK_VERSION "0.6.10"
 
 // Constants used by GPTData::PartsToMBR(). MBR_EMPTY must be the lowest-
 // numbered value to refer to partition numbers. (Most will be 0 or positive,
@@ -179,6 +179,7 @@
    uint64_t GetPartFirstLBA(uint32_t i) {return partitions[i].GetFirstLBA();}
    uint64_t GetPartLastLBA(uint32_t i) {return partitions[i].GetLastLBA();}
    uint32_t CountParts(void);
+   bool ValidPartNum (const uint32_t partNum);
 
    // Find information about free space
    uint64_t FindFirstAvailable(uint64_t start = 0);
@@ -200,6 +201,12 @@
    // Endianness functions
    void ReverseHeaderBytes(struct GPTHeader* header);
    void ReversePartitionBytes(); // for endianness
+
+   // Attributes functions
+   int ManageAttributes(int partNum, const string & command, const string & bits);
+   void ShowAttributes(const uint32_t partNum);
+   void GetAttribute(const uint32_t partNum, const string& attributeBits);
+
 }; // class GPTData
 
 // Function prototypes....
diff --git a/gpttext.cc b/gpttext.cc
index fe64be0..c37e01e 100644
--- a/gpttext.cc
+++ b/gpttext.cc
@@ -266,7 +266,6 @@
    Attributes theAttr;
 
    theAttr.SetAttributes(partitions[partNum].GetAttributes());
-   theAttr.DisplayAttributes();
    theAttr.ChangeAttributes();
    partitions[partNum].SetAttributes(theAttr.GetAttributes());
 } // GPTDataTextUI::SetAttributes()
diff --git a/sgdisk.8 b/sgdisk.8
index 1855bcd..ecb37d3 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.9" "Roderick W. Smith" "GPT fdisk Manual"
+.TH "SGDISK" "8" "0.6.10" "Roderick W. Smith" "GPT fdisk Manual"
 .SH "NAME"
 sgdisk \- Command\-line GUID partition table (GPT) manipulator for Linux and Unix
 .SH "SYNOPSIS"
@@ -153,6 +153,20 @@
 performance with Western Digital Advanced Format and similar drives with larger
 physical than logical sector sizes and with some types of RAID arrays.
 
+.TP
+.B \-A, \-\-attributes=list|[partnum:show|or|nand|xor|=|set|clear|toggle|get[:bitnum|hexbitmask]]
+View or set partition attributes. Use \fIlist\fR to see defined (known)
+attribute values. Omit the partition number (and even the device filename)
+when using this option. The others require a partition number. The
+\fIshow\fR and \fIget\fR options show the current attribute settings
+(all attributes or for a particular bit, respectively). The \fIor\fR,
+\fInand\fR, \fIxor\fR, \fI\=\fR, \fIset\fR, \fIclear\fR, and
+\fItoggle\fR options enable you to change the attribute bit value. The
+\fIset\fR, \fIclear\fR, \fItoggle\fR, and \fIget\fR options work on a
+bit number; the others work on a hexadecimal bit mask. For example, type 
+\fBsgdisk -A 4:set:2 /dev/sdc\fR to set the bit 2 attribute (legacy BIOS
+bootable) on partition 4 on \fI/dev/sdc\fR.
+
 .TP 
 .B \-b, \-\-backup=file
 Save partition data to a backup file. You can back up your current
@@ -210,7 +224,7 @@
 GPT data structures to the end of the disk, where they belong.
 
 .TP 
-.B E, \-\-end\-of\-largest
+.B \-E, \-\-end\-of\-largest
 Displays the sector number of the end of the largest available block of
 sectors on the disk. A script may store this value and pass it back as
 part of \fI\-n\fR's option to create a partition. If no unallocated
@@ -339,6 +353,13 @@
 way has no effect on their disk space allocation; it only alters their
 order in the partition table.
 
+.TP
+.B \-R, \-\-replicate=second_device_filename
+Replicate the main device's partition table on the specified second device.
+Note that the replicated partition table is an exact copy, including all
+GUIDs; if the device should have its own unique GUIDs, you should use the
+\-G option on the new disk.
+
 .TP 
 .B \-s, \-\-sort
 Sort partition entries. GPT partition numbers need not match the order of
diff --git a/sgdisk.cc b/sgdisk.cc
index 537639d..3927d26 100644
--- a/sgdisk.cc
+++ b/sgdisk.cc
@@ -19,13 +19,12 @@
 #include "gpt.h"
 #include "support.h"
 #include "parttypes.h"
+#include "attributes.h"
 
 using namespace std;
 
 #define MAX_OPTIONS 50
 
-uint64_t GetInt(char* Info, int itemNum);
-string GetString(char* Info, int itemNum);
 int BuildMBR(GPTData* theGPT, char* argument, int isHybrid);
 int CountColons(char* argument);
 
@@ -39,15 +38,18 @@
    unsigned int hexCode;
    uint32_t tableSize = 128;
    uint64_t startSector, endSector;
+   char *attributeOperation = NULL;
    char *device = NULL;
    char *newPartInfo = NULL, *typeCode = NULL, *partName = NULL;
    char *backupFile = NULL, *twoParts = NULL, *hybrids = NULL, *mbrParts;
    char *partGUID = NULL, *diskGUID = NULL, *outDevice = NULL;
+   string cmd;
    PartType typeHelper;
 
    poptContext poptCon;
    struct poptOption theOptions[] =
    {
+      {"attributes", 'A', POPT_ARG_STRING, &attributeOperation, 'A', "operate on partition attributes", "list|[partnum:show|or|nand|xor|=|set|clear|toggle|get[:bitnum|hexbitmask]]"},
       {"set-alignment", 'a', POPT_ARG_INT, &alignment, 'a', "set sector alignment", "value"},
       {"backup", 'b', POPT_ARG_STRING, &backupFile, 'b', "backup GPT to file", "file"},
       {"change-name", 'c', POPT_ARG_STRING, &partName, 'c', "change partition's name", "partnum:name"},
@@ -98,6 +100,11 @@
    // with options that don't require a device filename....
    while ((opt = poptGetNextOpt(poptCon)) > 0) {
       switch (opt) {
+         case 'A':
+            cmd = GetString(attributeOperation, 1);
+            if (cmd == "list")
+               Attributes::ListAttributes();
+            break;
          case 'L':
             typeHelper.ShowAllTypes();
             break;
@@ -125,6 +132,25 @@
             saveNonGPT = 0; // flag so we don't overwrite unless directed to do so
          while ((opt = poptGetNextOpt(poptCon)) > 0) {
             switch (opt) {
+               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
+                  break;
+               } // case 'A':
                case 'a':
                   theGPT.SetAlignment(alignment);
                   break;
@@ -339,6 +365,31 @@
             retval = 4;
          } // if
       } else { // if loaded OK
+         poptResetContext(poptCon);
+         // Do a few types of operations even if there are problems....
+         while ((opt = poptGetNextOpt(poptCon)) > 0) {
+            switch (opt) {
+               case 'v':
+                  cout << "Verification may miss some problems!\n";
+                  theGPT.Verify();
+                  break;
+               case 'z':
+                  if (!pretend) {
+                     theGPT.DestroyGPT();
+                  } // if
+                  saveNonGPT = 0;
+                  saveData = 0;
+                  break;
+               case 'Z':
+                  if (!pretend) {
+                     theGPT.DestroyGPT();
+                     theGPT.DestroyMBR();
+                  } // if
+                  saveNonGPT = 0;
+                  saveData = 0;
+                  break;
+            } // switch
+         } // while
          retval = 2;
       } // if/else loaded OK
    } // if (device != NULL)
@@ -347,43 +398,6 @@
    return retval;
 } // main
 
-// Extract integer data from argument string, which should be colon-delimited
-uint64_t GetInt(char* argument, int itemNum) {
-   int startPos = -1, endPos = -1;
-   uint64_t retval = 0;
-   string Info;
-
-   Info = argument;
-   while (itemNum-- > 0) {
-      startPos = endPos + 1;
-      endPos = Info.find(':', startPos);
-   }
-   if (endPos == (int) string::npos)
-      endPos = Info.length();
-   endPos--;
-
-   istringstream inString(Info.substr(startPos, endPos - startPos + 1));
-   inString >> retval;
-   return retval;
-} // GetInt()
-
-// Extract string data from argument string, which should be colon-delimited
-string GetString(char* argument, int itemNum) {
-   int startPos = -1, endPos = -1;
-   string Info;
-
-   Info = argument;
-   while (itemNum-- > 0) {
-      startPos = endPos + 1;
-      endPos = Info.find(':', startPos);
-   }
-   if (endPos == (int) string::npos)
-      endPos = Info.length();
-   endPos--;
-
-   return Info.substr(startPos, endPos - startPos + 1);
-} // GetString()
-
 // Create a hybrid or regular MBR from GPT data structures
 int BuildMBR(GPTData* theGPT, char* argument, int isHybrid) {
    int numParts, allOK = 1, i;
diff --git a/support.cc b/support.cc
index 11c6200..1711209 100644
--- a/support.cc
+++ b/support.cc
@@ -244,16 +244,35 @@
    } // if
 } // ReverseBytes()
 
-// Compute (2 ^ value). Given the return type, value must be 63 or less.
-// Used in some bit-fiddling functions
-uint64_t PowerOf2(uint32_t value) {
-   uint64_t retval = 1;
-   uint32_t i;
+// Extract integer data from argument string, which should be colon-delimited
+uint64_t GetInt(const string & argument, int itemNum) {
+   int startPos = -1, endPos = -1;
+   uint64_t retval = 0;
 
-   if (value < 64) {
-      for (i = 0; i < value; i++) {
-         retval *= 2;
-      } // for
-   } else retval = 0;
+   while (itemNum-- > 0) {
+      startPos = endPos + 1;
+      endPos = argument.find(':', startPos);
+   }
+   if (endPos == (int) string::npos)
+      endPos = argument.length();
+   endPos--;
+
+   istringstream inString(argument.substr(startPos, endPos - startPos + 1));
+   inString >> retval;
    return retval;
-} // PowerOf2()
+} // GetInt()
+
+// Extract string data from argument string, which should be colon-delimited
+string GetString(const string & argument, int itemNum) {
+   int startPos = -1, endPos = -1;
+
+   while (itemNum-- > 0) {
+      startPos = endPos + 1;
+      endPos = argument.find(':', startPos);
+   }
+   if (endPos == (int) string::npos)
+      endPos = argument.length();
+   endPos--;
+
+   return argument.substr(startPos, endPos - startPos + 1);
+} // GetString()
\ No newline at end of file
diff --git a/support.h b/support.h
index 8e29f7a..be55294 100644
--- a/support.h
+++ b/support.h
@@ -55,6 +55,9 @@
 unsigned char StrToHex(const string & input, unsigned int position);
 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
-uint64_t PowerOf2(uint32_t value);
+
+// Extract colon-separated fields from a string....
+uint64_t GetInt(const string & argument, int itemNum);
+string GetString(const string & Info, int itemNum);
 
 #endif