/*
 * Configurable ps-like program.
 * Column data and display routines.
 *
 * Copyright (c) 2010 David I. Bell
 * Permission is granted to use, distribute, or modify this source,
 * provided that this copyright notice remains intact.
 */

#include <signal.h>
#include <time.h>

#include "ips.h"


/*
 * Macro to define the column functions and to fill in the COLUMN
 * structure with values.
 */
#define	DEFCOL(symbol, name, header, width, justify, flags)		\
	static const char *	Show##symbol(const PROC * proc);	\
	static int	Sort##symbol(const PROC * proc1, const PROC * proc2); \
	static void	Eval##symbol(const PROC * proc, VALUE * val);	\
	static BOOL	Test##symbol(const PROC * proc);		\
									\
	static	COLUMN	Column##symbol =				\
	{								\
		#name, #header, sizeof(#header) - 1, width, width,	\
		justify, flags,						\
		Show##symbol,	Sort##symbol,				\
		Eval##symbol,	Test##symbol				\
	};


/*
 * The column definitions.
 */
DEFCOL(Pid,		pid,		Pid,
	5,	RIGHT,	USE_NONE)

DEFCOL(Tid,		tid,		Tid,
	5,	RIGHT,	USE_NONE)

DEFCOL(State,		state,		Stat,
	4,	CENTER,	USE_NONE)

DEFCOL(ThreadCount,	threads,	Threads,
	7,	RIGHT,	USE_NONE)

DEFCOL(ParentPid,	parentpid,	PPid,
	5,	RIGHT,	USE_NONE)

DEFCOL(SystemTime,	systemtime,	System Time,
	10,	RIGHT,	USE_NONE)

DEFCOL(UserTime,	usertime,	User Time,
	10,	RIGHT,	USE_NONE)

DEFCOL(RunTime,		runtime,	Runtime,
	10,	RIGHT,	USE_NONE)

DEFCOL(ChildRunTime,	childruntime,	ChildRuntime,
	10,	RIGHT,	USE_NONE)

DEFCOL(PageSwaps,	pageswaps,	PageSwaps,
	10,	RIGHT,	USE_NONE)

DEFCOL(Policy,		policy,		Policy,
	6,	RIGHT,	USE_NONE)

DEFCOL(Priority,	priority,	Pri,
	3,	RIGHT,	USE_NONE)

DEFCOL(RealTimePriority, realtimepriority, RTPri,
	5,	RIGHT,	USE_NONE)

DEFCOL(ChildPageSwaps,	childpageswaps,	ChildPgSwp,
	10,	RIGHT,	USE_NONE)

DEFCOL(Eip,		eip,		EIP,
	LONG_HEX_DIGITS, RIGHT,	USE_NONE)

DEFCOL(Esp,		esp,		ESP,
	LONG_HEX_DIGITS, RIGHT,	USE_NONE)

DEFCOL(WaitChannel,	waitchannel,	WaitChan,
	LONG_HEX_DIGITS, RIGHT,	USE_NONE)

DEFCOL(WaitSymbol,	waitsymbol,	WaitSymbol,
	16,	LEFT,	USE_WCHAN)

DEFCOL(Program,		program,	Program,
	12,	LEFT,	USE_NONE)

DEFCOL(Command,		command,	Command,
	20,	LEFT,	USE_COMMAND)

DEFCOL(Environment,	environment,	Environment,
	25,	LEFT,	USE_ENVIRON)

DEFCOL(ProcessGroup,	processgroup,	PGrp,
	5,	RIGHT,	USE_NONE)

DEFCOL(TtyProcessGroup,	ttyprocessgroup,TtyPG,
	5,	RIGHT,	USE_NONE)

DEFCOL(IdleTime,	idletime,	Idle,
	8,	RIGHT,	USE_INIT)

DEFCOL(DeadTime,	deadtime,	Dead,
	8,	RIGHT,	USE_NONE)

DEFCOL(TtyName,		ttyname,	TtyName,
	8,	LEFT,	USE_DEV_NAME)

DEFCOL(TtyDevice,	ttydevice,	TtyD,
	4,	RIGHT,	USE_NONE)

DEFCOL(UserName,	user,		User,
	8,	LEFT,	USE_USER_NAME)

DEFCOL(UserId,		uid,		Uid,
	5,	RIGHT,	USE_NONE)

DEFCOL(GroupName,	group,		Group,
	8,	LEFT,	USE_GROUP_NAME)

DEFCOL(GroupId,		gid,		Gid,
	5,	RIGHT,	USE_NONE)

DEFCOL(PercentCpu,	percentcpu,	%Cpu,
	6,	RIGHT,	USE_INIT)

DEFCOL(PercentMemory,	percentmemory,	%Mem,
	4,	RIGHT,	USE_NONE)

DEFCOL(Rss,		residentsetsize,Rss,
	5,	RIGHT,	USE_NONE)

DEFCOL(StartTime,	starttime,	Start Time,
	10,	LEFT,	USE_NONE)

DEFCOL(Age,		age,		Age,
	8,	RIGHT,	USE_NONE)

DEFCOL(Flags,		flags,		Flags,
	8,	RIGHT,	USE_NONE)

DEFCOL(PageFaults,	pagefaults,	Faults,
	10,	RIGHT,	USE_NONE)

DEFCOL(MinorPageFaults,	minorpagefaults,MinorFault,
	10,	RIGHT,	USE_NONE)

DEFCOL(MajorPageFaults,	majorpagefaults,MajorFault,
	10,	RIGHT,	USE_NONE)

DEFCOL(SignalCatch,	signalcatch,	SigCatch,
	8,	RIGHT,	USE_NONE)

DEFCOL(SignalIgnore,	signalignore,	SigIgnor,
	8,	RIGHT,	USE_NONE)

DEFCOL(SignalBlock,	signalblock,	SigBlock,
	8,	RIGHT,	USE_NONE)

DEFCOL(OpenFileCount,	openfiles,	Files,
	5,	RIGHT,	USE_OPEN_FILE)

DEFCOL(RunOrder,	runorder,	RunOrder,
	10,	RIGHT,	USE_NONE)

DEFCOL(CurrentDirectory,currentdirectory,Current Dir,
	25,	LEFT,	USE_CURR_DIR)

DEFCOL(RootDirectory,	rootdirectory,	Root Dir,
	25,	LEFT,	USE_ROOT_DIR)

DEFCOL(Executable,	executable,	Executable,
	25,	LEFT,	USE_EXEC_INODE)

DEFCOL(Summary,		summary,	Summary,
	14,	LEFT,	USE_NONE)

DEFCOL(Nice,		nice,		Nic,
	3,	RIGHT,	USE_NONE)

