1 #!/usr/bin/perl -w 2 # 3 # File: ElementalAnalysisTextFiles.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 FileUtil; 33 use TextUtil; 34 use MolecularFormula; 35 36 my($ScriptName, %Options, $StartTime, $EndTime, $TotalTime); 37 38 # Autoflush STDOUT 39 $| = 1; 40 41 # Starting message... 42 $ScriptName = basename($0); 43 print "\n$ScriptName: Starting...\n\n"; 44 $StartTime = new Benchmark; 45 46 # Get the options and setup script... 47 SetupScriptUsage(); 48 if ($Options{help} || @ARGV < 1) { 49 die GetUsageFromPod("$FindBin::Bin/$ScriptName"); 50 } 51 52 my(@TextFilesList); 53 @TextFilesList = ExpandFileNames(\@ARGV, "csv tsv"); 54 55 # Process options... 56 my(%OptionsInfo); 57 print "Processing options...\n"; 58 ProcessOptions(); 59 60 print "Checking input text file(s)...\n"; 61 my(%TextFilesInfo); 62 RetrieveTextFilesInfo(); 63 RetrieveColumnsAndLabelsInfo(); 64 65 # Generate output files... 66 my($FileIndex); 67 if (@TextFilesList > 1) { 68 print "\nProcessing text files...\n"; 69 } 70 for $FileIndex (0 .. $#TextFilesList) { 71 if ($TextFilesInfo{FileOkay}[$FileIndex]) { 72 print "\nProcessing file $TextFilesList[$FileIndex]...\n"; 73 PerformElementalAnalysis($FileIndex); 74 } 75 } 76 print "\n$ScriptName:Done...\n\n"; 77 78 $EndTime = new Benchmark; 79 $TotalTime = timediff ($EndTime, $StartTime); 80 print "Total time: ", timestr($TotalTime), "\n"; 81 82 ############################################################################### 83 84 # Perform elemental analysis... 85 sub PerformElementalAnalysis { 86 my($Index) = @_; 87 my($TextFile, $NewTextFile, $FormulaCol, $Line, $NewLine, $FormulaColValue, $InDelim, $ColNum, $Value, $Status, $ErrorMsg, @ColLabels, @LineWords, @ColNumsBeforeNew, @ColNumsAfterNew); 88 89 $TextFile = $TextFilesList[$Index]; 90 $InDelim = $TextFilesInfo{InDelim}[$Index]; 91 $NewTextFile = $TextFilesInfo{OutFile}[$Index]; 92 $FormulaCol = $TextFilesInfo{FormulaColNum}[$Index]; 93 94 @ColNumsBeforeNew = @{$TextFilesInfo{ColNumsBeforeNew}[$Index]}; 95 @ColNumsAfterNew = @{$TextFilesInfo{ColNumsAfterNew}[$Index]}; 96 97 print "Generating new Text file $NewTextFile...\n"; 98 open NEWTEXTFILE, ">$NewTextFile" or die "Error: Couldn't open $NewTextFile: $! \n"; 99 open TEXTFILE, "$TextFile" or die "Error: Can't open $TextFile: $! \n"; 100 101 # Skip over column labels from old file... 102 $Line = GetTextLine(\*TEXTFILE); 103 104 # Add column lablels in new file... 105 @ColLabels = (); 106 for $ColNum (@ColNumsBeforeNew) { 107 push @ColLabels, $TextFilesInfo{ColLabels}[$Index][$ColNum]; 108 } 109 for $Value (@{$OptionsInfo{SpecifiedCalculations}}) { 110 push @ColLabels, $TextFilesInfo{ValueLabelsMap}[$Index]{$Value}; 111 } 112 for $ColNum (@ColNumsAfterNew) { 113 push @ColLabels, $TextFilesInfo{ColLabels}[$Index][$ColNum]; 114 } 115 $NewLine = ''; 116 $NewLine = JoinWords(\@ColLabels, $OptionsInfo{OutDelim}, $OptionsInfo{OutQuote}); 117 print NEWTEXTFILE "$NewLine\n"; 118 119 # Go over all rows... 120 my($LineCount, $ElementsRef, $ElementCompositionRef, $CalculationType, $CalculatedValue, @CalculatedValues); 121 122 $LineCount = 1; 123 TEXTLINE: while ($Line = GetTextLine(\*TEXTFILE)) { 124 @LineWords = quotewords($InDelim, 0, $Line); 125 $LineCount++; 126 127 @CalculatedValues = (); 128 for $Value (@{$OptionsInfo{SpecifiedCalculations}}) { 129 push @CalculatedValues, ''; 130 } 131 if ($FormulaCol > @LineWords) { 132 $ErrorMsg = "Ignoring line $LineCount: Formula column $ColLabels[$FormulaCol] not found"; 133 PrintErrorMsg($Line, $ErrorMsg); 134 ComposeAndWriteNewLine(\*NEWTEXTFILE, \@LineWords, \@ColNumsBeforeNew, \@ColNumsAfterNew, \@CalculatedValues); 135 next TEXTLINE; 136 } 137 138 # Make sure it's a valid molecular formula... 139 $FormulaColValue = $LineWords[$FormulaCol]; 140 if ($OptionsInfo{CheckFormula}) { 141 ($Status, $ErrorMsg) = MolecularFormula::IsMolecularFormula($FormulaColValue); 142 if (!$Status) { 143 $ErrorMsg = "Ignoring line $LineCount: Formula column $ColLabels[$FormulaCol] value is not valid: $ErrorMsg"; 144 PrintErrorMsg($Line, $ErrorMsg); 145 ComposeAndWriteNewLine(\*NEWTEXTFILE, \@LineWords, \@ColNumsBeforeNew, \@ColNumsAfterNew, \@CalculatedValues); 146 next TEXTLINE; 147 } 148 } 149 150 # Calculate appropriate values and write 'em out... 151 @CalculatedValues = (); 152 for $CalculationType (@{$OptionsInfo{SpecifiedCalculations}}) { 153 if ($CalculationType =~ /^ElementalAnalysis$/i) { 154 ($ElementsRef, $ElementCompositionRef) = MolecularFormula::CalculateElementalComposition($FormulaColValue); 155 $CalculatedValue = (defined($ElementsRef) && defined($ElementCompositionRef)) ? MolecularFormula::FormatCompositionInfomation($ElementsRef, $ElementCompositionRef, $OptionsInfo{Precision}) : ''; 156 } 157 elsif ($CalculationType =~ /^MolecularWeight$/i) { 158 $CalculatedValue = MolecularFormula::CalculateMolecularWeight($FormulaColValue); 159 $CalculatedValue = (defined($CalculatedValue) && length($CalculatedValue)) ? (sprintf("%.$OptionsInfo{Precision}f", $CalculatedValue)) : ""; 160 } 161 elsif ($CalculationType =~ /^ExactMass$/i) { 162 $CalculatedValue = MolecularFormula::CalculateExactMass($FormulaColValue); 163 $CalculatedValue = (defined($CalculatedValue) && length($CalculatedValue)) ? (sprintf("%.$OptionsInfo{Precision}f", $CalculatedValue)) : ""; 164 } 165 else { 166 $CalculatedValue = ''; 167 } 168 push @CalculatedValues, $CalculatedValue; 169 } 170 171 ComposeAndWriteNewLine(\*NEWTEXTFILE, \@LineWords, \@ColNumsBeforeNew, \@ColNumsAfterNew, \@CalculatedValues); 172 } 173 close NEWTEXTFILE; 174 close TEXTFILE; 175 176 } 177 178 # Write out new line using old and new calculated data... 179 sub ComposeAndWriteNewLine { 180 my($NewTextFileRef, $OldLineWordsRef, $ColNumsBeforeNewRef, $ColNumsAfterNewRef, $CalculatedValuesRef) = @_; 181 my($NewLine, $ColNum, $Value, @NewLineWords); 182 183 @NewLineWords = (); 184 for $ColNum (@{$ColNumsBeforeNewRef}) { 185 push @NewLineWords, $OldLineWordsRef->[$ColNum]; 186 } 187 for $Value (@{$CalculatedValuesRef}) { 188 push @NewLineWords, $Value; 189 } 190 for $ColNum (@{$ColNumsAfterNewRef}) { 191 push @NewLineWords, $OldLineWordsRef->[$ColNum]; 192 } 193 $NewLine = JoinWords(\@NewLineWords, $OptionsInfo{OutDelim}, $OptionsInfo{OutQuote}); 194 print $NewTextFileRef "$NewLine\n"; 195 } 196 197 # Print out error message... 198 sub PrintErrorMsg { 199 my($Line, $ErrorMsg) = @_; 200 201 if ($OptionsInfo{DetailLevel} >= 2 ) { 202 print "$ErrorMsg: $Line\n"; 203 } 204 elsif ($OptionsInfo{DetailLevel} >= 1) { 205 print "$ErrorMsg\n"; 206 } 207 } 208 209 # Process formula columns and other information... 210 sub RetrieveColumnsAndLabelsInfo { 211 RetrieveFormulaColumnsInfo(); 212 RetrieveStartColumnsAndValueLabelsInfo(); 213 } 214 215 # Make sure specified formula column are okay... 216 sub RetrieveFormulaColumnsInfo { 217 my($Index, $TextFile); 218 219 @{$TextFilesInfo{FormulaColNum}} = (); 220 221 FILELIST: for $Index (0 .. $#TextFilesList) { 222 $TextFile = $TextFilesList[$Index]; 223 224 $TextFilesInfo{FormulaColNum}[$Index] = 0; 225 226 if ($TextFilesInfo{FileOkay}[$Index]) { 227 my($FormulaColNum, $FormulaColValid); 228 229 $FormulaColNum = 0; 230 $FormulaColValid = 0; 231 if ($OptionsInfo{SpecifiedFormulaCol}) { 232 if ($OptionsInfo{ColMode} =~ /^colnum$/i) { 233 if ($OptionsInfo{SpecifiedFormulaCol} <= $TextFilesInfo{ColCount}[$Index]) { 234 $FormulaColNum = $OptionsInfo{SpecifiedFormulaCol} - 1; 235 $FormulaColValid = 1; 236 } 237 } 238 else { 239 if (exists($TextFilesInfo{ColLabelToNumMap}[$Index]{$OptionsInfo{SpecifiedFormulaCol}})) { 240 $FormulaColNum = $TextFilesInfo{ColLabelToNumMap}[$Index]{$OptionsInfo{SpecifiedFormulaCol}}; 241 $FormulaColValid = 1; 242 } 243 } 244 } 245 else { 246 # Grab the first column with the word Formula in its label... 247 my($ColLabel); 248 LABEL: for $ColLabel (@{$TextFilesInfo{ColLabels}[$Index]}) { 249 if ($ColLabel =~ /Formula/i) { 250 $FormulaColNum = $TextFilesInfo{ColLabelToNumMap}[$Index]{$ColLabel}; 251 $FormulaColValid = 1; 252 last LABEL; 253 } 254 } 255 } 256 if ($FormulaColValid) { 257 $TextFilesInfo{FormulaColNum}[$Index] = $FormulaColNum; 258 } 259 else { 260 if ($OptionsInfo{SpecifiedFormulaCol}) { 261 warn "Warning: Ignoring file $TextFile: Formula column specified, $OptionsInfo{SpecifiedFormulaCol}, using \"f --formulacol\" option doesn't exist\n"; 262 } 263 else { 264 warn "Warning: Ignoring file $TextFile: Column label containing the word Formula doesn't exist\n"; 265 } 266 $TextFilesInfo{FileOkay}[$Index] = 0; 267 } 268 } 269 } 270 } 271 272 # Setup starting column number for adding calculated values and 273 # column lables to use for these values... 274 sub RetrieveStartColumnsAndValueLabelsInfo { 275 my($Index, $TextFile, $SpecifiedStartColNum, $StartColNum, $Label, $Value, $NewLabel, $Count, $BeforeStartColNum, $AfterStartColNum, $FirstColNum, $LastColNum, $ColNum, $Part1StartColNum, $Part1EndColNum, $Part2StartColNum, $Part2EndColNum, @Part1ColNums, @Part2ColNums); 276 277 # Start column number for inserting new values... 278 $SpecifiedStartColNum = "last"; 279 if (defined($OptionsInfo{StartCol})) { 280 if (length($OptionsInfo{StartCol})) { 281 $SpecifiedStartColNum = $OptionsInfo{StartCol} 282 } 283 } 284 285 # Column labels for for new calculated values... 286 my(%NewValueLabels) = (ElementalAnalysis => 'ElementalAnalysis', MolecularWeight => 'MolecularWeight', ExactMass => 'ExactMass'); 287 if (@{$OptionsInfo{SpecifiedValueLabels}}) { 288 for ($Index = 0; $Index < @{$OptionsInfo{SpecifiedValueLabels}}; $Index +=2) { 289 $Value = $OptionsInfo{SpecifiedValueLabels}[$Index]; 290 $Label = $OptionsInfo{SpecifiedValueLabels}[$Index + 1]; 291 if (exists $NewValueLabels{$Value}) { 292 $NewValueLabels{$Value} = $Label; 293 } 294 } 295 } 296 297 @{$TextFilesInfo{ColNumsBeforeNew}} = (); 298 @{$TextFilesInfo{ColNumsAfterNew}} = (); 299 @{$TextFilesInfo{ValueLabelsMap}} = (); 300 301 FILELIST: for $Index (0 .. $#TextFilesList) { 302 $TextFile = $TextFilesList[$Index]; 303 304 @{$TextFilesInfo{ColNumsBeforeNew}[$Index]} = (); 305 @{$TextFilesInfo{ColNumsAfterNew}[$Index]} = (); 306 %{$TextFilesInfo{ValueLabelsMap}[$Index]} = (); 307 308 if (!$TextFilesInfo{FileOkay}[$Index]) { 309 next FILELIST; 310 } 311 312 if ($SpecifiedStartColNum !~ /^last$/i) { 313 if ($OptionsInfo{ColMode} =~ /^collabel$/i) { 314 if (exists($TextFilesInfo{ColLabelToNumMap}[$Index]{$SpecifiedStartColNum})) { 315 $StartColNum = $TextFilesInfo{ColLabelToNumMap}[$Index]{$SpecifiedStartColNum}; 316 } 317 else { 318 die "Error: Invalid value $SpecifiedStartColNum specified using \"-s --startcol\" option: column name doesn't exist in $TextFile \n"; 319 } 320 } 321 else { 322 if ($SpecifiedStartColNum > 0 && $SpecifiedStartColNum <= $TextFilesInfo{ColCount}[$Index]) { 323 $StartColNum -= 1; 324 } 325 else { 326 die "Error: Invalid value $SpecifiedStartColNum specified using \"-s --startcol\" option: column number doesn't exist in $TextFile \n"; 327 } 328 } 329 } 330 else { 331 $StartColNum = $TextFilesInfo{ColCount}[$Index] - 1; 332 } 333 # Set up columns lists for before and after the addition of calculated column values 334 # for each text file... 335 my($BeforeStartColNum, $AfterStartColNum, $FirstColNum, $LastColNum, $ColNum, $Part1StartColNum, $Part1EndColNum, $Part2StartColNum, $Part2EndColNum, @Part1ColNums, @Part2ColNums); 336 337 $FirstColNum = 0; $LastColNum = $TextFilesInfo{ColCount}[$Index] - 1; 338 339 $BeforeStartColNum = $StartColNum - 1; 340 $AfterStartColNum = $StartColNum + 1; 341 342 if ($OptionsInfo{StartColMode} =~ /^after$/i) { 343 $Part1StartColNum = $FirstColNum; $Part1EndColNum = $StartColNum; 344 $Part2StartColNum = $AfterStartColNum; $Part2EndColNum = $LastColNum; 345 } 346 else { 347 $Part1StartColNum = $FirstColNum; $Part1EndColNum = $BeforeStartColNum; 348 $Part2StartColNum = $StartColNum; $Part2EndColNum = $LastColNum; 349 } 350 @Part1ColNums = (); @Part2ColNums = (); 351 for $ColNum (0 .. $TextFilesInfo{ColCount}[$Index]) { 352 if ($ColNum >= $Part1StartColNum && $ColNum <= $Part1EndColNum) { 353 push @Part1ColNums, $ColNum; 354 } 355 } 356 for $ColNum (0 .. $TextFilesInfo{ColCount}[$Index]) { 357 if ($ColNum >= $Part2StartColNum && $ColNum <= $Part2EndColNum) { 358 push @Part2ColNums, $ColNum; 359 } 360 } 361 push @{$TextFilesInfo{ColNumsBeforeNew}[$Index]}, @Part1ColNums; 362 push @{$TextFilesInfo{ColNumsAfterNew}[$Index]}, @Part2ColNums; 363 364 # Setup column labels for calculated values... 365 for $Value (keys %NewValueLabels) { 366 $Label = $NewValueLabels{$Value}; 367 368 # Make sure it doesn't already exists... 369 $Count = 1; 370 $NewLabel = $Label; 371 while (exists $TextFilesInfo{ColLabelToNumMap}[$Index]{$NewLabel}) { 372 $Count++; 373 $NewLabel = $Label . $Count; 374 } 375 $TextFilesInfo{ValueLabelsMap}[$Index]{$Value} = $NewLabel; 376 } 377 } 378 } 379 380 # Retrieve information about input text files... 381 sub RetrieveTextFilesInfo { 382 my($Index, $TextFile, $FileDir, $FileName, $FileExt, $InDelim, $Line, @ColLabels, $OutFileRoot, $OutFile, $ColNum, $ColLabel); 383 384 %TextFilesInfo = (); 385 386 @{$TextFilesInfo{FileOkay}} = (); 387 @{$TextFilesInfo{ColCount}} = (); 388 @{$TextFilesInfo{ColLabels}} = (); 389 @{$TextFilesInfo{ColLabelToNumMap}} = (); 390 @{$TextFilesInfo{InDelim}} = (); 391 @{$TextFilesInfo{OutFile}} = (); 392 393 FILELIST: for $Index (0 .. $#TextFilesList) { 394 $TextFile = $TextFilesList[$Index]; 395 396 $TextFilesInfo{FileOkay}[$Index] = 0; 397 $TextFilesInfo{ColCount}[$Index] = 0; 398 $TextFilesInfo{InDelim}[$Index] = ""; 399 $TextFilesInfo{OutFile}[$Index] = ""; 400 401 @{$TextFilesInfo{ColLabels}[$Index]} = (); 402 %{$TextFilesInfo{ColLabelToNumMap}[$Index]} = (); 403 404 if (!(-e $TextFile)) { 405 warn "Warning: Ignoring file $TextFile: It doesn't exist\n"; 406 next FILELIST; 407 } 408 if (!CheckFileType($TextFile, "csv tsv")) { 409 warn "Warning: Ignoring file $TextFile: It's not a csv or tsv file\n"; 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 ($Options{indelim} !~ /^(comma|semicolon)$/i) { 419 warn "Warning: Ignoring file $TextFile: The value specified, $Options{indelim}, for option \"--indelim\" is not valid for csv files\n"; 420 next FILELIST; 421 } 422 if ($Options{indelim} =~ /^semicolon$/i) { 423 $InDelim = "\;"; 424 } 425 } 426 427 if (!open TEXTFILE, "$TextFile") { 428 warn "Warning: Ignoring file $TextFile: Couldn't open it: $! \n"; 429 next FILELIST; 430 } 431 432 $Line = GetTextLine(\*TEXTFILE); 433 @ColLabels = quotewords($InDelim, 0, $Line); 434 close TEXTFILE; 435 436 $FileDir = ""; $FileName = ""; $FileExt = ""; 437 ($FileDir, $FileName, $FileExt) = ParseFileName($TextFile); 438 $FileExt = "csv"; 439 if ($Options{outdelim} =~ /^tab$/i) { 440 $FileExt = "tsv"; 441 } 442 if ($Options{root} && (@TextFilesList == 1)) { 443 my ($RootFileDir, $RootFileName, $RootFileExt) = ParseFileName($Options{root}); 444 if ($RootFileName && $RootFileExt) { 445 $FileName = $RootFileName; 446 } 447 else { 448 $FileName = $Options{root}; 449 } 450 $OutFileRoot = $FileName; 451 } 452 else { 453 $OutFileRoot = $FileName . "ElementalAnalysis"; 454 } 455 456 $OutFile = $OutFileRoot . ".$FileExt"; 457 if (lc($OutFile) eq lc($TextFile)) { 458 warn "Warning: Ignoring file $TextFile:Output file name, $OutFile, is same as input text file name, $TextFile\n"; 459 next FILELIST; 460 } 461 if (!$Options{overwrite}) { 462 if (-e $OutFile) { 463 warn "Warning: Ignoring file $TextFile: The file $OutFile already exists\n"; 464 next FILELIST; 465 } 466 } 467 468 $TextFilesInfo{FileOkay}[$Index] = 1; 469 $TextFilesInfo{InDelim}[$Index] = $InDelim; 470 $TextFilesInfo{OutFile}[$Index] = "$OutFile"; 471 472 $TextFilesInfo{ColCount}[$Index] = @ColLabels; 473 push @{$TextFilesInfo{ColLabels}[$Index]}, @ColLabels; 474 for $ColNum (0 .. $#ColLabels) { 475 $ColLabel = $ColLabels[$ColNum]; 476 $TextFilesInfo{ColLabelToNumMap}[$Index]{$ColLabel} = $ColNum; 477 } 478 } 479 480 } 481 482 # Process option values... 483 sub ProcessOptions { 484 %OptionsInfo = (); 485 486 $OptionsInfo{Mode} = $Options{mode}; 487 488 $OptionsInfo{ColMode} = $Options{colmode}; 489 $OptionsInfo{StartColMode} = $Options{startcolmode}; 490 491 $OptionsInfo{Fast} = defined $Options{fast} ? $Options{fast} : undef; 492 493 $OptionsInfo{DetailLevel} = $Options{detail}; 494 $OptionsInfo{CheckFormula} = $Options{fast} ? 0 : 1; 495 $OptionsInfo{Precision} = $Options{precision}; 496 497 $OptionsInfo{InDelim} = $Options{indelim}; 498 499 $OptionsInfo{OutDelim} = ($Options{outdelim} =~ /^tab$/i ) ? "\t" : (($Options{outdelim} =~ /^semicolon$/i) ? "\;" : "\,"); 500 $OptionsInfo{OutQuote} = ($Options{quote} =~ /^yes$/i) ? 1 : 0; 501 502 $OptionsInfo{Overwrite} = defined $Options{overwrite} ? $Options{overwrite} : undef; 503 $OptionsInfo{OutFileRoot} = defined $Options{root} ? $Options{root} : undef; 504 505 $OptionsInfo{StartCol} = defined $Options{startcol} ? $Options{startcol} : undef; 506 507 $OptionsInfo{FormulaCol} = defined $Options{formulacol} ? $Options{formulacol} : undef; 508 $OptionsInfo{SpecifiedFormulaCol} = ""; 509 510 if (defined $Options{formulacol}) { 511 $OptionsInfo{SpecifiedFormulaCol} = $Options{formulacol}; 512 if ($Options{colmode} =~ /^colnum$/i) { 513 if (!IsPositiveInteger($OptionsInfo{SpecifiedFormulaCol})) { 514 die "Error: Invalid value $Options{formulacol} specified using \"-f -formulacol\" option: Allowed values: > 0\n"; 515 } 516 } 517 } 518 519 # Setup what to calculate... 520 @{$OptionsInfo{SpecifiedCalculations}} = (); 521 if ($Options{mode} =~ /^All$/i) { 522 @{$OptionsInfo{SpecifiedCalculations}} = qw(ElementalAnalysis MolecularWeight ExactMass); 523 } 524 else { 525 my($Mode, $ModeValue, @SpecifiedModeValues); 526 $Mode = $Options{mode}; 527 $Mode =~ s/ //g; 528 @SpecifiedModeValues = split /\,/, $Mode; 529 for $ModeValue (@SpecifiedModeValues) { 530 if ($ModeValue !~ /^(ElementalAnalysis|MolecularWeight|ExactMass)$/i) { 531 if ($ModeValue =~ /^All$/i) { 532 die "Error: All value for option \"-m --mode\" is not allowed with other valid values.\n"; 533 } 534 else { 535 die "Error: The value specified, $ModeValue, for option \"-m --mode\" is not valid. Allowed values: ElementalAnalysis, MolecularWeight, or ExactMass\n"; 536 } 537 } 538 push @{$OptionsInfo{SpecifiedCalculations}}, $ModeValue; 539 } 540 } 541 542 $OptionsInfo{ValueColLabels} = defined $Options{valuecollabels} ? $Options{valuecollabels} : undef; 543 @{$OptionsInfo{SpecifiedValueLabels}} = (); 544 545 if ($Options{valuecollabels}) { 546 my($Value, $Label, @ValueLabels); 547 @ValueLabels = split /\,/, $Options{valuecollabels}; 548 if (@ValueLabels % 2) { 549 die "Error: The value specified, $Options{valuecollabels}, for option \"-v --valuecollabels\" is not valid: It must contain even number of comma delimited values\n"; 550 } 551 my($Index); 552 for ($Index = 0; $Index < @ValueLabels; $Index +=2) { 553 $Value = $ValueLabels[$Index]; 554 $Value =~ s/ //g; 555 $Label = $ValueLabels[$Index + 1]; 556 if ($Value !~ /^(ElementalAnalysis|MolecularWeight|ExactMass)$/i) { 557 die "Error: The value specified, $Value, using option \"-v --valuecollabels\" is not valid. Allowed values: ElementalAnalysis, MolecularWeight, or ExactMass\n"; 558 } 559 push @{$OptionsInfo{SpecifiedValueLabels}}, ($Value, $Label); 560 } 561 } 562 } 563 564 # Setup script usage and retrieve command line arguments specified using various options... 565 sub SetupScriptUsage { 566 567 # Retrieve all the options... 568 %Options = (); 569 $Options{colmode} = "colnum"; 570 $Options{detail} = 1; 571 $Options{mode} = "All"; 572 $Options{indelim} = "comma"; 573 $Options{outdelim} = "comma"; 574 $Options{precision} = 2; 575 $Options{quote} = "yes"; 576 $Options{startcolmode} = "after"; 577 578 if (!GetOptions(\%Options, "colmode|c=s", "detail|d=i", "fast", "formulacol|f=s", "help|h", "indelim=s", "mode|m=s", "outdelim=s", "overwrite|o", "precision|p=i", "quote|q=s", "root|r=s", "startcol|s=s", "startcolmode=s", "valuecollabels|v=s", "workingdir|w=s")) { 579 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"; 580 } 581 if ($Options{workingdir}) { 582 if (! -d $Options{workingdir}) { 583 die "Error: The value specified, $Options{workingdir}, for option \"-w --workingdir\" is not a directory name.\n"; 584 } 585 chdir $Options{workingdir} or die "Error: Couldn't chdir $Options{workingdir}: $! \n"; 586 } 587 if ($Options{colmode} !~ /^(colnum|collabel)$/i) { 588 die "Error: The value specified, $Options{colmode}, for option \"-c --colmode\" is not valid. Allowed values: colnum or collabel\n"; 589 } 590 if ($Options{indelim} !~ /^(comma|semicolon)$/i) { 591 die "Error: The value specified, $Options{indelim}, for option \"--indelim\" is not valid. Allowed values: comma or semicolon\n"; 592 } 593 if ($Options{outdelim} !~ /^(comma|semicolon|tab)$/i) { 594 die "Error: The value specified, $Options{outdelim}, for option \"--outdelim\" is not valid. Allowed values: comma, tab, or semicolon\n"; 595 } 596 if (!IsPositiveInteger($Options{precision})) { 597 die "Error: The value specified, $Options{precision}, for option \"-p --precision\" is not valid. Allowed values: > 0 \n"; 598 } 599 if ($Options{quote} !~ /^(yes|no)$/i) { 600 die "Error: The value specified, $Options{quote}, for option \"-q --quote\" is not valid. Allowed values: yes or no\n"; 601 } 602 if ($Options{startcolmode} !~ /^(before|after)$/i) { 603 die "Error: The value specified, $Options{quote}, for option \"--startcolmode\" is not valid. Allowed values: before or after\n"; 604 } 605 if (!IsPositiveInteger($Options{detail})) { 606 die "Error: The value specified, $Options{detail}, for option \"-d --detail\" is not valid. Allowed values: > 0\n"; 607 } 608 } 609