1 #!/usr/bin/perl -w 2 # 3 # File: InfoPeriodicTableElements.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 PeriodicTable; 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}) { 49 die GetUsageFromPod("$FindBin::Bin/$ScriptName"); 50 } 51 52 print "Processing options...\n"; 53 my(%OptionsInfo); 54 ProcessOptions(); 55 56 ListElementProperties(); 57 print "\n$ScriptName:Done...\n\n"; 58 59 $EndTime = new Benchmark; 60 $TotalTime = timediff ($EndTime, $StartTime); 61 print "Total time: ", timestr($TotalTime), "\n"; 62 63 ############################################################################### 64 65 # List atomic properties for elements... 66 sub ListElementProperties { 67 my($ElementID, $ElementDataRef, $PropertyName, $PropertyValue, $PropertyUnits, $PropertyUnitsRef, @PropertyLabels, @PropertyValues); 68 69 print "Listing information for periodic table element(s)...\n"; 70 71 if ($OptionsInfo{FileOutput}) { 72 print "Generating file $OptionsInfo{OutFileName}...\n"; 73 open OUTFILE, ">$OptionsInfo{OutFileName}" or die "Couldn't open $OptionsInfo{OutFileName}: $!\n"; 74 } 75 76 # Setup property labels... 77 @PropertyLabels = (); 78 $PropertyUnitsRef = PeriodicTable::GetElementPropertiesNamesAndUnits(); 79 for $PropertyName (@{$OptionsInfo{SpecifiedProperies}}) { 80 $PropertyUnits = (exists $PropertyUnitsRef->{$PropertyName}) ? $PropertyUnitsRef->{$PropertyName} : ''; 81 if ($PropertyName =~ /^NaturalIsotopeData$/i) { 82 push @PropertyLabels, qw(MassNumber: RelativeAtomicMass: NaturalAbundance:); 83 } 84 else { 85 push @PropertyLabels, ($PropertyUnits ? "$PropertyName ($PropertyUnits):" : "$PropertyName:"); 86 } 87 } 88 89 if ($OptionsInfo{ElementRowsOutput}) { 90 ListHeaderRowData(\@PropertyLabels); 91 } 92 93 # Go over specified properties... 94 for $ElementID (@{$OptionsInfo{SpecifiedElementIDs}}) { 95 $ElementDataRef = PeriodicTable::GetElementPropertiesData($ElementID); 96 97 if (!$OptionsInfo{ElementRowsOutput}) { 98 if ($OptionsInfo{FileOutput}) { 99 print OUTFILE "\nListing atomic properties for element $ElementID...\n\n"; 100 } 101 else { 102 print "\nListing atomic properties for element $ElementID...\n\n"; 103 } 104 } 105 106 # Collect data.. 107 @PropertyValues = (); 108 for $PropertyName (@{$OptionsInfo{SpecifiedProperies}}) { 109 if ($PropertyName =~ /^NaturalIsotopeData$/i) { 110 push @PropertyValues, SetupIsotopeData($ElementID); 111 } 112 else { 113 $PropertyValue = $ElementDataRef->{$PropertyName}; 114 if (IsFloat($PropertyValue)) { 115 $PropertyValue = sprintf("%.$OptionsInfo{Precision}f", $PropertyValue) + 0; 116 } 117 push @PropertyValues, $PropertyValue; 118 } 119 } 120 # List data... 121 ListElementData(\@PropertyLabels, \@PropertyValues); 122 } 123 if ($OptionsInfo{FileOutput}) { 124 close OUTFILE; 125 } 126 print "\n"; 127 } 128 129 # List data for an element... 130 sub ListElementData { 131 my($DataLabelRef, $DataValueRef) = @_; 132 my($Index, $Line, $Value); 133 134 if ($OptionsInfo{ElementRowsOutput}) { 135 $Line = ''; 136 # Format data... 137 if ($OptionsInfo{OutQuote} || $Options{outdelim} !~ /^comma$/i) { 138 $Line = JoinWords($DataValueRef, $OptionsInfo{OutDelim}, $OptionsInfo{OutQuote}); 139 } 140 else { 141 # Always quote values containing commas... 142 $Line = ($DataValueRef->[0] =~ /\,/) ? qq("$DataValueRef->[0]") : $DataValueRef->[0]; 143 for $Index (1 .. $#{$DataValueRef} ) { 144 $Value = $DataValueRef->[$Index]; 145 if ($Value =~ /\,/) { 146 $Value = qq("$Value"); 147 } 148 $Line .= $OptionsInfo{OutDelim} . $Value; 149 } 150 } 151 if ($OptionsInfo{FileOutput}) { 152 print OUTFILE "$Line\n"; 153 } 154 else { 155 print "$Line\n"; 156 } 157 } 158 else { 159 # Format and list data... 160 $Line = ''; 161 for $Index (0 .. $#{$DataLabelRef} ) { 162 $Line = $DataLabelRef->[$Index] . ' ' . $DataValueRef->[$Index]; 163 if ($OptionsInfo{FileOutput}) { 164 print OUTFILE "$Line\n"; 165 } 166 else { 167 print "$Line\n"; 168 } 169 } 170 } 171 } 172 173 # List data for an element... 174 sub ListHeaderRowData { 175 my($DataLabelRef) = @_; 176 my($Line); 177 178 # Format data... 179 $Line = JoinWords($DataLabelRef, $OptionsInfo{OutDelim}, $OptionsInfo{OutQuote}); 180 $Line =~ s/\://g; 181 # List data... 182 if ($OptionsInfo{FileOutput}) { 183 print OUTFILE "$Line\n"; 184 } 185 else { 186 print "$Line\n"; 187 } 188 } 189 190 # Setup isotope data strings... 191 sub SetupIsotopeData { 192 my($ElementID) = @_; 193 my($MassNumber, $RelativeAtomicMass, $NaturalAbundance, $NaturalIsotopeDataRef, @MassNumbers, @RelativeAtomicMasses, @NaturalAbundances); 194 195 # Get natural isotope data: MassNumber, RelativeAtomicMass and NaturalAbundance 196 @MassNumbers = (); @RelativeAtomicMasses = (); @NaturalAbundances = (); 197 $NaturalIsotopeDataRef = PeriodicTable::GetElementNaturalIsotopesData($ElementID); 198 for $MassNumber (sort {$a <=> $b} keys %{$NaturalIsotopeDataRef}) { 199 $RelativeAtomicMass = $NaturalIsotopeDataRef->{$MassNumber}{RelativeAtomicMass}; 200 $NaturalAbundance = $NaturalIsotopeDataRef->{$MassNumber}{NaturalAbundance}; 201 push @MassNumbers, $MassNumber; 202 $RelativeAtomicMass = ($RelativeAtomicMass > 0) ? (sprintf("%.$OptionsInfo{Precision}f", $RelativeAtomicMass) + 0) : ''; 203 push @RelativeAtomicMasses, $RelativeAtomicMass; 204 $NaturalAbundance = ($NaturalAbundance > 0) ? (sprintf("%.$OptionsInfo{Precision}f", $NaturalAbundance) + 0) : ''; 205 push @NaturalAbundances, $NaturalAbundance; 206 } 207 $MassNumber = JoinWords(\@MassNumbers, ",", 0); 208 $RelativeAtomicMass = JoinWords(\@RelativeAtomicMasses, ",", 0); 209 $NaturalAbundance = JoinWords(\@NaturalAbundances, ",", 0); 210 return ($MassNumber, $RelativeAtomicMass, $NaturalAbundance); 211 } 212 213 # Get propery names from categories... 214 sub GetPropertyNamesFromCategories { 215 my($CategoryName) = @_; 216 my(@PropertyNames); 217 218 @PropertyNames = (); 219 if ($CategoryName =~ /^Basic$/i) { 220 @PropertyNames = ('AtomicNumber', 'ElementSymbol', 'ElementName', 'AtomicWeight', 'GroundStateConfiguration', 'GroupNumber', 'PeriodNumber', 'FirstIonizationEnergy'); 221 } elsif ($CategoryName =~ /^BasicAndNaturalIsotope$/i) { 222 # Natural isotope data includes: 'MassNumber', 'RelativeAtomicMass', 'NaturalAbundance' 223 @PropertyNames = ('AtomicNumber', 'ElementSymbol', 'ElementName', 'AtomicWeight', 'GroundStateConfiguration', 'GroupNumber', 'PeriodNumber', 'FirstIonizationEnergy', 'NaturalIsotopeData'); 224 } elsif ($CategoryName =~ /^NaturalIsotope$/i) { 225 @PropertyNames = ('AtomicNumber', 'ElementSymbol', 'ElementName', 'NaturalIsotopeData'); 226 } 227 228 return @PropertyNames; 229 } 230 231 # Process option values... 232 sub ProcessOptions { 233 %OptionsInfo = (); 234 235 $OptionsInfo{Mode} = $Options{mode}; 236 237 $OptionsInfo{OutDelim} = ($Options{outdelim} =~ /^tab$/i ) ? "\t" : (($Options{outdelim} =~ /^semicolon$/i) ? "\;" : "\,"); 238 $OptionsInfo{OutQuote} = ($Options{quote} =~ /^yes$/i) ? 1 : 0; 239 240 $OptionsInfo{Overwrite} = defined $Options{overwrite} ? $Options{overwrite} : undef; 241 $OptionsInfo{OutFileRoot} = defined $Options{root} ? $Options{root} : undef; 242 243 $OptionsInfo{Output} = $Options{output}; 244 $OptionsInfo{OutputStyle} = $Options{outputstyle}; 245 246 $OptionsInfo{ElementRowsOutput} = ($Options{outputstyle} =~ /^ElementRows$/i) ? 1 : 0; 247 $OptionsInfo{FileOutput} = ($Options{output} =~ /^File$/i) ? 1 : 0; 248 249 $OptionsInfo{Precision} = $Options{precision}; 250 251 my($ElementID, @ElementIDs, @GroupElements, @PeriodElements, %GroupNamesMap); 252 253 @{$OptionsInfo{SpecifiedElementIDs}} = (); 254 if (@ARGV >=1 && ($Options{mode} =~ /^All$/i) ) { 255 warn "Warning: Ignoring comman line element IDs: Not valid for All value of \"-m --mode\" option...\n"; 256 } 257 258 # Set up element IDs except for All mode... 259 @ElementIDs = (); 260 %GroupNamesMap = (); 261 262 if (@ARGV >=1 ) { 263 if ($Options{mode} !~ /^All$/i) { 264 push @ElementIDs, @ARGV; 265 } 266 } 267 else { 268 # Setup mode specified default values... 269 my($Nothing); 270 MODE: { 271 if ($Options{mode} =~ /^ElementID$/i) { push @ElementIDs, 'H'; last MODE; }; 272 if ($Options{mode} =~ /^AmericanGroupLabel$/i) { push @ElementIDs, 'IA'; last MODE; }; 273 if ($Options{mode} =~ /^EuropeanGroupLabel$/i) { push @ElementIDs, 'IA'; last MODE; }; 274 if ($Options{mode} =~ /^GroupNumber$/i) { push @ElementIDs, '1'; last MODE; }; 275 if ($Options{mode} =~ /^GroupName$/i) { push @ElementIDs, 'AlkaliMetals'; last MODE; }; 276 if ($Options{mode} =~ /^PeriodNumber$/i) { push @ElementIDs, '1'; last MODE; }; 277 $Nothing = 1; 278 } 279 } 280 if ($Options{mode} =~ /^GroupName$/i) { 281 # Map group names to what's stored in Perioidic table data file... 282 %GroupNamesMap = ('alkalimetals', 'Alkali metal', 'alkalineearthmetals', 'Alkaline earth metal', 'chalcogens', 'Chalcogen', 'coinagemetals', 'Coinage metal', 'halogens', 'Halogen', 'noblegases', 'Noble gas', 'pnictogens', 'Pnictogen', 'lanthanides', 'Lanthanoid', 'lanthanoids', 'Lanthanoid', 'actinides', 'Actinoid', 'actinoids', 'Actinoid' ); 283 } 284 285 # Generate list of elements... 286 if ($Options{mode} =~ /^All$/i) { 287 push @{$OptionsInfo{SpecifiedElementIDs}}, PeriodicTable::GetElements(); 288 } 289 else { 290 ELEMENTID: for $ElementID (@ElementIDs) { 291 if ($Options{mode} =~ /^ElementID$/i) { 292 if (PeriodicTable::IsElement($ElementID)) { 293 push @{$OptionsInfo{SpecifiedElementIDs}}, $ElementID; 294 } 295 else { 296 warn "Ignoring element ID, $ElementID, specified using command line parameter: Unknown element ID...\n"; 297 next ELEMENTID; 298 } 299 } 300 elsif ($Options{mode} =~ /^AmericanGroupLabel$/i) { 301 if (@GroupElements = PeriodicTable::GetElementsByAmericanStyleGroupLabel($ElementID)) { 302 push @{$OptionsInfo{SpecifiedElementIDs}}, @GroupElements; 303 } 304 else { 305 warn "Ignoring American style group label, $ElementID, specified using command line parameter: Unknown group label...\n"; 306 next ELEMENTID; 307 } 308 } 309 elsif ($Options{mode} =~ /^EuropeanGroupLabel$/i) { 310 if (@GroupElements = PeriodicTable::GetElementsByEuropeanStyleGroupLabel($ElementID)) { 311 push @{$OptionsInfo{SpecifiedElementIDs}}, @GroupElements; 312 } 313 else { 314 warn "Ignoring American style group label, $ElementID, specified using command line parameter: Unknown group label...\n"; 315 next ELEMENTID; 316 } 317 } 318 elsif ($Options{mode} =~ /^GroupNumber$/i) { 319 if (@GroupElements = PeriodicTable::GetElementsByGroupNumber($ElementID)) { 320 push @{$OptionsInfo{SpecifiedElementIDs}}, @GroupElements; 321 } 322 else { 323 warn "Ignoring group number, $ElementID, specified using command line parameter: Unknown group number...\n"; 324 next ELEMENTID; 325 } 326 } 327 elsif ($Options{mode} =~ /^GroupName$/i) { 328 if (exists $GroupNamesMap{lc($ElementID)}) { 329 @GroupElements = PeriodicTable::GetElementsByGroupName($GroupNamesMap{lc($ElementID)}); 330 push @{$OptionsInfo{SpecifiedElementIDs}}, @GroupElements; 331 } 332 else { 333 warn "Ignoring group name, $ElementID, specified using command line parameter: Unknown group name...\n"; 334 next ELEMENTID; 335 } 336 } 337 elsif ($Options{mode} =~ /^PeriodNumber$/i) { 338 if (@GroupElements = PeriodicTable::GetElementsByPeriodNumber($ElementID)) { 339 push @{$OptionsInfo{SpecifiedElementIDs}}, @GroupElements; 340 } 341 else { 342 warn "Ignoring period number, $ElementID, specified using command line parameter: Unknown period number...\n"; 343 next ELEMENTID; 344 } 345 } 346 } 347 } 348 SetupSpecifiedProperties(); 349 350 # Setup output file name... 351 $OptionsInfo{OutFileName} = ''; 352 if ($OptionsInfo{FileOutput}) { 353 my($OutFileRoot, $OutFileExt); 354 355 $OutFileRoot = ''; 356 $OutFileExt = "csv"; 357 if ($Options{outdelim} =~ /^tab$/i) { 358 $OutFileExt = "tsv"; 359 } 360 if ($Options{root}) { 361 my ($RootFileDir, $RootFileName, $RootFileExt) = ParseFileName($Options{root}); 362 if ($RootFileName && $RootFileExt) { 363 $OutFileRoot = $RootFileName; 364 } 365 else { 366 $OutFileRoot = $Options{root}; 367 } 368 } 369 else { 370 $OutFileRoot = 'PeriodicTableElementsInfo' . $Options{mode}; 371 } 372 $OptionsInfo{OutFileName} = $OutFileRoot . '.' . $OutFileExt; 373 if (!$Options{overwrite}) { 374 if (-e $OptionsInfo{OutFileName}) { 375 die "Error: Output file, $OptionsInfo{OutFileName}, already exists.\nUse \-o --overwrite\ option or specify a different name using \"-r --root\" option.\n"; 376 } 377 } 378 } 379 } 380 381 # Setup properties to list... 382 sub SetupSpecifiedProperties { 383 $OptionsInfo{Properties} = defined $Options{properties} ? $Options{properties} : undef; 384 385 $OptionsInfo{PropertiesMode} = $Options{propertiesmode}; 386 $OptionsInfo{PropertiesListing} = $Options{propertieslisting}; 387 388 # Make sure atomic appropriate properties/category names are specified... 389 @{$OptionsInfo{SpecifiedProperies}} = (); 390 if ($Options{properties} && ($Options{propertiesmode} =~ /^All$/i) ) { 391 warn "Warning: Ignoring values specifed by \"-p --properties\" option: Not valid for All value of \"--propertiesmode\" option...\n"; 392 } 393 if ($Options{propertiesmode} =~ /^All$/i) { 394 if ($Options{propertieslisting} =~ /^Alphabetical$/i) { 395 push @{$OptionsInfo{SpecifiedProperies}}, PeriodicTable::GetElementPropertiesNames('Alphabetical'); 396 } 397 else { 398 push @{$OptionsInfo{SpecifiedProperies}}, PeriodicTable::GetElementPropertiesNames(); 399 } 400 push @{$OptionsInfo{SpecifiedProperies}}, 'NaturalIsotopeData'; 401 } 402 else { 403 if ($Options{properties}) { 404 if ($Options{propertiesmode} =~ /^Categories$/i) { 405 # Check category name... 406 if ($Options{properties} !~ /^(Basic|BasicAndNaturalIsotope|NaturalIsotope)$/i) { 407 die "Error: The value specified, $Options{properties}, for option \"-p --properties\" in conjunction with \"Categories\" value for option \"--propertiesmode\" is not valid. Allowed values: Basic, BasicAndNaturalIsotope, NaturalIsotope\n"; 408 } 409 # Set propertynames... 410 push @{$OptionsInfo{SpecifiedProperies}}, GetPropertyNamesFromCategories($Options{properties}); 411 } 412 else { 413 # Check property names.. 414 my($Name, $PropertyName, @Names); 415 @Names = split /\,/, $Options{properties}; 416 NAME: for $Name (@Names) { 417 $PropertyName = RemoveLeadingAndTrailingWhiteSpaces($Name); 418 if ($PropertyName =~ /^NaturalIsotopeData$/i) { 419 push @{$OptionsInfo{SpecifiedProperies}}, $PropertyName; 420 next NAME; 421 } 422 if (PeriodicTable::IsElementProperty($PropertyName)) { 423 push @{$OptionsInfo{SpecifiedProperies}}, $PropertyName; 424 } 425 else { 426 warn "Warning: Ignoring value, $Name, specifed by \"-p --properties\" option: Unknown property name...\n"; 427 } 428 } 429 if ($Options{propertieslisting} =~ /^Alphabetical$/i) { 430 # AtomicNumber, ElementSymbol and ElementName are always listed first and 431 # NaturalIsotopeData in the end... 432 my($AtomicNumberPresent, $ElementSymbolPresent, $ElementNamePresent, $NaturalIsotopeDataPresent, @AlphabeticalProperties, %PropertiesMap); 433 %PropertiesMap = (); 434 @AlphabeticalProperties = (); 435 $AtomicNumberPresent = 0; $ElementSymbolPresent = 0; $ElementNamePresent = 0; $NaturalIsotopeDataPresent = 0; 436 NAME: for $Name (@{$OptionsInfo{SpecifiedProperies}}) { 437 if ($Name =~ /^AtomicNumber$/i) { 438 $AtomicNumberPresent = 1; 439 next NAME; 440 } 441 if ($Name =~ /^ElementSymbol$/i) { 442 $ElementSymbolPresent = 1; 443 next NAME; 444 } 445 if ($Name =~ /^ElementName$/i) { 446 $ElementNamePresent = 1; 447 next NAME; 448 } 449 if ($Name =~ /^NaturalIsotopeData$/i) { 450 $NaturalIsotopeDataPresent = 1; 451 next NAME; 452 } 453 $PropertiesMap{$Name} = $Name; 454 } 455 # Setup the alphabetical list... 456 if ($AtomicNumberPresent) { 457 push @AlphabeticalProperties, 'AtomicNumber'; 458 } 459 if ($ElementSymbolPresent) { 460 push @AlphabeticalProperties, 'ElementSymbol'; 461 } 462 if ($ElementNamePresent) { 463 push @AlphabeticalProperties, 'ElementName'; 464 } 465 for $Name (sort keys %PropertiesMap) { 466 push @AlphabeticalProperties, $Name; 467 } 468 if ($NaturalIsotopeDataPresent) { 469 push @AlphabeticalProperties, 'NaturalIsotopeData'; 470 } 471 @{$OptionsInfo{SpecifiedProperies}} = (); 472 push @{$OptionsInfo{SpecifiedProperies}}, @AlphabeticalProperties; 473 } 474 } 475 } 476 else { 477 # Set default value... 478 push @{$OptionsInfo{SpecifiedProperies}}, GetPropertyNamesFromCategories('Basic'); 479 } 480 } 481 } 482 483 # Setup script usage and retrieve command line arguments specified using various options... 484 sub SetupScriptUsage { 485 486 # Retrieve all the options... 487 %Options = (); 488 $Options{mode} = "ElementID"; 489 $Options{outdelim} = "comma"; 490 $Options{output} = "STDOUT"; 491 $Options{outputstyle} = "ElementBlock"; 492 $Options{precision} = 4; 493 $Options{propertiesmode} = "Categories"; 494 $Options{propertieslisting} = "ByGroup"; 495 $Options{quote} = "yes"; 496 497 if (!GetOptions(\%Options, "help|h", "mode|m=s", "outdelim=s", "output=s", "outputstyle=s", "overwrite|o", "precision=i", "properties|p=s", "propertieslisting=s", "propertiesmode=s", "quote|q=s", "root|r=s", "workingdir|w=s")) { 498 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"; 499 } 500 if ($Options{workingdir}) { 501 if (! -d $Options{workingdir}) { 502 die "Error: The value specified, $Options{workingdir}, for option \"-w --workingdir\" is not a directory name.\n"; 503 } 504 chdir $Options{workingdir} or die "Error: Couldn't chdir $Options{workingdir}: $! \n"; 505 } 506 if ($Options{mode} !~ /^(ElementID|AmericanGroupLabel|EuropeanGroupLabel|GroupNumber|GroupName|PeriodNumber|All)$/i) { 507 die "Error: The value specified, $Options{mode}, for option \"-m --mode\" is not valid. Allowed values: ElementID, AmericanGroupLabel, EuropeanGroupLabel, GroupNumber, GroupName, PeriodNumber, or All\n"; 508 } 509 if ($Options{outdelim} !~ /^(comma|semicolon|tab)$/i) { 510 die "Error: The value specified, $Options{outdelim}, for option \"--outdelim\" is not valid. Allowed values: comma, tab, or semicolon\n"; 511 } 512 if ($Options{output} !~ /^(STDOUT|File)$/i) { 513 die "Error: The value specified, $Options{output}, for option \"--output\" is not valid. Allowed values: STDOUT or File\n"; 514 } 515 if ($Options{outputstyle} !~ /^(ElementBlock|ElementRows)$/i) { 516 die "Error: The value specified, $Options{outputstyle}, for option \"--outputstyle\" is not valid. Allowed values: ElementBlock or ElementRows\n"; 517 } 518 if (!IsPositiveInteger($Options{precision})) { 519 die "Error: The value specified, $Options{precision}, for option \"-p --precision\" is not valid. Allowed values: > 0 \n"; 520 } 521 if ($Options{propertiesmode} !~ /^(Categories|Names|All)$/i) { 522 die "Error: The value specified, $Options{propertiesmode}, for option \"--propertiesmode\" is not valid. Allowed values: Categories, Names, or All\n"; 523 } 524 if ($Options{propertieslisting} !~ /^(ByGroup|Alphabetical)$/i) { 525 die "Error: The value specified, $Options{propertieslisting}, for option \"--propertieslisting\" is not valid. Allowed values: ByGroup, or Alphabetical\n"; 526 } 527 if ($Options{quote} !~ /^(yes|no)$/i) { 528 die "Error: The value specified, $Options{quote}, for option \"-q --quote\" is not valid. Allowed values: yes or no\n"; 529 } 530 } 531