DEFCOL(Size,		size,		Size,
	5,	RIGHT,	USE_NONE)

DEFCOL(RealTimer,	realtimer,	RealTimer,
	10,	RIGHT,	USE_NONE)

DEFCOL(Stdin,		stdin,		Stdin,
	20,	LEFT,	USE_STDIN)

DEFCOL(Stdout,		stdout,		Stdout,
	20,	LEFT,	USE_STDOUT)

DEFCOL(Stderr,		stderr,		Stderr,
	20,	LEFT,	USE_STDERR)

DEFCOL(Stdio,		stdio,		Stdio,
	5,	CENTER,	USE_STDIN | USE_STDOUT | USE_STDERR)

DEFCOL(Active,		active,		Active,
	5,	CENTER,	USE_INIT)

DEFCOL(Processor,	processor,	Proc,
	4,	RIGHT,	USE_NONE)

DEFCOL(States,		states,		States,
	10,	LEFT,	USE_THREADS)


/*
 * Table of all columns.
 * The table is NULL terminated.
 */
static	COLUMN *	columnTable[] =
{
	&ColumnPid,
	&ColumnTid,
	&ColumnState,
	&ColumnParentPid,
	&ColumnSystemTime,
	&ColumnUserTime,
	&ColumnRunTime,
	&ColumnChildRunTime,
	&ColumnPageSwaps,
	&ColumnChildPageSwaps,
	&ColumnEip,
	&ColumnEsp,
	&ColumnWaitChannel,
	&ColumnWaitSymbol,
	&ColumnProgram,
	&ColumnCommand,
	&ColumnEnvironment,
	&ColumnProcessGroup,
	&ColumnTtyProcessGroup,
	&ColumnThreadCount,
	&ColumnIdleTime,
	&ColumnDeadTime,
	&ColumnTtyName,
	&ColumnTtyDevice,
	&ColumnUserName,
	&ColumnGroupName,
	&ColumnUserId,
	&ColumnGroupId,
	&ColumnPercentCpu,
	&ColumnPercentMemory,
	&ColumnRss,
	&ColumnStartTime,
	&ColumnAge,
	&ColumnFlags,
	&ColumnPageFaults,
	&ColumnMinorPageFaults,
	&ColumnMajorPageFaults,
	&ColumnSignalCatch,
	&ColumnSignalIgnore,
	&ColumnSignalBlock,
	&ColumnOpenFileCount,
	&ColumnRunOrder,
	&ColumnCurrentDirectory,
	&ColumnRootDirectory,
	&ColumnExecutable,
	&ColumnSummary,
	&ColumnNice,
	&ColumnPriority,
	&ColumnRealTimePriority,
	&ColumnPolicy,
	&ColumnProcessor,
	&ColumnSize,
	&ColumnRealTimer,
	&ColumnStdin,
	&ColumnStdout,
	&ColumnStderr,
	&ColumnStdio,
	&ColumnActive,
	&ColumnStates,
	NULL
};


/*
 * Default columns when nothing else has been set.
 */
static	COLUMN *	defaultColumns[] =
{
	&ColumnPid,
	&ColumnParentPid,
	&ColumnTtyName,
	&ColumnUserName,
	&ColumnSummary,
	&ColumnRunTime,
	&ColumnCommand,
	NULL
};


/*
 * Temporary buffer to contain constructed column strings.
 */
static	char	showBuffer[256];


/*
 * Other static routines.
 */
static	void	TicksToString(char * buf, long ticks);


/*
 * Default the widths of all the columns.
 */
void
DefaultColumnWidths(void)
{
	COLUMN **	columnPtr;
	COLUMN *	column;

	for (columnPtr = columnTable; *columnPtr; columnPtr++)
	{
		column = *columnPtr;

		column->width = column->initWidth;
	}
}


/*
 * List the available columns to stdout.
 */
void
ListColumns(void)
{
	COLUMN **	columnPtr;
	const COLUMN *	column;

	printf("Column Name          Displayed As    Width\n");
	printf("-----------          ------------    -----\n");

	for (columnPtr = columnTable; *columnPtr; columnPtr++)
	{
		column = *columnPtr;

		printf("%-20s %-15s %3d\n", column->name, column->heading,
			column->width);
	}

	printf("\n");
	printf("Note: Column names may be abbreviated.  They are used in\n");
	printf("several ways: displaying, sorting, and for the cond option.\n");
}


/*
 * Set the default columns.
 */
void
DefaultColumns(void)
{
	COLUMN **	src;
	COLUMN **	dest;

	dest = showList;
	src = defaultColumns;
	showCount = 0;

	while (*src)
	{
		*dest++ = *src++;
		showCount++;
	}
}


/*
 * Find the column with the given name.
 * Abbreviations are allowed.
 * Returns NULL if there was no match or it was ambiguous.
 */
COLUMN *
FindColumn(const char * name)
{
	COLUMN **	columnPtr;
	COLUMN *	column;
	COLUMN *	match;
	int		count;
	int		len;
	int		nameLength;

	match = NULL;
	count = 0;

	nameLength = strlen(name);

	for (columnPtr = columnTable; *columnPtr; columnPtr++)
	{
		column = *columnPtr;

		len = strlen(column->name);

		if ((len < nameLength) ||
			((memcmp(name, column->name, nameLength) != 0)))
				continue;

		if (len == nameLength)
			return column;

		match = column;
		count++;
	}

	if (count == 1)
		return match;

	return NULL;
}


/*
 * Functions to sort various columns based on comparing two processes.
 * This returns a negative value if the item for the first process is less
 * than the second process, a positive value if the item is greater, or
 * zero if the item is the same for both processes.
 */
static int
SortPid(const PROC * proc1, const PROC * proc2)
{
	return proc1->pid - proc2->pid;
}


static int
SortTid(const PROC * proc1, const PROC * proc2)
{
	if ((proc1->tid == NO_THREAD_ID) && (proc2->tid != NO_THREAD_ID))
		return -1;

	if ((proc1->tid != NO_THREAD_ID) && (proc2->tid == NO_THREAD_ID))
		return 1;

	if ((proc1->tid == proc1->pid) && (proc2->tid != proc2->pid))
		return -1;

	if ((proc1->tid != proc1->pid) && (proc2->tid == proc2->pid))
		return 1;

	if (proc1->tid < proc2->tid)
		return -1;

	if (proc1->tid > proc2->tid)
		return 1;

	return 0;
}


static int
SortState(const PROC * proc1, const PROC * proc2)
{
	return GetState(proc1) - GetState(proc2);
}


static int
SortStates(const PROC * proc1, const PROC * proc2)
{
	return strcmp(proc1->states, proc2->states);
}


