/******************************************************************************
* This file is Copyright 1993 by Philip G. Richards.  All Rights Reserved.
* See the file README that came with this distribution for permissions on
* code usage, copying, and distribution.  It comes with absolutely no warranty.
* email: <pgr@prg.ox.ac.uk>
******************************************************************************/

/* ---INFOBEGIN--- *  DO NOT DELETE THIS COMMENT BLOCK!!!
COMMAND du remote "calculate the remote disk usage"
 *  ---INFOEND---  */

#include "client.h"
#include <stdlib.h>
#include "table.h"

static int recursive;
static int want_all, want_summary;
static unsigned int cwdlen;
static char *abscwd;
static u_long grand_total, filcnt;

#define DUBLOCKSIZE 1024

static u_int
block_convert(u_int size)
{
    return (size + DUBLOCKSIZE - 1) / DUBLOCKSIZE;
}

static char *
strip_cwd(char *name, int type, int *rel)
{
    if (strncmp(abscwd, name, cwdlen) == 0)
    {
	/* it's probably a relative pathname... */
	*rel = 1;

	if (type == 1 && name[cwdlen] == 0)
	    return "";

	if (name[cwdlen] == '/')
	    return name + cwdlen;

	/* oh well, maybe not... */
    }

    *rel = 0;

    if (name[0] == '/' && name[1] == 0)
	return "";

    return name;
}

static int
add_file_size(char *name, struct stat *sbufp, int depth)
{
    if (want_all || depth == 0)
    {
	char *sname;
	int rel;

        sname = strip_cwd(name, 0, &rel);

        ffprintf(STDOUT, "%-7d %s%s\n", block_convert(sbufp->st_size),
		 rel? ".": "", sname);
    }

    grand_total += sbufp->st_size;

    return 0;
}

static int
enter_dir(char *name, int depth, char **pdata)
{
    int *curtotal;

    /*
    ** there is no point trying to process this directory if it can't be
    ** read -- check the directory for readability
    */
    if (!validate_operation(name, LITERAL_DIR | UTIL_DIR))
	return -1;

    /*
    ** set up some private data space to hold the current file total on
    ** entry to a directory; this is needed so we can print the total when
    ** the directory is left
    */
    curtotal = (int *)malloc(sizeof(int));
    *curtotal = grand_total;
    *pdata = (char *)curtotal;

    return 0;
}

static void
leave_dir(char *name, int depth, char *data)
{
    if (!want_summary || depth == 0)
    {
	char *sname;
	int rel;

	sname = strip_cwd(name, 1, &rel);
        ffprintf(STDOUT, "%-7d %s%s/\n",
	         block_convert(grand_total - *((int *)data)),
		 rel? ".": "", sname);
    }

    /* data will be free()'d by util_process_file() */
}

static int
do_du(char *name)
{
    if (!validate_operation(name, UTIL_PROCESS_FILE))
	return -1;

    filcnt++;
    return util_process_file(name, recursive, 0, add_file_size,
			     enter_dir, leave_dir);
}

/* ARGSUSED */
int
rdu_main(int argc, char *const*argv, char **envp)
{
    int retval, errcnt, ch;
    static char *here[2] = { ".", 0 };
    int want_total;
    char **argvec;

    recursive = 0;
    want_all = 0;
    want_total = 0;
    want_summary = 0;

    optind = 0;
    opterr = 0;
    errcnt = 0;
#ifdef HAVE_OPTRESET
    optreset = 1;
    optind = 1;
#endif        

    /* options in the style of GNU du ... well, sort of */
    while ((ch = getopt(argc, argv, "acrs")) != EOF)
	switch (ch)
	{
	  case 'a':
	    want_all = 1;
	    break;
	  case 'c':
	    want_total = 1;
	    break;
	  case 'r':
	    recursive = MAXRECURSION;
	    break;
	  case 's':
	    want_summary = 1;
	    break;
	  default:
	    errcnt++;
	    break;
	}

    if (errcnt > 0)
	ffprintf(STDERR, "?du usage: du [-[acrs]] [files...]\n");

    /* cross validate options */
    if (want_summary && want_all)
    {
	ffprintf(STDERR, "?du: cannot both summarize and show all entries\n");
	errcnt = 1;
    }

    /* if any errors in the options, return an error */
    if (errcnt > 0)
    	return 1;

    filcnt = 0;
    grand_total = 0;

    /* special case `du' without arguments -- becomes `du .' */
    argvec = (optind == argc)? here: argv + optind;

    /*
    ** if there is only one argument and no recursion has been requested,
    ** then allow it to be a directory and we will set recursive to be 1
    */
    if (recursive == 0 && optind >= argc - 1)
	recursive = 1;

    abscwd = util_abs_path(env_dir);
    cwdlen = strlen(abscwd);
    /* special case "/" */
    if (cwdlen == 1)
        cwdlen = 0;
    retval = -util_process_arglist(argvec, do_du);
    (void)free(abscwd);

    if (want_total && filcnt > 1)
    {
	ffprintf(STDOUT, "--------:------\n");
	ffprintf(STDOUT, "%-7d   TOTAL\n", block_convert(grand_total));
    }

    client_done();

    return retval;
}


syntax highlighted by Code2HTML, v. 0.9.1