/*
 * Copyright (C) 1994-2018 Altair Engineering, Inc.
 * For more information, contact Altair at www.altair.com.
 *
 * This file is part of the PBS Professional ("PBS Pro") software.
 *
 * Open Source License Information:
 *
 * PBS Pro is free software. You can redistribute it and/or modify it under the
 * terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 *
 * PBS Pro is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Commercial License Information:
 *
 * For a copy of the commercial license terms and conditions,
 * go to: (http://www.pbspro.com/UserArea/agreement.html)
 * or contact the Altair Legal Department.
 *
 * Altair’s dual-license business model allows companies, individuals, and
 * organizations to create proprietary derivative works of PBS Pro and
 * distribute them - whether embedded or bundled with other software -
 * under a commercial license agreement.
 *
 * Use of Altair’s trademarks, including but not limited to "PBS™",
 * "PBS Professional®", and "PBS Pro™" and Altair’s logos is subject to Altair's
 * trademark licensing policies.
 *
 */
/**
 * @file	qstat.c
 * @brief
 * 	qstat - (PBS) show stats of batch jobs, queues, or servers
 *
 * @author	Terry Heidelberg
 * 			Livermore Computing
 *
 * @author  Bruce Kelly
 * 			National Energy Research Supercomputer Center
 *
 * @author  Lawrence Livermore National Laboratory
 * 			University of California
 */

#include <pbs_config.h>   /* the master config generated by configure */
#include <pbs_version.h>

#include "pbs_ifl.h"
#include "cmds.h"
#include "pbs_share.h"
#include <pwd.h>
#include <stdlib.h>
#include "pbs_json.h"
#include "pbs_internal.h"
#include "libutil.h"

#if	TCL_QSTAT
#include	<sys/stat.h>
#include	<tcl.h>
#ifdef NAS /* localmod 071 */
extern char *	tcl_atrsep;
#endif /* localmod 071 */
#endif

/* default server */
char *def_server;
int alt_display_allow = 0;

static void states();
static char *	cvtResvstate(char *);
static int cmp_est_time(struct batch_status *a, struct batch_status *b);
char *cnvt_est_start_time(char *start_time, int shortform);


#if !defined(PBS_NO_POSIX_VIOLATION)
/* defines for alternative display formats */
#define ALT_DISPLAY_a		1		/* -a option - show all jobs */
#define ALT_DISPLAY_i		2		/* -i option - show not running */
#define ALT_DISPLAY_r		4		/* -r option - show only running */
#define ALT_DISPLAY_u		8		/* -u option - list user's jobs */
#define ALT_DISPLAY_n		0x10		/* -n option - add node list */
#define ALT_DISPLAY_s		0x20		/* -s option - add scheduler comment */
#define ALT_DISPLAY_H		0x40		/* -H option - show history(F/M) jobs */
#define ALT_DISPLAY_q		0x80		/* -q option - alt queue display */
#define ALT_DISPLAY_Mb	0x100		/* show sizes in MB */
#define ALT_DISPLAY_Mw	0x200		/* -M option - show sizes in MW */
#define ALT_DISPLAY_G		0x400		/* -G option - show sizes in GB */
#define ALT_DISPLAY_1l	0x800		/* -n -s -f on line line */
#define ALT_DISPLAY_w		0x1000		/* -[a|s|n]w - wide output */
#define ALT_DISPLAY_T		0x2000		/* -T option - estimated start times */
#define ALT_DISPLAY_p		0x4000		/* -p option - percentage completed for the job */
#define ALT_DISPLAY_INCR_WIDTH	0x8000	/* increases qstat header width */

#endif /* not PBS_NO_POSIX_VIOLATION */
#define HPCBP_EXEC_TAG  "jsdl-hpcpa:Executable"
#define CHAR_LINE_LIMIT 78 /* maximum number of characters which can be printed on a line */

static struct attrl basic_attribs[] = {
	{	&basic_attribs[1],
		ATTR_N,
		NULL,
		"",
		SET		},
	{	&basic_attribs[2],
		ATTR_owner,
		NULL,
		"",
		SET		},
	{	&basic_attribs[3],
		ATTR_used,
		NULL,
		"",
		SET		},
	{	&basic_attribs[4],
		ATTR_state,
		NULL,
		"",
		SET		},
	{	NULL,
		ATTR_queue,
		NULL,
		"",
		SET		}
};

static struct attrl alt_attribs[] = {
	{	&alt_attribs[1],
		ATTR_session,
		NULL,
		"",
		SET		},
	{	&basic_attribs[0],
		ATTR_l,
		NULL,
		"",
		SET		}
};

enum output_format_enum {
	FORMAT_DEFAULT = 0,
	FORMAT_DSV,
	FORMAT_JSON,
	FORMAT_MAX
};

/* This array contains the names users may specify for output format. */
static char *output_format_names[] = {"default", "dsv", "json", NULL};

static int  output_format = FORMAT_DEFAULT;
static char *dsv_delim = "|";
static char *delimiter = "\n";
static char *prev_resc_name = NULL;
static int  first_stat = 1;

static struct attrl *display_attribs = &basic_attribs[0];

int cmp_jobs(const void *j1, const void *j2)
{
	char *job1, *job2;
	char *seq_num1 = NULL;
	char *seq_num2 = NULL;
	char *pserver_one = NULL;
	char *pserver_two = NULL;
	int ret = 0;
	int ret_val = 0;
	char *eptr = NULL;
	long jid1,jid2;
	job1 = *(char **)j1;
	job2 = *(char **)j2;
	if (pbs_isjobid(job1)== 0) {
		ret_val = 1;
		goto return_here;
	}
	else if (pbs_isjobid(job2) == 0) {
		ret_val = 1;
		goto return_here;
	}
	else {
		parse_jobid(job1, &seq_num1, &pserver_one, NULL);
		/* default server */
		if (pserver_one == NULL)
			pserver_one =  strdup(def_server);
		else if (pserver_one[0] == '\0')
			strcpy(pserver_one, def_server);
		parse_jobid(job2, &seq_num2, &pserver_two, NULL);
		/* default server */
		if (pserver_two == NULL)
			pserver_two =  strdup(def_server);
		else if (pserver_two[0] == '\0')
			strcpy(pserver_two, def_server);

		ret = strcmp(pserver_one, pserver_two);
		if (ret < 0) {
			ret_val = -1;
			goto return_here;
		}
		else if (ret > 0) {
			ret_val = 1;
			goto return_here;
		}
	}
	/* Server name is same, Now sort on the job id */
	jid1 = strtoll(job1, &eptr, 10);
	jid2 = strtoll(job2, &eptr, 10);
	if (jid1 < jid2) {
		ret_val = -1;
		goto return_here;
	}
	else if (jid1 > jid2) {
		ret_val = 1;
		goto return_here;
	}
	else if (seq_num1!= NULL && seq_num2 != NULL) {
		/* Array sub jobs, sort on the basis of index */
		jid1 = strtoll(seq_num1, &eptr,10);
		jid2 = strtoll(seq_num2, &eptr,10);
		if (jid1 < jid2) {
			ret_val = -1;
			goto return_here;
		}
		else if (jid1 > jid2) {
			ret_val = 1;
			goto return_here;
		}
	}
	/* Same job id getting repeated */
	ret_val = 0;
return_here:
	    free(seq_num1);
	    free(seq_num2);
	    free(pserver_one);
	    free(pserver_two);
	    return ret_val;
}

/**
 * @brief
 *	tests whether the string value is true or false
 *
 * @param[in] string - string to be tested
 *
 * @return Boolean value
 * @retval 0  Failre
 * @retval 1  Success
 *
 */
int
istrue(char *string)
{
	if (strcmp(string, "TRUE") == 0) return TRUE;
	if (strcmp(string, "True") == 0) return TRUE;
	if (strcmp(string, "true") == 0) return TRUE;
	if (strcmp(string, "1") == 0) return TRUE;
	return FALSE;
}

/**
 * @brief
 *	sets single character for each state of job
 *
 * @param[in] string - string holding state of job
 * @param[in] q      - string holding string for que
 * @param[in] r      - string holding string for run
 * @param[in] h      - string holding string for hld
 * @param[in] w      - string holding string for wait
 * @param[in] t      - string holding string for transit
 * @param[in] e      - string holding string for end
 * @param[in] len    - length of string
 *
 */
static void
states(char *string, char *q, char *r, char *h, char *w, char *t, char *e, int len)
{
	char *c, *d, *f, *s, l;

	c = string;
	while (isspace(*c) && *c != '\0') c++;
	while (*c != '\0') {
		s = c;
		while ((*c != ':') && (*c != '\0')) c++;
		if (*c == '\0') break;
		*c = '\0';
		d = NULL;
		if (strcmp(s, "Queued") == 0) d = q;
		else if (strcmp(s, "Running") == 0) d = r;
		else if (strcmp(s, "Held")    == 0) d = h;
		else if (strcmp(s, "Waiting") == 0) d = w;
		else if (strcmp(s, "Transit") == 0) d = t;
		else if (strcmp(s, "Exiting") == 0) d = e;
		c++;
		if (d != NULL) {
			s = c;
			while (*c != ' ' && *c != '\0') c++;
			l = *c;
			*c = '\0';
			if (strlen(s) > (size_t)len) {
				f = s + len;
				*f = '\0';
			}
			strcpy(d, s);
			if (l != '\0') c++;
		} else {
			while (*c != ' ' && *c != '\0') c++;
		}
	}
}

/**
 * @brief
 *	Convert special characters, line feed and form feed into '\\'+n and '\\'+f respectively.
 *
 * @param[in]   val - input string
 *
 * @return string
 * @retval NULL     - if memory allocation failed.
 * @retval string   - string with feed characters escaped.
 *
 * @note
 *	The string returned should be freed by the caller.
 */
char *
convert_feed_chars(char *val) {
	int i = 0;
	int len = MAXBUFLEN;
	char *temp = NULL;
	char *buf = (char *) malloc(MAXBUFLEN);
	if (buf == NULL)
		return NULL;
	while (*val != '\0') {
		if (*val == '\n') {
			buf[i++] = '\\';
			buf[i++] = 'n';
			val++;
		} else if (*val == '\f') {
			buf[i++] = '\\';
			buf[i++] = 'f';
			val++;
		} else
			buf[i++] = *val++;
		if (i >= len - 2) {
			len *= BUFFER_GROWTH_RATE;
			temp = (char *) realloc(buf, len);
			if (temp == NULL) {
				free(buf);
				return NULL;
			}
			buf = temp;
		}
	}
	buf[i] = '\0';
	return buf;
}

/**
 * @brief
 *	print the exit message and die.
 */
void
exit_qstat(char *msg) {
	fprintf(stderr, "qstat: %s\n", msg);
	exit(1);
}

/**
 * @brief
 *	print a attribute value string, formating to break at a comma if possible
 *
 * @param[in] name - attribute name
 * @param[in] resource - resource name
 * @param[in] value - value for the attribute
 * @param[in] one_line - one line per attribute
 *
 */
void
prt_attr(char *name, char *resource, char *value, int one_line) {
	int first = 1;
	int len = 0;
	int start = 0;
	char *comma = ",";
	char *key = NULL;
	char *val = NULL;
	char *buf = NULL;
	char *temp = NULL;

	if (value == NULL)
		return;
	if (alt_display_allow == 0 && strcmp(name, ATTR_queue) == 0)
		return;

	switch (output_format) {
	case FORMAT_JSON:
		if (strcmp(name, ATTR_v) == 0) {
			if (add_json_node(JSON_OBJECT, JSON_NULL, JSON_NOVALUE, name, NULL) == NULL)
				exit_qstat("out of memory");
			buf = strdup(value);
			temp = buf;
			if (buf == NULL)
				exit_qstat("out of memory");
			while (*value) {
				/* value is split based on comma and each key-value is stored in keyvalpair.
				 * If the value contains an escaped comma, only the comma is copied to keyvalpair.
				 * Then separated into key and value based on the first '=' */
				key = buf;
				val = NULL;
				while (!(*value == *comma || *value == '\0')) {
					if (*value == ESC_CHAR && *(value + 1) == *comma)
						value++;
					if (!val && *value == '=') {
						*buf++ = '\0';
						val = buf;
						value++;
					}
					*buf++ = *value++;
				}
				*buf = '\0';
				if (add_json_node(JSON_VALUE, JSON_NULL, JSON_ESCAPE, key, val) == NULL)
					exit_qstat("out of memory");
				if (*value != '\0')
					value++;
			}
			if (add_json_node(JSON_OBJECT_END, JSON_NULL, JSON_NOVALUE, NULL, NULL) == NULL)
				exit_qstat("out of memory");
			free(temp);
		} else {
			if (resource) {
				if (prev_resc_name && strcmp(prev_resc_name, name) != 0) {
					if (add_json_node(JSON_OBJECT_END, JSON_NULL, JSON_NOVALUE, NULL, NULL)
							== NULL)
						exit_qstat("out of memory");
					prev_resc_name = NULL;
				}
				if (prev_resc_name == NULL || strcmp(prev_resc_name, name) != 0) {
					if (add_json_node(JSON_OBJECT, JSON_NULL, JSON_NOVALUE, name, NULL)
							== NULL)
						exit_qstat("out of memory");
					prev_resc_name = name;
				}
				if (add_json_node(JSON_VALUE, JSON_NULL, JSON_ESCAPE, resource, value)
						== NULL)
					exit_qstat("out of memory");
			} else {
				if (prev_resc_name) {
					if (add_json_node(JSON_OBJECT_END, JSON_NULL, JSON_NOVALUE, NULL, NULL)
							== NULL)
						exit_qstat("out of memory");
					prev_resc_name = NULL;
				}
				if (add_json_node(JSON_VALUE, JSON_NULL, JSON_ESCAPE, name, value) == NULL)
					exit_qstat("out of memory");
			}
		}
		break;

	case FORMAT_DSV:
		buf = escape_delimiter(value, delimiter, ESC_CHAR);
		if (buf == NULL)
			exit_qstat("out of memory");
		buf = convert_feed_chars(buf);
		if (buf == NULL)
			exit_qstat("out of memory");
		if (resource)
			printf("%s.%s=%s", name, resource, buf);
		else
			printf("%s=%s", name, buf);
		free(buf);
		break;

	default:
		if (one_line) {
			buf = convert_feed_chars(value);
			if (buf == NULL)
				exit_qstat("out of memory");
			if (resource)
				printf("    %s.%s = %s", name, resource, buf);
			else
				printf("    %s = %s", name, buf);
			free(buf);
		} else {
			start = strlen(name) + 7; /* 4 spaces + ' = ' is 7 */
			printf("    %s", name);
			if (resource) {
				start += strlen(resource) + 1; /* 1 for dot */
				printf(".%s", resource);
			}
			printf(" = ");
			if ((temp = strdup(value)) == NULL)
				exit_qstat("out of memory");
			buf = strtok(temp, comma);
			while (buf) {
				if ((len = strlen(buf)) + start < CHAR_LINE_LIMIT) {
					printf("%s", buf);
					start += len;
				} else {
					if (!first) {
						printf("\n\t");
						start = 9; /* tab + 1 */
					}
					while (*buf) {
						putchar(*buf++);
						if (++start > CHAR_LINE_LIMIT) {
							start = 8; /* tab */
							printf("\n\t");
						}
					}
				}
				if ((buf = strtok(NULL, comma)) != NULL) {
					first = 0;
					putchar(',');
				}
			}
			free(temp);
		}
	}
}

