diff --git a/doc/man/man1/sinfo.1 b/doc/man/man1/sinfo.1
index 03e0ef2e598c046d8d2d07b71b5d7fa61e28e792..695d7218f0bd20b32ac2d9eb9dc871a1e7ddfba8 100644
--- a/doc/man/man1/sinfo.1
+++ b/doc/man/man1/sinfo.1
@@ -42,15 +42,15 @@ This is ignored if the \fB\-\-format\fR option is specified.
 .TP
 \fB\-o <output_format>\fR, \fB\-\-format=<output_format>\fR
 Specify the information to be displayed.  
-The default format is "%9P %5a %.8l %.6D %6t %N".
+The default format is "%9P %5a %.9l %.5D %6t %N".
 If the \fB\-\-summarize\fR option is specified, the default 
-format is "%9P %5a %.8l %15F %N".
+format is "%9P %5a %.9l %15F %N".
 If the \fB\-\-long\fR option is specified, the default format is 
-"%9P %5a %.8l %.8s %4r %5h %10g %.6D %11T %N". 
+"%9P %5a %.9l %.8s %4r %5h %10g %.5D %11T %N". 
 If the \fB\-\-Node\fR option is specified, the default format is 
-"%#N %.6D %9P %6t". 
+"%#N %.5D %9P %6t". 
 If the \fB\-\-Node\fR and \fB\-\-long\fR options are both specified, 
-the default format is "%#N %.6D %9P %11T %.4c %.6m %.8d %.6w %8f".
+the default format is "%#N %.5D %9P %11T %.4c %.6m %.8d %.6w %8f".
 In the above two formats the value of "#" represents the maximum 
 length of an node list to be printed.
 
@@ -76,7 +76,7 @@ the different node states will be placed on separate lines.
 .br
 \fB%g\fR Groups which may use the nodes
 .br
-\fB%h\fR Jobs may share nodes, "YES", "NO", or "FORCE"
+\fB%h\fR Jobs may share nodes, "yes", "no", or "force"
 .br
 \fB%l\fR Maximum time for any job in the format "days:hours:minutes:seconds"
 .br
@@ -86,7 +86,7 @@ the different node states will be placed on separate lines.
 .br
 \fB%P\fR Partition name
 .br
-\fB%r\fR Only user root may initiate jobs, "YES" or "NO"
+\fB%r\fR Only user root may initiate jobs, "yes" or "no"
 .br
 \fB%s\fR Maximum job size in nodes
 .br
@@ -100,12 +100,16 @@ the different node states will be placed on separate lines.
 .br 
 \fB%<Number><*>\fR size of field
 .TP
-\fB\-t <state>\fR , \fB\-\-state=<state>\fR
-List nodes of a given state.
+\fB\-t <state>\fR , \fB\-\-states=<states>\fR
+List nodes of given states.
 .TP
 \fB\-s\fR , \fB\-\-summarize\fR
 List only a partition state summary with no node state details.
 This is ignored if the \fB\-\-format\fR option is specified.
+.TP
+\fB\-S <sort>\fR , \fB\-\-sort=<sort>\fR
+Sort the records in the order specified. 
+
 .TP
 \fB\-p <partition>\fR, \fB\-\-partition=<partition>\fR
 Print information only about the specified partition.  
@@ -130,8 +134,24 @@ through "linux07".
 \fBpartition\fR
 The name of one partition.
 .TP
-\fBstate\fR
-A valid node state. Possible values include: ALLOC, ALLOCATED, COMP, 
+\fBsort\fR
+Specification of the order in which records should be reported.
+This uses the same field specifciation as the <output_format>.
+Multiple sorts may be performed by listing multiple sort fields 
+separated by commas.
+The field specifications may be preceeded by "+" or "-" for 
+assending (default) and desending order respectively. 
+For example, a sort value of "P,-m" requests that records by 
+printed in order of increasing partition name and within a 
+partition by decreasing memory size.
+The default value of sort is "P,-t" (increasing partition name 
+then decreasing node state).
+If the "--Node" option is selected, the default sort value is 
+"N" (increasing node name). 
+.TP
+\fBstates\fR
+A comma separated list of valid node state (case insensitive). 
+Possible values include: ALLOC, ALLOCATED, COMP, 
 COMPLETING, DOWN, DRAIN, DRAINED, DRAINING, IDLE, UNK, and UNKNOWN.
 A "*" suffix may be appended to any of these states to search for 
 nodes in the specified state which are not responding. 
@@ -140,39 +160,39 @@ responding or not.
 .SH "OUTPUT"
 .TP
 \fBAVAIL\fR
-Partition state, \fBUP\fR or \fBDOWN\fR.
+Partition state, \fBup\fR or \fBdown\fR.
 .TP
 \fBCPUS\fR
 Count of CPUs (processors) on these nodes.
 .TP
 \fBGROUPS\fR
 Resource allocations in this partition are restricted to the named groups.
-\fBALL\fR indicates that all groups may use this partition.
+\fBall\fR indicates that all groups may use this partition.
 .TP
 \fBJOB_SIZE\fR
 Minimum and maximum node count that can be allocated to any user job. 
 A single number indicates the minimum and maximum node count are the 
 same.
-\fBINFINITE\fR is used to identify partitions without a maximum node count.
+\fBinfinite\fR is used to identify partitions without a maximum node count.
 .TP
-\fBMAX_TIME\fR
+\fBTIMELIMIT\fR
 Maximum time limit for any user job in days:hours:minutes:seconds.
-\fBINFINITE\fR is used to identify partitions without a job time limit.
+\fBinfinite\fR is used to identify partitions without a job time limit.
 .TP
 \fBMEMORY\fR
 Size of real memory in megabytes on these nodes.
 .TP
-\fBNODE_LIST\fR
+\fBNODELIST\fR
 Names of nodes associated with this configuration/partition.
 .TP
-\fB#NODES\fR
+\fBNODES\fR
 Count of nodes with this particular configuration.
 .TP
-\fB#NODES(A/T)\fR
+\fBNODES(A/T)\fR
 Count of nodes with this particular configuration by node 
 state in the form "available/total".
 .TP
-\fB#NODES(A/I/O/T)\fR
+\fBNODES(A/I/O/T)\fR
 Count of nodes with this particular configuration by node
 state in the form "available/idle/other/total".
 .TP
@@ -182,13 +202,13 @@ Note that the suffix "*" identifies the default partition.
 .TP
 \fBROOT\fR
 Is the ability to allocate resources in this partition restricted to 
-user root, \fBYES\fR or \fBNO\fR.
+user root, \fByes\fR or \fBno\fR.
 .TP
 \fBSHARE\fR
 Will jobs allocated resources in this partition share those resources.
-\fBNO\fR indicates resources are never shared. 
-\fBFORCE\fR indicates resources are always available to be shared.
-\fBYES\fR indicates resource may be shared or not per job's resource 
+\fBno\fR indicates resources are never shared. 
+\fBforce\fR indicates resources are always available to be shared.
+\fByes\fR indicates resource may be shared or not per job's resource 
 allocation.
 .TP
 \fBSTATE\fR
@@ -209,6 +229,9 @@ SINFO_FORMAT
 .TP
 SINFO_PARTITION
 \fB\-p <partition>, \-\-partition=<partition>\fR
+.TP
+SINFO_SORT
+\fB\-S <sort>, \-\-sort=<sort>\fR
 
 .SH "EXAMPLES"
 .eo
@@ -216,15 +239,13 @@ Report basic node and partition configurations:
 .br
 > sinfo
 .br
-PARTITION AVAIL MAX_TIME #NODES STATE  NODE_LIST
-.br
-------------------------------------------------
+PARTITION AVAIL TIMELIMIT NODES STATE  NODELIST
 .br
-debug     UP       30:00     8 IDLE   adev[0-7]
+batch     up     infinite     2 alloc  adev[8-9]
 .br
-batch*    UP    INFINITE     2 ALLOC  adev[8-9]
+batch     up     infinite     6 idle   adev[10-15]
 .br
-batch*    UP    INFINITE     6 IDLE   adev[10-15]
+debug*    up        30:00     8 idle   adev[0-7]
 .br
  
 .br
@@ -232,13 +253,11 @@ Report partition summary information:
 .br
 > sinfo -s
 .br
-PARTITION AVAIL MAX_TIME #NODES(A/I/O/T) NODE_LIST
+PARTITION AVAIL TIMELIMIT NODES(A/I/O/T) NODELIST
 .br
----------------------------------------------------
+batch     up     infinite 2/6/0/8        adev[8-15]
 .br
