/*
 * times stuff
 */

#include "sh.h"
#include "ksh_time.h"
#include <sys/times.h>

#if 0
static char *clocktos(clock_t);
#endif

int posh_builtin_times(int UNUSED(argc), char UNUSED(**argv), int UNUSED(flags))
{
	struct tms all;
	long ticks;

	(void) times(&all);
	/*
	shprintf("Shell: %8ss user ", clocktos(all.tms_utime));
	shprintf("%8ss system\n", clocktos(all.tms_stime));
	shprintf("Kids:  %8ss user ", clocktos(all.tms_cutime));
	shprintf("%8ss system\n", clocktos(all.tms_cstime));
	*/
	ticks = sysconf(_SC_CLK_TCK);

#define posh_times_mins(X) ((long)X)/(ticks*60)
#define posh_times_secs(X) (double)(((long)X) % (ticks * 60))/ticks
#define posh_times_minsandsecs(X) posh_times_mins(X), posh_times_secs(X)

	shprintf("%ldm%fs %ldm%fs\n", posh_times_minsandsecs(all.tms_utime), posh_times_minsandsecs(all.tms_stime));
	shprintf("%ldm%fs %ldm%fs\n", posh_times_minsandsecs(all.tms_cutime), posh_times_minsandsecs(all.tms_cstime));

	return 0;
}

#ifdef SILLY_FEATURES
/*
 * time pipeline (really a statement, not a built-in command)
 */
int
timex(t, f)
	struct op *t;
	int f;
{
#define TF_NOARGS	BIT(0)
#define TF_NOREAL	BIT(1)		/* don't report real time */
#define TF_POSIX	BIT(2)		/* report in posix format */
	int rv = 0;
	struct tms t0, t1, tms;
	clock_t t0t, t1t = 0;
	int tf = 0;
	extern clock_t j_usrtime, j_systime; /* computed by j_wait */
	char opts[1];

	t0t = times(&t0);
	if (t->left) {
		/*
		 * Two ways of getting cpu usage of a command: just use t0
		 * and t1 (which will get cpu usage from other jobs that
		 * finish while we are executing t->left), or get the
		 * cpu usage of t->left. at&t ksh does the former, while
		 * pdksh tries to do the later (the j_usrtime hack doesn't
		 * really work as it only counts the last job).
		 */
		j_usrtime = j_systime = 0;
		if (t->left->type == TCOM)
			t->left->str = opts;
		opts[0] = 0;
		rv = execute(t->left, f | XTIME);
		tf |= opts[0];
		t1t = times(&t1);
	} else
		tf = TF_NOARGS;

	if (tf & TF_NOARGS) { /* ksh93 - report shell times (shell+kids) */
		tf |= TF_NOREAL;
		tms.tms_utime = t0.tms_utime + t0.tms_cutime;
		tms.tms_stime = t0.tms_stime + t0.tms_cstime;
	} else {
		tms.tms_utime = t1.tms_utime - t0.tms_utime + j_usrtime;
		tms.tms_stime = t1.tms_stime - t0.tms_stime + j_systime;
	}

	if (!(tf & TF_NOREAL))
		shf_fprintf(shl_out,
			tf & TF_POSIX ? "real %8s\n" : "%8ss real ",
			clocktos(t1t - t0t));
	shf_fprintf(shl_out, tf & TF_POSIX ? "user %8s\n" : "%8ss user ",
		clocktos(tms.tms_utime));
	shf_fprintf(shl_out, tf & TF_POSIX ? "sys  %8s\n" : "%8ss system\n",
		clocktos(tms.tms_stime));
	shf_flush(shl_out);

	return rv;
}

void
timex_hook(t, app)
	struct op *t;
	char ** volatile *app;
{
	char **wp = *app;
	int optc;
	int i, j;
	LameGetopt opt;

	ksh_getopt_reset(&opt, 0);
	opt.optind = 0;	/* start at the start */
	while ((optc = ksh_getopt(wp, &opt, ":p")) != EOF)
		switch (optc) {
		  case 'p':
			t->str[0] |= TF_POSIX;
			break;
		  case '?':
			errorf("time: -%s unknown option", opt.optarg);
		  case ':':
			errorf("time: -%s requires an argument",
				opt.optarg);
		}
	/* Copy command words down over options. */
	if (opt.optind != 0) {
		for (i = 0; i < opt.optind; i++)
			afree(wp[i], ATEMP);
		for (i = 0, j = opt.optind; (wp[i] = wp[j]); i++, j++)
			;
	}
	if (!wp[0])
		t->str[0] |= TF_NOARGS;
	*app = wp;
}
#endif /* SILLY_FEATURES */

#if 0
static char *
clocktos(clock_t t)
{
	static char temp[22]; /* enough for 64 bit clock_t */
	int i;
	char *cp = temp + sizeof(temp);

	/* note: posix says must use max precision, ie, if clk_tck is
	 * 1000, must print 3 places after decimal (if non-zero, else 1).
	 */
	if (CLK_TCK != 100)	/* convert to 1/100'ths */
	    t = (t < 1000000000/CLK_TCK) ?
		    (t * 100) / CLK_TCK : (t / CLK_TCK) * 100;

	*--cp = '\0';
	for (i = -2; i <= 0 || t > 0; i++) {
		if (i == 0)
			*--cp = '.';
		*--cp = '0' + (char)(t%10);
		t /= 10;
	}
	return cp;
}
#endif
