--- old/usr/src/lib/libofmt/common/ofmt.c	Tue Aug 13 14:44:23 2019
+++ new/usr/src/lib/libofmt/common/ofmt.c	Tue Aug 13 14:44:23 2019
@@ -25,6 +25,7 @@
  */
 
 /*
+ * Copyright (c) 2015 by Delphix. All rights reserved.
  * Copyright 2017 Joyent, Inc.
  */
 
@@ -53,6 +54,8 @@
 } split_t;
 
 static void splitfree(split_t *);
+static split_t *split_str(const char *, uint_t);
+static split_t *split_fields(const ofmt_field_t *, uint_t, uint_t);
 
 /*
  * The state of the output is tracked in a ofmt_state_t structure.
@@ -61,7 +64,7 @@
  * os_nfields set to the number of requested fields.
  */
 typedef struct ofmt_state_s {
-	ofmt_field_t  	*os_fields;
+	ofmt_field_t	*os_fields;
 	uint_t		os_nfields;
 	boolean_t	os_lastfield;
 	uint_t		os_overflow;
@@ -71,6 +74,7 @@
 	int		os_nbad;
 	char		**os_badfields;
 	int		os_maxnamelen;	/* longest name (f. multiline) */
+	char		os_fs;		/* field seperator */
 } ofmt_state_t;
 /*
  * A B_TRUE return value from the callback function will print out the contents
@@ -82,12 +86,13 @@
 #define	OFMT_VAL_UNDEF		"--"
 #define	OFMT_VAL_UNKNOWN	"?"
 
+#define	OFMT_DEFAULT_FS		':'
+
 /*
  * The maximum number of rows supported by the OFMT_WRAP option.
  */
 #define	OFMT_MAX_ROWS		128
 
-static void ofmt_print_header(ofmt_state_t *);
 static void ofmt_print_field(ofmt_state_t *, ofmt_field_t *, const char *,
     boolean_t);
 
@@ -127,30 +132,26 @@
 }
 
 /*
- * Split a template into its maximum number of fields (capped by the maxcols
- * if it's non-zero).  Return a pointer to a split_t containing the split
- * fields, or NULL on failure.  Invoked when all fields are implicitly
- * selected at handle creation.
+ * Split `fields' into at most `maxfields' fields. Return a pointer to
+ * a split_t containing the split fields, or NULL on failure. Invoked
+ * when all fields are implicitly selected at handle creation by
+ * passing in a NULL fields_str
  */
 static split_t *
