X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2FID3FS%2FPath.pm;h=744946c560e51329b89c974880d344b1380332af;hb=2eb69e8fc1f41c6947afbb88c0cf59565d2eda7a;hp=0c1260dde6e9428ad226600290235f7990fa38b4;hpb=13e50dce4c98b33208f8d5b191e940c46433f61a;p=id3fs.git diff --git a/lib/ID3FS/Path.pm b/lib/ID3FS/Path.pm index 0c1260d..744946c 100644 --- a/lib/ID3FS/Path.pm +++ b/lib/ID3FS/Path.pm @@ -20,10 +20,10 @@ use strict; use warnings; use ID3FS::Path::Node; -our ($STATE_INVALID, $STATE_ROOT, $STATE_TAG, $STATE_TAGVAL, - $STATE_BOOLEAN, $STATE_ALBUMS, $STATE_TRACKLIST, - $STATE_FILE, $STATE_ALL)=(0..8); +our ($STATE_INVALID, $STATE_ROOT, $STATE_TAG, $STATE_BOOLEAN, + $STATE_ALBUMS, $STATE_TRACKLIST, $STATE_FILE, $STATE_ALL)=(0..7); +# operator precedence our %priorities=( "OR" => 0, "AND" => 1, "NOT" => 2 ); our $PATH_ALLTRACKS= "TRACKS"; @@ -97,10 +97,10 @@ sub dirents { @dents=($self->filter($PATH_ALLTRACKS, $PATH_NOARTIST), $self->artists()); } - elsif($state==$STATE_TAG || $state==$STATE_TAGVAL) + elsif($state==$STATE_TAG) { - if($state==$STATE_TAG && $self->at($TYPE_TAG) && - $self->{db}->tag_has_values($self->tail()->id())) + my $tail=$self->tail(); + if($self->is($TYPE_TAG, $tail) && $self->{db}->tag_has_values($tail->id())) { @dents=$self->tags(); } @@ -116,8 +116,7 @@ sub dirents elsif($state==$STATE_BOOLEAN) { my $parent=$self->tail(); - unless($self->is($TYPE_BOOL, $parent) && - $parent->{name} eq "NOT") + unless($self->is($TYPE_BOOL, $parent) && $parent->{name} eq "NOT") { @dents=("NOT"); } @@ -137,7 +136,7 @@ sub dirents } else { - print "DIRENTS: UNHANDLED STATE: $state\n"; + print "id3fsd: INTERNAL ERROR: DIRENTS: UNHANDLED STATE: $state\n"; } return(\@dents, \@fents); } @@ -146,11 +145,11 @@ sub dirents sub parse { my($self)=@_; + $self->state($STATE_ROOT); + return if($self->{path} eq "/"); @{$self->{components}}=split(/\//, $self->{path}); shift @{$self->{components}}; # drop empty field before leading / # print "PATH: $self->{path}\n"; - $self->state($STATE_ROOT); - return if($self->{path} eq "/"); my @parts=@{$self->{components}}; my($tag, $tagval); $self->{elements}=[]; @@ -195,18 +194,16 @@ sub parse } } } - elsif($state==$STATE_TAG || $state==$STATE_TAGVAL) + elsif($state==$STATE_TAG) { my $tag=$self->tail(); # print "SM: TAG/TAGVAL($state): $name\n"; - if($state==$STATE_TAG && $self->is($TYPE_TAG, $tag) && - $self->{db}->tag_has_values($tag->id())) + if($self->is($TYPE_TAG, $tag) && $self->{db}->tag_has_values($tag->id())) { # print "Parsing: parent: $tag->id()\n"; my $tagval=ID3FS::Path::Node->new($self->{db}, $TYPE_TAG, $name, $tag->id()); if(defined($tagval)) { - $self->state($STATE_TAGVAL); # stay in tag state push(@{$self->{elements}}, $tagval); } @@ -353,8 +350,8 @@ sub parse } } - # remove trailing boolean my @elements=@{$self->{elements}}; + # remove trailing boolean while(@elements && $self->is($TYPE_BOOL, $elements[$#elements])) { pop @elements; @@ -362,14 +359,6 @@ sub parse # sort elements by precedence @elements=$self->sort_elements(@elements); $self->{tagtree}=$self->elements_to_tree(\@elements); - if($self->{tagtree}) - { -# use Data::Dumper; -# print "TREE\n"; -# print Dumper $self->{tagtree}; -# my ($conditions, @joins)=$self->{tagtree}->to_sql(); -# print "CONDITIONS(", scalar(@joins), "): ", $conditions, "\n"; - } } sub state @@ -383,6 +372,7 @@ sub state return $self->{state}; } +# link up precedence-sorted list into a binary tree sub elements_to_tree { my($self, $elements)=@_; @@ -408,7 +398,6 @@ sub sort_elements my ($self, @input)=@_; my @opstack=(); my @output=(); -# print "INPUT: ", join(', ', map { $_->{name}; } @input), "\n"; while(my $thing = shift @input) { if($self->is($TYPE_TAG, $thing)) @@ -422,7 +411,6 @@ sub sort_elements } elsif($self->is($TYPE_BOOL, $thing)) { - # bool while(@opstack && ($priorities{$thing->{name}} <= $priorities{$opstack[$#opstack]->{name}})) { @@ -435,7 +423,6 @@ sub sort_elements { push(@output, pop(@opstack)); } -# print "STACK: ", join(', ', map { $_->{name}; } @output), "\n"; return @output; } @@ -484,12 +471,6 @@ sub tail return($self->{elements}->[$#{$self->{elements}}]); } -sub at -{ - my($self, $type)=@_; - return($self->is($type, $self->tail())); -} - sub is { my($self, $type, $thing)=@_; @@ -517,12 +498,8 @@ sub tags return($self->{db}->cmd_firstcol($sql)); } my $hasvals=$self->expecting_values(); - my $parent=$self->trailing_tag_parent(); -# print "THASVALS: $hasvals\n"; -# print "TPARENT: ", (defined($parent)? $parent : "NO"), "\n"; - my @ids=(); my $sql="SELECT tags.name FROM "; - if($self->in_or()) + if($self->want_all_tags()) { $sql .= "files_x_tags\n"; } @@ -538,14 +515,7 @@ sub tags my $id=$self->trailing_tag_id(); my $parentclause= "tags.parents_id='"; - if($hasvals) - { - $parentclause .= $id; - } - elsif($parent) - { - $parentclause .= $parent; - } + $parentclause .= $id if($hasvals); $parentclause .= "'"; push(@andclauses, $parentclause); @@ -574,7 +544,6 @@ sub artists my $sql="SELECT DISTINCT name FROM artists WHERE name!='';"; return($self->{db}->cmd_firstcol($sql)); } - my @ids=(); my $sql=$self->sql_start("artists.name"); $sql .= ("INNER JOIN artists ON files.artists_id=artists.id\n" . "WHERE artists.name != ''\n" . @@ -588,7 +557,6 @@ sub artists sub albums { my($self)=@_; - my @ids=(); my $tail=$self->tail(); if($self->is($TYPE_ARTIST, $tail)) { @@ -691,7 +659,6 @@ sub filename "GROUP BY paths.name, files.name"); print "FILENAME SQL: $sql\n" if($self->{verbose}); my ($path, $name)=$self->{db}->cmd_onerow($sql, $id); - my $id3fs_path=join('/', map { $_->{name}; } @{$self->{elements}}); return($self->{db}->relativise($path, $name, $mountpoint, $self->{path})); } # should never happen @@ -703,21 +670,10 @@ sub tags_subselect my($self)=@_; my $hasvals=$self->expecting_values(); my $tree=$self->{tagtree}; - my $parent=$self->trailing_tag_parent(); - - my $tag=undef; - if($hasvals) - { - $tag=$self->trailing_tag_id(); -# print "Trailing id: $tag\n"; - } - my ($sqlclause, @joins)=(undef, ()); - ($sqlclause, @joins) = $tree->to_sql($hasvals) if($tree); -# print "SQL(" . scalar(@joins) ."): $sqlclause\n"; + my ($sqlclause, @joins)=$tree->to_sql($hasvals) if($tree); my $sql="\tSELECT fxt1.files_id FROM tags t1"; my @crosses=(); my @inners=(); -# $joinsneeded++ if($tag); for(my $i=0; $i <= $#joins; $i++) { my $cnt=$i+1; @@ -734,10 +690,6 @@ sub tags_subselect $sql .= ("\n\t" . join(" ", @crosses)) if(@crosses); $sql .= ("\n" . join("\n", @inners)) if(@inners); $sql .= "\n\tWHERE $sqlclause" if($sqlclause); -# if($tag) -# { -# $sql .= " AND t${joinsneeded}.parents_id='$tag'"; -# } $sql .= "\n\tGROUP BY fxt1.files_id\n"; return $sql; } @@ -771,16 +723,7 @@ sub filter my @outdirs=(); for my $dir (@dirs) { -# print "\nFILTER (",$self->state(), "): $base / $dir\n"; - if($self->empty("$base/$dir")) - { -# print "empty: $base / $dir\n"; - } - else - { -# print "non-empty, accepting: $base / $dir\n"; - push(@outdirs, $dir); - } + push(@outdirs, $dir) unless($self->empty("$base/$dir")); } return(@outdirs); } @@ -796,19 +739,27 @@ sub empty return 1; } -# if path is .../OR/ or .../OR/NOT -sub in_or +# if path is .../OR/ or .../OR/NOT or .../AND/NOT +sub want_all_tags { my($self)=@_; my $tail=$self->tail(); return 0 unless($tail); - return 0 unless($tail->type() == $TYPE_BOOL); - return 1 if($tail->name() eq "OR"); - return 0 unless($tail->name() eq "NOT"); my $parent=$self->tail_parent(); - return 0 unless($parent); - return 0 unless($parent->type() == $TYPE_BOOL); - return 1 if($parent->name() eq "OR"); + my $parent_valid = ($parent && $parent->type() == $TYPE_BOOL); + if($tail->type() == $TYPE_BOOL) + { + return 1 if($tail->name() eq "OR"); + return 0 unless($tail->name() eq "NOT"); + return 0 unless($parent_valid); + return 1 if($parent->name() eq "OR"); + return 1 if($parent->name() eq "AND"); + } + elsif($tail->type() == $TYPE_TAG) + { + return 0 unless($parent_valid); + return 1 if($parent->name() eq "NOT"); + } return 0; }