static int
SortParentPid(const PROC * proc1, const PROC * proc2)
{
	return proc1->parentPid - proc2->parentPid;
}


static int
SortThreadCount(const PROC * proc1, const PROC * proc2)
{
	return proc1->threadCount - proc2->threadCount;
}


static int
SortSystemTime(const PROC * proc1, const PROC * proc2)
{
	return proc1->systemRunTime - proc2->systemRunTime;
}


static int
SortUserTime(const PROC * proc1, const PROC * proc2)
{
	return proc1->userRunTime - proc2->userRunTime;
}


static int
SortRunTime(const PROC * proc1, const PROC * proc2)
{
	return (proc1->systemRunTime + proc1->userRunTime) - (proc2->systemRunTime + proc2->userRunTime);
}


static int
SortChildRunTime(const PROC * proc1, const PROC * proc2)
{
	return (proc1->childSystemRunTime + proc1->childUserRunTime) -
		(proc2->childSystemRunTime + proc2->childUserRunTime);
}


static int
SortPageSwaps(const PROC * proc1, const PROC * proc2)
{
	return proc1->pagesSwapped - proc2->pagesSwapped;
}


static int
SortChildPageSwaps(const PROC * proc1, const PROC * proc2)
{
	return proc1->childPagesSwapped - proc2->childPagesSwapped;
}


static int
SortEip(const PROC * proc1, const PROC * proc2)
{
	return proc1->eip - proc2->eip;
}


static int
SortEsp(const PROC * proc1, const PROC * proc2)
{
	return proc1->esp - proc2->esp;
}


static int
SortWaitChannel(const PROC * proc1, const PROC * proc2)
{
	return proc1->waitChan - proc2->waitChan;
}


static int
SortWaitSymbol(const PROC * proc1, const PROC * proc2)
{
	return strcmp(proc1->waitChanSymbol, proc2->waitChanSymbol);
}


static int
SortProgram(const PROC * proc1, const PROC * proc2)
{
	return strcmp(proc1->program, proc2->program);
}


static int
SortCommand(const PROC * proc1, const PROC * proc2)
{
	return strcmp(proc1->command, proc2->command);
}


static int
SortEnvironment(const PROC * proc1, const PROC * proc2)
{
	return strcmp(proc1->environment, proc2->environment);
}


static int
SortProcessGroup(const PROC * proc1, const PROC * proc2)
{
	return proc1->processGroup - proc2->processGroup;
}


static int
SortTtyProcessGroup(const PROC * proc1, const PROC * proc2)
{
	return proc1->ttyProcessGroup - proc2->ttyProcessGroup;
}


static int
SortIdleTime(const PROC * proc1, const PROC * proc2)
{
	return GetLastActiveTime(proc2) - GetLastActiveTime(proc1);
}


static int
SortDeadTime(const PROC * proc1, const PROC * proc2)
{
	return proc2->deathTime - proc1->deathTime;
}


static int
SortTtyName(const PROC * proc1, const PROC * proc2)
{
	const char *	name1;
	const char *	name2;

	if (proc1->ttyDevice == proc2->ttyDevice)
		return 0;

	name1 = FindDeviceName(proc1->ttyDevice);
	name2 = FindDeviceName(proc2->ttyDevice);

	if (name1 && name2)
		return strcmp(name1, name2);

	if (!name1 && name2)
		return -1;

	if (name1 && !name2)
		return 1;

	return ((long) proc1->ttyDevice) - ((long) proc2->ttyDevice);
}


static int
SortTtyDevice(const PROC * proc1, const PROC * proc2)
{
	return ((long) proc1->ttyDevice) - ((long) proc2->ttyDevice);
}


static int
SortUserName(const PROC * proc1, const PROC * proc2)
{
	const char *	name1;
	const char *	name2;

	if (proc1->uid == proc2->uid)
		return 0;

	name1 = FindUserName(proc1->uid);
	name2 = FindUserName(proc2->uid);

	if (name1 && name2)
		return strcmp(name1, name2);

	if (!name1 && name2)
		return -1;

	if (name1 && !name2)
		return 1;

	return ((long) proc1->uid) - ((long) proc2->uid);
}


static int
SortUserId(const PROC * proc1, const PROC * proc2)
{
	return ((long) proc1->uid) - ((long) proc2->uid);
}


static int
SortGroupName(const PROC * proc1, const PROC * proc2)
{
	const char *	name1;
	const char *	name2;

	if (proc1->gid == proc2->gid)
		return 0;

	name1 = FindGroupName(proc1->gid);
	name2 = FindGroupName(proc2->gid);

	if (name1 && name2)
		return strcmp(name1, name2);

	if (!name1 && name2)
		return -1;

	if (name1 && !name2)
		return 1;

	return ((long) proc1->gid) - ((long) proc2->gid);
}


static int
SortGroupId(const PROC * proc1, const PROC * proc2)
{
	return ((long) proc1->gid) - ((long) proc2->gid);
}


static int
SortPercentCpu(const PROC * proc1, const PROC * proc2)
{
	return proc1->percentCpu - proc2->percentCpu;
}


static int
SortPercentMemory(const PROC * proc1, const PROC * proc2)
{
	return proc1->percentMemory - proc2->percentMemory;
}


static int
SortRss(const PROC * proc1, const PROC * proc2)
{
	return proc1->rss - proc2->rss;
}


static int
SortStartTime(const PROC * proc1, const PROC * proc2)
{
	return proc1->startTimeTicks - proc2->startTimeTicks;
}


static int
SortAge(const PROC * proc1, const PROC * proc2)
{
	return proc2->startTimeTicks - proc1->startTimeTicks;
}


static int
SortFlags(const PROC * proc1, const PROC * proc2)
{
	return proc1->flags - proc2->flags;
}


static int
SortPageFaults(const PROC * proc1, const PROC * proc2)
{
	return (proc1->minorFaults + proc1->majorFaults) -
		(proc2->minorFaults + proc2->majorFaults);
}


static int
SortMinorPageFaults(const PROC * proc1, const PROC * proc2)
{
	return proc1->minorFaults - proc2->minorFaults;
}


static int
SortMajorPageFaults(const PROC * proc1, const PROC * proc2)
{
	return proc1->majorFaults - proc2->majorFaults;
}


static int
SortSignalCatch(const PROC * proc1, const PROC * proc2)
{
	return proc1->sigCatch - proc2->sigCatch;
}


static int
SortSignalIgnore(const PROC * proc1, const PROC * proc2)
{
	return proc1->sigIgnore - proc2->sigIgnore;
}


static int
SortSignalBlock(const PROC * proc1, const PROC * proc2)
{
	return proc1->sigBlock - proc2->sigBlock;
}


