Add psql '\pset format wrapped' mode to wrap output to screen width, or
file/pipe output too if \pset columns' is set. Bryce Nesbitt
This commit is contained in:
parent
eb915caf92
commit
5adf98ae24
|
@ -1,5 +1,5 @@
|
||||||
<!--
|
<!--
|
||||||
$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.202 2008/05/08 00:27:57 momjian Exp $
|
$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.203 2008/05/08 17:04:26 momjian Exp $
|
||||||
PostgreSQL documentation
|
PostgreSQL documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
@ -1514,7 +1514,8 @@ lo_import 152801
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Sets the output format to one of <literal>unaligned</literal>,
|
Sets the output format to one of <literal>unaligned</literal>,
|
||||||
<literal>aligned</literal>, <literal>html</literal>,
|
<literal>aligned</literal>, <literal>wrapped</literal>,
|
||||||
|
<literal>html</literal>,
|
||||||
<literal>latex</literal>, or <literal>troff-ms</literal>.
|
<literal>latex</literal>, or <literal>troff-ms</literal>.
|
||||||
Unique abbreviations are allowed. (That would mean one letter
|
Unique abbreviations are allowed. (That would mean one letter
|
||||||
is enough.)
|
is enough.)
|
||||||
|
@ -1526,8 +1527,21 @@ lo_import 152801
|
||||||
is intended to create output that might be intended to be read
|
is intended to create output that might be intended to be read
|
||||||
in by other programs (tab-separated, comma-separated).
|
in by other programs (tab-separated, comma-separated).
|
||||||
<quote>Aligned</quote> mode is the standard, human-readable,
|
<quote>Aligned</quote> mode is the standard, human-readable,
|
||||||
nicely formatted text output that is default. The
|
nicely formatted text output that is default.
|
||||||
<quote><acronym>HTML</acronym></quote> and
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<quote>Wrapped</quote> is like <literal>aligned</> but wraps
|
||||||
|
output to the specified width. If <literal>\pset columns</> is
|
||||||
|
zero (the default), <literal>wrapped</> mode only affects screen
|
||||||
|
output and wrapped width is controlled by the environment
|
||||||
|
variable <envar>COLUMNS</> or the detected screen width. If
|
||||||
|
<literal>\pset columns</> is set to a non-zero value, all output
|
||||||
|
is wrapped, including file and pipe output.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The <quote><acronym>HTML</acronym></quote> and
|
||||||
<quote>LaTeX</quote> modes put out tables that are intended to
|
<quote>LaTeX</quote> modes put out tables that are intended to
|
||||||
be included in documents using the respective mark-up
|
be included in documents using the respective mark-up
|
||||||
language. They are not complete documents! (This might not be
|
language. They are not complete documents! (This might not be
|
||||||
|
@ -1537,6 +1551,17 @@ lo_import 152801
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><literal>columns</literal></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Controls the target width for the <literal>wrapped</> format.
|
||||||
|
Zero (the default) causes the <literal>wrapped</> format to
|
||||||
|
affect only screen output.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><literal>border</literal></term>
|
<term><literal>border</literal></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
@ -2706,6 +2731,18 @@ $endif
|
||||||
<title>Environment</title>
|
<title>Environment</title>
|
||||||
|
|
||||||
<variablelist>
|
<variablelist>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><envar>COLUMNS</envar></term>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Used for the <literal>wrapped</> output format if
|
||||||
|
<literal>\pset columns</> is zero.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><envar>PAGER</envar></term>
|
<term><envar>PAGER</envar></term>
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
|
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.187 2008/05/02 09:27:50 petere Exp $
|
* $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.188 2008/05/08 17:04:26 momjian Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres_fe.h"
|
#include "postgres_fe.h"
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
|
@ -1502,6 +1502,9 @@ _align2string(enum printFormat in)
|
||||||
case PRINT_ALIGNED:
|
case PRINT_ALIGNED:
|
||||||
return "aligned";
|
return "aligned";
|
||||||
break;
|
break;
|
||||||
|
case PRINT_WRAPPED:
|
||||||
|
return "wrapped";
|
||||||
|
break;
|
||||||
case PRINT_HTML:
|
case PRINT_HTML:
|
||||||
return "html";
|
return "html";
|
||||||
break;
|
break;
|
||||||
|
@ -1535,6 +1538,8 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
|
||||||
popt->topt.format = PRINT_UNALIGNED;
|
popt->topt.format = PRINT_UNALIGNED;
|
||||||
else if (pg_strncasecmp("aligned", value, vallen) == 0)
|
else if (pg_strncasecmp("aligned", value, vallen) == 0)
|
||||||
popt->topt.format = PRINT_ALIGNED;
|
popt->topt.format = PRINT_ALIGNED;
|
||||||
|
else if (pg_strncasecmp("wrapped", value, vallen) == 0)
|
||||||
|
popt->topt.format = PRINT_WRAPPED;
|
||||||
else if (pg_strncasecmp("html", value, vallen) == 0)
|
else if (pg_strncasecmp("html", value, vallen) == 0)
|
||||||
popt->topt.format = PRINT_HTML;
|
popt->topt.format = PRINT_HTML;
|
||||||
else if (pg_strncasecmp("latex", value, vallen) == 0)
|
else if (pg_strncasecmp("latex", value, vallen) == 0)
|
||||||
|
@ -1543,7 +1548,7 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
|
||||||
popt->topt.format = PRINT_TROFF_MS;
|
popt->topt.format = PRINT_TROFF_MS;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
psql_error("\\pset: allowed formats are unaligned, aligned, html, latex, troff-ms\n");
|
psql_error("\\pset: allowed formats are unaligned, aligned, wrapped, html, latex, troff-ms\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1724,6 +1729,16 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* set border style/width */
|
||||||
|
else if (strcmp(param, "columns") == 0)
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
popt->topt.columns = atoi(value);
|
||||||
|
|
||||||
|
if (!quiet)
|
||||||
|
printf(_("Target width for \"wrapped\" format is %d.\n"), popt->topt.columns);
|
||||||
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
psql_error("\\pset: unknown option: %s\n", param);
|
psql_error("\\pset: unknown option: %s\n", param);
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
|
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/bin/psql/mbprint.c,v 1.30 2008/04/16 18:18:00 momjian Exp $
|
* $PostgreSQL: pgsql/src/bin/psql/mbprint.c,v 1.31 2008/05/08 17:04:26 momjian Exp $
|
||||||
*
|
*
|
||||||
* XXX this file does not really belong in psql/. Perhaps move to libpq?
|
* XXX this file does not really belong in psql/. Perhaps move to libpq?
|
||||||
* It also seems that the mbvalidate function is redundant with existing
|
* It also seems that the mbvalidate function is redundant with existing
|
||||||
|
@ -204,8 +204,8 @@ pg_wcswidth(const unsigned char *pwcs, size_t len, int encoding)
|
||||||
/*
|
/*
|
||||||
* pg_wcssize takes the given string in the given encoding and returns three
|
* pg_wcssize takes the given string in the given encoding and returns three
|
||||||
* values:
|
* values:
|
||||||
* result_width: Width in display character of longest line in string
|
* result_width: Width in display characters of the longest line in string
|
||||||
* result_height: Number of lines in display output
|
* result_height: Number of newlines in display output
|
||||||
* result_format_size: Number of bytes required to store formatted representation of string
|
* result_format_size: Number of bytes required to store formatted representation of string
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
@ -279,9 +279,14 @@ pg_wcssize(unsigned char *pwcs, size_t len, int encoding, int *result_width,
|
||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Filter out unprintable characters, companion to wcs_size.
|
||||||
|
* Break input into lines based on \n. lineptr[i].ptr == NULL
|
||||||
|
* indicates the end of the array.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
pg_wcsformat(unsigned char *pwcs, size_t len, int encoding,
|
pg_wcsformat(unsigned char *pwcs, size_t len, int encoding,
|
||||||
struct lineptr * lines, int count)
|
struct lineptr *lines, int count)
|
||||||
{
|
{
|
||||||
int w,
|
int w,
|
||||||
chlen = 0;
|
chlen = 0;
|
||||||
|
@ -307,6 +312,7 @@ pg_wcsformat(unsigned char *pwcs, size_t len, int encoding,
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
exit(1); /* Screwup */
|
exit(1); /* Screwup */
|
||||||
|
|
||||||
|
/* make next line point to remaining memory */
|
||||||
lines->ptr = ptr;
|
lines->ptr = ptr;
|
||||||
}
|
}
|
||||||
else if (*pwcs == '\r') /* Linefeed */
|
else if (*pwcs == '\r') /* Linefeed */
|
||||||
|
@ -353,12 +359,13 @@ pg_wcsformat(unsigned char *pwcs, size_t len, int encoding,
|
||||||
}
|
}
|
||||||
len -= chlen;
|
len -= chlen;
|
||||||
}
|
}
|
||||||
*ptr++ = '\0';
|
|
||||||
lines->width = linewidth;
|
lines->width = linewidth;
|
||||||
lines++;
|
*ptr++ = '\0'; /* Terminate formatted string */
|
||||||
count--;
|
|
||||||
if (count > 0)
|
if (count == 0)
|
||||||
lines->ptr = NULL;
|
exit(1); /* Screwup */
|
||||||
|
|
||||||
|
(lines+1)->ptr = NULL; /* terminate line array */
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char *
|
unsigned char *
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
|
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.97 2008/03/27 03:57:34 tgl Exp $
|
* $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.98 2008/05/08 17:04:26 momjian Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres_fe.h"
|
#include "postgres_fe.h"
|
||||||
|
|
||||||
|
@ -28,6 +28,8 @@
|
||||||
|
|
||||||
#include "mbprint.h"
|
#include "mbprint.h"
|
||||||
|
|
||||||
|
static int strlen_max_width(unsigned char *str, int *target_width, int encoding);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We define the cancel_pressed flag in this file, rather than common.c where
|
* We define the cancel_pressed flag in this file, rather than common.c where
|
||||||
* it naturally belongs, because this file is also used by non-psql programs
|
* it naturally belongs, because this file is also used by non-psql programs
|
||||||
|
@ -43,6 +45,7 @@ static char *decimal_point;
|
||||||
static char *grouping;
|
static char *grouping;
|
||||||
static char *thousands_sep;
|
static char *thousands_sep;
|
||||||
|
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
pg_local_malloc(size_t size)
|
pg_local_malloc(size_t size)
|
||||||
{
|
{
|
||||||
|
@ -396,34 +399,43 @@ _print_horizontal_line(const unsigned int col_count, const unsigned int *widths,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prety pretty boxes around cells.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
print_aligned_text(const char *title, const char *const * headers,
|
print_aligned_text(const char *title, const char *const * headers,
|
||||||
const char *const * cells, const char *const * footers,
|
const char *const * cells, const char *const * footers,
|
||||||
const char *opt_align, const printTableOpt *opt,
|
const char *opt_align, const printTableOpt *opt,
|
||||||
FILE *fout)
|
bool is_pager, FILE *fout)
|
||||||
{
|
{
|
||||||
bool opt_tuples_only = opt->tuples_only;
|
bool opt_tuples_only = opt->tuples_only;
|
||||||
bool opt_numeric_locale = opt->numericLocale;
|
bool opt_numeric_locale = opt->numericLocale;
|
||||||
unsigned short int opt_border = opt->border;
|
|
||||||
int encoding = opt->encoding;
|
int encoding = opt->encoding;
|
||||||
unsigned int col_count = 0;
|
unsigned short int opt_border = opt->border;
|
||||||
unsigned int cell_count = 0;
|
|
||||||
unsigned int i;
|
unsigned int col_count = 0, cell_count = 0;
|
||||||
int tmp;
|
|
||||||
unsigned int *widths,
|
unsigned int i,
|
||||||
total_w;
|
j;
|
||||||
unsigned int *heights;
|
|
||||||
unsigned int *format_space;
|
unsigned int *width_header,
|
||||||
|
*max_width,
|
||||||
|
*width_wrap,
|
||||||
|
*width_average;
|
||||||
|
unsigned int *max_nl_lines, /* value split by newlines */
|
||||||
|
*curr_nl_line,
|
||||||
|
*max_bytes;
|
||||||
unsigned char **format_buf;
|
unsigned char **format_buf;
|
||||||
|
unsigned int width_total;
|
||||||
|
unsigned int total_header_width;
|
||||||
|
|
||||||
const char *const * ptr;
|
const char * const *ptr;
|
||||||
|
|
||||||
struct lineptr **col_lineptrs; /* pointers to line pointer for each
|
struct lineptr **col_lineptrs; /* pointers to line pointer per column */
|
||||||
* column */
|
|
||||||
struct lineptr *lineptr_list; /* complete list of linepointers */
|
|
||||||
|
|
||||||
int *complete; /* Array remembering which columns have
|
bool *header_done; /* Have all header lines been output? */
|
||||||
* completed output */
|
int *bytes_output; /* Bytes output for column value */
|
||||||
|
int output_columns = 0; /* Width of interactive console */
|
||||||
|
|
||||||
if (cancel_pressed)
|
if (cancel_pressed)
|
||||||
return;
|
return;
|
||||||
|
@ -437,275 +449,404 @@ print_aligned_text(const char *title, const char *const * headers,
|
||||||
|
|
||||||
if (col_count > 0)
|
if (col_count > 0)
|
||||||
{
|
{
|
||||||
widths = pg_local_calloc(col_count, sizeof(*widths));
|
width_header = pg_local_calloc(col_count, sizeof(*width_header));
|
||||||
heights = pg_local_calloc(col_count, sizeof(*heights));
|
width_average = pg_local_calloc(col_count, sizeof(*width_average));
|
||||||
|
max_width = pg_local_calloc(col_count, sizeof(*max_width));
|
||||||
|
width_wrap = pg_local_calloc(col_count, sizeof(*width_wrap));
|
||||||
|
max_nl_lines = pg_local_calloc(col_count, sizeof(*max_nl_lines));
|
||||||
|
curr_nl_line = pg_local_calloc(col_count, sizeof(*curr_nl_line));
|
||||||
col_lineptrs = pg_local_calloc(col_count, sizeof(*col_lineptrs));
|
col_lineptrs = pg_local_calloc(col_count, sizeof(*col_lineptrs));
|
||||||
format_space = pg_local_calloc(col_count, sizeof(*format_space));
|
max_bytes = pg_local_calloc(col_count, sizeof(*max_bytes));
|
||||||
format_buf = pg_local_calloc(col_count, sizeof(*format_buf));
|
format_buf = pg_local_calloc(col_count, sizeof(*format_buf));
|
||||||
complete = pg_local_calloc(col_count, sizeof(*complete));
|
header_done = pg_local_calloc(col_count, sizeof(*header_done));
|
||||||
|
bytes_output = pg_local_calloc(col_count, sizeof(*bytes_output));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
widths = NULL;
|
width_header = NULL;
|
||||||
heights = NULL;
|
width_average = NULL;
|
||||||
|
max_width = NULL;
|
||||||
|
width_wrap = NULL;
|
||||||
|
max_nl_lines = NULL;
|
||||||
|
curr_nl_line = NULL;
|
||||||
col_lineptrs = NULL;
|
col_lineptrs = NULL;
|
||||||
format_space = NULL;
|
max_bytes = NULL;
|
||||||
format_buf = NULL;
|
format_buf = NULL;
|
||||||
complete = NULL;
|
header_done = NULL;
|
||||||
|
bytes_output = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* count cells (rows * cols) */
|
/* scan all column headers, find maximum width and max max_nl_lines */
|
||||||
for (ptr = cells; *ptr; ptr++)
|
|
||||||
cell_count++;
|
|
||||||
|
|
||||||
/* calc column widths */
|
|
||||||
for (i = 0; i < col_count; i++)
|
for (i = 0; i < col_count; i++)
|
||||||
{
|
{
|
||||||
/* Get width & height */
|
int width,
|
||||||
int height,
|
nl_lines,
|
||||||
space;
|
bytes_required;
|
||||||
|
|
||||||
pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding, &tmp, &height, &space);
|
pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding, &width, &nl_lines, &bytes_required);
|
||||||
if (tmp > widths[i])
|
if (width > max_width[i])
|
||||||
widths[i] = tmp;
|
max_width[i] = width;
|
||||||
if (height > heights[i])
|
if (nl_lines > max_nl_lines[i])
|
||||||
heights[i] = height;
|
max_nl_lines[i] = nl_lines;
|
||||||
if (space > format_space[i])
|
if (bytes_required > max_bytes[i])
|
||||||
format_space[i] = space;
|
max_bytes[i] = bytes_required;
|
||||||
|
|
||||||
|
width_header[i] = width;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0, ptr = cells; *ptr; ptr++, i++)
|
/* scan all cells, find maximum width, compute cell_count */
|
||||||
|
for (i = 0, ptr = cells; *ptr; ptr++, i++, cell_count++)
|
||||||
{
|
{
|
||||||
int numeric_locale_len;
|
int width,
|
||||||
int height,
|
nl_lines,
|
||||||
space;
|
bytes_required;
|
||||||
|
|
||||||
if (opt_align[i % col_count] == 'r' && opt_numeric_locale)
|
/* Get width, ignore nl_lines */
|
||||||
numeric_locale_len = additional_numeric_locale_len(*ptr);
|
pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding, &width, &nl_lines, &bytes_required);
|
||||||
else
|
if (opt_numeric_locale && opt_align[i % col_count] == 'r')
|
||||||
numeric_locale_len = 0;
|
{
|
||||||
|
width += additional_numeric_locale_len(*ptr);
|
||||||
|
bytes_required += additional_numeric_locale_len(*ptr);
|
||||||
|
}
|
||||||
|
|
||||||
/* Get width, ignore height */
|
if (width > max_width[i % col_count])
|
||||||
pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding, &tmp, &height, &space);
|
max_width[i % col_count] = width;
|
||||||
tmp += numeric_locale_len;
|
if (nl_lines > max_nl_lines[i % col_count])
|
||||||
if (tmp > widths[i % col_count])
|
max_nl_lines[i % col_count] = nl_lines;
|
||||||
widths[i % col_count] = tmp;
|
if (bytes_required > max_bytes[i % col_count])
|
||||||
if (height > heights[i % col_count])
|
max_bytes[i % col_count] = bytes_required;
|
||||||
heights[i % col_count] = height;
|
|
||||||
if (space > format_space[i % col_count])
|
width_average[i % col_count] += width;
|
||||||
format_space[i % col_count] = space;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If we have rows, compute average */
|
||||||
|
if (col_count != 0 && cell_count != 0)
|
||||||
|
{
|
||||||
|
int rows = cell_count / col_count;
|
||||||
|
|
||||||
|
for (i = 0; i < col_count; i++)
|
||||||
|
width_average[i % col_count] /= rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* adjust the total display width based on border style */
|
||||||
if (opt_border == 0)
|
if (opt_border == 0)
|
||||||
total_w = col_count - 1;
|
width_total = col_count - 1;
|
||||||
else if (opt_border == 1)
|
else if (opt_border == 1)
|
||||||
total_w = col_count * 3 - 1;
|
width_total = col_count * 3 - 1;
|
||||||
else
|
else
|
||||||
total_w = col_count * 3 + 1;
|
width_total = col_count * 3 + 1;
|
||||||
|
total_header_width = width_total;
|
||||||
|
|
||||||
for (i = 0; i < col_count; i++)
|
for (i = 0; i < col_count; i++)
|
||||||
total_w += widths[i];
|
{
|
||||||
|
width_total += max_width[i];
|
||||||
|
total_header_width += width_header[i];
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* At this point: widths contains the max width of each column heights
|
* At this point: max_width[] contains the max width of each column,
|
||||||
* contains the max height of a cell of each column format_space contains
|
* max_nl_lines[] contains the max number of lines in each column,
|
||||||
* maximum space required to store formatted string so we prepare the
|
* max_bytes[] contains the maximum storage space for formatting
|
||||||
* formatting structures
|
* strings, width_total contains the giant width sum. Now we allocate
|
||||||
|
* some memory for line pointers.
|
||||||
*/
|
*/
|
||||||
if (col_count > 0)
|
for (i = 0; i < col_count; i++)
|
||||||
{
|
{
|
||||||
int heights_total = 0;
|
/* Add entry for ptr == NULL array termination */
|
||||||
struct lineptr *lineptr;
|
col_lineptrs[i] = pg_local_calloc(max_nl_lines[i] + 1,
|
||||||
|
sizeof(**col_lineptrs));
|
||||||
|
|
||||||
for (i = 0; i < col_count; i++)
|
format_buf[i] = pg_local_malloc(max_bytes[i] + 1);
|
||||||
heights_total += heights[i];
|
|
||||||
|
|
||||||
lineptr = lineptr_list = pg_local_calloc(heights_total, sizeof(*lineptr_list));
|
col_lineptrs[i]->ptr = format_buf[i];
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < col_count; i++)
|
/* Default word wrap to the full width, i.e. no word wrap */
|
||||||
|
for (i = 0; i < col_count; i++)
|
||||||
|
width_wrap[i] = max_width[i];
|
||||||
|
|
||||||
|
if (opt->format == PRINT_WRAPPED)
|
||||||
|
{
|
||||||
|
/* Get terminal width */
|
||||||
|
if (opt->columns > 0)
|
||||||
|
output_columns = opt->columns;
|
||||||
|
else if ((fout == stdout && isatty(fileno(stdout))) || is_pager)
|
||||||
{
|
{
|
||||||
col_lineptrs[i] = lineptr;
|
if (opt->env_columns)
|
||||||
lineptr += heights[i];
|
output_columns = opt->env_columns;
|
||||||
|
#ifdef TIOCGWINSZ
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct winsize screen_size;
|
||||||
|
|
||||||
format_buf[i] = pg_local_malloc(format_space[i]);
|
if (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) != -1)
|
||||||
|
output_columns = screen_size.ws_col;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
col_lineptrs[i]->ptr = format_buf[i];
|
/*
|
||||||
|
* Optional optimized word wrap. Shrink columns with a high max/avg ratio.
|
||||||
|
* Slighly bias against wider columns. (Increases chance a narrow column
|
||||||
|
* will fit in its cell.)
|
||||||
|
* If available columns is positive...
|
||||||
|
* and greater than the width of the unshrinkable column headers
|
||||||
|
*/
|
||||||
|
if (output_columns > 0 && output_columns >= total_header_width)
|
||||||
|
{
|
||||||
|
/* While there is still excess width... */
|
||||||
|
while (width_total > output_columns)
|
||||||
|
{
|
||||||
|
double max_ratio = 0;
|
||||||
|
int worst_col = -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find column that has the highest ratio of its maximum
|
||||||
|
* width compared to its average width. This tells us which
|
||||||
|
* column will produce the fewest wrapped values if shortened.
|
||||||
|
* width_wrap starts as equal to max_width.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < col_count; i++)
|
||||||
|
{
|
||||||
|
if (width_average[i] && width_wrap[i] > width_header[i])
|
||||||
|
{
|
||||||
|
/* Penalize wide columns by +1% of their width (0.01) */
|
||||||
|
double ratio = (double)width_wrap[i] / width_average[i] +
|
||||||
|
max_width[i] * 0.01;
|
||||||
|
|
||||||
|
if (ratio > max_ratio)
|
||||||
|
{
|
||||||
|
max_ratio = ratio;
|
||||||
|
worst_col = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Exit loop if we can't squeeze any more. */
|
||||||
|
if (worst_col == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Decrease width of target column by one. */
|
||||||
|
width_wrap[worst_col]--;
|
||||||
|
width_total--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
lineptr_list = NULL;
|
|
||||||
|
|
||||||
|
/* time to output */
|
||||||
if (opt->start_table)
|
if (opt->start_table)
|
||||||
{
|
{
|
||||||
/* print title */
|
/* print title */
|
||||||
if (title && !opt_tuples_only)
|
if (title && !opt_tuples_only)
|
||||||
{
|
{
|
||||||
/* Get width & height */
|
int width, height;
|
||||||
int height;
|
|
||||||
|
|
||||||
pg_wcssize((unsigned char *) title, strlen(title), encoding, &tmp, &height, NULL);
|
pg_wcssize((unsigned char *) title, strlen(title), encoding, &width, &height, NULL);
|
||||||
if (tmp >= total_w)
|
if (width >= width_total)
|
||||||
fprintf(fout, "%s\n", title);
|
fprintf(fout, "%s\n", title); /* Aligned */
|
||||||
else
|
else
|
||||||
fprintf(fout, "%-*s%s\n", (total_w - tmp) / 2, "", title);
|
fprintf(fout, "%-*s%s\n", (width_total - width) / 2, "", title); /* Centered */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* print headers */
|
/* print headers */
|
||||||
if (!opt_tuples_only)
|
if (!opt_tuples_only)
|
||||||
{
|
{
|
||||||
int cols_todo;
|
int more_col_wrapping;
|
||||||
int line_count;
|
int curr_nl_line;
|
||||||
|
|
||||||
if (opt_border == 2)
|
if (opt_border == 2)
|
||||||
_print_horizontal_line(col_count, widths, opt_border, fout);
|
_print_horizontal_line(col_count, width_wrap, opt_border, fout);
|
||||||
|
|
||||||
for (i = 0; i < col_count; i++)
|
for (i = 0; i < col_count; i++)
|
||||||
pg_wcsformat((unsigned char *) headers[i], strlen(headers[i]), encoding, col_lineptrs[i], heights[i]);
|
pg_wcsformat((unsigned char *) headers[i], strlen(headers[i]),
|
||||||
|
encoding, col_lineptrs[i], max_nl_lines[i]);
|
||||||
|
|
||||||
cols_todo = col_count;
|
more_col_wrapping = col_count;
|
||||||
line_count = 0;
|
curr_nl_line = 0;
|
||||||
memset(complete, 0, col_count * sizeof(int));
|
memset(header_done, false, col_count * sizeof(bool));
|
||||||
while (cols_todo)
|
while (more_col_wrapping)
|
||||||
{
|
{
|
||||||
if (opt_border == 2)
|
if (opt_border == 2)
|
||||||
fprintf(fout, "|%c", line_count ? '+' : ' ');
|
fprintf(fout, "|%c", curr_nl_line ? '+' : ' ');
|
||||||
else if (opt_border == 1)
|
else if (opt_border == 1)
|
||||||
fputc(line_count ? '+' : ' ', fout);
|
fputc(curr_nl_line ? '+' : ' ', fout);
|
||||||
|
|
||||||
for (i = 0; i < col_count; i++)
|
for (i = 0; i < col_count; i++)
|
||||||
{
|
{
|
||||||
unsigned int nbspace;
|
unsigned int nbspace;
|
||||||
|
|
||||||
struct lineptr *this_line = col_lineptrs[i] + line_count;
|
struct lineptr *this_line = col_lineptrs[i] + curr_nl_line;
|
||||||
|
|
||||||
if (!complete[i])
|
if (!header_done[i])
|
||||||
{
|
{
|
||||||
nbspace = widths[i] - this_line->width;
|
nbspace = width_wrap[i] - this_line->width;
|
||||||
|
|
||||||
/* centered */
|
/* centered */
|
||||||
fprintf(fout, "%-*s%s%-*s",
|
fprintf(fout, "%-*s%s%-*s",
|
||||||
nbspace / 2, "", this_line->ptr, (nbspace + 1) / 2, "");
|
nbspace / 2, "", this_line->ptr, (nbspace + 1) / 2, "");
|
||||||
|
|
||||||
if (line_count == (heights[i] - 1) || !(this_line + 1)->ptr)
|
if (!(this_line + 1)->ptr)
|
||||||
{
|
{
|
||||||
cols_todo--;
|
more_col_wrapping--;
|
||||||
complete[i] = 1;
|
header_done[i] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
fprintf(fout, "%*s", widths[i], "");
|
fprintf(fout, "%*s", width_wrap[i], "");
|
||||||
if (i < col_count - 1)
|
if (i < col_count - 1)
|
||||||
{
|
{
|
||||||
if (opt_border == 0)
|
if (opt_border == 0)
|
||||||
fputc(line_count ? '+' : ' ', fout);
|
fputc(curr_nl_line ? '+' : ' ', fout);
|
||||||
else
|
else
|
||||||
fprintf(fout, " |%c", line_count ? '+' : ' ');
|
fprintf(fout, " |%c", curr_nl_line ? '+' : ' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
line_count++;
|
curr_nl_line++;
|
||||||
|
|
||||||
if (opt_border == 2)
|
if (opt_border == 2)
|
||||||
fputs(" |", fout);
|
fputs(" |", fout);
|
||||||
else if (opt_border == 1)
|
else if (opt_border == 1)
|
||||||
fputc(' ', fout);;
|
fputc(' ', fout);
|
||||||
fputc('\n', fout);
|
fputc('\n', fout);
|
||||||
}
|
}
|
||||||
|
|
||||||
_print_horizontal_line(col_count, widths, opt_border, fout);
|
_print_horizontal_line(col_count, width_wrap, opt_border, fout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* print cells */
|
/* print cells, one loop per row */
|
||||||
for (i = 0, ptr = cells; *ptr; i += col_count, ptr += col_count)
|
for (i = 0, ptr = cells; *ptr; i += col_count, ptr += col_count)
|
||||||
{
|
{
|
||||||
int j;
|
bool more_lines;
|
||||||
int cols_todo = col_count;
|
|
||||||
int line_count; /* Number of lines output so far in row */
|
|
||||||
|
|
||||||
if (cancel_pressed)
|
if (cancel_pressed)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Format each cell. Format again, it is a numeric formatting locale
|
||||||
|
* (e.g. 123,456 vs. 123456)
|
||||||
|
*/
|
||||||
for (j = 0; j < col_count; j++)
|
for (j = 0; j < col_count; j++)
|
||||||
pg_wcsformat((unsigned char *) ptr[j], strlen(ptr[j]), encoding, col_lineptrs[j], heights[j]);
|
|
||||||
|
|
||||||
line_count = 0;
|
|
||||||
memset(complete, 0, col_count * sizeof(int));
|
|
||||||
while (cols_todo)
|
|
||||||
{
|
{
|
||||||
/* beginning of line */
|
pg_wcsformat((unsigned char *) ptr[j], strlen(ptr[j]), encoding, col_lineptrs[j], max_nl_lines[j]);
|
||||||
|
curr_nl_line[j] = 0;
|
||||||
|
|
||||||
|
if (opt_numeric_locale && opt_align[j % col_count] == 'r')
|
||||||
|
{
|
||||||
|
char *my_cell;
|
||||||
|
|
||||||
|
my_cell = format_numeric_locale((char *) col_lineptrs[j]->ptr);
|
||||||
|
strcpy((char *) col_lineptrs[j]->ptr, my_cell); /* Buffer IS large
|
||||||
|
* enough... now */
|
||||||
|
free(my_cell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(bytes_output, 0, col_count * sizeof(int));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Each time through this loop, one display line is output.
|
||||||
|
* It can either be a full value or a partial value if embedded
|
||||||
|
* newlines exist or if 'format=wrapping' mode is enabled.
|
||||||
|
*/
|
||||||
|
do
|
||||||
|
{
|
||||||
|
more_lines = false;
|
||||||
|
|
||||||
|
/* left border */
|
||||||
if (opt_border == 2)
|
if (opt_border == 2)
|
||||||
fputs("| ", fout);
|
fputs("| ", fout);
|
||||||
else if (opt_border == 1)
|
else if (opt_border == 1)
|
||||||
fputc(' ', fout);
|
fputc(' ', fout);
|
||||||
|
|
||||||
|
/* for each column */
|
||||||
for (j = 0; j < col_count; j++)
|
for (j = 0; j < col_count; j++)
|
||||||
{
|
{
|
||||||
struct lineptr *this_line = col_lineptrs[j] + line_count;
|
/* We have a valid array element, so index it */
|
||||||
bool finalspaces = (opt_border == 2 || j != col_count - 1);
|
struct lineptr *this_line = &col_lineptrs[j][curr_nl_line[j]];
|
||||||
|
int bytes_to_output, chars_to_output = width_wrap[j];
|
||||||
|
|
||||||
if (complete[j]) /* Just print spaces... */
|
/* Past newline lines so pad for other columns */
|
||||||
{
|
if (!this_line->ptr)
|
||||||
if (finalspaces)
|
fprintf(fout, "%*s", width_wrap[j], "");
|
||||||
fprintf(fout, "%*s", widths[j], "");
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* content */
|
/* Get strlen() of the width_wrap character */
|
||||||
if (opt_align[j] == 'r')
|
bytes_to_output = strlen_max_width(this_line->ptr +
|
||||||
{
|
bytes_output[j], &chars_to_output, encoding);
|
||||||
if (opt_numeric_locale)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Assumption: This code used only on strings
|
|
||||||
* without multibyte characters, otherwise
|
|
||||||
* this_line->width < strlen(this_ptr) and we get
|
|
||||||
* an overflow
|
|
||||||
*/
|
|
||||||
char *my_cell = format_numeric_locale((char *) this_line->ptr);
|
|
||||||
|
|
||||||
fprintf(fout, "%*s%s",
|
/*
|
||||||
(int) (widths[i % col_count] - strlen(my_cell)), "",
|
* If we exceeded width_wrap, it means the display width
|
||||||
my_cell);
|
* of a single character was wider than our target width.
|
||||||
free(my_cell);
|
* In that case, we have to pretend we are only printing
|
||||||
}
|
* the target display width and make the best of it.
|
||||||
else
|
*/
|
||||||
fprintf(fout, "%*s%s",
|
if (chars_to_output > width_wrap[j])
|
||||||
widths[j] - this_line->width, "",
|
chars_to_output = width_wrap[j];
|
||||||
this_line->ptr);
|
|
||||||
}
|
if (opt_align[j] == 'r') /* Right aligned cell */
|
||||||
else
|
|
||||||
fprintf(fout, "%-s%*s", this_line->ptr,
|
|
||||||
finalspaces ? (widths[j] - this_line->width) : 0, "");
|
|
||||||
/* If at the right height, done this col */
|
|
||||||
if (line_count == heights[j] - 1 || !this_line[1].ptr)
|
|
||||||
{
|
{
|
||||||
complete[j] = 1;
|
/* spaces first */
|
||||||
cols_todo--;
|
fprintf(fout, "%*s", width_wrap[j] - chars_to_output, "");
|
||||||
|
fprintf(fout, "%.*s", bytes_to_output,
|
||||||
|
this_line->ptr + bytes_output[j]);
|
||||||
|
}
|
||||||
|
else /* Left aligned cell */
|
||||||
|
{
|
||||||
|
/* spaces second */
|
||||||
|
fprintf(fout, "%.*s", bytes_to_output,
|
||||||
|
this_line->ptr + bytes_output[j]);
|
||||||
|
fprintf(fout, "%*s", width_wrap[j] - chars_to_output, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes_output[j] += bytes_to_output;
|
||||||
|
|
||||||
|
/* Do we have more text to wrap? */
|
||||||
|
if (*(this_line->ptr + bytes_output[j]) != 0)
|
||||||
|
more_lines = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Advance to next newline line */
|
||||||
|
curr_nl_line[j]++;
|
||||||
|
if (col_lineptrs[j][curr_nl_line[j]].ptr != NULL)
|
||||||
|
more_lines = true;
|
||||||
|
bytes_output[j] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* divider */
|
/* print a divider, middle columns only */
|
||||||
if ((j + 1) % col_count)
|
if ((j + 1) % col_count)
|
||||||
{
|
{
|
||||||
if (opt_border == 0)
|
if (opt_border == 0)
|
||||||
fputc(' ', fout);
|
fputc(' ', fout);
|
||||||
else if (line_count == 0)
|
/* Next value is beyond past newlines? */
|
||||||
fputs(" | ", fout);
|
else if (col_lineptrs[j+1][curr_nl_line[j+1]].ptr == NULL)
|
||||||
|
fputs(" ", fout);
|
||||||
|
/* In wrapping of value? */
|
||||||
|
else if (bytes_output[j+1] != 0)
|
||||||
|
fputs(" ; ", fout);
|
||||||
|
/* After first newline value */
|
||||||
|
else if (curr_nl_line[j+1] != 0)
|
||||||
|
fputs(" : ", fout);
|
||||||
else
|
else
|
||||||
fprintf(fout, " %c ", complete[j + 1] ? ' ' : ':');
|
/* Ordinary line */
|
||||||
|
fputs(" | ", fout);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* end of row border */
|
||||||
if (opt_border == 2)
|
if (opt_border == 2)
|
||||||
fputs(" |", fout);
|
fputs(" |", fout);
|
||||||
fputc('\n', fout);
|
fputc('\n', fout);
|
||||||
line_count++;
|
|
||||||
}
|
} while (more_lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt->stop_table)
|
if (opt->stop_table)
|
||||||
{
|
{
|
||||||
if (opt_border == 2 && !cancel_pressed)
|
if (opt_border == 2 && !cancel_pressed)
|
||||||
_print_horizontal_line(col_count, widths, opt_border, fout);
|
_print_horizontal_line(col_count, width_wrap, opt_border, fout);
|
||||||
|
|
||||||
/* print footers */
|
/* print footers */
|
||||||
if (footers && !opt_tuples_only && !cancel_pressed)
|
if (footers && !opt_tuples_only && !cancel_pressed)
|
||||||
|
@ -722,12 +863,16 @@ print_aligned_text(const char *title, const char *const * headers,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clean up */
|
/* clean up */
|
||||||
free(widths);
|
free(width_header);
|
||||||
free(heights);
|
free(width_average);
|
||||||
|
free(max_width);
|
||||||
|
free(width_wrap);
|
||||||
|
free(max_nl_lines);
|
||||||
|
free(curr_nl_line);
|
||||||
free(col_lineptrs);
|
free(col_lineptrs);
|
||||||
free(format_space);
|
free(max_bytes);
|
||||||
free(complete);
|
free(header_done);
|
||||||
free(lineptr_list);
|
free(bytes_output);
|
||||||
for (i = 0; i < col_count; i++)
|
for (i = 0; i < col_count; i++)
|
||||||
free(format_buf[i]);
|
free(format_buf[i]);
|
||||||
free(format_buf);
|
free(format_buf);
|
||||||
|
@ -754,7 +899,6 @@ print_aligned_vertical(const char *title, const char *const * headers,
|
||||||
dheight = 1,
|
dheight = 1,
|
||||||
hformatsize = 0,
|
hformatsize = 0,
|
||||||
dformatsize = 0;
|
dformatsize = 0;
|
||||||
int tmp = 0;
|
|
||||||
char *divider;
|
char *divider;
|
||||||
unsigned int cell_count = 0;
|
unsigned int cell_count = 0;
|
||||||
struct lineptr *hlineptr,
|
struct lineptr *hlineptr,
|
||||||
|
@ -779,12 +923,13 @@ print_aligned_vertical(const char *title, const char *const * headers,
|
||||||
/* Find the maximum dimensions for the headers */
|
/* Find the maximum dimensions for the headers */
|
||||||
for (i = 0; i < col_count; i++)
|
for (i = 0; i < col_count; i++)
|
||||||
{
|
{
|
||||||
int height,
|
int width,
|
||||||
|
height,
|
||||||
fs;
|
fs;
|
||||||
|
|
||||||
pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding, &tmp, &height, &fs);
|
pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding, &width, &height, &fs);
|
||||||
if (tmp > hwidth)
|
if (width > hwidth)
|
||||||
hwidth = tmp;
|
hwidth = width;
|
||||||
if (height > hheight)
|
if (height > hheight)
|
||||||
hheight = height;
|
hheight = height;
|
||||||
if (fs > hformatsize)
|
if (fs > hformatsize)
|
||||||
|
@ -799,7 +944,8 @@ print_aligned_vertical(const char *title, const char *const * headers,
|
||||||
for (i = 0, ptr = cells; *ptr; ptr++, i++)
|
for (i = 0, ptr = cells; *ptr; ptr++, i++)
|
||||||
{
|
{
|
||||||
int numeric_locale_len;
|
int numeric_locale_len;
|
||||||
int height,
|
int width,
|
||||||
|
height,
|
||||||
fs;
|
fs;
|
||||||
|
|
||||||
if (opt_align[i % col_count] == 'r' && opt_numeric_locale)
|
if (opt_align[i % col_count] == 'r' && opt_numeric_locale)
|
||||||
|
@ -807,10 +953,10 @@ print_aligned_vertical(const char *title, const char *const * headers,
|
||||||
else
|
else
|
||||||
numeric_locale_len = 0;
|
numeric_locale_len = 0;
|
||||||
|
|
||||||
pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding, &tmp, &height, &fs);
|
pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding, &width, &height, &fs);
|
||||||
tmp += numeric_locale_len;
|
width += numeric_locale_len;
|
||||||
if (tmp > dwidth)
|
if (width > dwidth)
|
||||||
dwidth = tmp;
|
dwidth = width;
|
||||||
if (height > dheight)
|
if (height > dheight)
|
||||||
dheight = height;
|
dheight = height;
|
||||||
if (fs > dformatsize)
|
if (fs > dformatsize)
|
||||||
|
@ -821,8 +967,8 @@ print_aligned_vertical(const char *title, const char *const * headers,
|
||||||
* We now have all the information we need to setup the formatting
|
* We now have all the information we need to setup the formatting
|
||||||
* structures
|
* structures
|
||||||
*/
|
*/
|
||||||
dlineptr = pg_local_malloc(sizeof(*dlineptr) * dheight);
|
dlineptr = pg_local_malloc((sizeof(*dlineptr) + 1) * dheight);
|
||||||
hlineptr = pg_local_malloc(sizeof(*hlineptr) * hheight);
|
hlineptr = pg_local_malloc((sizeof(*hlineptr) + 1) * hheight);
|
||||||
|
|
||||||
dlineptr->ptr = pg_local_malloc(dformatsize);
|
dlineptr->ptr = pg_local_malloc(dformatsize);
|
||||||
hlineptr->ptr = pg_local_malloc(hformatsize);
|
hlineptr->ptr = pg_local_malloc(hformatsize);
|
||||||
|
@ -910,7 +1056,7 @@ print_aligned_vertical(const char *title, const char *const * headers,
|
||||||
fprintf(fout, "%-s%*s", hlineptr[line_count].ptr,
|
fprintf(fout, "%-s%*s", hlineptr[line_count].ptr,
|
||||||
hwidth - hlineptr[line_count].width, "");
|
hwidth - hlineptr[line_count].width, "");
|
||||||
|
|
||||||
if (line_count == (hheight - 1) || !hlineptr[line_count + 1].ptr)
|
if (!hlineptr[line_count + 1].ptr)
|
||||||
hcomplete = 1;
|
hcomplete = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -943,7 +1089,7 @@ print_aligned_vertical(const char *title, const char *const * headers,
|
||||||
dwidth - dlineptr[line_count].width, "");
|
dwidth - dlineptr[line_count].width, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (line_count == dheight - 1 || !dlineptr[line_count + 1].ptr)
|
if (!dlineptr[line_count + 1].ptr)
|
||||||
dcomplete = 1;
|
dcomplete = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1823,6 +1969,7 @@ printTable(const char *title,
|
||||||
{
|
{
|
||||||
static const char *default_footer[] = {NULL};
|
static const char *default_footer[] = {NULL};
|
||||||
FILE *output;
|
FILE *output;
|
||||||
|
bool is_pager = false;
|
||||||
|
|
||||||
if (cancel_pressed)
|
if (cancel_pressed)
|
||||||
return;
|
return;
|
||||||
|
@ -1858,6 +2005,7 @@ printTable(const char *title,
|
||||||
for (ptr = footers; *ptr; ptr++)
|
for (ptr = footers; *ptr; ptr++)
|
||||||
lines++;
|
lines++;
|
||||||
output = PageOutput(lines, opt->pager);
|
output = PageOutput(lines, opt->pager);
|
||||||
|
is_pager = (output != fout);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
output = fout;
|
output = fout;
|
||||||
|
@ -1866,7 +2014,7 @@ printTable(const char *title,
|
||||||
|
|
||||||
if (flog)
|
if (flog)
|
||||||
print_aligned_text(title, headers, cells, footers, align,
|
print_aligned_text(title, headers, cells, footers, align,
|
||||||
opt, flog);
|
opt, is_pager, flog);
|
||||||
|
|
||||||
switch (opt->format)
|
switch (opt->format)
|
||||||
{
|
{
|
||||||
|
@ -1879,12 +2027,13 @@ printTable(const char *title,
|
||||||
opt, output);
|
opt, output);
|
||||||
break;
|
break;
|
||||||
case PRINT_ALIGNED:
|
case PRINT_ALIGNED:
|
||||||
|
case PRINT_WRAPPED:
|
||||||
if (opt->expanded)
|
if (opt->expanded)
|
||||||
print_aligned_vertical(title, headers, cells, footers, align,
|
print_aligned_vertical(title, headers, cells, footers, align,
|
||||||
opt, output);
|
opt, output);
|
||||||
else
|
else
|
||||||
print_aligned_text(title, headers, cells, footers, align,
|
print_aligned_text(title, headers, cells, footers, align,
|
||||||
opt, output);
|
opt, is_pager, output);
|
||||||
break;
|
break;
|
||||||
case PRINT_HTML:
|
case PRINT_HTML:
|
||||||
if (opt->expanded)
|
if (opt->expanded)
|
||||||
|
@ -1915,8 +2064,7 @@ printTable(const char *title,
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Only close if we used the pager */
|
if (is_pager)
|
||||||
if (output != fout)
|
|
||||||
ClosePager(output);
|
ClosePager(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2066,3 +2214,38 @@ setDecimalLocale(void)
|
||||||
else
|
else
|
||||||
thousands_sep = ".";
|
thousands_sep = ".";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the byte length to the end of the specified character
|
||||||
|
* and number of display characters processed (useful if the string
|
||||||
|
* is shorter then dpylen).
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
strlen_max_width(unsigned char *str, int *target_width, int encoding)
|
||||||
|
{
|
||||||
|
unsigned char *start = str;
|
||||||
|
int curr_width = 0;
|
||||||
|
|
||||||
|
while (*str && curr_width < *target_width)
|
||||||
|
{
|
||||||
|
int char_width = PQdsplen((char *) str, encoding);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the display width of the new character causes
|
||||||
|
* the string to exceed its target width, skip it
|
||||||
|
* and return. However, if this is the first character
|
||||||
|
* of the string (*width == 0), we have to accept it.
|
||||||
|
*/
|
||||||
|
if (*target_width - curr_width < char_width && curr_width != 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
str += PQmblen((char *)str, encoding);
|
||||||
|
|
||||||
|
curr_width += char_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
*target_width = curr_width;
|
||||||
|
|
||||||
|
/* last byte */
|
||||||
|
return str - start;
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
|
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/bin/psql/print.h,v 1.35 2008/01/01 19:45:56 momjian Exp $
|
* $PostgreSQL: pgsql/src/bin/psql/print.h,v 1.36 2008/05/08 17:04:26 momjian Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef PRINT_H
|
#ifndef PRINT_H
|
||||||
#define PRINT_H
|
#define PRINT_H
|
||||||
|
@ -21,6 +21,7 @@ enum printFormat
|
||||||
PRINT_NOTHING = 0, /* to make sure someone initializes this */
|
PRINT_NOTHING = 0, /* to make sure someone initializes this */
|
||||||
PRINT_UNALIGNED,
|
PRINT_UNALIGNED,
|
||||||
PRINT_ALIGNED,
|
PRINT_ALIGNED,
|
||||||
|
PRINT_WRAPPED,
|
||||||
PRINT_HTML,
|
PRINT_HTML,
|
||||||
PRINT_LATEX,
|
PRINT_LATEX,
|
||||||
PRINT_TROFF_MS
|
PRINT_TROFF_MS
|
||||||
|
@ -47,6 +48,8 @@ typedef struct _printTableOpt
|
||||||
* decimal marker */
|
* decimal marker */
|
||||||
char *tableAttr; /* attributes for HTML <table ...> */
|
char *tableAttr; /* attributes for HTML <table ...> */
|
||||||
int encoding; /* character encoding */
|
int encoding; /* character encoding */
|
||||||
|
int env_columns; /* $COLUMNS on psql start, 0 is unset */
|
||||||
|
int columns; /* target width for wrapped format */
|
||||||
} printTableOpt;
|
} printTableOpt;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
|
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.146 2008/01/01 19:45:56 momjian Exp $
|
* $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.147 2008/05/08 17:04:26 momjian Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres_fe.h"
|
#include "postgres_fe.h"
|
||||||
|
|
||||||
|
@ -147,6 +147,8 @@ main(int argc, char *argv[])
|
||||||
pset.popt.topt.start_table = true;
|
pset.popt.topt.start_table = true;
|
||||||
pset.popt.topt.stop_table = true;
|
pset.popt.topt.stop_table = true;
|
||||||
pset.popt.default_footer = true;
|
pset.popt.default_footer = true;
|
||||||
|
/* We must get COLUMNS here before readline() sets it */
|
||||||
|
pset.popt.topt.env_columns = getenv("COLUMNS") ? atoi(getenv("COLUMNS")) : 0;
|
||||||
|
|
||||||
pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout)));
|
pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout)));
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue