33 *
44 * Copyright (c) 2000-2008, PostgreSQL Global Development Group
55 *
6- * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.98 2008/05/08 17:04:26 momjian Exp $
6+ * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.99 2008/05/10 03:31:58 tgl Exp $
77 */
88#include "postgres_fe.h"
99
2828
2929#include "mbprint.h"
3030
31- static int strlen_max_width (unsignedchar * str ,int * target_width ,int encoding );
32-
3331/*
3432 * We define the cancel_pressed flag in this file, rather than common.c where
3533 * it naturally belongs, because this file is also used by non-psql programs
@@ -45,6 +43,9 @@ static char *decimal_point;
4543static char * grouping ;
4644static char * thousands_sep ;
4745
46+ /* Local functions */
47+ static int strlen_max_width (unsignedchar * str ,int * target_width ,int encoding );
48+
4849
4950static void *
5051pg_local_malloc (size_t size )
@@ -400,7 +401,7 @@ _print_horizontal_line(const unsigned int col_count, const unsigned int *widths,
400401
401402
402403/*
403- *Prety pretty boxes around cells.
404+ *Print pretty boxes around cells.
404405 */
405406static void
406407print_aligned_text (const char * title ,const char * const * headers ,
@@ -411,7 +412,7 @@ print_aligned_text(const char *title, const char *const * headers,
411412bool opt_tuples_only = opt -> tuples_only ;
412413bool opt_numeric_locale = opt -> numericLocale ;
413414int encoding = opt -> encoding ;
414- unsigned shortint opt_border = opt -> border ;
415+ unsigned short opt_border = opt -> border ;
415416
416417unsignedint col_count = 0 ,cell_count = 0 ;
417418
@@ -483,7 +484,8 @@ print_aligned_text(const char *title, const char *const * headers,
483484nl_lines ,
484485bytes_required ;
485486
486- pg_wcssize ((unsignedchar * )headers [i ],strlen (headers [i ]),encoding ,& width ,& nl_lines ,& bytes_required );
487+ pg_wcssize ((unsignedchar * )headers [i ],strlen (headers [i ]),encoding ,
488+ & width ,& nl_lines ,& bytes_required );
487489if (width > max_width [i ])
488490max_width [i ]= width ;
489491if (nl_lines > max_nl_lines [i ])
@@ -502,7 +504,8 @@ print_aligned_text(const char *title, const char *const * headers,
502504bytes_required ;
503505
504506/* Get width, ignore nl_lines */
505- pg_wcssize ((unsignedchar * )* ptr ,strlen (* ptr ),encoding ,& width ,& nl_lines ,& bytes_required );
507+ pg_wcssize ((unsignedchar * )* ptr ,strlen (* ptr ),encoding ,
508+ & width ,& nl_lines ,& bytes_required );
506509if (opt_numeric_locale && opt_align [i %col_count ]== 'r' )
507510{
508511width += additional_numeric_locale_len (* ptr );
@@ -567,12 +570,14 @@ print_aligned_text(const char *title, const char *const * headers,
567570
568571if (opt -> format == PRINT_WRAPPED )
569572{
570- /* Get terminal width */
573+ /*
574+ * Choose target output width: \pset columns, or $COLUMNS, or ioctl
575+ */
571576if (opt -> columns > 0 )
572577output_columns = opt -> columns ;
573578else if ((fout == stdout && isatty (fileno (stdout )))|| is_pager )
574579{
575- if (opt -> env_columns )
580+ if (opt -> env_columns > 0 )
576581output_columns = opt -> env_columns ;
577582#ifdef TIOCGWINSZ
578583else
@@ -586,11 +591,11 @@ print_aligned_text(const char *title, const char *const * headers,
586591}
587592
588593/*
589- * Optional optimized word wrap. Shrink columns with a high max/avg ratio.
590- * Slighly bias against wider columns. (Increases chance a narrow column
591- * will fit in its cell.)
592- *If available columns is positive...
593- *and greater than the width of the unshrinkable column headers
594+ * Optional optimized word wrap. Shrink columns with a high max/avg
595+ *ratio. Slighly bias against wider columns. (Increases chance a
596+ *narrow column will fit in its cell.) If available columns is
597+ * positive... and greater than the width of the unshrinkable column
598+ * headers
594599 */
595600if (output_columns > 0 && output_columns >=total_header_width )
596601{
@@ -610,10 +615,11 @@ print_aligned_text(const char *title, const char *const * headers,
610615{
611616if (width_average [i ]&& width_wrap [i ]> width_header [i ])
612617{
613- /* Penalize wide columns by +1% of their width (0.01) */
614- double ratio = (double )width_wrap [i ] /width_average [i ]+
615- max_width [i ]* 0.01 ;
618+ /* Penalize wide columns by 1% of their width */
619+ double ratio ;
616620
621+ ratio = (double )width_wrap [i ] /width_average [i ]+
622+ max_width [i ]* 0.01 ;
617623if (ratio > max_ratio )
618624{
619625max_ratio = ratio ;
@@ -641,7 +647,8 @@ print_aligned_text(const char *title, const char *const * headers,
641647{
642648int width ,height ;
643649
644- pg_wcssize ((unsignedchar * )title ,strlen (title ),encoding ,& width ,& height ,NULL );
650+ pg_wcssize ((unsignedchar * )title ,strlen (title ),encoding ,
651+ & width ,& height ,NULL );
645652if (width >=width_total )
646653fprintf (fout ,"%s\n" ,title );/* Aligned */
647654else
@@ -723,21 +730,22 @@ print_aligned_text(const char *title, const char *const * headers,
723730break ;
724731
725732/*
726- * Format each cell. Format again,it is a numeric formatting locale
733+ * Format each cell. Format again,if it's a numeric formatting locale
727734 * (e.g. 123,456 vs. 123456)
728735 */
729736for (j = 0 ;j < col_count ;j ++ )
730737{
731- pg_wcsformat ((unsignedchar * )ptr [j ],strlen (ptr [j ]),encoding ,col_lineptrs [j ],max_nl_lines [j ]);
738+ pg_wcsformat ((unsignedchar * )ptr [j ],strlen (ptr [j ]),encoding ,
739+ col_lineptrs [j ],max_nl_lines [j ]);
732740curr_nl_line [j ]= 0 ;
733741
734742if (opt_numeric_locale && opt_align [j %col_count ]== 'r' )
735743{
736744char * my_cell ;
737745
738746my_cell = format_numeric_locale ((char * )col_lineptrs [j ]-> ptr );
739- strcpy (( char * ) col_lineptrs [ j ] -> ptr , my_cell ); /* Buffer IS large
740- * enough... now */
747+ /* Buffer IS large enough... now */
748+ strcpy (( char * ) col_lineptrs [ j ] -> ptr , my_cell );
741749free (my_cell );
742750}
743751}
@@ -764,16 +772,22 @@ print_aligned_text(const char *title, const char *const * headers,
764772{
765773/* We have a valid array element, so index it */
766774struct lineptr * this_line = & col_lineptrs [j ][curr_nl_line [j ]];
767- int bytes_to_output ,chars_to_output = width_wrap [j ];
775+ int bytes_to_output ;
776+ int chars_to_output = width_wrap [j ];
777+ bool finalspaces = (opt_border == 2 || j < col_count - 1 );
768778
769- /* Past newline lines so pad for other columns */
770779if (!this_line -> ptr )
771- fprintf (fout ,"%*s" ,width_wrap [j ],"" );
780+ {
781+ /* Past newline lines so just pad for other columns */
782+ if (finalspaces )
783+ fprintf (fout ,"%*s" ,chars_to_output ,"" );
784+ }
772785else
773786{
774- /* Get strlen() of the width_wrap character */
775- bytes_to_output = strlen_max_width (this_line -> ptr +
776- bytes_output [j ],& chars_to_output ,encoding );
787+ /* Get strlen() of the characters up to width_wrap */
788+ bytes_to_output =
789+ strlen_max_width (this_line -> ptr + bytes_output [j ],
790+ & chars_to_output ,encoding );
777791
778792/*
779793 *If we exceeded width_wrap, it means the display width
@@ -796,13 +810,14 @@ print_aligned_text(const char *title, const char *const * headers,
796810/* spaces second */
797811fprintf (fout ,"%.*s" ,bytes_to_output ,
798812this_line -> ptr + bytes_output [j ]);
799- fprintf (fout ,"%*s" ,width_wrap [j ]- chars_to_output ,"" );
813+ if (finalspaces )
814+ fprintf (fout ,"%*s" ,width_wrap [j ]- chars_to_output ,"" );
800815}
801816
802817bytes_output [j ]+= bytes_to_output ;
803818
804819/* Do we have more text to wrap? */
805- if (* (this_line -> ptr + bytes_output [j ])!= 0 )
820+ if (* (this_line -> ptr + bytes_output [j ])!= '\0' )
806821more_lines = true;
807822else
808823{
@@ -814,8 +829,8 @@ print_aligned_text(const char *title, const char *const * headers,
814829}
815830}
816831
817- /* print a divider,middle columns only */
818- if (( j + 1 ) % col_count )
832+ /* print a divider,if not the last column */
833+ if (j < col_count - 1 )
819834{
820835if (opt_border == 0 )
821836fputc (' ' ,fout );
@@ -832,10 +847,9 @@ print_aligned_text(const char *title, const char *const * headers,
832847/* Ordinary line */
833848fputs (" | " ,fout );
834849}
835-
836850}
837851
838- /* end of row border */
852+ /* end-of- row border */
839853if (opt_border == 2 )
840854fputs (" |" ,fout );
841855fputc ('\n' ,fout );
@@ -887,7 +901,7 @@ print_aligned_vertical(const char *title, const char *const * headers,
887901{
888902bool opt_tuples_only = opt -> tuples_only ;
889903bool opt_numeric_locale = opt -> numericLocale ;
890- unsigned shortint opt_border = opt -> border ;
904+ unsigned short opt_border = opt -> border ;
891905int encoding = opt -> encoding ;
892906unsignedint col_count = 0 ;
893907unsigned long record = opt -> prior_records + 1 ;
@@ -927,7 +941,8 @@ print_aligned_vertical(const char *title, const char *const * headers,
927941height ,
928942fs ;
929943
930- pg_wcssize ((unsignedchar * )headers [i ],strlen (headers [i ]),encoding ,& width ,& height ,& fs );
944+ pg_wcssize ((unsignedchar * )headers [i ],strlen (headers [i ]),encoding ,
945+ & width ,& height ,& fs );
931946if (width > hwidth )
932947hwidth = width ;
933948if (height > hheight )
@@ -953,7 +968,8 @@ print_aligned_vertical(const char *title, const char *const * headers,
953968else
954969numeric_locale_len = 0 ;
955970
956- pg_wcssize ((unsignedchar * )* ptr ,strlen (* ptr ),encoding ,& width ,& height ,& fs );
971+ pg_wcssize ((unsignedchar * )* ptr ,strlen (* ptr ),encoding ,
972+ & width ,& height ,& fs );
957973width += numeric_locale_len ;
958974if (width > dwidth )
959975dwidth = width ;
@@ -1041,9 +1057,11 @@ print_aligned_vertical(const char *title, const char *const * headers,
10411057
10421058/* Format the header */
10431059pg_wcsformat ((unsignedchar * )headers [i %col_count ],
1044- strlen (headers [i %col_count ]),encoding ,hlineptr ,hheight );
1060+ strlen (headers [i %col_count ]),
1061+ encoding ,hlineptr ,hheight );
10451062/* Format the data */
1046- pg_wcsformat ((unsignedchar * )* ptr ,strlen (* ptr ),encoding ,dlineptr ,dheight );
1063+ pg_wcsformat ((unsignedchar * )* ptr ,strlen (* ptr ),encoding ,
1064+ dlineptr ,dheight );
10471065
10481066line_count = 0 ;
10491067dcomplete = hcomplete = 0 ;
@@ -1182,7 +1200,7 @@ print_html_text(const char *title, const char *const * headers,
11821200{
11831201bool opt_tuples_only = opt -> tuples_only ;
11841202bool opt_numeric_locale = opt -> numericLocale ;
1185- unsigned shortint opt_border = opt -> border ;
1203+ unsigned short opt_border = opt -> border ;
11861204const char * opt_table_attr = opt -> tableAttr ;
11871205unsignedint col_count = 0 ;
11881206unsignedint i ;
@@ -1283,7 +1301,7 @@ print_html_vertical(const char *title, const char *const * headers,
12831301{
12841302bool opt_tuples_only = opt -> tuples_only ;
12851303bool opt_numeric_locale = opt -> numericLocale ;
1286- unsigned shortint opt_border = opt -> border ;
1304+ unsigned short opt_border = opt -> border ;
12871305const char * opt_table_attr = opt -> tableAttr ;
12881306unsignedint col_count = 0 ;
12891307unsigned long record = opt -> prior_records + 1 ;
@@ -1421,7 +1439,7 @@ print_latex_text(const char *title, const char *const * headers,
14211439{
14221440bool opt_tuples_only = opt -> tuples_only ;
14231441bool opt_numeric_locale = opt -> numericLocale ;
1424- unsigned shortint opt_border = opt -> border ;
1442+ unsigned short opt_border = opt -> border ;
14251443unsignedint col_count = 0 ;
14261444unsignedint i ;
14271445const char * const * ptr ;
@@ -1534,7 +1552,7 @@ print_latex_vertical(const char *title, const char *const * headers,
15341552{
15351553bool opt_tuples_only = opt -> tuples_only ;
15361554bool opt_numeric_locale = opt -> numericLocale ;
1537- unsigned shortint opt_border = opt -> border ;
1555+ unsigned short opt_border = opt -> border ;
15381556unsignedint col_count = 0 ;
15391557unsigned long record = opt -> prior_records + 1 ;
15401558unsignedint i ;
@@ -1661,7 +1679,7 @@ print_troff_ms_text(const char *title, const char *const * headers,
16611679{
16621680bool opt_tuples_only = opt -> tuples_only ;
16631681bool opt_numeric_locale = opt -> numericLocale ;
1664- unsigned shortint opt_border = opt -> border ;
1682+ unsigned short opt_border = opt -> border ;
16651683unsignedint col_count = 0 ;
16661684unsignedint i ;
16671685const char * const * ptr ;
@@ -1764,7 +1782,7 @@ print_troff_ms_vertical(const char *title, const char *const * headers,
17641782{
17651783bool opt_tuples_only = opt -> tuples_only ;
17661784bool opt_numeric_locale = opt -> numericLocale ;
1767- unsigned shortint opt_border = opt -> border ;
1785+ unsigned short opt_border = opt -> border ;
17681786unsignedint col_count = 0 ;
17691787unsigned long record = opt -> prior_records + 1 ;
17701788unsignedint i ;
@@ -1970,7 +1988,7 @@ printTable(const char *title,
19701988static const char * default_footer []= {NULL };
19711989FILE * output ;
19721990bool is_pager = false;
1973-
1991+
19741992if (cancel_pressed )
19751993return ;
19761994
@@ -2216,36 +2234,36 @@ setDecimalLocale(void)
22162234}
22172235
22182236/*
2219- *Returns the bytelength to the end of thespecified character
2220- * and number of display characters processed (useful if the string
2221- *is shorter then dpylen) .
2237+ * Compute the bytedistance to the end of thestring or *target_width
2238+ *display character positions, whichever comes first. Update *target_width
2239+ * to be the number of display character positions actually filled .
22222240 */
22232241static int
22242242strlen_max_width (unsignedchar * str ,int * target_width ,int encoding )
22252243{
22262244unsignedchar * start = str ;
2245+ unsignedchar * end = str + strlen ((char * )str );
22272246int curr_width = 0 ;
22282247
2229- while (* str && curr_width < * target_width )
2248+ while (str < end )
22302249{
22312250int char_width = PQdsplen ((char * )str ,encoding );
22322251
22332252/*
22342253 *If the display width of the new character causes
22352254 *the string to exceed its target width, skip it
22362255 *and return. However, if this is the first character
2237- *of the string (*width == 0), we have to accept it.
2256+ *of the string (curr_width == 0), we have to accept it.
22382257 */
2239- if (* target_width - curr_width < char_width && curr_width != 0 )
2258+ if (* target_width < curr_width + char_width && curr_width != 0 )
22402259break ;
2241-
2242- str += PQmblen ((char * )str ,encoding );
22432260
22442261curr_width += char_width ;
2262+
2263+ str += PQmblen ((char * )str ,encoding );
22452264}
22462265
22472266* target_width = curr_width ;
22482267
2249- /* last byte */
22502268return str - start ;
22512269}