diff options
author | Sebastien Roy <seb@delphix.com> | 2015-05-29 13:47:23 -0400 |
---|---|---|
committer | Richard Lowe <richlowe@richlowe.net> | 2019-08-19 22:32:45 +0000 |
commit | 519cca71df494bfdf951168b57893cdbe961647f (patch) | |
tree | adc3ebe2b9dab08c63f483c57bf80074f7d27731 /usr/src | |
parent | 5b6e8d437b064342671e0a40b3146d7f98802a64 (diff) | |
download | illumos-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-vers | 4 | ||||
-rw-r--r-- | usr/src/lib/libofmt/common/ofmt.c | 91 | ||||
-rw-r--r-- | usr/src/lib/libofmt/common/ofmt.h | 17 | ||||
-rw-r--r-- | usr/src/man/man3ofmt/Makefile | 6 | ||||
-rw-r--r-- | usr/src/man/man3ofmt/ofmt.3ofmt | 29 |
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 |