static int
SortOpenFileCount(const PROC * proc1, const PROC * proc2)
{
	if (proc1->openFiles < proc2->openFiles)
		return -1;

	if (proc1->openFiles > proc2->openFiles)
		return 1;

	return 0;
}


static int
SortRunOrder(const PROC * proc1, const PROC * proc2)
{
	ULONG	runOrder1 = GetRunOrder(proc1);
	ULONG	runOrder2 = GetRunOrder(proc2);

	if (runOrder1 < runOrder2)
		return -1;

	if (runOrder1 > runOrder2)
		return 1;

	return 0;
}


static int
SortCurrentDirectory(const PROC * proc1, const PROC * proc2)
{
	return strcmp(proc1->cwdPath, proc2->cwdPath);
}


static int
SortRootDirectory(const PROC * proc1, const PROC * proc2)
{
	return strcmp(proc1->rootPath, proc2->rootPath);
}


static int
SortExecutable(const PROC * proc1, const PROC * proc2)
{
	return strcmp(proc1->execPath, proc2->execPath);
}


static int
SortStdin(const PROC * proc1, const PROC * proc2)
{
	return strcmp(proc1->stdioPaths[0], proc2->stdioPaths[0]);
}


static int
SortStdout(const PROC * proc1, const PROC * proc2)
{
	return strcmp(proc1->stdioPaths[1], proc2->stdioPaths[1]);
}


static int
SortStderr(const PROC * proc1, const PROC * proc2)
{
	return strcmp(proc1->stdioPaths[2], proc2->stdioPaths[2]);
}


static int
SortStdio(const PROC * proc1, const PROC * proc2)
{
	char	buf[8];

	strcpy(buf, ShowStdio(proc1));

	return strcmp(buf, ShowStdio(proc2));
}


static int
SortSummary(const PROC * proc1, const PROC * proc2)
{
	char	buf[30];

	strcpy(buf, ShowSummary(proc1));

	return strcmp(buf, ShowSummary(proc2));
}


static int
SortPriority(const PROC * proc1, const PROC * proc2)
{
	if (proc1->priority < proc2->priority)
		return -1;

	if (proc1->priority > proc2->priority)
		return 1;

	return 0;
}


static int
SortPolicy(const PROC * proc1, const PROC * proc2)
{
	if (proc1->policy < proc2->policy)
		return -1;

	if (proc1->policy > proc2->policy)
		return 1;

	return 0;
}


static int
SortRealTimePriority(const PROC * proc1, const PROC * proc2)
{
	if (proc1->realTimePriority < proc2->realTimePriority)
		return -1;

	if (proc1->realTimePriority > proc2->realTimePriority)
		return 1;

	return 0;
}


static int
SortNice(const PROC * proc1, const PROC * proc2)
{
	if (proc1->nice < proc2->nice)
		return -1;

	if (proc1->nice > proc2->nice)
		return 1;

	return 0;
}


static int
SortProcessor(const PROC * proc1, const PROC * proc2)
{
	if (proc1->processor < proc2->processor)
		return -1;

	if (proc1->processor > proc2->processor)
		return 1;

	return 0;
}


static int
SortSize(const PROC * proc1, const PROC * proc2)
{
	if (proc1->virtualSize < proc2->virtualSize)
		return -1;

	if (proc1->virtualSize > proc2->virtualSize)
		return 1;

	return 0;
}


static int
SortRealTimer(const PROC * proc1, const PROC * proc2)
{
	if (proc1->itRealValue < proc2->itRealValue)
		return -1;

	if (proc1->itRealValue > proc2->itRealValue)
		return 1;

	return 0;
}


static int
SortActive(const PROC * proc1, const PROC * proc2)
{
	BOOL isActive1 = GetIsActive(proc1);
	BOOL isActive2 = GetIsActive(proc2);
	
	if (!isActive1 && isActive2)
		return -1;

	if (isActive1 && !isActive2)
		return 1;

	return 0;
}


/*
 * Routines to evaluate a column, and return it with the specified type.
 * (This is either a string or a number.)
 */
static void
EvalPid(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->pid;
}


static void
EvalTid(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->tid;
}


static void
EvalState(const PROC * proc, VALUE * val)
{
	char *	cp;

	cp = AllocTempString(2);
	cp[0] = GetState(proc);
	cp[1] = '\0';

	val->type = VALUE_STRING;
	val->strVal = cp;
}


static void
EvalStates(const PROC * proc, VALUE * val)
{
	val->type = VALUE_STRING;
	val->strVal = proc->states;
}


static void
EvalParentPid(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->parentPid;
}


static void
EvalThreadCount(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->threadCount;
}


static void
EvalSystemTime(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->systemRunTime;
}


static void
EvalUserTime(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->userRunTime;
}


static void
EvalRunTime(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->systemRunTime + proc->userRunTime;
}


static void
EvalChildRunTime(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->childSystemRunTime + proc->childUserRunTime;
}


static void
EvalPageSwaps(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->pagesSwapped;
}


static void
EvalChildPageSwaps(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->childPagesSwapped;
}


static void
EvalEip(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->eip;
}


static void
EvalEsp(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->eip;
}


static void
EvalWaitChannel(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->waitChan;
}


static void
EvalWaitSymbol(const PROC * proc, VALUE * val)
{
	val->type = VALUE_STRING;
	val->strVal = proc->waitChanSymbol;
}


static void
EvalProgram(const PROC * proc, VALUE * val)
{
	val->type = VALUE_STRING;
	val->strVal = proc->program;
}


static void
EvalCommand(const PROC * proc, VALUE * val)
{
	val->type = VALUE_STRING;
	val->strVal = proc->command;
}


static void
EvalEnvironment(const PROC * proc, VALUE * val)
{
	val->type = VALUE_STRING;
	val->strVal = proc->environment;
}


static void
EvalProcessGroup(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->processGroup;
}


static void
EvalTtyProcessGroup(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->ttyProcessGroup;
}


static void
EvalIdleTime(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = (currentTime - GetLastActiveTime(proc)) / 60;
}


static void
EvalDeadTime(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = 0;

	if (proc->deathTime > 0)
		val->intVal = (currentTime - proc->deathTime) / 60;
}


static void
EvalTtyName(const PROC * proc, VALUE * val)
{
	val->type = VALUE_STRING;
	val->strVal = FindDeviceName(proc->ttyDevice);

	if (val->strVal == NULL)
		val->strVal = "";
}


static void
EvalTtyDevice(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = (long) proc->ttyDevice;
}


static void
EvalUserName(const PROC * proc, VALUE * val)
{
	val->type = VALUE_STRING;
	val->strVal = FindUserName(proc->uid);

	if (val->strVal == NULL)
		val->strVal = "";
}


