diff options
Diffstat (limited to 'src/doveadm/doveadm-print.c')
-rw-r--r-- | src/doveadm/doveadm-print.c | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/src/doveadm/doveadm-print.c b/src/doveadm/doveadm-print.c new file mode 100644 index 0000000..c1c5fac --- /dev/null +++ b/src/doveadm/doveadm-print.c @@ -0,0 +1,211 @@ +/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "istream.h" +#include "ostream.h" +#include "doveadm-print-private.h" + +struct doveadm_print_header_context { + const char *key; + char *sticky_value; + bool sticky; +}; + +struct doveadm_print_context { + pool_t pool; + ARRAY(struct doveadm_print_header_context) headers; + const struct doveadm_print_vfuncs *v; + + unsigned int header_idx; + bool print_stream_open; +}; + +bool doveadm_print_hide_titles = FALSE; +struct ostream *doveadm_print_ostream = NULL; + +static struct doveadm_print_context *ctx; + +bool doveadm_print_is_initialized(void) +{ + return ctx != NULL; +} + +void doveadm_print_header(const char *key, const char *title, + enum doveadm_print_header_flags flags) +{ + struct doveadm_print_header hdr; + struct doveadm_print_header_context *hdr_ctx; + + i_assert(title != NULL); + + i_zero(&hdr); + hdr.key = key; + hdr.title = title; + hdr.flags = flags; + ctx->v->header(&hdr); + + hdr_ctx = array_append_space(&ctx->headers); + hdr_ctx->key = p_strdup(ctx->pool, key); + hdr_ctx->sticky = (flags & DOVEADM_PRINT_HEADER_FLAG_STICKY) != 0; +} + +void doveadm_print_header_simple(const char *key_title) +{ + doveadm_print_header(key_title, key_title, 0); +} + +unsigned int doveadm_print_get_headers_count(void) +{ + return array_count(&ctx->headers); +} + +static void doveadm_print_sticky_headers(void) +{ + const struct doveadm_print_header_context *headers; + unsigned int count; + + headers = array_get(&ctx->headers, &count); + i_assert(count > 0); + for (;;) { + if (ctx->header_idx == count) + ctx->header_idx = 0; + else if (headers[ctx->header_idx].sticky) { + ctx->v->print(headers[ctx->header_idx].sticky_value); + ctx->header_idx++; + } else { + break; + } + } +} + +void doveadm_print(const char *value) +{ + i_assert(!ctx->print_stream_open); + + doveadm_print_sticky_headers(); + ctx->v->print(value); + ctx->header_idx++; +} + +void doveadm_print_num(uintmax_t value) +{ + T_BEGIN { + doveadm_print(dec2str(value)); + } T_END; +} + +void doveadm_print_stream(const void *value, size_t size) +{ + if (!ctx->print_stream_open) { + doveadm_print_sticky_headers(); + ctx->print_stream_open = TRUE; + } + ctx->v->print_stream(value, size); + if (size == 0) { + ctx->header_idx++; + ctx->print_stream_open = FALSE; + } +} + +int doveadm_print_istream(struct istream *input) +{ + const unsigned char *data; + size_t size; + ssize_t ret; + + while ((ret = i_stream_read_more(input, &data, &size)) > 0) { + doveadm_print_stream(data, size); + i_stream_skip(input, size); + } + i_assert(ret == -1); + doveadm_print_stream("", 0); + if (input->stream_errno != 0) { + /* caller will log the error */ + return -1; + } + return 0; +} + +void doveadm_print_sticky(const char *key, const char *value) +{ + struct doveadm_print_header_context *hdr; + + if (ctx == NULL) { + /* command doesn't really print anything */ + return; + } + + array_foreach_modifiable(&ctx->headers, hdr) { + if (strcmp(hdr->key, key) == 0) { + i_free(hdr->sticky_value); + hdr->sticky_value = i_strdup(value); + return; + } + } + i_unreached(); +} + +void doveadm_print_flush(void) +{ + if (ctx != NULL && ctx->v->flush != NULL) + ctx->v->flush(); + o_stream_uncork(doveadm_print_ostream); + o_stream_cork(doveadm_print_ostream); +} + +void doveadm_print_unstick_headers(void) +{ + struct doveadm_print_header_context *hdr; + + if (ctx != NULL) { + array_foreach_modifiable(&ctx->headers, hdr) + hdr->sticky = FALSE; + } +} + +void doveadm_print_init(const char *name) +{ + pool_t pool; + unsigned int i; + + if (ctx != NULL) { + /* already forced the type */ + return; + } + + pool = pool_alloconly_create("doveadm print", 1024); + ctx = p_new(pool, struct doveadm_print_context, 1); + ctx->pool = pool; + p_array_init(&ctx->headers, pool, 16); + + for (i = 0; doveadm_print_vfuncs_all[i] != NULL; i++) { + if (strcmp(doveadm_print_vfuncs_all[i]->name, name) == 0) { + ctx->v = doveadm_print_vfuncs_all[i]; + break; + } + } + if (ctx->v == NULL) + i_fatal("Unknown print formatter: %s", name); + if (ctx->v->init != NULL) + ctx->v->init(); +} + +void doveadm_print_deinit(void) +{ + struct doveadm_print_header_context *hdr; + + if (ctx == NULL) + return; + + if (ctx->v->flush != NULL && doveadm_print_ostream != NULL) { + ctx->v->flush(); + o_stream_uncork(doveadm_print_ostream); + } + if (ctx->v->deinit != NULL) + ctx->v->deinit(); + array_foreach_modifiable(&ctx->headers, hdr) + i_free(hdr->sticky_value); + pool_unref(&ctx->pool); + ctx = NULL; +} |