Reputation: 11
I have a problem. I was trying to handle normalization in Perl.
Let's say I have the following two key.txt and value.txt input files.
For example, the key.txt unix_socket_connect
in the first line corresponds to the value.txt allow $1 $2_socket:sock_file write;allow $1 $3:unix_stream_socket connectto;
.
key.txt
:
unix_socket_connect
set_prop
get_prop
unix_socket_send
value.txt
:
allow $1 $2_socket:sock_file write;allow $1 $3:unix_stream_socket connectto;
unix_socket_connect($1, property, init)allow $1 $2:property_service set;get_prop($1, $2)
allow $1 $2:file { getattr open read map };
allow $1 $2_socket:sock_file write;allow $1 $3:unix_dgram_socket sendto;
result.txt
:
unix_socket_connect , allow $1 $2_socket:sock_file write;allow $1 $3:unix_stream_socket connectto;
set_prop , allow $1 property_socket:sock_file write;allow $1 init:unix_stream_socket connectto;allow $1 $2:property_service set;allow $1 $2:file { getattr open read map };
get_prop , allow $1 $2:file { getattr open read map };
unix_socket_send , allow $1 $2_socket:sock_file write;allow $1 $3:unix_dgram_socket sendto;
These are used to rewrite the value if the key exists in the content of the value.
It is like expanding a function. Here, the second line contains the values of the first and third lines.
To explain, if unix_socket_connect
is written in the value, the arguments will be reflected in the order of $1
, $2
, and $3
, and then
to see the"unix_socket_connect($1, property, init)
unix_socket_connect($1, property, init) → allow $1 property_socket:sock_file write;allow $1 init:unix_stream_socket connectto;
To achieve this, I came up with the following code.
#!/usr/bin/env perl
use strict;
use warnings;
my $key_file = 'key.txt';
my $value_file = 'value.txt';
my $result_file = 'result.txt';
my @key = ();
my @value = ();
# input text
open(KEY, "$key_file");
while(<KEY>){
push @key ,$_;
}
open(VALUE, "$value_file");
while(<VALUE>){
push @value ,$_;
}
for(my $i=0; $i < $#value+1; $i++){
for(my $j = 0; $j < $#key+1; $j++){
if($value[$i] =~ /$key[$j]/){
$value[$i] = $value[$j];
}
}
}
open (RESULT, "> $result_file") or die "$!";
for(my $i = 0; $i < $#value+1; $i++){
print OUT "$key[$i]" . " ," . "$value[$i]";
}
close(KEY);
close(VALUE);
close(RESULT);
However, I am not getting the output I want, am I not comparing key and value properly?
Upvotes: 1
Views: 122
Reputation: 385506
The problem as I understand it
You want to expand
unix_socket_connect($1, property, init)
to
allow $1 property_socket:sock_file write;allow $1 init:unix_stream_socket connectto;
given defintions such as
my %defs = (
unix_socket_connect => 'allow $1 $2_socket:sock_file write;allow $1 $3:unix_stream_socket connectto;',
...
);
Solution
Say we get to the point where we have
my $name = 'unix_socket_connect';
my $def = 'allow $1 $2_socket:sock_file write;allow $1 $3:unix_stream_socket connectto;'
my @args = ( '$1', 'property', 'init' );
$def
is effectively a simple template. We can resolve this using a substitution.
s{
\$(\d+)
}{
my $i = $1 - 1;
0 <= $i && $i < @args ? $args[$i] : $&
}xeg;
So now we need to find the sub calls. The language doesn't appear to support nesting calls (such as unix_socket_connect(..., getprop(...), ...)
), which makes this fairly easy.
s{
\b (\w+) \b \( ([^()]+) \)
}{
my $name = $1;
my @args = split /\s*,\s*/, $2;
if (defined( my $def = $defs{$name} )) {
$def =~ s{
\$(\d+)
}{
my $i = $1 - 1;
0 <= $i && $i < @args ? $args[$i] : $&
}xegr
} else {
$&
}
}xeg;
Upvotes: 2