-debug     UP       30:00 0/8/0/8         adev[0-7]
-.br
-batch*    UP    INFINITE 2/6/0/8         adev[8-15]
+debug*    up        30:00 0/8/0/8        adev[0-7]
 .br
  
 .br
@@ -246,23 +265,19 @@ Report more complete information about the partition debug:
 .br
 > sinfo --long --partition=debug
 .br
-PARTITION AVAIL MAX_TIME JOB_SIZE ROOT SHARE GROUPS #NODES STATE NODE_LIST
-.br
---------------------------------------------------------------------------
+PARTITION AVAIL TIMELIMIT JOB_SIZE ROOT SHARE GROUPS NODES STATE NODELIST
 .br
-debug     UP       30:00        8 NO   NO    ALL    8      IDLE  dev[0-7]
+debug*    up        30:00        8 no   no    all        8 idle  dev[0-7]
 .br
 
 .br
 Report only those nodes that are in state DRAINED:
 .br
-> sinfo --state=DRAINED
+> sinfo --state=drained
 .br
-PARTITION AVAIL NODES STATE  NODE_LIST
+PARTITION AVAIL NODES TIMELIMIT STATE  NODELIST
 .br
---------------------------------------
-.br
-debug     UP        2 DRAIN  adev[6-7]
+debug*    up        2     30:00 drain  adev[6-7]
 .br
 
 .br
@@ -270,19 +285,17 @@ Report node-oriented information with details and exact matches:
 .br
 > sinfo -Nel
 .br
-NODE_LIST  #NODES PARTITION STATE  CPUS MEMORY TMP_DISK WEIGHT FEATURES
-.br
------------------------------------------------------------------------
+NODELIST    NODES PARTITION STATE  CPUS MEMORY TMP_DISK WEIGHT FEATURES
 .br
-adev[0-1]       2 debug     IDLE      2   3448    38536     16 (null)  
+adev[0-1]       2 debug*    idle      2   3448    38536     16 (null)  
 .br
-adev[2,4-7]     5 debug     IDLE      2   3384    38536     16 (null)  
+adev[2,4-7]     5 debug*    idle      2   3384    38536     16 (null)  
 .br
-adev3           1 debug     IDLE      2   3394    38536     16 (null)  
+adev3           1 debug*    idle      2   3394    38536     16 (null)  
 .br
-adev[8-9]       2 batch     ALLOCATED 2    246    82306     16 (null)  
+adev[8-9]       2 batch     allocated 2    246    82306     16 (null)  
 .br
-adev[10-15]     6 batch     IDLE      2    246    82306     16 (null)  
+adev[10-15]     6 batch     idle      2    246    82306     16 (null)  
 .ec
 
 .SH "COPYING"
diff --git a/src/sinfo/Makefile.am b/src/sinfo/Makefile.am
index 8688e4edd61f911812428f660828a9576ccd67d2..d23ef52bf2642e1a8b426b84cad597194e2f4970 100644
--- a/src/sinfo/Makefile.am
+++ b/src/sinfo/Makefile.am
@@ -14,7 +14,7 @@ sinfo_LDADD =					  \
 	$(POPT_LIBS)
 
 noinst_HEADERS = sinfo.h print.h
-sinfo_SOURCES = sinfo.c opts.c print.c
+sinfo_SOURCES = sinfo.c opts.c print.c sort.c
 
 force:
 $(sinfo_LDADD) : force
diff --git a/src/sinfo/opts.c b/src/sinfo/opts.c
index 7de226e3952e86ee80f816dd84bdca18d08d1f2a..b168e0e60bb8dad48b9aec88339e762535c4cf5f 100644
--- a/src/sinfo/opts.c
+++ b/src/sinfo/opts.c
@@ -47,16 +47,18 @@
 #define OPT_VERBOSE   	0x07
 #define OPT_ITERATE   	0x08
 #define OPT_EXACT   	0x09
-#define OPT_LONG   	    0x0a
-#define OPT_SHORT  	    0x0b
+#define OPT_LONG    	0x0a
+#define OPT_SHORT  		0x0b
 #define OPT_NO_HEAD   	0x0c
 #define OPT_VERSION     0x0d
-
+#define OPT_SORT    	0x0e
 
 /* FUNCTIONS */
+static List  _build_state_list( char* str );
+static List  _build_all_states_list( void );
 static char *_get_prefix(char *token);
 static int   _parse_format( char* );
-static int   _parse_state(char *str, enum node_states *states);
+static int   _parse_state(char *str, uint16_t *states);
 static void  _parse_token( char *token, char *field, int *field_size, 
                            bool *right_justify, char **suffix);
 static void  _print_options( void );
@@ -74,34 +76,39 @@ int parse_command_line(int argc, char *argv[])
 	int curr_opt;
 	int rc = 0;
 	char *env_val = NULL;
-	static char *temp_state = NULL;
 
 	/* Declare the Options */
 	static const struct poptOption options[] = {
 		{"exact", 'e', POPT_ARG_NONE, &params.exact_match, OPT_EXACT,
-		 "group nodes only on exact match of configuration",NULL},
+			"group nodes only on exact match of configuration",
+			NULL},
 		{"iterate", 'i', POPT_ARG_INT, &params.iterate,
-		 OPT_ITERATE, "specify an interation period", "seconds"},
-		{"state", 't', POPT_ARG_STRING, &temp_state,
-		 OPT_NODE_STATE, "specify the what state of nodes to view",
-		 "node_state"},
+			OPT_ITERATE, "specify an interation period", 
+			"seconds"},
+		{"states", 't', POPT_ARG_STRING, &params.states,
+			OPT_NODE_STATE, 
+			"specify the what states of nodes to view",
+			"node_state"},
 		{"partition", 'p', POPT_ARG_STRING, &params.partition,
-		 OPT_PARTITION, "report on specific partition", "PARTITION"},
+			OPT_PARTITION, "report on specific partition", 
+			"PARTITION"},
 		{"nodes", 'n', POPT_ARG_STRING, &params.nodes, OPT_NODES,
-		 "report on specific node(s)", "NODES"},
+			"report on specific node(s)", "NODES"},
 		{"Node", 'N', POPT_ARG_NONE, &params.node_flag, OPT_NODE,
-		 "Node-centric format", NULL},
+			"Node-centric format", NULL},
 		{"long", 'l', POPT_ARG_NONE, &params.long_output,
-		 OPT_LONG, "long output - displays more information",
-		 NULL},
+			OPT_LONG, "long output - displays more information",
+			NULL},
+		{"sort", 'S', POPT_ARG_STRING, &params.sort, OPT_SORT,
+			"comma seperated list of fields to sort on", "fields"},
 		{"summarize", 's', POPT_ARG_NONE, &params.summarize,
-		 OPT_SHORT,"report state summary only", NULL},
+			OPT_SHORT,"report state summary only", NULL},
 		{"verbose", 'v', POPT_ARG_NONE, &params.verbose,
-		 OPT_VERBOSE, "verbosity level", "level"},
+			OPT_VERBOSE, "verbosity level", "level"},
 		{"noheader", 'h', POPT_ARG_NONE, &params.no_header, 
-		 OPT_NO_HEAD, "no headers on output", NULL},
+			OPT_NO_HEAD, "no headers on output", NULL},
 		{"format", 'o', POPT_ARG_STRING, &params.format, OPT_FORMAT, 
-		 "format specification", "format"},
+			"format specification", "format"},
 		{"version", 'V', POPT_ARG_NONE, 0, OPT_VERSION,
 			"output version information and exit", NULL},
 		POPT_AUTOHELP 
@@ -118,14 +125,7 @@ int parse_command_line(int argc, char *argv[])
 		switch ( curr_opt )
 		{
 			case OPT_NODE_STATE:
-				params.state_flag = true;
-				if (_parse_state(temp_state, &params.state)
-				    == SLURM_ERROR) {
-					fprintf(stderr,
-						"%s: %s is invalid node state\n",
-						argv[0], temp_state);
-					exit(1);
-				}
+				params.state_list = _build_state_list( params.states );
 				break;
 			case OPT_VERSION:
 				_print_version();
@@ -146,28 +146,32 @@ int parse_command_line(int argc, char *argv[])
 	}
 
 	if ( ( params.format == NULL ) && 
-	     ( env_val = getenv("SINFO_FORMAT") ) ) 
+	     ( env_val = getenv("SINFO_FORMAT") ) )
 		params.format = xstrdup(env_val);
 
 	if ( ( params.partition == NULL ) && 
-	     ( env_val = getenv("SINFO_PARTITION") ) ) 
+	     ( env_val = getenv("SINFO_PARTITION") ) )
 		params.partition = xstrdup(env_val);
 