#define NAMEL   16  /* printf of jobs, queues, and servers */
#define OWNERL  16  /* printf of jobs */
#define TIMEUL  8   /* printf of jobs */
#define STATEL  1   /* printf of jobs */
#define LOCL    16  /* printf of jobs */
#define SIZEL	6   /* length of "SIZE" fields in printf */

/* format widths defined for display in wide format output */
#define SIZEJOBID 30    /* length of JobId field in printf */
#define SIZEJOBNAME 15  /* length of JobName field in printf when wide is true */
#define SIZESESSID 8    /* length of session id in printf */
#define SIZENDS 4	/* length of nds in printf */
#define SIZETSK 5	/* length of tsk in printf */
#define SIZEUSER 15	/* length of user name in printf */

/**
 * @brief
 *	Format and display string of assigned nodes, (1) strip off domain name
 *	if present and (2) break line at '+' sign.
 *
 * @param[in] nodes - name of exechosts
 * @param[in] no_newl - int value to decide which comment to be set
 *
 */
static void
prt_nodes(char *nodes, int no_newl)
{
	int  i;
	char linebuf[78];
	char *stp;
	int   vnodeid = 0;

	if ((nodes == NULL) || (*nodes == '\0'))
		return;

	i = 0;
	stp = nodes;
	while (*nodes != '\0') {
		if (*stp == '[')
			vnodeid = 1;
		else if (*stp == ']')
			vnodeid = 0;
		if ((vnodeid == 0) &&
			((*stp == '.') || (*stp == '+') || (*stp == '\0'))) {
			/* does node fit into line? */
			if (i + stp - nodes < 77) {
				while (nodes < stp)
					linebuf[i++] = *nodes++;
			} else {
				/* flush line and start next */
				linebuf[i] = '\0';
				if (no_newl)
					printf("%s", linebuf);
				else
					printf("   %s\n", linebuf);
				i = 0;
				while (nodes < stp)
					linebuf[i++] = *nodes++;
			}

			/* strip off domain name to keep string short */
			while ((*stp != '+') && (*stp != ':') && (*stp != '\0'))
				stp++;
			nodes = stp++;
		} else {
			stp++;
		}
	}
	if (i != 0) {
		linebuf[i] = '\0';
		if (no_newl)
			printf("%s\n", linebuf);
		else
			printf("   %s\n", linebuf);
	} else if (no_newl)
		printf("\n");
}

/**
 * @brief
 *	convert size from suffix string (nnnn[ kmgt][ bw]) to string of
 *	k[bw] for neither -M or -G (magnitude may be adjusted to fit print)
 *	mw    for	  -M
 *	gb    for	  -G
 * @param[in] value - string holding info about size which processed to get long int
 * @param[in] opt   - option indicating which conversion
 *
 * @return string
 * @retval string holding magnitude
 *
 */

static char *
cnv_size(char *value, int opt)
{
	static int sift_factor[5][5] = {
		{   0,  10, 20, 30, 40 },	/*  b conversion */
		{ -10,   0, 10, 20, 30 },	/* kb conversion */
		{ -20, -10,  0, 10, 20 },	/* mb conversion */
		{ -30, -20, -10, 0, 10 },	/* gb conversion */
		{ -40, -30, -20, -10, 0 }	/* tb conversion */
	};

	static char suffixletter[]  = " kmgtp?";
	int in;		/* magnitude of value from server  */
	int out;	/* magnitude of value when printed */
	int sft;
	unsigned long nval;
	char *pc;
	char  suffix1;		/* magnitude key letter [ kmgt] */
	char  suffix2 = 'b';	/* suffix letter, 'b' or 'w'    */
	static char outbuf[25];

	nval = strtol(value, &pc, 10);
	if (*pc == 'k')	     in = 1;
	else if (*pc == 'm') in = 2;
	else if (*pc == 'g') in = 3;
	else if (*pc == 't') in = 4;
	else in = 0;

	if ((*pc == 'w') || (*(pc+1) == 'w')) {
		nval = nval << 3;	/* convert to bytes */
		suffix2 = 'w';
	}

	if (opt & (ALT_DISPLAY_Mb | ALT_DISPLAY_Mw)) {
		out = 2;
		suffix1 = 'm';
		if (opt & ALT_DISPLAY_Mw)
			suffix2 = 'w';
		else
			suffix2 = 'b';
	} else if (opt & ALT_DISPLAY_G) {
		out = 3;
		suffix2 = 'b';
	} else {
		out = in;
	}

	sft = sift_factor[out][in];

	if (sft < 0) {
		nval = nval + ((1 << -sft) - 1);  /* round up (ceiling) */
		nval = nval >> -sft;
	} else if (sft > 0) {
		nval = nval << sft;
	}

	if (suffix2 == 'w')
		nval = (nval + 7) >> 3;	/* round and convert (back) to words */

	/* if the value will overflow the field size, up the magnitude */
	while (nval > 9999) {
		nval = (nval + 1023) >> 10;
		out++;
	}
	suffix1 = suffixletter[out];

	(void)sprintf(outbuf, "%lu%c%c", nval, suffix1, suffix2);
	return outbuf;
}

/**
 * @brief
 *	Format and display status of job in alternate and alternate wide form (not POSIX standard)
 *
 *
 */

