1cf200d32Sopenharmony_ci// support.cc
2cf200d32Sopenharmony_ci// Non-class support functions for gdisk program.
3cf200d32Sopenharmony_ci// Primarily by Rod Smith, February 2009, but with a few functions
4cf200d32Sopenharmony_ci// copied from other sources (see attributions below).
5cf200d32Sopenharmony_ci
6cf200d32Sopenharmony_ci/* This program is copyright (c) 2009-2024 by Roderick W. Smith. It is distributed
7cf200d32Sopenharmony_ci  under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
8cf200d32Sopenharmony_ci
9cf200d32Sopenharmony_ci#define __STDC_LIMIT_MACROS
10cf200d32Sopenharmony_ci#ifndef __STDC_CONSTANT_MACROS
11cf200d32Sopenharmony_ci#define __STDC_CONSTANT_MACROS
12cf200d32Sopenharmony_ci#endif
13cf200d32Sopenharmony_ci#ifndef __STDC_FORMAT_MACROS
14cf200d32Sopenharmony_ci#define __STDC_FORMAT_MACROS
15cf200d32Sopenharmony_ci#endif
16cf200d32Sopenharmony_ci
17cf200d32Sopenharmony_ci#include <inttypes.h>
18cf200d32Sopenharmony_ci#include <stdio.h>
19cf200d32Sopenharmony_ci#include <stdint.h>
20cf200d32Sopenharmony_ci#include <errno.h>
21cf200d32Sopenharmony_ci#include <fcntl.h>
22cf200d32Sopenharmony_ci#include <string.h>
23cf200d32Sopenharmony_ci#include <sys/stat.h>
24cf200d32Sopenharmony_ci#include <string>
25cf200d32Sopenharmony_ci#include <cctype>
26cf200d32Sopenharmony_ci#include <algorithm>
27cf200d32Sopenharmony_ci#include <iostream>
28cf200d32Sopenharmony_ci#include <sstream>
29cf200d32Sopenharmony_ci#include "support.h"
30cf200d32Sopenharmony_ci
31cf200d32Sopenharmony_ci#include <sys/types.h>
32cf200d32Sopenharmony_ci
33cf200d32Sopenharmony_ci// As of 1/2010, BLKPBSZGET is very new, so I'm explicitly defining it if
34cf200d32Sopenharmony_ci// it's not already defined. This should become unnecessary in the future.
35cf200d32Sopenharmony_ci// Note that this is a Linux-only ioctl....
36cf200d32Sopenharmony_ci#ifndef BLKPBSZGET
37cf200d32Sopenharmony_ci#define BLKPBSZGET _IO(0x12,123)
38cf200d32Sopenharmony_ci#endif
39cf200d32Sopenharmony_ci
40cf200d32Sopenharmony_ciusing namespace std;
41cf200d32Sopenharmony_ci
42cf200d32Sopenharmony_ci// Reads a string from stdin, returning it as a C++-style string.
43cf200d32Sopenharmony_ci// Note that the returned string will NOT include the carriage return
44cf200d32Sopenharmony_ci// entered by the user.
45cf200d32Sopenharmony_ci#ifdef EFI
46cf200d32Sopenharmony_ciextern int __sscanf( const char * str , const char * format , ... ) ;
47cf200d32Sopenharmony_cistring ReadString(void) {
48cf200d32Sopenharmony_ci   string inString;
49cf200d32Sopenharmony_ci   char efiString[256];
50cf200d32Sopenharmony_ci   int stringLength;
51cf200d32Sopenharmony_ci
52cf200d32Sopenharmony_ci   if (fgets(efiString, 255, stdin) != NULL) {
53cf200d32Sopenharmony_ci      stringLength = strlen(efiString);
54cf200d32Sopenharmony_ci      if ((stringLength > 0) && (efiString[stringLength - 1] == '\n'))
55cf200d32Sopenharmony_ci          efiString[stringLength - 1] = '\0';
56cf200d32Sopenharmony_ci      inString = efiString;
57cf200d32Sopenharmony_ci   } else {
58cf200d32Sopenharmony_ci      inString = "";
59cf200d32Sopenharmony_ci   }
60cf200d32Sopenharmony_ci   return inString;
61cf200d32Sopenharmony_ci} // ReadString()
62cf200d32Sopenharmony_ci#else
63cf200d32Sopenharmony_cistring ReadString(void) {
64cf200d32Sopenharmony_ci   string inString;
65cf200d32Sopenharmony_ci
66cf200d32Sopenharmony_ci   cout << flush;
67cf200d32Sopenharmony_ci   getline(cin, inString);
68cf200d32Sopenharmony_ci   if (!cin.good())
69cf200d32Sopenharmony_ci      exit(5);
70cf200d32Sopenharmony_ci   return inString;
71cf200d32Sopenharmony_ci} // ReadString()
72cf200d32Sopenharmony_ci#endif
73cf200d32Sopenharmony_ci
74cf200d32Sopenharmony_ci// Get a numeric value from the user, between low and high (inclusive).
75cf200d32Sopenharmony_ci// Keeps looping until the user enters a value within that range.
76cf200d32Sopenharmony_ci// If user provides no input, def (default value) is returned.
77cf200d32Sopenharmony_ci// (If def is outside of the low-high range, an explicit response
78cf200d32Sopenharmony_ci// is required.)
79cf200d32Sopenharmony_ciuint64_t GetNumber(uint64_t low, uint64_t high, uint64_t def, const string & prompt) {
80cf200d32Sopenharmony_ci   uint64_t response, num;
81cf200d32Sopenharmony_ci   char line[255];
82cf200d32Sopenharmony_ci
83cf200d32Sopenharmony_ci   if (low != high) { // bother only if low and high differ...
84cf200d32Sopenharmony_ci      do {
85cf200d32Sopenharmony_ci         cout << prompt << flush;
86cf200d32Sopenharmony_ci         cin.getline(line, 255);
87cf200d32Sopenharmony_ci         if (!cin.good())
88cf200d32Sopenharmony_ci            exit(5);
89cf200d32Sopenharmony_ci         num = sscanf(line, "%" PRIu64, &response);
90cf200d32Sopenharmony_ci         if (num == 1) { // user provided a response
91cf200d32Sopenharmony_ci            if ((response < low) || (response > high))
92cf200d32Sopenharmony_ci               cout << "Value out of range\n";
93cf200d32Sopenharmony_ci         } else { // user hit enter; return default
94cf200d32Sopenharmony_ci            response = def;
95cf200d32Sopenharmony_ci         } // if/else
96cf200d32Sopenharmony_ci      } while ((response < low) || (response > high));
97cf200d32Sopenharmony_ci   } else { // low == high, so return this value
98cf200d32Sopenharmony_ci      cout << "Using " << low << "\n";
99cf200d32Sopenharmony_ci      response = low;
100cf200d32Sopenharmony_ci   } // else
101cf200d32Sopenharmony_ci   return (response);
102cf200d32Sopenharmony_ci} // GetNumber()
103cf200d32Sopenharmony_ci
104cf200d32Sopenharmony_ci// Gets a Y/N response (and converts lowercase to uppercase)
105cf200d32Sopenharmony_cichar GetYN(void) {
106cf200d32Sopenharmony_ci   char response;
107cf200d32Sopenharmony_ci   string line;
108cf200d32Sopenharmony_ci   bool again = 0 ;
109cf200d32Sopenharmony_ci
110cf200d32Sopenharmony_ci   do {
111cf200d32Sopenharmony_ci      if ( again ) { cout << "Your option? " ; }
112cf200d32Sopenharmony_ci      again = 1 ;
113cf200d32Sopenharmony_ci      cout << "(Y/N): " << flush;
114cf200d32Sopenharmony_ci      line = ReadString();
115cf200d32Sopenharmony_ci      response = toupper(line[0]);
116cf200d32Sopenharmony_ci   } while ((response != 'Y') && (response != 'N'));
117cf200d32Sopenharmony_ci   return response;
118cf200d32Sopenharmony_ci} // GetYN(void)
119cf200d32Sopenharmony_ci
120cf200d32Sopenharmony_ci// Convert an IEEE-1541-2002 value (K, M, G, T, P, or E) to its equivalent in
121cf200d32Sopenharmony_ci// number of sectors. If no units are appended, interprets as the number
122cf200d32Sopenharmony_ci// of sectors; otherwise, interprets as number of specified units and
123cf200d32Sopenharmony_ci// converts to sectors. For instance, with 512-byte sectors, "1K" converts
124cf200d32Sopenharmony_ci// to 2. If value includes a "+", adds low and subtracts 1; if inValue
125cf200d32Sopenharmony_ci// inclues a "-", subtracts from high. If IeeeValue is empty, returns def.
126cf200d32Sopenharmony_ci// Returns final sector value. In case inValue is invalid, returns 0 (a
127cf200d32Sopenharmony_ci// sector value that's always in use on GPT and therefore invalid); and if
128cf200d32Sopenharmony_ci// inValue works out to something outside the range low-high, returns the
129cf200d32Sopenharmony_ci// computed value; the calling function is responsible for checking the
130cf200d32Sopenharmony_ci// validity of this value.
131cf200d32Sopenharmony_ci// If inValue contains a decimal number (e.g., "9.5G"), quietly truncate it
132cf200d32Sopenharmony_ci// (to "9G" in this example).
133cf200d32Sopenharmony_ci// NOTE: There's a difference in how GCC and VC++ treat oversized values
134cf200d32Sopenharmony_ci// (say, "999999999999999999999") read via the ">>" operator; GCC turns
135cf200d32Sopenharmony_ci// them into the maximum value for the type, whereas VC++ turns them into
136cf200d32Sopenharmony_ci// 0 values. The result is that IeeeToInt() returns UINT64_MAX when
137cf200d32Sopenharmony_ci// compiled with GCC (and so the value is rejected), whereas when VC++
138cf200d32Sopenharmony_ci// is used, the default value is returned.
139cf200d32Sopenharmony_ciuint64_t IeeeToInt(string inValue, uint64_t sSize, uint64_t low, uint64_t high, uint32_t sectorAlignment, uint64_t def) {
140cf200d32Sopenharmony_ci   uint64_t response = def, bytesPerUnit, mult = 1, divide = 1;
141cf200d32Sopenharmony_ci   size_t foundAt = 0;
142cf200d32Sopenharmony_ci   char suffix = ' ', plusFlag = ' ';
143cf200d32Sopenharmony_ci   string suffixes = "KMGTPE";
144cf200d32Sopenharmony_ci   int badInput = 0; // flag bad input; once this goes to 1, other values are irrelevant
145cf200d32Sopenharmony_ci
146cf200d32Sopenharmony_ci   if (sSize == 0) {
147cf200d32Sopenharmony_ci      sSize = SECTOR_SIZE;
148cf200d32Sopenharmony_ci      cerr << "Bug: Sector size invalid in IeeeToInt()!\n";
149cf200d32Sopenharmony_ci   } // if
150cf200d32Sopenharmony_ci
151cf200d32Sopenharmony_ci   // Remove leading spaces, if present
152cf200d32Sopenharmony_ci   while (inValue[0] == ' ')
153cf200d32Sopenharmony_ci      inValue.erase(0, 1);
154cf200d32Sopenharmony_ci
155cf200d32Sopenharmony_ci   // If present, flag and remove leading plus or minus sign
156cf200d32Sopenharmony_ci   if ((inValue[0] == '+') || (inValue[0] == '-')) {
157cf200d32Sopenharmony_ci      plusFlag = inValue[0];
158cf200d32Sopenharmony_ci      inValue.erase(0, 1);
159cf200d32Sopenharmony_ci   } // if
160cf200d32Sopenharmony_ci
161cf200d32Sopenharmony_ci   // Extract numeric response and, if present, suffix
162cf200d32Sopenharmony_ci   istringstream inString(inValue);
163cf200d32Sopenharmony_ci   if (((inString.peek() < '0') || (inString.peek() > '9')) && (inString.peek() != -1))
164cf200d32Sopenharmony_ci      badInput = 1;
165cf200d32Sopenharmony_ci   inString >> response >> suffix;
166cf200d32Sopenharmony_ci   suffix = toupper(suffix);
167cf200d32Sopenharmony_ci   foundAt = suffixes.find(suffix);
168cf200d32Sopenharmony_ci   // If suffix is invalid, try to find a valid one. Done because users
169cf200d32Sopenharmony_ci   // sometimes enter decimal numbers; when they do, suffix becomes
170cf200d32Sopenharmony_ci   // '.', and we need to truncate the number and find the real suffix.
171cf200d32Sopenharmony_ci   while (foundAt > (suffixes.length() - 1) && inString.peek() != -1) {
172cf200d32Sopenharmony_ci      inString >> suffix;
173cf200d32Sopenharmony_ci      foundAt = suffixes.find(suffix);
174cf200d32Sopenharmony_ci      suffix = toupper(suffix);
175cf200d32Sopenharmony_ci   }
176cf200d32Sopenharmony_ci   // If no response, or if response == 0, use default (def)
177cf200d32Sopenharmony_ci   if ((inValue.length() == 0) || (response == 0)) {
178cf200d32Sopenharmony_ci      response = def;
179cf200d32Sopenharmony_ci      suffix = ' ';
180cf200d32Sopenharmony_ci      plusFlag = ' ';
181cf200d32Sopenharmony_ci   } // if
182cf200d32Sopenharmony_ci
183cf200d32Sopenharmony_ci   // Find multiplication and division factors for the suffix
184cf200d32Sopenharmony_ci   if (foundAt != string::npos) {
185cf200d32Sopenharmony_ci      bytesPerUnit = UINT64_C(1) << (10 * (foundAt + 1));
186cf200d32Sopenharmony_ci      mult = bytesPerUnit / sSize;
187cf200d32Sopenharmony_ci      divide = sSize / bytesPerUnit;
188cf200d32Sopenharmony_ci   } // if
189cf200d32Sopenharmony_ci
190cf200d32Sopenharmony_ci   // Adjust response based on multiplier and plus flag, if present
191cf200d32Sopenharmony_ci   if (mult > 1) {
192cf200d32Sopenharmony_ci      if (response > (UINT64_MAX / mult))
193cf200d32Sopenharmony_ci         badInput = 1;
194cf200d32Sopenharmony_ci      else
195cf200d32Sopenharmony_ci         response *= mult;
196cf200d32Sopenharmony_ci   } else if (divide > 1) {
197cf200d32Sopenharmony_ci         response /= divide;
198cf200d32Sopenharmony_ci   } // if/elseif
199cf200d32Sopenharmony_ci
200cf200d32Sopenharmony_ci   if (plusFlag == '+') {
201cf200d32Sopenharmony_ci      // Recompute response based on low part of range (if default is within
202cf200d32Sopenharmony_ci      // sectorAlignment sectors of high, which should be the case when
203cf200d32Sopenharmony_ci      // prompting for the end of a range) or the defaut value (if default is
204cf200d32Sopenharmony_ci      // further away from the high value, which should be the case for the
205cf200d32Sopenharmony_ci      // first sector of a partition).
206cf200d32Sopenharmony_ci      if ((high - def) < sectorAlignment) {
207cf200d32Sopenharmony_ci         if (response > 0)
208cf200d32Sopenharmony_ci            response--;
209cf200d32Sopenharmony_ci         if (response > (UINT64_MAX - low))
210cf200d32Sopenharmony_ci            badInput = 1;
211cf200d32Sopenharmony_ci         else
212cf200d32Sopenharmony_ci            response = response + low;
213cf200d32Sopenharmony_ci      } else {
214cf200d32Sopenharmony_ci         if (response > (UINT64_MAX - def))
215cf200d32Sopenharmony_ci            badInput = 1;
216cf200d32Sopenharmony_ci         else
217cf200d32Sopenharmony_ci            response = response + def;
218cf200d32Sopenharmony_ci      } // if/else
219cf200d32Sopenharmony_ci   } else if (plusFlag == '-') {
220cf200d32Sopenharmony_ci      if (response > high)
221cf200d32Sopenharmony_ci         badInput = 1;
222cf200d32Sopenharmony_ci      else
223cf200d32Sopenharmony_ci         response = high - response;
224cf200d32Sopenharmony_ci   } // if
225cf200d32Sopenharmony_ci
226cf200d32Sopenharmony_ci   if (badInput)
227cf200d32Sopenharmony_ci      response = UINT64_C(0);
228cf200d32Sopenharmony_ci
229cf200d32Sopenharmony_ci   return response;
230cf200d32Sopenharmony_ci} // IeeeToInt()
231cf200d32Sopenharmony_ci
232cf200d32Sopenharmony_ci// Takes a size and converts this to a size in IEEE-1541-2002 units (KiB, MiB,
233cf200d32Sopenharmony_ci// GiB, TiB, PiB, or EiB), returned in C++ string form. The size is either in
234cf200d32Sopenharmony_ci// units of the sector size or, if that parameter is omitted, in bytes.
235cf200d32Sopenharmony_ci// (sectorSize defaults to 1). Note that this function uses peculiar
236cf200d32Sopenharmony_ci// manual computation of decimal value rather than simply setting
237cf200d32Sopenharmony_ci// theValue.precision() because this isn't possible using the available
238cf200d32Sopenharmony_ci// EFI library.
239cf200d32Sopenharmony_cistring BytesToIeee(uint64_t size, uint32_t sectorSize) {
240cf200d32Sopenharmony_ci   uint64_t sizeInIeee;
241cf200d32Sopenharmony_ci   uint64_t previousIeee;
242cf200d32Sopenharmony_ci   float decimalIeee;
243cf200d32Sopenharmony_ci   uint64_t index = 0;
244cf200d32Sopenharmony_ci   string units, prefixes = " KMGTPEZ";
245cf200d32Sopenharmony_ci   ostringstream theValue;
246cf200d32Sopenharmony_ci
247cf200d32Sopenharmony_ci   sizeInIeee = previousIeee = size * (uint64_t) sectorSize;
248cf200d32Sopenharmony_ci   while ((sizeInIeee > 1024) && (index < (prefixes.length() - 1))) {
249cf200d32Sopenharmony_ci      index++;
250cf200d32Sopenharmony_ci      previousIeee = sizeInIeee;
251cf200d32Sopenharmony_ci      sizeInIeee /= 1024;
252cf200d32Sopenharmony_ci   } // while
253cf200d32Sopenharmony_ci   if (prefixes[index] == ' ') {
254cf200d32Sopenharmony_ci      theValue << sizeInIeee << " bytes";
255cf200d32Sopenharmony_ci   } else {
256cf200d32Sopenharmony_ci      units = "  iB";
257cf200d32Sopenharmony_ci      units[1] = prefixes[index];
258cf200d32Sopenharmony_ci      decimalIeee = ((float) previousIeee -
259cf200d32Sopenharmony_ci                     ((float) sizeInIeee * 1024.0) + 51.2) / 102.4;
260cf200d32Sopenharmony_ci      if (decimalIeee >= 10.0) {
261cf200d32Sopenharmony_ci         decimalIeee = 0.0;
262cf200d32Sopenharmony_ci         sizeInIeee++;
263cf200d32Sopenharmony_ci      }
264cf200d32Sopenharmony_ci      theValue << sizeInIeee << "." << (uint32_t) decimalIeee << units;
265cf200d32Sopenharmony_ci   } // if/else
266cf200d32Sopenharmony_ci   return theValue.str();
267cf200d32Sopenharmony_ci} // BytesToIeee()
268cf200d32Sopenharmony_ci
269cf200d32Sopenharmony_ci// Converts two consecutive characters in the input string into a
270cf200d32Sopenharmony_ci// number, interpreting the string as a hexadecimal number, starting
271cf200d32Sopenharmony_ci// at the specified position.
272cf200d32Sopenharmony_ciunsigned char StrToHex(const string & input, unsigned int position) {
273cf200d32Sopenharmony_ci   unsigned char retval = 0x00;
274cf200d32Sopenharmony_ci   unsigned int temp;
275cf200d32Sopenharmony_ci
276cf200d32Sopenharmony_ci   if (input.length() > position) {
277cf200d32Sopenharmony_ci      sscanf(input.substr(position, 2).c_str(), "%x", &temp);
278cf200d32Sopenharmony_ci      retval = (unsigned char) temp;
279cf200d32Sopenharmony_ci   } // if
280cf200d32Sopenharmony_ci   return retval;
281cf200d32Sopenharmony_ci} // StrToHex()
282cf200d32Sopenharmony_ci
283cf200d32Sopenharmony_ci// Returns 1 if input can be interpreted as a hexadecimal number --
284cf200d32Sopenharmony_ci// all characters must be spaces, digits, or letters A-F (upper- or
285cf200d32Sopenharmony_ci// lower-case), with at least one valid hexadecimal digit; with the
286cf200d32Sopenharmony_ci// exception of the first two characters, which may be "0x"; otherwise
287cf200d32Sopenharmony_ci// returns 0.
288cf200d32Sopenharmony_ciint IsHex(string input) {
289cf200d32Sopenharmony_ci   int isHex = 1, foundHex = 0, i;
290cf200d32Sopenharmony_ci
291cf200d32Sopenharmony_ci   if (input.substr(0, 2) == "0x")
292cf200d32Sopenharmony_ci      input.erase(0, 2);
293cf200d32Sopenharmony_ci   for (i = 0; i < (int) input.length(); i++) {
294cf200d32Sopenharmony_ci      if ((input[i] < '0') || (input[i] > '9')) {
295cf200d32Sopenharmony_ci         if ((input[i] < 'A') || (input[i] > 'F')) {
296cf200d32Sopenharmony_ci            if ((input[i] < 'a') || (input[i] > 'f')) {
297cf200d32Sopenharmony_ci               if ((input[i] != ' ') && (input[i] != '\n')) {
298cf200d32Sopenharmony_ci                  isHex = 0;
299cf200d32Sopenharmony_ci               }
300cf200d32Sopenharmony_ci            } else foundHex = 1;
301cf200d32Sopenharmony_ci         } else foundHex = 1;
302cf200d32Sopenharmony_ci      } else foundHex = 1;
303cf200d32Sopenharmony_ci   } // for
304cf200d32Sopenharmony_ci   if (!foundHex)
305cf200d32Sopenharmony_ci      isHex = 0;
306cf200d32Sopenharmony_ci   return isHex;
307cf200d32Sopenharmony_ci} // IsHex()
308cf200d32Sopenharmony_ci
309cf200d32Sopenharmony_ci// Return 1 if the CPU architecture is little endian, 0 if it's big endian....
310cf200d32Sopenharmony_ciint IsLittleEndian(void) {
311cf200d32Sopenharmony_ci   int littleE = 1; // assume little-endian (Intel-style)
312cf200d32Sopenharmony_ci   union {
313cf200d32Sopenharmony_ci      uint32_t num;
314cf200d32Sopenharmony_ci      unsigned char uc[sizeof(uint32_t)];
315cf200d32Sopenharmony_ci   } endian;
316cf200d32Sopenharmony_ci
317cf200d32Sopenharmony_ci   endian.num = 1;
318cf200d32Sopenharmony_ci   if (endian.uc[0] != (unsigned char) 1) {
319cf200d32Sopenharmony_ci      littleE = 0;
320cf200d32Sopenharmony_ci   } // if
321cf200d32Sopenharmony_ci   return (littleE);
322cf200d32Sopenharmony_ci} // IsLittleEndian()
323cf200d32Sopenharmony_ci
324cf200d32Sopenharmony_ci// Reverse the byte order of theValue; numBytes is number of bytes
325cf200d32Sopenharmony_civoid ReverseBytes(void* theValue, int numBytes) {
326cf200d32Sopenharmony_ci   char* tempValue = NULL;
327cf200d32Sopenharmony_ci   int i;
328cf200d32Sopenharmony_ci
329cf200d32Sopenharmony_ci   tempValue = new char [numBytes];
330cf200d32Sopenharmony_ci   if (tempValue != NULL) {
331cf200d32Sopenharmony_ci      memcpy(tempValue, theValue, numBytes);
332cf200d32Sopenharmony_ci      for (i = 0; i < numBytes; i++)
333cf200d32Sopenharmony_ci         ((char*) theValue)[i] = tempValue[numBytes - i - 1];
334cf200d32Sopenharmony_ci      delete[] tempValue;
335cf200d32Sopenharmony_ci   } else {
336cf200d32Sopenharmony_ci      cerr << "Could not allocate memory in ReverseBytes()! Terminating\n";
337cf200d32Sopenharmony_ci      exit(1);
338cf200d32Sopenharmony_ci   } // if/else
339cf200d32Sopenharmony_ci} // ReverseBytes()
340cf200d32Sopenharmony_ci
341cf200d32Sopenharmony_ci// On Windows, display a warning and ask whether to continue. If the user elects
342cf200d32Sopenharmony_ci// not to continue, exit immediately.
343cf200d32Sopenharmony_civoid WinWarning(void) {
344cf200d32Sopenharmony_ci   #ifdef _WIN32
345cf200d32Sopenharmony_ci   cout << "\a************************************************************************\n"
346cf200d32Sopenharmony_ci        << "Most versions of Windows cannot boot from a GPT disk except on a UEFI-based\n"
347cf200d32Sopenharmony_ci        << "computer, and most varieties prior to Vista cannot read GPT disks. Therefore,\n"
348cf200d32Sopenharmony_ci        << "you should exit now unless you understand the implications of converting MBR\n"
349cf200d32Sopenharmony_ci        << "to GPT or creating a new GPT disk layout!\n"
350cf200d32Sopenharmony_ci        << "************************************************************************\n\n";
351cf200d32Sopenharmony_ci   cout << "Are you SURE you want to continue? ";
352cf200d32Sopenharmony_ci   if (GetYN() != 'Y')
353cf200d32Sopenharmony_ci      exit(0);
354cf200d32Sopenharmony_ci   #endif
355cf200d32Sopenharmony_ci} // WinWarning()
356cf200d32Sopenharmony_ci
357cf200d32Sopenharmony_ci// Returns the input string in lower case
358cf200d32Sopenharmony_cistring ToLower(const string& input) {
359cf200d32Sopenharmony_ci   string lower = input; // allocate correct size through copy
360cf200d32Sopenharmony_ci
361cf200d32Sopenharmony_ci   transform(input.begin(), input.end(), lower.begin(), ::tolower);
362cf200d32Sopenharmony_ci   return lower;
363cf200d32Sopenharmony_ci} // ToLower()
364