+
+#----- selection -----
+
+if ($leaves) {
+ debug("leaves");
+ foreach my $p (keys %patches) {
+ debug("leaves $p");
+ my $v = $patches{$p};
+ next if $v->{Info}[0]{Deleted};
+ foreach my $dep (keys %{ $v->{Info}[1] }) {
+ debug("leaves $p $dep");
+ next unless exists $patches{$dep};
+ $patches{$dep}{NotLeaf} = 1;
+ }
+ }
+}
+
+if ($relatedto) {
+ foreach my $p (keys %patches) {
+ my $v = $patches{$p};
+ # mark Related=1 if any patch matching $relatedto includes us
+ foreach my $dep (keys %{ $v->{Info}[3] }) {
+ next unless exists $patches{$dep};
+ my $depv = $patches{$dep};
+ next unless patch_matches_spec($depv->{ParsedName}, $relatedto);
+ $v->{Related} = 1;
+ last;
+ }
+ if (patch_matches_spec($v->{ParsedName}, $relatedto)) {
+ # if we match $relatedto, mark all our inclusions as Related=1
+ foreach my $dep (keys %{ $v->{Info}[3] }) {
+ next unless exists $patches{$dep};
+ $patches{$dep}{Related} = 1;
+ }
+ # oh, and mark ourselves as Related=1 too!
+ $v->{Related} = 1;
+ }
+ }
+}
+
+our @output;
+
+foreach my $p (keys %patches) {
+ my $v = $patches{$p};
+ next if !$deleted && $v->{Info}[0]{Deleted};
+ next if $deleted_only && !$v->{Info}[0]{Deleted};
+ next if $leaves && $v->{NotLeaf};
+ next if $relatedto && !$v->{Related};
+ next if $spec && !patch_matches_spec($v->{ParsedName}, $spec);
+ push @output, $p;
+}
+
+#----- sorting -----
+
+sub sortsub () {
+ my $txt = "sub sort_cmp {\n my \$r;\n";
+ debug("@sort");
+ my $def_vab;
+ $def_vab = sub {
+ foreach my $ab (qw(a b)) {
+ $txt .= " my \$v$ab = \$patches{\$$ab};\n";
+ }
+ $def_vab = sub { };
+ };
+ my $by_r = sub {
+ $txt .= " \$r = $_[0];\n return \$r if \$r;\n";
+ };
+ my $by_parsed = sub {
+ $def_vab->();
+ $by_r->("\$va->{ParsedName}{$_[0]} cmp \$vb->{ParsedName}{$_[0]}");
+ };
+ my %done;
+ foreach my $sort (@sort) {
+ next if $done{$sort}++;
+ if ($sort eq 'fullname') {
+ $by_r->('$a cmp $b');
+ } elsif ($sort eq 'created') {
+ $by_parsed->('Date');
+ } elsif ($sort eq 'nick') {
+ $by_parsed->('Nick');
+ } elsif ($sort eq 'topo') {
+ $def_vab->();
+ foreach my $ix (qw(0 1)) {
+ my $ab = (qw(a b))[$ix];
+ my $ba = (qw(b a))[$ix];
+ my $r = (qw(1 -1))[$ix];
+ $txt .= " return $r if \$v${ab}->{Info}[3]{\$$ba};\n";
+ }
+ } else {
+ die $sort;
+ }
+ }
+ $txt .= " return 0;\n}\n";
+ debug("sortsub | $_") foreach split /\n/, $txt;
+ return $txt;
+}
+eval sortsub()." 1;" or die "$@ ?";
+
+@output = sort sort_cmp @output;
+
+#----- printing -----
+
+my $current_branch = current_branch();
+my $current_patch = '';
+my $ifcurrent;
+if ($current_branch->{Kind} eq 'tip') {
+ $current_patch = $current_branch->{Fullname};
+ $ifcurrent = '>';
+} elsif ($current_branch->{Kind} eq 'base') {
+ $current_patch = $current_branch->{Fullname};
+ $ifcurrent = '#';
+}
+
+foreach my $p (@output) {
+ my $v = $patches{$p};
+ my $pa = $v->{ParsedName};
+ my ($msgkind, $msg) = git_get_object("$pa->{Ref}:.topbloke/msg");
+ die "$p $msgkind ?" unless $msgkind eq 'blob';
+ my $subject =
+ $msg =~ m/^Subject:\s*(?:\[[^][]*\]\s*)?(.*\S)\s*$/mi
+ ? $1 : "[no subject]";
+ printf("%1s%1s %s\@%s/%s/%-20s %s\n",
+ $p eq $current_patch ? $ifcurrent : '',
+ $v->{Info}[0]{Deleted} ? 'D' : '',
+ $pa->{Email}, $pa->{Domain}, $pa->{Date}, $pa->{Nick},
+ $subject)
+ or die $!;
+}
+
+closeout();