static void
EvalGroupName(const PROC * proc, VALUE * val)
{
	val->type = VALUE_STRING;
	val->strVal = FindGroupName(proc->uid);

	if (val->strVal == NULL)
		val->strVal = "";
}


static void
EvalUserId(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = (long) proc->uid;
}


static void
EvalGroupId(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = (long) proc->gid;
}


static void
EvalPercentCpu(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->percentCpu;
}


static void
EvalPercentMemory(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->percentMemory;
}


static void
EvalRss(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->rss * 4;
}


static void
EvalStartTime(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->startTimeClock;
}


static void
EvalAge(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = currentTime - proc->startTimeClock;

	if (val->intVal < 0)
		val->intVal = 0;
}


static void
EvalFlags(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->flags;
}


static void
EvalPageFaults(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->minorFaults + proc->majorFaults;
}


static void
EvalMinorPageFaults(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->minorFaults;
}


static void
EvalMajorPageFaults(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->majorFaults;
}


static void
EvalSignalCatch(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->sigCatch;
}


static void
EvalSignalIgnore(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->sigIgnore;
}


static void
EvalSignalBlock(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->sigBlock;
}


static void
EvalOpenFileCount(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->openFiles;
}


static void
EvalRunOrder(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = GetRunOrder(proc);
}


static void
EvalCurrentDirectory(const PROC * proc, VALUE * val)
{
	val->type = VALUE_STRING;
	val->strVal = proc->cwdPath;
}


static void
EvalRootDirectory(const PROC * proc, VALUE * val)
{
	val->type = VALUE_STRING;
	val->strVal = proc->rootPath;
}


static void
EvalExecutable(const PROC * proc, VALUE * val)
{
	val->type = VALUE_STRING;
	val->strVal = proc->execPath;
}


static void
EvalStdin(const PROC * proc, VALUE * val)
{
	val->type = VALUE_STRING;
	val->strVal = proc->stdioPaths[0];
}


static void
EvalStdout(const PROC * proc, VALUE * val)
{
	val->type = VALUE_STRING;
	val->strVal = proc->stdioPaths[1];
}


static void
EvalStderr(const PROC * proc, VALUE * val)
{
	val->type = VALUE_STRING;
	val->strVal = proc->stdioPaths[2];
}


static void
EvalStdio(const PROC * proc, VALUE * val)
{
	val->type = VALUE_STRING;
	val->strVal = CopyTempString(ShowStdio(proc));
}


static void
EvalSummary(const PROC * proc, VALUE * val)
{
	val->type = VALUE_STRING;
	val->strVal = CopyTempString(ShowSummary(proc));
}


static void
EvalPolicy(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->policy;
}


static void
EvalPriority(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->priority;
}


static void
EvalRealTimePriority(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->realTimePriority;
}


static void
EvalNice(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->nice;
}


static void
EvalProcessor(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->processor;
}


static void
EvalSize(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = (proc->virtualSize + 1023) / 1024;
}


static void
EvalRealTimer(const PROC * proc, VALUE * val)
{
	val->type = VALUE_NUMBER;
	val->intVal = proc->itRealValue;
}


static void
EvalActive(const PROC * proc, VALUE * val)
{
	val->type = VALUE_BOOLEAN;
	val->intVal = GetIsActive(proc);
}


/*
 * Routines to test whether a column value is "TRUE" in some sense.
 * The meaning differs from column to column, but generally means that
 * the column value is nonzero or non-null.  These functions are used when
 * the "test" attribute is used on a column name.
 */
static BOOL
TestPid(const PROC * proc)
{
	return (proc->pid != 0);
}


static BOOL
TestTid(const PROC * proc)
{
	return (proc->tid != NO_THREAD_ID);
}


static BOOL
TestState(const PROC * proc)
{
	int state = GetState(proc);

	return ((state != 'Z') && (state != ' '));
}


static BOOL
TestStates(const PROC * proc)
{
	/*
	 * The state of the main process should be good
	 * enough for all of the threads since they are
	 * all zombies or non-existant together.
	 */
	return TestState(proc);
}


static BOOL
TestThreadCount(const PROC * proc)
{
	return (proc->threadCount > 1);
}


static BOOL
TestParentPid(const PROC * proc)
{
	return (proc->parentPid && (proc->parentPid != 1));
}


static BOOL
TestSystemTime(const PROC * proc)
{
	return (proc->systemRunTime != 0);
}


static BOOL
TestUserTime(const PROC * proc)
{
	return (proc->userRunTime != 0);
}


static BOOL
TestRunTime(const PROC * proc)
{
	return ((proc->systemRunTime != 0) || (proc->userRunTime != 0));
}


static BOOL
TestChildRunTime(const PROC * proc)
{
	return ((proc->childSystemRunTime != 0) || (proc->childUserRunTime != 0));
}


static BOOL
TestPageSwaps(const PROC * proc)
{
	return (proc->pagesSwapped != 0);
}


static BOOL
TestChildPageSwaps(const PROC * proc)
{
	return (proc->childPagesSwapped != 0);
}


static BOOL
TestEip(const PROC * proc)
{
	return (proc->eip != 0);
}


static BOOL
TestEsp(const PROC * proc)
{
	return (proc->esp != 0);
}


static BOOL
TestWaitChannel(const PROC * proc)
{
	return (proc->waitChan != 0);
}


static BOOL
TestWaitSymbol(const PROC * proc)
{
	return (proc->waitChanSymbol[0] != '\0');
}


static BOOL
TestProgram(const PROC * proc)
{
	return (proc->program[0] != '\0');
}


static BOOL
TestCommand(const PROC * proc)
{
	return proc->hasCommand;
}


static BOOL
TestEnvironment(const PROC * proc)
{
	return (proc->environment[0] != '\0');
}


static BOOL
TestProcessGroup(const PROC * proc)
{
	return (proc->processGroup != 0);
}


static BOOL
TestTtyProcessGroup(const PROC * proc)
{
	return ((proc->ttyProcessGroup != 0) && (proc->ttyProcessGroup != -1));
}


static BOOL
TestIdleTime(const PROC * proc)
{
	return (GetLastActiveTime(proc) != currentTime);
}


static BOOL
TestDeadTime(const PROC * proc)
{
	return (proc->deathTime != 0);
}


static BOOL
TestTtyName(const PROC * proc)
{
	return ((proc->ttyDevice != 0) && (proc->ttyDevice != BAD_DEVID));
}


static BOOL
TestTtyDevice(const PROC * proc)
{
	return ((proc->ttyDevice != 0) && (proc->ttyDevice != BAD_DEVID));
}


static BOOL
TestUserName(const PROC * proc)
{
	return (FindUserName(proc->uid) != NULL);
}