static void
altdsp_statjob(struct batch_status *pstat, struct batch_status *prtheader, int alt_opt, int wide, int how_opt)
{
	char *comment;
	char *pc;
	struct attrl *pat;
	char *exechost;
	char *usern;
	char *queuen;
	char *jobn;
	char *sess;
	char *tasks;
	char *nodect;
	char *rqtimecpu;
	char *rqtimewal;
	char *jstate;
	char *eltimecpu;
	char *eltimewal;
	char *est_time;
	char *timeval;
	int   usecput;
	static char  pfs[SIZEL];
	static char  rqmem[SIZEL];
	static char  srfsbig[SIZEL];
	static char  srfsfast[SIZEL];
	static char *blank = " -- ";
	char buf[COMMENT_BUF_SIZE] = {'\0'};

	if (alt_opt & ALT_DISPLAY_T)
		pstat = bs_isort(pstat, cmp_est_time);

	if (prtheader) {
		printf("\n%s: ", prtheader->name);
		pc = get_attr(prtheader->attribs, ATTR_comment, NULL);
		if (pc)
			printf("%s", pc);
		if (wide) {

			/* Used for for displaying spaces and dashes dynamically for wide formatted output */
#define  STR_DASH  "--------------------------------------------------------------------------------"
#define  STR_SPACE "                                                                                "

			/* dynamic formatting to display spaces */
			printf("\n");
			if (alt_opt & ALT_DISPLAY_T) {
				printf("%*.*s %*.*s %*.*s %*.*s %*.*s %*.*s %*.*s ", SIZEJOBID, SIZEJOBID, STR_SPACE,
				SIZEUSER, SIZEUSER, STR_SPACE,
				PBS_MAXQUEUENAME, PBS_MAXQUEUENAME, STR_SPACE,
				SIZEJOBNAME, SIZEJOBNAME, STR_SPACE,
				SIZESESSID, SIZESESSID, STR_SPACE,
				SIZENDS, SIZENDS, STR_SPACE,
				SIZETSK, SIZETSK, STR_SPACE);
				printf("               Est\n");
			}

			printf("%*.*s %*.*s %*.*s %*.*s %*.*s %*.*s %*.*s ", SIZEJOBID, SIZEJOBID, STR_SPACE,
				SIZEUSER, SIZEUSER, STR_SPACE,
				PBS_MAXQUEUENAME, PBS_MAXQUEUENAME, STR_SPACE,
				SIZEJOBNAME, SIZEJOBNAME, STR_SPACE,
				SIZESESSID, SIZESESSID, STR_SPACE,
				SIZENDS, SIZENDS, STR_SPACE,
				SIZETSK, SIZETSK, STR_SPACE);
			if (alt_opt & ALT_DISPLAY_T)
				printf("Req'd  Req'd   Start\n");
			else
				printf("Req'd  Req'd   Elap\n");

			/* dynamic formatting to display header */
			printf("%-*.*s %-*.*s %-*.*s %-*.*s %-*.*s %-*.*s %-*.*s ", SIZEJOBID, SIZEJOBID, "Job ID",
				SIZEUSER, SIZEUSER, "Username",
				PBS_MAXQUEUENAME, PBS_MAXQUEUENAME, "Queue",
				SIZEJOBNAME, SIZEJOBNAME, "Jobname",
				SIZESESSID, SIZESESSID, "SessID",
				SIZENDS, SIZENDS, "NDS",
				SIZETSK, SIZETSK, "TSK");
			printf("Memory Time  S Time\n");

			/* dynamic formatting to display dashes */
			printf("%-*.*s %-*.*s %-*.*s %-*.*s %-*.*s %-*.*s %-*.*s ", SIZEJOBID, SIZEJOBID, STR_DASH,
				SIZEUSER, SIZEUSER, STR_DASH,
				PBS_MAXQUEUENAME, PBS_MAXQUEUENAME, STR_DASH,
				SIZEJOBNAME, SIZEJOBNAME, STR_DASH,
				SIZESESSID, SIZESESSID, STR_DASH,
				SIZENDS, SIZENDS, STR_DASH,
				SIZETSK, SIZETSK, STR_DASH);
			printf("------ ----- - -----\n");
		} else {
			if (alt_opt & ALT_DISPLAY_T) {
				if (how_opt & ALT_DISPLAY_INCR_WIDTH)
					printf("\n%80s%s\n%65s%-7s%-8s%s\n", " ", "Est", " ", "Req'd", "Req'd", "Start");
				else
					printf("\n%75s%s\n%60s%-7s%-8s%s\n", " ", "Est", " ", "Req'd", "Req'd", "Start");
			} else {
				if (how_opt & ALT_DISPLAY_INCR_WIDTH)
					printf("\n%65s%-7s%-8s%s\n", " ", "Req'd", "Req'd", "Elap");
				else
					printf("\n%60s%-7s%-8s%s\n", " ", "Req'd", "Req'd", "Elap");
			}
			if (alt_display_allow == 1){
				if (how_opt & ALT_DISPLAY_INCR_WIDTH) {
					printf("Job ID               Username Queue    Jobname    SessID NDS TSK Memory Time  S Time\n");
					printf("-------------------- -------- -------- ---------- ------ --- --- ------ ----- - -----\n");
				} else {
					printf("Job ID          Username Queue    Jobname    SessID NDS TSK Memory Time  S Time\n");
					printf("--------------- -------- -------- ---------- ------ --- --- ------ ----- - -----\n");
				}
			}else {
				if (how_opt & ALT_DISPLAY_INCR_WIDTH) {
					printf("Job ID               Username Jobname    SessID NDS TSK Memory Time  S Time\n");
					printf("-------------------- -------- ---------- ------ --- --- ------ ----- - -----\n");
				} else {
					printf("Job ID          Username Jobname    SessID NDS TSK Memory Time  S Time\n");
					printf("--------------- -------- ---------- ------ --- --- ------ ----- - -----\n");
				}
			}
		}
	}
	while (pstat) {
		exechost = blank;
		sess   = blank;
		nodect  = blank;
		tasks  = blank;
		rqtimecpu = blank;
		rqtimewal = blank;
		eltimecpu = blank;
		eltimewal = blank;
		jstate    = blank;
		comment   = blank;
		usern  = blank;
		jobn   = blank;
		queuen = blank;
		est_time  = NULL;
		/*		*pfs      = *blank;  */
		(void)strcpy(pfs, blank);
		/*		*rqmem    = *blank;  */
		(void)strcpy(rqmem, blank);
		/*		*srfsbig  = *blank;  */
		(void)strcpy(srfsbig, blank);
		/*		*srfsfast = *blank;  */
		(void)strcpy(srfsfast, blank);
		usecput = 0;

		pat = pstat->attribs;

		while (pat) {
			if (strcmp(pat->name, ATTR_N) == 0) {
				jobn = pat->value;
			} else if (strcmp(pat->name, ATTR_owner) == 0) {
				usern = pat->value;
				if ((pc = strchr(usern, (int)'@')) != NULL)
					*pc = '\0';
			} else if (strcmp(pat->name, ATTR_state) == 0) {
				jstate = pat->value;
			} else if (strcmp(pat->name, ATTR_queue) == 0) {
				queuen = pat->value;
			} else if (strcmp(pat->name, ATTR_session) == 0) {
				sess = pat->value;
			} else if (strcmp(pat->name, ATTR_l) == 0) {
				if (strcmp(pat->resource, "nodect") == 0) {
					nodect = pat->value;
				} else if (strcmp(pat->resource, "ncpus") == 0) {
					if (strcmp(pat->value, "0") != 0)
						tasks = pat->value;
				} else if (strcmp(pat->resource, "mppe") == 0) {
					if (strcmp(pat->value, "0") != 0)
						tasks = pat->value;
				} else if (strcmp(pat->resource, "mem") == 0) {
					(void)strncpy(rqmem,
						cnv_size(pat->value, alt_opt), sizeof(rqmem) - 1);
				} else if (strcmp(pat->resource, "walltime") == 0) {
					rqtimewal = pat->value;
				} else if (strcmp(pat->resource, "cput") == 0) {
					rqtimecpu = pat->value;
					usecput = 1;
				} else if (strcmp(pat->resource, "srfs_big") == 0) {
					(void)strncpy(srfsbig,
						cnv_size(pat->value, alt_opt), sizeof(srfsbig) - 1);
				} else if (strcmp(pat->resource, "srfs_fast") == 0) {
					(void)strncpy(srfsfast,
						cnv_size(pat->value, alt_opt), sizeof(srfsfast) - 1);
				} else if (strcmp(pat->resource, "piofs") == 0) {
					(void)strncpy(pfs,
						cnv_size(pat->value, alt_opt), sizeof(pfs) - 1);
				}

			} else if (strcmp(pat->name, ATTR_exechost) == 0) {
				exechost = pat->value;
			} else if (strcmp(pat->name, ATTR_estimated) == 0) {
				if (strcmp(pat->resource, "start_time") == 0) {
					est_time = pat->value;
				}
			} else if (strcmp(pat->name, ATTR_used) == 0) {
				if (strcmp(pat->resource, "walltime") == 0) {
					eltimewal = pat->value;
				} else if (strcmp(pat->resource, "cput") == 0) {
					eltimecpu = pat->value;
				}
			} else if (strcmp(pat->name, ATTR_comment) == 0) {
				/* there are 3 blank spaces after & before comment string */
				/* hence, for 80char line - 74 chars are displayed and for */
				/* 120 char line - 114 chars are displayed */
				if (strlen(pat->value) > COMMENTLENSCOPE_SHORT) {
					if (wide) {
						if (strlen(pat->value) > COMMENTLENSCOPE_WIDE) {
							strncpy(buf, pat->value, COMMENTLEN_WIDE);
							buf[COMMENTLEN_WIDE] = '\0';
							strcat(buf, "...");
							comment = buf;
						} else {
							comment = pat->value;
						}
					} else {
						strncpy(buf, pat->value, COMMENTLEN_SHORT);
						buf[COMMENTLEN_SHORT] = '\0';
						strcat(buf, "...");
						comment = buf;
					}
				} else {
					comment = pat->value;
				}
			}

			pat = pat->next;
		}

		if (alt_opt & ALT_DISPLAY_T) {
			pc = get_attr(pstat->attribs, ATTR_state, NULL);
			if (pc != NULL && (*pc == 'Q' || *pc == 'S'))
				timeval = cnvt_est_start_time(est_time, wide);
			else
				timeval = "--";
		}
		else
			timeval = usecput ? eltimecpu : eltimewal;


		if (wide) {
			if (alt_display_allow == 1) {
			/* dynamic formatting of values as defined by constants */
				printf("%-*.*s %-*.*s %-*.*s %-*.*s %*.*s %*.*s %*.*s ", SIZEJOBID, SIZEJOBID, pstat->name,
					SIZEUSER, SIZEUSER, usern,
					PBS_MAXQUEUENAME, PBS_MAXQUEUENAME, queuen,
					SIZEJOBNAME, SIZEJOBNAME, jobn,
					SIZESESSID, SIZESESSID, sess,
					SIZENDS, SIZENDS, nodect,
					SIZETSK, SIZETSK, tasks);
			} else {
				printf("%-*.*s %-*.*s %-*.*s %*.*s %*.*s %*.*s ", SIZEJOBID, SIZEJOBID, pstat->name,
					SIZEUSER, SIZEUSER, usern,
					SIZEJOBNAME, SIZEJOBNAME, jobn,
					SIZESESSID, SIZESESSID, sess,
					SIZENDS, SIZENDS, nodect,
					SIZETSK, SIZETSK, tasks);
			}


			/* static formatting of fixed size values */
			printf("%6.6s %5.5s %1s %s",
				rqmem,
				usecput ? rqtimecpu : rqtimewal,
				jstate,
				timeval);
		} else {
			if(how_opt & ALT_DISPLAY_INCR_WIDTH) {
				// printf("%-20.20s %-8.8s %-8.8s ",
				// 		pstat->name, usern, queuen);
				printf("%-20.20s %-8.8s",
						pstat->name, usern);
			} else {
				// printf("%-15.15s %-8.8s %-8.8s ",
				// 		pstat->name, usern, queuen);
				printf("%-15.15s %-8.8s ",
						pstat->name, usern);						
			}
			printf("%-10.10s %6.6s %3.3s %3.3s %6.6s %5.5s %1.1s %5.5s",
				jobn, sess, nodect, tasks,
				rqmem,
				usecput ? rqtimecpu : rqtimewal,
				jstate,
				timeval);
		}
		if (!(alt_opt & ALT_DISPLAY_1l))
			printf("\n");
		else
			printf(" ");

		if (alt_opt & ALT_DISPLAY_n) {
			/* print assigned nodes */
			prt_nodes(exechost, alt_opt & ALT_DISPLAY_1l);
		}
		if (alt_opt & ALT_DISPLAY_s) {
			/* print (scheduler) comment */
			if (*comment != '\0')
				printf("   %s\n", comment);
		}

		pstat = pstat->next;
	}
}

/**
 * @brief
 * 	get_ct - get count of jobs in queue/run state
 *	support function for altdsp_statque()
 */
static void
get_ct(char *str, int *jque, int *jrun)
{
	char *ps;
	int   colon = (int)':';

	ps = strchr(str, colon);	/* Transit - skip */
	ps = strchr(ps+1, colon);	/* Queued  - add to jque */
	*jque += atoi(ps+1);
	ps = strchr(ps+1, colon);	/* Held    - add to jque  */
	*jque += atoi(ps+1);
	ps = strchr(ps+1, colon);	/* Waiting - add to jque  */
	*jque += atoi(ps+1);
	ps = strchr(ps+1, colon);	/* Running - add to jrun  */
	*jrun += atoi(ps+1);
}

/**
 * @brief
 * 	altdsp_statque - alternative display for queue information, -q option
 */

static void
altdsp_statque(char *serv, struct batch_status *pstat, int opt)
{
	char  rmem[SIZEL];
	char *cput;
	char *wallt;
	char *jmax;
	char *nodect;
	char *blank = "  --   ";
	int   jrun;
	int   jque;
	char  qenabled;
	char  qstarted;
	int   tot_jrun = 0;
	int   tot_jque = 0;
	struct attrl *pat;

	printf("\nserver: %s\n\n", serv);
	printf("Queue            Memory CPU Time Walltime Node   Run   Que   Lm  State\n");
	printf("---------------- ------ -------- -------- ---- ----- ----- ----  -----\n");

	while (pstat) {
		/* *rmem = '\0'; */
		(void)strncpy(rmem, "--  ", sizeof(rmem) - 1);
		cput  = blank;
		wallt = blank;
		nodect= "-- ";
		jrun  = 0;
		jque  = 0;
		jmax  = blank;


		qenabled = 'D';
		qstarted = 'S';
		pat = pstat->attribs;

		while (pat) {
			if (strcmp(pat->name, ATTR_maxrun) == 0) {
				jmax = pat->value;
			} else if (strcmp(pat->name, ATTR_enable) == 0) {
				if (*pat->value == 'T')
					qenabled = 'E';
			} else if (strcmp(pat->name, ATTR_start) == 0) {
				if (*pat->value == 'T')
					qstarted = 'R';
			} else if (strcmp(pat->name, ATTR_count) == 0) {
				get_ct(pat->value, &jque, &jrun);
				tot_jque += jque;
				tot_jrun += jrun;
			} else if (strcmp(pat->name, ATTR_rescmax) == 0) {
				if (strcmp(pat->resource, "mem") == 0) {
					(void)strncpy(rmem,
						cnv_size(pat->value, opt), sizeof(rmem) - 1);
				} else if (strcmp(pat->resource, "cput") == 0) {
					cput = pat->value;
				} else if (strcmp(pat->resource, "walltime")==0) {
					wallt = pat->value;
				} else if (strcmp(pat->resource, "nodect")==0) {
					nodect = pat->value;
				}
			}
			pat = pat->next;
		}

		printf("%-16.16s %6.6s %8.8s %8.8s %4.4s ",
			pstat->name, rmem, cput, wallt, nodect);
		printf("%5d %5d %4.4s   %c %c\n",
			jrun, jque, jmax, qenabled, qstarted);

		pstat = pstat->next;
	}
	printf("                                               ----- -----\n");
	printf("                                               %5d %5d\n", tot_jrun, tot_jque);
}

/* build and add an attropl struct to the list */

static void
add_atropl(struct attropl **list, char *name, char *resc, char *value, enum batch_op op)
{
	struct attropl *patro;

	patro = (struct attropl *)malloc(sizeof(struct attropl));
	if (patro == 0)
		exit_qstat("out of memory");
	patro->next     = *list;
	patro->name     = name;
	patro->resource = resc;
	patro->value    = value;
	patro->op       = op;
	*list = patro;
}

static long
cvt_time_to_seconds(char *ts)
{
	char *workval;
	char *pc;
	char *pv;
	long  rv = 0;

	if ((workval = strdup(ts)) == NULL)
		exit_qstat("out of memory");
	for (pc = workval, pv=workval; *pc; ++pc) {
		if (*pc == ':') {
			*pc = '\0';
			rv = (rv * 60) + atol(pv);
			pv = pc + 1;
		}
	}
	rv = rv * 60 + atol(pv);
	free(workval);
	return rv;
}


/**
 * @brief
 * 	percent_cal - calculate the percent done for the -p option
 *	Calculation is either:
 *	1.  expired / total subjobs for an array,
 *	2.  cput_used / cput_requested, if cput specified, or
 *	3.  walltime_used / walltime_requested if walltime specified, or
 *	4.  "--" if none of the above apply
 */
char *
percent_cal(char *state, char *timeu, char *timer, char *wtimu, char *wtimr, char *arsct)
{
	char *rtn = NULL;
	long bot = 0;
	long top = 0;
	int qu, ru, ex, ep;

	switch (*state) {

		case 'Q':
		case 'T':
		case 'W':
			return (rtn);

		case 'X':
			return ("100");
	}


	if (arsct) {			/* array job: percent expired */
		long percexp = -1;
		sscanf(arsct, "Queued:%d Running:%d Exiting:%d Expired:%d", &qu, &ru, &ex, &ep);
		bot = qu + ru + ex + ep;
		top = ep;
		if (bot != 0)
			percexp = (top * 100) / bot;
		if ((percexp >= 0) && (percexp < 1000)) {
			pbs_asprintf(&rtn, "%3ld ", percexp);
		}
	} else {
		long perccpu = -1;
		long percwal = -1;
		if (timer && timeu) {	/* if cput specified */
			top = cvt_time_to_seconds(timeu);
			bot = cvt_time_to_seconds(timer);
			if (bot != 0)
				perccpu = (top * 100) / bot;
		}
		if (wtimr && wtimu) {	/* if walltime specified */
			top = cvt_time_to_seconds(wtimu);
			bot = cvt_time_to_seconds(wtimr);
			if (bot != 0)
				percwal = (top * 100) / bot;
		}
		if ((perccpu != -1) || (percwal != -1)) {
			pbs_asprintf(&rtn, "%3ld ",
				perccpu > percwal ? perccpu : percwal);
		}
	}
	if (rtn == NULL) {
		pbs_asprintf(&rtn, "%3s", "-- ");
	}
	return (rtn);
}

/** @fn display_statjob
 * @brief	display job status in specific format.
 *
 * @return int
 * @retval	0	- success
 * @retval	1	- failure
 *
 */

