summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorSebastien Roy <seb@delphix.com>2015-05-29 13:47:23 -0400
committerRichard Lowe <richlowe@richlowe.net>2019-08-19 22:32:45 +0000
commit519cca71df494bfdf951168b57893cdbe961647f (patch)
treeadc3ebe2b9dab08c63f483c57bf80074f7d27731 /usr/src
parent5b6e8d437b064342671e0a40b3146d7f98802a64 (diff)
downloadillumos-joyent-519cca71df494bfdf951168b57893cdbe961647f.tar.gz
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> Reviewed by: Toomas Soome <tsoome@me.com> Approved by: Richard Lowe <richlowe@richlowe.net>
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/lib/libofmt/common/mapfile-vers4
-rw-r--r--usr/src/lib/libofmt/common/ofmt.c91
-rw-r--r--usr/src/lib/libofmt/common/ofmt.h17
-rw-r--r--usr/src/man/man3ofmt/Makefile6
-rw-r--r--usr/src/man/man3ofmt/ofmt.3ofmt29
5 files changed, 96 insertions, 51 deletions
diff --git a/usr/src/lib/libofmt/common/mapfile-vers b/usr/src/lib/libofmt/common/mapfile-vers
index fa94086eb6..81f730f06a 100644
--- a/usr/src/lib/libofmt/common/mapfile-vers
+++ b/usr/src/lib/libofmt/common/mapfile-vers
@@ -32,12 +32,14 @@ $mapfile_version 2
SYMBOL_VERSION ILLUMOSprivate {
global:
+ ofmt_check;
ofmt_close;
ofmt_open;
ofmt_print;
+ ofmt_print_header;
+ ofmt_set_fs;
ofmt_strerror;
ofmt_update_winsize;
- ofmt_check;
local:
*;
diff --git a/usr/src/lib/libofmt/common/ofmt.c b/usr/src/lib/libofmt/common/ofmt.c
index 27765b0430..0b248b2b2d 100644
--- a/usr/src/lib/libofmt/common/ofmt.c
+++ b/usr/src/lib/libofmt/common/ofmt.c
@@ -25,6 +25,7 @@
*/
/*
+ * Copyright (c) 2015 by Delphix. All rights reserved.
* Copyright 2017 Joyent, Inc.
*/
@@ -53,6 +54,8 @@ typedef struct {
} 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 @@ static void splitfree(split_t *);
* 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 @@ typedef struct ofmt_state_s {
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 @@ typedef struct ofmt_state_s {
#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 @@ fail:
}
/*
- * 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 @@ 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);
@@ -215,29 +217,18 @@ ofmt_open(const char *str, const ofmt_field_t *template, uint_t flags,
}
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_open(const char *str, const ofmt_field_t *template, uint_t flags,
*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 @@ ofmt_open(const char *str, const ofmt_field_t *template, uint_t flags,
* 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 @@ ofmt_open(const char *str, const ofmt_field_t *template, uint_t flags,
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 @@ ofmt_open(const char *str, const ofmt_field_t *template, uint_t flags,
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 @@ nomem:
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 @@ ofmt_print_field(ofmt_state_t *os, ofmt_field_t *ofp, const char *value,
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 @@ ofmt_print_field(ofmt_state_t *os, ofmt_field_t *ofp, const char *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;
@@ -455,7 +454,8 @@ ofmt_print(ofmt_handle_t ofmt, void *arg)
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 @@ ofmt_print(ofmt_handle_t ofmt, void *arg)
/*
* 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 @@ ofmt_check(ofmt_status_t oferr, boolean_t parsable, ofmt_handle_t ofmt,
/*
* 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.
*/
diff --git a/usr/src/lib/libofmt/common/ofmt.h b/usr/src/lib/libofmt/common/ofmt.h
index 6048367a84..7248556189 100644
--- a/usr/src/lib/libofmt/common/ofmt.h
+++ b/usr/src/lib/libofmt/common/ofmt.h
@@ -25,6 +25,7 @@
*/
/*
+ * Copyright (c) 2015 by Delphix. All rights reserved.
* Copyright 2017 Joyent, Inc.
*/
@@ -127,12 +128,12 @@
* caller), the function ofmt_update_winsize(handle) may be called.
*/
-#include <sys/types.h>
-
#ifdef __cplusplus
extern "C" {
#endif
+#include <sys/types.h>
+
/*
* Recommended buffer size for buffers passed, for example, to ofmt_strerror().
*/
@@ -187,6 +188,7 @@ extern ofmt_status_t ofmt_open(const char *, const ofmt_field_t *, uint_t,
#define OFMT_WRAP 0x00000002 /* wrap output if field width is exceeded */
#define OFMT_MULTILINE 0x00000004 /* "long" output: "name: value" lines */
#define OFMT_RIGHTJUST 0x00000008 /* right justified output */
+#define OFMT_NOHEADER 0x00000010 /* do not automatically print header lines */
/*
* ofmt_close() must be called to free resources associated
@@ -195,11 +197,22 @@ extern ofmt_status_t ofmt_open(const char *, const ofmt_field_t *, uint_t,
extern void ofmt_close(ofmt_handle_t);
/*
+ * Set the field separator used in parsable output (default is ':').
+ */
+extern void ofmt_set_fs(ofmt_handle_t, char);
+
+/*
* ofmt_print() emits one row of output
*/
extern void ofmt_print(ofmt_handle_t, void *);
/*
+ * ofmt_print_header() prints the header line. It can be used with
+ * OFMT_NOHEADER to control exactly when the header gets printed.
+ */
+extern void ofmt_print_header(ofmt_handle_t);
+
+/*
* ofmt_update_winsize() updates the window size information for ofmt_handle_t
*/
extern void ofmt_update_winsize(ofmt_handle_t);
diff --git a/usr/src/man/man3ofmt/Makefile b/usr/src/man/man3ofmt/Makefile
index b89d88fb35..f1d66dc4f8 100644
--- a/usr/src/man/man3ofmt/Makefile
+++ b/usr/src/man/man3ofmt/Makefile
@@ -15,7 +15,7 @@
include $(SRC)/Makefile.master
-MANSECT= 3ofmt
+MANSECT= 3ofmt
MANFILES= ofmt.3ofmt
@@ -28,6 +28,8 @@ MANLINKS= ofmt_close.3ofmt \
ofmt_close.3ofmt := LINKSRC = ofmt.3ofmt
ofmt_open.3ofmt := LINKSRC = ofmt.3ofmt
ofmt_print.3ofmt := LINKSRC = ofmt.3ofmt
+ofmt_print_header.3ofmt := LINKSRC = ofmt.3ofmt
+ofmt_set_fs.3ofmt := LINKSRC = ofmt.3ofmt
ofmt_strerror.3ofmt := LINKSRC = ofmt.3ofmt
ofmt_update_winsize.3ofmt := LINKSRC = ofmt.3ofmt
@@ -35,4 +37,4 @@ ofmt_update_winsize.3ofmt := LINKSRC = ofmt.3ofmt
include $(SRC)/man/Makefile.man
-install: $(ROOTMANFILES) $(ROOTMANLINKS)
+install: $(ROOTMANFILES) $(ROOTMANLINKS)
diff --git a/usr/src/man/man3ofmt/ofmt.3ofmt b/usr/src/man/man3ofmt/ofmt.3ofmt
index bc996dafa1..9c05dc8c21 100644
--- a/usr/src/man/man3ofmt/ofmt.3ofmt
+++ b/usr/src/man/man3ofmt/ofmt.3ofmt
@@ -13,13 +13,15 @@
.\" Copyright 2017 Nexenta Systems, Inc.
.\" Copyright 2018 Joyent, Inc.
.\"
-.Dd December 20, 2018
+.Dd February 13, 2019
.Dt OFMT 3OFMT
.Os
.Sh NAME
.Nm ofmt_open ,
.Nm ofmt_print ,
+.Nm ofmt_print_header ,
.Nm ofmt_update_winsize ,
+.Nm ofmt_set_fs ,
.Nm ofmt_strerror ,
.Nm ofmt_close
.Nd data structures and routines for printing output
@@ -41,9 +43,18 @@
.Fa "void *cbarg"
.Fc
.Ft void
+.Fo ofmt_print_header
+.Fa "ofmt_handle_t ofmt"
+.Fc
+.Ft void
.Fo ofmt_update_winsize
.Fa "ofmt_handle_t ofmt"
.Fc
+.Ft void
+.Fo ofmt_set_fs
+.Fa "ofmt_handle_t ofmt"
+.Fa "char fs"
+.Fc
.Ft "char *"
.Fo ofmt_strerror
.Fa "ofmt_handle_t ofmt"
@@ -212,6 +223,9 @@ will result in
.Dv OFMT_EPARSEMULTI .
.It Dv OFMT_RIGHTJUST
Right justified output.
+.It Dv OFMT_NOHEADER
+Skip printing the header when calling
+.Fn ofmt_print .
.El
.Pp
The non-zero
@@ -241,6 +255,15 @@ The callback function should fill
.Fa buf
with the string to be printed for the field using the data in
.Fa cbarg .
+.Ss Fn ofmt_print_header
+The
+.Fn ofmt_print_header
+function prints the output header.
+This is usually done as part of calling
+.Fn ofmt_print ,
+but is skipped when using
+.Dv OFMT_NOHEADER .
+This function allows you to insert it when and where desired.
.Ss Fn ofmt_update_winsize
The
.Fn ofmt_update_winsize
@@ -251,6 +274,10 @@ in the
If the
.Dv TIOCGWINSZ
ioctl fails, the window size is set to 80x24.
+.Ss Fn ofmt_set_fs
+The
+.Fn ofmt_set_fs
+function sets the output field separator for parsable output.
.Ss Fn ofmt_strerror
The
.Fn ofmt_strerror