+	if ( ( params.partition == NULL ) && 
+	     ( env_val = getenv("SINFO_SORT") ) )
+		params.sort = xstrdup(env_val);
+
 	if ( params.format == NULL ) {
 		if ( params.summarize ) 
-			params.format = "%9P %5a %.8l %15F %N";
+			params.format = "%9P %5a %.9l %15F %N";
 		else if ( params.node_flag ) {
 			params.node_field_flag = true;	/* compute size later */
 			if ( params.long_output ) {
-				params.format = "%N %.6D %9P %11T %.4c %.6m %.8d %.6w %8f";
+				params.format = "%N %.5D %9P %11T %.4c %.6m %.8d %.6w %8f";
 			} else {
-				params.format = "%N %.6D %9P %6t";
+				params.format = "%N %.5D %9P %6t";
 			}
 		} else {
 			if ( params.long_output )
-				params.format = "%9P %5a %.8l %.8s %4r %5h %10g %.6D %11T %N";
+				params.format = "%9P %5a %.9l %.8s %4r %5h %10g %.5D %11T %N";
 			else
-				params.format = "%9P %5a %.8l %.6D %6t %N";
+				params.format = "%9P %5a %.9l %.5D %6t %N";
 		}
 	}
 	_parse_format( params.format );
@@ -177,14 +181,66 @@ int parse_command_line(int argc, char *argv[])
 	return rc;
 }
 
+/*
+ * _build_state_list - build a list of job states
+ * IN str - comma separated list of job states
+ * RET List of enum job_states values
+ */
+static List 
+_build_state_list( char* str )
+{
+	List my_list;
+	char *state, *tmp_char, *my_state_list;
+	uint16_t *state_id;
+
+	if ( str == NULL)
+		return NULL;
+	if ( strcasecmp( str, "all" ) == 0 )
+		return _build_all_states_list ();
+
+	my_list = list_create( NULL );
+	my_state_list = xstrdup( str );
+	state = strtok_r( my_state_list, ",", &tmp_char );
+	while (state) 
+	{
+		state_id = xmalloc( sizeof( uint16_t ) );
+		if ( _parse_state( state, state_id ) != SLURM_SUCCESS )
+			exit( 1 );
+		list_append( my_list, state_id );
+		state = strtok_r( NULL, ",", &tmp_char );
+	}
+	xfree( my_state_list );
+	return my_list;
+}
+
+/*
+ * _build_all_states_list - build a list containing all possible job states
+ * RET List of enum job_states values
+ */
+static List 
+_build_all_states_list( void )
+{
+	List my_list;
+	int i;
+	uint16_t *state_id;
+
+	my_list = list_create( NULL );
+	for (i = 0; i<NODE_STATE_END; i++) {
+		state_id = xmalloc( sizeof( uint16_t ) );
+		*state_id = (uint16_t) i;
+		list_append( my_list, state_id );
+	}
+	return my_list;
+}
+
 /*
  * _parse_state - convert node state name string to numeric value
  * IN str - state name
- * OUT states - enum node_states value corresponding to str
+ * OUT states - node_state value corresponding to str
  * RET 0 or error code
  */
 static int
-_parse_state( char* str, enum node_states* states )
+_parse_state( char* str, uint16_t* states )
 {	
 	int i;
 	char *state_names;
@@ -230,10 +286,7 @@ _parse_format( char* format )
 	if ((prefix = _get_prefix(format)))
 		format_add_prefix( params.format_list, 0, 0, prefix); 
 
-	field_size = strlen( format );
-	tmp_format = xmalloc( field_size + 1 );
-	strcpy( tmp_format, format );
-
+	tmp_format = xstrdup( format );
 	token = strtok_r( tmp_format, "%", &tmp_char);
 	if (token && (format[0] != '%'))	/* toss header */
 		token = strtok_r( NULL, "%", &tmp_char );
@@ -408,13 +461,6 @@ _parse_token( char *token, char *field, int *field_size, bool *right_justify,
 /* print the parameters specified */
 void _print_options( void )
 {
-	char *node_state;
-	
-	if (params.state_flag)
-		node_state = node_state_string(params.state);
-	else
-		node_state = "N/A";
-
 	printf("-----------------------------\n");
 	printf("exact       = %d\n", params.exact_match);
 	printf("format      = %s\n", params.format);
@@ -424,18 +470,19 @@ void _print_options( void )
 	printf("node_field  = %s\n", params.node_field_flag ? 
 					"true" : "false");
 	printf("node_format = %s\n", params.node_flag   ? "true" : "false");
-	printf("nodes       = %s\n", params.nodes ? params.nodes : "N/A");
+	printf("nodes       = %s\n", params.nodes ? params.nodes : "n/a");
 	printf("partition   = %s\n", params.partition ? 
-					params.partition: "N/A");
-	printf("state       = %s\n", node_state);
+					params.partition: "n/a");
+	printf("states      = %s\n", params.states);
+	printf("sort        = %s\n", params.sort);
 	printf("summarize   = %s\n", params.summarize   ? "true" : "false");
 	printf("verbose     = %d\n", params.verbose);
 	printf("-----------------------------\n\n");
 }
 
+
 static void _print_version(void)
 {
 	printf("%s %s\n", PACKAGE, SLURM_VERSION);
 }
 
-
diff --git a/src/sinfo/print.c b/src/sinfo/print.c
index 1f4e608ef687df8181508ab9a2ece5a3b47d69a9..63739392572ccf3667eeea8e7bd7742d2cb525d7 100644
--- a/src/sinfo/print.c
+++ b/src/sinfo/print.c
@@ -24,6 +24,7 @@
  *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
 \*****************************************************************************/
 
+#include <ctype.h>
 #include <time.h>
 #include <stdio.h>
 #include <string.h>
@@ -39,11 +40,12 @@
 
 #define MIN_NODE_FIELD_SIZE 9
 
-static int  _build_min_max_string(char *buffer, int buf_size, int min, 
-                                  int max, bool range);
-static int  _print_secs(long time, int width, bool right, bool cut_output);
-static int  _print_str(char *str, int width, bool right, bool cut_output);
-static void _set_node_field_size(List sinfo_list);
+static int   _build_min_max_string(char *buffer, int buf_size, int min, 
+                                   int max, bool range);
+static int   _print_secs(long time, int width, bool right, bool cut_output);
+static int   _print_str(char *str, int width, bool right, bool cut_output);
+static void  _set_node_field_size(List sinfo_list);
+static char *_str_tolower(char *upper_str);
 
 /*****************************************************************************
  * Global Print Functions
@@ -56,7 +58,7 @@ void print_date(void)
 	printf("%s", ctime(&now));
 }
 
-int print_sinfo_list(List sinfo_list, List format)
+int print_sinfo_list(List sinfo_list)
 {
 	ListIterator i = list_iterator_create(sinfo_list);
 	sinfo_data_t *current;
@@ -65,20 +67,19 @@ int print_sinfo_list(List sinfo_list, List format)
 		_set_node_field_size(sinfo_list);
 
 	if (!params.no_header)
-		print_sinfo_entry(NULL, format);
+		print_sinfo_entry(NULL);
 
 	while ((current = list_next(i)) != NULL)
-		 print_sinfo_entry(current, format);
+		 print_sinfo_entry(current);
 
 	list_iterator_destroy(i);
 	return SLURM_SUCCESS;
 }
 
-int print_sinfo_entry(sinfo_data_t *sinfo_data , List format)
+int print_sinfo_entry(sinfo_data_t *sinfo_data)
 {
-	ListIterator i = list_iterator_create(format);
+	ListIterator i = list_iterator_create(params.format_list);
 	sinfo_format_t *current;
-	int total_width = 0, inx;
 
 	while ((current = (sinfo_format_t *) list_next(i)) != NULL) {
 		if (current->
@@ -86,23 +87,10 @@ int print_sinfo_entry(sinfo_data_t *sinfo_data , List format)
 					current->right_justify, current->suffix)
 		    != SLURM_SUCCESS)
 			return SLURM_ERROR;
-		if (current->width)
-			total_width += (current->width + 1);
-		else if ((current->function == _print_node_list) &&
-		         (params.node_field_flag))
-			total_width += (params.node_field_size + 1);
-		else
-			total_width += 10;
 	}
 	list_iterator_destroy(i);
 
 	printf("\n");
-	if (sinfo_data == NULL) {
-		/* one-origin for no trailing space */
-		for (inx=1; inx<total_width; inx++)
-			printf("-");
-		printf("\n");
-	}
 	return SLURM_SUCCESS;
 }
 
