#!/usr/bin/muawk
# du for muLinux
# contributed by: Ed Hynan <ehy@delphi.com>
#

BEGIN {
     ARGC=split(arg,ARGV)+1;

    ls="/bin/ls";
    lscmd = ls " -AilQRqs --color=no";
    gtot = 0;
    opt["b"] = "blocks";

    for ( i = 1; i < ARGC; i++ ) {
        Arg = ARGV[i];
        if ( Arg == "--" ) {
            i++;
            break;
        }
        if ( index(Arg, "-") != 1 )
            break;
        if ( Arg == "-a" || Arg == "--all" ) {
            opt["a"] = 1;
        } else if ( Arg == "-b" || Arg == "--bytes" ) {
            opt["b"] = "bytes";
        } else if ( Arg == "-k" || Arg == "--kilobytes" ) {
            opt["k"] = 1;
        } else if ( Arg == "-c" || Arg == "--total" ) {
            opt["c"] = 1;
        } else if ( Arg == "-l" || Arg == "--count-links" ) {
            opt["l"] = 1;
        } else if ( Arg == "-s" || Arg == "--summarize" ) {
            opt["s"] = 1;
        } else if ( Arg == "-S" || Arg == "--separate-dirs" ) {
            opt["S"] = 1;
        } else {
		help();
            #eprint("bad option: " Arg);
            exit(1);
        }
    }
    if ( opt["a"] && opt["s"] ) {
        eprint("cannot both summarize and show all entries");
        exit(1);
    }
    for ( ; i < ARGC; i++ ) {
        sub("/$", "", ARGV[i]);
        doArg(ARGV[i]);
    }
    if ( opt["c"] )
        prnitem(gtot,"total");
    exit(0);
}

function help()
{
print "Usage: du [OPTION]... [FILE]...";
print "Summarize disk usage of each FILE, recursively for directories.";
print "awk version by: Ed Hynan <ehy@delphi.com>\n";
print "  -a, --all               write counts for all files"
print "  -b, --bytes           print size in bytes"
print "  -c, --total           produce a grand total"
print "  -k, --kilobytes       use 1024-byte blocks, not 512"
print "  -l, --count-links     count sizes many times if hard linked"
print "  -S, --separate-dirs   do not include size of subdirectories"
print "  -s, --summarize       display only a total for each argument"
}


function doArg(Arg    , basecmd, cmd, tmp) {
    basecmd = lscmd " ";
    if ( opt["k"] ) basecmd = basecmd "-k ";
    cmd = basecmd "-d " Arg;

    initdata();
    if ( (cmd | getline) < 1 ) {
        eprint("failed checking " Arg);
        close(cmd);
        return;
    }
    close(cmd);

    tmp = substr($3, 1, 1);
    if ( tmp == "d" ) {
        newdir(Arg);
        newitem(Arg, $1, $2, $3, $4, $7);
        cmd = basecmd Arg;
        while ( (cmd | getline) > 0 ) {
            if ( $0 == "" )
                continue;
            if ( $0 ~ /^.*[^\"]:$/ ) {
                sub(":$", "", $0);
                newdir($0);
            } else if ( $1 !~ /^total$/ ) {
                sub("^\"", "", $11); sub("\".*?", "", $11);
                newitem($11, $1, $2, $3, $4, $7);
            }
        }
        close(cmd);
        prndir(Arg);
    } else {
        if ( opt["b"] == "bytes" )
            tmp = $7;
        else
            tmp = $2;
        prnitem(tmp, Arg);
    }
}

function initdata() {
    delete dirs;
    delete dtree;
    delete hlinks;
    delete items;
    delete entries;
    delete dnames
    iidx = 0;
    didx = -1;
}

function newdir(name) {
    dnames[++didx] = name;
    dirs[name] = 0;
}

function newitem(name, inode, blocks, mode, links, bsize    , t) {
    t = substr(mode, 1, 1);
    items[iidx] = didx;
    items["names",iidx] = name;
    entries["inode",didx,iidx] = inode;
    entries["blocks",didx,iidx] = blocks;
    entries["bytes",didx,iidx] = bsize;
    entries["type",didx,iidx] = t;
    if ( t == "d" ) {
        if ( opt["b"] == "bytes" )
            items[dnames[didx] "/" name] = bsize;
        else
            items[dnames[didx] "/" name] = blocks;
    } else if ( links > 1 ) {
        hlinks[inode] = \
            hlinks[inode] SUBSEP dnames[didx] "/" name;
    }
    iidx++;
}

function prndir(top    , tot, n, nd, ts, tn, ta) {
    tot = 0;

    for ( n = 0; n < iidx; n++ ) {
        nd = items[n];
        tn = dnames[nd] "/" items["names",n];
        ts = entries[opt["b"],nd,n];

        if ( !opt["l"] && (entries["inode",nd,n] in hlinks) ) {
            split(hlinks[entries["inode",nd,n]], ta, SUBSEP);
            # only count 1st link (index 2 in ta).
            if ( tn != ta[2] )
                continue;
        }

        if ( entries["type",nd,n] == "d" ) {
            if ( !opt["S"] )
                dirs[dnames[nd]] += ts;
            dtree[dnames[nd]] = \
                dtree[dnames[nd]] SUBSEP items["names",n];
        } else if ( opt["a"] ) {
            dirs[dnames[nd]] += ts;
            prnitem(ts, tn);
        }
        tot += ts;
    }

    if ( !opt["S"] )
        fixdirtotals(top);

    if ( !opt["s"] )
        for ( n = 1; n <= didx; n++ )
            prnitem(dirs[dnames[n]] + items[dnames[n]], dnames[n]);

    gtot += tot;
    if ( opt["S"] )
        prnitem(dirs[top] + entries[opt["b"],0,0], top);
    else
        prnitem(tot, top);
}

function fixdirtotals(dir    , ta, tn, i) {
    split(dtree[dir], ta, SUBSEP);
    for ( i = 2; (i in ta); i++ ) {
        tn = dir "/" ta[i];
        fixdirtotals(tn);
        dirs[dir] += dirs[tn];
    }
}

function prnitem(size, name) {
    printf("%-7lu %s\n", size, name);
}

function eprint(msg) {
    # If necessary remove the >"/dev/stderr", but /dev/stderr should work.
    print "" "du.awk: " msg >"/dev/stderr";
}