-split_max(const ofmt_field_t *template, uint_t maxcols)
+split_fields(const ofmt_field_t *template, uint_t maxfields, uint_t maxcols)
 {
-	const ofmt_field_t *ofp;
 	split_t	*sp;
-	int i, cols, nfields = 0;
+	int i, cols;
 
 	sp = calloc(sizeof (split_t), 1);
 	if (sp == NULL)
 		return (NULL);
 
-	for (ofp = template; ofp->of_name != NULL; ofp++)
-		nfields++;
-
-	sp->s_fields = malloc(sizeof (char *) * nfields);
+	sp->s_fields = malloc(sizeof (char *) * maxfields);
 	if (sp->s_fields == NULL)
 		goto fail;
 	cols = 0;
-	for (i = 0; i < nfields; i++) {
+	for (i = 0; i < maxfields; i++) {
 		cols += template[i].of_width;
 		/*
 		 * If all fields are implied without explicitly passing
@@ -188,10 +189,11 @@
     uint_t maxcols, ofmt_handle_t *ofmt)
 {
 	split_t		*sp;
-	uint_t		i, of_index;
+	uint_t		i, j, of_index;
 	const ofmt_field_t *ofp;
 	ofmt_field_t	*of;
 	ofmt_state_t	*os = NULL;
+	uint_t		nfields = 0;
 	ofmt_status_t	error = OFMT_SUCCESS;
 	boolean_t	parsable = (flags & OFMT_PARSABLE);
 	boolean_t	wrap = (flags & OFMT_WRAP);
@@ -215,29 +217,18 @@
 	}
 	if (template == NULL)
 		return (OFMT_ENOTEMPLATE);
-
+	for (ofp = template; ofp->of_name != NULL; ofp++)
+		nfields++;
 	/*
 	 * split str into the columns selected, or construct the
 	 * full set of columns (equivalent to -o all).
 	 */
 	if (str != NULL && strcasecmp(str, "all") != 0) {
-		const char *c;
-		int nfields = 1;
-
-		/*
-		 * Get an upper bound on the number of fields by counting
-		 * the commas.
-		 */
-		for (c = str; *c != '\0'; c++) {
-			if (*c == ',')
-				nfields++;
-		}
-
 		sp = split_str(str, nfields);
 	} else {
 		if (parsable || (str != NULL && strcasecmp(str, "all") == 0))
 			maxcols = 0;
-		sp = split_max(template, maxcols);
+		sp = split_fields(template, nfields, maxcols);
 	}
 	if (sp == NULL)
 		goto nomem;
@@ -249,6 +240,7 @@
 	*ofmt = os;
 	os->os_fields = (ofmt_field_t *)&os[1];
 	os->os_flags = flags;
+	os->os_fs = OFMT_DEFAULT_FS;
 
 	of = os->os_fields;
 	of_index = 0;
@@ -257,12 +249,13 @@
 	 * nfields is the number of fields in template.
 	 */
 	for (i = 0; i < sp->s_nfields; i++) {
-		for (ofp = template; ofp->of_name != NULL; ofp++) {
-			if (strcasecmp(sp->s_fields[i], ofp->of_name) == 0)
+		for (j = 0; j < nfields; j++) {
+			if (strcasecmp(sp->s_fields[i],
+			    template[j].of_name) == 0) {
 				break;
+			}
 		}
-
-		if (ofp->of_name == NULL) {
+		if (j == nfields) {
 			int nbad = os->os_nbad++;
 
 			error = OFMT_EBADFIELDS;
@@ -277,7 +270,7 @@
 				goto nomem;
 			continue;
 		}
-		of[of_index].of_name = strdup(ofp->of_name);
+		of[of_index].of_name = strdup(template[j].of_name);
 		if (of[of_index].of_name == NULL)
 			goto nomem;
 		if (multiline) {
@@ -285,9 +278,9 @@
 
 			os->os_maxnamelen = MAX(n, os->os_maxnamelen);
 		}
-		of[of_index].of_width = ofp->of_width;
-		of[of_index].of_id = ofp->of_id;
-		of[of_index].of_cb = ofp->of_cb;
+		of[of_index].of_width = template[j].of_width;
+		of[of_index].of_id = template[j].of_id;
+		of[of_index].of_cb = template[j].of_cb;
 		of_index++;
 	}
 	splitfree(sp);
@@ -305,6 +298,12 @@
 	return (error);
 }
 
+void
+ofmt_set_fs(ofmt_handle_t ofmt, char fs)
+{
+	((ofmt_state_t *)ofmt)->os_fs = fs;
+}
+
 /*
  * free resources associated with the ofmt_handle_t
  */
@@ -341,8 +340,8 @@
 	char	c;
 
 	/*
-	 * Parsable fields are separated by ':'. If such a field contains
-	 * a ':' or '\', this character is prefixed by a '\'.
+	 * Parsable fields are separated by os_fs. os_fs and '\' are escaped
+	 * (prefixed by a) '\'.
 	 */
 	if (parsable) {
 		if (os->os_nfields == 1) {
@@ -350,12 +349,12 @@
 			return;
 		}
 		while ((c = *value++) != '\0') {
-			if (escsep && ((c == ':' || c == '\\')))
+			if (escsep && ((c == os->os_fs || c == '\\')))
 				(void) putchar('\\');
 			(void) putchar(c);
 		}
 		if (!os->os_lastfield)
-			(void) putchar(':');
+			(void) putchar(os->os_fs);
 	} else if (multiline) {
 		if (value[0] == '\0')
 			value = OFMT_VAL_UNDEF;
@@ -455,7 +454,8 @@
 
 	if ((os->os_nrow++ % os->os_winsize.ws_row) == 0 &&
 	    !parsable && !multiline) {
-		ofmt_print_header(os);
+		if (!(os->os_flags & OFMT_NOHEADER))
+			ofmt_print_header(os);
 		os->os_nrow++;
 	}
 
@@ -521,9 +521,10 @@
 /*
  * Print the field headers
  */
-static void
-ofmt_print_header(ofmt_state_t *os)
+void
+ofmt_print_header(ofmt_handle_t ofmt)
 {
+	ofmt_state_t *os = ofmt;
 	int i;
 	ofmt_field_t *of = os->os_fields;
 	boolean_t escsep = (os->os_nfields > 1);
@@ -647,7 +648,7 @@
 
 	/*
 	 * All errors are considered fatal in parsable mode.  OFMT_ENOMEM and
-	 * OFMT_ENOFIELDS errors are always fatal, regardless of mode.  For
+	 * OFMT_ENOFIELDS errors are always fatal, regardless of mode. For
 	 * other errors, we print diagnostics in human-readable mode and
 	 * processs what we can.
 	 */
