MayaChemTools

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