Restore psql's former behavior that padding spaces to the right of the last

output column are not emitted.  (That change already caused more noise in
the regression test output files than I would like.)  Provide some needed
editorial help for comments, clean up code formatting.
This commit is contained in:
Tom Lane 2008-05-10 03:31:58 +00:00
parent 2cabe2db79
commit 125ed6853e
1 changed files with 73 additions and 55 deletions

View File

@ -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.98 2008/05/08 17:04:26 momjian Exp $ * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.99 2008/05/10 03:31:58 tgl Exp $
*/ */
#include "postgres_fe.h" #include "postgres_fe.h"
@ -28,8 +28,6 @@
#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
@ -45,6 +43,9 @@ static char *decimal_point;
static char *grouping; static char *grouping;
static char *thousands_sep; static char *thousands_sep;
/* Local functions */
static int strlen_max_width(unsigned char *str, int *target_width, int encoding);
static void * static void *
pg_local_malloc(size_t size) pg_local_malloc(size_t size)
@ -400,7 +401,7 @@ _print_horizontal_line(const unsigned int col_count, const unsigned int *widths,
/* /*
* Prety pretty boxes around cells. * Print 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,
@ -411,7 +412,7 @@ print_aligned_text(const char *title, const char *const * headers,
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;
int encoding = opt->encoding; int encoding = opt->encoding;
unsigned short int opt_border = opt->border; unsigned short opt_border = opt->border;
unsigned int col_count = 0, cell_count = 0; unsigned int col_count = 0, cell_count = 0;
@ -483,7 +484,8 @@ print_aligned_text(const char *title, const char *const * headers,
nl_lines, nl_lines,
bytes_required; bytes_required;
pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding, &width, &nl_lines, &bytes_required); pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding,
&width, &nl_lines, &bytes_required);
if (width > max_width[i]) if (width > max_width[i])
max_width[i] = width; max_width[i] = width;
if (nl_lines > max_nl_lines[i]) if (nl_lines > max_nl_lines[i])
@ -502,7 +504,8 @@ print_aligned_text(const char *title, const char *const * headers,
bytes_required; bytes_required;
/* Get width, ignore nl_lines */ /* Get width, ignore nl_lines */
pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding, &width, &nl_lines, &bytes_required); pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding,
&width, &nl_lines, &bytes_required);
if (opt_numeric_locale && opt_align[i % col_count] == 'r') if (opt_numeric_locale && opt_align[i % col_count] == 'r')
{ {
width += additional_numeric_locale_len(*ptr); width += additional_numeric_locale_len(*ptr);
@ -567,12 +570,14 @@ print_aligned_text(const char *title, const char *const * headers,
if (opt->format == PRINT_WRAPPED) if (opt->format == PRINT_WRAPPED)
{ {
/* Get terminal width */ /*
* Choose target output width: \pset columns, or $COLUMNS, or ioctl
*/
if (opt->columns > 0) if (opt->columns > 0)
output_columns = opt->columns; output_columns = opt->columns;
else if ((fout == stdout && isatty(fileno(stdout))) || is_pager) else if ((fout == stdout && isatty(fileno(stdout))) || is_pager)
{ {
if (opt->env_columns) if (opt->env_columns > 0)
output_columns = opt->env_columns; output_columns = opt->env_columns;
#ifdef TIOCGWINSZ #ifdef TIOCGWINSZ
else else
@ -586,11 +591,11 @@ print_aligned_text(const char *title, const char *const * headers,
} }
/* /*
* Optional optimized word wrap. Shrink columns with a high max/avg ratio. * Optional optimized word wrap. Shrink columns with a high max/avg
* Slighly bias against wider columns. (Increases chance a narrow column * ratio. Slighly bias against wider columns. (Increases chance a
* will fit in its cell.) * narrow column will fit in its cell.) If available columns is
* If available columns is positive... * positive... and greater than the width of the unshrinkable column
* and greater than the width of the unshrinkable column headers * headers
*/ */
if (output_columns > 0 && output_columns >= total_header_width) if (output_columns > 0 && output_columns >= total_header_width)
{ {
@ -610,10 +615,11 @@ print_aligned_text(const char *title, const char *const * headers,
{ {
if (width_average[i] && width_wrap[i] > width_header[i]) if (width_average[i] && width_wrap[i] > width_header[i])
{ {
/* Penalize wide columns by +1% of their width (0.01) */ /* Penalize wide columns by 1% of their width */
double ratio = (double)width_wrap[i] / width_average[i] + double ratio;
max_width[i] * 0.01;
ratio = (double) width_wrap[i] / width_average[i] +
max_width[i] * 0.01;
if (ratio > max_ratio) if (ratio > max_ratio)
{ {
max_ratio = ratio; max_ratio = ratio;
@ -641,7 +647,8 @@ print_aligned_text(const char *title, const char *const * headers,
{ {
int width, height; int width, height;
pg_wcssize((unsigned char *) title, strlen(title), encoding, &width, &height, NULL); pg_wcssize((unsigned char *) title, strlen(title), encoding,
&width, &height, NULL);
if (width >= width_total) if (width >= width_total)
fprintf(fout, "%s\n", title); /* Aligned */ fprintf(fout, "%s\n", title); /* Aligned */
else else
@ -723,12 +730,13 @@ print_aligned_text(const char *title, const char *const * headers,
break; break;
/* /*
* Format each cell. Format again, it is a numeric formatting locale * Format each cell. Format again, if it's a numeric formatting locale
* (e.g. 123,456 vs. 123456) * (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], max_nl_lines[j]); pg_wcsformat((unsigned char *) ptr[j], strlen(ptr[j]), encoding,
col_lineptrs[j], max_nl_lines[j]);
curr_nl_line[j] = 0; curr_nl_line[j] = 0;
if (opt_numeric_locale && opt_align[j % col_count] == 'r') if (opt_numeric_locale && opt_align[j % col_count] == 'r')
@ -736,8 +744,8 @@ print_aligned_text(const char *title, const char *const * headers,
char *my_cell; char *my_cell;
my_cell = format_numeric_locale((char *) col_lineptrs[j]->ptr); my_cell = format_numeric_locale((char *) col_lineptrs[j]->ptr);
strcpy((char *) col_lineptrs[j]->ptr, my_cell); /* Buffer IS large /* Buffer IS large enough... now */
* enough... now */ strcpy((char *) col_lineptrs[j]->ptr, my_cell);
free(my_cell); free(my_cell);
} }
} }
@ -764,16 +772,22 @@ print_aligned_text(const char *title, const char *const * headers,
{ {
/* We have a valid array element, so index it */ /* We have a valid array element, so index it */
struct lineptr *this_line = &col_lineptrs[j][curr_nl_line[j]]; struct lineptr *this_line = &col_lineptrs[j][curr_nl_line[j]];
int bytes_to_output, chars_to_output = width_wrap[j]; int bytes_to_output;
int chars_to_output = width_wrap[j];
bool finalspaces = (opt_border == 2 || j < col_count - 1);
/* Past newline lines so pad for other columns */
if (!this_line->ptr) if (!this_line->ptr)
fprintf(fout, "%*s", width_wrap[j], ""); {
/* Past newline lines so just pad for other columns */
if (finalspaces)
fprintf(fout, "%*s", chars_to_output, "");
}
else else
{ {
/* Get strlen() of the width_wrap character */ /* Get strlen() of the characters up to width_wrap */
bytes_to_output = strlen_max_width(this_line->ptr + bytes_to_output =
bytes_output[j], &chars_to_output, encoding); strlen_max_width(this_line->ptr + bytes_output[j],
&chars_to_output, encoding);
/* /*
* If we exceeded width_wrap, it means the display width * If we exceeded width_wrap, it means the display width
@ -796,13 +810,14 @@ print_aligned_text(const char *title, const char *const * headers,
/* spaces second */ /* spaces second */
fprintf(fout, "%.*s", bytes_to_output, fprintf(fout, "%.*s", bytes_to_output,
this_line->ptr + bytes_output[j]); this_line->ptr + bytes_output[j]);
if (finalspaces)
fprintf(fout, "%*s", width_wrap[j] - chars_to_output, ""); fprintf(fout, "%*s", width_wrap[j] - chars_to_output, "");
} }
bytes_output[j] += bytes_to_output; bytes_output[j] += bytes_to_output;
/* Do we have more text to wrap? */ /* Do we have more text to wrap? */
if (*(this_line->ptr + bytes_output[j]) != 0) if (*(this_line->ptr + bytes_output[j]) != '\0')
more_lines = true; more_lines = true;
else else
{ {
@ -814,8 +829,8 @@ print_aligned_text(const char *title, const char *const * headers,
} }
} }
/* print a divider, middle columns only */ /* print a divider, if not the last column */
if ((j + 1) % col_count) if (j < col_count - 1)
{ {
if (opt_border == 0) if (opt_border == 0)
fputc(' ', fout); fputc(' ', fout);
@ -832,10 +847,9 @@ print_aligned_text(const char *title, const char *const * headers,
/* Ordinary line */ /* Ordinary line */
fputs(" | ", fout); fputs(" | ", fout);
} }
} }
/* end of row border */ /* end-of-row border */
if (opt_border == 2) if (opt_border == 2)
fputs(" |", fout); fputs(" |", fout);
fputc('\n', fout); fputc('\n', fout);
@ -887,7 +901,7 @@ print_aligned_vertical(const char *title, const char *const * headers,
{ {
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; unsigned short opt_border = opt->border;
int encoding = opt->encoding; int encoding = opt->encoding;
unsigned int col_count = 0; unsigned int col_count = 0;
unsigned long record = opt->prior_records + 1; unsigned long record = opt->prior_records + 1;
@ -927,7 +941,8 @@ print_aligned_vertical(const char *title, const char *const * headers,
height, height,
fs; fs;
pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding, &width, &height, &fs); pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding,
&width, &height, &fs);
if (width > hwidth) if (width > hwidth)
hwidth = width; hwidth = width;
if (height > hheight) if (height > hheight)
@ -953,7 +968,8 @@ 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, &width, &height, &fs); pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding,
&width, &height, &fs);
width += numeric_locale_len; width += numeric_locale_len;
if (width > dwidth) if (width > dwidth)
dwidth = width; dwidth = width;
@ -1041,9 +1057,11 @@ print_aligned_vertical(const char *title, const char *const * headers,
/* Format the header */ /* Format the header */
pg_wcsformat((unsigned char *) headers[i % col_count], pg_wcsformat((unsigned char *) headers[i % col_count],
strlen(headers[i % col_count]), encoding, hlineptr, hheight); strlen(headers[i % col_count]),
encoding, hlineptr, hheight);
/* Format the data */ /* Format the data */
pg_wcsformat((unsigned char *) *ptr, strlen(*ptr), encoding, dlineptr, dheight); pg_wcsformat((unsigned char *) *ptr, strlen(*ptr), encoding,
dlineptr, dheight);
line_count = 0; line_count = 0;
dcomplete = hcomplete = 0; dcomplete = hcomplete = 0;
@ -1182,7 +1200,7 @@ print_html_text(const char *title, const char *const * headers,
{ {
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; unsigned short opt_border = opt->border;
const char *opt_table_attr = opt->tableAttr; const char *opt_table_attr = opt->tableAttr;
unsigned int col_count = 0; unsigned int col_count = 0;
unsigned int i; unsigned int i;
@ -1283,7 +1301,7 @@ print_html_vertical(const char *title, const char *const * headers,
{ {
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; unsigned short opt_border = opt->border;
const char *opt_table_attr = opt->tableAttr; const char *opt_table_attr = opt->tableAttr;
unsigned int col_count = 0; unsigned int col_count = 0;
unsigned long record = opt->prior_records + 1; unsigned long record = opt->prior_records + 1;
@ -1421,7 +1439,7 @@ print_latex_text(const char *title, const char *const * headers,
{ {
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; unsigned short opt_border = opt->border;
unsigned int col_count = 0; unsigned int col_count = 0;
unsigned int i; unsigned int i;
const char *const * ptr; const char *const * ptr;
@ -1534,7 +1552,7 @@ print_latex_vertical(const char *title, const char *const * headers,
{ {
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; unsigned short opt_border = opt->border;
unsigned int col_count = 0; unsigned int col_count = 0;
unsigned long record = opt->prior_records + 1; unsigned long record = opt->prior_records + 1;
unsigned int i; unsigned int i;
@ -1661,7 +1679,7 @@ print_troff_ms_text(const char *title, const char *const * headers,
{ {
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; unsigned short opt_border = opt->border;
unsigned int col_count = 0; unsigned int col_count = 0;
unsigned int i; unsigned int i;
const char *const * ptr; const char *const * ptr;
@ -1764,7 +1782,7 @@ print_troff_ms_vertical(const char *title, const char *const * headers,
{ {
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; unsigned short opt_border = opt->border;
unsigned int col_count = 0; unsigned int col_count = 0;
unsigned long record = opt->prior_records + 1; unsigned long record = opt->prior_records + 1;
unsigned int i; unsigned int i;
@ -2216,17 +2234,18 @@ setDecimalLocale(void)
} }
/* /*
* Returns the byte length to the end of the specified character * Compute the byte distance to the end of the string or *target_width
* and number of display characters processed (useful if the string * display character positions, whichever comes first. Update *target_width
* is shorter then dpylen). * to be the number of display character positions actually filled.
*/ */
static int static int
strlen_max_width(unsigned char *str, int *target_width, int encoding) strlen_max_width(unsigned char *str, int *target_width, int encoding)
{ {
unsigned char *start = str; unsigned char *start = str;
unsigned char *end = str + strlen((char *) str);
int curr_width = 0; int curr_width = 0;
while (*str && curr_width < *target_width) while (str < end)
{ {
int char_width = PQdsplen((char *) str, encoding); int char_width = PQdsplen((char *) str, encoding);
@ -2234,18 +2253,17 @@ strlen_max_width(unsigned char *str, int *target_width, int encoding)
* If the display width of the new character causes * If the display width of the new character causes
* the string to exceed its target width, skip it * the string to exceed its target width, skip it
* and return. However, if this is the first character * and return. However, if this is the first character
* of the string (*width == 0), we have to accept it. * of the string (curr_width == 0), we have to accept it.
*/ */
if (*target_width - curr_width < char_width && curr_width != 0) if (*target_width < curr_width + char_width && curr_width != 0)
break; break;
str += PQmblen((char *)str, encoding);
curr_width += char_width; curr_width += char_width;
str += PQmblen((char *) str, encoding);
} }
*target_width = curr_width; *target_width = curr_width;
/* last byte */
return str - start; return str - start;
} }