int
display_statjob(struct batch_status *status, struct batch_status *prtheader, int full, int how_opt, int alt_opt)
{
	struct batch_status *p;
	struct attrl *a;
	int l;
	char *c;
	char *jid;
	char *name;
	char *owner;
	char *timeu;
	char *timer;
	char *wtimu;
	char *wtimr;
	char *arsct;
	char *state;
	char *location;
	char format[80];
	char long_name[SIZEJOBNAME + 1] = {'\0'};
	char *cmdargs = NULL;
	char *hpcbp_executable;
	if (alt_display_allow == 1) {
		if (how_opt & ALT_DISPLAY_INCR_WIDTH) {
			sprintf(format, "%%-%ds %%-%ds %%-%ds  %%%ds %%%ds %%-%ds\n",
				PBS_MAXSEQNUM+10, NAMEL, OWNERL, TIMEUL, STATEL, LOCL);
		} else {
			sprintf(format, "%%-%ds %%-%ds %%-%ds  %%%ds %%%ds %%-%ds\n",
				PBS_MAXSEQNUM+5, NAMEL, OWNERL, TIMEUL, STATEL, LOCL);
		}
	}else {
		if (how_opt & ALT_DISPLAY_INCR_WIDTH) {
			sprintf(format, "%%-%ds %%-%ds %%-%ds  %%%ds %%%ds \n",
				PBS_MAXSEQNUM+10, NAMEL, OWNERL, TIMEUL, STATEL);
		} else {
			sprintf(format, "%%-%ds %%-%ds %%-%ds  %%%ds %%%ds \n",
				PBS_MAXSEQNUM+5, NAMEL, OWNERL, TIMEUL, STATEL);
		}
	}


	if (! full && prtheader && output_format == FORMAT_DEFAULT) {
		c = get_attr(prtheader->attribs, ATTR_comment, NULL);
		if (c)
			printf("%s\n", c);
		if (alt_display_allow == 1) {

			if (how_opt & ALT_DISPLAY_p) {
					if (how_opt & ALT_DISPLAY_INCR_WIDTH) {
						printf("Job id                 Name             User               %% done  S Queue\n");
						printf("---------------------  ---------------- ----------------  -------- - -----\n");
					} else {
						printf("Job id            Name             User               %% done  S Queue\n");
						printf("----------------  ---------------- ----------------  -------- - -----\n");
					}
			} else {
					if (how_opt & ALT_DISPLAY_INCR_WIDTH) {
						printf("Job id                 Name             User              Time Use S Queue\n");
						printf("---------------------  ---------------- ----------------  -------- - -----\n");
					} else {
						printf("Job id            Name             User              Time Use S Queue\n");
						printf("----------------  ---------------- ----------------  -------- - -----\n");
					}
			}
		}else {
			if (how_opt & ALT_DISPLAY_p) {
					if (how_opt & ALT_DISPLAY_INCR_WIDTH) {
						printf("Job id                 Name             User               %% done  S \n");
						printf("---------------------  ---------------- ----------------  -------- - n");
					} else {
						printf("Job id            Name             User               %% done  S \n");
						printf("----------------  ---------------- ----------------  -------- - \n");
					}
			} else {
					if (how_opt & ALT_DISPLAY_INCR_WIDTH) {
						printf("Job id                 Name             User              Time Use S \n");
						printf("---------------------  ---------------- ----------------  -------- - \n");
					} else {
						printf("Job id            Name             User              Time Use S \n");
						printf("----------------  ---------------- ----------------  -------- - \n");
					}
			}
		}
	}

	if (output_format == FORMAT_JSON && first_stat) {
		if (add_json_node(JSON_OBJECT, JSON_NULL, JSON_FULLESCAPE, "Jobs", NULL) == NULL)
			return 1;
		first_stat = 0;
	}
	p = status;
	while (p != NULL) {
		jid = NULL;
		name = NULL;
		owner = NULL;
		timeu = NULL;
		timer = NULL;
		wtimu = NULL;
		wtimr = NULL;
		arsct = NULL;
		state = NULL;
		location = NULL;
		hpcbp_executable = NULL;
		if (full) {
			if (output_format == FORMAT_DSV || output_format == FORMAT_DEFAULT)
				printf("Job Id: %s%s", p->name, delimiter);
			else if (output_format == FORMAT_JSON)
				if (add_json_node(JSON_OBJECT, JSON_NULL, JSON_NOVALUE, p->name, NULL) == NULL)
					return 1;
			a = p->attribs;
			while (a != NULL) {
				if (a->name != NULL) {
					time_t epoch;

					if (strcmp(a->name, ATTR_ctime) == 0 ||
						strcmp(a->name, ATTR_etime) == 0 ||
						strcmp(a->name, ATTR_stime) == 0 ||
						strcmp(a->name, ATTR_mtime) == 0 ||
						strcmp(a->name, ATTR_qtime) == 0 ||
						strcmp(a->name, ATTR_resv_start) == 0 ||
						strcmp(a->name, ATTR_resv_end) == 0 ||
						(strcmp(a->name, ATTR_estimated) == 0 &&
						strcmp(a->resource, "start_time") == 0) ||
						strcmp(a->name, ATTR_a) == 0) {
						epoch = (time_t) atol(a->value);
						if (epoch == 0 &&
							strcmp(a->name, ATTR_estimated) == 0 &&
							strcmp(a->resource, "start_time") == 0) {
							/*
							 * Must not pass constant string to
							 * ptr_attr due to strtok bug in Linux.
							 * Use a stack variable instead.
							 */
							char noval[] = "UNKNOWN";
							prt_attr(a->name, a->resource, noval, alt_opt & ALT_DISPLAY_w);
						} else
						{
							char time_buffer[32];
							strcpy(time_buffer,ctime(&epoch));
							time_buffer[strlen(time_buffer)-1]='\0';
							prt_attr(a->name, a->resource, time_buffer, alt_opt & ALT_DISPLAY_w);
						}
					} else if (strcmp(a->name, ATTR_resv_state) == 0) {
						prt_attr(a->name, a->resource, cvtResvstate(a->value), alt_opt & ALT_DISPLAY_w);
					} else if (strcmp(a->name, ATTR_submit_arguments) == 0) {
						if (decode_xml_arg_list_str((a->value),  &cmdargs) == -1)
							exit_qstat("out of memory");
						prt_attr(a->name, a->resource, cmdargs, alt_opt & ALT_DISPLAY_w);
						free(cmdargs);
					} else if (strcmp(a->name, ATTR_executable) == 0) {
						/*
						 * Prefix and suffix attribute value with
						 * HPCBP_EXEC_TAG value.
						 */
						hpcbp_executable =
								malloc((strlen(HPCBP_EXEC_TAG) * 2) +
								sizeof("<></>") + strlen(a->value) + 1);
						if (hpcbp_executable == NULL)
							exit_qstat("out of memory");
						(void)sprintf(hpcbp_executable, "<%s>%s</%s>",
								HPCBP_EXEC_TAG, a->value, HPCBP_EXEC_TAG);
						prt_attr(a->name, a->resource, hpcbp_executable, alt_opt & ALT_DISPLAY_w);
						free(hpcbp_executable);
					} else {
						prt_attr(a->name, a->resource, a->value, alt_opt & ALT_DISPLAY_w);
					}
				}
				a = a->next;
				if ((a || output_format == FORMAT_DEFAULT))
					printf("%s", delimiter);
				else if (output_format == FORMAT_JSON) {
					if (prev_resc_name != NULL)
						if (add_json_node(JSON_OBJECT_END, JSON_NULL, JSON_NOVALUE, NULL,
								NULL) == NULL)
							return 1;
					if (add_json_node(JSON_OBJECT_END, JSON_NULL, JSON_NOVALUE, NULL, NULL)
							== NULL)
						return 1;
				}
			}
		} else {
			if (p->name != NULL) {
				c = p->name;
				while (*c != '.' && *c != '\0') c++;
				c++;    /* List the first part of the server name, too. */
				while (*c != '.' && *c != '\0') c++;
				*c = '\0';
				l = strlen(p->name);
				if (how_opt & ALT_DISPLAY_INCR_WIDTH) {
					if (l > (PBS_MAXSEQNUM+10)) {
						c = p->name + PBS_MAXSEQNUM + 10;
						*c = '\0';
					}
				} else {
					if (l > (PBS_MAXSEQNUM+5)) {
						c = p->name + PBS_MAXSEQNUM + 5;
					        *c = '\0';
					}
				}
				jid = p->name;
			}
			a = p->attribs;
			while (a != NULL) {
				if (a->name != NULL) {
					if (strcmp(a->name, ATTR_name) == 0) {
						l = strlen(a->value);
						if (l >= NAMEL) {
							strncpy(long_name, a->value, (NAMEL - 1));
							c = long_name;
						} else
							c = a->value;
						name = c;
					} else if (strcmp(a->name, ATTR_owner) == 0) {
						c = a->value;
						while (*c != '@' && *c != '\0') c++;
						*c = '\0';
						l = strlen(a->value);
						if (l > OWNERL) {
							c = a->value + OWNERL;
							*c = '\0';
						}
						owner = a->value;
					} else if (strcmp(a->name, ATTR_used) == 0) {
						if (strcmp(a->resource, "cput") == 0) {
							l = strlen(a->value);
							if (l > TIMEUL) {
								c = a->value + TIMEUL;
								*c = '\0';
							}
							timeu = a->value;
						} else if (strcmp(a->resource, "walltime") == 0) {
							l = strlen(a->value);
							if (l > TIMEUL) {
								c = a->value + TIMEUL;
								*c = '\0';
							}
							wtimu = a->value;
						}
					} else if (strcmp(a->name, ATTR_l) == 0) {
						if (strcmp(a->resource, "cput") == 0) {
							l = strlen(a->value);
							if (l > TIMEUL) {
								c = a->value + TIMEUL;
								*c = '\0';
							}
							timer = a->value;
						} else if (strcmp(a->resource, "walltime") == 0) {
							l = strlen(a->value);
							if (l > TIMEUL) {
								c = a->value + TIMEUL;
								*c = '\0';
							}
							wtimr = a->value;
						}
					} else if (strcmp(a->name, ATTR_state) == 0) {
						l = strlen(a->value);
						if (l > STATEL) {
							c = a->value + STATEL;
							*c = '\0';
						}
						state = a->value;
					} else if (strcmp(a->name, ATTR_queue) == 0) {
						c = a->value;
						while (*c != '@' && *c != '\0') c++;
						*c = '\0';
						l = strlen(a->value);
						if (l > LOCL) {
							c = a->value + LOCL;
							*c = '\0';
						}
						location = a->value;
					} else if (strcmp(a->name, ATTR_array_state_count) == 0) {
						arsct = a->value;
					}
				}
				a = a->next;
			}
			if (timeu == NULL) timeu = "0";
			if (alt_display_allow == 1) {
				if (how_opt & ALT_DISPLAY_p) {
					char *pc = percent_cal(state, timeu, timer, wtimu, wtimr, arsct);
					printf(format, jid, name, owner, pc, state, location);
					free(pc);
				} else
					printf(format, jid, name, owner, timeu, state, location);
			}else{
				if (how_opt & ALT_DISPLAY_p) {
					char *pc = percent_cal(state, timeu, timer, wtimu, wtimr, arsct);
					printf(format, jid, name, owner, pc, state);
					free(pc);
				} else
					printf(format, jid, name, owner, timeu, state);
			}

		}
		if (full && output_format != FORMAT_JSON)
			printf("\n");
		p = p->next;
	}
	return 0;
}



#define NUML    5
#define TYPEL   4

/**
 * @brief
 *	Displays the status of queue.
 *
 * @param[in] status - batch request for queue status
 * @param[in] prtheader - true or false
 * @param[in] full - server full name
 *
 * @return	int
 * @retval	0	- success
 * @retval	1	- failure
 *
 */
int
display_statque(struct batch_status *status, int prtheader, int full, int alt_opt)
{
	struct batch_status *p;
	struct attrl *a;
	int l;
	char *c;
	char *name;
	char *max;
	char *tot;
	char ena[3+1];
	char str[3+1];
	char que[NUML+1];
	char run[NUML+1];
	char hld[NUML+1];
	char wat[NUML+1];
	char trn[NUML+1];
	char ext[NUML+1];
	char *type;
	char format[80];

	sprintf(format, "%%-%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%-%ds\n",
		NAMEL, NUML, NUML, 3, 3, NUML,
		NUML, NUML, NUML, NUML, NUML, TYPEL);

	if (! full && prtheader && output_format == FORMAT_DEFAULT) {
		printf("Queue              Max   Tot Ena Str   Que   Run   Hld   Wat   Trn   Ext Type\n");
		printf("---------------- ----- ----- --- --- ----- ----- ----- ----- ----- ----- ----\n");
	}

	if (output_format == FORMAT_JSON && first_stat) {
		if (add_json_node(JSON_OBJECT, JSON_NULL, JSON_FULLESCAPE, "Queue", NULL) == NULL)
			return 1;
		first_stat = 0;
	}
	p = status;
	while (p != NULL) {
		name = NULL;
		max = "0";
		tot = "0";
		strcpy(ena, "no");
		strcpy(str, "no");
		strcpy(que, "0");
		strcpy(run, "0");
		strcpy(hld, "0");
		strcpy(wat, "0");
		strcpy(trn, "0");
		strcpy(ext, "0");
		type = "not defined";
		if (full) {
			if(output_format == FORMAT_DSV || output_format == FORMAT_DEFAULT)
				printf("Queue: %s%s", p->name, delimiter);
			else if (output_format == FORMAT_JSON) {
				if (prev_resc_name != NULL)
					if (add_json_node(JSON_OBJECT_END, JSON_NULL, JSON_NOVALUE, NULL, NULL)
							== NULL)
						return 1;
				if (add_json_node(JSON_OBJECT, JSON_NULL, JSON_NOVALUE, p->name, NULL)
						== NULL)
					return 1;
			}
			a = p->attribs;
			while (a != NULL) {
				if (a->name != NULL) {
					prt_attr(a->name, a->resource, a->value,
							alt_opt & ALT_DISPLAY_w);
				}
				a = a->next;
				if ((a || output_format == FORMAT_DEFAULT))
					printf("%s", delimiter);
				else if (output_format == FORMAT_JSON)
					if (add_json_node(JSON_OBJECT_END, JSON_NULL, JSON_NOVALUE, NULL, NULL)
							== NULL)
						return 1;
			}
		} else {
			if (p->name != NULL) {
				l = strlen(p->name);
				if (l > NAMEL) {
					c = p->name + NAMEL;
					*c = '\0';
				}
				name = p->name;
			}
			a = p->attribs;
			while (a != NULL) {
				if (a->name != NULL) {
					if (strcmp(a->name, ATTR_maxrun) == 0) {
						l = strlen(a->value);
						if (l > NUML) {
							c = a->value + NUML;
							*c = '\0';
						}
						max = a->value;
					} else if (strcmp(a->name, ATTR_total) == 0) {
						l = strlen(a->value);
						if (l > NUML) {
							c = a->value + NUML;
							*c = '\0';
						}
						tot = a->value;
					} else if (strcmp(a->name, ATTR_enable) == 0) {
						if (istrue(a->value))
							strcpy(ena, "yes");
						else
							strcpy(ena, "no");
					} else if (strcmp(a->name, ATTR_start) == 0) {
						if (istrue(a->value))
							strcpy(str, "yes");
						else
							strcpy(str, "no");
					} else if (strcmp(a->name, ATTR_count) == 0) {
						states(a->value, que, run, hld, wat, trn, ext, NUML);
					} else if (strcmp(a->name, ATTR_qtype) == 0) {
						l = strlen(a->value);
						if (l > TYPEL) {
							c = a->value + TYPEL;
							*c = '\0';
						}
						type = a->value;
					}
				}
				a = a->next;
			}
			printf(format, name, max, tot, ena, str, que, run, hld, wat, trn, ext, type);
		}
		if (full && output_format != FORMAT_JSON)
			printf("\n");
		p = p->next;

	}
	return 0;
}



#define STATUSL 10

/**
 * @brief
 *      Displays the status of server.
 *
 * @param[in] status - batch request for server status
 * @param[in] prtheader - true or false
 * @param[in] full - server full name
 *
 * @return  int
 * @retval	0	- success
 * @retval	1	- failure
 *
 */

int
display_statserver(struct batch_status *status, int prtheader, int full, int alt_opt)
{
	struct batch_status *p;
	struct attrl *a;
	int l;
	char *c;
	char *name;
	char *max;
	char *tot;
	char que[NUML+1];
	char run[NUML+1];
	char hld[NUML+1];
	char wat[NUML+1];
	char trn[NUML+1];
	char ext[NUML+1];
	char *stats;
	char format[80];

	sprintf(format, "%%-%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%-%ds\n",
		NAMEL, NUML, NUML, NUML, NUML, NUML, NUML, NUML, NUML, STATUSL);

	if (! full && prtheader && output_format == FORMAT_DEFAULT) {
		printf("Server             Max   Tot   Que   Run   Hld   Wat   Trn   Ext Status\n");
		printf("---------------- ----- ----- ----- ----- ----- ----- ----- ----- -----------\n");
	}

	if(output_format == FORMAT_JSON && first_stat) {
		if (add_json_node(JSON_OBJECT, JSON_NULL, JSON_NOVALUE, "Server", NULL) == NULL)
			return 1;
		first_stat = 0;
	}
	p = status;
	while (p != NULL) {
		name = NULL;
		max = "0";
		tot = "0";
		strcpy(que, "0");
		strcpy(run, "0");
		strcpy(hld, "0");
		strcpy(wat, "0");
		strcpy(trn, "0");
		strcpy(ext, "0");
		stats = "";
		if (full) {
			if (output_format == FORMAT_DSV || output_format == FORMAT_DEFAULT)
				printf("Server: %s%s", p->name, delimiter);
			else if (output_format == FORMAT_JSON)
				if (add_json_node(JSON_OBJECT, JSON_NULL, JSON_NOVALUE, p->name, NULL)
						== NULL)
					return 1;
			a = p->attribs;
			while (a != NULL) {
				if (a->name != NULL) {
					prt_attr(a->name, a->resource, a->value, alt_opt & ALT_DISPLAY_w);
				}
				a = a->next;
				if((a || output_format == FORMAT_DEFAULT))
					printf("%s", delimiter);
				else if (output_format == FORMAT_JSON) {
					if (prev_resc_name != NULL)
						if (add_json_node(JSON_OBJECT_END, JSON_NULL, JSON_NOVALUE, NULL,
								NULL) == NULL)
							return 1;
					if (add_json_node(JSON_OBJECT_END, JSON_NULL, JSON_NOVALUE, NULL, NULL)
							== NULL)
						return 1;
				}
			}
		} else {
			if (p->name != NULL) {
				l = strlen(p->name);
				if (l > NAMEL) {
					c = p->name + NAMEL;
					*c = '\0';
				}
				name = p->name;
			}
			a = p->attribs;
			while (a != NULL) {
				if (a->name != NULL) {
					if (strcmp(a->name, ATTR_maxrun) == 0) {
						l = strlen(a->value);
						if (l > NUML) {
							c = a->value + NUML;
							*c = '\0';
						}
						max = a->value;
					} else if (strcmp(a->name, ATTR_total) == 0) {
						l = strlen(a->value);
						if (l > NUML) {
							c = a->value + NUML;
							*c = '\0';
						}
						tot = a->value;
					} else if (strcmp(a->name, ATTR_count) == 0) {
						states(a->value, que, run, hld, wat, trn, ext, NUML);
					} else if (strcmp(a->name, ATTR_status) == 0) {
						l = strlen(a->value);
						if (l > STATUSL) {
							c = a->value + STATUSL;
							*c = '\0';
						}
						stats = a->value;
					}
				}
				a = a->next;
			}
			printf(format, name, max, tot, que, run, hld, wat, trn, ext, stats);
		}
		if (full && output_format != FORMAT_JSON)
			printf("\n");
		p = p->next;
	}
	return 0;
}

#if	TCL_QSTAT
#ifdef NAS /* localmod 071 */
static Tcl_Obj	*
attrlist(struct attrl *ap)
{
	char	nameres[256];
	int	rc;
	Tcl_Obj	*ret;
	Tcl_Obj *sublist;

	/*
	 * Build a list out of sublists made from attribute name / value
	 * pairs
	 */
	ret = Tcl_NewListObj(0, NULL);
	if (ret == NULL)
		return ret;
	while (ap) {
		Tcl_Obj	*twol[2];

		if (ap->resource) {
			sprintf(nameres, "%s%s%s",
				ap->name, tcl_atrsep, ap->resource);
			twol[0] = Tcl_NewStringObj(nameres, -1);
		}
		else
			twol[0] = Tcl_NewStringObj(ap->name, -1);
		twol[1] = Tcl_NewStringObj(ap->value, -1);
		sublist = Tcl_NewListObj(2, twol);
		if (sublist == NULL) {
			if (twol[0])
				Tcl_DecrRefCount(twol[0]);
			if (twol[1])
				Tcl_DecrRefCount(twol[1]);
			break;
		}
		rc = Tcl_ListObjAppendElement(NULL, ret, sublist);
		if (rc != TCL_OK) {
			Tcl_DecrRefCount(sublist);
			break;
		}
		ap = ap->next;
	}
	return (ret);
}
#else
#define	ARGNUM	1024

char	*
attrlist(struct  attrl   *ap)
{
	char	nameres[256];
	char	*argv[ARGNUM];
	char	*ret;
	int	i, num = 0;

	while (ap) {
		char	*twol[2];

		if (ap->resource) {
			sprintf(nameres, "%s%s%s",
				ap->name, TCL_ATRSEP, ap->resource);
			twol[0] = nameres;
		}
		else
			twol[0] = ap->name;
		twol[1] = ap->value;
		argv[num++] = Tcl_Merge(2, twol);
		if (num == ARGNUM)
			break;
		ap = ap->next;
	}
	ret = Tcl_Merge(num, argv);
	for (i=0; i<num; i++)
		free(argv[i]);
	return (ret);
}
#endif /* localmod 071 */

Tcl_Interp	*interp = NULL;
char		script[200];
char		flags[] = "flags";
char		ops[] = "operands";
char		error[] = "error";

#ifdef NAS /* localmod 071 */
char	log_buffer[4096];
extern	int	quiet;

extern	void	add_cmds(Tcl_Interp *interp);

/**
 * @brief
 *	log error msg on error
 *
 * @param[in] errnum - error number
 * @param[in] func - function name where error occured
 * @param[in] text - error msg
 *
 * @return	Void
 *
 */
void
log_err(int errnum, char *func, char *text)
{
	if (quiet)
		return;
	fprintf(stderr, "%s: %s: %s\n",
		(errnum < 0) ? "Internal error" : strerror(errnum),
		func, text);
}

/**
 * @brief
 *	initialise the tcl.
 */
void
tcl_init()
{
	struct	passwd	*pw;
	uid_t		uid;
	struct	stat	sb;
	struct	batch_status	*bp;
	int		i, ret = 1;
	char		*home;

	if ((home = getenv("QSTATRCHOME")) == NULL &&
		(home = getenv("HOME")) == NULL) {
		uid = getuid();
		pw = getpwuid(uid);
		if (pw == NULL)
			return;
		home = pw->pw_dir;
	}

#ifdef WIN32
	snprintf(script, sizeof(script), "%s\\.qstatrc", home);
#else
	snprintf(script, sizeof(script), "%s/.qstatrc", home);
#endif
	if (stat(script, &sb) == -1) {
		strcpy(script, QSTATRC_PATH);
		if (stat(script, &sb) == -1)
			return;
	}

	interp = Tcl_CreateInterp();
	if (Tcl_Init(interp) == TCL_ERROR) {
		fprintf(stderr, "Tcl_Init error: %s",
			Tcl_GetStringResult(interp));
	}
#if	TCLX
#if	TCL_MINOR_VERSION < 5  && TCL_MAJOR_VERSION < 8
	if (TclX_Init(interp) == TCL_ERROR)
#else
	if (Tclx_Init(interp) == TCL_ERROR)
#endif
	{
		fprintf(stderr, "Tclx_Init error: %s",
			interp->result);
	}
#endif	/* TCLX */
	add_cmds(interp);
	return;
}
#else

/**
 * @brief
 *      initialise the tcl lib.
 */

void
tcl_init()
{
	struct	passwd	*pw;
	uid_t		uid;
	struct	stat	sb;
	struct	batch_status	*bp;
	int		i, ret = 1;

	uid = getuid();
	pw = getpwuid(uid);
	if (pw == NULL)
		return;

#ifdef WIN32
	sprintf(script, "%s\\.qstatrc", pw->pw_dir);
#else
	sprintf(script, "%s/.qstatrc", pw->pw_dir);
#endif
	if (stat(script, &sb) == -1) {
		strcpy(script, QSTATRC_PATH);
		if (stat(script, &sb) == -1)
			return;
	}

	interp = Tcl_CreateInterp();
	if (Tcl_Init(interp) == TCL_ERROR) {
		fprintf(stderr, "Tcl_Init error: %s",
			Tcl_GetStringResult(interp));
	}
#if	TCLX
#if	TCL_MINOR_VERSION < 5  && TCL_MAJOR_VERSION < 8
	if (TclX_Init(interp) == TCL_ERROR)
#else
	if (Tclx_Init(interp) == TCL_ERROR)
#endif
	{
		fprintf(stderr, "Tclx_Init error: %s",
			interp->result);
	}
#endif	/* TCLX */
	return;
}
#endif /* localmod 071 */

/**
 * @brief
 *	add argument to tcl list.
 *
 * @param[in] name - flag
 * @param[in] arg - argument
 *
 * @return	Void
 *
 */

void
tcl_addarg(char *name, char *arg)
{
	if (interp == NULL)
		return;

	if (arg == NULL || *arg == '\0')
		return;

	Tcl_SetVar(interp, name, arg,
		TCL_GLOBAL_ONLY|
		TCL_LIST_ELEMENT|
		TCL_APPEND_VALUE);
}

/**
 * @brief
 *      set tcl status .
 *
 * @param[in] type - type
 * @param[in] bs - batch request for tcl status
 * @param[in] f_opt - file option
 *
 * @return      int
 * @retval      0       success
 * @retval      1       error
 *
 */

#ifdef NAS /* localmod 071 */
int tcl_stat(char *, struct batch_status *, int);
int
tcl_stat(char *type, struct  batch_status  *bs, int tcl_opt)
{
	struct	batch_status	*bp;
	Tcl_Obj	*twol[2];
	Tcl_Obj *value;
	Tcl_Obj *result;
	Tcl_Obj *name;
	int	rc;
	int	i;
	int	errs = 0;

	if (interp == NULL)
		return 1;

	if (tcl_opt == 0)
		return 1;

	value = Tcl_NewListObj(0, NULL);
	if (value == NULL)
		return 1;

	for (bp=bs; bp; bp=bp->next) {
		Tcl_Obj	*threel[3];
		Tcl_Obj *sublist;

		threel[0] = Tcl_NewStringObj(bp->name, -1);
		threel[1] = attrlist(bp->attribs);
		threel[2] = Tcl_NewStringObj(bp->text, -1);

		sublist = Tcl_NewListObj(3, threel);
		if (sublist == NULL) {
			for (i = 0; i < 3; ++i) {
				if (threel[i] != NULL) {
					Tcl_DecrRefCount(threel[i]);
				}
			}
			++errs;
			break;
		}
		rc = Tcl_ListObjAppendElement(interp, value, sublist);
		if (rc != TCL_OK) {
			Tcl_DecrRefCount(sublist);
			++errs;
			break;
		}
	}
	if (errs) {
		Tcl_DecrRefCount(value);
		return 1;
	}
	twol[0] = Tcl_NewStringObj(type, -1);
	twol[1] = value;

	result = Tcl_NewListObj(2, twol);
	if (result == NULL) {
		for (i = 0; i < 2; ++i) {
			if (twol[i] != NULL) {
				Tcl_DecrRefCount(twol[i]);
			}
		}
		return 1;
	}
	name = Tcl_NewStringObj("objects", -1);
	if (name == NULL) {
		Tcl_DecrRefCount(result);
		return 1;
	}

	Tcl_ObjSetVar2(interp, name, NULL, result,
		TCL_GLOBAL_ONLY|
		TCL_LIST_ELEMENT|
		TCL_APPEND_VALUE);
	return 0;
}
#else
/**
 * @brief
 *	set tcl status .
 *
 * @param[in] type - type
 * @param[in] bs - batch request for tcl status
 * @param[in] f_opt - file option
 *
 * @return	int
 * @retval	0	success
 * @retval	1	error
 *
 */
int
tcl_stat(char *type, struct  batch_status *bs, int f_opt)
{
	struct	batch_status	*bp;
	char	*twol[2];
	char	*argv[ARGNUM];
	int	i, num = 0;
	char	*result;

	if (interp == NULL)
		return 1;

	if (f_opt == 0)
		return 1;

	twol[0] = type;
	for (bp=bs; bp; bp=bp->next) {
		char	*threel[3];

		threel[0] = bp->name;
		threel[1] = attrlist(bp->attribs);
		threel[2] = bp->text;

		argv[num++] = Tcl_Merge(3, threel);
		free(threel[1]);	/* malloc'ed in attrlist() */
		if (num == ARGNUM)
			break;
	}
	twol[1] = Tcl_Merge(num, argv);
	for (i=0; i<num; i++)
		free(argv[i]);

	result = Tcl_Merge(2, twol);
	Tcl_SetVar(interp, "objects", result,
		TCL_GLOBAL_ONLY|
		TCL_LIST_ELEMENT|
		TCL_APPEND_VALUE);
	free(twol[1]);
	free(result);
	return 0;
}
#endif /* localmod 071 */

