diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c index 0e615d8cb8fdfbc3d8415c887919abab95873a13..68c675c06f80435509d682fabca3b54d12bb2f30 100644 --- a/src/bin/psql/print.c +++ b/src/bin/psql/print.c @@ -3,7 +3,7 @@ * * 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" @@ -28,8 +28,6 @@ #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 @@ -45,6 +43,9 @@ static char *decimal_point; 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) @@ -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 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_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; @@ -483,7 +484,8 @@ print_aligned_text(const char *title, const char *const * headers, 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]) @@ -502,7 +504,8 @@ print_aligned_text(const char *title, const char *const * headers, 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); @@ -567,12 +570,14 @@ print_aligned_text(const char *title, const char *const * headers, 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 @@ -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. - * 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) { @@ -610,10 +615,11 @@ print_aligned_text(const char *title, const char *const * headers, { 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; @@ -641,7 +647,8 @@ print_aligned_text(const char *title, const char *const * headers, { 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 @@ -723,12 +730,13 @@ print_aligned_text(const char *title, const char *const * headers, 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') @@ -736,8 +744,8 @@ print_aligned_text(const char *title, const char *const * headers, 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); } } @@ -764,16 +772,22 @@ print_aligned_text(const char *title, const char *const * headers, { /* 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 @@ -796,13 +810,14 @@ print_aligned_text(const char *title, const char *const * headers, /* 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 { @@ -814,8 +829,8 @@ print_aligned_text(const char *title, const char *const * headers, } } - /* 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); @@ -832,10 +847,9 @@ print_aligned_text(const char *title, const char *const * headers, /* Ordinary line */ fputs(" | ", fout); } - } - /* end of row border */ + /* end-of-row border */ if (opt_border == 2) fputs(" |", 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_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; @@ -927,7 +941,8 @@ print_aligned_vertical(const char *title, const char *const * headers, 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) @@ -953,7 +968,8 @@ print_aligned_vertical(const char *title, const char *const * headers, 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; @@ -1041,9 +1057,11 @@ print_aligned_vertical(const char *title, const char *const * headers, /* 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; @@ -1182,7 +1200,7 @@ print_html_text(const char *title, const char *const * headers, { 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; @@ -1283,7 +1301,7 @@ print_html_vertical(const char *title, const char *const * headers, { 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; @@ -1421,7 +1439,7 @@ print_latex_text(const char *title, const char *const * headers, { 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; @@ -1534,7 +1552,7 @@ print_latex_vertical(const char *title, const char *const * headers, { 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; @@ -1661,7 +1679,7 @@ print_troff_ms_text(const char *title, const char *const * headers, { 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; @@ -1764,7 +1782,7 @@ print_troff_ms_vertical(const char *title, const char *const * headers, { 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; @@ -1970,7 +1988,7 @@ printTable(const char *title, static const char *default_footer[] = {NULL}; FILE *output; bool is_pager = false; - + if (cancel_pressed) return; @@ -2216,17 +2234,18 @@ setDecimalLocale(void) } /* - * 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); @@ -2234,18 +2253,17 @@ strlen_max_width(unsigned char *str, int *target_width, int 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; }