Bryce Nesbitt wrote: > I've attached a patch, against current 8.4 cvs, which optionally sets a > maximum width for psql output: > > # \pset format aligned-wrapped > # \pset border 2 > # select * from distributors order by did; > +------+--------------------+---------------------+---------------+ > | did | name | descr | long_col_name | > +------+--------------------+---------------------+---------------+ > | 1 | Food fish and wine | default | | > | 2 | Cat Food Heaven 2 | abcdefghijklmnopqrs ! | > | | | tuvwxyz | | > | 3 | Cat Food Heaven 3 | default | | > | 10 | Lah | default | | > | 12 | name | line one | | > | 2892 ! short name | short | | > | 8732 | | | | > +------+--------------------+---------------------+---------------+ > (8 rows) > > The interactive terminal column width comes from > char * temp = getenv("COLUMNS"); > Which has the strong advantage of great simplicity and portability. But > it may not be 1000% universal. If $COLUMNS is not defined, the code > bails to assuming an infinitely wide terminal. > > I will also backport this to Postgres 8.1, for my own use. Though the > code is almost totally different in structure.
I spent time reviewing your patch --- quite impressive. I have attached and updated version with mostly stylistic changes. In testing I found the regression tests were failing because of a divide by zero error (fixed), and a missing case where the column delimiter has to be ":". In fact I now see all your line continuation cases using ":" rather than "!". It actually looks better --- "!" was too close to "|" to be easily recognized. (Did you update your patch to use ":". I didn't see "!" in your patch.) I have added an XXX comment questioning whether the loop to find the column to wrap is inefficient because it potentially loops over the length of the longest column and for each character loops over the number of columns. Not sure if that is a problem. I checked the use of COLUMNS and it seems bash updates the environment variable when a window is resized. I added ioctl(TIOCGWINSZ) if COLUMNS isn't set. We already had a call in print.c for detecting the number of rows on the screen to determine if the pager should be used. Seems COLUMNS should take precedence over ioctl(), right? I don't think Win32 supports that ioctl(), does it? I added some comments and clarified some variable names. I also renamed the option to a shorter "wrapped". I added documentation too. For testers compare: \df with: \pset format wrap \df Impressive! -- Bruce Momjian <[EMAIL PROTECTED]> http://momjian.us EnterpriseDB http://enterprisedb.com + If your life is a hard drive, Christ can be your backup. +
Index: doc/src/sgml/ref/psql-ref.sgml =================================================================== RCS file: /cvsroot/pgsql/doc/src/sgml/ref/psql-ref.sgml,v retrieving revision 1.199 diff -c -c -r1.199 psql-ref.sgml *** doc/src/sgml/ref/psql-ref.sgml 30 Mar 2008 18:10:20 -0000 1.199 --- doc/src/sgml/ref/psql-ref.sgml 17 Apr 2008 02:45:38 -0000 *************** *** 1513,1519 **** <listitem> <para> Sets the output format to one of <literal>unaligned</literal>, ! <literal>aligned</literal>, <literal>html</literal>, <literal>latex</literal>, or <literal>troff-ms</literal>. Unique abbreviations are allowed. (That would mean one letter is enough.) --- 1513,1520 ---- <listitem> <para> Sets the output format to one of <literal>unaligned</literal>, ! <literal>aligned</literal>, <literal>wrapped</literal>, ! <literal>html</literal>, <literal>latex</literal>, or <literal>troff-ms</literal>. Unique abbreviations are allowed. (That would mean one letter is enough.) *************** *** 1525,1531 **** is intended to create output that might be intended to be read in by other programs (tab-separated, comma-separated). <quote>Aligned</quote> mode is the standard, human-readable, ! nicely formatted text output that is default. The <quote><acronym>HTML</acronym></quote> and <quote>LaTeX</quote> modes put out tables that are intended to be included in documents using the respective mark-up --- 1526,1535 ---- is intended to create output that might be intended to be read in by other programs (tab-separated, comma-separated). <quote>Aligned</quote> mode is the standard, human-readable, ! nicely formatted text output that is default. ! <quote>Wrapped</quote> is like <literal>aligned</> but wraps ! the output to fit the screen's width, based on the environment ! variable <envar>COLUMNS</> or the autodetected width. The <quote><acronym>HTML</acronym></quote> and <quote>LaTeX</quote> modes put out tables that are intended to be included in documents using the respective mark-up *************** *** 2708,2713 **** --- 2712,2730 ---- <variablelist> <varlistentry> + <term><envar>COLUMNS</envar></term> + + <listitem> + <para> + The character width to wrap output in <literal>wrapped</> format + mode. Many shells automatically update <envar>COLUMNS</> when + a window is resized. If not set the screen width is automatically + detected, if possible. + </para> + </listitem> + </varlistentry> + + <varlistentry> <term><envar>PAGER</envar></term> <listitem> Index: src/bin/psql/command.c =================================================================== RCS file: /cvsroot/pgsql/src/bin/psql/command.c,v retrieving revision 1.186 diff -c -c -r1.186 command.c *** src/bin/psql/command.c 1 Jan 2008 19:45:55 -0000 1.186 --- src/bin/psql/command.c 17 Apr 2008 02:45:38 -0000 *************** *** 1526,1531 **** --- 1526,1534 ---- case PRINT_ALIGNED: return "aligned"; break; + case PRINT_WRAP: + return "wrapped"; + break; case PRINT_HTML: return "html"; break; *************** *** 1559,1564 **** --- 1562,1569 ---- popt->topt.format = PRINT_UNALIGNED; else if (pg_strncasecmp("aligned", value, vallen) == 0) popt->topt.format = PRINT_ALIGNED; + else if (pg_strncasecmp("wrapped", value, vallen) == 0) + popt->topt.format = PRINT_WRAP; else if (pg_strncasecmp("html", value, vallen) == 0) popt->topt.format = PRINT_HTML; else if (pg_strncasecmp("latex", value, vallen) == 0) *************** *** 1567,1573 **** popt->topt.format = PRINT_TROFF_MS; else { ! psql_error("\\pset: allowed formats are unaligned, aligned, html, latex, troff-ms\n"); return false; } --- 1572,1578 ---- popt->topt.format = PRINT_TROFF_MS; else { ! psql_error("\\pset: allowed formats are unaligned, aligned, wrapped, html, latex, troff-ms\n"); return false; } Index: src/bin/psql/mbprint.c =================================================================== RCS file: /cvsroot/pgsql/src/bin/psql/mbprint.c,v retrieving revision 1.30 diff -c -c -r1.30 mbprint.c *** src/bin/psql/mbprint.c 16 Apr 2008 18:18:00 -0000 1.30 --- src/bin/psql/mbprint.c 17 Apr 2008 02:45:38 -0000 *************** *** 279,284 **** --- 279,288 ---- return width; } + /* + * Filter out unprintable characters, companion to wcs_size. + * Break input into lines (based on \n or \r). + */ void pg_wcsformat(unsigned char *pwcs, size_t len, int encoding, struct lineptr * lines, int count) *************** *** 353,364 **** } len -= chlen; } ! *ptr++ = '\0'; lines->width = linewidth; ! lines++; ! count--; ! if (count > 0) lines->ptr = NULL; } unsigned char * --- 357,373 ---- } len -= chlen; } ! *ptr++ = '\0'; /* Terminate formatted string */ ! lines->width = linewidth; ! ! /* Fill remaining array slots with nulls */ ! while (--count) ! { ! lines++; lines->ptr = NULL; + lines->width = 0; + } } unsigned char * Index: src/bin/psql/print.c =================================================================== RCS file: /cvsroot/pgsql/src/bin/psql/print.c,v retrieving revision 1.97 diff -c -c -r1.97 print.c *** src/bin/psql/print.c 27 Mar 2008 03:57:34 -0000 1.97 --- src/bin/psql/print.c 17 Apr 2008 02:45:38 -0000 *************** *** 396,401 **** --- 396,404 ---- } + /* + * Prety pretty boxes around cells. + */ static void print_aligned_text(const char *title, const char *const * headers, const char *const * cells, const char *const * footers, *************** *** 404,429 **** { bool opt_tuples_only = opt->tuples_only; bool opt_numeric_locale = opt->numericLocale; - unsigned short int opt_border = opt->border; int encoding = opt->encoding; ! unsigned int col_count = 0; ! unsigned int cell_count = 0; ! unsigned int i; ! int tmp; ! unsigned int *widths, ! total_w; ! unsigned int *heights; ! unsigned int *format_space; unsigned char **format_buf; const char *const * ptr; ! struct lineptr **col_lineptrs; /* pointers to line pointer for each ! * column */ struct lineptr *lineptr_list; /* complete list of linepointers */ int *complete; /* Array remembering which columns have * completed output */ if (cancel_pressed) return; --- 407,437 ---- { 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 int col_count = 0, cell_count = 0; ! ! unsigned int i, ! j; ! ! unsigned int *width_header, ! *width_max, ! *width_wrap, ! *width_average; ! unsigned int *heights, ! *format_space; unsigned char **format_buf; + unsigned int width_total; const char *const * ptr; ! struct lineptr **col_lineptrs; /* pointers to line pointer per column */ struct lineptr *lineptr_list; /* complete list of linepointers */ int *complete; /* Array remembering which columns have * completed output */ + int tcolumns = 0; /* Width of interactive console */ if (cancel_pressed) return; *************** *** 437,443 **** if (col_count > 0) { ! widths = pg_local_calloc(col_count, sizeof(*widths)); heights = pg_local_calloc(col_count, sizeof(*heights)); col_lineptrs = pg_local_calloc(col_count, sizeof(*col_lineptrs)); format_space = pg_local_calloc(col_count, sizeof(*format_space)); --- 445,454 ---- if (col_count > 0) { ! width_header = pg_local_calloc(col_count, sizeof(*width_header)); ! width_average = pg_local_calloc(col_count, sizeof(*width_average)); ! width_max = pg_local_calloc(col_count, sizeof(*width_max)); ! width_wrap = pg_local_calloc(col_count, sizeof(*width_wrap)); heights = pg_local_calloc(col_count, sizeof(*heights)); col_lineptrs = pg_local_calloc(col_count, sizeof(*col_lineptrs)); format_space = pg_local_calloc(col_count, sizeof(*format_space)); *************** *** 446,452 **** } else { ! widths = NULL; heights = NULL; col_lineptrs = NULL; format_space = NULL; --- 457,466 ---- } else { ! width_header = NULL; ! width_average = NULL; ! width_max = NULL; ! width_wrap = NULL; heights = NULL; col_lineptrs = NULL; format_space = NULL; *************** *** 454,533 **** complete = NULL; } ! /* count cells (rows * cols) */ ! for (ptr = cells; *ptr; ptr++) ! cell_count++; ! ! /* calc column widths */ for (i = 0; i < col_count; i++) { /* Get width & height */ ! int height, space; ! pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding, &tmp, &height, &space); ! if (tmp > widths[i]) ! widths[i] = tmp; if (height > heights[i]) heights[i] = height; if (space > format_space[i]) format_space[i] = space; } ! for (i = 0, ptr = cells; *ptr; ptr++, i++) { ! int numeric_locale_len; ! int height, space; - if (opt_align[i % col_count] == 'r' && opt_numeric_locale) - numeric_locale_len = additional_numeric_locale_len(*ptr); - else - numeric_locale_len = 0; - /* Get width, ignore height */ ! pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding, &tmp, &height, &space); ! tmp += numeric_locale_len; ! if (tmp > widths[i % col_count]) ! widths[i % col_count] = tmp; if (height > heights[i % col_count]) heights[i % col_count] = height; if (space > format_space[i % col_count]) format_space[i % col_count] = space; } if (opt_border == 0) ! total_w = col_count - 1; else if (opt_border == 1) ! total_w = col_count * 3 - 1; else ! total_w = col_count * 3 + 1; for (i = 0; i < col_count; i++) ! total_w += widths[i]; /* ! * At this point: widths contains the max width of each column heights ! * contains the max height of a cell of each column format_space contains ! * maximum space required to store formatted string so we prepare the ! * formatting structures */ if (col_count > 0) { ! int heights_total = 0; struct lineptr *lineptr; for (i = 0; i < col_count; i++) ! heights_total += heights[i]; ! lineptr = lineptr_list = pg_local_calloc(heights_total, sizeof(*lineptr_list)); for (i = 0; i < col_count; i++) { col_lineptrs[i] = lineptr; lineptr += heights[i]; ! format_buf[i] = pg_local_malloc(format_space[i]); col_lineptrs[i]->ptr = format_buf[i]; } --- 468,560 ---- complete = NULL; } ! /* scan all column headers, find maximum width */ for (i = 0; i < col_count; i++) { /* Get width & height */ ! int width, ! height, space; ! pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding, &width, &height, &space); ! if (width > width_max[i]) ! width_max[i] = width; if (height > heights[i]) heights[i] = height; if (space > format_space[i]) format_space[i] = space; + + width_header[i] = width; } ! /* scan all rows, find maximum width, compute cell_count */ ! for (i = 0, ptr = cells; *ptr; ptr++, i++, cell_count++) { ! int width, ! height, space; /* Get width, ignore height */ ! pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding, &width, &height, &space); ! if (opt_numeric_locale && opt_align[i % col_count] == 'r') ! { ! width += additional_numeric_locale_len(*ptr); ! space += additional_numeric_locale_len(*ptr); ! } ! ! if (width > width_max[i % col_count]) ! width_max[i % col_count] = width; if (height > heights[i % col_count]) heights[i % col_count] = height; if (space > format_space[i % col_count]) format_space[i % col_count] = space; + + width_average[i % col_count] += width; + } + + /* 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) ! width_total = col_count - 1; else if (opt_border == 1) ! width_total = col_count * 3 - 1; else ! width_total = col_count * 3 + 1; for (i = 0; i < col_count; i++) ! width_total += width_max[i]; /* ! * At this point: width_max[] contains the max width of each column, ! * heights[] contains the max number of lines in each column, ! * format_space[] contains the maximum storage space for formatting ! * strings, width_total contains the giant width sum. Now we allocate ! * some memory... */ if (col_count > 0) { ! int height_total = 0; struct lineptr *lineptr; for (i = 0; i < col_count; i++) ! height_total += heights[i]; ! lineptr = lineptr_list = pg_local_calloc(height_total, sizeof(*lineptr_list)); for (i = 0; i < col_count; i++) { col_lineptrs[i] = lineptr; lineptr += heights[i]; ! format_buf[i] = pg_local_malloc(format_space[i] + 1); col_lineptrs[i]->ptr = format_buf[i]; } *************** *** 535,553 **** else lineptr_list = NULL; if (opt->start_table) { /* print title */ if (title && !opt_tuples_only) { ! /* Get width & height */ ! int height; ! pg_wcssize((unsigned char *) title, strlen(title), encoding, &tmp, &height, NULL); ! if (tmp >= total_w) ! fprintf(fout, "%s\n", title); else ! fprintf(fout, "%-*s%s\n", (total_w - tmp) / 2, "", title); } /* print headers */ --- 562,650 ---- else lineptr_list = NULL; + + /* Default word wrap to the full width, i.e. no word wrap */ + for (i = 0; i < col_count; i++) + width_wrap[i] = width_max[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 (opt->format == PRINT_WRAP) + { + /* If we can get the terminal width */ + char *env = getenv("COLUMNS"); + + if (env != NULL) + tcolumns = atoi(env); + #ifdef TIOCGWINSZ + else + { + struct winsize screen_size; + + if (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) != -1) + tcolumns = screen_size.ws_col; + } + #endif + + if (tcolumns > 0) + { + /* Shink high ratio columns */ + while (width_total > tcolumns) + { + double ratio = 0; + double curr_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 width_max. + */ + for (i = 0; i < col_count; i++) + if (width_average[i] && width_wrap[i] > width_header[i]) + { + curr_ratio = (double) width_wrap[i] / width_average[i]; + curr_ratio += width_max[i] * 0.01; /* Penalize wide columns */ + if (curr_ratio > ratio) + { + ratio = curr_ratio; + worst_col = i; + } + } + + /* Exit loop if we can't squeeze any more. */ + if (worst_col < 0) + break; + + /* Squeeze the worst column. Lather, rinse, repeat */ + /* + * XXX This only reduces one character at a time so might + * be inefficient for very long rows. + */ + width_wrap[worst_col]--; + width_total--; + } + } + } + + /* time to output */ if (opt->start_table) { /* print title */ if (title && !opt_tuples_only) { ! int width, ! height; ! pg_wcssize((unsigned char *) title, strlen(title), encoding, &width, &height, NULL); ! if (width >= width_total) ! fprintf(fout, "%s\n", title); /* Aligned */ else ! fprintf(fout, "%-*s%s\n", (width_total - width) / 2, "", title); /* Centered */ } /* print headers */ *************** *** 557,563 **** int line_count; if (opt_border == 2) ! _print_horizontal_line(col_count, widths, opt_border, fout); for (i = 0; i < col_count; i++) pg_wcsformat((unsigned char *) headers[i], strlen(headers[i]), encoding, col_lineptrs[i], heights[i]); --- 654,660 ---- int line_count; if (opt_border == 2) ! _print_horizontal_line(col_count, width_wrap, opt_border, fout); for (i = 0; i < col_count; i++) pg_wcsformat((unsigned char *) headers[i], strlen(headers[i]), encoding, col_lineptrs[i], heights[i]); *************** *** 580,586 **** if (!complete[i]) { ! nbspace = widths[i] - this_line->width; /* centered */ fprintf(fout, "%-*s%s%-*s", --- 677,683 ---- if (!complete[i]) { ! nbspace = width_wrap[i] - this_line->width; /* centered */ fprintf(fout, "%-*s%s%-*s", *************** *** 593,599 **** } } else ! fprintf(fout, "%*s", widths[i], ""); if (i < col_count - 1) { if (opt_border == 0) --- 690,696 ---- } } else ! fprintf(fout, "%*s", width_wrap[i], ""); if (i < col_count - 1) { if (opt_border == 0) *************** *** 611,711 **** fputc('\n', fout); } ! _print_horizontal_line(col_count, widths, opt_border, fout); } } /* print cells */ for (i = 0, ptr = cells; *ptr; i += col_count, ptr += col_count) { ! int j; ! int cols_todo = col_count; ! int line_count; /* Number of lines output so far in row */ if (cancel_pressed) break; 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 */ ! if (opt_border == 2) ! fputs("| ", fout); ! else if (opt_border == 1) ! fputc(' ', fout); ! ! for (j = 0; j < col_count; j++) { ! struct lineptr *this_line = col_lineptrs[j] + line_count; ! bool finalspaces = (opt_border == 2 || j != col_count - 1); ! if (complete[j]) /* Just print spaces... */ ! { ! if (finalspaces) ! fprintf(fout, "%*s", widths[j], ""); ! } ! else { ! /* content */ ! if (opt_align[j] == 'r') { ! 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)), "", ! my_cell); ! free(my_cell); } else ! fprintf(fout, "%*s%s", ! widths[j] - this_line->width, "", ! this_line->ptr); } ! 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; ! cols_todo--; } } ! /* divider */ ! if ((j + 1) % col_count) { ! if (opt_border == 0) ! fputc(' ', fout); ! else if (line_count == 0) ! fputs(" | ", fout); ! else ! fprintf(fout, " %c ", complete[j + 1] ? ' ' : ':'); } } - if (opt_border == 2) - fputs(" |", fout); - fputc('\n', fout); - line_count++; } } if (opt->stop_table) { if (opt_border == 2 && !cancel_pressed) ! _print_horizontal_line(col_count, widths, opt_border, fout); /* print footers */ if (footers && !opt_tuples_only && !cancel_pressed) --- 708,855 ---- fputc('\n', fout); } ! _print_horizontal_line(col_count, width_wrap, opt_border, fout); } } /* print cells */ for (i = 0, ptr = cells; *ptr; i += col_count, ptr += col_count) { ! bool line_todo, ! cols_todo; ! int line_count; if (cancel_pressed) 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++) + { pg_wcsformat((unsigned char *) ptr[j], strlen(ptr[j]), encoding, col_lineptrs[j], heights[j]); + 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); ! } ! } ! ! /* Print rows to console */ memset(complete, 0, col_count * sizeof(int)); ! line_count = 0; ! line_todo = true; ! while (line_todo) { ! cols_todo = true; ! while (cols_todo) { ! char border_cell = '*'; ! cols_todo = false; ! ! /* left border */ ! if (opt_border == 2) ! fputs("| ", fout); ! else if (opt_border == 1) ! fputc(' ', fout); ! ! /* for each column */ ! for (j = 0; j < col_count; j++) { ! struct lineptr *this_line = &col_lineptrs[j][line_count]; ! ! if (heights[j] <= line_count) /* Blank column content */ ! { ! fprintf(fout, "%*s", width_wrap[j], ""); ! border_cell = '|'; ! } ! else if (opt_align[j] == 'r') /* Right aligned cell */ { ! int strlen_remaining = strlen((char *) this_line->ptr + complete[j]); ! ! if (strlen_remaining > width_wrap[j]) { ! fprintf(fout, "%.*s", (int) width_wrap[j], this_line->ptr + complete[j]); ! complete[j] += width_wrap[j]; /* We've done THIS much */ ! cols_todo = true; /* And there is more to do... */ ! border_cell = ':'; } else ! { ! fprintf(fout, "%*s", width_wrap[j] - strlen_remaining, ""); ! fprintf(fout, "%-s", this_line->ptr + complete[j]); ! complete[j] += strlen_remaining; ! border_cell = '|'; ! } } ! else /* Left aligned cell */ { ! int strlen_remaining = strlen((char *) this_line->ptr + complete[j]); ! ! if (strlen_remaining > width_wrap[j]) ! { ! fprintf(fout, "%.*s", (int) width_wrap[j], this_line->ptr + complete[j]); ! complete[j] += width_wrap[j]; /* We've done THIS much */ ! cols_todo = true; /* And there is more to do... */ ! border_cell = ':'; ! } ! else ! { ! fprintf(fout, "%-s", this_line->ptr + complete[j]); ! fprintf(fout, "%*s", width_wrap[j] - strlen_remaining, ""); ! complete[j] += strlen_remaining; ! border_cell = '|'; ! } ! } ! ! /* print a divider, middle of columns only */ ! if ((j + 1) % col_count) ! { ! if (opt_border == 0) ! fputc(' ', fout); ! else if (line_count == 0) ! fprintf(fout, " %c ", border_cell); ! else ! fprintf(fout, " %c ", complete[j + 1] ? ' ' : ':'); } } ! /* end of row border */ ! if (opt_border == 2) ! fprintf(fout, " %c", border_cell); ! fputc('\n', fout); ! } ! ! /* ! * Check if any columns have line continuations due to \n in the ! * cell. ! */ ! line_count++; ! line_todo = false; ! for (j = 0; j < col_count; j++) ! { ! if (line_count < heights[j]) { ! if (col_lineptrs[j][line_count].ptr) ! { ! line_todo = true; ! complete[j] = 0; ! } } } } } if (opt->stop_table) { if (opt_border == 2 && !cancel_pressed) ! _print_horizontal_line(col_count, width_wrap, opt_border, fout); /* print footers */ if (footers && !opt_tuples_only && !cancel_pressed) *************** *** 722,728 **** } /* clean up */ ! free(widths); free(heights); free(col_lineptrs); free(format_space); --- 866,875 ---- } /* clean up */ ! free(width_header); ! free(width_average); ! free(width_max); ! free(width_wrap); free(heights); free(col_lineptrs); free(format_space); *************** *** 754,760 **** dheight = 1, hformatsize = 0, dformatsize = 0; - int tmp = 0; char *divider; unsigned int cell_count = 0; struct lineptr *hlineptr, --- 901,906 ---- *************** *** 779,790 **** /* Find the maximum dimensions for the headers */ for (i = 0; i < col_count; i++) { ! int height, fs; ! pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding, &tmp, &height, &fs); ! if (tmp > hwidth) ! hwidth = tmp; if (height > hheight) hheight = height; if (fs > hformatsize) --- 925,937 ---- /* Find the maximum dimensions for the headers */ for (i = 0; i < col_count; i++) { ! int width, ! height, fs; ! pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding, &width, &height, &fs); ! if (width > hwidth) ! hwidth = width; if (height > hheight) hheight = height; if (fs > hformatsize) *************** *** 799,805 **** for (i = 0, ptr = cells; *ptr; ptr++, i++) { int numeric_locale_len; ! int height, fs; if (opt_align[i % col_count] == 'r' && opt_numeric_locale) --- 946,953 ---- for (i = 0, ptr = cells; *ptr; ptr++, i++) { int numeric_locale_len; ! int width, ! height, fs; if (opt_align[i % col_count] == 'r' && opt_numeric_locale) *************** *** 807,816 **** else numeric_locale_len = 0; ! pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding, &tmp, &height, &fs); ! tmp += numeric_locale_len; ! if (tmp > dwidth) ! dwidth = tmp; if (height > dheight) dheight = height; if (fs > dformatsize) --- 955,964 ---- else numeric_locale_len = 0; ! pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding, &width, &height, &fs); ! width += numeric_locale_len; ! if (width > dwidth) ! dwidth = width; if (height > dheight) dheight = height; if (fs > dformatsize) *************** *** 1879,1884 **** --- 2027,2033 ---- opt, output); break; case PRINT_ALIGNED: + case PRINT_WRAP: if (opt->expanded) print_aligned_vertical(title, headers, cells, footers, align, opt, output); Index: src/bin/psql/print.h =================================================================== RCS file: /cvsroot/pgsql/src/bin/psql/print.h,v retrieving revision 1.35 diff -c -c -r1.35 print.h *** src/bin/psql/print.h 1 Jan 2008 19:45:56 -0000 1.35 --- src/bin/psql/print.h 17 Apr 2008 02:45:38 -0000 *************** *** 21,26 **** --- 21,27 ---- PRINT_NOTHING = 0, /* to make sure someone initializes this */ PRINT_UNALIGNED, PRINT_ALIGNED, + PRINT_WRAP, PRINT_HTML, PRINT_LATEX, PRINT_TROFF_MS
-- Sent via pgsql-patches mailing list (pgsql-patches@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-patches