static BOOL
TestGroupName(const PROC * proc)
{
	return (FindGroupName(proc->gid) != NULL);
}


static BOOL
TestUserId(const PROC * proc)
{
	return (proc->uid != 0);
}


static BOOL
TestGroupId(const PROC * proc)
{
	return (proc->gid != 0);
}


static BOOL
TestPercentCpu(const PROC * proc)
{
	return (proc->percentCpu != 0);
}


static BOOL
TestPercentMemory(const PROC * proc)
{
	return (proc->percentMemory != 0);
}


static BOOL
TestRss(const PROC * proc)
{
	return (proc->rss != 0);
}


static BOOL
TestStartTime(const PROC * proc)
{
	return (proc->startTimeTicks != 0);
}


static BOOL
TestAge(const PROC * proc)
{
	return (proc->startTimeClock < currentTime);
}


static BOOL
TestFlags(const PROC * proc)
{
	return (proc->flags != 0);
}


static BOOL
TestPageFaults(const PROC * proc)
{
	return ((proc->minorFaults != 0) || (proc->majorFaults != 0));
}


static BOOL
TestMinorPageFaults(const PROC * proc)
{
	return (proc->minorFaults != 0);
}


static BOOL
TestMajorPageFaults(const PROC * proc)
{
	return (proc->majorFaults != 0);
}


static BOOL
TestSignalCatch(const PROC * proc)
{
	return (proc->sigCatch != 0);
}


static BOOL
TestSignalIgnore(const PROC * proc)
{
	return (proc->sigIgnore != 0);
}


static BOOL
TestSignalBlock(const PROC * proc)
{
	return (proc->sigBlock != 0);
}


static BOOL
TestOpenFileCount(const PROC * proc)
{
	return (proc->openFiles > 0);
}


static BOOL
TestRunOrder(const PROC * proc)
{
	return (GetRunOrder(proc) > 0);
}


static BOOL
TestCurrentDirectory(const PROC * proc)
{
	return (proc->cwdPath != emptyString);
}


static BOOL
TestRootDirectory(const PROC * proc)
{
	return (proc->rootPath != emptyString);
}


static BOOL
TestExecutable(const PROC * proc)
{
	return (proc->execPath != emptyString);
}


static BOOL
TestStdin(const PROC * proc)
{
	return (proc->stdioPaths[0] != emptyString);
}


static BOOL
TestStdout(const PROC * proc)
{
	return (proc->stdioPaths[1] != emptyString);
}


static BOOL
TestStderr(const PROC * proc)
{
	return (proc->stdioPaths[2] != emptyString);
}


static BOOL
TestStdio(const PROC * proc)
{
	return ((proc->stdioPaths[0] != '\0') ||
		(proc->stdioPaths[1] != '\0') ||
		(proc->stdioPaths[2] != '\0'));
}


static BOOL
TestSummary(const PROC * proc)
{
	return TRUE;
}


static BOOL
TestPolicy(const PROC * proc)
{
	return (proc->policy != 0);
}


static BOOL
TestPriority(const PROC * proc)
{
	return (proc->priority != 0);
}


static BOOL
TestRealTimePriority(const PROC * proc)
{
	return (proc->realTimePriority != 0);
}


static BOOL
TestNice(const PROC * proc)
{
	return (proc->nice != 0);
}


static BOOL
TestProcessor(const PROC * proc)
{
	return (proc->processor != 0);
}


static BOOL
TestSize(const PROC * proc)
{
	return (proc->virtualSize != 0);
}


static BOOL
TestRealTimer(const PROC * proc)
{
	return (proc->itRealValue != 0);
}


static BOOL
TestActive(const PROC * proc)
{
	return GetIsActive(proc);
}


/*
 * Functions to show various columns.
 * This just means return a pointer to a string containing the desired
 * information.  The string should be of minimal length, since left or
 * right space padding is done elsewhere.  The string only has to be valid
 * until the next ShowXXX function is called, and so a common buffer can
 * be used for many routines.
 */
static const char *
ShowPid(const PROC * proc)
{
	sprintf(showBuffer, "%ld", (long) proc->pid);

	return showBuffer;
}


static const char *
ShowTid(const PROC * proc)
{
	if (proc->tid == NO_THREAD_ID)
		return "-";

	sprintf(showBuffer, "%ld", (long) proc->tid);

	return showBuffer;
}


static const char *
ShowState(const PROC * proc)
{
	showBuffer[0] = GetState(proc);
	showBuffer[1] = '\0';

	return showBuffer;
}


static const char *
ShowStates(const PROC * proc)
{
	return proc->states;
}


static const char *
ShowThreadCount(const PROC * proc)
{
	sprintf(showBuffer, "%d", proc->threadCount);

	return showBuffer;
}


static const char *
ShowParentPid(const PROC * proc)
{
	sprintf(showBuffer, "%ld", (long) proc->parentPid);

	return showBuffer;
}


static const char *
ShowSystemTime(const PROC * proc)
{
	TicksToString(showBuffer, proc->systemRunTime);

	return showBuffer;
}


static const char *
ShowUserTime(const PROC * proc)
{
	TicksToString(showBuffer, proc->userRunTime);

	return showBuffer;
}


static const char *
ShowRunTime(const PROC * proc)
{
	TicksToString(showBuffer, proc->systemRunTime + proc->userRunTime);

	return showBuffer;
}


static const char *
ShowChildRunTime(const PROC * proc)
{
	TicksToString(showBuffer, proc->childSystemRunTime + proc->childUserRunTime);

	return showBuffer;
}


static const char *
ShowPageSwaps(const PROC * proc)
{
	sprintf(showBuffer, "%ld", proc->pagesSwapped);

	return showBuffer;
}


static const char *
ShowChildPageSwaps(const PROC * proc)
{
	sprintf(showBuffer, "%ld", proc->childPagesSwapped);

	return showBuffer;
}


static const char *
ShowEip(const PROC * proc)
{
	sprintf(showBuffer, LONG_HEX_FORMAT, proc->eip);

	return showBuffer;
}


static const char *
ShowEsp(const PROC * proc)
{
	sprintf(showBuffer, LONG_HEX_FORMAT, proc->esp);

	return showBuffer;
}


static const char *
ShowWaitChannel(const PROC * proc)
{
	if (proc->waitChan == 0)
		return "";

	sprintf(showBuffer, LONG_HEX_FORMAT, proc->waitChan);

	return showBuffer;
}


static const char *
ShowWaitSymbol(const PROC * proc)
{
	return proc->waitChanSymbol;
}


static const char *
ShowProgram(const PROC * proc)
{
	return proc->program;
}


static const char *
ShowCommand(const PROC * proc)
{
	return proc->command;
}


