Print this page
11545 Want configurable output field separator for libofmt
Portions contributed by: Cody Peter Mello <cody.mello@joyent.com>
Reviewed by: Jason King <jason.king@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
@@ -23,10 +23,11 @@
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
+ * Copyright (c) 2015 by Delphix. All rights reserved.
* Copyright 2017 Joyent, Inc.
*/
#include <errno.h>
#include <sys/types.h>
@@ -51,10 +52,12 @@
uint_t s_nfields; /* the number of fields in s_buf */
uint_t s_currfield; /* the current field being processed */
} 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.
* Each os_fields[i] entry points at an ofmt_field_t array for
* the sub-command whose contents are provided by the caller, with
@@ -69,10 +72,11 @@
int os_nrow;
uint_t os_flags;
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
* of the output buffer, except when the buffer is returned with the empty
* string "", in which case the OFMT_VAL_UNDEF will be printed.
@@ -80,16 +84,17 @@
* If the callback function returns B_FALSE, the "?" string will be emitted.
*/
#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);
/*
* Split `str' into at most `maxfields' fields, Return a pointer to a
@@ -125,34 +130,30 @@
splitfree(sp);
return (NULL);
}
/*
- * 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
* in a fields_str, build a list of field names, stopping
* when we run out of columns.
@@ -186,14 +187,15 @@
ofmt_status_t
ofmt_open(const char *str, const ofmt_field_t *template, uint_t flags,
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);
boolean_t multiline = (flags & OFMT_MULTILINE);
@@ -213,33 +215,22 @@
if (wrap)
return (OFMT_EPARSEWRAP);
}
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;
os = calloc(sizeof (ofmt_state_t) +
@@ -247,24 +238,26 @@
if (os == NULL)
goto nomem;
*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;
/*
* sp->s_nfields is the number of fields requested in fields_str.
* 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;
if (os->os_badfields == NULL) {
os->os_badfields = malloc(sp->s_nfields *
@@ -275,21 +268,21 @@
os->os_badfields[nbad] = strdup(sp->s_fields[i]);
if (os->os_badfields[nbad] == NULL)
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) {
int n = strlen(of[of_index].of_name);
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);
if (of_index == 0) /* all values in str are bogus */
return (OFMT_ENOFIELDS);
@@ -303,10 +296,16 @@
*ofmt = NULL;
splitfree(sp);
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
*/
void
ofmt_close(ofmt_handle_t ofmt)
@@ -339,25 +338,25 @@
boolean_t multiline = (os->os_flags & OFMT_MULTILINE);
boolean_t rightjust = (os->os_flags & OFMT_RIGHTJUST);
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) {
(void) printf("%s", value);
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;
(void) printf("%*.*s: %s", os->os_maxnamelen,
os->os_maxnamelen, ofp->of_name, value);
@@ -453,10 +452,11 @@
return;
}
if ((os->os_nrow++ % os->os_winsize.ws_row) == 0 &&
!parsable && !multiline) {
+ if (!(os->os_flags & OFMT_NOHEADER))
ofmt_print_header(os);
os->os_nrow++;
}
if (multiline && os->os_nrow > 1)
@@ -519,13 +519,14 @@
}
/*
* 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);
for (i = 0; i < os->os_nfields; i++) {