#!/usr/bin/perl -wCSD use strict; use warnings; use Safe; use YAML::XS; use Scalar::Util qw(looks_like_number); my ($file, @data) = @ARGV; unless (defined($file)) { print {*STDERR} ("1st parameter 'file' is not defined\n"); exit (1); } unless (@data) { print {*STDERR} ("2nd parameter 'data' is not defined\n"); exit (1); } my $yaml = YAML::XS::LoadFile($file); my $compartment = Safe->new(); foreach my $option_data (@data) { my ($option, $value) = $option_data =~ m/^([\w\.\[\]]+)=(.+)$/; if (!(defined($option)) || !(defined($value))) { print {*STDERR} ("Error: can't parse '$option_data'\n"); exit (1); } else { set_value($option, $value); } } YAML::XS::DumpFile($file, $yaml); sub log_debug { my $message = shift; if (defined($ENV{DEBUG})) { print "$message\n"; } } sub set_value { my $option = shift; my $value = shift; my $valref = \$yaml; if ($value =~ /^['"]+.*['"]+$/) { log_debug ('$value is already quoted.'); } elsif (looks_like_number($value)) { log_debug ('Not quoting $value for integers.'); } elsif ($value =~ /^\[.*\]$/) { log_debug ('Not quoting $value for arrays.'); if ($value =~ /^\[\]$/) { log_debug ('Empty array, do not check quoting'); } elsif ($value !~ /^\[['"].+['"]\]$/) { print {*STDERR} ("Error: Elements in array '$value' should be quoted\n"); exit (1); } } elsif ($value =~ /^\{.*\}$/) { log_debug ('Not quoting $value for hashes.'); } else { $value = "\"$value\""; } # If the value is a float number like N.0 - reval turns it into int N # even if it's quoted. if ($value =~ /^['"]*(\d+\.\d+)['"]*$/ ) { $value = $1; log_debug ('$value is a float number so no need to reval() it'); } else { $value = $compartment->reval($value); } for my $component (split(/\./, $option)) { if (ref($valref) eq 'SCALAR' && defined(${$valref})) { print {*STDERR} ("Key resolved to a SCALAR at '$component'; cannot continue.\n"); exit (1); } elsif (looks_like_number($component) && (! defined(${$valref}) || ref(${$valref}) eq 'ARRAY')) { $valref = \${$valref}->[$component]; } elsif ($component eq 'APPEND' && ref($$valref) eq 'ARRAY') { $valref = \${$valref}->[$#{$$valref}+1]; } elsif (! defined(${$valref}) || ref(${$valref}) eq 'HASH') { $valref = \${$valref}->{$component}; } else { print {*STDERR} ("Key resolved to a " . ref(${$valref}) . " reference; refusing to overwrite.\n"); exit (1); } } if (! defined(${$valref}) || ref($valref) eq 'SCALAR') { ${$valref} = $value; } elsif (ref(${$valref}) eq 'ARRAY' && ref($value) eq 'ARRAY') { ${$valref} = $value; } elsif (ref(${$valref}) eq 'HASH' && ref($value) eq 'HASH') { ${$valref} = $value; } else { print {*STDERR} ("Key resolved to a " . ref(${$valref}) . " reference; refusing to overwrite.\n"); exit (1); } }