#!/usr/bin/env perl # +-======-+ # Copyright (c) 2003-2007 United States Government as represented by # the Admistrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # THIS OPEN SOURCE AGREEMENT ("AGREEMENT") DEFINES THE RIGHTS OF USE, # REPRODUCTION, DISTRIBUTION, MODIFICATION AND REDISTRIBUTION OF CERTAIN # COMPUTER SOFTWARE ORIGINALLY RELEASED BY THE UNITED STATES GOVERNMENT AS # REPRESENTED BY THE GOVERNMENT AGENCY LISTED BELOW ("GOVERNMENT AGENCY"). # THE UNITED STATES GOVERNMENT, AS REPRESENTED BY GOVERNMENT AGENCY, IS AN # INTENDED THIRD-PARTY BENEFICIARY OF ALL SUBSEQUENT DISTRIBUTIONS OR # REDISTRIBUTIONS OF THE SUBJECT SOFTWARE. ANYONE WHO USES, REPRODUCES, # DISTRIBUTES, MODIFIES OR REDISTRIBUTES THE SUBJECT SOFTWARE, AS DEFINED # HEREIN, OR ANY PART THEREOF, IS, BY THAT ACTION, ACCEPTING IN FULL THE # RESPONSIBILITIES AND OBLIGATIONS CONTAINED IN THIS AGREEMENT. # # Government Agency: National Aeronautics and Space Administration # Government Agency Original Software Designation: GSC-15354-1 # Government Agency Original Software Title: GEOS-5 GCM Modeling Software # User Registration Requested. Please Visit http://opensource.gsfc.nasa.gov # Government Agency Point of Contact for Original Software: # Dale Hithon, SRA Assistant, (301) 286-2691 # # +-======-+ #======================================================================= # name - vED (variable editor) # purpose - this script assigns values to variables and/or substitutes # values for variables within a file (see usage for details) # # !Revision History # 20110624 J.Stassi Initial version #======================================================================= use strict; use warnings; # global variables #----------------- my ($infil, $outfl, $verbose, $envFlg, %varVal); # main program #------------- { use File::Copy ("move"); my (@var1, @var2, $var, $val, $line, @lineArr); init(); # read and edit lines from input file #------------------------------------ open INFIL, "< $infil" or die "Error: opening infile, $infil: $!"; foreach () { chomp($line = $_); foreach $var (keys %varVal) { $val = $varVal{$var}; flagged_variable_subst(\$line, $var, $val); } @var1 = ( $line =~ /\$(\w+)\b/g ); @var2 = ( $line =~ /\${(\w+)}/g ); foreach $var (@var1) { variable_subst(\$line, $var, 0) } foreach $var (@var2) { variable_subst(\$line, $var, 1) } push @lineArr, "$line\n"; } close INFIL; # write to output file ... #------------------------- if ($outfl) { move $infil, "$infil~" if $outfl eq $infil; open OUTFL, "> $outfl" or die "Error: opening outfile, $outfl: $!"; foreach (@lineArr) { print OUTFL $_ } close OUTFL; } # ... or to STDOUT #----------------- else { foreach (@lineArr) { print $_ } } } #======================================================================= # name - init # purpose - get input parameters # # Note: # The -var flag is maintained for backward compatibility, even though # the -vv flag is the advertised option in the usage message. #======================================================================= sub init { use Getopt::Long; my ($help, $inplace, $ans); my (@varValStr, @varValArr, $str, $num, $vv, $var, $val); GetOptions( "h|help" => \$help, "i" => \$inplace, "o=s" => \$outfl, "var|vv=s@" => \@varValStr, "v" => \$verbose, "env" => \$envFlg ); usage() if $help; usage() unless @ARGV; # get input file name #-------------------- $infil = shift @ARGV; die "Error: Cannot find input file: $infil;" unless -e $infil; if (-B $infil) { print "File appears to be a binary: $infil\n" . "Do you want to continue? (y/n) [n] "; chomp($ans = lc ); unless ($ans eq "y") { print "Quitting\n"; exit } } # output file #------------ if ($inplace) { $outfl = $infil unless $outfl } # extract $var=$val combinations #------------------------------- foreach (@varValStr) { s/^\s*//; s/\s*$//; # remove leading/trailing blanks s/^,*//; s/,*$//; # remove leading/trailing commas # count number of assignments #---------------------------- $num = (s/=/=/g); if ($num < 1) { warn "WARNING: No variable assignment found in expression: $_;"; next; } # split bundled assignments #-------------------------- if ($num > 1) { @varValArr = split /[,]/ } else { @varValArr = ( $_ ) } # store assignments in %varVal hash #---------------------------------- foreach $vv (@varValArr) { unless ($vv =~ /=/) { warn "WARNING: No variable assignment found in expression: $vv;"; next; } ($var, $val) = split /[=]/, $vv; $varVal{$var} = $val; } } } #======================================================================= # name - flagged_variable_subst # purpose - set values for variables in "variable[:|=]value" format #======================================================================= sub flagged_variable_subst { my ($strAddr, $var, $val); my ($comment, @P); # input parameters #----------------- $strAddr = shift @_; $var = shift @_; $val = shift @_; $comment = $1 if $$strAddr =~ m/(\s*\#.*)$/; # variable/value separated by 1 or 2 chars from {':', '='} # (check delimiter character pairs until good one found) #------------------------------------------------------- @P = ( $$strAddr =~ m/^(\s*)($var)(\s*)([:|=]{1,2})(\s*)\S*/ ); if (@P) { $$strAddr = $P[0].$P[1].$P[2].$P[3].$P[4].$val; $$strAddr .= $comment if $comment; } } #======================================================================= # name - variable_subst # purpose - substitute $variable/${variable} variables in a string with # their values. # # input parameters # => $strAddr: address of string potentially containing variable # => $varName: name of variable to substitute value for # => $flg: # if =0 (false), then variable format is $varName (*default) # if =1 (true), then variable format is ${varName} #======================================================================= sub variable_subst { my ($strAddr, $varName, $flg); my ($val, $var); # input parameters #----------------- $strAddr = shift @_; $varName = shift @_; $flg = shift @_; # short-circuit, if user does not want to automatically expand env variables #--------------------------------------------------------------------------- unless ($envFlg) { return unless $varVal{$varName} } # get value from %valVar or from ENV; return if not found #-------------------------------------------------------- $val = undef; $val = $varVal{$varName}; $val = $ENV{$varName} unless defined($val); unless (defined($val)) { warn "Variable, $varName, in $infil, not defined in environment;" if $verbose; return; } # define variable to replace #--------------------------- if ($flg) { $var = "\\\${$varName}" } else { $var = "\\\$$varName" } # replace variable with its value #-------------------------------- $$strAddr =~ s/$var/$val/g; } #======================================================================= # name - usage # purpose - print usage information #======================================================================= sub usage { use File::Basename; my $name = basename $0; print <<"EOF"; Usage: $name infile [options] $name -h where infile is file to be read options -h print usage information -i edit file "in place", i.e. overwrite input file with output -o outfl name of output file; defaults to STDOUT -vv varname=val set or substitute variable "varname" with value "val" -v verbose; warn if undefined environment variables are found -env substitute values for all defined environment variables Description: This script replaces variable assignment lines in the following formats, if the "varname" and "value" are given with -vv flag: varname: value varname = value varname := value varname =: value \$varname or \${varname} (replaced by "value") If the -env flag is given, then environment variables of the format \$varname or \${varname} will be replaced by their values defined in the environment. Environment variables which are not defined will not be changed. Notes: 1. The number of spaces before and after ":", "=", ":=", "=:" in the infile is irrelevant and will be preserved in the output. 2. For environment variables, the value assigned with the -vv flag takes precedence over the value defined in the environment. 3. Multiple variable assignments or substitutions can be made either by using multiple occurrences of the -vv flag or by bundling, i.e. using a single -vv flag followed by multiple assignments separated by commas (no spaces) 4. Do not bundle a variable assignment with others if the assigned value contains a comma (','); otherwise, the comma will be interpreted as a separator between assignments. EOF exit; }