MayaChemTools

   1 #!/usr/bin/perl -w
   2 #
   3 # File: MergeTextFilesWithSD.pl
   4 # Author: Manish Sud <msud@san.rr.com>
   5 #
   6 # Copyright (C) 2024 Manish Sud. All rights reserved.
   7 #
   8 # This file is part of MayaChemTools.
   9 #
  10 # MayaChemTools is free software; you can redistribute it and/or modify it under
  11 # the terms of the GNU Lesser General Public License as published by the Free
  12 # Software Foundation; either version 3 of the License, or (at your option) any
  13 # later version.
  14 #
  15 # MayaChemTools is distributed in the hope that it will be useful, but without
  16 # any warranty; without even the implied warranty of merchantability of fitness
  17 # for a particular purpose.  See the GNU Lesser General Public License for more
  18 # details.
  19 #
  20 # You should have received a copy of the GNU Lesser General Public License
  21 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or
  22 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330,
  23 # Boston, MA, 02111-1307, USA.
  24 #
  25 
  26 use strict;
  27 use FindBin; use lib "$FindBin::Bin/../lib";
  28 use Getopt::Long;
  29 use File::Basename;
  30 use Text::ParseWords;
  31 use Benchmark;
  32 use FileHandle;
  33 use SDFileUtil;
  34 use FileUtil;
  35 use TextUtil;
  36 
  37 my($ScriptName, %Options, $StartTime, $EndTime, $TotalTime);
  38 
  39 # Autoflush STDOUT
  40 $| = 1;
  41 
  42 # Starting message...
  43 $ScriptName = basename $0;
  44 print "\n$ScriptName:Starting...\n\n";
  45 $StartTime = new Benchmark;
  46 
  47 # Get the options and setup script...
  48 SetupScriptUsage();
  49 if ($Options{help} || @ARGV < 1) {
  50   die GetUsageFromPod("$FindBin::Bin/$ScriptName");
  51 }
  52 
  53 my($SDFile, @TextFilesList);
  54 @TextFilesList = ExpandFileNames(\@ARGV, "csv tsv");
  55 
  56 if (@TextFilesList < 2) {
  57   die "Error: Specify one or more text files.\n";
  58 }
  59 $SDFile = shift @TextFilesList;
  60 
  61 # Process options...
  62 print "Processing options...\n";
  63 my(%OptionsInfo);
  64 ProcessOptions();
  65 
  66 # Setup information about input files...
  67 print "Checking input SD and text files...\n";
  68 my(%TextFilesInfo);
  69 ProcessSDFileInfo();
  70 RetrieveTextFilesInfo();
  71 RetrieveColumnsAndKeysInfo();
  72 
  73 # Merge files...
  74 print "\nGenerating new SD file $OptionsInfo{NewSDFile}...\n";
  75 MergeTextFilesWithSD();
  76 
  77 print "\n$ScriptName:Done...\n\n";
  78 
  79 $EndTime = new Benchmark;
  80 $TotalTime = timediff ($EndTime, $StartTime);
  81 print "Total time: ", timestr($TotalTime), "\n";
  82 
  83 ###############################################################################
  84 
  85 # Merge all valid Text files with SD file...
  86 sub MergeTextFilesWithSD {
  87   my($Index, $Line);
  88 
  89   open NEWSDFILE, ">$OptionsInfo{NewSDFile}" or die "Error: Couldn't open $OptionsInfo{NewSDFile}: $! \n";
  90 
  91   open SDFILE, "$SDFile" or die "Error: Couldn't open $SDFile: $! \n";
  92 
  93   @{$TextFilesInfo{FileHandle}} = ();
  94   for $Index (0 .. $#TextFilesList) {
  95     $TextFilesInfo{FileHandle}[$Index] = new FileHandle;
  96 
  97     open $TextFilesInfo{FileHandle}[$Index], "$TextFilesList[$Index]" or die "Error: Couldn't open $TextFilesList[$Index]: $! \n";
  98     GetTextLine($TextFilesInfo{FileHandle}[$Index]);
  99   }
 100 
 101   if ($OptionsInfo{Keys}) {
 102     MergeTextColumnValuesUsingKeys(\*NEWSDFILE, \*SDFILE);
 103   }
 104   else {
 105     MergeTextColumnValues(\*NEWSDFILE, \*SDFILE);
 106   }
 107 
 108   # Close all opened files...
 109   close NEWSDFILE;
 110   close SDFILE;
 111   for $Index (0 .. $#TextFilesList) {
 112     close $TextFilesInfo{FileHandle}[$Index];
 113   }
 114 }
 115 
 116 # Merge the specified text columns into SD file...
 117 sub MergeTextColumnValues {
 118   my($NewSDFileRef, $SDFileRef) = @_;
 119   my($Index, $Value, $CmpdString, $Line, $InDelim, $ColNum, $ColIndex, @ColLabels, @ColValues, @LineWords);
 120 
 121   while ($CmpdString = ReadCmpdString($SDFileRef)) {
 122     $CmpdString =~ s/\$\$\$\$$//g;
 123     print $NewSDFileRef "$CmpdString";
 124 
 125     # Merge coulmn values from other text files...
 126     @ColLabels = (); @ColValues = ();
 127     for $Index (0 .. $#TextFilesList) {
 128       push @ColLabels, @{$TextFilesInfo{ColToMergeLabels}[$Index]};
 129       $InDelim = $TextFilesInfo{InDelim}[$Index];
 130 
 131       if ($Line = GetTextLine($TextFilesInfo{FileHandle}[$Index])) {
 132         @LineWords = quotewords($InDelim, 0, $Line);
 133 
 134         for $ColNum (@{$TextFilesInfo{ColToMerge}[$Index]}) {
 135           $Value = ($ColNum < @LineWords) ? $LineWords[$ColNum] : "";
 136           push @ColValues, $Value;
 137         }
 138       }
 139     }
 140 
 141     for $ColIndex (0 .. $#ColLabels) {
 142       print $NewSDFileRef "> <$ColLabels[$ColIndex]>\n$ColValues[$ColIndex]\n\n";
 143     }
 144     print $NewSDFileRef "\$\$\$\$\n";
 145   }
 146 }
 147 
 148 # Merge the specified text columns into SD file using keys...
 149 sub MergeTextColumnValuesUsingKeys {
 150   my($NewSDFileRef, $SDFileRef) = @_;
 151   my($Index, $CmpdString, $Value, $InDelim, $KeyColNum, $KeyColValue, $Line, $ColIndex, $ColNum, @ColLabels, @ColValues, @LineWords, @CmpdLines, @TextFilesKeysToLinesMap, %DataFieldValues);
 152 
 153   # Retrieve text lines from all the text files...
 154   @TextFilesKeysToLinesMap = ();
 155 
 156   for $Index (0 .. $#TextFilesList) {
 157     $InDelim = $TextFilesInfo{InDelim}[$Index];
 158     %{$TextFilesKeysToLinesMap[$Index]} = ();
 159     $KeyColNum = $TextFilesInfo{KeysToUse}[$Index];
 160 
 161     while ($Line = GetTextLine($TextFilesInfo{FileHandle}[$Index])) {
 162       @LineWords = quotewords($InDelim, 0, $Line);
 163 
 164       if ($KeyColNum < @LineWords) {
 165         $KeyColValue = $LineWords[$KeyColNum];
 166 
 167         if (length($KeyColValue)) {
 168           if (exists($TextFilesKeysToLinesMap[$Index]{$KeyColValue})) {
 169             warn "Warning: Ignoring line, $Line, in text file $TextFilesList[$Index]: Column key value, $KeyColValue, already exists\n";
 170           }
 171           else {
 172             @{$TextFilesKeysToLinesMap[$Index]{$KeyColValue}} = ();
 173             push @{$TextFilesKeysToLinesMap[$Index]{$KeyColValue}}, @LineWords;
 174           }
 175         }
 176       }
 177     }
 178   }
 179 
 180   while ($CmpdString = ReadCmpdString($SDFileRef)) {
 181     @CmpdLines = split "\n", $CmpdString;
 182     %DataFieldValues = GetCmpdDataHeaderLabelsAndValues(\@CmpdLines);
 183 
 184     if (exists($DataFieldValues{$OptionsInfo{SDKey}})) {
 185       @ColLabels = (); @ColValues = ();
 186       $CmpdString =~ s/\$\$\$\$$//g;
 187       print $NewSDFileRef "$CmpdString";
 188 
 189       $KeyColValue = $DataFieldValues{$OptionsInfo{SDKey}};
 190 
 191       # Merge coulmn values from other text files...
 192       for $Index (0 .. $#TextFilesList) {
 193         push @ColLabels, @{$TextFilesInfo{ColToMergeLabels}[$Index]};
 194         @LineWords = ();
 195 
 196         if (exists($TextFilesKeysToLinesMap[$Index]{$KeyColValue})) {
 197           push @LineWords, @{$TextFilesKeysToLinesMap[$Index]{$KeyColValue}};
 198         }
 199 
 200         for $ColNum (@{$TextFilesInfo{ColToMerge}[$Index]}) {
 201           $Value = ($ColNum < @LineWords) ? $LineWords[$ColNum] : "";
 202           push @ColValues, $Value;
 203         }
 204       }
 205 
 206       for $ColIndex (0 .. $#ColLabels) {
 207         $Value = (($ColIndex < @ColValues) && IsNotEmpty($ColValues[$ColIndex]) ) ? $ColValues[$ColIndex] : "";
 208         print $NewSDFileRef "> <$ColLabels[$ColIndex]>\n$Value\n\n";
 209       }
 210       print $NewSDFileRef "\$\$\$\$\n";
 211     }
 212   }
 213 }
 214 
 215 # Retrieve text file columns and keys information for specified options...
 216 sub RetrieveColumnsAndKeysInfo {
 217   ProcessColumnsInfo();
 218 
 219   if ($OptionsInfo{Keys}) {
 220     ProcessKeysInfo();
 221   }
 222 }
 223 
 224 # Process specified columns...
 225 sub ProcessColumnsInfo {
 226   my($Index, $Values, $ColIndex, $ColNum, $ColLabel, @Words);
 227 
 228   @{$TextFilesInfo{ColSpecified}} = ();
 229   @{$TextFilesInfo{ColToMerge}} = ();
 230   @{$TextFilesInfo{ColToMergeLabels}} = ();
 231   @{$TextFilesInfo{ColToMergeNumToLabelMap}} = ();
 232 
 233   for $Index (0 .. $#TextFilesList) {
 234 
 235     @{$TextFilesInfo{ColSpecified}[$Index]} = ();
 236 
 237     $Values = "all";
 238     if ($OptionsInfo{Columns}) {
 239       $Values = $OptionsInfo{ColValues}[$Index];
 240     }
 241 
 242     if ($Values =~ /all/i) {
 243       if ($OptionsInfo{Mode} =~ /^colnum$/i) {
 244         for $ColNum (1 .. $TextFilesInfo{ColCount}[$Index]) {
 245           push @{$TextFilesInfo{ColSpecified}[$Index]}, $ColNum;
 246         }
 247       } else {
 248         push @{$TextFilesInfo{ColSpecified}[$Index]}, @{$TextFilesInfo{ColLabels}[$Index]};
 249       }
 250     }
 251     else {
 252       @Words = split ",", $Values;
 253       push @{$TextFilesInfo{ColSpecified}[$Index]}, @Words;
 254     }
 255 
 256     @{$TextFilesInfo{ColToMerge}[$Index]} = ();
 257     %{$TextFilesInfo{ColToMergeNumToLabelMap}[$Index]} = ();
 258 
 259     if ($OptionsInfo{Mode} =~ /^collabel$/i) {
 260       for $ColIndex (0 .. $#{$TextFilesInfo{ColSpecified}[$Index]}) {
 261         $ColLabel = $TextFilesInfo{ColSpecified}[$Index][$ColIndex];
 262 
 263         if (exists($TextFilesInfo{ColLabelToNumMap}[$Index]{$ColLabel})) {
 264           $ColNum = $TextFilesInfo{ColLabelToNumMap}[$Index]{$ColLabel};
 265           push @{$TextFilesInfo{ColToMerge}[$Index]}, $ColNum;
 266           $TextFilesInfo{ColToMergeNumToLabelMap}[$Index]{$ColNum} = $ColLabel;
 267         }
 268         else {
 269           warn "Warning: Ignoring value, $ColLabel, specified using \"-c --column\" option: column name doesn't exist in  $TextFilesList[$Index]  \n";
 270         }
 271       }
 272     }
 273     else {
 274       for $ColIndex (0 .. $#{$TextFilesInfo{ColSpecified}[$Index]}) {
 275         $ColNum = $TextFilesInfo{ColSpecified}[$Index][$ColIndex];
 276 
 277         # Make sure it's a numeric value...
 278         if (!IsPositiveInteger($ColNum)) {
 279           warn "Warning: Ignoring value, $ColNum, specified using \"-c --column\" option:  Allowed integer values: > 0\n";
 280         }
 281         else {
 282           if ($ColNum > 0 && $ColNum <= $TextFilesInfo{ColCount}[$Index]) {
 283             $ColNum -= 1;
 284             push @{$TextFilesInfo{ColToMerge}[$Index]}, $ColNum;
 285             $TextFilesInfo{ColToMergeNumToLabelMap}[$Index]{$ColNum} = $TextFilesInfo{ColLabels}[$Index][$ColNum];
 286           }
 287           else {
 288             warn "Warning: Ignoring value, $ColNum, specified using \"-c --column\" option: column number doesn't exist in  $TextFilesList[$Index]  \n";
 289           }
 290         }
 291       }
 292     }
 293 
 294     my (@TextFilesColToMergeSorted) = sort { $a <=> $b } @{$TextFilesInfo{ColToMerge}[$Index]};
 295 
 296     @{$TextFilesInfo{ColToMerge}[$Index]} = ();
 297     push @{$TextFilesInfo{ColToMerge}[$Index]}, @TextFilesColToMergeSorted;
 298 
 299     # Set up the labels...
 300     @{$TextFilesInfo{ColToMergeLabels}[$Index]} = ();
 301     for $ColNum (@TextFilesColToMergeSorted) {
 302       push @{$TextFilesInfo{ColToMergeLabels}[$Index]}, $TextFilesInfo{ColToMergeNumToLabelMap}[$Index]{$ColNum};
 303     }
 304   }
 305 }
 306 
 307 # Process specified keys....
 308 sub ProcessKeysInfo {
 309   my($Index, $ColNum, $ColLabel, $Key);
 310 
 311   @{$TextFilesInfo{KeysSpecified}} = ();
 312   @{$TextFilesInfo{KeysToUse}} = ();
 313 
 314   for $Index (0 .. $#TextFilesList) {
 315     $Key = $OptionsInfo{KeyValues}[$Index];
 316 
 317     $TextFilesInfo{KeysSpecified}[$Index] = $Key;
 318     $TextFilesInfo{KeysToUse}[$Index] = -1;
 319 
 320     if ($OptionsInfo{Mode} =~ /^collabel$/i) {
 321       $ColLabel = $Key;
 322 
 323       if (exists($TextFilesInfo{ColLabelToNumMap}[$Index]{$ColLabel})) {
 324         $TextFilesInfo{KeysToUse}[$Index] =  $TextFilesInfo{ColLabelToNumMap}[$Index]{$ColLabel};
 325       }
 326       else {
 327         warn "Warning: Ignoring value, $ColLabel, specified using \"-k --keys\" option: column name doesn't exist in  $TextFilesList[$Index]  \n";
 328       }
 329     }
 330     else {
 331       $ColNum = $Key;
 332       if (!IsPositiveInteger($ColNum)) {
 333         warn "Warning: Ignoring value, $ColNum, specified using \"-k --keys\" option: Allowed integer values: > 0  \n";
 334       }
 335       else {
 336         if ($ColNum > 0 && $ColNum <= $TextFilesInfo{ColCount}[$Index]) {
 337           $TextFilesInfo{KeysToUse}[$Index] = $ColNum - 1;
 338         }
 339         else {
 340           warn "Warning: Ignoring value, $ColNum, specified using \"-k --keys\" option: column number doesn't exist in  $TextFilesList[$Index]  \n";
 341         }
 342       }
 343     }
 344   }
 345 
 346   # Modify columns to merge list to make sure the columns identified by key are taken off the list
 347   my(@TextFilesColToMergeFiltered, @TextFilesColToMergeLabelsFiltered);
 348 
 349   for $Index (0 .. $#TextFilesList) {
 350     @TextFilesColToMergeFiltered = ();
 351     @TextFilesColToMergeLabelsFiltered = ();
 352 
 353     for $ColNum (@{$TextFilesInfo{ColToMerge}[$Index]}) {
 354       if ($TextFilesInfo{KeysToUse}[$Index] != $ColNum) {
 355         push @TextFilesColToMergeFiltered, $ColNum;
 356         push @TextFilesColToMergeLabelsFiltered, $TextFilesInfo{ColToMergeNumToLabelMap}[$Index]{$ColNum};
 357       }
 358     }
 359 
 360     @{$TextFilesInfo{ColToMerge}[$Index]} = ();
 361     push @{$TextFilesInfo{ColToMerge}[$Index]}, @TextFilesColToMergeFiltered;
 362 
 363     @{$TextFilesInfo{ColToMergeLabels}[$Index]} = ();
 364     push @{$TextFilesInfo{ColToMergeLabels}[$Index]}, @TextFilesColToMergeLabelsFiltered;
 365   }
 366 }
 367 
 368 # Check SD file...
 369 sub ProcessSDFileInfo {
 370   if (!CheckFileType($SDFile, "sd sdf")) {
 371     die "Error: Invalid first file $SDFile: It's not a SD file\n";
 372   }
 373   if (!(-e $SDFile)) {
 374     die "Error: SDFile $SDFile doesn't exist\n";
 375   }
 376 }
 377 
 378 # Retrieve information about input text files...
 379 sub RetrieveTextFilesInfo {
 380   my($Index, $TextFile, $FileDir, $FileName, $FileExt, $InDelim, $Line, $ColNum, $ColLabel, $FileNotOkayCount, @ColLabels,);
 381 
 382   %TextFilesInfo = ();
 383 
 384   @{$TextFilesInfo{FileOkay}} = ();
 385   @{$TextFilesInfo{ColCount}} = ();
 386   @{$TextFilesInfo{ColLabels}} = ();
 387   @{$TextFilesInfo{ColLabelToNumMap}} = ();
 388   @{$TextFilesInfo{InDelim}} = ();
 389 
 390   $FileNotOkayCount = 0;
 391 
 392   FILELIST: for $Index (0 .. $#TextFilesList) {
 393     $TextFile = $TextFilesList[$Index];
 394 
 395     $TextFilesInfo{FileOkay}[$Index] = 0;
 396     $TextFilesInfo{ColCount}[$Index] = 0;
 397     $TextFilesInfo{InDelim}[$Index] = "";
 398 
 399     @{$TextFilesInfo{ColLabels}[$Index]} = ();
 400     %{$TextFilesInfo{ColLabelToNumMap}[$Index]} = ();
 401 
 402     if (!(-e $TextFile)) {
 403       warn "Warning: Ignoring file $TextFile: It doesn't exist\n";
 404       $FileNotOkayCount++;
 405       next FILELIST;
 406     }
 407     if (!CheckFileType($TextFile, "csv tsv")) {
 408       warn "Warning: Ignoring file $TextFile: It's not a csv or tsv file\n";
 409       $FileNotOkayCount++;
 410       next FILELIST;
 411     }
 412     ($FileDir, $FileName, $FileExt) = ParseFileName($TextFile);
 413     if ($FileExt =~ /^tsv$/i) {
 414       $InDelim = "\t";
 415     }
 416     else {
 417       $InDelim = "\,";
 418       if ($OptionsInfo{InDelim} !~ /^(comma|semicolon)$/i) {
 419         warn "Warning: Ignoring file $TextFile: The value specified, $OptionsInfo{InDelim}, for option \"--indelim\" is not valid for csv files\n";
 420         $FileNotOkayCount++;
 421         next FILELIST;
 422       }
 423       if ($OptionsInfo{InDelim} =~ /^semicolon$/i) {
 424         $InDelim = "\;";
 425       }
 426     }
 427 
 428     if (!open TEXTFILE, "$TextFile") {
 429       warn "Warning: Ignoring file $TextFile: Couldn't open it: $! \n";
 430       $FileNotOkayCount++;
 431       next FILELIST;
 432     }
 433 
 434     $Line = GetTextLine(\*TEXTFILE);
 435     @ColLabels = quotewords($InDelim, 0, $Line);
 436     close TEXTFILE;
 437 
 438     $TextFilesInfo{FileOkay}[$Index] = 1;
 439     $TextFilesInfo{InDelim}[$Index] = $InDelim;
 440 
 441     $TextFilesInfo{ColCount}[$Index] = @ColLabels;
 442     push @{$TextFilesInfo{ColLabels}[$Index]}, @ColLabels;
 443     for $ColNum (0 .. $#ColLabels) {
 444       $ColLabel = $ColLabels[$ColNum];
 445       $TextFilesInfo{ColLabelToNumMap}[$Index]{$ColLabel} = $ColNum;
 446     }
 447   }
 448   # Make sure all specified files are valid for merging to work properly...
 449   if ($FileNotOkayCount) {
 450     die "Error: Problems with input text file(s)...\n";
 451   }
 452 }
 453 
 454 # Process option values...
 455 sub ProcessOptions {
 456   my($Index, $FileDir, $FileName, $FileExt, $NewSDFile, @ColValues, @KeyValues);
 457 
 458   %OptionsInfo = ();
 459 
 460   $OptionsInfo{Mode} = $Options{mode};
 461 
 462   $OptionsInfo{Columns} = $Options{columns};
 463   @{$OptionsInfo{ColValues}} = ();
 464 
 465   if ($Options{columns}) {
 466     @ColValues = split ";", $Options{columns};
 467     if (@ColValues != @TextFilesList) {
 468       die "Error: Invalid number of values specified by \"-c --columns\" option: it must be equal to number of input text files.\n";
 469     }
 470     for $Index (0 .. $#ColValues) {
 471       if (!length($ColValues[$Index])) {
 472         die "Error: Invalid value specified by \"-c --columns\" option: empty values are not allowed.\n";
 473       }
 474     }
 475     @{$OptionsInfo{ColValues}} = @ColValues;
 476   }
 477 
 478   $OptionsInfo{Keys} = $Options{keys};
 479   @{$OptionsInfo{KeyValues}} = ();
 480 
 481   if ($Options{keys}) {
 482     @KeyValues = split ";", $Options{keys};
 483     if (@KeyValues != @TextFilesList) {
 484       die "Error: Invalid number of values specified by \"-k --keys\" option: it must be equal to number of input text files.\n";
 485     }
 486     for $Index (0 .. $#KeyValues) {
 487       if (!length($KeyValues[$Index])) {
 488         die "Error: Invalid value specified by \"-k --keys\" option: empty values are not allowed.\n";
 489       }
 490     }
 491     @{$OptionsInfo{KeyValues}} = @KeyValues;
 492   }
 493 
 494   $OptionsInfo{InDelim} = $Options{indelim};
 495 
 496   $OptionsInfo{OutFileRoot} = defined $Options{root} ? $Options{root} : undef;
 497   $OptionsInfo{Overwrite} = defined $Options{overwrite} ? $Options{overwrite} : undef;
 498 
 499   $OptionsInfo{SDKey} = defined $Options{sdkey} ? $Options{sdkey} : undef;
 500 
 501   # Setup new SD file...
 502   if ($Options{root}) {
 503     $FileDir = ""; $FileName = ""; $FileExt = "";
 504     ($FileDir, $FileName, $FileExt) = ParseFileName($Options{root});
 505     if ($FileName && $FileExt) {
 506       $NewSDFile = $FileName;
 507     }
 508     else {
 509       $NewSDFile =  $Options{root};
 510     }
 511   }
 512   else {
 513     $FileDir = ""; $FileName = ""; $FileExt = "";
 514     ($FileDir, $FileName, $FileExt) = ParseFileName($SDFile);
 515 
 516     $NewSDFile = $FileName;
 517     ($FileDir, $FileName, $FileExt) = ParseFileName($TextFilesList[0]);
 518 
 519     $NewSDFile = $NewSDFile . "MergedWith" . $FileName . "1To" . @TextFilesList;
 520   }
 521 
 522   $NewSDFile = $NewSDFile . ".sdf";
 523   if (!$Options{overwrite}) {
 524     if (-e $NewSDFile) {
 525       die "Error: The file $NewSDFile already exists.\n";
 526     }
 527   }
 528   if ($Options{root}) {
 529     if (lc($NewSDFile) eq lc($SDFile)) {
 530       die "Error: Output filename, $NewSDFile, is similar to a input file name.\nSpecify a different name using \"-r --root\" option or use default name.\n";
 531     }
 532   }
 533   $OptionsInfo{NewSDFile} = $NewSDFile;
 534 }
 535 
 536 # Setup script usage  and retrieve command line arguments specified using various options...
 537 sub SetupScriptUsage {
 538 
 539   # Retrieve all the options...
 540   %Options = ();
 541   $Options{mode} = "colnum";
 542   $Options{indelim} = "comma";
 543 
 544   if (!GetOptions(\%Options, "help|h", "indelim=s", "columns|c=s", "keys|k=s", "mode|m=s", "overwrite|o", "root|r=s", "sdkey|s=s", "workingdir|w=s")) {
 545     die "\nTo get a list of valid options and their values, use \"$ScriptName -h\" or\n\"perl -S $ScriptName -h\" command and try again...\n";
 546   }
 547   if ($Options{workingdir}) {
 548     if (! -d $Options{workingdir}) {
 549       die "Error: The value specified, $Options{workingdir}, for option \"-w --workingdir\" is not a directory name.\n";
 550     }
 551     chdir $Options{workingdir} or die "Error: Couldn't chdir $Options{workingdir}: $! \n";
 552   }
 553   if ($Options{mode} !~ /^(colnum|collabel)$/i) {
 554     die "Error: The value specified, $Options{mode}, for option \"-m --mode\" is not valid. Allowed values: colnum, or collabel\n";
 555   }
 556   if ($Options{indelim} !~ /^(comma|semicolon)$/i) {
 557     die "Error: The value specified, $Options{indelim}, for option \"--indelim\" is not valid. Allowed values: comma or semicolon\n";
 558   }
 559   if ($Options{sdkey} && !$Options{keys}) {
 560     die "Error: The option \"-s --sdkey\" can't be specified without the \"-k --keys\" option.\n";
 561   }
 562   elsif (!$Options{sdkey} && $Options{keys}) {
 563     die "Error: The option \"-k --keys\" can't be specified without the \"-s --sdkey\" option.\n";
 564   }
 565 }
 566