@@ -175,7 +163,7 @@ _build_min_max_string(char *buffer, int buf_size, int min, int max, bool range)
 		return snprintf(buffer, buf_size, "%d", max);
 	else if (range) {
 		if (max == INFINITE)
-			return snprintf(buffer, buf_size, "%d-INFINITE", min);
+			return snprintf(buffer, buf_size, "%d-infinite", min);
 		else
 			return snprintf(buffer, buf_size, "%d-%d", min, max);
 	} else
@@ -216,6 +204,22 @@ static void _set_node_field_size(List sinfo_list)
 	params.node_field_size = max_width;
 }
 
+/*
+ * _str_tolower - convert string to all lower case
+ * upper_str IN - upper case input string
+ * RET - lower case version of upper_str, caller must be xfree
+ */ 
+static char *_str_tolower(char *upper_str)
+{
+	int i = strlen(upper_str) + 1;
+	char *lower_str = xmalloc(i);
+
+	for (i=0; upper_str[i]; i++)
+		lower_str[i] = tolower((int) upper_str[i]);
+
+	return lower_str;
+}
+
 /*****************************************************************************
  * Sinfo Print Functions
  *****************************************************************************/
@@ -225,11 +229,11 @@ int _print_avail(sinfo_data_t * sinfo_data, int width,
 {
 	if (sinfo_data) {
 		if (sinfo_data->part_info == NULL)
-			_print_str("N/A", width, right_justify, true);
+			_print_str("n/a", width, right_justify, true);
 		else if (sinfo_data->part_info->state_up)
-			_print_str("UP", width, right_justify, true);
+			_print_str("up", width, right_justify, true);
 		else
-			_print_str("DOWN", width, right_justify, true);
+			_print_str("down", width, right_justify, true);
 	} else
 		_print_str("AVAIL", width, right_justify, true);
 
@@ -290,12 +294,12 @@ int _print_groups(sinfo_data_t * sinfo_data, int width,
 {
 	if (sinfo_data) {
 		if (sinfo_data->part_info == NULL)
-			_print_str("N/A", width, right_justify, true);
+			_print_str("n/a", width, right_justify, true);
 		else if (sinfo_data->part_info->allow_groups)
 			_print_str(sinfo_data->part_info->allow_groups, 
 					width, right_justify, true);
 		else
-			_print_str("ALL", width, right_justify, true);
+			_print_str("all", width, right_justify, true);
 	} else
 		_print_str("GROUPS", width, right_justify, true);
 
@@ -333,7 +337,7 @@ int _print_node_list(sinfo_data_t * sinfo_data, int width,
 					sizeof(tmp), tmp);
 		_print_str(tmp, width, right_justify, true);
 	} else
-		_print_str("NODE_LIST", width, right_justify, true);
+		_print_str("NODELIST", width, right_justify, true);
 
 	if (suffix)
 		printf("%s", suffix);
@@ -348,7 +352,7 @@ int _print_nodes_t(sinfo_data_t * sinfo_data, int width,
 		snprintf(id, FORMAT_STRING_SIZE, "%u", sinfo_data->nodes_tot);
 		_print_str(id, width, right_justify, true);
 	} else
-		_print_str("#NODES", width, right_justify, true);
+		_print_str("NODES", width, right_justify, true);
 
 	if (suffix)
 		printf("%s", suffix);
@@ -364,7 +368,7 @@ int _print_nodes_at(sinfo_data_t * sinfo_data, int width,
 		         sinfo_data->nodes_alloc, sinfo_data->nodes_tot);
 		_print_str(id, width, right_justify, true);
 	} else
-		_print_str("#NODES(A/T)", width, right_justify, true);
+		_print_str("NODES(A/T)", width, right_justify, true);
 
 	if (suffix)
 		printf("%s", suffix);
@@ -381,7 +385,7 @@ int _print_nodes_aiot(sinfo_data_t * sinfo_data, int width,
 		         sinfo_data->nodes_other, sinfo_data->nodes_tot);
 		_print_str(id, width, right_justify, true);
 	} else
-		_print_str("#NODES(A/I/O/T)", width, right_justify, true);
+		_print_str("NODES(A/I/O/T)", width, right_justify, true);
 
 	if (suffix)
 		printf("%s", suffix);
@@ -393,7 +397,7 @@ int _print_partition(sinfo_data_t * sinfo_data, int width,
 {
 	if (sinfo_data) {
 		if (sinfo_data->part_info == NULL)
-			_print_str("N/A", width, right_justify, true);
+			_print_str("n/a", width, right_justify, true);
 		else {
 			char *tmp;
 			tmp = xstrdup(sinfo_data->part_info->name);
@@ -423,11 +427,11 @@ int _print_root(sinfo_data_t * sinfo_data, int width,
 {
 	if (sinfo_data) {
 		if (sinfo_data->part_info == NULL)
-			_print_str("N/A", width, right_justify, true);
+			_print_str("n/a", width, right_justify, true);
 		else if (sinfo_data->part_info->root_only)
-			_print_str("YES", width, right_justify, true);
+			_print_str("yes", width, right_justify, true);
 		else
-			_print_str("NO", width, right_justify, true);
+			_print_str("no", width, right_justify, true);
 	} else
 		_print_str("ROOT", width, right_justify, true);
 
@@ -441,13 +445,13 @@ int _print_share(sinfo_data_t * sinfo_data, int width,
 {
 	if (sinfo_data) {
 		if (sinfo_data->part_info == NULL)
-			_print_str("N/A", width, right_justify, true);
+			_print_str("n/a", width, right_justify, true);
 		else if (sinfo_data->part_info->shared > 1)
-			_print_str("FORCE", width, right_justify, true);
+			_print_str("force", width, right_justify, true);
 		else if (sinfo_data->part_info->shared)
-			_print_str("YES", width, right_justify, true);
+			_print_str("yes", width, right_justify, true);
 		else
-			_print_str("NO", width, right_justify, true);
+			_print_str("no", width, right_justify, true);
 	} else
 		_print_str("SHARE", width, right_justify, true);
 
@@ -462,8 +466,11 @@ int _print_size(sinfo_data_t * sinfo_data, int width,
 	char id[FORMAT_STRING_SIZE];
 	if (sinfo_data) {
 		if (sinfo_data->part_info == NULL)
-			_print_str("N/A", width, right_justify, true);
+			_print_str("n/a", width, right_justify, true);
 		else {
+			if ((sinfo_data->part_info->min_nodes < 1) &&
+			    (sinfo_data->part_info->max_nodes > 0))
+				sinfo_data->part_info->min_nodes = 1;
 			_build_min_max_string(id, FORMAT_STRING_SIZE, 
 		                      sinfo_data->part_info->min_nodes, 
 		                      sinfo_data->part_info->max_nodes,
@@ -481,10 +488,15 @@ int _print_size(sinfo_data_t * sinfo_data, int width,
 int _print_state_compact(sinfo_data_t * sinfo_data, int width,
 			bool right_justify, char *suffix)
 {
-	if (sinfo_data) {
-		_print_str(node_state_string_compact(sinfo_data->node_state), 
-				width, right_justify, true);
-	} else
+	if (sinfo_data && sinfo_data->nodes_tot) {
+		char *upper_state = node_state_string_compact(
+				sinfo_data->node_state);
+		char *lower_state = _str_tolower(upper_state);
+		_print_str(lower_state, width, right_justify, true);
+		xfree(lower_state);
+	} else if (sinfo_data)
+		_print_str("n/a", width, right_justify, true);
+	else
 		_print_str("STATE", width, right_justify, true);
 
 	if (suffix)
@@ -495,10 +507,14 @@ int _print_state_compact(sinfo_data_t * sinfo_data, int width,
 int _print_state_long(sinfo_data_t * sinfo_data, int width,
 			bool right_justify, char *suffix)
 {
-	if (sinfo_data) {
-		_print_str(node_state_string(sinfo_data->node_state), 
-				width, right_justify, true);
-	} else
+	if (sinfo_data && sinfo_data->nodes_tot) {
+		char *upper_state = node_state_string(sinfo_data->node_state);
+		char *lower_state = _str_tolower(upper_state);
+		_print_str(lower_state, width, right_justify, true);
+		xfree(lower_state);
+	} else if (sinfo_data)
+		_print_str("n/a", width, right_justify, true);
+	else
 		_print_str("STATE", width, right_justify, true);
 
 	if (suffix)
@@ -512,14 +528,14 @@ int _print_time(sinfo_data_t * sinfo_data, int width,
 {
 	if (sinfo_data) {
 		if (sinfo_data->part_info == NULL)
-			_print_str("N/A", width, right_justify, true);
+			_print_str("n/a", width, right_justify, true);
 		else if (sinfo_data->part_info->max_time == INFINITE)
-			_print_str("INFINITE", width, right_justify, true);
+			_print_str("infinite", width, right_justify, true);
 		else
 			_print_secs((sinfo_data->part_info->max_time * 60L),
 					width, right_justify, true);
 	} else
-		_print_str("MAX_TIME", width, right_justify, true);
+		_print_str("TIMELIMIT", width, right_justify, true);
 
 	if (suffix)
 		printf("%s", suffix);
diff --git a/src/sinfo/print.h b/src/sinfo/print.h
index d63231fd4af3171b20292d77d3f2e1fea536b8e8..b36d3f25b051f928c73563dafcbd5e0f4eda0a37 100644
--- a/src/sinfo/print.h
+++ b/src/sinfo/print.h
@@ -50,7 +50,10 @@ typedef struct sinfo_format {
 int format_add_function(List list, int width, bool right_justify,
 		char * suffix, 
 		int (*function) (sinfo_data_t  *, int, bool, char *));
+
 void print_date(void);
+int  print_sinfo_entry(sinfo_data_t *sinfo_data);
+int  print_sinfo_list(List sinfo_list);
 
 #define format_add_avail(list,wid,right,suffix) \
 	format_add_function(list,wid,right,suffix,_print_avail)
diff --git a/src/sinfo/sinfo.c b/src/sinfo/sinfo.c
index 1dadf5f1f51581c5b525d24754410d3b9e902a8f..e3c05713bfb4e0ef7360e60b07b860a72f51187d 100644
--- a/src/sinfo/sinfo.c
+++ b/src/sinfo/sinfo.c
@@ -44,22 +44,24 @@ static void _sinfo_list_delete(void *data);
 static void _filter_nodes(node_info_msg_t *node_msg, int *node_rec_cnt);
 static partition_info_t *_find_part(char *part_name, 
 		partition_info_msg_t *partition_msg);
+static bool _match_node_data(sinfo_data_t *sinfo_ptr, 
+                             node_info_t *node_ptr);
+static bool _match_part_data(sinfo_data_t *sinfo_ptr, 
+                             partition_info_t* part_ptr);
 static int  _query_server(partition_info_msg_t ** part_pptr,
 		node_info_msg_t ** node_pptr);
-static int  _part_order (void *data1, void *data2);
-static void _sort_sinfo_data(List sinfo_list);
 static int  _strcmp(char *data1, char *data2);
 static void _swap_char(char **from, char **to);
 static void _swap_node_rec(node_info_t *from_node, node_info_t *to_node);
-static void _update_sinfo(sinfo_data_t *sinfo_ptr, partition_info_t* part_ptr, 
-		node_info_t *node_ptr);
+static void _update_sinfo(sinfo_data_t *sinfo_ptr, 
+		partition_info_t* part_ptr, node_info_t *node_ptr);
 
 int main(int argc, char *argv[])
 {
 	log_options_t opts = LOG_OPTS_STDERR_ONLY;
 	partition_info_msg_t *partition_msg = NULL;
 	node_info_msg_t *node_msg = NULL;
-	List sinfo_list;
+	List sinfo_list = NULL;
 	int node_rec_cnt = 0;
 
 	log_init("sinfo", opts, SYSLOG_FACILITY_DAEMON, NULL);
@@ -77,8 +79,8 @@ int main(int argc, char *argv[])
 		sinfo_list = list_create(_sinfo_list_delete);
 		_build_sinfo_data(sinfo_list, partition_msg, 
 				node_msg, node_rec_cnt);
-		_sort_sinfo_data(sinfo_list);
-		print_sinfo_list(sinfo_list, params.format_list);
+		sort_sinfo_list(sinfo_list);
+		print_sinfo_list(sinfo_list);
 
 		if (params.iterate) {
 			list_destroy(sinfo_list);
@@ -123,7 +125,6 @@ _query_server(partition_info_msg_t ** part_pptr,
 		return error_code;
 	}
 
-
 	old_part_ptr = new_part_ptr;
 	*part_pptr = new_part_ptr;
 
@@ -161,12 +162,14 @@ static void _filter_nodes(node_info_msg_t *node_msg, int *node_rec_cnt)
 
 	if (((params.nodes == NULL) && 
 	     (params.partition 	== NULL) && 
-	     (!params.state_flag)) ||
+	     (params.state_list == NULL)) ||
 	     params.summarize) {
+		params.filtering = false;
 		/* Nothing to filter out */
 		*node_rec_cnt = node_msg->record_count;
 		return;
 	}
+	params.filtering = true;
 
 	if (params.nodes)
 		hosts = hostlist_create(params.nodes);
@@ -179,12 +182,26 @@ static void _filter_nodes(node_info_msg_t *node_msg, int *node_rec_cnt)
 			 (node_msg->node_array[i].partition,
 			  params.partition))
 			continue;
-		if (params.state_flag && 
-		    (node_msg->node_array[i].node_state !=
-			    params.state) && 
-		    ((node_msg->node_array[i].node_state & 
-		      (~NODE_STATE_NO_RESPOND)) != params.state)) 
-			continue;
+		if (params.state_list) {
+			int *node_state;
+			bool match = false;
+			ListIterator iterator;
+			iterator = list_iterator_create(params.state_list);
+			while ((node_state = list_next(iterator))) {
+				if ((node_msg->node_array[i].node_state ==
+				     *node_state) || 
+				    ((node_msg->node_array[i].node_state & 
+		      		     (~NODE_STATE_NO_RESPOND)) == 
+				     *node_state)) {
+					match = true;
+					break;
+				}
+			}
+			list_iterator_destroy(iterator);
+			if (!match) 
+				continue;
+		}
+
 		_swap_node_rec(&node_msg->node_array[i], 
 			       &node_msg->node_array[new_rec_cnt]);
 		new_rec_cnt++;
@@ -238,7 +255,13 @@ static int _build_sinfo_data(List sinfo_list,
 	ListIterator i;
 	int j;
 
-	/* remove any existing sinfo_list entries */
+	/* by default every partition is shown, even if no nodes */
+	if ((!params.filtering) && (!params.node_flag)) {
+		for (j=0; j<partition_msg->record_count; j++) {
+			part_ptr = partition_msg->partition_array + j;
+			_create_sinfo(sinfo_list, part_ptr, NULL);
+		}
+	}
 
 	/* make sinfo_list entries for each node */
 	for (j=0; j<node_cnt; j++) {
@@ -249,42 +272,11 @@ static int _build_sinfo_data(List sinfo_list,
 
 		/* test if node can be added to existing sinfo_data entry */
 		while ((sinfo_ptr = list_next(i))) {
-			if (params.match_flags.avail_flag &&
-			    (part_ptr->state_up != sinfo_ptr->part_info->state_up))
-					continue;
-			if (params.match_flags.features_flag &&
-			    (_strcmp(node_ptr->features, sinfo_ptr->features)))
-					continue;
-			
-			if (params.match_flags.groups_flag &&
-			    (_strcmp(part_ptr->allow_groups, 
-			             sinfo_ptr->part_info->allow_groups)))
-					continue;
-			if (params.match_flags.job_size_flag &&
-			    (part_ptr->min_nodes != 
-			     sinfo_ptr->part_info->min_nodes))
-					continue;
-			if (params.match_flags.job_size_flag &&
-			    (part_ptr->max_nodes != 
-			     sinfo_ptr->part_info->max_nodes))
-					continue;
-			if (params.match_flags.max_time_flag &&
-			    (part_ptr->max_time != sinfo_ptr->part_info->max_time))
-					continue;
-			if (params.match_flags.partition_flag &&
-			    (_strcmp(part_ptr->name, sinfo_ptr->part_info->name)))
-					continue;
-			if (params.match_flags.root_flag &&
-			    (part_ptr->root_only != 
-			     sinfo_ptr->part_info->root_only))
-					continue;
-			if (params.match_flags.share_flag &&
-			    (part_ptr->shared != 
-			     sinfo_ptr->part_info->shared))
-					continue;
-			if (params.match_flags.state_flag &&
-			    (node_ptr->node_state != sinfo_ptr->node_state))
-					continue;
+			if (!_match_part_data(sinfo_ptr, part_ptr))
+				continue;
+			if (sinfo_ptr->nodes_tot &&
+			    (!_match_node_data(sinfo_ptr, node_ptr)))
+				continue;
 
 			/* This node has the same configuration as this 
 			 * sinfo_data, just add to this record */
@@ -301,9 +293,112 @@ static int _build_sinfo_data(List sinfo_list,
 	return SLURM_SUCCESS;
 }
 
+static bool _match_node_data(sinfo_data_t *sinfo_ptr, 
+                             node_info_t *node_ptr)
+{
+	if (sinfo_ptr->nodes &&
+	    params.match_flags.features_flag &&
+	    (_strcmp(node_ptr->features, sinfo_ptr->features)))
+		return false;
+
+	if (params.match_flags.state_flag &&
+	    (node_ptr->node_state != sinfo_ptr->node_state))
+		return false;
+
+	/* If no need to exactly match sizes, just return here 
+	 * otherwise check cpu count, memory, disk, etc. */
+	if (!params.exact_match)
+		return true;
+	if (node_ptr->cpus        != sinfo_ptr->min_cpus)
+		return false;
+	if (node_ptr->tmp_disk    != sinfo_ptr->min_disk)
+		return false;
+	if (node_ptr->real_memory != sinfo_ptr->min_mem)
+		return false;
+	if (node_ptr->weight      != sinfo_ptr->min_weight)
+		return false;
+
+	return true;
+}
+
+static bool _match_part_data(sinfo_data_t *sinfo_ptr, 
+                             partition_info_t* part_ptr)
+{
+	if (part_ptr == sinfo_ptr->part_info) /* identical partition */
+		return true;
+
+	if (params.match_flags.avail_flag &&
+	    (part_ptr->state_up != sinfo_ptr->part_info->state_up))
+		return false;
+			
+	if (params.match_flags.groups_flag &&
+	    (_strcmp(part_ptr->allow_groups, 
+	             sinfo_ptr->part_info->allow_groups)))
+		return false;
+
+	if (params.match_flags.job_size_flag &&
+	    (part_ptr->min_nodes != sinfo_ptr->part_info->min_nodes))
+		return false;
+
+	if (params.match_flags.job_size_flag &&
+	    (part_ptr->max_nodes != sinfo_ptr->part_info->max_nodes))
+		return false;
+
+	if (params.match_flags.max_time_flag &&
+	    (part_ptr->max_time != sinfo_ptr->part_info->max_time))
+		return false;
+
+	if (params.match_flags.partition_flag &&
+	    (_strcmp(part_ptr->name, sinfo_ptr->part_info->name)))
+		return false;
+
+	if (params.match_flags.root_flag &&
+	    (part_ptr->root_only != sinfo_ptr->part_info->root_only))
+		return false;
+
+	if (params.match_flags.share_flag &&
+	    (part_ptr->shared != sinfo_ptr->part_info->shared))
+		return false;
+
+	return true;
+}
+
 static void _update_sinfo(sinfo_data_t *sinfo_ptr, partition_info_t* part_ptr, 
 		node_info_t *node_ptr)
 {
+	if (sinfo_ptr->nodes_tot == 0) {	/* first node added */
+		sinfo_ptr->node_state = node_ptr->node_state;
+		sinfo_ptr->features   = node_ptr->features;
+		sinfo_ptr->min_cpus   = node_ptr->cpus;
+		sinfo_ptr->max_cpus   = node_ptr->cpus;
+		sinfo_ptr->min_disk   = node_ptr->tmp_disk;
+		sinfo_ptr->max_disk   = node_ptr->tmp_disk;
+		sinfo_ptr->min_mem    = node_ptr->real_memory;
+		sinfo_ptr->max_mem    = node_ptr->real_memory;
+		sinfo_ptr->min_weight = node_ptr->weight;
+		sinfo_ptr->max_weight = node_ptr->weight;
+	} else {
+		if (sinfo_ptr->min_cpus > node_ptr->cpus)
+			sinfo_ptr->min_cpus = node_ptr->cpus;
+		if (sinfo_ptr->max_cpus < node_ptr->cpus)
+			sinfo_ptr->max_cpus = node_ptr->cpus;
+
+		if (sinfo_ptr->min_disk > node_ptr->tmp_disk)
+			sinfo_ptr->min_disk = node_ptr->tmp_disk;
+		if (sinfo_ptr->max_disk < node_ptr->tmp_disk)
+			sinfo_ptr->max_disk = node_ptr->tmp_disk;
+
+		if (sinfo_ptr->min_mem > node_ptr->real_memory)
+			sinfo_ptr->min_mem = node_ptr->real_memory;
+		if (sinfo_ptr->max_mem < node_ptr->real_memory)
+			sinfo_ptr->max_mem = node_ptr->real_memory;
+
+		if (sinfo_ptr->min_weight> node_ptr->weight)
+			sinfo_ptr->min_weight = node_ptr->weight;
+		if (sinfo_ptr->max_weight < node_ptr->weight)
+			sinfo_ptr->max_weight = node_ptr->weight;
+	}
+
 	if (node_ptr->node_state == NODE_STATE_ALLOCATED)
 		sinfo_ptr->nodes_alloc++;
 	else if (node_ptr->node_state == NODE_STATE_IDLE)
@@ -312,26 +407,6 @@ static void _update_sinfo(sinfo_data_t *sinfo_ptr, partition_info_t* part_ptr,
 		sinfo_ptr->nodes_other++;
 	sinfo_ptr->nodes_tot++;
 
-	if (sinfo_ptr->min_cpus > node_ptr->cpus)
-		sinfo_ptr->min_cpus = node_ptr->cpus;
-	if (sinfo_ptr->max_cpus < node_ptr->cpus)
-		sinfo_ptr->max_cpus = node_ptr->cpus;
-
-	if (sinfo_ptr->min_disk > node_ptr->tmp_disk)
-		sinfo_ptr->min_disk = node_ptr->tmp_disk;
-	if (sinfo_ptr->max_disk < node_ptr->tmp_disk)
-		sinfo_ptr->max_disk = node_ptr->tmp_disk;
-
-	if (sinfo_ptr->min_mem > node_ptr->real_memory)
-		sinfo_ptr->min_mem = node_ptr->real_memory;
-	if (sinfo_ptr->max_mem < node_ptr->real_memory)
-		sinfo_ptr->max_mem = node_ptr->real_memory;
-
-	if (sinfo_ptr->min_weight> node_ptr->weight)
-		sinfo_ptr->min_weight = node_ptr->weight;
-	if (sinfo_ptr->max_weight < node_ptr->weight)
-		sinfo_ptr->max_weight = node_ptr->weight;
-
 	hostlist_push(sinfo_ptr->nodes, node_ptr->name);
 }
 
@@ -343,31 +418,36 @@ static void _create_sinfo(List sinfo_list, partition_info_t* part_ptr,
 	/* create an entry */
 	sinfo_ptr = xmalloc(sizeof(sinfo_data_t));
 
-	sinfo_ptr->node_state = node_ptr->node_state;
-	if (node_ptr->node_state == NODE_STATE_ALLOCATED)
-		sinfo_ptr->nodes_alloc++;
-	else if (node_ptr->node_state == NODE_STATE_IDLE)
-		sinfo_ptr->nodes_idle++;
-	else 
-		sinfo_ptr->nodes_other++;
-	sinfo_ptr->nodes_tot++;
+	sinfo_ptr->part_info = part_ptr;
 
-	sinfo_ptr->min_cpus = node_ptr->cpus;
-	sinfo_ptr->max_cpus = node_ptr->cpus;
+	if (node_ptr) {
+		sinfo_ptr->node_state = node_ptr->node_state;
+		if (node_ptr->node_state == NODE_STATE_ALLOCATED)
+			sinfo_ptr->nodes_alloc++;
+		else if (node_ptr->node_state == NODE_STATE_IDLE)
+			sinfo_ptr->nodes_idle++;
+		else 
+			sinfo_ptr->nodes_other++;
+		sinfo_ptr->nodes_tot++;
 
-	sinfo_ptr->min_disk = node_ptr->tmp_disk;
-	sinfo_ptr->max_disk = node_ptr->tmp_disk;
+		sinfo_ptr->min_cpus = node_ptr->cpus;
+		sinfo_ptr->max_cpus = node_ptr->cpus;
 
-	sinfo_ptr->min_mem = node_ptr->real_memory;
-	sinfo_ptr->max_mem = node_ptr->real_memory;
+		sinfo_ptr->min_disk = node_ptr->tmp_disk;
+		sinfo_ptr->max_disk = node_ptr->tmp_disk;
 
-	sinfo_ptr->min_weight = node_ptr->weight;
-	sinfo_ptr->max_weight = node_ptr->weight;
+		sinfo_ptr->min_mem = node_ptr->real_memory;
+		sinfo_ptr->max_mem = node_ptr->real_memory;
 
-	sinfo_ptr->features = node_ptr->features;
-	sinfo_ptr->part_info = part_ptr;
+		sinfo_ptr->min_weight = node_ptr->weight;
+		sinfo_ptr->max_weight = node_ptr->weight;
 
-	sinfo_ptr->nodes = hostlist_create(node_ptr->name);
+		sinfo_ptr->features = node_ptr->features;
+
+		sinfo_ptr->nodes = hostlist_create(node_ptr->name);
+	} else {
+		sinfo_ptr->nodes = hostlist_create("");
+	}
 
 	list_append(sinfo_list, sinfo_ptr);
 }
@@ -378,34 +458,19 @@ static partition_info_t *_find_part(char *part_name,
 {
 	int i;
 	for (i=0; i<partition_msg->record_count; i++) {
-		if (_strcmp(part_name, partition_msg->partition_array[i].name))
+		if (_strcmp(part_name, 
+		            partition_msg->partition_array[i].name))
 			continue;
 		return &(partition_msg->partition_array[i]);
 	}
 	return NULL;
 }
 
-static void _sort_sinfo_data(List sinfo_list)
-{
-	if (params.node_field_flag) 	/* already in node order */
-		return;
-
-	/* sort list in partition order */
-	list_sort(sinfo_list, _part_order);
-}
-static int _part_order (void *data1, void *data2)
-{
-	sinfo_data_t *sinfo_ptr1 = data1;
-	sinfo_data_t *sinfo_ptr2 = data2;
-
-	return _strcmp(sinfo_ptr1->part_info->name,
-	               sinfo_ptr2->part_info->name);
-}
-
 static void _sinfo_list_delete(void *data)
 {
 	sinfo_data_t *sinfo_ptr = data;
 
+	xfree(sinfo_ptr->features);
 	hostlist_destroy(sinfo_ptr->nodes);
 	xfree(sinfo_ptr);
 }
diff --git a/src/sinfo/sinfo.h b/src/sinfo/sinfo.h
index e0cf35751a21642d75c68b5595774249fe8dc3a9..97ba870e31bd7bda8c770fb0e9a528925e787a06 100644
--- a/src/sinfo/sinfo.h
+++ b/src/sinfo/sinfo.h
@@ -98,33 +98,33 @@ struct sinfo_match_flags {
 /* Input parameters */
 struct sinfo_parameters {
 	bool exact_match;
+	bool filtering;
 	bool long_output;
 	bool line_wrap;
 	bool no_header;
 	bool node_field_flag;
 	bool node_flag;
-	bool state_flag;
 	bool summarize;
 	struct sinfo_match_flags match_flags;
 
 	char* format;
 	char* nodes;
 	char* partition;
+	char* sort;
+	char* states;
 
 	int iterate;
 	int node_field_size;
-	enum node_states state;
 	int verbose;
 
 	List  format_list;
+	List  state_list;
 };
 
 extern struct sinfo_parameters params;
 
 int  parse_command_line( int argc, char* argv[] );
-int  parse_state( char* str, enum job_states* states );
-void print_date(void);
-int  print_sinfo_entry(sinfo_data_t *sinfo_data , List format);
-int  print_sinfo_list(List sinfo_list, List format);
+int  parse_state( char* str, uint16_t* states );
+void sort_sinfo_list( List sinfo_list );
 
 #endif
diff --git a/src/sinfo/sort.c b/src/sinfo/sort.c
new file mode 100644
index 0000000000000000000000000000000000000000..644a7fcdebf740c77baabe0dc9808744d5574941
--- /dev/null
+++ b/src/sinfo/sort.c
@@ -0,0 +1,408 @@
+/*****************************************************************************\
+ *  sort.c - sinfo sorting functions
+ *****************************************************************************
+ *  Copyright (C) 2002 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Joey Ekstrom <ekstrom1@llnl.gov>, 
+ *             Moe Jette <jette1@llnl.gov>, et. al.
+ *  UCRL-CODE-2002-040.
+ *  
+ *  This file is part of SLURM, a resource management program.
+ *  For details, see <http://www.llnl.gov/linux/slurm/>.
+ *  
+ *  SLURM is free software; you can redistribute it and/or modify it under
+ *  the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *  
+ *  SLURM 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 General Public License for more
+ *  details.
+ *  
+ *  You should have received a copy of the GNU General Public License along
+ *  with SLURM; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
+\*****************************************************************************/
+
+#include <ctype.h>
+#include "src/common/xstring.h"
+#include "src/sinfo/sinfo.h"
+#include "src/squeue/print.h"
+
+/* If you want "linux12" to sort before "linux2", then set PURE_ALPHA_SORT */
+#define PURE_ALPHA_SORT 0
+
+static bool reverse_order;
+
+static int _sort_by_avail(void *void1, void *void2);
+static int _sort_by_cpus(void *void1, void *void2);
+static int _sort_by_disk(void *void1, void *void2);
+static int _sort_by_features(void *void1, void *void2);
+static int _sort_by_groups(void *void1, void *void2);
+static int _sort_by_job_size(void *void1, void *void2);
+static int _sort_by_max_time(void *void1, void *void2);
+static int _sort_by_memory(void *void1, void *void2);
+static int _sort_by_node_list(void *void1, void *void2);
+static int _sort_by_nodes_at(void *void1, void *void2);
+static int _sort_by_nodes(void *void1, void *void2);
+static int _sort_by_partition(void *void1, void *void2);
+static int _sort_by_root(void *void1, void *void2);
+static int _sort_by_share(void *void1, void *void2);
+static int _sort_by_state(void *void1, void *void2);
+static int _sort_by_weight(void *void1, void *void2);
+
+/*****************************************************************************
+ * Global Sort Function
+ *****************************************************************************/
+void sort_sinfo_list(List sinfo_list)
+{
+	int i;
+
+	if (params.sort == NULL) {
+		if (params.node_flag)
+			params.sort = xstrdup("N");
+		else
+			params.sort = xstrdup("P,-t");
+	}
+
+	for (i=(strlen(params.sort)-1); i >= 0; i--) {
+		reverse_order = false;
+		if ((params.sort[i] == ',') || 
+		    (params.sort[i] == '+') || params.sort[i] == '-')
+			continue;
+		if ((i > 0) && (params.sort[i-1] == '-'))
+			reverse_order = true;
+		if      (params.sort[i] == 'a')
+				list_sort(sinfo_list, _sort_by_avail);
+		else if (params.sort[i] == 'A')
+				list_sort(sinfo_list, _sort_by_nodes_at);
+		else if (params.sort[i] == 'c')
+				list_sort(sinfo_list, _sort_by_cpus);
+		else if (params.sort[i] == 'd')
+				list_sort(sinfo_list, _sort_by_disk);
+		else if (params.sort[i] == 'D')
+				list_sort(sinfo_list, _sort_by_nodes);
+		else if (params.sort[i] == 'f')
+				list_sort(sinfo_list, _sort_by_features);
+		else if (params.sort[i] == 'F')
+				list_sort(sinfo_list, _sort_by_nodes_at);
+		else if (params.sort[i] == 'g')
+				list_sort(sinfo_list, _sort_by_groups);
+		else if (params.sort[i] == 'h')
+				list_sort(sinfo_list, _sort_by_share);
+		else if (params.sort[i] == 'l')
+				list_sort(sinfo_list, _sort_by_max_time);
+		else if (params.sort[i] == 'm')
+				list_sort(sinfo_list, _sort_by_memory);
+		else if (params.sort[i] == 'N')
+				list_sort(sinfo_list, _sort_by_node_list);
+		else if (params.sort[i] == 'P')
+				list_sort(sinfo_list, _sort_by_partition);
+		else if (params.sort[i] == 'r')
+				list_sort(sinfo_list, _sort_by_root);
+		else if (params.sort[i] == 's')
+				list_sort(sinfo_list, _sort_by_job_size);
+		else if (params.sort[i] == 't')
+				list_sort(sinfo_list, _sort_by_state);
+		else if (params.sort[i] == 'T')
+				list_sort(sinfo_list, _sort_by_state);
+		else if (params.sort[i] == 'w')
+				list_sort(sinfo_list, _sort_by_weight);
+	}
+}
+
+/*****************************************************************************
+ * Local Sort Functions
+ *****************************************************************************/
+static int _sort_by_avail(void *void1, void *void2)
+{
+	int diff;
+	sinfo_data_t *sinfo1 = (sinfo_data_t *) void1;
+	sinfo_data_t *sinfo2 = (sinfo_data_t *) void2;
+	int val1 = 0, val2 = 0;
+
+	if (sinfo1->part_info)
+		val1 = sinfo1->part_info->state_up;
+	if (sinfo2->part_info)
+		val2 = sinfo2->part_info->state_up;
+	diff = val1 - val2;
+
+	if (reverse_order)
+		diff = -diff;
+	return diff;
+}
+
+static int _sort_by_cpus(void *void1, void *void2)
+{
+	int diff;
+	sinfo_data_t *sinfo1 = (sinfo_data_t *) void1;
+	sinfo_data_t *sinfo2 = (sinfo_data_t *) void2;
+
+	diff = sinfo1->min_cpus - sinfo2->min_cpus;
+
+	if (reverse_order)
+		diff = -diff;
+	return diff;
+}
+
+static int _sort_by_disk(void *void1, void *void2)
+{
+	int diff;
+	sinfo_data_t *sinfo1 = (sinfo_data_t *) void1;
+	sinfo_data_t *sinfo2 = (sinfo_data_t *) void2;
+
+	diff = sinfo1->min_disk - sinfo2->min_disk;
+
+	if (reverse_order)
+		diff = -diff;
+	return diff;
+}
+
+static int _sort_by_features(void *void1, void *void2)
+{
+	int diff;
+	sinfo_data_t *sinfo1 = (sinfo_data_t *) void1;
+	sinfo_data_t *sinfo2 = (sinfo_data_t *) void2;
+	char *val1 = "", *val2 = "";
+
+	if (sinfo1->features)
+		val1 = sinfo1->features;
+	if (sinfo2->features)
+		val2 = sinfo2->features;
+	diff = strcmp(val1, val2);
+
+	if (reverse_order)
+		diff = -diff;
+	return diff;
+}
+
+static int _sort_by_groups(void *void1, void *void2)
+{
+	int diff;
+	sinfo_data_t *sinfo1 = (sinfo_data_t *) void1;
+	sinfo_data_t *sinfo2 = (sinfo_data_t *) void2;
+	char *val1 = "", *val2 = "";
+
+	if (sinfo1->part_info && sinfo1->part_info->allow_groups)
+		val1 = sinfo1->part_info->allow_groups;
+	if (sinfo2->part_info && sinfo2->part_info->allow_groups)
+		val2 = sinfo2->part_info->allow_groups;
+	diff = strcmp(val1, val2);
+
+	if (reverse_order)
+		diff = -diff;
+	return diff;
+}
+
+static int _sort_by_job_size(void *void1, void *void2)
+{
+	int diff;
+	sinfo_data_t *sinfo1 = (sinfo_data_t *) void1;
+	sinfo_data_t *sinfo2 = (sinfo_data_t *) void2;
+	uint32_t val1 = 0, val2 = 0;
+
+	if (sinfo1->part_info) {
+		val1 = sinfo1->part_info->max_nodes;
+		if (val1 != INFINITE)
+			val1 += sinfo1->part_info->min_nodes;
+	}
+	if (sinfo2->part_info) {
+		val2 = sinfo2->part_info->max_nodes;
+		if (val2 != INFINITE)
+			val2 += sinfo2->part_info->min_nodes;
+	}
+	diff = val1 - val2;
+
+	if (reverse_order)
+		diff = -diff;
+	return diff;
+}
+
+static int _sort_by_max_time(void *void1, void *void2)
+{
+	int diff;
+	sinfo_data_t *sinfo1 = (sinfo_data_t *) void1;
+	sinfo_data_t *sinfo2 = (sinfo_data_t *) void2;
+	uint32_t val1 = 0, val2 = 0;
+
+	if (sinfo1->part_info)
+		val1 = sinfo1->part_info->max_time;
+	if (sinfo2->part_info)
+		val2 = sinfo2->part_info->max_time;
+	diff = val1 - val2;
+
+	if (reverse_order)
+		diff = -diff;
+	return diff;
+}
+
+static int _sort_by_memory(void *void1, void *void2)
+{
+	int diff;
+	sinfo_data_t *sinfo1 = (sinfo_data_t *) void1;
+	sinfo_data_t *sinfo2 = (sinfo_data_t *) void2;
+
+	diff = sinfo1->min_mem - sinfo2->min_mem;
+
+	if (reverse_order)
+		diff = -diff;
+	return diff;
+}
+
+static int _sort_by_node_list(void *void1, void *void2)
+{
+	int diff;
+	sinfo_data_t *sinfo1 = (sinfo_data_t *) void1;
+	sinfo_data_t *sinfo2 = (sinfo_data_t *) void2;
+	char *val1, *val2;
+#if	PURE_ALPHA_SORT == 0
+	int inx;
+#endif
+
+	hostlist_sort(sinfo1->nodes);
+	hostlist_sort(sinfo2->nodes);
+	val1 = hostlist_shift(sinfo1->nodes);
+	if (val1)
+		hostlist_push_host(sinfo1->nodes, val1);
+	else
+		val1 = "";
+	val2 = hostlist_shift(sinfo2->nodes);
+	if (val2)
+		hostlist_push_host(sinfo2->nodes, val2);
+	else
+		val2 = "";
+#if	PURE_ALPHA_SORT
+	diff = strcmp(val1, val2);
+#else
+	for (inx=0; ; inx++) {
+		if (val1[inx] == val2[inx])
+			continue;
+		if ((isdigit((int)val1[inx])) &&
+		    (isdigit((int)val2[inx]))) {
+			int num1, num2;
+			num1 = atoi(val1+inx);
+			num2 = atoi(val2+inx);
+			diff = num1 - num2;
+		} else
+			diff = strcmp(val1, val2);
+		break;
+	}
+#endif
+	if (strlen(val1))
+		free(val1);
+	if (strlen(val2))
+		free(val2);
+
+	if (reverse_order)
+		diff = -diff;
+
+	return diff;
+}
+
+static int _sort_by_nodes_at(void *void1, void *void2)
+{
+	int diff;
+	sinfo_data_t *sinfo1 = (sinfo_data_t *) void1;
+	sinfo_data_t *sinfo2 = (sinfo_data_t *) void2;
+
+	diff = sinfo1->nodes_alloc - sinfo2->nodes_alloc;
+
+	if (reverse_order)
+		diff = -diff;
+	return diff;
+}
+
+static int _sort_by_nodes(void *void1, void *void2)
+{
+	int diff;
+	sinfo_data_t *sinfo1 = (sinfo_data_t *) void1;
+	sinfo_data_t *sinfo2 = (sinfo_data_t *) void2;
+
+	diff = sinfo1->nodes_tot - sinfo2->nodes_tot;
+
+	if (reverse_order)
+		diff = -diff;
+	return diff;
+}
+
+static int _sort_by_partition(void *void1, void *void2)
+{
+	int diff;
+	sinfo_data_t *sinfo1 = (sinfo_data_t *) void1;
+	sinfo_data_t *sinfo2 = (sinfo_data_t *) void2;
+	char *val1 = "", *val2 = "";
+
+	if (sinfo1->part_info && sinfo1->part_info->name)
+		val1 = sinfo1->part_info->name;
+	if (sinfo2->part_info && sinfo2->part_info->name)
+		val2 = sinfo2->part_info->name;
+	diff = strcmp(val1, val2);
+
+	if (reverse_order)
+		diff = -diff;
+	return diff;
+}
+
+static int _sort_by_root(void *void1, void *void2)
+{
+	int diff;
+	sinfo_data_t *sinfo1 = (sinfo_data_t *) void1;
+	sinfo_data_t *sinfo2 = (sinfo_data_t *) void2;
+	int val1 = 0, val2 = 0;
+
+	if (sinfo1->part_info)
+		val1 = sinfo1->part_info->root_only;
+	if (sinfo2->part_info)
+		val2 = sinfo2->part_info->root_only;
+	diff = val1 - val2;
+
+	if (reverse_order)
+		diff = -diff;
+	return diff;
+}
+
+static int _sort_by_share(void *void1, void *void2)
+{
+	int diff;
+	sinfo_data_t *sinfo1 = (sinfo_data_t *) void1;
+	sinfo_data_t *sinfo2 = (sinfo_data_t *) void2;
+	int val1 = 0, val2 = 0;
+
+	if (sinfo1->part_info)
+		val1 = sinfo1->part_info->shared;
+	if (sinfo2->part_info)
+		val2 = sinfo2->part_info->shared;
+	diff = val1 - val2;
+
+	if (reverse_order)
+		diff = -diff;
+	return diff;
+}
+
+static int _sort_by_state(void *void1, void *void2)
+{
+	int diff;
+	sinfo_data_t *sinfo1 = (sinfo_data_t *) void1;
+	sinfo_data_t *sinfo2 = (sinfo_data_t *) void2;
+
+	diff = sinfo1->node_state - sinfo2->node_state;
+
+	if (reverse_order)
+		diff = -diff;
+
+	return diff;
+}
+
+static int _sort_by_weight(void *void1, void *void2)
+{
+	int diff;
+	sinfo_data_t *sinfo1 = (sinfo_data_t *) void1;
+	sinfo_data_t *sinfo2 = (sinfo_data_t *) void2;
+
+	diff = sinfo1->min_weight - sinfo2->min_weight;
+
+	if (reverse_order)
+		diff = -diff;
+	return diff;
+}