#!/usr/bin/pike
// dutree - print sorted indented rendition of du output
// as a slight deviation from the perl version, the sizes are still in one
// column, to make it more readable.

array input(array(string) args)
{
  mapping Dirsize=([]);
  mapping Kids=([]);

  object pipe = Stdio.File();
  Process.create_process(({ "du" })+args, ([ "stdout":pipe->pipe() ]));

  string name;
  foreach(pipe->line_iterator();; string line)
  {
    int size;
    [size, name] = array_sscanf(line, "%d%*[ \t]%s");
    Dirsize[name] = size;
    array path = name/"/";
    string parent = path[..sizeof(path)-2]*"/";
    if(!Kids[parent])
      Kids[parent] = ({ name });
    else
      Kids[parent] += ({ name });
  }
  return ({ name, Dirsize, Kids });
}

void getdots(string root, mapping Dirsize, mapping Kids)
{
  int size, cursize;
  size = cursize = Dirsize[root];
  if(Kids[root])
  {
    foreach(Kids[root];; string kid)
    {
      cursize -= Dirsize[kid]; 
      getdots(kid, Dirsize, Kids);
    }
  }
  else
    Kids[root] = ({});

  if(size != cursize)
  {
    string dot = root+"/.";    
    Dirsize[dot] = cursize;
    Kids[root] += ({ dot });
  }
}

void output(string root, mapping Dirsize, mapping Kids, 
            int width, void|string prefix)
{
  if(!prefix)
    prefix="";
  string path = (root/"/")[-1];
  int size = Dirsize[root];
  write("%*d %s%s\n", width, size, prefix, path);
  prefix += "|" + " "*(sizeof(path)-1);
  if(Kids[root])
  {
    array kids = Kids[root];
    // get the dirsize for each kid and sort by that
    sort(Dirsize[kids[*]], kids); 
    
    // make the output for each kid
    output(kids[*], Dirsize, Kids, width, prefix);
  }
}

void main(int argc, array(string) argv)
{
  mapping Dirsize;
  mapping Kids;
  string topdir;

  [ topdir, Dirsize, Kids ] = input(argv[1..]);
  getdots(topdir, Dirsize, Kids);
  output(topdir, Dirsize, Kids, sizeof((string)sort(values(Dirsize))[-1]));
}