#!/usr/bin/env perl

## Sorts the input lines by directory order:
##   first, every file in a given directory, in sorted order
##   then, process subdirectories recursively, in sorted order
## Example output order:
##   annotatenullable.txt
##   chicory.txt
##   varinfoaux.txt
##   varinfoname.txt
##   asm/asmfile.txt
##   asm/dsforest.txt
##   asm/pptfile.txt
##   asm/testredundantvars.txt
##   asm/x86instruction.txt
##   chicory/arrayinfo.txt
##   chicory/chicorypremain.txt
##   derive/derivation.txt
##   derive/derivationfactory.txt
##   derive/valueandmodified.txt
##   derive/binary/binaryderivation.txt
##   derive/binary/binaryderivationfactory.txt
##   derive/binary/sequencespredicatefactoryfloat.txt
##   derive/binary/sequencespredicatefloat.txt
##   derive/ternary/sequencefloatarbitrarysubsequence.txt
##   derive/ternary/sequencefloatarbitrarysubsequencefactory.txt
##   derive/ternary/ternaryderivation.txt
##   derive/ternary/ternaryderivationfactory.txt
##   derive/unary/sequenceinitial.txt
##   derive/unary/sequenceinitialfactory.txt
##   derive/unary/unaryderivation.txt
##   derive/unary/unaryderivationfactory.txt

## This can be used with "find" to put the results in sorted order.
## (find's default order has to do with where files happen to be stored on
## disk.)  Sorted order may be more sensible to a user, or may make other
## commands more deterministic.  (But for determinism alone, you might as
## well just use "sort", which is faster than this script.)
##
## For example, when making a TAGS file, instead of
##   etags `find . -iname '*.java' -print`
## do
##   etags `find . -iname '*.java' -print | sort-directory-order`

## Note a directory name will appear immediately before its contents if it
## ends with a slash (/), but a directory name that lacks a slash will
## appear with the contents of the parent directory.  If this is
## undesirable, then you want to use `sort` instead of this program.

## Mac OS X has a "-s" option to "find" that is similar (but not
## necessarily identical) to "find | sort".

my $debug = 0;
# $debug = 1;


my @lines = <>;
my @sorted_lines = sort cmp_parents_first @lines;
print @sorted_lines;
exit;




sub num_slashes ( $ ) {
  my ($tmp) = @_;
  return ($tmp =~ tr/\///);
}

sub longest_common_prefix {
  my $prefix = shift;
  for (@_) {
    chop $prefix while (! /^\Q$prefix\E/);
  }
  return $prefix;
}


# Crazily, if the first two lines of this routine are
#   sub cmp_parents_first ( $$ ) {
#     my ($a, $b) = @_;
# then it does not behave properly with sort even though it does
# behave properly when called directly.
# Perl's sort routine is messed up.

# Comparator that places entries in parent directories first.
sub cmp_parents_first {
  if ($debug) { print "cmp_parents_first($a, $b)\n"; }

  my $num_slashes_a = num_slashes($a);
  my $num_slashes_b = num_slashes($b);
  if ($debug) { print "slashes: $num_slashes_a $num_slashes_b\n"; }
  if ($num_slashes_a == $num_slashes_b) {
    return ($a cmp $b);
  }

  my $prefix = longest_common_prefix($a, $b);
  my $num_slashes_prefix = num_slashes($prefix);
  my $num_extra_slashes_a = $num_slashes_a - $num_slashes_prefix;
  my $num_extra_slashes_b = $num_slashes_b - $num_slashes_prefix;
  if ($debug) { print "prefix ($num_slashes_prefix slashes): $prefix\n"; }
  if ($debug) { print "num_extra_slashes $num_extra_slashes_a $num_extra_slashes_b\n"; }

  # If one of the directories contains all the slashes that the other does,
  # plus more, then the one with less slashes is a file in a parent
  # directory and should appear earlier in the sort order.
  if (($num_extra_slashes_a == 0) && ($num_extra_slashes_b != 0)) {
    return -1;
  } elsif (($num_extra_slashes_b == 0) && ($num_extra_slashes_a != 0)) {
    return 1;
  } else {
    return ($a cmp $b);
  }

}