static const char *
ShowEnvironment(const PROC * proc)
{
	return proc->environment;
}


static const char *
ShowProcessGroup(const PROC * proc)
{
	sprintf(showBuffer, "%ld", (long) proc->processGroup);

	return showBuffer;
}


static const char *
ShowTtyProcessGroup(const PROC * proc)
{
	sprintf(showBuffer, "%ld", (long) proc->ttyProcessGroup);

	return showBuffer;
}


static const char *
ShowIdleTime(const PROC * proc)
{
	char *	cp;
	long	idle;

	cp = showBuffer;

	if (proc->isAncient)
		*cp++ = '+';

	idle = (currentTime - GetLastActiveTime(proc)) / 60;

	if (idle < 60)
		sprintf(cp, "%ld", idle);
	else
		sprintf(cp, "%ld:%02ld", idle / 60, idle % 60);

	return showBuffer;
}


static const char *
ShowDeadTime(const PROC * proc)
{
	char *	cp;
	long	minutes;

	if (proc->deathTime == 0)
		return "-";

	cp = showBuffer;

	minutes = (currentTime - proc->deathTime) / 60;

	if (minutes < 60)
		sprintf(cp, "%ld", minutes);
	else
		sprintf(cp, "%ld:%02ld", minutes / 60, minutes % 60);

	return showBuffer;
}


static const char *
ShowTtyName(const PROC * proc)
{
	const char *	name;

	name = FindDeviceName(proc->ttyDevice);

	if (name != NULL)
		return name;

	sprintf(showBuffer, "%lx", (long) proc->ttyDevice);

	return showBuffer;
}


static const char *
ShowTtyDevice(const PROC * proc)
{
	sprintf(showBuffer, "%lx", (long) proc->ttyDevice);

	return showBuffer;
}


static const char *
ShowUserName(const PROC * proc)
{
	const char *	name;

	name = FindUserName(proc->uid);

	if (name)
		return name;

	sprintf(showBuffer, "%ld", (long) proc->uid);

	return showBuffer;
}


static const char *
ShowGroupName(const PROC * proc)
{
	const char *	name;

	name = FindGroupName(proc->gid);

	if (name)
		return name;

	sprintf(showBuffer, "%ld", (long) proc->gid);

	return showBuffer;
}


static const char *
ShowUserId(const PROC * proc)
{
	sprintf(showBuffer, "%ld", (long) proc->uid);

	return showBuffer;
}


static const char *
ShowGroupId(const PROC * proc)
{
	sprintf(showBuffer, "%ld", (long) proc->gid);

	return showBuffer;
}


static const char *
ShowPercentCpu(const PROC * proc)
{
	sprintf(showBuffer, "%d.%02d", proc->percentCpu / 100,
		proc->percentCpu % 100);

	return showBuffer;
}


static const char *
ShowPercentMemory(const PROC * proc)
{
	sprintf(showBuffer, "%d.%d", proc->percentMemory / 10,
		proc->percentMemory % 10);

	return showBuffer;
}


static const char *
ShowRss(const PROC * proc)
{
	sprintf(showBuffer, "%ld", proc->rss * 4);

	return showBuffer;
}


static const char *
ShowStartTime(const PROC * proc)
{
	int	procAgeDays;
	char *	cp;

	/*
	 * Get the formatted string for the process's start time:
	 *	"Wed Jun 30 21:49:08 1993\n"
	 */
	cp = ctime(&proc->startTimeClock);

	/*
	 * Show the start time as just the hour and minute, unless the
	 * process started more than one day ago, in which case also give
	 * the number of days it has been around.
	 */
	memcpy(showBuffer, cp + 11, 5);
	showBuffer[5] = '\0';

	procAgeDays = (currentTime - proc->startTimeClock)
		/ (60 * 60 * 24);

	if (procAgeDays > 0)
		sprintf(showBuffer + 5, "-%dd", procAgeDays);

	return showBuffer;
}


static const char *
ShowAge(const PROC * proc)
{
	long	minutes;
	long	hours;
	long	days;

	minutes = (currentTime - proc->startTimeClock) / 60;

	if (minutes < 0)
		minutes = 0;

	hours = minutes / 60;
	minutes %= 60;

	days = hours / 24;
	hours %= 24;

	if (days)
		sprintf(showBuffer, "%ldd%02ld:%02ld", days, hours, minutes);
	else if (hours)
		sprintf(showBuffer, "%ld:%02ld", hours, minutes);
	else
		sprintf(showBuffer, "%ld", minutes);

	return showBuffer;
}


static const char *
ShowFlags(const PROC * proc)
{
	sprintf(showBuffer, "%lx", proc->flags);

	return showBuffer;
}


static const char *
ShowPageFaults(const PROC * proc)
{
	sprintf(showBuffer, "%ld", proc->minorFaults + proc->majorFaults);

	return showBuffer;
}


static const char *
ShowMinorPageFaults(const PROC * proc)
{
	sprintf(showBuffer, "%ld", proc->minorFaults);

	return showBuffer;
}


static const char *
ShowMajorPageFaults(const PROC * proc)
{
	sprintf(showBuffer, "%ld", proc->majorFaults);

	return showBuffer;
}


static const char *
ShowSignalCatch(const PROC * proc)
{
	sprintf(showBuffer, "%08lx", proc->sigCatch);

	return showBuffer;
}


static const char *
ShowSignalIgnore(const PROC * proc)
{
	sprintf(showBuffer, "%08lx", proc->sigIgnore);

	return showBuffer;
}


static const char *
ShowSignalBlock(const PROC * proc)
{
	sprintf(showBuffer, "%08lx", proc->sigBlock);

	return showBuffer;
}


static const char *
ShowOpenFileCount(const PROC * proc)
{
	if (proc->openFiles < 0)
		return "-";

	sprintf(showBuffer, "%d", proc->openFiles);

	return showBuffer;
}


static const char *
ShowRunOrder(const PROC * proc)
{
	sprintf(showBuffer, "%lu", GetRunOrder(proc));

	return showBuffer;
}


static const char *
ShowCurrentDirectory(const PROC * proc)
{
	return proc->cwdPath;
}


static const char *
ShowRootDirectory(const PROC * proc)
{
	return proc->rootPath;
}


static const char *
ShowExecutable(const PROC * proc)
{
	return proc->execPath;
}


static const char *
ShowStdin(const PROC * proc)
{
	return proc->stdioPaths[0];
}


static const char *
ShowStdout(const PROC * proc)
{
	return proc->stdioPaths[1];
}


static const char *
ShowStderr(const PROC * proc)
{
	return proc->stdioPaths[2];
}


