Winter
Winter

Reputation: 11

How do I do a search in Perl?

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

Answers (1)

ikegami
ikegami

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

Related Questions