doveadm-print-table.c revision 6176f3618240943f3cb41cb7063ecef56b1dd7df
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch/* Copyright (c) 2010-2011 Dovecot authors, see the included COPYING file */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include "lib.h"
fc94140acba51adafedafbc8491a3223a51db7a8Stephan Bosch#include "array.h"
fc94140acba51adafedafbc8491a3223a51db7a8Stephan Bosch#include "doveadm-print-private.h"
1920ef85b63738a06914e56508049dd0afe38732Timo Sirainen
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch#include <stdio.h>
74c09aceb0118b564f8443e1276c465738d19c17Timo Sirainen#include <unistd.h>
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include <sys/ioctl.h>
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#include <termios.h>
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#define DEFAULT_COLUMNS 80
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#define MIN_COLUMNS 30
c275cef636c79e1d08b3a82462c4abdca6f8cef3Martti Rannanjärvi#define MAX_BUFFER_LINES 100
c275cef636c79e1d08b3a82462c4abdca6f8cef3Martti Rannanjärvi
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Boschstruct doveadm_print_table_header {
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch const char *key;
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch const char *title;
1d048c5050f03c24251e5af8087e640de21b2d62Timo Sirainen enum doveadm_print_header_flags flags;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch unsigned int min_length, max_length, length;
7944646fad6aa1e7c649c3d33e454c516b0220b6Timo Sirainen};
7944646fad6aa1e7c649c3d33e454c516b0220b6Timo Sirainen
7944646fad6aa1e7c649c3d33e454c516b0220b6Timo Sirainenstruct doveadm_print_table_context {
7944646fad6aa1e7c649c3d33e454c516b0220b6Timo Sirainen pool_t pool;
7944646fad6aa1e7c649c3d33e454c516b0220b6Timo Sirainen ARRAY_DEFINE(headers, struct doveadm_print_table_header);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch ARRAY_TYPE(const_string) buffered_values;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch unsigned int hdr_idx;
c275cef636c79e1d08b3a82462c4abdca6f8cef3Martti Rannanjärvi unsigned int columns;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
b99130e4cf4af4e6b103b949456222f3a2dff424Timo Sirainen unsigned int lengths_set:1;
b99130e4cf4af4e6b103b949456222f3a2dff424Timo Sirainen};
b99130e4cf4af4e6b103b949456222f3a2dff424Timo Sirainen
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Boschstatic struct doveadm_print_table_context *ctx;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Boschstatic void
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Boschdoveadm_print_table_header(const struct doveadm_print_header *hdr)
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch{
4c4c4a740bbb1b674d4b0dae009d1919f8ad96b7Stephan Bosch struct doveadm_print_table_header *thdr;
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch thdr = array_append_space(&ctx->headers);
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch thdr->key = p_strdup(ctx->pool, hdr->key);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch thdr->title = p_strdup(ctx->pool, hdr->title);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch thdr->length = thdr->max_length = thdr->min_length = strlen(hdr->title);
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch thdr->flags = hdr->flags;
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch}
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic void doveadm_calc_header_length(void)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct doveadm_print_table_header *headers;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch const char *value, *const *values;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch unsigned int i, line, len, hdr_count, value_count, line_count;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch unsigned int max_length, orig_length, diff;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch ctx->lengths_set = TRUE;
ad03049781fc14807248007d524be4daf06c3ee2Stephan Bosch
ad03049781fc14807248007d524be4daf06c3ee2Stephan Bosch headers = array_get_modifiable(&ctx->headers, &hdr_count);
ad03049781fc14807248007d524be4daf06c3ee2Stephan Bosch values = array_get(&ctx->buffered_values, &value_count);
486c7c8d9e725e0227c7723aa43b7fce724eb9eeStephan Bosch i_assert((value_count % hdr_count) == 0);
486c7c8d9e725e0227c7723aa43b7fce724eb9eeStephan Bosch line_count = value_count / hdr_count;
486c7c8d9e725e0227c7723aa43b7fce724eb9eeStephan Bosch
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch /* find min and max lengths of fields */
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch for (line = 0; line < line_count; line++) {
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch for (i = 0; i < hdr_count; i++) {
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch value = values[line*hdr_count + i];
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch len = value == NULL ? 0 : strlen(value);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (headers[i].min_length > len)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch headers[i].min_length = len;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (headers[i].max_length < len) {
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch headers[i].max_length = len;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch headers[i].length = len;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch }
9d746c6785d17e421c3f3c74cf29d059ae2ab233Stephan Bosch }
9d746c6785d17e421c3f3c74cf29d059ae2ab233Stephan Bosch
9d746c6785d17e421c3f3c74cf29d059ae2ab233Stephan Bosch /* +1 for space between fields */
9d746c6785d17e421c3f3c74cf29d059ae2ab233Stephan Bosch max_length = 0;
9d746c6785d17e421c3f3c74cf29d059ae2ab233Stephan Bosch for (i = 0; i < hdr_count; i++)
9d746c6785d17e421c3f3c74cf29d059ae2ab233Stephan Bosch max_length += headers[i].max_length + 1;
9d746c6785d17e421c3f3c74cf29d059ae2ab233Stephan Bosch max_length--;
9d746c6785d17e421c3f3c74cf29d059ae2ab233Stephan Bosch
9d746c6785d17e421c3f3c74cf29d059ae2ab233Stephan Bosch while (max_length > ctx->columns) {
9d746c6785d17e421c3f3c74cf29d059ae2ab233Stephan Bosch /* shrink something so we'll fit */
9d746c6785d17e421c3f3c74cf29d059ae2ab233Stephan Bosch orig_length = max_length;
fe2b0e3de834dd40b698bb579adc5357d5789ec9Stephan Bosch for (i = hdr_count - 1;; i--) {
fe2b0e3de834dd40b698bb579adc5357d5789ec9Stephan Bosch diff = headers[i].length - headers[i].min_length;
94d1b08c9e20d637db568a3eab3dfc2b9e96e62aStephan Bosch if (max_length - diff <= ctx->columns) {
94d1b08c9e20d637db568a3eab3dfc2b9e96e62aStephan Bosch /* we can finish with this */
fe2b0e3de834dd40b698bb579adc5357d5789ec9Stephan Bosch diff = max_length - ctx->columns;
feba5e502b2131c9a1c766b7ef9ff041dbf71d1dStephan Bosch headers[i].length -= diff;
feba5e502b2131c9a1c766b7ef9ff041dbf71d1dStephan Bosch max_length -= diff;
feba5e502b2131c9a1c766b7ef9ff041dbf71d1dStephan Bosch break;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (diff > 0) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* take a bit off from it */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch headers[i].length -= diff == 1 ? 1 : diff/2;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
a8c4e79ff50fac21b05a7368b052583d410ca15cTimo Sirainen if (i == 0)
a8c4e79ff50fac21b05a7368b052583d410ca15cTimo Sirainen break;
a8c4e79ff50fac21b05a7368b052583d410ca15cTimo Sirainen }
a8c4e79ff50fac21b05a7368b052583d410ca15cTimo Sirainen if (max_length == orig_length) {
a8c4e79ff50fac21b05a7368b052583d410ca15cTimo Sirainen /* can't shrink it any more */
a8c4e79ff50fac21b05a7368b052583d410ca15cTimo Sirainen break;
70505f4839520ac67895992621c97d2480c22e7fTimo Sirainen }
70505f4839520ac67895992621c97d2480c22e7fTimo Sirainen }
70505f4839520ac67895992621c97d2480c22e7fTimo Sirainen if (max_length < ctx->columns) {
70505f4839520ac67895992621c97d2480c22e7fTimo Sirainen for (i = 0; i < hdr_count; i++) {
a8c4e79ff50fac21b05a7368b052583d410ca15cTimo Sirainen if ((headers[i].flags & DOVEADM_PRINT_HEADER_FLAG_EXPAND) != 0) {
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch i++;
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch break;
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch }
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch }
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch headers[i-1].length += (ctx->columns - max_length) / 2;
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch }
c972eaa3565e849df71b44cf0cd45d38c5567d07Stephan Bosch}
c972eaa3565e849df71b44cf0cd45d38c5567d07Stephan Bosch
c972eaa3565e849df71b44cf0cd45d38c5567d07Stephan Boschstatic void doveadm_print_next(const char *value)
c972eaa3565e849df71b44cf0cd45d38c5567d07Stephan Bosch{
c972eaa3565e849df71b44cf0cd45d38c5567d07Stephan Bosch const struct doveadm_print_table_header *hdr;
c972eaa3565e849df71b44cf0cd45d38c5567d07Stephan Bosch
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch hdr = array_idx(&ctx->headers, ctx->hdr_idx);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if ((hdr->flags & DOVEADM_PRINT_HEADER_FLAG_RIGHT_JUSTIFY) == 0)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch printf("%-*s", (int)hdr->length, value);
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch else
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch printf("%*s", (int)hdr->length, value);
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch if (++ctx->hdr_idx == array_count(&ctx->headers)) {
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch ctx->hdr_idx = 0;
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch printf("\n");
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch } else {
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch printf(" ");
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch }
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch}
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Boschstatic void doveadm_buffer_flush(void)
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch{
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch const struct doveadm_print_table_header *headers;
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch const char *const *valuep;
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch unsigned int i, count;
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch doveadm_calc_header_length();
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch headers = array_get(&ctx->headers, &count);
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch for (i = 0; i < count; i++) {
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch if (i > 0) fprintf(stderr, " ");
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch if ((headers[i].flags &
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch DOVEADM_PRINT_HEADER_FLAG_RIGHT_JUSTIFY) == 0) {
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch fprintf(stderr, "%-*s", (int)headers[i].length,
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch headers[i].title);
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch } else {
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch fprintf(stderr, "%*s", (int)headers[i].length,
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch headers[i].title);
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch }
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch }
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch fprintf(stderr, "\n");
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch array_foreach(&ctx->buffered_values, valuep)
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch doveadm_print_next(*valuep);
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch array_clear(&ctx->buffered_values);
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch}
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Boschstatic void doveadm_print_table_print(const char *value)
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch{
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch unsigned int line_count;
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch if (!ctx->lengths_set) {
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch line_count = array_count(&ctx->buffered_values) /
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch array_count(&ctx->headers);
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch if (line_count < MAX_BUFFER_LINES) {
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch value = p_strdup(ctx->pool, value);
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch array_append(&ctx->buffered_values, &value, 1);
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch return;
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch }
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch doveadm_buffer_flush();
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch }
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch doveadm_print_next(value);
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic void
7384b4e78eaab44693c985192276e31322155e32Stephan Boschdoveadm_print_table_print_stream(const unsigned char *value ATTR_UNUSED,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch size_t size ATTR_UNUSED)
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch i_fatal("table formatter doesn't support multi-line values");
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic void doveadm_print_table_flush(void)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch{
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (!ctx->lengths_set && array_count(&ctx->headers) > 0)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch doveadm_buffer_flush();
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch}
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic void doveadm_print_table_init(void)
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch{
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch pool_t pool;
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch struct winsize ws;
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch pool = pool_alloconly_create("doveadm print table", 2048);
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch ctx = p_new(pool, struct doveadm_print_table_context, 1);
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch ctx->pool = pool;
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch p_array_init(&ctx->headers, pool, 16);
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch i_array_init(&ctx->buffered_values, 64);
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch ctx->columns = DEFAULT_COLUMNS;
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0) {
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch ctx->columns = ws.ws_col < MIN_COLUMNS ?
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch MIN_COLUMNS : ws.ws_col;
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch }
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch}
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Boschstatic void doveadm_print_table_deinit(void)
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch{
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch array_free(&ctx->buffered_values);
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch pool_unref(&ctx->pool);
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch ctx = NULL;
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch}
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Boschstruct doveadm_print_vfuncs doveadm_print_table_vfuncs = {
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch "table",
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch doveadm_print_table_init,
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch doveadm_print_table_deinit,
5a37824675033747fcae3fe3fc3c0dd7ef0ca1cdStephan Bosch doveadm_print_table_header,
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch doveadm_print_table_print,
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch doveadm_print_table_print_stream,
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch doveadm_print_table_flush
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch};
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Bosch