~ubuntu-branches/ubuntu/utopic/gdisk/utopic-proposed

« back to all changes in this revision

Viewing changes to sgdisk.cc

  • Committer: Bazaar Package Importer
  • Author(s): Guillaume Delacour
  • Date: 2011-10-03 20:46:30 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20111003204630-3cl1nosx48ofyig8
Tags: 0.8.1-1
* New upstream release
* debian/rules: Install cgdisk binary (curses based)
* debian/manpages: Install cgdisk manpage
* debian/control:
  + Remove Intel-based from description thanks Witold Baryluk
  (Closes: #642363)
  + Add libncurses5-dev in Build-Depends
* debian/copyright: Change to new DEP-5 format
* debian/patches/manpages.diff: Refresh patch to escape two hyphen

Show diffs side-by-side

added added

removed removed

Lines of Context:
9
9
/* This program is copyright (c) 2009-2011 by Roderick W. Smith. It is distributed
10
10
  under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
11
11
 
12
 
#include <stdio.h>
13
 
#include <popt.h>
14
 
#include <errno.h>
15
 
#include <stdint.h>
16
 
#include <string.h>
17
 
#include <string>
18
 
#include <iostream>
19
 
#include <sstream>
20
 
#include "mbr.h"
21
 
#include "gpt.h"
22
 
#include "support.h"
23
 
#include "parttypes.h"
24
 
#include "attributes.h"
 
12
#include "gptcl.h"
25
13
 
26
14
using namespace std;
27
15
 
28
16
#define MAX_OPTIONS 50
29
17
 
30
 
int BuildMBR(GPTData& theGPT, char* argument, int isHybrid);
31
 
int CountColons(char* argument);
32
 
 
33
 
// Extract colon-separated fields from a string....
34
 
uint64_t GetInt(const string & argument, int itemNum);
35
 
string GetString(string argument, int itemNum);
36
 
 
37
 
 
38
18
int main(int argc, char *argv[]) {
39
 
   GPTData theGPT, secondDevice;
40
 
   uint32_t sSize;
41
 
   uint64_t low, high;
42
 
   int opt, numOptions = 0, saveData = 0, neverSaveData = 0;
43
 
   int partNum = 0, deletePartNum = 0, infoPartNum = 0, bsdPartNum = 0, largestPartNum = 0;
44
 
   int saveNonGPT = 1;
45
 
   uint32_t gptPartNum = 0;
46
 
   int alignment = DEFAULT_ALIGNMENT, retval = 0, pretend = 0;
47
 
   uint32_t tableSize = 128;
48
 
   uint64_t startSector, endSector;
49
 
   uint64_t temp; // temporary variable; free to use in any case
50
 
   char *attributeOperation = NULL;
51
 
   char *device;
52
 
   char *newPartInfo = NULL, *typeCode = NULL, *partName = NULL;
53
 
   char *backupFile = NULL, *twoParts = NULL, *hybrids = NULL, *mbrParts;
54
 
   char *partGUID = NULL, *diskGUID = NULL, *outDevice = NULL;
55
 
   string cmd, typeGUID, name;
56
 
   PartType typeHelper;
57
 
 
58
 
   poptContext poptCon;
59
 
   struct poptOption theOptions[] =
60
 
   {
61
 
      {"attributes", 'A', POPT_ARG_STRING, &attributeOperation, 'A', "operate on partition attributes", "list|[partnum:show|or|nand|xor|=|set|clear|toggle|get[:bitnum|hexbitmask]]"},
62
 
      {"set-alignment", 'a', POPT_ARG_INT, &alignment, 'a', "set sector alignment", "value"},
63
 
      {"backup", 'b', POPT_ARG_STRING, &backupFile, 'b', "backup GPT to file", "file"},
64
 
      {"change-name", 'c', POPT_ARG_STRING, &partName, 'c', "change partition's name", "partnum:name"},
65
 
      {"recompute-chs", 'C', POPT_ARG_NONE, NULL, 'C', "recompute CHS values in protective/hybrid MBR", ""},
66
 
      {"delete", 'd', POPT_ARG_INT, &deletePartNum, 'd', "delete a partition", "partnum"},
67
 
      {"display-alignment", 'D', POPT_ARG_NONE, NULL, 'D', "show number of sectors per allocation block", ""},
68
 
      {"move-second-header", 'e', POPT_ARG_NONE, NULL, 'e', "move second header to end of disk", ""},
69
 
      {"end-of-largest", 'E', POPT_ARG_NONE, NULL, 'E', "show end of largest free block", ""},
70
 
      {"first-in-largest", 'f', POPT_ARG_NONE, NULL, 'f', "show start of the largest free block", ""},
71
 
      {"first-aligned-in-largest", 'F', POPT_ARG_NONE, NULL, 'F', "show start of the largest free block, aligned", ""},
72
 
      {"mbrtogpt", 'g', POPT_ARG_NONE, NULL, 'g', "convert MBR to GPT", ""},
73
 
      {"randomize-guids", 'G', POPT_ARG_NONE, NULL, 'G', "randomize disk and partition GUIDs", ""},
74
 
      {"hybrid", 'h', POPT_ARG_STRING, &hybrids, 'h', "create hybrid MBR", "partnum[:partnum...]"},
75
 
      {"info", 'i', POPT_ARG_INT, &infoPartNum, 'i', "show detailed information on partition", "partnum"},
76
 
      {"load-backup", 'l', POPT_ARG_STRING, &backupFile, 'l', "load GPT backup from file", "file"},
77
 
      {"list-types", 'L', POPT_ARG_NONE, NULL, 'L', "list known partition types", ""},
78
 
      {"gpttombr", 'm', POPT_ARG_STRING, &mbrParts, 'm', "convert GPT to MBR", "partnum[:partnum...]"},
79
 
      {"new", 'n', POPT_ARG_STRING, &newPartInfo, 'n', "create new partition", "partnum:start:end"},
80
 
      {"largest-new", 'N', POPT_ARG_INT, &largestPartNum, 'N', "create largest possible new partition", "partnum"},
81
 
      {"clear", 'o', POPT_ARG_NONE, NULL, 'o', "clear partition table", ""},
82
 
      {"print", 'p', POPT_ARG_NONE, NULL, 'p', "print partition table", ""},
83
 
      {"pretend", 'P', POPT_ARG_NONE, NULL, 'P', "make changes in memory, but don't write them", ""},
84
 
      {"transpose", 'r', POPT_ARG_STRING, &twoParts, 'r', "transpose two partitions", "partnum:partnum"},
85
 
      {"replicate", 'R', POPT_ARG_STRING, &outDevice, 'R', "replicate partition table", "device_filename"},
86
 
      {"sort", 's', POPT_ARG_NONE, NULL, 's', "sort partition table entries", ""},
87
 
      {"resize-table", 'S', POPT_ARG_INT, &tableSize, 'S', "resize partition table", "numparts"},
88
 
      {"typecode", 't', POPT_ARG_STRING, &typeCode, 't', "change partition type code", "partnum:{hexcode|GUID}"},
89
 
      {"transform-bsd", 'T', POPT_ARG_INT, &bsdPartNum, 'T', "transform BSD disklabel partition to GPT", "partnum"},
90
 
      {"partition-guid", 'u', POPT_ARG_STRING, &partGUID, 'u', "set partition GUID", "partnum:guid"},
91
 
      {"disk-guid", 'U', POPT_ARG_STRING, &diskGUID, 'U', "set disk GUID", "guid"},
92
 
      {"verify", 'v', POPT_ARG_NONE, NULL, 'v', "check partition table integrity", ""},
93
 
      {"version", 'V', POPT_ARG_NONE, NULL, 'V', "display version information", ""},
94
 
      {"zap", 'z', POPT_ARG_NONE, NULL, 'z', "zap (destroy) GPT (but not MBR) data structures", ""},
95
 
      {"zap-all", 'Z', POPT_ARG_NONE, NULL, 'Z', "zap (destroy) GPT and MBR data structures", ""},
96
 
      POPT_AUTOHELP { NULL, 0, 0, NULL, 0 }
97
 
   };
98
 
 
99
 
   // Create popt context...
100
 
   poptCon = poptGetContext(NULL, argc, (const char**) argv, theOptions, 0);
101
 
 
102
 
   poptSetOtherOptionHelp(poptCon, " [OPTION...] <device>");
103
 
 
104
 
   if (argc < 2) {
105
 
      poptPrintUsage(poptCon, stderr, 0);
106
 
      exit(1);
107
 
   }
108
 
 
109
 
   // Do one loop through the options to find the device filename and deal
110
 
   // with options that don't require a device filename....
111
 
   while ((opt = poptGetNextOpt(poptCon)) > 0) {
112
 
      switch (opt) {
113
 
         case 'A':
114
 
            cmd = GetString(attributeOperation, 1);
115
 
            if (cmd == "list")
116
 
               Attributes::ListAttributes();
117
 
            break;
118
 
         case 'L':
119
 
            typeHelper.ShowAllTypes();
120
 
            break;
121
 
         case 'P':
122
 
            pretend = 1;
123
 
            break;
124
 
         case 'V':
125
 
            cout << "GPT fdisk (sgdisk) version " << GPTFDISK_VERSION << "\n\n";
126
 
            break;
127
 
         default:
128
 
            break;
129
 
      } // switch
130
 
      numOptions++;
131
 
   } // while
132
 
 
133
 
   // Assume first non-option argument is the device filename....
134
 
   device = (char*) poptGetArg(poptCon);
135
 
   poptResetContext(poptCon);
136
 
 
137
 
   if (device != NULL) {
138
 
      theGPT.JustLooking(); // reset as necessary
139
 
      theGPT.BeQuiet(); // Tell called functions to be less verbose & interactive
140
 
      if (theGPT.LoadPartitions((string) device)) {
141
 
         if ((theGPT.WhichWasUsed() == use_mbr) || (theGPT.WhichWasUsed() == use_bsd))
142
 
            saveNonGPT = 0; // flag so we don't overwrite unless directed to do so
143
 
         sSize = theGPT.GetBlockSize();
144
 
         while ((opt = poptGetNextOpt(poptCon)) > 0) {
145
 
            switch (opt) {
146
 
               case 'A': {
147
 
                  if (cmd != "list") {
148
 
                     partNum = (int) GetInt(attributeOperation, 1) - 1;
149
 
                     if ((partNum >= 0) && (partNum < (int) theGPT.GetNumParts())) {
150
 
                        switch (theGPT.ManageAttributes(partNum, GetString(attributeOperation, 2),
151
 
                              GetString(attributeOperation, 3))) {
152
 
                           case -1:
153
 
                              saveData = 0;
154
 
                              neverSaveData = 1;
155
 
                              break;
156
 
                           case 1:
157
 
                              theGPT.JustLooking(0);
158
 
                              saveData = 1;
159
 
                              break;
160
 
                           default:
161
 
                              break;
162
 
                        } // switch
163
 
                     } else {
164
 
                        cerr << "Error: Invalid partition number " << partNum + 1 << "\n";
165
 
                        saveData = 0;
166
 
                        neverSaveData = 1;
167
 
                     } // if/else reasonable partition #
168
 
                  } // if (cmd != "list")
169
 
                  break;
170
 
               } // case 'A':
171
 
               case 'a':
172
 
                  theGPT.SetAlignment(alignment);
173
 
                  break;
174
 
               case 'b':
175
 
                  theGPT.SaveGPTBackup(backupFile);
176
 
                  free(backupFile);
177
 
                  break;
178
 
               case 'c':
179
 
                  theGPT.JustLooking(0);
180
 
                  partNum = (int) GetInt(partName, 1) - 1;
181
 
                  name = GetString(partName, 2);
182
 
                  if (theGPT.SetName(partNum, (UnicodeString) name.c_str())) {
183
 
                     saveData = 1;
184
 
                  } else {
185
 
                     cerr << "Unable to set partition " << partNum + 1
186
 
                          << "'s name to '" << GetString(partName, 2) << "'!\n";
187
 
                     neverSaveData = 1;
188
 
                  } // if/else
189
 
                  free(partName);
190
 
                  break;
191
 
               case 'C':
192
 
                  theGPT.JustLooking(0);
193
 
                  theGPT.RecomputeCHS();
194
 
                  saveData = 1;
195
 
                  break;
196
 
               case 'd':
197
 
                  theGPT.JustLooking(0);
198
 
                  if (theGPT.DeletePartition(deletePartNum - 1) == 0) {
199
 
                     cerr << "Error " << errno << " deleting partition!\n";
200
 
                     neverSaveData = 1;
201
 
                  } else saveData = 1;
202
 
                  break;
203
 
               case 'D':
204
 
                  cout << theGPT.GetAlignment() << "\n";
205
 
                  break;
206
 
               case 'e':
207
 
                  theGPT.JustLooking(0);
208
 
                  theGPT.MoveSecondHeaderToEnd();
209
 
                  saveData = 1;
210
 
                  break;
211
 
               case 'E':
212
 
                  cout << theGPT.FindLastInFree(theGPT.FindFirstInLargest()) << "\n";
213
 
                  break;
214
 
               case 'f':
215
 
                  cout << theGPT.FindFirstInLargest() << "\n";
216
 
                  break;
217
 
               case 'F':
218
 
                  temp = theGPT.FindFirstInLargest();
219
 
                  theGPT.Align(&temp);
220
 
                  cout << temp << "\n";
221
 
                  break;
222
 
               case 'g':
223
 
                  theGPT.JustLooking(0);
224
 
                  saveData = 1;
225
 
                  saveNonGPT = 1;
226
 
                  break;
227
 
               case 'G':
228
 
                  theGPT.JustLooking(0);
229
 
                  saveData = 1;
230
 
                  theGPT.RandomizeGUIDs();
231
 
                  break;
232
 
               case 'h':
233
 
                  theGPT.JustLooking(0);
234
 
                  if (BuildMBR(theGPT, hybrids, 1) == 1)
235
 
                     saveData = 1;
236
 
                  break;
237
 
               case 'i':
238
 
                  theGPT.ShowPartDetails(infoPartNum - 1);
239
 
                  break;
240
 
               case 'l':
241
 
                  if (theGPT.LoadGPTBackup((string) backupFile) == 1) {
242
 
                     theGPT.JustLooking(0);
243
 
                     saveData = 1;
244
 
                  } else {
245
 
                     saveData = 0;
246
 
                     neverSaveData = 1;
247
 
                     cerr << "Error loading backup file!\n";
248
 
                  } // else
249
 
                  free(backupFile);
250
 
                  break;
251
 
               case 'L':
252
 
                  break;
253
 
               case 'm':
254
 
                  theGPT.JustLooking(0);
255
 
                  if (BuildMBR(theGPT, mbrParts, 0) == 1) {
256
 
                     if (!pretend) {
257
 
                        if (theGPT.SaveMBR()) {
258
 
                           theGPT.DestroyGPT();
259
 
                        } else
260
 
                           cerr << "Problem saving MBR!\n";
261
 
                     } // if
262
 
                     saveNonGPT = 0;
263
 
                     pretend = 1; // Not really, but works around problem if -g is used with this...
264
 
                     saveData = 0;
265
 
                  } // if
266
 
                  break;
267
 
               case 'n':
268
 
                  theGPT.JustLooking(0);
269
 
                  partNum = (int) GetInt(newPartInfo, 1) - 1;
270
 
                  if (partNum < 0)
271
 
                     partNum = theGPT.FindFirstFreePart();
272
 
                  low = theGPT.FindFirstInLargest();
273
 
                  high = theGPT.FindLastInFree(low);
274
 
                  startSector = IeeeToInt(GetString(newPartInfo, 2), sSize, low, high, low);
275
 
                  endSector = IeeeToInt(GetString(newPartInfo, 3), sSize, startSector, high, high);
276
 
                  if (theGPT.CreatePartition(partNum, startSector, endSector)) {
277
 
                     saveData = 1;
278
 
                  } else {
279
 
                     cerr << "Could not create partition " << partNum + 1 << " from "
280
 
                          << startSector << " to " << endSector << "\n";
281
 
                     neverSaveData = 1;
282
 
                  } // if/else
283
 
                  free(newPartInfo);
284
 
                  break;
285
 
               case 'N':
286
 
                  theGPT.JustLooking(0);
287
 
                  startSector = theGPT.FindFirstInLargest();
288
 
                  endSector = theGPT.FindLastInFree(startSector);
289
 
                  if (largestPartNum < 0)
290
 
                     largestPartNum = theGPT.FindFirstFreePart();
291
 
                  if (theGPT.CreatePartition(largestPartNum - 1, startSector, endSector)) {
292
 
                     saveData = 1;
293
 
                  } else {
294
 
                     cerr << "Could not create partition " << largestPartNum << " from "
295
 
                          << startSector << " to " << endSector << "\n";
296
 
                     neverSaveData = 1;
297
 
                  } // if/else
298
 
                  break;
299
 
               case 'o':
300
 
                  theGPT.JustLooking(0);
301
 
                  theGPT.ClearGPTData();
302
 
                  saveData = 1;
303
 
                  break;
304
 
               case 'p':
305
 
                  theGPT.DisplayGPTData();
306
 
                  break;
307
 
               case 'P':
308
 
                  pretend = 1;
309
 
                  break;
310
 
               case 'r':
311
 
                  theGPT.JustLooking(0);
312
 
                  uint64_t p1, p2;
313
 
                  p1 = GetInt(twoParts, 1) - 1;
314
 
                  p2 = GetInt(twoParts, 2) - 1;
315
 
                  if (theGPT.SwapPartitions((uint32_t) p1, (uint32_t) p2) == 0) {
316
 
                     neverSaveData = 1;
317
 
                     cerr << "Cannot swap partitions " << p1 + 1 << " and " << p2 + 1 << "\n";
318
 
                  } else saveData = 1;
319
 
                  break;
320
 
               case 'R':
321
 
                  secondDevice = theGPT;
322
 
                  secondDevice.SetDisk(outDevice);
323
 
                  secondDevice.JustLooking(0);
324
 
                  secondDevice.SaveGPTData(1);
325
 
                  break;
326
 
               case 's':
327
 
                  theGPT.JustLooking(0);
328
 
                  theGPT.SortGPT();
329
 
                  saveData = 1;
330
 
                  break;
331
 
               case 'S':
332
 
                  theGPT.JustLooking(0);
333
 
                  if (theGPT.SetGPTSize(tableSize) == 0)
334
 
                     neverSaveData = 1;
335
 
                  else
336
 
                     saveData = 1;
337
 
                  break;
338
 
               case 't':
339
 
                  theGPT.JustLooking(0);
340
 
                  partNum = (int) GetInt(typeCode, 1) - 1;
341
 
                  typeHelper = GetString(typeCode, 2);
342
 
                  if ((typeHelper != (GUIDData) "00000000-0000-0000-0000-000000000000") &&
343
 
                      (theGPT.ChangePartType(partNum, typeHelper))) {
344
 
                     saveData = 1;
345
 
                  } else {
346
 
                     cerr << "Could not change partition " << partNum + 1
347
 
                          << "'s type code to " << GetString(typeCode, 2) << "!\n";
348
 
                     neverSaveData = 1;
349
 
                  } // if/else
350
 
                  free(typeCode);
351
 
                  break;
352
 
               case 'T':
353
 
                  theGPT.JustLooking(0);
354
 
                  theGPT.XFormDisklabel(bsdPartNum - 1);
355
 
                  saveData = 1;
356
 
                  break;
357
 
               case 'u':
358
 
                  theGPT.JustLooking(0);
359
 
                  saveData = 1;
360
 
                  gptPartNum = (int) GetInt(partGUID, 1) - 1;
361
 
                  theGPT.SetPartitionGUID(gptPartNum, GetString(partGUID, 2).c_str());
362
 
                  break;
363
 
               case 'U':
364
 
                  theGPT.JustLooking(0);
365
 
                  saveData = 1;
366
 
                  theGPT.SetDiskGUID(diskGUID);
367
 
                  break;
368
 
               case 'v':
369
 
                  theGPT.Verify();
370
 
                  break;
371
 
               case 'z':
372
 
                  if (!pretend) {
373
 
                     theGPT.DestroyGPT();
374
 
                  } // if
375
 
                  saveNonGPT = 0;
376
 
                  saveData = 0;
377
 
                  break;
378
 
               case 'Z':
379
 
                  if (!pretend) {
380
 
                     theGPT.DestroyGPT();
381
 
                     theGPT.DestroyMBR();
382
 
                  } // if
383
 
                  saveNonGPT = 0;
384
 
                  saveData = 0;
385
 
                  break;
386
 
               default:
387
 
                  cerr << "Unknown option (-" << opt << ")!\n";
388
 
                  break;
389
 
            } // switch
390
 
         } // while
391
 
         if ((saveData) && (!neverSaveData) && (saveNonGPT) && (!pretend)) {
392
 
            theGPT.SaveGPTData(1);
393
 
         }
394
 
         if (saveData && (!saveNonGPT)) {
395
 
            cout << "Non-GPT disk; not saving changes. Use -g to override.\n";
396
 
            retval = 3;
397
 
         } // if
398
 
         if (neverSaveData) {
399
 
            cerr << "Error encountered; not saving changes.\n";
400
 
            retval = 4;
401
 
         } // if
402
 
      } else { // if loaded OK
403
 
         poptResetContext(poptCon);
404
 
         // Do a few types of operations even if there are problems....
405
 
         while ((opt = poptGetNextOpt(poptCon)) > 0) {
406
 
            switch (opt) {
407
 
               case 'v':
408
 
                  cout << "Verification may miss some problems or report too many!\n";
409
 
                  theGPT.Verify();
410
 
                  break;
411
 
               case 'z':
412
 
                  if (!pretend) {
413
 
                     theGPT.DestroyGPT();
414
 
                  } // if
415
 
                  saveNonGPT = 0;
416
 
                  saveData = 0;
417
 
                  break;
418
 
               case 'Z':
419
 
                  if (!pretend) {
420
 
                     theGPT.DestroyGPT();
421
 
                     theGPT.DestroyMBR();
422
 
                  } // if
423
 
                  saveNonGPT = 0;
424
 
                  saveData = 0;
425
 
                  break;
426
 
            } // switch
427
 
         } // while
428
 
         retval = 2;
429
 
      } // if/else loaded OK
430
 
   } // if (device != NULL)
431
 
   poptFreeContext(poptCon);
432
 
 
433
 
   return retval;
 
19
   GPTDataCL theGPT;
 
20
   return theGPT.DoOptions(argc, argv);
434
21
} // main
435
 
 
436
 
// Create a hybrid or regular MBR from GPT data structures
437
 
int BuildMBR(GPTData & theGPT, char* argument, int isHybrid) {
438
 
   int numParts, allOK = 1, i, origPartNum;
439
 
   MBRPart newPart;
440
 
   BasicMBRData newMBR;
441
 
 
442
 
   if ((&theGPT != NULL) && (argument != NULL)) {
443
 
      numParts = CountColons(argument) + 1;
444
 
      if (numParts <= (4 - isHybrid)) {
445
 
         newMBR.SetDisk(theGPT.GetDisk());
446
 
         for (i = 0; i < numParts; i++) {
447
 
            origPartNum = GetInt(argument, i + 1) - 1;
448
 
            if (theGPT.IsUsedPartNum(origPartNum)) {
449
 
               newPart.SetInclusion(PRIMARY);
450
 
               newPart.SetLocation(theGPT[origPartNum].GetFirstLBA(),
451
 
                                 theGPT[origPartNum].GetLengthLBA());
452
 
               newPart.SetStatus(0);
453
 
               newPart.SetType((uint8_t)(theGPT[origPartNum].GetHexType() / 0x0100));
454
 
               newMBR.AddPart(i + isHybrid, newPart);
455
 
            } else {
456
 
               cerr << "Partition " << origPartNum << " does not exist! Aborting operation!\n";
457
 
               allOK = 0;
458
 
            } // if/else
459
 
         } // for
460
 
         if (isHybrid) {
461
 
            newPart.SetInclusion(PRIMARY);
462
 
            newPart.SetLocation(1, newMBR.FindLastInFree(1));
463
 
            newPart.SetStatus(0);
464
 
            newPart.SetType(0xEE);
465
 
            newMBR.AddPart(0, newPart);
466
 
         } // if
467
 
         theGPT.SetProtectiveMBR(newMBR);
468
 
      } else allOK = 0;
469
 
   } else allOK = 0;
470
 
   if (!allOK)
471
 
      cerr << "Problem creating MBR!\n";
472
 
   return allOK;
473
 
} // BuildMBR()
474
 
 
475
 
// Returns the number of colons in argument string, ignoring the
476
 
// first character (thus, a leading colon is ignored, as GetString()
477
 
// does).
478
 
int CountColons(char* argument) {
479
 
   int num = 0;
480
 
 
481
 
   while ((argument[0] != '\0') && (argument = strchr(&argument[1], ':')))
482
 
      num++;
483
 
 
484
 
   return num;
485
 
} // CountColons()
486
 
 
487
 
// Extract integer data from argument string, which should be colon-delimited
488
 
uint64_t GetInt(const string & argument, int itemNum) {
489
 
   uint64_t retval;
490
 
   
491
 
   istringstream inString(GetString(argument, itemNum));
492
 
   inString >> retval;
493
 
   return retval;
494
 
} // GetInt()
495
 
 
496
 
// Extract string data from argument string, which should be colon-delimited
497
 
// If string begins with a colon, that colon is skipped in the counting. If an
498
 
// invalid itemNum is specified, returns an empty string.
499
 
string GetString(string argument, int itemNum) {
500
 
   size_t startPos = 0, endPos = 0;
501
 
   string retVal = "";
502
 
   int foundLast = 0;
503
 
   int numFound = 0;
504
 
   
505
 
   if (argument[0] == ':')
506
 
      argument.erase(0, 1);
507
 
   while ((numFound < itemNum) && (!foundLast)) {
508
 
      endPos = argument.find(':', startPos);
509
 
      numFound++;
510
 
      if (endPos == string::npos) {
511
 
         foundLast = 1;
512
 
         endPos = argument.length();
513
 
      } else if (numFound < itemNum) {
514
 
         startPos = endPos + 1;
515
 
      } // if/elseif
516
 
   } // while
517
 
   if ((numFound == itemNum) && (numFound > 0))
518
 
      retVal = argument.substr(startPos, endPos - startPos);
519
 
   
520
 
   return retVal;
521
 
} // GetString()