*
* 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 "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
* it naturally belongs, because this file is also used by non-psql programs
static char *grouping;
static char *thousands_sep;
+/* Local functions */
+static int strlen_max_width(unsigned char *str, int *target_width, int encoding);
+
static void *
pg_local_malloc(size_t size)
/*
- * Prety pretty boxes around cells.
+ * Print pretty boxes around cells.
*/
static void
print_aligned_text(const char *title, const char *const * headers,
bool opt_tuples_only = opt->tuples_only;
bool opt_numeric_locale = opt->numericLocale;
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;
nl_lines,
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])
max_width[i] = width;
if (nl_lines > max_nl_lines[i])
bytes_required;
/* 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')
{
width += additional_numeric_locale_len(*ptr);
if (opt->format == PRINT_WRAPPED)
{
- /* Get terminal width */
+ /*
+ * Choose target output width: \pset columns, or $COLUMNS, or ioctl
+ */
if (opt->columns > 0)
output_columns = opt->columns;
else if ((fout == stdout && isatty(fileno(stdout))) || is_pager)
{
- if (opt->env_columns)
+ if (opt->env_columns > 0)
output_columns = opt->env_columns;
#ifdef TIOCGWINSZ
else
}
/*
- * 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
+ * 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)
{
{
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;
+ /* Penalize wide columns by 1% of their width */
+ double ratio;
+ ratio = (double) width_wrap[i] / width_average[i] +
+ max_width[i] * 0.01;
if (ratio > max_ratio)
{
max_ratio = ratio;
{
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)
fprintf(fout, "%s\n", title); /* Aligned */
else
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)
*/
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;
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 */
+ /* Buffer IS large enough... now */
+ strcpy((char *) col_lineptrs[j]->ptr, my_cell);
free(my_cell);
}
}
{
/* We have a valid array element, so index it */
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)
- fprintf(fout, "%*s", width_wrap[j], "");
+ {
+ /* Past newline lines so just pad for other columns */
+ if (finalspaces)
+ fprintf(fout, "%*s", chars_to_output, "");
+ }
else
{
- /* Get strlen() of the width_wrap character */
- bytes_to_output = strlen_max_width(this_line->ptr +
- bytes_output[j], &chars_to_output, encoding);
+ /* Get strlen() of the characters up to width_wrap */
+ bytes_to_output =
+ strlen_max_width(this_line->ptr + bytes_output[j],
+ &chars_to_output, encoding);
/*
* If we exceeded width_wrap, it means the display width
/* spaces second */
fprintf(fout, "%.*s", bytes_to_output,
this_line->ptr + bytes_output[j]);
- fprintf(fout, "%*s", width_wrap[j] - chars_to_output, "");
+ if (finalspaces)
+ 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)
+ if (*(this_line->ptr + bytes_output[j]) != '\0')
more_lines = true;
else
{
}
}
- /* print a divider, middle columns only */
- if ((j + 1) % col_count)
+ /* print a divider, if not the last column */
+ if (j < col_count - 1)
{
if (opt_border == 0)
fputc(' ', fout);
/* Ordinary line */
fputs(" | ", fout);
}
-
}
- /* end of row border */
+ /* end-of-row border */
if (opt_border == 2)
fputs(" |", fout);
fputc('\n', fout);
{
bool opt_tuples_only = opt->tuples_only;
bool opt_numeric_locale = opt->numericLocale;
- unsigned short int opt_border = opt->border;
+ unsigned short opt_border = opt->border;
int encoding = opt->encoding;
unsigned int col_count = 0;
unsigned long record = opt->prior_records + 1;
height,
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)
hwidth = width;
if (height > hheight)
else
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;
if (width > dwidth)
dwidth = width;
/* Format the header */
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 */
- pg_wcsformat((unsigned char *) *ptr, strlen(*ptr), encoding, dlineptr, dheight);
+ pg_wcsformat((unsigned char *) *ptr, strlen(*ptr), encoding,
+ dlineptr, dheight);
line_count = 0;
dcomplete = hcomplete = 0;
{
bool opt_tuples_only = opt->tuples_only;
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;
unsigned int col_count = 0;
unsigned int i;
{
bool opt_tuples_only = opt->tuples_only;
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;
unsigned int col_count = 0;
unsigned long record = opt->prior_records + 1;
{
bool opt_tuples_only = opt->tuples_only;
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 i;
const char *const * ptr;
{
bool opt_tuples_only = opt->tuples_only;
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 long record = opt->prior_records + 1;
unsigned int i;
{
bool opt_tuples_only = opt->tuples_only;
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 i;
const char *const * ptr;
{
bool opt_tuples_only = opt->tuples_only;
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 long record = opt->prior_records + 1;
unsigned int i;
static const char *default_footer[] = {NULL};
FILE *output;
bool is_pager = false;
-
+
if (cancel_pressed)
return;
}
/*
- * 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).
+ * Compute the byte distance to the end of the string or *target_width
+ * display character positions, whichever comes first. Update *target_width
+ * to be the number of display character positions actually filled.
*/
static int
strlen_max_width(unsigned char *str, int *target_width, int encoding)
{
unsigned char *start = str;
+ unsigned char *end = str + strlen((char *) str);
int curr_width = 0;
- while (*str && curr_width < *target_width)
+ while (str < end)
{
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.
+ * 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;
-
- str += PQmblen((char *)str, encoding);
curr_width += char_width;
+
+ str += PQmblen((char *) str, encoding);
}
*target_width = curr_width;
- /* last byte */
return str - start;
}