Version 0.6.14 release
diff --git a/NEWS b/NEWS
index a734b09..eabf53d 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,25 @@
+0.6.14 (1/8/2011):
+------------------
+
+- Made small change to the way the start sector is interpreted if you use a
+  "+" specification, as in "+2G" to locate a partition 2 GiB into the
+  default range. This change makes adjustments for sector alignment less
+  likely.
+
+- Modified sgdisk's -n (--new) option to work with relative start and end
+  values (which the man page incorrectly stated it already did). Values of
+  0 for the start and end sectors refer to the first and last available
+  sectors in the largest free block, and a partition number of 0 refers to
+  the first available partition.
+
+- Added ChromeOS GUID values to list of recognized partition type GUIDs.
+  7F00 = ChromeOS kernel, 7501 = ChromeOS root, 7502 = ChromeOS reserved.
+  Untested on actual ChromeOS system.
+
+- Tweaked APM detection to look for APM signature even if an MBR
+  signature has already been found. Helps in diagnosis of cases
+  in which an MBR has overwritten an APM disk.
+
 0.6.13 (10/12/2010):
 --------------------
 
diff --git a/current.spec b/current.spec
index caa1a84..18b283b 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.13
+Version: 0.6.14
 Release: 1%{?dist}
 License: GPLv2
 URL: http://www.rodsbooks.com/gdisk
 Group: Applications/System
-Source: http://www.rodsbooks.com/gdisk/gdisk-0.6.13.tgz
+Source: http://www.rodsbooks.com/gdisk/gdisk-0.6.14.tgz
 BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
 
 %description
@@ -40,5 +40,5 @@
 %doc %{_mandir}/man8*
 
 %changelog
-* Tue Oct 12 2010 R Smith <rodsmith@rodsbooks.com> - 0.6.13
-- Created spec file for 0.6.13 release
+* Sat Jan 8 2011 R Smith <rodsmith@rodsbooks.com> - 0.6.14
+- Created spec file for 0.6.14 release
diff --git a/gdisk.8 b/gdisk.8
index fdb7277..7d5d2c6 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.13" "Roderick W. Smith" "GPT fdisk Manual"
+.TH "GDISK" "8" "0.6.14" "Roderick W. Smith" "GPT fdisk Manual"
 .SH "NAME"
 gdisk \- Interactive GUID partition table (GPT) manipulator
 .SH "SYNOPSIS"
@@ -560,7 +560,7 @@
 usually bypasses the prompt entirely.
 
 .SH "BUGS"
-As of March 2010 (version 0.6.6), \fBgdisk\fR
+As of January 2011 (version 0.6.14), \fBgdisk\fR
 should be considered beta software. Known bugs and limitations include:
 
 .TP 
@@ -569,7 +569,8 @@
 Linux versions for x86\-64 (64\-bit), x86 (32\-bit), and PowerPC (32\-bit) have been
 tested, with the x86\-64 version having seen the most testing. Under FreeBSD,
 32\-bit (x86) and 64\-bit (x86\-64) versions have been tested. Only 32\-bit
-versions for Mac OS X and Windows have been tested.
+versions for Mac OS X and Windows have been tested by the author, although
+I've heard of 64-bit versions being successfully compiled.
 
 .TP 
 .B *
@@ -645,9 +646,9 @@
 
 .PP 
 
-The support for big\-endian CPUs (PowerPC, for example) is new, as of version
-0.3.5. I advise using caution on that platform, particularly with the more
-obscure features of the program.
+The support for big\-endian CPUs (PowerPC, for example) is new, as of
+version 0.3.5. I advise using caution on such CPUs, particularly with the
+more obscure features of the program.
 
 .SH "AUTHORS"
 Primary author: Roderick W. Smith (rodsmith@rodsbooks.com)
diff --git a/gpt.cc b/gpt.cc
index 2a2df8f..bcc053a 100644
--- a/gpt.cc
+++ b/gpt.cc
@@ -344,10 +344,9 @@
       cout << UINT32_C(0x00010000) << dec << "\n";
    } // if/else/if
 
