A colleague of mine asked me if I knew how to automatically indent an LDAP filter to make it more readable. E.g.: he wantend something like this:
(&
(&
(&
(&
(mailnickname=*)
(|
(&
(objectCategory=person)
(objectClass=user)
(!
(homeMDB=*)
)
(!
(msExchHomeServerName=*)
)
)
(&
(objectCategory=person)
(objectClass=user)
(|
(homeMDB=*)
(msExchHomeServerName=*)
)
)
(&
(objectCategory=person)
(objectClass=contact)
)
(objectCategory=group)
(objectCategory=publicFolder)
(objectCategory=msExchDynamicDistributionList)
)
)
)
(objectCategory=contact)
(proxyAddresses=smtp:*example.com)
)
)
I didn't want to spend a long time over this, so after a few attempts with the trial-and-error technique and with the help of Devel::ptkdb I came out with this quick and dirty script based on Text::Balanced
#!/usr/bin/perl
use strict ;
use warnings ;
use Text::Balanced qw(extract_multiple) ;
die "Uso: $0 filtro\n" unless @ARGV ;
my ($begop,$begin,$end) = (qr/\([&|!]\s*/, qr/\(\s*/, qr/\)\s*/) ;
my $filter = shift @ARGV ;
my @blocks = extract_multiple($filter,[$begop]) ;
my $step = 0 ;
foreach my $block (@blocks) {
if ($block =~ $begop) {
# Inizia un operatore
print_chunk($step++,$block,1) ;
} else {
# E` un blocco di match, probabilmente sbilanciato
my @matches = extract_multiple($block,[$begin,$end]) ;
# Questi sono match
while (@matches >= 3) {
my @chunks = splice(@matches,0,3) ;
# Fai check sui "chunk" e agisci di conseguenza:
if ($chunks[1] =~ /=/) {
# E` un match:
print_chunk($step,join("",@chunks),1) ;
} else {
# Sfiga
while (my $chunk = shift @chunks) {
if ($chunk =~ $end) {
print_chunk(--$step,$chunk,1) ;
} else {
# Ricarica gli elementi in @matches e riparti
unshift @matches,$chunk,@chunks ;
last ;
}
}
}
}
# Queste sono parentesi che si chiudono
drop_parenses(@matches) ;
}
}
sub print_chunk {
my ($step,$string,$newline) = @_ ;
print " "x$step ;
print $string ;
print "\n" if $newline ;
}
sub drop_parenses {
while (my $parens = shift @_) {
print_chunk(--$step,$parens,1) ;
}
}
I am pretty sure that there are far better ways to do that, and I am interested on how you'd do it. Anyone?