LINUX.ORG.RU

[perl] метапрограммирование(?)

 


0

0

Есть файл конфигурации (для кабельных модемов, но это неважно).

Выглядит он примерно так:

Main {
/* тут всякое неинтересное */
  SnmpMibObject docsDevFilterIpDefault.0 Integer 1;

  SnmpMibObject docsDevFilterIpSaddr.1 IPAddress 0.0.0.0;
  SnmpMibObject docsDevFilterIpSmask.1 IPAddress 0.0.0.0;
  /* ...еще несколько параметров первого объекта ACL */

  SnmpMibObject docsDevFilterIpSaddr.2 IPAddress 0.0.0.0;
  SnmpMibObject docsDevFilterIpSmask.2 IPAddress 0.0.0.0;
  /* ...и еще несколько параметров второго объекта ACL */
}

Хотелось бы на выходе получить что-то вроде:

# ip-policy --> docsDevFilterIpDefault
$config{ 'common' }{ 'ip-policy' } = 1;

$config{ '1' }{ 'srcaddr' } = '0.0.0.0';
$config{ '1' }{ 'srcmask' } = '0.0.0.0';

$config{ '2' }{ 'srcaddr' } = '0.0.0.0';
$config{ '2' }{ 'srcmask' } = '0.0.0.0';


Как это сделать в лоб -- понятно. Но хочется странного, чтобы
всю структуру файла описать статически, примерно так:

my $matches = [
  'ip-policy' => {
    match => [
      # этот параметр можно задать несколькими способами,
      # поэтому здесь массив шаблонов
      '^docsDevFilterIpDefault\.0$',
      '^mib-2\.69\.1\.6\.3\.0$',
    ],
    default => '1',
    function => \&cm_Integer,
  },

  'srcaddr' => {
    match => [
      '^docsDevFilterIpSaddr\.(\d+)$',
    ],
    default => '0.0.0.0',
    function => \&cm_IPAddress,
  },
];

Но есть несколько затруднений. Параметр srcaddr определяется
по регэкспу '^docsDevFilterIpSaddr\.(\d+)$', и индексировать его надо
по вот этому (\d+) которое в конце. А параметр ip-policy такого
не имеет, и общность нарушается. Плюс еще хочется как можно меньше
привязываться к ключевым словам типа match, default и т.д.,
и оперировать понятиями ХЕШ, МАССИВ, СКАЛЯР, ФУНКЦИЯ.

Нутром чую, что где-то здесь притаилось решение в виде
метапрограммы (eval), но как-то не могу сообразить как его применить.

Каким образом из регэкспа '^docsDevFilterIpSaddr\.(\d+)$' выцепить $1,
да еще засунуть его в инициализацию $config{ ВОТСЮДА }{} ?

Есть какие-нибудь идеи?
anonymous

chego tol'ko ne delayut chtoby LISP ne ispol'zovat'.

anonymous
()

> Каким образом из регэкспа '^docsDevFilterIpSaddr\.(\d+)$' выцепить $1,
> да еще засунуть его в инициализацию $config{ ВОТСЮДА }{} ?

#!/usr/bin/perl

$matches = [
	[ 'ip-policy', \&cm_Integer, 'common',
		qr/^docsDevFilterIpDefault\.0\s/,
		qr/^mib-2\.69\.1\.6\.3\.0$/ ],
	[ 'srcaddr', \&cm_IPAddress, undef,
		qr/^docsDevFilterIpSaddr\.(\d+)\s/ ]
];

while(<>) {
	chomp;
	s/^\s*//;
	next unless s/^SnmpMibObject //;
	s/;$//;
	foreach $m (@$matches) {
		$r = 3;
		while(defined(($R = $m->[$r++]))) {
			next unless m!$R!;
			printf "\$config{ '\%s' }{ '\%s' } = '\%s';\n",
				(defined($m->[2]) ? $m->[2] : $1),
				# или (defined($1) ? ... )
				$m->[0],
				$m->[1]->($');
			last;
		}
	}
}

sub cm_Integer { return shift; }
sub cm_IPAddress { return shift; }

> Нутром чую, что где-то здесь притаилось решение в виде
> метапрограммы (eval), но как-то не могу сообразить как его применить.
Нафига здесь eval?..

anonymous
()

> Есть какие-нибудь идеи?

Есть, perldoc perlfilter ;)

swizard
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.