-   // If MBR bad, check for an Apple disk signature
-   if ((protectiveMBR.GetValidity() == invalid) &&
-        (((mainHeader.signature << 32) == APM_SIGNATURE1) ||
-        (mainHeader.signature << 32) == APM_SIGNATURE2)) {
+   // Check for an Apple disk signature
+   if (((mainHeader.signature << 32) == APM_SIGNATURE1) ||
+        (mainHeader.signature << 32) == APM_SIGNATURE2) {
       apmFound = 1; // Will display warning message later
    } // if
    cout.fill(' ');
diff --git a/gpt.h b/gpt.h
index e92b8b1..9d13750 100644
--- a/gpt.h
+++ b/gpt.h
@@ -16,7 +16,7 @@
 #ifndef __GPTSTRUCTS
 #define __GPTSTRUCTS
 
-#define GPTFDISK_VERSION "0.6.13"
+#define GPTFDISK_VERSION "0.6.14"
 
 // Constants used by GPTData::PartsToMBR(). MBR_EMPTY must be the lowest-
 // numbered value to refer to partition numbers. (Most will be 0 or positive,
@@ -180,6 +180,7 @@
    bool ValidPartNum (const uint32_t partNum);
    const GPTPart & operator[](uint32_t partNum) const;
    const GUIDData & GetDiskGUID(void) const;
+   uint32_t GetBlockSize(void) {return blockSize;}
 
    // Find information about free space
    uint64_t FindFirstAvailable(uint64_t start = 0);
diff --git a/parttypes.cc b/parttypes.cc
index d8d8624..c6e2098 100644
--- a/parttypes.cc
+++ b/parttypes.cc
@@ -95,6 +95,16 @@
    // An oddball IBM filesystem....
    AddType(0x7501, "37AFFC90-EF7D-4E96-91C3-2D7AE055B174", "IBM GPFS"); // General Parallel File System (GPFS)
 
+   // ChromeOS-specific partition types...
+   // Values taken from vboot_reference/firmware/lib/cgptlib/include/gpt.h in
+   // ChromeOS source code, retrieved 12/23/2010. They're also at
+   // http://www.chromium.org/chromium-os/chromiumos-design-docs/disk-format.
+   // These have no MBR equivalents, AFAIK, so I'm using 0x7Fxx values, since they're close
+   // to the Linux values.
+   AddType(0x7f00, "FE3A2A5D-4F32-41A7-B725-ACCC3285A309", "ChromeOS kernel");
+   AddType(0x7f01, "3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC", "ChromeOS root");
+   AddType(0x7f02, "2E0A753D-9E48-43B0-8337-B15192CB1B5E", "ChromeOS reserved");
+
    // Linux-specific partition types....
    AddType(0x8200, "0657FD6D-A4AB-43C4-84E5-0933C84B4F4F", "Linux swap"); // Linux swap (or Solaris)
    AddType(0x8300, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Linux/Windows data", 0); // Linux native
diff --git a/sgdisk.8 b/sgdisk.8
index 4b75053..1cd2b90 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.13" "Roderick W. Smith" "GPT fdisk Manual"
+.TH "SGDISK" "8" "0.6.14" "Roderick W. Smith" "GPT fdisk Manual"
 .SH "NAME"
 sgdisk \- Command\-line GUID partition table (GPT) manipulator for Linux and Unix
 .SH "SYNOPSIS"
@@ -323,9 +323,10 @@
 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.
+sector. A start or end value of 0 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. A partnum value of 0 causes the program
+to use the first available partition number.
 
 .TP
 .B \-N, \-\-largest\-new=num
@@ -334,7 +335,8 @@
 result in a sector-moved warning, since the first available sector
 (normally 34) doesn't fall on a 2048-sector boundary (the default for
 alignment). You can use the \fI\-a\fR (\fI\-\-set\-alignment\fR) option to
-adjust the alignment, if desired.
+adjust the alignment, if desired. A num value of 0 causes the program to
+use the first available partition number.
 
 .TP 
 .B \-o, \-\-clear
@@ -468,7 +470,7 @@
 .B 4
 An error prevented saving changes
 .SH "BUGS"
-As of March 2010 (version 0.6.6), \fBsgdisk\fR
+As of January 2011 (version 0.6.14), \fBsgdisk\fR
 should be considered beta software. Known bugs and limitations include:
 
 .TP 
@@ -551,9 +553,9 @@
 
 .PP 
 
-The support for big\-endian CPUs (PowerPC, for example) is new, as of version
-0.3.5. I advise using caution on that platform, particularly with the more
-obscure features of the program.
+The support for big\-endian CPUs (PowerPC, for example) is new, as of
+version 0.3.5. I advise using caution on such systems, particularly with
+the more obscure features of the program.
 
 .SH "AUTHORS"
 Primary author: Roderick W. Smith (rodsmith@rodsbooks.com)
diff --git a/sgdisk.cc b/sgdisk.cc
index fc56202..fb0e2c8 100644
--- a/sgdisk.cc
+++ b/sgdisk.cc
@@ -10,9 +10,10 @@
   under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
 
 #include <stdio.h>
-#include <string>
 #include <popt.h>
 #include <errno.h>
+#include <stdint.h>
+#include <string>
 #include <iostream>
 #include <sstream>
 #include "mbr.h"
@@ -30,6 +31,8 @@
 
 int main(int argc, char *argv[]) {
    GPTData theGPT;
+   uint32_t sSize;
+   uint64_t low, high;
    int opt, numOptions = 0, saveData = 0, neverSaveData = 0;
    int partNum = 0, deletePartNum = 0, infoPartNum = 0, bsdPartNum = 0, largestPartNum = 0;
    int saveNonGPT = 1;
@@ -131,6 +134,7 @@
       if (theGPT.LoadPartitions((string) device)) {
          if ((theGPT.WhichWasUsed() == use_mbr) || (theGPT.WhichWasUsed() == use_bsd))
             saveNonGPT = 0; // flag so we don't overwrite unless directed to do so
+         sSize = theGPT.GetBlockSize();
          while ((opt = poptGetNextOpt(poptCon)) > 0) {
             switch (opt) {
                case 'A': {
@@ -254,12 +258,16 @@
                case 'n':
                   theGPT.JustLooking(0);
                   partNum = (int) GetInt(newPartInfo, 1) - 1;
-                  startSector = GetInt(newPartInfo, 2);
-                  endSector = GetInt(newPartInfo, 3);
+                  if (partNum < 0)
+                     partNum = theGPT.FindFirstFreePart();
+                  low = theGPT.FindFirstInLargest();
+                  high = theGPT.FindLastInFree(low);
+                  startSector = SIToInt(GetString(newPartInfo, 2), sSize, low, high, low);
+                  endSector = SIToInt(GetString(newPartInfo, 3), sSize, startSector, high, high);
                   if (theGPT.CreatePartition(partNum, startSector, endSector)) {
                      saveData = 1;
                   } else {
-                     cerr << "Could not create partition " << partNum << " from "
+                     cerr << "Could not create partition " << partNum + 1 << " from "
                           << startSector << " to " << endSector << "\n";
                      neverSaveData = 1;
                   } // if/else
@@ -269,6 +277,8 @@
                   theGPT.JustLooking(0);
                   startSector = theGPT.FindFirstInLargest();
                   endSector = theGPT.FindLastInFree(startSector);
+                  if (largestPartNum < 0)
+                     largestPartNum = theGPT.FindFirstFreePart();
                   if (theGPT.CreatePartition(largestPartNum - 1, startSector, endSector)) {
                      saveData = 1;
                   } else {
diff --git a/support.cc b/support.cc
index 6211fdb..ee44566 100644
--- a/support.cc
+++ b/support.cc
@@ -85,98 +85,118 @@
 // 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];
-
-   if (sSize == 0) {
-      sSize = SECTOR_SIZE;
-      cerr << "Bug: Sector size invalid in GetSectorNum()!\n";
-   } // if
+uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, uint64_t sSize,
+                      const string & prompt) {
+   uint64_t response;
+   char line[255];
 
    do {
       cout << prompt;
       cin.getline(line, 255);
-
-      // Remove leading spaces, if present
-      while (line[0] == ' ')
-         strcpy(line, &line[1]);
-
-      // If present, flag and remove leading plus sign
-      if (line[0] == '+') {
-         plusFlag = 1;
-         strcpy(line, &line[1]);
-      } // if
-
-      // If present, flag and remove leading minus sign
-      if (line[0] == '-') {
-         plusFlag = -1;
-         strcpy(line, &line[1]);
-      } // if
-
-      // Extract numeric response and, if present, suffix
-      istringstream inString(line);
-      inString >> response >> suffix;
-
-      // If no response, use default (def)
-      if (strlen(line) == 0) {
-         response = def;
-	      suffix = ' ';
-         plusFlag = 0;
-      } // if
-
-      // Set multiplier based on suffix
-      switch (suffix) {
-         case 'K':
-         case 'k':
-            mult = UINT64_C(1024) / sSize;
-            divide = sSize / UINT64_C(1024);
-            break;
-	    break;
-         case 'M':
-	      case 'm':
-            mult = UINT64_C(1048576) / sSize;
-            divide = sSize / UINT64_C(1048576);
-            break;
-         case 'G':
-         case 'g':
-            mult = UINT64_C(1073741824) / sSize;
-            break;
-         case 'T':
-	      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
-      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
-         // range) or the defaut value (if default != high, which should be
-         // the case for the first sector of a partition).
-         if (def == high)
-            response = response + low - UINT64_C(1);
-         else
-            response = response + def - UINT64_C(1);
-      } // if
-      if (plusFlag == -1) {
-         response = high - response;
-      } // if
+      response = SIToInt(line, sSize, low, high, def);
    } while ((response < low) || (response > high));
    return response;
 } // GetSectorNum()
 
+// Convert an SI value (K, M, G, T, or P) to its equivalent in
+// number of sectors. If no units are appended, interprets as the number
+// of sectors; otherwise, interprets as number of specified units and
+// converts to sectors. For instance, with 512-byte sectors, "1K" converts
+// to 2. If value includes a "+", adds low and subtracts 1; if SIValue
+// inclues a "-", subtracts from high. If SIValue is empty, returns def.
+// Returns integral sector value.
+uint64_t SIToInt(string SIValue, uint64_t sSize, uint64_t low, uint64_t high, uint64_t def) {
+   int plusFlag = 0, badInput = 0;
+   uint64_t response = def, mult = 1, divide = 1;
+   char suffix;
+
+   if (sSize == 0) {
+      sSize = SECTOR_SIZE;
+      cerr << "Bug: Sector size invalid in SIToInt()!\n";
+   } // if
+
+   // Remove leading spaces, if present
+   while (SIValue[0] == ' ')
+      SIValue.erase(0, 1);
+
+   // If present, flag and remove leading plus sign
+   if (SIValue[0] == '+') {
+      plusFlag = 1;
+      SIValue.erase(0, 1);
+   } // if
+
+   // If present, flag and remove leading minus sign
+   if (SIValue[0] == '-') {
+      plusFlag = -1;
+      SIValue.erase(0, 1);
+   } // if
+
+   // Extract numeric response and, if present, suffix
+   istringstream inString(SIValue);
+   if (((inString.peek() < '0') || (inString.peek() > '9')) && (inString.peek() != -1))
+      badInput = 1;
+   inString >> response >> suffix;
+
+   // If no response, or if response == 0, use default (def)
+   if ((SIValue.length() == 0) || (response == 0)) {
+      response = def;
+      suffix = ' ';
+      plusFlag = 0;
+   } // if
+
+    // Set multiplier based on suffix
+   switch (suffix) {
+      case 'K':
+      case 'k':
+         mult = UINT64_C(1024) / sSize;
+         divide = sSize / UINT64_C(1024);
+         break;
+      case 'M':
+      case 'm':
+         mult = UINT64_C(1048576) / sSize;
+         divide = sSize / UINT64_C(1048576);
+         break;
+      case 'G':
+      case 'g':
+         mult = UINT64_C(1073741824) / sSize;
+         break;
+      case 'T':
+      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
+   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
+      // range) or the defaut value (if default != high, which should be
+      // the case for the first sector of a partition).
+      if (def == high)
+         response = response + low - UINT64_C(1);
+      else
+         response = response + def;
+   } // if
+   if (plusFlag == -1) {
+      response = high - response;
+   } // if
+
+   if (badInput)
+      response = high + UINT64_C(1);
+
+   return response;
+} // SIToInt()
+
 // 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.
diff --git a/support.h b/support.h
index 3ae2d9f..6a4dcef 100644
--- a/support.h
+++ b/support.h
@@ -50,6 +50,7 @@
 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, uint64_t sSize, const std::string& prompt);
+uint64_t SIToInt(string SIValue, uint64_t sSize, uint64_t low, uint64_t high, uint64_t def = 0);
 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....