void
#ifdef NAS /* localmod 071 */
tcl_run(int tcl_opt)
#else
tcl_run(int f_opt)
#endif /* localmod 071 */
{
	if (interp == NULL)
		return;

#ifdef NAS /* localmod 071 */
	if (tcl_opt &&
#else
	if (f_opt &&
#endif /* localmod 071 */
		Tcl_EvalFile(interp, script) != TCL_OK) {
		char	*trace;

		trace = (char *)Tcl_GetVar(interp, "errorInfo", 0);
		if (trace == NULL)
			trace = Tcl_GetStringResult(interp);

		fprintf(stderr, "%s: TCL error @ line %d: %s\n",
			script, Tcl_GetErrorLine(interp), trace);
	}
	Tcl_DeleteInterp(interp);
}

#else
#define tcl_init()
#define tcl_addarg(name, arg)
#ifdef NAS /* localmod 071 */
#define	tcl_stat(type, bs, tcl_opt) 1
#define tcl_run(tcl_opt)
#else
#define	tcl_stat(type, bs, f_opt) 1
#define tcl_run(f_opt)
#endif /* localmod 071 */
#endif	/* TCL_QSTAT */

int
main(int argc, char **argv, char **envp) /* qstat */
{
	int added_queue;
	int c;
	int errflg=0;
	int any_failed=0;
	extern char *optarg;
	char *conflict = "qstat: conflicting options.\n";
	char *pc;
	int located = FALSE;
	char extend[4];
	int wide=0;
	int format = 0;
	time_t timenow;
	int check_seqid_len; /* for dynamic qstat width */

#if TCL_QSTAT
	char option[3];
#endif

	char job_id[PBS_MAXCLTJOBID];

	char job_id_out[PBS_MAXCLTJOBID];
	char server_out[MAXSERVERNAME] = {0};
	char prev_server[MAXSERVERNAME] = {0};
	char server_old[MAXSERVERNAME] = "";
	char rmt_server[MAXSERVERNAME];
	char destination[PBS_MAXDEST+1];

	char *queue_name_out;
	char *server_name_out;

	char operand[PBS_MAXCLTJOBID+1];
	int alt_opt;
	int f_opt, B_opt, Q_opt, how_opt, E_opt;
	int p_header = TRUE;
	int stat_single_job = 0;
	int new_remote_server = 0;
	enum { JOBS, QUEUES, SERVERS } mode;
	struct batch_status *p_status;
	struct batch_status *p_server = NULL;
	struct attropl *p_atropl = 0;
	struct attropl *new_atropl;
#ifdef NAS /* localmod 071 */
	int tcl_opt;
	struct batch_status *p_rsvstat;
#endif /* localmod 071 */

	char *errmsg;
	char *job_list = NULL;
	size_t job_list_size = 0;
	char *query_job_list = NULL;

#if !defined(PBS_NO_POSIX_VIOLATION)
#ifdef NAS /* localmod 071 */
#define GETOPT_ARGS "aeinpqrstwxu:fGHJMQEBW:T1"
#else
#define GETOPT_ARGS "ainpqrstwxu:fGHJMQEBW:T1F:D:"
#endif /* localmod 071 */
#else
#define GETOPT_ARGS "fQBW:"
#endif /* PBS_NO_POSIX_VIOLATION */

	/*test for real deal or just version and exit*/

	execution_mode(argc, argv);

#ifdef WIN32
	winsock_init();
#endif

	mode = JOBS; /* default */
	alt_opt = 0;
	f_opt = 0;
	B_opt = 0;
	Q_opt = 0;
	E_opt = 0;
	how_opt = 0;
#ifdef NAS /* localmod 071 */
	tcl_opt = -2;
#endif /* localmod 071 */
	extend[0] = '\0';


#if TCL_QSTAT

#ifdef WIN32
	/* needed so that program recognizes correct TCL_LIBRARY */
	Tcl_FindExecutable(argv[0]);
#endif

	tcl_init();
	tcl_addarg(flags, argv[0]);
	option[0] = '-';
	option[2] = '\0';
#endif	/* TCL_QSTAT */

	if (argc >= 2 && strcasecmp(argv[1], "--vip") == 0) {
		alt_display_allow = 1;
		argc--;
		argv = argv+1;
	}

	while ((c = getopt(argc, argv, GETOPT_ARGS)) != EOF) {
#if TCL_QSTAT
		option[1] = (char)c;
		tcl_addarg(flags, option);
		tcl_addarg(flags, optarg);
#endif /* TCL_QSTAT */
		switch (c) {

#if !defined(PBS_NO_POSIX_VIOLATION)

			case 'a':
				alt_opt |= ALT_DISPLAY_a;
				display_attribs = &alt_attribs[0];
				break;

#ifdef NAS /* localmod 071 */
			case 'e':
				tcl_opt += 1;
				break;
#endif /* localmod 071 */

			case 'T':
				alt_opt |= ALT_DISPLAY_T;
				display_attribs = &alt_attribs[0];
				add_atropl((struct attropl **)&display_attribs, ATTR_estimated, "start_time", "", SET);
				add_atropl((struct attropl **)&display_attribs, ATTR_stime, NULL, "", SET);
				break;

			case 'i':
				alt_opt |= ALT_DISPLAY_i;
				display_attribs = &alt_attribs[0];
#ifdef NAS /* localmod 071 */
				add_atropl(&p_atropl, ATTR_state, NULL, "HQTW", EQ);
#else
				add_atropl(&p_atropl, ATTR_state, NULL, "EHQTW", EQ);
#endif /* localmod 071 */
				break;

			case 'r':
				alt_opt |= ALT_DISPLAY_r;
				display_attribs = &alt_attribs[0];
#ifdef NAS /* localmod 071 */
				add_atropl(&p_atropl, ATTR_state, NULL, "BERS", EQ);
#else
				add_atropl(&p_atropl, ATTR_state, NULL, "RS", EQ);
#endif /* localmod 071 */
				break;

			case 'H':
				alt_opt |= ALT_DISPLAY_H;
				display_attribs = &alt_attribs[0];
				if (strchr(extend, (int)'x') == NULL)
					strcat(extend, "x");
				add_atropl(&p_atropl, ATTR_state, NULL, "MFX", EQ);
				break;

			case 't':
				/* send 't' in extend field to include sub jobs */
				if (strchr(extend, (int)'t') == NULL)
					strcat(extend, "t");
				break;

			case 'x':
				/* send 'x' in extend field to include history jobs */
				if (strchr(extend, (int)'x') == NULL)
					strcat(extend, "x");
				break;

			case 'u':
				alt_opt |= ALT_DISPLAY_u;
				display_attribs = &alt_attribs[0];
				add_atropl(&p_atropl, ATTR_u, NULL, optarg, EQ);
				break;

			case 'n':
				alt_opt |= ALT_DISPLAY_n;
				if (display_attribs == &basic_attribs[0] || f_opt == 1)
					display_attribs = &alt_attribs[0];
				add_atropl((struct attropl **)&display_attribs, ATTR_exechost,
					NULL, "", SET);
				f_opt=0;
				break;

			case 'p':
				how_opt |= ALT_DISPLAY_p;
				add_atropl((struct attropl **)&display_attribs, ATTR_l, NULL, "", EQ);
				add_atropl((struct attropl **)&display_attribs, ATTR_array_state_count, NULL, "", EQ);
				break;

			case 's':
				alt_opt |= ALT_DISPLAY_s;
				if (display_attribs == &basic_attribs[0] || f_opt == 1)
					display_attribs = &alt_attribs[0];
				add_atropl((struct attropl **)&display_attribs, ATTR_comment,
					NULL, "", SET);
				f_opt=0;
				break;

			case 'q':
				if (alt_display_allow == 1){
					alt_opt |= ALT_DISPLAY_q;
					mode = QUEUES;
				}

				break;

			case 'G':
				alt_opt |= ALT_DISPLAY_G;
				display_attribs = &alt_attribs[0];
				break;

			case 'J':
				add_atropl(&p_atropl, ATTR_array, NULL, "True", EQ);
				break;

			case 'M':
				alt_opt |= ALT_DISPLAY_Mw;
				display_attribs = &alt_attribs[0];
				break;

			case '1':
				alt_opt |= ALT_DISPLAY_1l;
				break;

			case 'w':
				alt_opt |= ALT_DISPLAY_w;
				wide = 1;
				break;
#endif /* PBS_NO_POSIX_VIOLATION */

			case 'f':
				f_opt = 1;
				display_attribs = NULL;	/* get all attributes */
				break;

			case 'B':
				B_opt = 1;
				mode = SERVERS;
				if (Q_opt || (alt_opt && !wide)) {
					fprintf(stderr, "%s", conflict);
					errflg++;
				}
				break;

			case 'Q':
				if (alt_display_allow == 1){
					Q_opt = 1;
					mode = QUEUES;
					if (B_opt || (alt_opt && !wide)) {
						fprintf(stderr, "%s", conflict);
						errflg++;
					}
				}
				break;

			case 'E':
				E_opt = 1;
				break;

			case 'D':
				if (output_format == FORMAT_DSV)
					dsv_delim = optarg;
				else
					errflg++;
				break;

			case 'F':
				for (format = FORMAT_DEFAULT; format < FORMAT_MAX; format++) {
					if (strcasecmp(optarg, output_format_names[format]) == 0) {
						output_format = format;
						break;
					}
				}
				if (format >= FORMAT_MAX)
					errflg++;
				break;

			case 'W':
#if (TCL_QSTAT == 0)
				pc = optarg;
				while (*pc) {
					switch (*pc) {
						case 'a':
							alt_opt |= ALT_DISPLAY_a;
							break;

						case 'i':
							alt_opt |= ALT_DISPLAY_i;
							add_atropl(&p_atropl, ATTR_state, NULL, "EHQTW", EQ);
							break;

						case 'r':
							alt_opt |= ALT_DISPLAY_r;
#ifdef NAS /* localmod 071 */
							add_atropl(&p_atropl, ATTR_state, NULL, "BRS", EQ);
#else
							add_atropl(&p_atropl, ATTR_state, NULL, "RS", EQ);
#endif /* localmod 071 */
							break;

						case 'H':
							alt_opt |= ALT_DISPLAY_H;
							if (strchr(extend, (int)'x') == NULL)
								strcat(extend, "x");
							add_atropl(&p_atropl, ATTR_state, NULL, "MF", EQ);
							break;

						case 'u':
							/* note - u option is assumed to be last in  */
							/* string and all remaining is the name list */
							alt_opt |= ALT_DISPLAY_u;
							while (*++pc == ' ');
							add_atropl(&p_atropl, ATTR_u, NULL, pc, EQ);
							pc = pc + strlen(pc) - 1;	/* for the later incr */
							break;

						case 'n':
							alt_opt |= ALT_DISPLAY_n;
							break;

						case 's':
							alt_opt |= ALT_DISPLAY_s;
							break;

						case 'q':
							if (alt_display_allow == 1){
								alt_opt |= ALT_DISPLAY_q;
								mode = QUEUES;
							}
							break;

						case 'G':
							alt_opt |= ALT_DISPLAY_G;
							break;

						case 'M':
							alt_opt |= ALT_DISPLAY_Mw;
							break;

						case '1':
							alt_opt |= ALT_DISPLAY_1l;
							break;

						case ' ':
							break;		/* ignore blanks */

						default:
							errflg++;
					}
					++pc;
				}
#endif	/* (TCL_QSTAT == 0) */
				break;

			case '?':
			default:
				errflg++;
		}
	}

#if !defined(PBS_NO_POSIX_VIOLATION)
#ifdef NAS /* localmod 071 */
#if TCL_QSTAT
	if (tcl_opt) {
		display_attribs = NULL;        /* get all attributes */
	}
#endif
#endif /* localmod 071 */

	/* certain combinations are not allowed */

#ifdef NAS /* localmod 071 */
	if (f_opt == 1 && alt_opt != 0) {
		fprintf(stderr, conflict);
		errflg++;
	}
#endif /* localmod 071 */
	c = alt_opt & (ALT_DISPLAY_a |ALT_DISPLAY_i |ALT_DISPLAY_r
		|ALT_DISPLAY_q |ALT_DISPLAY_H);
	if ((c != 0) && ((c != ALT_DISPLAY_a) && (c != ALT_DISPLAY_i) &&
		(c != ALT_DISPLAY_r) && (c != ALT_DISPLAY_q) &&
		(c != ALT_DISPLAY_H))) {
		fprintf(stderr, "%s", conflict);
		errflg++;
	}
	c = alt_opt & (ALT_DISPLAY_Mw | ALT_DISPLAY_G);
	if (c == (ALT_DISPLAY_Mw | ALT_DISPLAY_G)) {
		fprintf(stderr, "%s", conflict);
		errflg++;
	}
	if(!(output_format == FORMAT_DEFAULT || f_opt)) {
		fprintf(stderr, "%s", conflict);
		errflg++;
	}
#ifndef NAS /* localmod 071 */
	if ((alt_opt & ALT_DISPLAY_q) && (f_opt == 1)) {
		fprintf(stderr, "%s", conflict);
		errflg++;
	}
#endif /* localmod 071 */
	if ((alt_opt&ALT_DISPLAY_1l) && !(alt_opt&(ALT_DISPLAY_n|ALT_DISPLAY_s))) {
		fprintf(stderr, "%s", conflict);
		errflg++;
	}
	if (wide) {
		if (!((alt_opt & ALT_DISPLAY_a) || (alt_opt & ALT_DISPLAY_n) || (alt_opt & ALT_DISPLAY_s) ||
			(alt_opt & ALT_DISPLAY_T) || f_opt == 1)) {
			fprintf(stderr, "qstat: option w can be used only with option a, n, T, s or f\n");
			errflg++;
		}
	}
#endif /* PBS_NO_POSIX_VIOLATION */

	if (errflg) {
		static char usag2[]="qstat --version\n";
		static char usage[]="usage: \n\
qstat [-f] [-J] [-p] [-t] [-x] [-E] [-F format] [-D delim] [ job_identifier... | destination... ]\n\
qstat [-a|-i|-r|-H|-T] [-J] [-t] [-u user] [-n] [-s] [-G|-M] [-1] [-w]\n\
\t[ job_identifier... | destination... ]\n\
qstat -Q [-f] [-F format] [-D delim] [ destination... ]\n\
qstat -q [-G|-M] [ destination... ]\n\
qstat -B [-f] [-F format] [-D delim] [ server_name... ]\n";
		fprintf(stderr, "%s", usage);
		fprintf(stderr, "%s", usag2);
		exit(2);
	}

	def_server = pbs_default();
	if (def_server == NULL)
		def_server = "";

	/*perform needed security library initializations (including none)*/

	if (CS_client_init() != CS_SUCCESS)
		exit_qstat("unable to initialize security library.");

	/* keep original list for reuse with next operand */
	/* in case a queue_name is added to front of list */
	added_queue = 0;
	new_atropl = p_atropl;

	if(output_format == FORMAT_DSV)
		delimiter = dsv_delim;
	else if(output_format == FORMAT_JSON) {
		delimiter = "";
		/* adding prologue to json output. */
		timenow = time(0);
		if (add_json_node(JSON_VALUE, JSON_INT, JSON_FULLESCAPE, "timestamp", &timenow) == NULL)
			exit_qstat("out of memory");
		if (add_json_node(JSON_VALUE, JSON_STRING, JSON_FULLESCAPE, "pbs_version", pbs_version) == NULL)
			exit_qstat("out of memory");
		if (add_json_node(JSON_VALUE, JSON_STRING, JSON_FULLESCAPE, "pbs_server", def_server) == NULL)
			exit_qstat("out of memory");
	}

	if (optind >= argc) { /* If no arguments, then set defaults */
		switch (mode) {

			case JOBS:
				server_out[0] = '@';
				strcpy(&server_out[1], def_server);
				tcl_addarg(ops, server_out);

				job_id_out[0] = '\0';
				server_out[0] = '\0';
				goto job_no_args;
			case QUEUES:
				server_out[0] = '@';
				strcpy(&server_out[1], def_server);
				tcl_addarg(ops, server_out);

				queue_name_out = NULL;
				server_out[0] = '\0';
				goto que_no_args;
			case SERVERS:
				tcl_addarg(ops, def_server);

				server_out[0] = '\0';
				goto svr_no_args;
		}
	}
	if (E_opt == 1 && mode == JOBS) {
		/* allocate enough memory to store list of job ids */
		job_list_size = ((argc - 1) * (PBS_MAXCLTJOBID + 1));
		job_list = calloc(argc - 1, PBS_MAXCLTJOBID + 1);
		if (job_list == NULL)
			exit_qstat("out of memory");
		/* sort all jobs */
		qsort(&argv[optind], (argc - optind), sizeof(char *), cmp_jobs);
	}
	for (; optind < argc; optind++) {
		int connect;

		located = FALSE;

		strcpy(operand, argv[optind]);
		tcl_addarg(ops, operand);
		switch (mode) {

			case JOBS:      /* get status of batch jobs */
				if (pbs_isjobid(operand)) {  /* must be a job-id */
					stat_single_job = 1;
					strcpy(job_id, operand);
					if (get_server(job_id, job_id_out, server_out)) {
						fprintf(stderr, "qstat: illegally formed job identifier: %s\n", job_id);
#ifdef NAS /* localmod 071 */
						(void)tcl_stat(error, NULL, tcl_opt);
#else
						(void)tcl_stat(error, NULL, f_opt);
#endif /* localmod 071 */
						any_failed = 1;
						break;
					}
					if (E_opt == 1) {
						/* Local Server */
						if (server_out[0] == '\0' || (strcmp(server_out, def_server) == 0)) {
							/* This is probably the first job id requested from primary server */
							if (prev_server[0] == '\0')
								strcpy(prev_server, def_server);
							strncat(job_list, job_id_out, job_list_size - strlen(job_list));
							strncat(job_list, ",", job_list_size - strlen(job_list));
							if (optind != argc -1)
								continue;
							else {
								free(query_job_list);
								query_job_list = strdup(job_list);
								job_list[0] = '\0';
							}
						}
						else {
							/* Remote server but jobs in continuation */
							if ((prev_server[0] == '\0' ) || (strcmp(server_out, prev_server) == 0)) {
								/* This is probably the first job id requested and not from primary server */
								if (prev_server[0] == '\0')
									strcpy(prev_server, server_out);
								strncat(job_list, job_id_out, job_list_size - strlen(job_list));
								strncat(job_list, ",", job_list_size - strlen(job_list));
								if (optind != argc-1)
									continue;
								else {
									/* It's a new remote server and the only job */
									new_remote_server = 1;
									free(query_job_list);
									query_job_list = strdup(job_list);
									job_list[0] = '\0';
								}
							} else {
								/* A new remote server */
								new_remote_server = 1;
								free(query_job_list);
								query_job_list = strdup(job_list);
								snprintf(job_list, job_list_size, "%s,", job_id_out);
							}
						}
					}
				} else {  /* must be a destination-id */
					if (E_opt == 1) {
						fprintf(stderr, "qstat: Express option can only be used with job ids\n");
						return 1;
					}
					stat_single_job = 0;
					strcpy(destination, operand);
					if (parse_destination_id(destination,
						&queue_name_out,
						&server_name_out)) {
						fprintf(stderr, "qstat: illegally formed destination: %s\n", destination);
#ifdef NAS /* localmod 071 */
						(void)tcl_stat(error, NULL, tcl_opt);
#else
						(void)tcl_stat(error, NULL, f_opt);
#endif /* localmod 071 */
						any_failed = 1;
						break;
					} else {
						if (notNULL(server_name_out)) {
							strcpy(server_out, server_name_out);
						} else {
							server_out[0] = '\0';
						}
						(void)strcpy(job_id_out, queue_name_out);
						if (*queue_name_out != '\0') {
							/* add "destination" to front of list */
							add_atropl(&new_atropl, ATTR_q, NULL, queue_name_out, EQ);
							added_queue = 1;
						}
					}
				}
job_no_args:
				/* We could have been sent here after p_server was set. Free it. */
				pbs_statfree(p_server);
				p_server = NULL;
				if (E_opt == 1)
					connect = cnt2server(prev_server);
				else
					connect = cnt2server(server_out);

				if (connect <= 0) {
					fprintf(stderr, "qstat: cannot connect to server %s (errno=%d)\n",
						pbs_server, pbs_errno);
#ifdef NAS /* localmod 071 */
					(void)tcl_stat(error, NULL, tcl_opt);
#else
					(void)tcl_stat(error, NULL, f_opt);
#endif /* localmod 071 */
					any_failed = connect;
					break;
				}
				if (strcmp(pbs_server, server_old) != 0) {
					/* changing to a different server */
					p_server = pbs_statserver(connect, NULL, NULL);
#ifdef NAS /* localmod 071 */
					p_rsvstat = pbs_statresv(connect, NULL, NULL, NULL);
#endif /* localmod 071 */
					(void)strcpy(server_old, pbs_server);
				} else {
					p_server = NULL;
				}

				if ((stat_single_job == 1) || (new_atropl == 0)) {
					if (E_opt == 1)
						p_status = pbs_statjob(connect, query_job_list, display_attribs, extend);
					else
						p_status = pbs_statjob(connect, job_id_out, display_attribs, extend);
				} else {
					p_status = pbs_selstat(connect, new_atropl, NULL, extend);
				}

				if (added_queue) {
					/* added queue name as first entry in atropl list,  */
					/* remove it and reset list pointer to base list    */
					free(new_atropl);
					new_atropl = p_atropl;
					added_queue = 0;
				}
				if (p_status == NULL) {
					if ((pbs_errno == PBSE_UNKJOBID) && !located) {
						located = TRUE;
						if (locate_job(job_id_out, server_out, rmt_server)) {
							pbs_disconnect(connect);
							strcpy(server_out, rmt_server);
							goto job_no_args;
						}
#ifdef NAS /* localmod 071 */
						(void)tcl_stat("job", NULL, tcl_opt);
#else
						(void)tcl_stat("job", NULL, f_opt);
#endif /* localmod 071 */
						if (pbs_errno != PBSE_HISTJOBID) {
							prt_job_err("qstat", connect, job_id_out);
							any_failed = pbs_errno;
						}
					} else {
#ifdef NAS /* localmod 071 */
						if (p_server) {
							tcl_stat("serverhdr", p_server, tcl_opt);
							tcl_stat("resv", p_rsvstat, tcl_opt);
						}
						(void)tcl_stat("job", NULL, tcl_opt);
#else
						(void)tcl_stat("job", NULL, f_opt);
#endif /* localmod 071 */
						if (pbs_errno != PBSE_NONE && pbs_errno != PBSE_HISTJOBID) {
							if (pbs_errno == PBSE_ATTRRO && alt_opt & ALT_DISPLAY_T)
								fprintf(stderr, "qstat: -T option is unavailable.\n");
							else
								prt_job_err("qstat", connect, job_id_out);
							any_failed = pbs_errno;
						}
					}

					/*
					 * If it is qstat command and error is PBSE_HISTJOBID, then
					 * handle it separately without using prt_job_err() API as we
					 * are adding some extra message.
					 */
					if (pbs_errno == PBSE_HISTJOBID) {
						errmsg = pbs_geterrmsg(connect);
						if (errmsg) {
							fprintf(stderr,
								"qstat: %s %s, use -x or -H to obtain historical job information\n",
								job_id_out, errmsg);
						}
						any_failed = pbs_errno;
					}
				} else {
				    /* check the server attribute max_job_sequence_id value */
					check_seqid_len = check_max_job_sequence_id("qstat");
					if (check_seqid_len == 1) {
						how_opt |= ALT_DISPLAY_INCR_WIDTH; /* increase column width*/
					} else if(check_seqid_len == -1) {
						fprintf(stderr, "qstat: Unable to fetch the width format\n");
						exit(1);
					}

#ifdef NAS /* localmod 071 */
					if (p_server) {
						tcl_stat("serverhdr", p_server, tcl_opt);
						tcl_stat("resv", p_rsvstat, tcl_opt);
					}
					if (tcl_stat("job", p_status, tcl_opt)) {
						if (alt_opt != 0) {
							altdsp_statjob(p_status, p_server, alt_opt, wide, how_opt);
						} else
							if (display_statjob(p_status, p_server, f_opt, how_opt))
								exit_qstat("out of memory");
					}
#else

					if (alt_opt != 0 && !(wide && f_opt)) {
						altdsp_statjob(p_status, p_server, alt_opt, wide, how_opt);
					} else if (f_opt == 0 || tcl_stat("job", p_status, f_opt))
						if (display_statjob(p_status, p_server, f_opt, how_opt, alt_opt))
							exit_qstat("out of memory");
#endif /* localmod 071 */
					p_header = FALSE;
					pbs_statfree(p_status);
				}
				pbs_statfree(p_server);
				p_server = NULL;
				pbs_disconnect(connect);
				if (E_opt == 1) {
					free(query_job_list);
					query_job_list = NULL;
					if (new_remote_server == 1) {
						/* If there is a new remote server
						* then update the prev_server to new server
						*/
						strcpy(prev_server, server_out);
						new_remote_server = 0;
						/* If we are at the end of the loop then
						* query jobs one more time if and only if
						* there are jobs present in job_list
						*/
						if (optind == argc -1) {
							if (query_job_list != NULL) {
								free(query_job_list);
								query_job_list = NULL;
							}
							if (job_list [0] != '\0') {
								query_job_list = strdup(job_list);
								optind++;
								goto job_no_args;
							}
						}
					}
				}
				break;

			case QUEUES:        /* get status of batch queues */
				strcpy(destination, operand);
				if (parse_destination_id(destination,
					&queue_name_out,
					&server_name_out)) {
					fprintf(stderr, "qstat: illegal 'destination' value\n");
#ifdef NAS /* localmod 071 */
					(void)tcl_stat(error, NULL, tcl_opt);
#else
					(void)tcl_stat(error, NULL, f_opt);
#endif /* localmod 071 */
					any_failed = 1;
					break;
				} else {
					if (notNULL(server_name_out)) {
						strcpy(server_out, server_name_out);
					}
					else
						server_out[0] = '\0';
				}
que_no_args:
				connect = cnt2server(server_out);
				if (connect <= 0) {
					fprintf(stderr, "qstat: cannot connect to server %s (errno=%d)\n", pbs_server, pbs_errno);
#ifdef NAS /* localmod 071 */
					(void)tcl_stat(error, NULL, tcl_opt);
#else
					(void)tcl_stat(error, NULL, f_opt);
#endif /* localmod 071 */
					any_failed = connect;
					break;
				}
				p_status = pbs_statque(connect, queue_name_out, NULL, NULL);
				if (p_status == NULL) {
					if (pbs_errno) {
						errmsg = pbs_geterrmsg(connect);
						if (errmsg != NULL) {
							fprintf(stderr, "qstat: %s ", errmsg);
						} else
							fprintf(stderr, "qstat: Error (%d) getting status of queue ", pbs_errno);
						fprintf(stderr, "%s\n", queue_name_out);
#ifdef NAS /* localmod 071 */
						(void)tcl_stat(error, NULL, tcl_opt);
#else
						(void)tcl_stat(error, NULL, f_opt);
#endif /* localmod 071 */
						any_failed = pbs_errno;
					}
				} else {
					if (alt_opt & ALT_DISPLAY_q) {
						altdsp_statque(pbs_server, p_status, alt_opt);
#ifdef NAS /* localmod 071 */
					} else if (tcl_stat("queue", p_status, tcl_opt)) {
#else
					} else if (tcl_stat("queue", p_status, f_opt)) {
#endif /* localmod 071 */
						if(display_statque(p_status, p_header, f_opt, alt_opt))
							exit_qstat("out of memory");
					}
					p_header = FALSE;
					pbs_statfree(p_status);
				}
				pbs_disconnect(connect);
				break;

			case SERVERS:           /* get status of batch servers */
				strcpy(server_out, operand);
svr_no_args:
				connect = cnt2server(server_out);
				if (connect <= 0) {
					fprintf(stderr, "qstat: cannot connect to server %s (errno=%d)\n",
						pbs_server, pbs_errno);
#ifdef NAS /* localmod 071 */
					(void)tcl_stat(error, NULL, tcl_opt);
#else
					(void)tcl_stat(error, NULL, f_opt);
#endif /* localmod 071 */
					any_failed = connect;
					break;
				}
				p_status = pbs_statserver(connect, NULL, NULL);
				if (p_status == NULL) {
					if (pbs_errno) {
						errmsg = pbs_geterrmsg(connect);
						if (errmsg != NULL) {
							fprintf(stderr, "qstat: %s ", errmsg);
						} else
							fprintf(stderr, "qstat: Error (%d) getting status of server ", pbs_errno);
						fprintf(stderr, "%s\n", server_out);
#ifdef NAS /* localmod 071 */
						(void)tcl_stat(error, NULL, tcl_opt);
#else
						(void)tcl_stat(error, NULL, f_opt);
#endif /* localmod 071 */
						any_failed = pbs_errno;
					}
				} else {
#ifdef NAS /* localmod 071 */
					if (tcl_stat("server", p_status, tcl_opt))
#else
					if (tcl_stat("server", p_status, f_opt))
#endif /* localmod 071 */
						if(display_statserver(p_status, p_header, f_opt, alt_opt))
							exit_qstat("out of memory");
					p_header = FALSE;
					pbs_statfree(p_status);
				}
				pbs_disconnect(connect);
				break;

		} /* switch */
	}
	if(output_format == FORMAT_JSON) {
		if (add_json_node(JSON_OBJECT_END, JSON_NULL, JSON_NOVALUE, NULL, NULL) == NULL)
			exit_qstat("out of memory");
		generate_json(stdout);
		free_json_node();
	}
#ifdef NAS /* localmod 071 */
	tcl_run(tcl_opt);
#else
	tcl_run(f_opt);
#endif /* localmod 071 */
	if (E_opt == 1) {
		if (query_job_list != NULL)
			free(query_job_list);
		free(job_list);
	}
	/*cleanup security library initializations before exiting*/
	CS_close_app();

	/*
	 * If the server is not configured for history jobs i.e. job_history_enable
	 * svr attr is unset/set to FALSE, qstat command with -x/-H option is being
	 * used, then pbs_selstat()/pbs_statjob() will return PBSE_JOBHISTNOTSET
	 * error code. But command will exit with exit code '0'after printing the
	 * corresponding error message. i.e. "job_history_enable is set to false".
	 */
	if (any_failed == PBSE_JOBHISTNOTSET)
		any_failed = 0;

	exit(any_failed);
}


/**
 * @brief
 *	cvtResvstate - converts a job reservation "state code" to
 *	descriptive text string
 *
 * @param[out] pcode - descriptive text string
 *
 * @return	string
 * @retval	Pointer to the descriptive text string
 * @retval	The input pointer if conversion fails
 */

static	char*
cvtResvstate(char *pcode)
{
	int	i;
	static char*	resvStrings[] = {"RESV_NONE", "RESV_UNCONFIRMED",
		"RESV_CONFIRMED", "RESV_WAIT",
		"RESV_TIME_TO_RUN", "RESV_RUNNING",
		"RESV_FINISHED", "RESV_BEING_DELETED",
		"RESV_DELETED", "RESV_DELETING_JOBS",
		"RESV_BEING_ALTERED"};

	/*Remark: the static buffer below is used to get around a problem with
	 *	the linux strtok() library function.  There is a "bugs" comment
	 *	on the man page for strtok() that mentions that the function can't
	 *	be called on constant strings.  I presume that this is what is
	 *	causing strtok in prt_attr() to fail when fed the return value
	 *	resvStrings[i], as we had been doing.  So, we return acopy instead
	 */
	static char	acopy[25];

	switch (i = atoi(pcode)) {
		case RESV_NONE:
		case RESV_UNCONFIRMED:
		case RESV_CONFIRMED:
		case RESV_WAIT:
		case RESV_TIME_TO_RUN:
		case RESV_RUNNING:
		case RESV_FINISHED:
		case RESV_BEING_DELETED:
		case RESV_DELETED:
		case RESV_DELETING_JOBS:
		case RESV_BEING_ALTERED:
			strcpy(acopy, resvStrings[i]);
			return  acopy;

		default:
			return  pcode;
	}
}

/*!
 *	cmp_est_time -  compare function used with bs_isort
 *		        compares based on:
 *			1. stime
 *			2. if estimated.start_time < now sort to bottom
 *			3. estimated.start_time
 *
 *	\param a
 *	\param b
 *
 *	\return -1: a < b
 *	\return  0: a == b
 *	\return  1: a > b
 *
 */
static int
cmp_est_time(struct batch_status *a, struct batch_status *b)
{
	char *attrval;
	time_t est_a = -1;
	time_t est_b = -1;
	time_t stime_a = -1;
	time_t stime_b = -1;
	time_t now;

	attrval = get_attr(a->attribs, ATTR_estimated, "start_time");
	if (attrval != NULL)
		est_a = atol(attrval);

	attrval = get_attr(b->attribs, ATTR_estimated, "start_time");
	if (attrval != NULL)
		est_b = atol(attrval);

	attrval = get_attr(a->attribs, ATTR_stime, NULL);
	if (attrval != NULL)
		stime_a = atol(attrval);

	attrval = get_attr(b->attribs, ATTR_stime, NULL);
	if (attrval != NULL)
		stime_b = atol(attrval);


	/* sort running jobs first by stime */
	if (stime_a >= 0 || stime_b >= 0) {
		if (stime_a == -1 && stime_b >= 0)
			return 1;
		else if (stime_a >= 0 && stime_b == -1)
			return -1;
		else if (stime_a < stime_b)
			return -1;
		else if (stime_a > stime_b)
			return 1;
		else
			return 0;
	}


	if (est_a == est_b)
		return 0;

	time(&now);
	/* if estimated start time is before now, sort to bottom */
	if (est_a == -1 || est_a < now)
		return 1;

	if (est_b == -1 || est_b < now)
		return -1;

	if (est_a < est_b)
		return -1;

	if (est_a > est_b)
		return 1;

	return 0;
}

#define SEC_IN_WEEK 604800
/*!
 *	cnvt_est_start_time - convert estimated start time to a time form
 *			      either a short form of 5 characters or the
 *			      wider form of convert_time().
 *
 *	\param est_time - the string value of estimated.start time
 *				ex: "1247683654"
 *	\param wide	- 1 if we should use the wide format 0 if not
 *
 *	\return converted time string
 *	\return "--" if estimated.start_time  < now or est_time == NULL
 *	\return "?" if estimated.start_time == 0
 *
 */
char *
cnvt_est_start_time(char *est_time, int wide)
{
	time_t t;
	time_t start_time;
	char buf[16];
	char buf2[16];
	static char timebuf[32];
	struct tm *tmptr;
	struct tm nowtm;
	struct tm esttm;

	if (est_time == NULL)
		return "--";

	start_time = atol(est_time);

	/* special case: unknown estimated start time: return "?" */
	if (start_time == 0)
		return "?";

	time(&t);
	tmptr = localtime(&t);
	if (tmptr != NULL) {
		nowtm = *tmptr;
		tmptr = localtime(&start_time);
		if (tmptr != NULL)
			esttm = *tmptr;
		else
			return "--";
	}
	else
		return "--";

	/* special case: estimated start time before now: return "--" */
	if (start_time < t)
		return "--";

	if (wide)
		return convert_time(est_time);

	/* within the current day: HH:MM */
	if (nowtm.tm_year == esttm.tm_year && nowtm.tm_yday == esttm.tm_yday) {
		strftime(timebuf, 32, "%H:%M", &esttm);
	} /* within 7 days of now */
	else if ((start_time - t) < SEC_IN_WEEK) {
		strftime(buf, 16, "%a", &esttm);
		strftime(buf2, 16, "%H", &esttm);
		snprintf(timebuf, 32, "%2.2s %s", buf, buf2);
	} /* within the current year: short form of the month */
	else if (nowtm.tm_year == esttm.tm_year) {
		strftime(timebuf, 32, "%b", &esttm);
		/* after the current year: the 4 digit year */
	} else if (esttm.tm_year - nowtm.tm_year < 5) {
		strftime(timebuf, 32, "%Y", &esttm);
	} else { /* after 5 years, print ">5yrs" */
		strcpy(timebuf, ">5yrs");
	}

	return timebuf;
}

