33 *
44 * Copyright (c) 2000-2008, PostgreSQL Global Development Group
55 *
6- * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.101 2008/05/13 00:14:11 alvherre Exp $
6+ * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.102 2008/05/16 16:59:05 momjian Exp $
77 */
88#include "postgres_fe.h"
99
@@ -45,6 +45,8 @@ static char *thousands_sep;
4545
4646/* Local functions */
4747static int strlen_max_width (unsignedchar * str ,int * target_width ,int encoding );
48+ static void IsPagerNeeded (const printTableContent * cont ,const int extra_lines ,
49+ FILE * * fout ,bool * is_pager );
4850
4951
5052static void *
@@ -394,7 +396,7 @@ _print_horizontal_line(const unsigned int ncolumns, const unsigned int *widths,
394396 *Print pretty boxes around cells.
395397 */
396398static void
397- print_aligned_text (const printTableContent * cont ,bool is_pager , FILE * fout )
399+ print_aligned_text (const printTableContent * cont ,FILE * fout )
398400{
399401bool opt_tuples_only = cont -> opt -> tuples_only ;
400402bool opt_numeric_locale = cont -> opt -> numericLocale ;
@@ -416,6 +418,8 @@ print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
416418unsignedchar * * format_buf ;
417419unsignedint width_total ;
418420unsignedint total_header_width ;
421+ unsignedint extra_row_output_lines = 0 ;
422+ unsignedint extra_output_lines = 0 ;
419423
420424const char * const * ptr ;
421425
@@ -424,6 +428,7 @@ print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
424428bool * header_done ;/* Have all header lines been output? */
425429int * bytes_output ;/* Bytes output for column value */
426430int output_columns = 0 ;/* Width of interactive console */
431+ bool is_pager = false;
427432
428433if (cancel_pressed )
429434return ;
@@ -476,9 +481,14 @@ print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
476481max_nl_lines [i ]= nl_lines ;
477482if (bytes_required > max_bytes [i ])
478483max_bytes [i ]= bytes_required ;
484+ if (nl_lines > extra_row_output_lines )
485+ extra_row_output_lines = nl_lines ;
479486
480487width_header [i ]= width ;
481488}
489+ /* Add height of tallest header column */
490+ extra_output_lines += extra_row_output_lines ;
491+ extra_row_output_lines = 0 ;
482492
483493/* scan all cells, find maximum width, compute cell_count */
484494for (i = 0 ,ptr = cont -> cells ;* ptr ;ptr ++ ,i ++ ,cell_count ++ )
@@ -487,7 +497,6 @@ print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
487497nl_lines ,
488498bytes_required ;
489499
490- /* Get width, ignore nl_lines */
491500pg_wcssize ((unsignedchar * )* ptr ,strlen (* ptr ),encoding ,
492501& width ,& nl_lines ,& bytes_required );
493502if (opt_numeric_locale && cont -> aligns [i %col_count ]== 'r' )
@@ -552,28 +561,28 @@ print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
552561for (i = 0 ;i < col_count ;i ++ )
553562width_wrap [i ]= max_width [i ];
554563
555- if (cont -> opt -> format == PRINT_WRAPPED )
564+ /*
565+ * Choose target output width: \pset columns, or $COLUMNS, or ioctl
566+ */
567+ if (cont -> opt -> columns > 0 )
568+ output_columns = cont -> opt -> columns ;
569+ else if ((fout == stdout && isatty (fileno (stdout )))|| is_pager )
556570{
557- /*
558- * Choose target output width: \pset columns, or $COLUMNS, or ioctl
559- */
560- if (cont -> opt -> columns > 0 )
561- output_columns = cont -> opt -> columns ;
562- else if ((fout == stdout && isatty (fileno (stdout )))|| is_pager )
563- {
564- if (cont -> opt -> env_columns > 0 )
565- output_columns = cont -> opt -> env_columns ;
571+ if (cont -> opt -> env_columns > 0 )
572+ output_columns = cont -> opt -> env_columns ;
566573#ifdef TIOCGWINSZ
567- else
568- {
569- struct winsize screen_size ;
570-
571- if (ioctl (fileno (stdout ),TIOCGWINSZ ,& screen_size )!= -1 )
572- output_columns = screen_size .ws_col ;
573- }
574- #endif
574+ else
575+ {
576+ struct winsize screen_size ;
577+
578+ if (ioctl (fileno (stdout ),TIOCGWINSZ ,& screen_size )!= -1 )
579+ output_columns = screen_size .ws_col ;
575580}
581+ #endif
582+ }
576583
584+ if (cont -> opt -> format == PRINT_WRAPPED )
585+ {
577586/*
578587 * Optional optimized word wrap. Shrink columns with a high max/avg
579588 * ratio. Slighly bias against wider columns. (Increases chance a
@@ -623,6 +632,49 @@ print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
623632}
624633}
625634
635+ /* If we wrapped beyond the display width, use the pager */
636+ if (!is_pager && output_columns > 0 &&
637+ (output_columns < total_header_width || output_columns < width_total ))
638+ {
639+ fout = PageOutput (INT_MAX ,cont -> opt -> pager );/* force pager */
640+ is_pager = true;
641+ }
642+
643+ /* Check if newlines or our wrapping now need the pager */
644+ if (!is_pager )
645+ {
646+ /* scan all cells, find maximum width, compute cell_count */
647+ for (i = 0 ,ptr = cont -> cells ;* ptr ;ptr ++ ,i ++ ,cell_count ++ )
648+ {
649+ int width ,
650+ nl_lines ,
651+ bytes_required ;
652+
653+ pg_wcssize ((unsignedchar * )* ptr ,strlen (* ptr ),encoding ,
654+ & width ,& nl_lines ,& bytes_required );
655+ if (opt_numeric_locale && cont -> align [i %col_count ]== 'r' )
656+ width += additional_numeric_locale_len (* ptr );
657+
658+ /*
659+ *A row can have both wrapping and newlines that cause
660+ *it to display across multiple lines. We check
661+ *for both cases below.
662+ */
663+ if (width > 0 && width_wrap [i ]&&
664+ (width - 1 ) /width_wrap [i ]+ nl_lines > extra_row_output_lines )
665+ extra_row_output_lines = (width - 1 ) /width_wrap [i ]+ nl_lines ;
666+
667+ /* If last column, add tallest column height */
668+ if (i %col_count == col_count - 1 )
669+ {
670+ /* Add height of tallest row */
671+ extra_output_lines += extra_row_output_lines ;
672+ extra_row_output_lines = 0 ;
673+ }
674+ }
675+ IsPagerNeeded (cont ,extra_output_lines ,& fout ,& is_pager );
676+ }
677+
626678/* time to output */
627679if (cont -> opt -> start_table )
628680{
@@ -882,6 +934,9 @@ print_aligned_text(const printTableContent *cont, bool is_pager, FILE *fout)
882934for (i = 0 ;i < col_count ;i ++ )
883935free (format_buf [i ]);
884936free (format_buf );
937+
938+ if (is_pager )
939+ ClosePager (fout );
885940}
886941
887942
@@ -2115,21 +2170,15 @@ printTableCleanup(printTableContent *content)
21152170}
21162171
21172172/*
2118- * Use this to print just any table in the supported formats.
2173+ * IsPagerNeeded
2174+ *
2175+ * Setup pager if required
21192176 */
21202177void
2121- printTable (const printTableContent * cont ,FILE * fout ,FILE * flog )
2178+ IsPagerNeeded (const printTableContent * cont ,const int extra_lines ,FILE * * fout ,
2179+ bool * is_pager )
21222180{
2123- FILE * output ;
2124- bool is_pager = false;
2125-
2126- if (cancel_pressed )
2127- return ;
2128-
2129- if (cont -> opt -> format == PRINT_NOTHING )
2130- return ;
2131-
2132- if (fout == stdout )
2181+ if (* fout == stdout )
21332182{
21342183int lines ;
21352184
@@ -2150,58 +2199,79 @@ printTable(const printTableContent *cont, FILE *fout, FILE *flog)
21502199lines ++ ;
21512200}
21522201
2153- output = PageOutput (lines ,cont -> opt -> pager );
2154- is_pager = (output != fout );
2202+ * fout = PageOutput (lines + extra_lines ,cont -> opt -> pager );
2203+ * is_pager = (* fout != stdout );
21552204}
21562205else
2157- output = fout ;
2206+ * is_pager = false;
2207+ }
2208+
2209+ /*
2210+ * Use this to print just any table in the supported formats.
2211+ */
2212+ void
2213+ printTable (const printTableContent * cont ,FILE * fout ,FILE * flog )
2214+ {
2215+ bool is_pager = false;
2216+
2217+ if (cancel_pressed )
2218+ return ;
2219+
2220+ if (cont -> opt -> format == PRINT_NOTHING )
2221+ return ;
2222+
2223+ /* print_aligned_text() handles the pager itself */
2224+ if ((cont -> opt -> format != PRINT_ALIGNED &&
2225+ cont -> opt -> format != PRINT_WRAPPED )||
2226+ cont -> opt -> expanded )
2227+ IsPagerNeeded (cont ,0 ,& fout ,& is_pager );
21582228
21592229/* print the stuff */
21602230
21612231if (flog )
2162- print_aligned_text (cont ,is_pager , flog );
2232+ print_aligned_text (cont ,flog );
21632233
21642234switch (cont -> opt -> format )
21652235{
21662236case PRINT_UNALIGNED :
21672237if (cont -> opt -> expanded )
2168- print_unaligned_vertical (cont ,output );
2238+ print_unaligned_vertical (cont ,fout );
21692239else
2170- print_unaligned_text (cont ,output );
2240+ print_unaligned_text (cont ,fout );
21712241break ;
21722242case PRINT_ALIGNED :
21732243case PRINT_WRAPPED :
21742244if (cont -> opt -> expanded )
2175- print_aligned_vertical (cont ,output );
2245+ print_aligned_vertical (cont ,fout );
21762246else
2177- print_aligned_text (cont ,is_pager , output );
2247+ print_aligned_text (cont ,fout );
21782248break ;
21792249case PRINT_HTML :
21802250if (cont -> opt -> expanded )
2181- print_html_vertical (cont ,output );
2251+ print_html_vertical (cont ,fout );
21822252else
2183- print_html_text (cont ,output );
2253+ print_html_text (cont ,fout );
21842254break ;
21852255case PRINT_LATEX :
21862256if (cont -> opt -> expanded )
2187- print_latex_vertical (cont ,output );
2257+ print_latex_vertical (cont ,fout );
21882258else
2189- print_latex_text (cont ,output );
2259+ print_latex_text (cont ,fout );
21902260break ;
21912261case PRINT_TROFF_MS :
21922262if (cont -> opt -> expanded )
2193- print_troff_ms_vertical (cont ,output );
2263+ print_troff_ms_vertical (cont ,fout );
21942264else
2195- print_troff_ms_text (cont ,output );
2265+ print_troff_ms_text (cont ,fout );
21962266break ;
21972267default :
2198- fprintf (stderr ,_ ("invalidoutput format (internal error): %d" ),
2268+ fprintf (stderr ,_ ("invalidfout format (internal error): %d" ),
21992269cont -> opt -> format );
22002270exit (EXIT_FAILURE );
22012271}
22022272
22032273if (is_pager )
2204- ClosePager (output );
2274+ ClosePager (fout );
22052275}
22062276
22072277/*