#!/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 #======================================================================= sub init { use Getopt::Long; my ($help, $inplace, $ans); my ($var, $val); GetOptions( "h|help" => \$help, "i" => \$inplace, "o=s" => \$outfl, "var=s" => \%varVal, "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 } } #======================================================================= # name - flagged_variable_subst # purpose - set values for variables in "variable[:|=]value" format #======================================================================= sub flagged_variable_subst { my ($strAddr, $var, $val); my (@P); # input parameters #----------------- $strAddr = shift @_; $var = shift @_; $val = shift @_; # variable/value separated by 1 or 2 chars from {':', '='} # (check delimiter characters until good ones found) #--------------------------------------------------- if ($val !~ /\//) { @P = ( $$strAddr =~ m/^(\s*)($var)(\s*)([:|=]{1,2})(\s*)\S*/ ); } elsif ($val !~ /\?/) { @P = ( $$strAddr =~ m?^(\s*)($var)(\s*)([:|=]{1,2})(\s*)\S*? ); } elsif ($val !~ /\-/) { @P = ( $$strAddr =~ m-^(\s*)($var)(\s*)([:|=]{1,2})(\s*)\S*- ); } elsif ($val !~ /\@/) { @P = ( $$strAddr =~ m@^(\s*)($var)(\s*)([:|=]{1,2})(\s*)\S*@ ); } elsif ($val !~ /\&/) { @P = ( $$strAddr =~ m&^(\s*)($var)(\s*)([:|=]{1,2})(\s*)\S*& ); } elsif ($val !~ /\~/) { @P = ( $$strAddr =~ m~^(\s*)($var)(\s*)([:|=]{1,2})(\s*)\S*~ ); } elsif ($val !~ /\!/) { @P = ( $$strAddr =~ m!^(\s*)($var)(\s*)([:|=]{1,2})(\s*)\S*! ); } elsif ($val !~ /\%/) { @P = ( $$strAddr =~ m%^(\s*)($var)(\s*)([:|=]{1,2})(\s*)\S*% ); } elsif ($val !~ m/\{/ and $val !~ m/\}/) { @P = ( $$strAddr =~ m{^(\s*)($var)(\s*)([:|=]{1,2})(\s*)\S*} ); } elsif ($val !~ /\/) { @P = ( $$strAddr =~ m<^(\s*)($var)(\s*)([:|=]{1,2})(\s*)\S*> ); } else { die "Error: unable to find matching delimiter for value = $val;"; } $$strAddr = $P[0].$P[1].$P[2].$P[3].$P[4].$val if @P; } #======================================================================= # 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 # (check delimiter characters until good ones found) #--------------------------------------------------- unless ($val =~ /\|/) { $$strAddr =~ s|$var|$val|g; return } unless ($val =~ /\//) { $$strAddr =~ s/$var/$val/g; return } unless ($val =~ /\^/) { $$strAddr =~ s^$var^$val^g; return } unless ($val =~ /\?/) { $$strAddr =~ s?$var?$val?g; return } unless ($val =~ /\@/) { $$strAddr =~ s@$var@$val@g; return } unless ($val =~ /\&/) { $$strAddr =~ s&$var&$val&g; return } unless ($val =~ /\+/) { $$strAddr =~ s+$var+$val+g; return } unless ($val =~ /\!/) { $$strAddr =~ s!$var!$val!g; return } unless ($val =~ /\%/) { $$strAddr =~ s%$var%$val%g; return } unless ($val =~ /\,/) { $$strAddr =~ s,$var,$val,g; return } unless ($val =~ /\-/) { $$strAddr =~ s-$var-$val-g; return } unless ($val =~ /\=/) { $$strAddr =~ s=$var=$val=g; return } unless ($val =~ /\~/) { $$strAddr =~ s~$var~$val~g; return } unless ($val =~ /\*/) { $$strAddr =~ s*$var*$val*g; return } unless ($val =~ /\./) { $$strAddr =~ s.$var.$val.g; return } unless ($val =~ /\{/ or $val =~ /\}/) { $$strAddr =~ s{$var}{$val}g; return } unless ($val =~ /\(/ or $val =~ /\)/) { $$strAddr =~ s($var)($val)g; return } unless ($val =~ /\/) { $$strAddr =~ s<$var><$val>g; return } unless ($val =~ /\[/ or $val =~ /\]/) { $$strAddr =~ s[$var][$val]g; return } # if you get this far, then there is a problem #--------------------------------------------- die "Error: unable to find substitute delimiters for value = $val;"; } #======================================================================= # 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 -var 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 oDescription: This script replaces variable assignment lines in the following formats, if the "varname" and "value" are given with -var 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 ":", "=", ":=", "=:" is irrelevant and will be preserved in the output. 2. Comments or text on the assignment line in the input file following "value" will be lost in the output. 3. For environment variables, the value assigned with the -var flag takes precedence over the value defined in the environment. 4. The -val flag can occur multiple times for multiple variable assignments or substitutions. EOF exit; }