static const char *
ShowStdio(const PROC * proc)
{
	char *	path;
	char *	tag;
	int	fd;

	strcpy(showBuffer, "---");

	/*
	 * Loop over the stdio file descriptors.
	 */
	for (fd = 0; fd <= 2; fd++)
	{
		path = proc->stdioPaths[fd];
		tag = &showBuffer[fd];

		/*
		 * If there is no path then leave the dash.
		 */
		if (*path == '\0')
			continue;

		/*
		 * If this is a pipe then say so.
		 */
		if (memcmp(path, "pipe:", 5) == 0)
		{
			*tag = 'P';

			continue;
		}

		/*
		 * If this is a socket then say so.
		 */
		if (memcmp(path, "socket:", 7) == 0)
		{
			*tag = 'S';

			continue;
		}

		/*
		 * If this is the null device say so.
		 */
		if (strcmp(path, "/dev/null") == 0)
		{
			*tag = 'N';

			continue;
		}

		/*
		 * If this is a terminal say so.
		 */
		if ((memcmp(path, "/dev/tty", 8) == 0) ||
			(memcmp(path, "/dev/pts/", 9) == 0) ||
			(memcmp(path, "/dev/vc/", 8) == 0))
		{
			*tag = 'T';

			continue;
		}

		/*
		 * Don't know what it is, say it is just some file.
		 */
		*tag = 'F';
	}

	return showBuffer;
}


static const char *
ShowSummary(const PROC * proc)
{
	int	state = GetState(proc);
	long	age;
	char *	cp;

	cp = showBuffer;
	strcpy(cp, "--------------");

	if (proc->deathTime != 0)
		cp[0] = '-';
	else if ((state == 'R') || (state == 'Z') ||
		(state == 'T') || (state == 'D'))
	{
		cp[0] = state;		/* copy state */
	}
	else if (GetIsActive(proc))
		cp[0] = 'A';		/* active */
	else
		cp[0] = 'I';		/* or idle */

	if ((proc->rss == 0) && (proc->virtualSize != 0) && (state != 'Z'))
		cp[1] = 'W';

	if (proc->nice > 0)
		cp[2] = 'N';
	else if (proc->nice < 0)
		cp[2] = 'H';

	if (proc->sessionId == proc->pid)
		cp[3] = 'S';		/* session id leader */

	if (proc->processGroup == proc->pid)
		cp[4] = 'P';		/* process group leader */

	if ((proc->ttyDevice != 0) && (proc->ttyDevice != BAD_DEVID))
		cp[5] = 'T';		/* on a terminal */

	if (proc->ttyProcessGroup == proc->processGroup)
		cp[6] = 'F';		/* foreground process */

	if (proc->parentPid == 1)
		cp[7] = 'I';		/* owned by init */

	if (proc->sigIgnore & (1 << (SIGHUP - 1)))
		cp[8] = 'H';		/* ignores SIGHUP */
	else if (proc->sigCatch & (1 << (SIGHUP - 1)))
		cp[8] = 'h';		/* catches SIGHUP */

	if (proc->sigIgnore & (1 << (SIGTERM - 1)))
		cp[9] = 'T';		/* ignores SIGTERM */
	else if (proc->sigCatch & (1 << (SIGTERM - 1)))
		cp[9] = 't';		/* catches SIGTERM */

	if (proc->uid == myUid)
		cp[10] = 'U';		/* has my user id */

	if (proc->gid == myGid)
		cp[11] = 'G';		/* has my group id */

	if (proc->uid == 0)
		cp[12] = 'R';		/* root process */
	else if (proc->uid < BASE_USER_UID)
		cp[12] = 'S';		/* server process */

	age = currentTime - proc->startTimeClock;

	if (age >= (60 * 60 * 24 * 7))
		cp[13] = 'W';		/* week old */
	else if (age >= (60 * 60 * 24))
		cp[13] = 'D';		/* day old */
	else if (age >= (60 * 60))
		cp[13] = 'H';		/* hour old */
	else if (age >= (60 * 10))
		cp[13] = 'T';		/* ten minutes old */
	else if (age >= (60 * 5))
		cp[13] = 'F';		/* five minutes old */
	else if (age >= 60)
		cp[13] = 'M';		/* minute old */
	else
		cp[13] = 'N';		/* new process */

	return showBuffer;
}


static const char *
ShowPolicy(const PROC * proc)
{
	sprintf(showBuffer, "%ld", proc->policy);

	return showBuffer;
}


static const char *
ShowPriority(const PROC * proc)
{
	sprintf(showBuffer, "%ld", proc->priority);

	return showBuffer;
}


static const char *
ShowRealTimePriority(const PROC * proc)
{
	sprintf(showBuffer, "%ld", proc->realTimePriority);

	return showBuffer;
}


static const char *
ShowNice(const PROC * proc)
{
	sprintf(showBuffer, "%ld", proc->nice);

	return showBuffer;
}


static const char *
ShowProcessor(const PROC * proc)
{
	sprintf(showBuffer, "%ld", (long) proc->processor);

	return showBuffer;
}


static const char *
ShowSize(const PROC * proc)
{
	sprintf(showBuffer, "%ld", (proc->virtualSize + 1023) / 1024);

	return showBuffer;
}


static const char *
ShowRealTimer(const PROC * proc)
{
	long	intPart;
	long	fracPart;

	intPart = proc->itRealValue / ticksPerSecond;
	fracPart = proc->itRealValue % ticksPerSecond;

	if (fracPart)
	{
		sprintf(showBuffer, "%ld.%02ld", intPart,
			((fracPart * 100) / ticksPerSecond));
	} else
		sprintf(showBuffer, "%ld", intPart);

	return showBuffer;
}


static const char *
ShowActive(const PROC * proc)
{
	return (GetIsActive(proc) ? "active" : "idle");
}


/*
 * Convert a time in ticks into hours, minutes, seconds and hundreths of
 * seconds in the form:
 *	hhh:mm:ss.hh
 * and store that into the supplied buffer.
 */
static void
TicksToString(char * buf, long ticks)
{
	int	hundreths;
	int	seconds;
	int	minutes;
	long	hours;

	hundreths = ticks % ticksPerSecond;
	ticks /= ticksPerSecond;

	seconds = ticks % 60;
	ticks /= 60;

	minutes = ticks % 60;
	ticks /= 60;

	hours = ticks;

	if (hours > 0)
	{
		sprintf(buf, "%ld:%02d:%02d.%02d", hours, minutes, seconds,
			hundreths);
	}
	else if (minutes > 0)
		sprintf(buf, "%d:%02d.%02d", minutes, seconds, hundreths);
	else
		sprintf(buf, "%d.%02d", seconds, hundreths);
}

/* END CODE */
