LCOV - differential code coverage report
Current view: top level - src/fe_utils - print.c (source / functions) Coverage Total Hit UNC UBC GBC GNC CBC ECB DUB DCB
Current: a2387c32f2f8a1643c7d71b951587e6bcb2d4744 vs 371a302eecdc82274b0ae2967d18fd726a0aa6a1 Lines: 93.0 % 1634 1519 16 99 15 78 1426 1 5 39
Current Date: 2025-10-26 12:31:50 -0700 Functions: 100.0 % 49 49 7 42 1
Baseline: lcov-20251027-010456-baseline Branches: 83.6 % 1303 1089 22 192 9 54 1026
Baseline Date: 2025-10-26 11:01:32 +1300 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 83.0 % 94 78 16 78
(30,360] days: 0.0 % 2 0 2
(360..) days: 93.7 % 1538 1441 97 15 1426 1
Function coverage date bins:
(7,30] days: 100.0 % 3 3 3
(360..) days: 100.0 % 46 46 4 42
Branch coverage date bins:
(7,30] days: 71.1 % 76 54 22 54
(360..) days: 84.4 % 1227 1035 192 9 1026

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * Query-result printing support for frontend code
                                  4                 :                :  *
                                  5                 :                :  * This file used to be part of psql, but now it's separated out to allow
                                  6                 :                :  * other frontend programs to use it.  Because the printing code needs
                                  7                 :                :  * access to the cancel_pressed flag as well as SIGPIPE trapping and
                                  8                 :                :  * pager open/close functions, all that stuff came with it.
                                  9                 :                :  *
                                 10                 :                :  *
                                 11                 :                :  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
                                 12                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                 13                 :                :  *
                                 14                 :                :  * src/fe_utils/print.c
                                 15                 :                :  *
                                 16                 :                :  *-------------------------------------------------------------------------
                                 17                 :                :  */
                                 18                 :                : #include "postgres_fe.h"
                                 19                 :                : 
                                 20                 :                : #include <limits.h>
                                 21                 :                : #include <math.h>
                                 22                 :                : #include <unistd.h>
                                 23                 :                : 
                                 24                 :                : #ifndef WIN32
                                 25                 :                : #include <sys/ioctl.h>            /* for ioctl() */
                                 26                 :                : #endif
                                 27                 :                : 
                                 28                 :                : #ifdef HAVE_TERMIOS_H
                                 29                 :                : #include <termios.h>
                                 30                 :                : #endif
                                 31                 :                : 
                                 32                 :                : #include "catalog/pg_type_d.h"
                                 33                 :                : #include "fe_utils/mbprint.h"
                                 34                 :                : #include "fe_utils/print.h"
                                 35                 :                : 
                                 36                 :                : /* Presently, count_table_lines() is only used within #ifdef TIOCGWINSZ */
                                 37                 :                : #ifdef TIOCGWINSZ
                                 38                 :                : #define NEED_COUNT_TABLE_LINES
                                 39                 :                : #endif
                                 40                 :                : 
                                 41                 :                : /*
                                 42                 :                :  * If the calling program doesn't have any mechanism for setting
                                 43                 :                :  * cancel_pressed, it will have no effect.
                                 44                 :                :  *
                                 45                 :                :  * Note: print.c's general strategy for when to check cancel_pressed is to do
                                 46                 :                :  * so at completion of each row of output.
                                 47                 :                :  */
                                 48                 :                : volatile sig_atomic_t cancel_pressed = false;
                                 49                 :                : 
                                 50                 :                : static bool always_ignore_sigpipe = false;
                                 51                 :                : 
                                 52                 :                : /* info for locale-aware numeric formatting; set up by setDecimalLocale() */
                                 53                 :                : static char *decimal_point;
                                 54                 :                : static int  groupdigits;
                                 55                 :                : static char *thousands_sep;
                                 56                 :                : 
                                 57                 :                : static char default_footer[100];
                                 58                 :                : static printTableFooter default_footer_cell = {default_footer, NULL};
                                 59                 :                : 
                                 60                 :                : /* Line style control structures */
                                 61                 :                : const printTextFormat pg_asciiformat =
                                 62                 :                : {
                                 63                 :                :     "ascii",
                                 64                 :                :     {
                                 65                 :                :         {"-", "+", "+", "+"},
                                 66                 :                :         {"-", "+", "+", "+"},
                                 67                 :                :         {"-", "+", "+", "+"},
                                 68                 :                :         {"", "|", "|", "|"}
                                 69                 :                :     },
                                 70                 :                :     "|",
                                 71                 :                :     "|",
                                 72                 :                :     "|",
                                 73                 :                :     " ",
                                 74                 :                :     "+",
                                 75                 :                :     " ",
                                 76                 :                :     "+",
                                 77                 :                :     ".",
                                 78                 :                :     ".",
                                 79                 :                :     true
                                 80                 :                : };
                                 81                 :                : 
                                 82                 :                : const printTextFormat pg_asciiformat_old =
                                 83                 :                : {
                                 84                 :                :     "old-ascii",
                                 85                 :                :     {
                                 86                 :                :         {"-", "+", "+", "+"},
                                 87                 :                :         {"-", "+", "+", "+"},
                                 88                 :                :         {"-", "+", "+", "+"},
                                 89                 :                :         {"", "|", "|", "|"}
                                 90                 :                :     },
                                 91                 :                :     ":",
                                 92                 :                :     ";",
                                 93                 :                :     " ",
                                 94                 :                :     "+",
                                 95                 :                :     " ",
                                 96                 :                :     " ",
                                 97                 :                :     " ",
                                 98                 :                :     " ",
                                 99                 :                :     " ",
                                100                 :                :     false
                                101                 :                : };
                                102                 :                : 
                                103                 :                : /* Default unicode linestyle format */
                                104                 :                : printTextFormat pg_utf8format;
                                105                 :                : 
                                106                 :                : typedef struct unicodeStyleRowFormat
                                107                 :                : {
                                108                 :                :     const char *horizontal;
                                109                 :                :     const char *vertical_and_right[2];
                                110                 :                :     const char *vertical_and_left[2];
                                111                 :                : } unicodeStyleRowFormat;
                                112                 :                : 
                                113                 :                : typedef struct unicodeStyleColumnFormat
                                114                 :                : {
                                115                 :                :     const char *vertical;
                                116                 :                :     const char *vertical_and_horizontal[2];
                                117                 :                :     const char *up_and_horizontal[2];
                                118                 :                :     const char *down_and_horizontal[2];
                                119                 :                : } unicodeStyleColumnFormat;
                                120                 :                : 
                                121                 :                : typedef struct unicodeStyleBorderFormat
                                122                 :                : {
                                123                 :                :     const char *up_and_right;
                                124                 :                :     const char *vertical;
                                125                 :                :     const char *down_and_right;
                                126                 :                :     const char *horizontal;
                                127                 :                :     const char *down_and_left;
                                128                 :                :     const char *left_and_right;
                                129                 :                : } unicodeStyleBorderFormat;
                                130                 :                : 
                                131                 :                : typedef struct unicodeStyleFormat
                                132                 :                : {
                                133                 :                :     unicodeStyleRowFormat row_style[2];
                                134                 :                :     unicodeStyleColumnFormat column_style[2];
                                135                 :                :     unicodeStyleBorderFormat border_style[2];
                                136                 :                :     const char *header_nl_left;
                                137                 :                :     const char *header_nl_right;
                                138                 :                :     const char *nl_left;
                                139                 :                :     const char *nl_right;
                                140                 :                :     const char *wrap_left;
                                141                 :                :     const char *wrap_right;
                                142                 :                :     bool        wrap_right_border;
                                143                 :                : } unicodeStyleFormat;
                                144                 :                : 
                                145                 :                : static const unicodeStyleFormat unicode_style = {
                                146                 :                :     {
                                147                 :                :         {
                                148                 :                :             /* U+2500 Box Drawings Light Horizontal */
                                149                 :                :             "\342\224\200",
                                150                 :                : 
                                151                 :                :             /*--
                                152                 :                :              * U+251C Box Drawings Light Vertical and Right,
                                153                 :                :              * U+255F Box Drawings Vertical Double and Right Single
                                154                 :                :              *--
                                155                 :                :              */
                                156                 :                :             {"\342\224\234", "\342\225\237"},
                                157                 :                : 
                                158                 :                :             /*--
                                159                 :                :              * U+2524 Box Drawings Light Vertical and Left,
                                160                 :                :              * U+2562 Box Drawings Vertical Double and Left Single
                                161                 :                :              *--
                                162                 :                :              */
                                163                 :                :             {"\342\224\244", "\342\225\242"},
                                164                 :                :         },
                                165                 :                :         {
                                166                 :                :             /* U+2550 Box Drawings Double Horizontal */
                                167                 :                :             "\342\225\220",
                                168                 :                : 
                                169                 :                :             /*--
                                170                 :                :              * U+255E Box Drawings Vertical Single and Right Double,
                                171                 :                :              * U+2560 Box Drawings Double Vertical and Right
                                172                 :                :              *--
                                173                 :                :              */
                                174                 :                :             {"\342\225\236", "\342\225\240"},
                                175                 :                : 
                                176                 :                :             /*--
                                177                 :                :              * U+2561 Box Drawings Vertical Single and Left Double,
                                178                 :                :              * U+2563 Box Drawings Double Vertical and Left
                                179                 :                :              *--
                                180                 :                :              */
                                181                 :                :             {"\342\225\241", "\342\225\243"},
                                182                 :                :         },
                                183                 :                :     },
                                184                 :                :     {
                                185                 :                :         {
                                186                 :                :             /* U+2502 Box Drawings Light Vertical */
                                187                 :                :             "\342\224\202",
                                188                 :                : 
                                189                 :                :             /*--
                                190                 :                :              * U+253C Box Drawings Light Vertical and Horizontal,
                                191                 :                :              * U+256A Box Drawings Vertical Single and Horizontal Double
                                192                 :                :              *--
                                193                 :                :              */
                                194                 :                :             {"\342\224\274", "\342\225\252"},
                                195                 :                : 
                                196                 :                :             /*--
                                197                 :                :              * U+2534 Box Drawings Light Up and Horizontal,
                                198                 :                :              * U+2567 Box Drawings Up Single and Horizontal Double
                                199                 :                :              *--
                                200                 :                :              */
                                201                 :                :             {"\342\224\264", "\342\225\247"},
                                202                 :                : 
                                203                 :                :             /*--
                                204                 :                :              * U+252C Box Drawings Light Down and Horizontal,
                                205                 :                :              * U+2564 Box Drawings Down Single and Horizontal Double
                                206                 :                :              *--
                                207                 :                :              */
                                208                 :                :             {"\342\224\254", "\342\225\244"},
                                209                 :                :         },
                                210                 :                :         {
                                211                 :                :             /* U+2551 Box Drawings Double Vertical */
                                212                 :                :             "\342\225\221",
                                213                 :                : 
                                214                 :                :             /*--
                                215                 :                :              * U+256B Box Drawings Vertical Double and Horizontal Single,
                                216                 :                :              * U+256C Box Drawings Double Vertical and Horizontal
                                217                 :                :              *--
                                218                 :                :              */
                                219                 :                :             {"\342\225\253", "\342\225\254"},
                                220                 :                : 
                                221                 :                :             /*--
                                222                 :                :              * U+2568 Box Drawings Up Double and Horizontal Single,
                                223                 :                :              * U+2569 Box Drawings Double Up and Horizontal
                                224                 :                :              *--
                                225                 :                :              */
                                226                 :                :             {"\342\225\250", "\342\225\251"},
                                227                 :                : 
                                228                 :                :             /*--
                                229                 :                :              * U+2565 Box Drawings Down Double and Horizontal Single,
                                230                 :                :              * U+2566 Box Drawings Double Down and Horizontal
                                231                 :                :              *--
                                232                 :                :              */
                                233                 :                :             {"\342\225\245", "\342\225\246"},
                                234                 :                :         },
                                235                 :                :     },
                                236                 :                :     {
                                237                 :                :         /*--
                                238                 :                :          * U+2514 Box Drawings Light Up and Right,
                                239                 :                :          * U+2502 Box Drawings Light Vertical,
                                240                 :                :          * U+250C Box Drawings Light Down and Right,
                                241                 :                :          * U+2500 Box Drawings Light Horizontal,
                                242                 :                :          * U+2510 Box Drawings Light Down and Left,
                                243                 :                :          * U+2518 Box Drawings Light Up and Left
                                244                 :                :          *--
                                245                 :                :          */
                                246                 :                :         {"\342\224\224", "\342\224\202", "\342\224\214", "\342\224\200", "\342\224\220", "\342\224\230"},
                                247                 :                : 
                                248                 :                :         /*--
                                249                 :                :          * U+255A Box Drawings Double Up and Right,
                                250                 :                :          * U+2551 Box Drawings Double Vertical,
                                251                 :                :          * U+2554 Box Drawings Double Down and Right,
                                252                 :                :          * U+2550 Box Drawings Double Horizontal,
                                253                 :                :          * U+2557 Box Drawings Double Down and Left,
                                254                 :                :          * U+255D Box Drawings Double Up and Left
                                255                 :                :          *--
                                256                 :                :          */
                                257                 :                :         {"\342\225\232", "\342\225\221", "\342\225\224", "\342\225\220", "\342\225\227", "\342\225\235"},
                                258                 :                :     },
                                259                 :                :     " ",
                                260                 :                :     /* U+21B5 Downwards Arrow with Corner Leftwards */
                                261                 :                :     "\342\206\265",
                                262                 :                :     " ",
                                263                 :                :     /* U+21B5 Downwards Arrow with Corner Leftwards */
                                264                 :                :     "\342\206\265",
                                265                 :                :     /* U+2026 Horizontal Ellipsis */
                                266                 :                :     "\342\200\246",
                                267                 :                :     "\342\200\246",
                                268                 :                :     true
                                269                 :                : };
                                270                 :                : 
                                271                 :                : 
                                272                 :                : /* Local functions */
                                273                 :                : static int  strlen_max_width(unsigned char *str, int *target_width, int encoding);
                                274                 :                : static FILE *PageOutputInternal(int lines, const printTableOpt *topt,
                                275                 :                :                                 const printTableContent *cont,
                                276                 :                :                                 const unsigned int *width_wrap,
                                277                 :                :                                 bool vertical);
                                278                 :                : static void IsPagerNeeded(const printTableContent *cont,
                                279                 :                :                           const unsigned int *width_wrap,
                                280                 :                :                           bool vertical,
                                281                 :                :                           FILE **fout, bool *is_pager);
                                282                 :                : #ifdef NEED_COUNT_TABLE_LINES
                                283                 :                : static int  count_table_lines(const printTableContent *cont,
                                284                 :                :                               const unsigned int *width_wrap,
                                285                 :                :                               bool vertical,
                                286                 :                :                               int threshold);
                                287                 :                : #endif
                                288                 :                : static void print_aligned_vertical(const printTableContent *cont,
                                289                 :                :                                    FILE *fout, bool is_pager);
                                290                 :                : 
                                291                 :                : 
                                292                 :                : /* Count number of digits in integral part of number */
                                293                 :                : static int
 7410 bruce@momjian.us          294                 :CBC          96 : integer_digits(const char *my_str)
                                295                 :                : {
                                296                 :                :     /* ignoring any sign ... */
 3686 tgl@sss.pgh.pa.us         297   [ +  +  -  + ]:             96 :     if (my_str[0] == '-' || my_str[0] == '+')
 7414 bruce@momjian.us          298                 :             18 :         my_str++;
                                299                 :                :     /* ... count initial integral digits */
 3686 tgl@sss.pgh.pa.us         300                 :             96 :     return strspn(my_str, "0123456789");
                                301                 :                : }
                                302                 :                : 
                                303                 :                : /* Compute additional length required for locale-aware numeric output */
                                304                 :                : static int
 7406 bruce@momjian.us          305                 :             48 : additional_numeric_locale_len(const char *my_str)
                                306                 :                : {
 7317                           307                 :             48 :     int         int_len = integer_digits(my_str),
                                308                 :             48 :                 len = 0;
                                309                 :                : 
                                310                 :                :     /* Account for added thousands_sep instances */
 3686 tgl@sss.pgh.pa.us         311         [ -  + ]:             48 :     if (int_len > groupdigits)
 3686 tgl@sss.pgh.pa.us         312                 :UBC           0 :         len += ((int_len - 1) / groupdigits) * strlen(thousands_sep);
                                313                 :                : 
                                314                 :                :     /* Account for possible additional length of decimal_point */
 7406 bruce@momjian.us          315         [ -  + ]:CBC          48 :     if (strchr(my_str, '.') != NULL)
 3686 tgl@sss.pgh.pa.us         316                 :UBC           0 :         len += strlen(decimal_point) - 1;
                                317                 :                : 
 7406 bruce@momjian.us          318                 :CBC          48 :     return len;
                                319                 :                : }
                                320                 :                : 
                                321                 :                : /*
                                322                 :                :  * Format a numeric value per current LC_NUMERIC locale setting
                                323                 :                :  *
                                324                 :                :  * Returns the appropriately formatted string in a new allocated block,
                                325                 :                :  * caller must free.
                                326                 :                :  *
                                327                 :                :  * setDecimalLocale() must have been called earlier.
                                328                 :                :  */
                                329                 :                : static char *
 7335                           330                 :             48 : format_numeric_locale(const char *my_str)
                                331                 :                : {
                                332                 :                :     char       *new_str;
                                333                 :                :     int         new_len,
                                334                 :                :                 int_len,
                                335                 :                :                 leading_digits,
                                336                 :                :                 i,
                                337                 :                :                 new_str_pos;
                                338                 :                : 
                                339                 :                :     /*
                                340                 :                :      * If the string doesn't look like a number, return it unchanged.  This
                                341                 :                :      * check is essential to avoid mangling already-localized "money" values.
                                342                 :                :      */
 3685 tgl@sss.pgh.pa.us         343         [ -  + ]:             48 :     if (strspn(my_str, "0123456789+-.eE") != strlen(my_str))
 3685 tgl@sss.pgh.pa.us         344                 :UBC           0 :         return pg_strdup(my_str);
                                345                 :                : 
 3685 tgl@sss.pgh.pa.us         346                 :CBC          48 :     new_len = strlen(my_str) + additional_numeric_locale_len(my_str);
                                347                 :             48 :     new_str = pg_malloc(new_len + 1);
                                348                 :             48 :     new_str_pos = 0;
                                349                 :             48 :     int_len = integer_digits(my_str);
                                350                 :                : 
                                351                 :                :     /* number of digits in first thousands group */
 3686                           352                 :             48 :     leading_digits = int_len % groupdigits;
                                353         [ +  + ]:             48 :     if (leading_digits == 0)
                                354                 :              9 :         leading_digits = groupdigits;
                                355                 :                : 
                                356                 :                :     /* process sign */
                                357   [ +  +  -  + ]:             48 :     if (my_str[0] == '-' || my_str[0] == '+')
                                358                 :                :     {
                                359                 :              9 :         new_str[new_str_pos++] = my_str[0];
 7335 bruce@momjian.us          360                 :              9 :         my_str++;
                                361                 :                :     }
                                362                 :                : 
                                363                 :                :     /* process integer part of number */
 3686 tgl@sss.pgh.pa.us         364         [ +  + ]:            114 :     for (i = 0; i < int_len; i++)
                                365                 :                :     {
                                366                 :                :         /* Time to insert separator? */
                                367   [ +  +  -  + ]:             66 :         if (i > 0 && --leading_digits == 0)
                                368                 :                :         {
 3686 tgl@sss.pgh.pa.us         369                 :UBC           0 :             strcpy(&new_str[new_str_pos], thousands_sep);
                                370                 :              0 :             new_str_pos += strlen(thousands_sep);
                                371                 :              0 :             leading_digits = groupdigits;
                                372                 :                :         }
 3686 tgl@sss.pgh.pa.us         373                 :CBC          66 :         new_str[new_str_pos++] = my_str[i];
                                374                 :                :     }
                                375                 :                : 
                                376                 :                :     /* handle decimal point if any */
                                377         [ -  + ]:             48 :     if (my_str[i] == '.')
                                378                 :                :     {
 3686 tgl@sss.pgh.pa.us         379                 :UBC           0 :         strcpy(&new_str[new_str_pos], decimal_point);
                                380                 :              0 :         new_str_pos += strlen(decimal_point);
                                381                 :              0 :         i++;
                                382                 :                :     }
                                383                 :                : 
                                384                 :                :     /* copy the rest (fractional digits and/or exponent, and \0 terminator) */
 3686 tgl@sss.pgh.pa.us         385                 :CBC          48 :     strcpy(&new_str[new_str_pos], &my_str[i]);
                                386                 :                : 
                                387                 :                :     /* assert we didn't underestimate new_len (an overestimate is OK) */
                                388         [ -  + ]:             48 :     Assert(strlen(new_str) <= new_len);
                                389                 :                : 
 7335 bruce@momjian.us          390                 :             48 :     return new_str;
                                391                 :                : }
                                392                 :                : 
                                393                 :                : 
                                394                 :                : static void
 5009 peter_e@gmx.net           395                 :        1900160 : print_separator(struct separator sep, FILE *fout)
                                396                 :                : {
                                397         [ -  + ]:        1900160 :     if (sep.separator_zero)
 5009 peter_e@gmx.net           398                 :UBC           0 :         fputc('\000', fout);
 5009 peter_e@gmx.net           399         [ +  - ]:CBC     1900160 :     else if (sep.separator)
                                400                 :        1900160 :         fputs(sep.separator, fout);
                                401                 :        1900160 : }
                                402                 :                : 
                                403                 :                : 
                                404                 :                : /*
                                405                 :                :  * Return the list of explicitly-requested footers or, when applicable, the
                                406                 :                :  * default "(xx rows)" footer.  Always omit the default footer when given
                                407                 :                :  * non-default footers, "\pset footer off", or a specific instruction to that
                                408                 :                :  * effect from a calling backslash command.  Vertical formats number each row,
                                409                 :                :  * making the default footer redundant; they do not call this function.
                                410                 :                :  *
                                411                 :                :  * The return value may point to static storage; do not keep it across calls.
                                412                 :                :  */
                                413                 :                : static printTableFooter *
 4927 rhaas@postgresql.org      414                 :          69223 : footers_with_default(const printTableContent *cont)
                                415                 :                : {
                                416   [ +  +  +  + ]:          69223 :     if (cont->footers == NULL && cont->opt->default_footer)
                                417                 :                :     {
                                418                 :                :         unsigned long total_records;
                                419                 :                : 
                                420                 :          67063 :         total_records = cont->opt->prior_records + cont->nrows;
                                421                 :          67063 :         snprintf(default_footer, sizeof(default_footer),
                                422                 :          67063 :                  ngettext("(%lu row)", "(%lu rows)", total_records),
                                423                 :                :                  total_records);
                                424                 :                : 
                                425                 :          67063 :         return &default_footer_cell;
                                426                 :                :     }
                                427                 :                :     else
                                428                 :           2160 :         return cont->footers;
                                429                 :                : }
                                430                 :                : 
                                431                 :                : 
                                432                 :                : /*************************/
                                433                 :                : /* Unaligned text        */
                                434                 :                : /*************************/
                                435                 :                : 
                                436                 :                : 
                                437                 :                : static void
 6377 alvherre@alvh.no-ip.      438                 :           5361 : print_unaligned_text(const printTableContent *cont, FILE *fout)
                                439                 :                : {
                                440                 :           5361 :     bool        opt_tuples_only = cont->opt->tuples_only;
                                441                 :                :     unsigned int i;
                                442                 :                :     const char *const *ptr;
 9329 bruce@momjian.us          443                 :           5361 :     bool        need_recordsep = false;
                                444                 :                : 
 7075 tgl@sss.pgh.pa.us         445         [ -  + ]:           5361 :     if (cancel_pressed)
 7075 tgl@sss.pgh.pa.us         446                 :UBC           0 :         return;
                                447                 :                : 
 6377 alvherre@alvh.no-ip.      448         [ +  - ]:CBC        5361 :     if (cont->opt->start_table)
                                449                 :                :     {
                                450                 :                :         /* print title */
                                451   [ +  +  +  + ]:           5361 :         if (!opt_tuples_only && cont->title)
                                452                 :                :         {
 5009 peter_e@gmx.net           453                 :              4 :             fputs(cont->title, fout);
                                454                 :              4 :             print_separator(cont->opt->recordSep, fout);
                                455                 :                :         }
                                456                 :                : 
                                457                 :                :         /* print headers */
 7410 bruce@momjian.us          458         [ +  + ]:           5361 :         if (!opt_tuples_only)
                                459                 :                :         {
 6377 alvherre@alvh.no-ip.      460         [ +  + ]:            210 :             for (ptr = cont->headers; *ptr; ptr++)
                                461                 :                :             {
                                462         [ +  + ]:            145 :                 if (ptr != cont->headers)
 5009 peter_e@gmx.net           463                 :             80 :                     print_separator(cont->opt->fieldSep, fout);
 6999 tgl@sss.pgh.pa.us         464                 :            145 :                 fputs(*ptr, fout);
                                465                 :                :             }
                                466                 :             65 :             need_recordsep = true;
                                467                 :                :         }
                                468                 :                :     }
                                469                 :                :     else
                                470                 :                :         /* assume continuing printout */
 9329 bruce@momjian.us          471                 :UBC           0 :         need_recordsep = true;
                                472                 :                : 
                                473                 :                :     /* print cells */
 6377 alvherre@alvh.no-ip.      474         [ +  + ]:CBC     1908732 :     for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
                                475                 :                :     {
 9329 bruce@momjian.us          476         [ +  + ]:        1903371 :         if (need_recordsep)
                                477                 :                :         {
 5009 peter_e@gmx.net           478                 :         972359 :             print_separator(cont->opt->recordSep, fout);
 9329 bruce@momjian.us          479                 :         972359 :             need_recordsep = false;
 7075 tgl@sss.pgh.pa.us         480         [ -  + ]:         972359 :             if (cancel_pressed)
 7075 tgl@sss.pgh.pa.us         481                 :UBC           0 :                 break;
                                482                 :                :         }
 5719 heikki.linnakangas@i      483                 :CBC     1903371 :         fputs(*ptr, fout);
                                484                 :                : 
 6377 alvherre@alvh.no-ip.      485         [ +  + ]:        1903371 :         if ((i + 1) % cont->ncolumns)
 5009 peter_e@gmx.net           486                 :         926042 :             print_separator(cont->opt->fieldSep, fout);
                                487                 :                :         else
 9329 bruce@momjian.us          488                 :         977329 :             need_recordsep = true;
                                489                 :                :     }
                                490                 :                : 
                                491                 :                :     /* print footers */
 6377 alvherre@alvh.no-ip.      492         [ +  - ]:           5361 :     if (cont->opt->stop_table)
                                493                 :                :     {
 4927 rhaas@postgresql.org      494                 :           5361 :         printTableFooter *footers = footers_with_default(cont);
                                495                 :                : 
                                496   [ +  +  +  -  :           5361 :         if (!opt_tuples_only && footers != NULL && !cancel_pressed)
                                              +  - ]
                                497                 :                :         {
                                498                 :                :             printTableFooter *f;
                                499                 :                : 
                                500         [ +  + ]:            131 :             for (f = footers; f; f = f->next)
                                501                 :                :             {
 6999 tgl@sss.pgh.pa.us         502         [ +  - ]:             66 :                 if (need_recordsep)
                                503                 :                :                 {
 5009 peter_e@gmx.net           504                 :             66 :                     print_separator(cont->opt->recordSep, fout);
 6999 tgl@sss.pgh.pa.us         505                 :             66 :                     need_recordsep = false;
                                506                 :                :                 }
 6377 alvherre@alvh.no-ip.      507                 :             66 :                 fputs(f->data, fout);
 6999 tgl@sss.pgh.pa.us         508                 :             66 :                 need_recordsep = true;
                                509                 :                :             }
                                510                 :                :         }
                                511                 :                : 
                                512                 :                :         /*
                                513                 :                :          * The last record is terminated by a newline, independent of the set
                                514                 :                :          * record separator.  But when the record separator is a zero byte, we
                                515                 :                :          * use that (compatible with find -print0 and xargs).
                                516                 :                :          */
                                517         [ +  + ]:           5361 :         if (need_recordsep)
                                518                 :                :         {
 5009 peter_e@gmx.net           519         [ -  + ]:           5035 :             if (cont->opt->recordSep.separator_zero)
 5009 peter_e@gmx.net           520                 :UBC           0 :                 print_separator(cont->opt->recordSep, fout);
                                521                 :                :             else
 5009 peter_e@gmx.net           522                 :CBC        5035 :                 fputc('\n', fout);
                                523                 :                :         }
                                524                 :                :     }
                                525                 :                : }
                                526                 :                : 
                                527                 :                : 
                                528                 :                : static void
 6377 alvherre@alvh.no-ip.      529                 :             52 : print_unaligned_vertical(const printTableContent *cont, FILE *fout)
                                530                 :                : {
                                531                 :             52 :     bool        opt_tuples_only = cont->opt->tuples_only;
                                532                 :                :     unsigned int i;
                                533                 :                :     const char *const *ptr;
 6999 tgl@sss.pgh.pa.us         534                 :             52 :     bool        need_recordsep = false;
                                535                 :                : 
 7075                           536         [ -  + ]:             52 :     if (cancel_pressed)
 7075 tgl@sss.pgh.pa.us         537                 :UBC           0 :         return;
                                538                 :                : 
 6377 alvherre@alvh.no-ip.      539         [ +  - ]:CBC          52 :     if (cont->opt->start_table)
                                540                 :                :     {
                                541                 :                :         /* print title */
                                542   [ +  +  +  + ]:             52 :         if (!opt_tuples_only && cont->title)
                                543                 :                :         {
                                544                 :              3 :             fputs(cont->title, fout);
 6999 tgl@sss.pgh.pa.us         545                 :              3 :             need_recordsep = true;
                                546                 :                :         }
                                547                 :                :     }
                                548                 :                :     else
                                549                 :                :         /* assume continuing printout */
 6999 tgl@sss.pgh.pa.us         550                 :UBC           0 :         need_recordsep = true;
                                551                 :                : 
                                552                 :                :     /* print records */
 6377 alvherre@alvh.no-ip.      553         [ +  + ]:CBC         735 :     for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
                                554                 :                :     {
 6999 tgl@sss.pgh.pa.us         555         [ +  + ]:            683 :         if (need_recordsep)
                                556                 :                :         {
                                557                 :                :             /* record separator is 2 occurrences of recordsep in this mode */
 5009 peter_e@gmx.net           558                 :            286 :             print_separator(cont->opt->recordSep, fout);
                                559                 :            286 :             print_separator(cont->opt->recordSep, fout);
 6999 tgl@sss.pgh.pa.us         560                 :            286 :             need_recordsep = false;
 7075                           561         [ -  + ]:            286 :             if (cancel_pressed)
 7075 tgl@sss.pgh.pa.us         562                 :UBC           0 :                 break;
                                563                 :                :         }
                                564                 :                : 
 6377 alvherre@alvh.no-ip.      565                 :CBC         683 :         fputs(cont->headers[i % cont->ncolumns], fout);
 5009 peter_e@gmx.net           566                 :            683 :         print_separator(cont->opt->fieldSep, fout);
 5719 heikki.linnakangas@i      567                 :            683 :         fputs(*ptr, fout);
                                568                 :                : 
 6377 alvherre@alvh.no-ip.      569         [ +  + ]:            683 :         if ((i + 1) % cont->ncolumns)
 5009 peter_e@gmx.net           570                 :            348 :             print_separator(cont->opt->recordSep, fout);
                                571                 :                :         else
 6999 tgl@sss.pgh.pa.us         572                 :            335 :             need_recordsep = true;
                                573                 :                :     }
                                574                 :                : 
 6377 alvherre@alvh.no-ip.      575         [ +  - ]:             52 :     if (cont->opt->stop_table)
                                576                 :                :     {
                                577                 :                :         /* print footers */
                                578   [ +  +  +  +  :             52 :         if (!opt_tuples_only && cont->footers != NULL && !cancel_pressed)
                                              +  - ]
                                579                 :                :         {
                                580                 :                :             printTableFooter *f;
                                581                 :                : 
 5009 peter_e@gmx.net           582                 :              3 :             print_separator(cont->opt->recordSep, fout);
 6377 alvherre@alvh.no-ip.      583         [ +  + ]:              6 :             for (f = cont->footers; f; f = f->next)
                                584                 :                :             {
 5009 peter_e@gmx.net           585                 :              3 :                 print_separator(cont->opt->recordSep, fout);
 6377 alvherre@alvh.no-ip.      586                 :              3 :                 fputs(f->data, fout);
                                587                 :                :             }
                                588                 :                :         }
                                589                 :                : 
                                590                 :                :         /* see above in print_unaligned_text() */
 4643 peter_e@gmx.net           591         [ +  - ]:             52 :         if (need_recordsep)
                                592                 :                :         {
                                593         [ -  + ]:             52 :             if (cont->opt->recordSep.separator_zero)
 4643 peter_e@gmx.net           594                 :UBC           0 :                 print_separator(cont->opt->recordSep, fout);
                                595                 :                :             else
 4643 peter_e@gmx.net           596                 :CBC          52 :                 fputc('\n', fout);
                                597                 :                :         }
                                598                 :                :     }
                                599                 :                : }
                                600                 :                : 
                                601                 :                : 
                                602                 :                : /********************/
                                603                 :                : /* Aligned text     */
                                604                 :                : /********************/
                                605                 :                : 
                                606                 :                : 
                                607                 :                : /* draw "line" */
                                608                 :                : static void
 6377 alvherre@alvh.no-ip.      609                 :          63729 : _print_horizontal_line(const unsigned int ncolumns, const unsigned int *widths,
                                610                 :                :                        unsigned short border, printTextRule pos,
                                611                 :                :                        const printTextFormat *format,
                                612                 :                :                        FILE *fout)
                                613                 :                : {
 5858 tgl@sss.pgh.pa.us         614                 :          63729 :     const printTextLineFormat *lformat = &format->lrule[pos];
                                615                 :                :     unsigned int i,
                                616                 :                :                 j;
                                617                 :                : 
 9489 bruce@momjian.us          618         [ +  + ]:          63729 :     if (border == 1)
 5858 tgl@sss.pgh.pa.us         619                 :          63633 :         fputs(lformat->hrule, fout);
 9489 bruce@momjian.us          620         [ +  + ]:             96 :     else if (border == 2)
 5858 tgl@sss.pgh.pa.us         621                 :             72 :         fprintf(fout, "%s%s", lformat->leftvrule, lformat->hrule);
                                622                 :                : 
 6377 alvherre@alvh.no-ip.      623         [ +  + ]:         186108 :     for (i = 0; i < ncolumns; i++)
                                624                 :                :     {
 9489 bruce@momjian.us          625         [ +  + ]:        1940785 :         for (j = 0; j < widths[i]; j++)
 5858 tgl@sss.pgh.pa.us         626                 :        1818406 :             fputs(lformat->hrule, fout);
                                627                 :                : 
 6377 alvherre@alvh.no-ip.      628         [ +  + ]:         122379 :         if (i < ncolumns - 1)
                                629                 :                :         {
 9489 bruce@momjian.us          630         [ +  + ]:          58765 :             if (border == 0)
                                631                 :             24 :                 fputc(' ', fout);
                                632                 :                :             else
 5858 tgl@sss.pgh.pa.us         633                 :          58741 :                 fprintf(fout, "%s%s%s", lformat->hrule,
                                634                 :          58741 :                         lformat->midvrule, lformat->hrule);
                                635                 :                :         }
                                636                 :                :     }
                                637                 :                : 
 9489 bruce@momjian.us          638         [ +  + ]:          63729 :     if (border == 2)
 5858 tgl@sss.pgh.pa.us         639                 :             72 :         fprintf(fout, "%s%s", lformat->hrule, lformat->rightvrule);
 9489 bruce@momjian.us          640         [ +  + ]:          63657 :     else if (border == 1)
 5858 tgl@sss.pgh.pa.us         641                 :          63633 :         fputs(lformat->hrule, fout);
                                642                 :                : 
 9489 bruce@momjian.us          643                 :          63729 :     fputc('\n', fout);
                                644                 :          63729 : }
                                645                 :                : 
                                646                 :                : 
                                647                 :                : /*
                                648                 :                :  *  Print pretty boxes around cells.
                                649                 :                :  */
                                650                 :                : static void
 3617 tgl@sss.pgh.pa.us         651                 :          63829 : print_aligned_text(const printTableContent *cont, FILE *fout, bool is_pager)
                                652                 :                : {
 6377 alvherre@alvh.no-ip.      653                 :          63829 :     bool        opt_tuples_only = cont->opt->tuples_only;
                                654                 :          63829 :     int         encoding = cont->opt->encoding;
                                655                 :          63829 :     unsigned short opt_border = cont->opt->border;
 5858 tgl@sss.pgh.pa.us         656                 :          63829 :     const printTextFormat *format = get_line_style(cont->opt);
                                657                 :          63829 :     const printTextLineFormat *dformat = &format->lrule[PRINT_RULE_DATA];
                                658                 :                : 
 5982 bruce@momjian.us          659                 :          63829 :     unsigned int col_count = 0,
                                660                 :          63829 :                 cell_count = 0;
                                661                 :                : 
                                662                 :                :     unsigned int i,
                                663                 :                :                 j;
                                664                 :                : 
                                665                 :                :     unsigned int *width_header,
                                666                 :                :                *max_width,
                                667                 :                :                *width_wrap,
                                668                 :                :                *width_average;
                                669                 :                :     unsigned int *max_nl_lines, /* value split by newlines */
                                670                 :                :                *curr_nl_line,
                                671                 :                :                *max_bytes;
                                672                 :                :     unsigned char **format_buf;
                                673                 :                :     unsigned int width_total;
                                674                 :                :     unsigned int total_header_width;
                                675                 :                : 
                                676                 :                :     const char *const *ptr;
                                677                 :                : 
                                678                 :                :     struct lineptr **col_lineptrs;  /* pointers to line pointer per column */
                                679                 :                : 
                                680                 :                :     bool       *header_done;    /* Have all header lines been output? */
                                681                 :                :     int        *bytes_output;   /* Bytes output for column value */
                                682                 :                :     printTextLineWrap *wrap;    /* Wrap status for each column */
 3050 tgl@sss.pgh.pa.us         683                 :          63829 :     int         output_columns = 0; /* Width of interactive console */
 3617                           684                 :          63829 :     bool        is_local_pager = false;
                                685                 :                : 
 7075                           686         [ -  + ]:          63829 :     if (cancel_pressed)
 7075 tgl@sss.pgh.pa.us         687                 :UBC           0 :         return;
                                688                 :                : 
 6999 tgl@sss.pgh.pa.us         689         [ -  + ]:CBC       63829 :     if (opt_border > 2)
 6999 tgl@sss.pgh.pa.us         690                 :UBC           0 :         opt_border = 2;
                                691                 :                : 
 6377 alvherre@alvh.no-ip.      692         [ +  + ]:CBC       63829 :     if (cont->ncolumns > 0)
                                693                 :                :     {
                                694                 :          63714 :         col_count = cont->ncolumns;
 4773 tgl@sss.pgh.pa.us         695                 :          63714 :         width_header = pg_malloc0(col_count * sizeof(*width_header));
                                696                 :          63714 :         width_average = pg_malloc0(col_count * sizeof(*width_average));
                                697                 :          63714 :         max_width = pg_malloc0(col_count * sizeof(*max_width));
                                698                 :          63714 :         width_wrap = pg_malloc0(col_count * sizeof(*width_wrap));
                                699                 :          63714 :         max_nl_lines = pg_malloc0(col_count * sizeof(*max_nl_lines));
                                700                 :          63714 :         curr_nl_line = pg_malloc0(col_count * sizeof(*curr_nl_line));
                                701                 :          63714 :         col_lineptrs = pg_malloc0(col_count * sizeof(*col_lineptrs));
                                702                 :          63714 :         max_bytes = pg_malloc0(col_count * sizeof(*max_bytes));
                                703                 :          63714 :         format_buf = pg_malloc0(col_count * sizeof(*format_buf));
                                704                 :          63714 :         header_done = pg_malloc0(col_count * sizeof(*header_done));
                                705                 :          63714 :         bytes_output = pg_malloc0(col_count * sizeof(*bytes_output));
                                706                 :          63714 :         wrap = pg_malloc0(col_count * sizeof(*wrap));
                                707                 :                :     }
                                708                 :                :     else
                                709                 :                :     {
 6381 bruce@momjian.us          710                 :            115 :         width_header = NULL;
                                711                 :            115 :         width_average = NULL;
                                712                 :            115 :         max_width = NULL;
                                713                 :            115 :         width_wrap = NULL;
                                714                 :            115 :         max_nl_lines = NULL;
                                715                 :            115 :         curr_nl_line = NULL;
 7199                           716                 :            115 :         col_lineptrs = NULL;
 6381                           717                 :            115 :         max_bytes = NULL;
 7199                           718                 :            115 :         format_buf = NULL;
 6381                           719                 :            115 :         header_done = NULL;
                                720                 :            115 :         bytes_output = NULL;
 5818 tgl@sss.pgh.pa.us         721                 :            115 :         wrap = NULL;
                                722                 :                :     }
                                723                 :                : 
                                724                 :                :     /* scan all column headers, find maximum width and max max_nl_lines */
 8768 bruce@momjian.us          725         [ +  + ]:         186494 :     for (i = 0; i < col_count; i++)
                                726                 :                :     {
                                727                 :                :         int         width,
                                728                 :                :                     nl_lines,
                                729                 :                :                     bytes_required;
                                730                 :                : 
 5160 peter_e@gmx.net           731                 :         122665 :         pg_wcssize((const unsigned char *) cont->headers[i], strlen(cont->headers[i]),
                                732                 :                :                    encoding, &width, &nl_lines, &bytes_required);
 6381 bruce@momjian.us          733         [ +  + ]:         122665 :         if (width > max_width[i])
                                734                 :         122647 :             max_width[i] = width;
                                735         [ +  - ]:         122665 :         if (nl_lines > max_nl_lines[i])
                                736                 :         122665 :             max_nl_lines[i] = nl_lines;
                                737         [ +  - ]:         122665 :         if (bytes_required > max_bytes[i])
                                738                 :         122665 :             max_bytes[i] = bytes_required;
                                739                 :                : 
                                740                 :         122665 :         width_header[i] = width;
                                741                 :                :     }
                                742                 :                : 
                                743                 :                :     /* scan all cells, find maximum width, compute cell_count */
   20 tgl@sss.pgh.pa.us         744         [ +  + ]:GNC      615660 :     for (i = 0, ptr = cont->cells; *ptr; ptr++, cell_count++)
                                745                 :                :     {
                                746                 :                :         int         width,
                                747                 :                :                     nl_lines,
                                748                 :                :                     bytes_required;
                                749                 :                : 
 5160 peter_e@gmx.net           750                 :CBC      551831 :         pg_wcssize((const unsigned char *) *ptr, strlen(*ptr), encoding,
                                751                 :                :                    &width, &nl_lines, &bytes_required);
                                752                 :                : 
   20 tgl@sss.pgh.pa.us         753         [ +  + ]:GNC      551831 :         if (width > max_width[i])
                                754                 :          68582 :             max_width[i] = width;
                                755         [ +  + ]:         551831 :         if (nl_lines > max_nl_lines[i])
                                756                 :            879 :             max_nl_lines[i] = nl_lines;
                                757         [ +  + ]:         551831 :         if (bytes_required > max_bytes[i])
                                758                 :          68863 :             max_bytes[i] = bytes_required;
                                759                 :                : 
                                760                 :         551831 :         width_average[i] += width;
                                761                 :                : 
                                762                 :                :         /* i is the current column number: increment with wrap */
                                763         [ +  + ]:         551831 :         if (++i >= col_count)
                                764                 :         238789 :             i = 0;
                                765                 :                :     }
                                766                 :                : 
                                767                 :                :     /* If we have rows, compute average */
 6381 bruce@momjian.us          768   [ +  +  +  + ]:CBC       63829 :     if (col_count != 0 && cell_count != 0)
                                769                 :                :     {
 5982                           770                 :          60564 :         int         rows = cell_count / col_count;
                                771                 :                : 
 6381                           772         [ +  + ]:         174953 :         for (i = 0; i < col_count; i++)
 6372 tgl@sss.pgh.pa.us         773                 :         114389 :             width_average[i] /= rows;
                                774                 :                :     }
                                775                 :                : 
                                776                 :                :     /* adjust the total display width based on border style */
 9489 bruce@momjian.us          777         [ +  + ]:          63829 :     if (opt_border == 0)
 5818 tgl@sss.pgh.pa.us         778                 :             24 :         width_total = col_count;
 9489 bruce@momjian.us          779         [ +  + ]:          63805 :     else if (opt_border == 1)
 3870                           780         [ +  + ]:          63781 :         width_total = col_count * 3 - ((col_count > 0) ? 1 : 0);
                                781                 :                :     else
 6381                           782                 :             24 :         width_total = col_count * 3 + 1;
                                783                 :          63829 :     total_header_width = width_total;
                                784                 :                : 
 9489                           785         [ +  + ]:         186494 :     for (i = 0; i < col_count; i++)
                                786                 :                :     {
 6381                           787                 :         122665 :         width_total += max_width[i];
                                788                 :         122665 :         total_header_width += width_header[i];
                                789                 :                :     }
                                790                 :                : 
                                791                 :                :     /*
                                792                 :                :      * At this point: max_width[] contains the max width of each column,
                                793                 :                :      * max_nl_lines[] contains the max number of lines in each column,
                                794                 :                :      * max_bytes[] contains the maximum storage space for formatting strings,
                                795                 :                :      * width_total contains the giant width sum.  Now we allocate some memory
                                796                 :                :      * for line pointers.
                                797                 :                :      */
                                798         [ +  + ]:         186494 :     for (i = 0; i < col_count; i++)
                                799                 :                :     {
                                800                 :                :         /* Add entry for ptr == NULL array termination */
 4773 tgl@sss.pgh.pa.us         801                 :         122665 :         col_lineptrs[i] = pg_malloc0((max_nl_lines[i] + 1) *
                                802                 :                :                                      sizeof(**col_lineptrs));
                                803                 :                : 
                                804                 :         122665 :         format_buf[i] = pg_malloc(max_bytes[i] + 1);
                                805                 :                : 
 6381 bruce@momjian.us          806                 :         122665 :         col_lineptrs[i]->ptr = format_buf[i];
                                807                 :                :     }
                                808                 :                : 
                                809                 :                :     /* Default word wrap to the full width, i.e. no word wrap */
                                810         [ +  + ]:         186494 :     for (i = 0; i < col_count; i++)
                                811                 :         122665 :         width_wrap[i] = max_width[i];
                                812                 :                : 
                                813                 :                :     /*
                                814                 :                :      * Choose target output width: \pset columns, or $COLUMNS, or ioctl
                                815                 :                :      */
 6373                           816         [ +  + ]:          63829 :     if (cont->opt->columns > 0)
                                817                 :            675 :         output_columns = cont->opt->columns;
                                818   [ +  -  +  -  :          63154 :     else if ((fout == stdout && isatty(fileno(stdout))) || is_pager)
                                              +  + ]
                                819                 :                :     {
                                820         [ -  + ]:             51 :         if (cont->opt->env_columns > 0)
 6373 bruce@momjian.us          821                 :UBC           0 :             output_columns = cont->opt->env_columns;
                                822                 :                : #ifdef TIOCGWINSZ
                                823                 :                :         else
                                824                 :                :         {
                                825                 :                :             struct winsize screen_size;
                                826                 :                : 
 6373 bruce@momjian.us          827         [ -  + ]:CBC          51 :             if (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) != -1)
 6373 bruce@momjian.us          828                 :UBC           0 :                 output_columns = screen_size.ws_col;
                                829                 :                :         }
                                830                 :                : #endif
                                831                 :                :     }
                                832                 :                : 
 6373 bruce@momjian.us          833         [ +  + ]:CBC       63829 :     if (cont->opt->format == PRINT_WRAPPED)
                                834                 :                :     {
                                835                 :                :         /*
                                836                 :                :          * Optional optimized word wrap. Shrink columns with a high max/avg
                                837                 :                :          * ratio.  Slightly bias against wider columns. (Increases chance a
                                838                 :                :          * narrow column will fit in its cell.)  If available columns is
                                839                 :                :          * positive...  and greater than the width of the unshrinkable column
                                840                 :                :          * headers
                                841                 :                :          */
 6381                           842   [ +  -  +  + ]:             72 :         if (output_columns > 0 && output_columns >= total_header_width)
                                843                 :                :         {
                                844                 :                :             /* While there is still excess width... */
                                845         [ +  + ]:            132 :             while (width_total > output_columns)
                                846                 :                :             {
                                847                 :             96 :                 double      max_ratio = 0;
                                848                 :             96 :                 int         worst_col = -1;
                                849                 :                : 
                                850                 :                :                 /*
                                851                 :                :                  * Find column that has the highest ratio of its maximum width
                                852                 :                :                  * compared to its average width.  This tells us which column
                                853                 :                :                  * will produce the fewest wrapped values if shortened.
                                854                 :                :                  * width_wrap starts as equal to max_width.
                                855                 :                :                  */
                                856         [ +  + ]:            288 :                 for (i = 0; i < col_count; i++)
                                857                 :                :                 {
                                858   [ +  -  +  - ]:            192 :                     if (width_average[i] && width_wrap[i] > width_header[i])
                                859                 :                :                     {
                                860                 :                :                         /* Penalize wide columns by 1% of their width */
                                861                 :                :                         double      ratio;
                                862                 :                : 
 6379 tgl@sss.pgh.pa.us         863                 :            192 :                         ratio = (double) width_wrap[i] / width_average[i] +
                                864                 :            192 :                             max_width[i] * 0.01;
 6381 bruce@momjian.us          865         [ +  + ]:            192 :                         if (ratio > max_ratio)
                                866                 :                :                         {
                                867                 :            126 :                             max_ratio = ratio;
                                868                 :            126 :                             worst_col = i;
                                869                 :                :                         }
                                870                 :                :                     }
                                871                 :                :                 }
                                872                 :                : 
                                873                 :                :                 /* Exit loop if we can't squeeze any more. */
                                874         [ -  + ]:             96 :                 if (worst_col == -1)
 6381 bruce@momjian.us          875                 :UBC           0 :                     break;
                                876                 :                : 
                                877                 :                :                 /* Decrease width of target column by one. */
 6381 bruce@momjian.us          878                 :CBC          96 :                 width_wrap[worst_col]--;
                                879                 :             96 :                 width_total--;
                                880                 :                :             }
                                881                 :                :         }
                                882                 :                :     }
                                883                 :                : 
                                884                 :                :     /*
                                885                 :                :      * If in expanded auto mode, we have now calculated the expected width, so
                                886                 :                :      * we can now escape to vertical mode if necessary.  If the output has
                                887                 :                :      * only one column, the expanded format would be wider than the regular
                                888                 :                :      * format, so don't use it in that case.
                                889                 :                :      */
 3517 rhaas@postgresql.org      890   [ -  +  -  -  :          63829 :     if (cont->opt->expanded == 2 && output_columns > 0 && cont->ncolumns > 1 &&
                                              -  - ]
 5098 peter_e@gmx.net           891   [ #  #  #  # ]:UBC           0 :         (output_columns < total_header_width || output_columns < width_total))
                                892                 :                :     {
 3617 tgl@sss.pgh.pa.us         893                 :              0 :         print_aligned_vertical(cont, fout, is_pager);
 4982 peter_e@gmx.net           894                 :              0 :         goto cleanup;
                                895                 :                :     }
                                896                 :                : 
                                897                 :                :     /* If we wrapped beyond the display width, use the pager */
 6372 bruce@momjian.us          898   [ +  +  +  +  :CBC       63829 :     if (!is_pager && fout == stdout && output_columns > 0 &&
                                              +  + ]
 6373                           899   [ +  +  +  + ]:            639 :         (output_columns < total_header_width || output_columns < width_total))
                                900                 :                :     {
 3866 andrew@dunslane.net       901                 :            306 :         fout = PageOutput(INT_MAX, cont->opt);   /* force pager */
 3617 tgl@sss.pgh.pa.us         902                 :            306 :         is_pager = is_local_pager = true;
                                903                 :                :     }
                                904                 :                : 
                                905                 :                :     /* Check if there are enough lines to require the pager */
   20 tgl@sss.pgh.pa.us         906         [ +  + ]:GNC       63829 :     if (!is_pager)
                                907                 :                :     {
                                908                 :          63460 :         IsPagerNeeded(cont, width_wrap, false, &fout, &is_pager);
 3617 tgl@sss.pgh.pa.us         909                 :CBC       63460 :         is_local_pager = is_pager;
                                910                 :                :     }
                                911                 :                : 
                                912                 :                :     /* time to output */
 6377 alvherre@alvh.no-ip.      913         [ +  + ]:          63829 :     if (cont->opt->start_table)
                                914                 :                :     {
                                915                 :                :         /* print title */
                                916   [ +  +  +  + ]:          63793 :         if (cont->title && !opt_tuples_only)
                                917                 :                :         {
                                918                 :                :             int         width,
                                919                 :                :                         height;
                                920                 :                : 
 5160 peter_e@gmx.net           921                 :           2913 :             pg_wcssize((const unsigned char *) cont->title, strlen(cont->title),
                                922                 :                :                        encoding, &width, &height, NULL);
 6381 bruce@momjian.us          923         [ +  + ]:           2913 :             if (width >= width_total)
                                924                 :                :                 /* Aligned */
 6377 alvherre@alvh.no-ip.      925                 :            126 :                 fprintf(fout, "%s\n", cont->title);
                                926                 :                :             else
                                927                 :                :                 /* Centered */
                                928                 :           2787 :                 fprintf(fout, "%-*s%s\n", (width_total - width) / 2, "",
                                929                 :           2787 :                         cont->title);
                                930                 :                :         }
                                931                 :                : 
                                932                 :                :         /* print headers */
 6999 tgl@sss.pgh.pa.us         933         [ +  + ]:          63793 :         if (!opt_tuples_only)
                                934                 :                :         {
                                935                 :                :             int         more_col_wrapping;
                                936                 :                :             int         curr_nl_line;
                                937                 :                : 
 7199 bruce@momjian.us          938         [ +  + ]:          63681 :             if (opt_border == 2)
 5858 tgl@sss.pgh.pa.us         939                 :             24 :                 _print_horizontal_line(col_count, width_wrap, opt_border,
                                940                 :                :                                        PRINT_RULE_TOP, format, fout);
                                941                 :                : 
 7199 bruce@momjian.us          942         [ +  + ]:         185964 :             for (i = 0; i < col_count; i++)
 5160 peter_e@gmx.net           943                 :         122283 :                 pg_wcsformat((const unsigned char *) cont->headers[i],
 6377 alvherre@alvh.no-ip.      944                 :         122283 :                              strlen(cont->headers[i]), encoding,
                                945                 :         122283 :                              col_lineptrs[i], max_nl_lines[i]);
                                946                 :                : 
 6381 bruce@momjian.us          947                 :          63681 :             more_col_wrapping = col_count;
                                948                 :          63681 :             curr_nl_line = 0;
 1334 tgl@sss.pgh.pa.us         949         [ +  + ]:          63681 :             if (col_count > 0)
                                950                 :          63566 :                 memset(header_done, false, col_count * sizeof(bool));
 6381 bruce@momjian.us          951         [ +  + ]:         127319 :             while (more_col_wrapping)
                                952                 :                :             {
 6999 tgl@sss.pgh.pa.us         953         [ +  + ]:          63638 :                 if (opt_border == 2)
 5818                           954                 :             48 :                     fputs(dformat->leftvrule, fout);
                                955                 :                : 
 6377 alvherre@alvh.no-ip.      956         [ +  + ]:         186065 :                 for (i = 0; i < cont->ncolumns; i++)
                                957                 :                :                 {
 6381 bruce@momjian.us          958                 :         122427 :                     struct lineptr *this_line = col_lineptrs[i] + curr_nl_line;
                                959                 :                :                     unsigned int nbspace;
                                960                 :                : 
 5818 tgl@sss.pgh.pa.us         961         [ +  + ]:         122427 :                     if (opt_border != 0 ||
 5461 rhaas@postgresql.org      962   [ +  +  +  + ]:             96 :                         (!format->wrap_right_border && i > 0))
 5818 tgl@sss.pgh.pa.us         963         [ +  + ]:         122355 :                         fputs(curr_nl_line ? format->header_nl_left : " ",
                                964                 :                :                               fout);
                                965                 :                : 
 6381 bruce@momjian.us          966         [ +  + ]:         122427 :                     if (!header_done[i])
                                967                 :                :                     {
                                968                 :         122391 :                         nbspace = width_wrap[i] - this_line->width;
                                969                 :                : 
                                970                 :                :                         /* centered */
 6999 tgl@sss.pgh.pa.us         971                 :         122391 :                         fprintf(fout, "%-*s%s%-*s",
                                972                 :         122391 :                                 nbspace / 2, "", this_line->ptr, (nbspace + 1) / 2, "");
                                973                 :                : 
 6381 bruce@momjian.us          974         [ +  + ]:         122391 :                         if (!(this_line + 1)->ptr)
                                975                 :                :                         {
                                976                 :         122283 :                             more_col_wrapping--;
                                977                 :         122283 :                             header_done[i] = 1;
                                978                 :                :                         }
                                979                 :                :                     }
                                980                 :                :                     else
                                981                 :             36 :                         fprintf(fout, "%*s", width_wrap[i], "");
                                982                 :                : 
 5461 rhaas@postgresql.org      983   [ +  +  +  + ]:         122427 :                     if (opt_border != 0 || format->wrap_right_border)
 5818 tgl@sss.pgh.pa.us         984         [ +  + ]:         122379 :                         fputs(!header_done[i] ? format->header_nl_right : " ",
                                985                 :                :                               fout);
                                986                 :                : 
 3870 bruce@momjian.us          987   [ +  +  +  -  :         122427 :                     if (opt_border != 0 && col_count > 0 && i < col_count - 1)
                                              +  + ]
 5818 tgl@sss.pgh.pa.us         988                 :          58741 :                         fputs(dformat->midvrule, fout);
                                989                 :                :                 }
 6381 bruce@momjian.us          990                 :          63638 :                 curr_nl_line++;
                                991                 :                : 
 6999 tgl@sss.pgh.pa.us         992         [ +  + ]:          63638 :                 if (opt_border == 2)
 5818                           993                 :             48 :                     fputs(dformat->rightvrule, fout);
 6999                           994                 :          63638 :                 fputc('\n', fout);
                                995                 :                :             }
                                996                 :                : 
 5858                           997                 :          63681 :             _print_horizontal_line(col_count, width_wrap, opt_border,
                                998                 :                :                                    PRINT_RULE_MIDDLE, format, fout);
                                999                 :                :         }
                               1000                 :                :     }
                               1001                 :                : 
                               1002                 :                :     /* print cells, one loop per row */
 6377 alvherre@alvh.no-ip.     1003         [ +  + ]:         302618 :     for (i = 0, ptr = cont->cells; *ptr; i += col_count, ptr += col_count)
                               1004                 :                :     {
                               1005                 :                :         bool        more_lines;
                               1006                 :                : 
 7075 tgl@sss.pgh.pa.us        1007         [ -  + ]:         238789 :         if (cancel_pressed)
 7075 tgl@sss.pgh.pa.us        1008                 :UBC           0 :             break;
                               1009                 :                : 
                               1010                 :                :         /*
                               1011                 :                :          * Format each cell.
                               1012                 :                :          */
 7199 bruce@momjian.us         1013         [ +  + ]:CBC      790620 :         for (j = 0; j < col_count; j++)
                               1014                 :                :         {
 5160 peter_e@gmx.net          1015                 :         551831 :             pg_wcsformat((const unsigned char *) ptr[j], strlen(ptr[j]), encoding,
 6379 tgl@sss.pgh.pa.us        1016                 :         551831 :                          col_lineptrs[j], max_nl_lines[j]);
 6381 bruce@momjian.us         1017                 :         551831 :             curr_nl_line[j] = 0;
                               1018                 :                :         }
                               1019                 :                : 
                               1020                 :         238789 :         memset(bytes_output, 0, col_count * sizeof(int));
                               1021                 :                : 
                               1022                 :                :         /*
                               1023                 :                :          * Each time through this loop, one display line is output. It can
                               1024                 :                :          * either be a full value or a partial value if embedded newlines
                               1025                 :                :          * exist or if 'format=wrapping' mode is enabled.
                               1026                 :                :          */
                               1027                 :                :         do
                               1028                 :                :         {
                               1029                 :         247897 :             more_lines = false;
                               1030                 :                : 
                               1031                 :                :             /* left border */
 9489                          1032         [ +  + ]:         247897 :             if (opt_border == 2)
 5818 tgl@sss.pgh.pa.us        1033                 :            276 :                 fputs(dformat->leftvrule, fout);
                               1034                 :                : 
                               1035                 :                :             /* for each column */
 7199 bruce@momjian.us         1036         [ +  + ]:         810783 :             for (j = 0; j < col_count; j++)
                               1037                 :                :             {
                               1038                 :                :                 /* We have a valid array element, so index it */
 6381                          1039                 :         562886 :                 struct lineptr *this_line = &col_lineptrs[j][curr_nl_line[j]];
                               1040                 :                :                 int         bytes_to_output;
 5982                          1041                 :         562886 :                 int         chars_to_output = width_wrap[j];
 3870                          1042   [ +  +  +  - ]:        1125220 :                 bool        finalspaces = (opt_border == 2 ||
 3050 tgl@sss.pgh.pa.us        1043         [ +  + ]:         562334 :                                            (col_count > 0 && j < col_count - 1));
                               1044                 :                : 
                               1045                 :                :                 /* Print left-hand wrap or newline mark */
 5818                          1046         [ +  + ]:         562886 :                 if (opt_border != 0)
                               1047                 :                :                 {
                               1048         [ +  + ]:         562406 :                     if (wrap[j] == PRINT_LINE_WRAP_WRAP)
                               1049                 :             60 :                         fputs(format->wrap_left, fout);
                               1050         [ +  + ]:         562346 :                     else if (wrap[j] == PRINT_LINE_WRAP_NEWLINE)
                               1051                 :           9147 :                         fputs(format->nl_left, fout);
                               1052                 :                :                     else
                               1053                 :         553199 :                         fputc(' ', fout);
                               1054                 :                :                 }
                               1055                 :                : 
 6381 bruce@momjian.us         1056         [ +  + ]:         562886 :                 if (!this_line->ptr)
                               1057                 :                :                 {
                               1058                 :                :                     /* Past newline lines so just pad for other columns */
 6379 tgl@sss.pgh.pa.us        1059         [ +  + ]:           1656 :                     if (finalspaces)
                               1060                 :           1417 :                         fprintf(fout, "%*s", chars_to_output, "");
                               1061                 :                :                 }
                               1062                 :                :                 else
                               1063                 :                :                 {
                               1064                 :                :                     /* Get strlen() of the characters up to width_wrap */
                               1065                 :                :                     bytes_to_output =
                               1066                 :         561230 :                         strlen_max_width(this_line->ptr + bytes_output[j],
                               1067                 :                :                                          &chars_to_output, encoding);
                               1068                 :                : 
                               1069                 :                :                     /*
                               1070                 :                :                      * If we exceeded width_wrap, it means the display width
                               1071                 :                :                      * of a single character was wider than our target width.
                               1072                 :                :                      * In that case, we have to pretend we are only printing
                               1073                 :                :                      * the target display width and make the best of it.
                               1074                 :                :                      */
 6381 bruce@momjian.us         1075         [ -  + ]:         561230 :                     if (chars_to_output > width_wrap[j])
 6381 bruce@momjian.us         1076                 :UBC           0 :                         chars_to_output = width_wrap[j];
                               1077                 :                : 
 5982 bruce@momjian.us         1078         [ +  + ]:CBC      561230 :                     if (cont->aligns[j] == 'r') /* Right aligned cell */
                               1079                 :                :                     {
                               1080                 :                :                         /* spaces first */
 6381                          1081                 :         222232 :                         fprintf(fout, "%*s", width_wrap[j] - chars_to_output, "");
 1946 tgl@sss.pgh.pa.us        1082                 :         222232 :                         fwrite((char *) (this_line->ptr + bytes_output[j]),
                               1083                 :                :                                1, bytes_to_output, fout);
                               1084                 :                :                     }
                               1085                 :                :                     else        /* Left aligned cell */
                               1086                 :                :                     {
                               1087                 :                :                         /* spaces second */
                               1088                 :         338998 :                         fwrite((char *) (this_line->ptr + bytes_output[j]),
                               1089                 :                :                                1, bytes_to_output, fout);
                               1090                 :                :                     }
                               1091                 :                : 
 6381 bruce@momjian.us         1092                 :         561230 :                     bytes_output[j] += bytes_to_output;
                               1093                 :                : 
                               1094                 :                :                     /* Do we have more text to wrap? */
 6379 tgl@sss.pgh.pa.us        1095         [ +  + ]:         561230 :                     if (*(this_line->ptr + bytes_output[j]) != '\0')
 6381 bruce@momjian.us         1096                 :             60 :                         more_lines = true;
                               1097                 :                :                     else
                               1098                 :                :                     {
                               1099                 :                :                         /* Advance to next newline line */
                               1100                 :         561170 :                         curr_nl_line[j]++;
                               1101         [ +  + ]:         561170 :                         if (col_lineptrs[j][curr_nl_line[j]].ptr != NULL)
                               1102                 :           9339 :                             more_lines = true;
                               1103                 :         561170 :                         bytes_output[j] = 0;
                               1104                 :                :                     }
                               1105                 :                :                 }
                               1106                 :                : 
                               1107                 :                :                 /* Determine next line's wrap status for this column */
 5818 tgl@sss.pgh.pa.us        1108                 :         562886 :                 wrap[j] = PRINT_LINE_WRAP_NONE;
                               1109         [ +  + ]:         562886 :                 if (col_lineptrs[j][curr_nl_line[j]].ptr != NULL)
                               1110                 :                :                 {
                               1111         [ +  + ]:           9399 :                     if (bytes_output[j] != 0)
                               1112                 :             60 :                         wrap[j] = PRINT_LINE_WRAP_WRAP;
                               1113         [ +  - ]:           9339 :                     else if (curr_nl_line[j] != 0)
                               1114                 :           9339 :                         wrap[j] = PRINT_LINE_WRAP_NEWLINE;
                               1115                 :                :                 }
                               1116                 :                : 
                               1117                 :                :                 /*
                               1118                 :                :                  * If left-aligned, pad out remaining space if needed (not
                               1119                 :                :                  * last column, and/or wrap marks required).
                               1120                 :                :                  */
 3050                          1121         [ +  + ]:         562886 :                 if (cont->aligns[j] != 'r') /* Left aligned cell */
                               1122                 :                :                 {
 5818                          1123         [ +  + ]:         340422 :                     if (finalspaces ||
                               1124         [ +  + ]:         176398 :                         wrap[j] == PRINT_LINE_WRAP_WRAP ||
 5722 bruce@momjian.us         1125         [ +  + ]:         176392 :                         wrap[j] == PRINT_LINE_WRAP_NEWLINE)
 5818 tgl@sss.pgh.pa.us        1126                 :         172761 :                         fprintf(fout, "%*s",
                               1127                 :         172761 :                                 width_wrap[j] - chars_to_output, "");
                               1128                 :                :                 }
                               1129                 :                : 
                               1130                 :                :                 /* Print right-hand wrap or newline mark */
                               1131         [ +  + ]:         562886 :                 if (wrap[j] == PRINT_LINE_WRAP_WRAP)
                               1132                 :             60 :                     fputs(format->wrap_right, fout);
                               1133         [ +  + ]:         562826 :                 else if (wrap[j] == PRINT_LINE_WRAP_NEWLINE)
                               1134                 :           9339 :                     fputs(format->nl_right, fout);
 3870 bruce@momjian.us         1135   [ +  +  +  -  :         553487 :                 else if (opt_border == 2 || (col_count > 0 && j < col_count - 1))
                                              +  + ]
 5818 tgl@sss.pgh.pa.us        1136                 :         314603 :                     fputc(' ', fout);
                               1137                 :                : 
                               1138                 :                :                 /* Print column divider, if not the last column */
 3870 bruce@momjian.us         1139   [ +  +  +  -  :         562886 :                 if (opt_border != 0 && (col_count > 0 && j < col_count - 1))
                                              +  + ]
                               1140                 :                :                 {
 5722                          1141         [ +  + ]:         314749 :                     if (wrap[j + 1] == PRINT_LINE_WRAP_WRAP)
 5818 tgl@sss.pgh.pa.us        1142                 :             18 :                         fputs(format->midvrule_wrap, fout);
 5722 bruce@momjian.us         1143         [ +  + ]:         314731 :                     else if (wrap[j + 1] == PRINT_LINE_WRAP_NEWLINE)
 5818 tgl@sss.pgh.pa.us        1144                 :            601 :                         fputs(format->midvrule_nl, fout);
 5982 bruce@momjian.us         1145         [ +  + ]:         314130 :                     else if (col_lineptrs[j + 1][curr_nl_line[j + 1]].ptr == NULL)
 5818 tgl@sss.pgh.pa.us        1146                 :           1232 :                         fputs(format->midvrule_blank, fout);
                               1147                 :                :                     else
                               1148                 :         312898 :                         fputs(dformat->midvrule, fout);
                               1149                 :                :                 }
                               1150                 :                :             }
                               1151                 :                : 
                               1152                 :                :             /* end-of-row border */
 9489 bruce@momjian.us         1153         [ +  + ]:         247897 :             if (opt_border == 2)
 5818 tgl@sss.pgh.pa.us        1154                 :            276 :                 fputs(dformat->rightvrule, fout);
 9489 bruce@momjian.us         1155                 :         247897 :             fputc('\n', fout);
 6381                          1156         [ +  + ]:         247897 :         } while (more_lines);
                               1157                 :                :     }
                               1158                 :                : 
 6377 alvherre@alvh.no-ip.     1159         [ +  + ]:          63829 :     if (cont->opt->stop_table)
                               1160                 :                :     {
 4927 rhaas@postgresql.org     1161                 :          63790 :         printTableFooter *footers = footers_with_default(cont);
                               1162                 :                : 
 6999 tgl@sss.pgh.pa.us        1163   [ +  +  +  - ]:          63790 :         if (opt_border == 2 && !cancel_pressed)
 5858                          1164                 :             24 :             _print_horizontal_line(col_count, width_wrap, opt_border,
                               1165                 :                :                                    PRINT_RULE_BOTTOM, format, fout);
                               1166                 :                : 
                               1167                 :                :         /* print footers */
 4927 rhaas@postgresql.org     1168   [ +  +  +  +  :          63790 :         if (footers && !opt_tuples_only && !cancel_pressed)
                                              +  - ]
                               1169                 :                :         {
                               1170                 :                :             printTableFooter *f;
                               1171                 :                : 
                               1172         [ +  + ]:         130938 :             for (f = footers; f; f = f->next)
 6377 alvherre@alvh.no-ip.     1173                 :          67528 :                 fprintf(fout, "%s\n", f->data);
                               1174                 :                :         }
                               1175                 :                : 
 6999 tgl@sss.pgh.pa.us        1176                 :          63790 :         fputc('\n', fout);
                               1177                 :                :     }
                               1178                 :                : 
 4982 peter_e@gmx.net          1179                 :             39 : cleanup:
                               1180                 :                :     /* clean up */
 5749 tgl@sss.pgh.pa.us        1181         [ +  + ]:         186494 :     for (i = 0; i < col_count; i++)
                               1182                 :                :     {
                               1183                 :         122665 :         free(col_lineptrs[i]);
                               1184                 :         122665 :         free(format_buf[i]);
                               1185                 :                :     }
 6381 bruce@momjian.us         1186                 :          63829 :     free(width_header);
                               1187                 :          63829 :     free(width_average);
                               1188                 :          63829 :     free(max_width);
                               1189                 :          63829 :     free(width_wrap);
                               1190                 :          63829 :     free(max_nl_lines);
                               1191                 :          63829 :     free(curr_nl_line);
 7199                          1192                 :          63829 :     free(col_lineptrs);
 6381                          1193                 :          63829 :     free(max_bytes);
 5749 tgl@sss.pgh.pa.us        1194                 :          63829 :     free(format_buf);
 6381 bruce@momjian.us         1195                 :          63829 :     free(header_done);
                               1196                 :          63829 :     free(bytes_output);
 5749 tgl@sss.pgh.pa.us        1197                 :          63829 :     free(wrap);
                               1198                 :                : 
 3617                          1199         [ +  + ]:          63829 :     if (is_local_pager)
 6373 bruce@momjian.us         1200                 :            306 :         ClosePager(fout);
                               1201                 :                : }
                               1202                 :                : 
                               1203                 :                : 
                               1204                 :                : static void
 1190 andrew@dunslane.net      1205                 :            820 : print_aligned_vertical_line(const printTableOpt *topt,
                               1206                 :                :                             unsigned long record,
                               1207                 :                :                             unsigned int hwidth,
                               1208                 :                :                             unsigned int dwidth,
                               1209                 :                :                             int output_columns,
                               1210                 :                :                             printTextRule pos,
                               1211                 :                :                             FILE *fout)
                               1212                 :                : {
                               1213                 :            820 :     const printTextLineFormat *lformat = &get_line_style(topt)->lrule[pos];
                               1214                 :            820 :     const unsigned short opt_border = topt->border;
                               1215                 :                :     unsigned int i;
 5722 bruce@momjian.us         1216                 :            820 :     int         reclen = 0;
                               1217                 :                : 
 5858 tgl@sss.pgh.pa.us        1218         [ +  + ]:            820 :     if (opt_border == 2)
                               1219                 :            234 :         fprintf(fout, "%s%s", lformat->leftvrule, lformat->hrule);
                               1220         [ +  + ]:            586 :     else if (opt_border == 1)
                               1221                 :            382 :         fputs(lformat->hrule, fout);
                               1222                 :                : 
                               1223         [ +  + ]:            820 :     if (record)
                               1224                 :                :     {
                               1225         [ +  + ]:            781 :         if (opt_border == 0)
                               1226                 :            204 :             reclen = fprintf(fout, "* Record %lu", record);
                               1227                 :                :         else
                               1228                 :            577 :             reclen = fprintf(fout, "[ RECORD %lu ]", record);
                               1229                 :                :     }
                               1230         [ +  + ]:            820 :     if (opt_border != 2)
                               1231                 :            586 :         reclen++;
                               1232         [ -  + ]:            820 :     if (reclen < 0)
 5858 tgl@sss.pgh.pa.us        1233                 :UBC           0 :         reclen = 0;
 5858 tgl@sss.pgh.pa.us        1234         [ +  + ]:CBC        3886 :     for (i = reclen; i < hwidth; i++)
                               1235         [ +  + ]:           3066 :         fputs(opt_border > 0 ? lformat->hrule : " ", fout);
                               1236                 :            820 :     reclen -= hwidth;
                               1237                 :                : 
                               1238         [ +  + ]:            820 :     if (opt_border > 0)
                               1239                 :                :     {
                               1240         [ +  + ]:            616 :         if (reclen-- <= 0)
                               1241                 :            517 :             fputs(lformat->hrule, fout);
                               1242         [ +  + ]:            616 :         if (reclen-- <= 0)
                               1243                 :                :         {
 1190 andrew@dunslane.net      1244         [ -  + ]:            520 :             if (topt->expanded_header_width_type == PRINT_XHEADER_COLUMN)
                               1245                 :                :             {
 1190 andrew@dunslane.net      1246                 :UBC           0 :                 fputs(lformat->rightvrule, fout);
                               1247                 :                :             }
                               1248                 :                :             else
                               1249                 :                :             {
 1190 andrew@dunslane.net      1250                 :CBC         520 :                 fputs(lformat->midvrule, fout);
                               1251                 :                :             }
                               1252                 :                :         }
                               1253         [ +  + ]:            616 :         if (reclen-- <= 0
                               1254         [ +  - ]:            532 :             && topt->expanded_header_width_type != PRINT_XHEADER_COLUMN)
 5858 tgl@sss.pgh.pa.us        1255                 :            532 :             fputs(lformat->hrule, fout);
                               1256                 :                :     }
                               1257                 :                :     else
                               1258                 :                :     {
                               1259         [ +  + ]:            204 :         if (reclen-- <= 0)
                               1260                 :            180 :             fputc(' ', fout);
                               1261                 :                :     }
                               1262                 :                : 
 1190 andrew@dunslane.net      1263         [ +  - ]:            820 :     if (topt->expanded_header_width_type != PRINT_XHEADER_COLUMN)
                               1264                 :                :     {
                               1265         [ +  - ]:            820 :         if (topt->expanded_header_width_type == PRINT_XHEADER_PAGE
                               1266         [ -  + ]:            820 :             || topt->expanded_header_width_type == PRINT_XHEADER_EXACT_WIDTH)
                               1267                 :                :         {
 1190 andrew@dunslane.net      1268         [ #  # ]:UBC           0 :             if (topt->expanded_header_width_type == PRINT_XHEADER_EXACT_WIDTH)
                               1269                 :                :             {
                               1270                 :              0 :                 output_columns = topt->expanded_header_exact_width;
                               1271                 :                :             }
                               1272         [ #  # ]:              0 :             if (output_columns > 0)
                               1273                 :                :             {
                               1274         [ #  # ]:              0 :                 if (opt_border == 0)
                               1275                 :              0 :                     dwidth = Min(dwidth, Max(0, (int) (output_columns - hwidth)));
                               1276         [ #  # ]:              0 :                 if (opt_border == 1)
                               1277                 :              0 :                     dwidth = Min(dwidth, Max(0, (int) (output_columns - hwidth - 3)));
                               1278                 :                : 
                               1279                 :                :                 /*
                               1280                 :                :                  * Handling the xheader width for border=2 doesn't make much
                               1281                 :                :                  * sense because this format has an additional right border,
                               1282                 :                :                  * but keep this for consistency.
                               1283                 :                :                  */
                               1284         [ #  # ]:              0 :                 if (opt_border == 2)
                               1285                 :              0 :                     dwidth = Min(dwidth, Max(0, (int) (output_columns - hwidth - 7)));
                               1286                 :                :             }
                               1287                 :                :         }
                               1288                 :                : 
 1190 andrew@dunslane.net      1289         [ +  + ]:CBC         820 :         if (reclen < 0)
                               1290                 :            712 :             reclen = 0;
                               1291         [ +  + ]:            820 :         if (dwidth < reclen)
                               1292                 :             16 :             dwidth = reclen;
                               1293                 :                : 
                               1294         [ +  + ]:          30272 :         for (i = reclen; i < dwidth; i++)
                               1295         [ +  + ]:          29452 :             fputs(opt_border > 0 ? lformat->hrule : " ", fout);
                               1296         [ +  + ]:            820 :         if (opt_border == 2)
                               1297                 :            234 :             fprintf(fout, "%s%s", lformat->hrule, lformat->rightvrule);
                               1298                 :                :     }
                               1299                 :                : 
 5858 tgl@sss.pgh.pa.us        1300                 :            820 :     fputc('\n', fout);
                               1301                 :            820 : }
                               1302                 :                : 
                               1303                 :                : static void
 3617                          1304                 :            259 : print_aligned_vertical(const printTableContent *cont,
                               1305                 :                :                        FILE *fout, bool is_pager)
                               1306                 :                : {
 6377 alvherre@alvh.no-ip.     1307                 :            259 :     bool        opt_tuples_only = cont->opt->tuples_only;
                               1308                 :            259 :     unsigned short opt_border = cont->opt->border;
 5858 tgl@sss.pgh.pa.us        1309                 :            259 :     const printTextFormat *format = get_line_style(cont->opt);
                               1310                 :            259 :     const printTextLineFormat *dformat = &format->lrule[PRINT_RULE_DATA];
 6377 alvherre@alvh.no-ip.     1311                 :            259 :     int         encoding = cont->opt->encoding;
                               1312                 :            259 :     unsigned long record = cont->opt->prior_records + 1;
                               1313                 :                :     const char *const *ptr;
                               1314                 :                :     unsigned int i,
 9489 bruce@momjian.us         1315                 :            259 :                 hwidth = 0,
 7199                          1316                 :            259 :                 dwidth = 0,
                               1317                 :            259 :                 hheight = 1,
                               1318                 :            259 :                 dheight = 1,
                               1319                 :            259 :                 hformatsize = 0,
                               1320                 :            259 :                 dformatsize = 0;
                               1321                 :                :     struct lineptr *hlineptr,
                               1322                 :                :                *dlineptr;
 3617 tgl@sss.pgh.pa.us        1323                 :            259 :     bool        is_local_pager = false,
 4088 stark@mit.edu            1324                 :            259 :                 hmultiline = false,
                               1325                 :            259 :                 dmultiline = false;
 3050 tgl@sss.pgh.pa.us        1326                 :            259 :     int         output_columns = 0; /* Width of interactive console */
                               1327                 :                : 
 7075                          1328         [ -  + ]:            259 :     if (cancel_pressed)
 7075 tgl@sss.pgh.pa.us        1329                 :UBC           0 :         return;
                               1330                 :                : 
 6999 tgl@sss.pgh.pa.us        1331         [ -  + ]:CBC         259 :     if (opt_border > 2)
 6999 tgl@sss.pgh.pa.us        1332                 :UBC           0 :         opt_border = 2;
                               1333                 :                : 
                               1334                 :                :     /*
                               1335                 :                :      * Kluge for totally empty table: use the default footer even though
                               1336                 :                :      * vertical modes normally don't.  Otherwise we'd print nothing at all,
                               1337                 :                :      * which isn't terribly friendly.  Assume pager will not be needed.
                               1338                 :                :      */
 6377 alvherre@alvh.no-ip.     1339   [ +  +  +  + ]:CBC         259 :     if (cont->cells[0] == NULL && cont->opt->start_table &&
                               1340         [ +  - ]:              8 :         cont->opt->stop_table)
                               1341                 :                :     {
 3870 bruce@momjian.us         1342                 :              8 :         printTableFooter *footers = footers_with_default(cont);
                               1343                 :                : 
                               1344   [ +  -  +  -  :              8 :         if (!opt_tuples_only && !cancel_pressed && footers)
                                              +  - ]
                               1345                 :                :         {
                               1346                 :                :             printTableFooter *f;
                               1347                 :                : 
                               1348         [ +  + ]:             16 :             for (f = footers; f; f = f->next)
                               1349                 :              8 :                 fprintf(fout, "%s\n", f->data);
                               1350                 :                :         }
                               1351                 :                : 
                               1352                 :              8 :         fputc('\n', fout);
                               1353                 :                : 
 9329                          1354                 :              8 :         return;
                               1355                 :                :     }
                               1356                 :                : 
                               1357                 :                :     /*
                               1358                 :                :      * Deal with the pager here instead of in printTable(), because we could
                               1359                 :                :      * get here via print_aligned_text() in expanded auto mode, and so we have
                               1360                 :                :      * to recalculate the pager requirement based on vertical output.
                               1361                 :                :      */
 3617 tgl@sss.pgh.pa.us        1362         [ +  + ]:            251 :     if (!is_pager)
                               1363                 :                :     {
   20 tgl@sss.pgh.pa.us        1364                 :GNC         239 :         IsPagerNeeded(cont, NULL, true, &fout, &is_pager);
 3617 tgl@sss.pgh.pa.us        1365                 :CBC         239 :         is_local_pager = is_pager;
                               1366                 :                :     }
                               1367                 :                : 
                               1368                 :                :     /* Find the maximum dimensions for the headers */
 6377 alvherre@alvh.no-ip.     1369         [ +  + ]:           1421 :     for (i = 0; i < cont->ncolumns; i++)
                               1370                 :                :     {
                               1371                 :                :         int         width,
                               1372                 :                :                     height,
                               1373                 :                :                     fs;
                               1374                 :                : 
 5160 peter_e@gmx.net          1375                 :           1170 :         pg_wcssize((const unsigned char *) cont->headers[i], strlen(cont->headers[i]),
                               1376                 :                :                    encoding, &width, &height, &fs);
 6381 bruce@momjian.us         1377         [ +  + ]:           1170 :         if (width > hwidth)
                               1378                 :            338 :             hwidth = width;
 7199                          1379         [ +  + ]:           1170 :         if (height > hheight)
                               1380                 :                :         {
                               1381                 :             36 :             hheight = height;
 4088 stark@mit.edu            1382                 :             36 :             hmultiline = true;
                               1383                 :                :         }
 7199 bruce@momjian.us         1384         [ +  + ]:           1170 :         if (fs > hformatsize)
                               1385                 :            338 :             hformatsize = fs;
                               1386                 :                :     }
                               1387                 :                : 
                               1388                 :                :     /* find longest data cell */
  706 alvherre@alvh.no-ip.     1389         [ +  + ]:           2658 :     for (ptr = cont->cells; *ptr; ptr++)
                               1390                 :                :     {
                               1391                 :                :         int         width,
                               1392                 :                :                     height,
                               1393                 :                :                     fs;
                               1394                 :                : 
 5160 peter_e@gmx.net          1395                 :           2407 :         pg_wcssize((const unsigned char *) *ptr, strlen(*ptr), encoding,
                               1396                 :                :                    &width, &height, &fs);
 6381 bruce@momjian.us         1397         [ +  + ]:           2407 :         if (width > dwidth)
                               1398                 :            505 :             dwidth = width;
 7199                          1399         [ +  + ]:           2407 :         if (height > dheight)
                               1400                 :                :         {
                               1401                 :             42 :             dheight = height;
 4088 stark@mit.edu            1402                 :             42 :             dmultiline = true;
                               1403                 :                :         }
 7199 bruce@momjian.us         1404         [ +  + ]:           2407 :         if (fs > dformatsize)
                               1405                 :            509 :             dformatsize = fs;
                               1406                 :                :     }
                               1407                 :                : 
                               1408                 :                :     /*
                               1409                 :                :      * We now have all the information we need to setup the formatting
                               1410                 :                :      * structures
                               1411                 :                :      */
 4773 tgl@sss.pgh.pa.us        1412                 :            251 :     dlineptr = pg_malloc((sizeof(*dlineptr)) * (dheight + 1));
                               1413                 :            251 :     hlineptr = pg_malloc((sizeof(*hlineptr)) * (hheight + 1));
                               1414                 :                : 
                               1415                 :            251 :     dlineptr->ptr = pg_malloc(dformatsize);
                               1416                 :            251 :     hlineptr->ptr = pg_malloc(hformatsize);
                               1417                 :                : 
 6377 alvherre@alvh.no-ip.     1418         [ +  + ]:            251 :     if (cont->opt->start_table)
                               1419                 :                :     {
                               1420                 :                :         /* print title */
                               1421   [ +  +  +  + ]:            245 :         if (!opt_tuples_only && cont->title)
                               1422                 :             18 :             fprintf(fout, "%s\n", cont->title);
                               1423                 :                :     }
                               1424                 :                : 
                               1425                 :                :     /*
                               1426                 :                :      * Choose target output width: \pset columns, or $COLUMNS, or ioctl
                               1427                 :                :      */
 4200 stark@mit.edu            1428         [ +  + ]:            251 :     if (cont->opt->columns > 0)
                               1429                 :            114 :         output_columns = cont->opt->columns;
                               1430   [ +  -  +  -  :            137 :     else if ((fout == stdout && isatty(fileno(stdout))) || is_pager)
                                              +  + ]
                               1431                 :                :     {
                               1432         [ -  + ]:             12 :         if (cont->opt->env_columns > 0)
 4200 stark@mit.edu            1433                 :UBC           0 :             output_columns = cont->opt->env_columns;
                               1434                 :                : #ifdef TIOCGWINSZ
                               1435                 :                :         else
                               1436                 :                :         {
                               1437                 :                :             struct winsize screen_size;
                               1438                 :                : 
 4200 stark@mit.edu            1439         [ -  + ]:CBC          12 :             if (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) != -1)
 4200 stark@mit.edu            1440                 :UBC           0 :                 output_columns = screen_size.ws_col;
                               1441                 :                :         }
                               1442                 :                : #endif
                               1443                 :                :     }
                               1444                 :                : 
                               1445                 :                :     /*
                               1446                 :                :      * Calculate available width for data in wrapped mode
                               1447                 :                :      */
 4200 stark@mit.edu            1448         [ +  + ]:CBC         251 :     if (cont->opt->format == PRINT_WRAPPED)
                               1449                 :                :     {
                               1450                 :                :         unsigned int swidth,
 3619 tgl@sss.pgh.pa.us        1451                 :             54 :                     rwidth = 0,
                               1452                 :                :                     newdwidth;
                               1453                 :                : 
 4200 stark@mit.edu            1454         [ +  + ]:             54 :         if (opt_border == 0)
                               1455                 :                :         {
                               1456                 :                :             /*
                               1457                 :                :              * For border = 0, one space in the middle.  (If we discover we
                               1458                 :                :              * need to wrap, the spacer column will be replaced by a wrap
                               1459                 :                :              * marker, and we'll make room below for another wrap marker at
                               1460                 :                :              * the end of the line.  But for now, assume no wrap is needed.)
                               1461                 :                :              */
 4088                          1462                 :             15 :             swidth = 1;
                               1463                 :                : 
                               1464                 :                :             /* We might need a column for header newline markers, too */
 3619 tgl@sss.pgh.pa.us        1465         [ +  + ]:             15 :             if (hmultiline)
                               1466                 :              6 :                 swidth++;
                               1467                 :                :         }
 4200 stark@mit.edu            1468         [ +  + ]:             39 :         else if (opt_border == 1)
                               1469                 :                :         {
                               1470                 :                :             /*
                               1471                 :                :              * For border = 1, two spaces and a vrule in the middle.  (As
                               1472                 :                :              * above, we might need one more column for a wrap marker.)
                               1473                 :                :              */
 4088                          1474                 :             24 :             swidth = 3;
                               1475                 :                : 
                               1476                 :                :             /* We might need a column for left header newline markers, too */
 3619 tgl@sss.pgh.pa.us        1477   [ +  +  +  + ]:             24 :             if (hmultiline && (format == &pg_asciiformat_old))
                               1478                 :              3 :                 swidth++;
                               1479                 :                :         }
                               1480                 :                :         else
                               1481                 :                :         {
                               1482                 :                :             /*
                               1483                 :                :              * For border = 2, two more for the vrules at the beginning and
                               1484                 :                :              * end of the lines, plus spacer columns adjacent to these.  (We
                               1485                 :                :              * won't need extra columns for wrap/newline markers, we'll just
                               1486                 :                :              * repurpose the spacers.)
                               1487                 :                :              */
 4088 stark@mit.edu            1488                 :             15 :             swidth = 7;
                               1489                 :                :         }
                               1490                 :                : 
                               1491                 :                :         /* Reserve a column for data newline indicators, too, if needed */
 3619 tgl@sss.pgh.pa.us        1492   [ +  +  +  + ]:             54 :         if (dmultiline &&
                               1493         [ +  + ]:             12 :             opt_border < 2 && format != &pg_asciiformat_old)
                               1494                 :              6 :             swidth++;
                               1495                 :                : 
                               1496                 :                :         /* Determine width required for record header lines */
 4200 stark@mit.edu            1497         [ +  + ]:             54 :         if (!opt_tuples_only)
                               1498                 :                :         {
 3618 tgl@sss.pgh.pa.us        1499         [ +  - ]:             51 :             if (cont->nrows > 0)
                               1500                 :             51 :                 rwidth = 1 + (int) log10(cont->nrows);
 4200 stark@mit.edu            1501         [ +  + ]:             51 :             if (opt_border == 0)
 4088                          1502                 :             15 :                 rwidth += 9;    /* "* RECORD " */
 4200                          1503         [ +  + ]:             36 :             else if (opt_border == 1)
 4088                          1504                 :             21 :                 rwidth += 12;   /* "-[ RECORD  ]" */
                               1505                 :                :             else
                               1506                 :             15 :                 rwidth += 15;   /* "+-[ RECORD  ]-+" */
                               1507                 :                :         }
                               1508                 :                : 
                               1509                 :                :         /* We might need to do the rest of the calculation twice */
                               1510                 :                :         for (;;)
 3619 tgl@sss.pgh.pa.us        1511                 :             12 :         {
                               1512                 :                :             unsigned int width;
                               1513                 :                : 
                               1514                 :                :             /* Total width required to not wrap data */
                               1515                 :             66 :             width = hwidth + swidth + dwidth;
                               1516                 :                :             /* ... and not the header lines, either */
 3618                          1517         [ -  + ]:             66 :             if (width < rwidth)
 3618 tgl@sss.pgh.pa.us        1518                 :UBC           0 :                 width = rwidth;
                               1519                 :                : 
 3618 tgl@sss.pgh.pa.us        1520         [ +  - ]:CBC          66 :             if (output_columns > 0)
                               1521                 :                :             {
                               1522                 :                :                 unsigned int min_width;
                               1523                 :                : 
                               1524                 :                :                 /* Minimum acceptable width: room for just 3 columns of data */
                               1525                 :             66 :                 min_width = hwidth + swidth + 3;
                               1526                 :                :                 /* ... but not less than what the record header lines need */
                               1527         [ +  + ]:             66 :                 if (min_width < rwidth)
                               1528                 :             18 :                     min_width = rwidth;
                               1529                 :                : 
                               1530         [ +  + ]:             66 :                 if (output_columns >= width)
                               1531                 :                :                 {
                               1532                 :                :                     /* Plenty of room, use native data width */
                               1533                 :                :                     /* (but at least enough for the record header lines) */
                               1534                 :             15 :                     newdwidth = width - hwidth - swidth;
                               1535                 :                :                 }
                               1536         [ +  + ]:             51 :                 else if (output_columns < min_width)
                               1537                 :                :                 {
                               1538                 :                :                     /* Set data width to match min_width */
                               1539                 :             12 :                     newdwidth = min_width - hwidth - swidth;
                               1540                 :                :                 }
                               1541                 :                :                 else
                               1542                 :                :                 {
                               1543                 :                :                     /* Set data width to match output_columns */
                               1544                 :             39 :                     newdwidth = output_columns - hwidth - swidth;
                               1545                 :                :                 }
                               1546                 :                :             }
                               1547                 :                :             else
                               1548                 :                :             {
                               1549                 :                :                 /* Don't know the wrap limit, so use native data width */
                               1550                 :                :                 /* (but at least enough for the record header lines) */
 3618 tgl@sss.pgh.pa.us        1551                 :UBC           0 :                 newdwidth = width - hwidth - swidth;
                               1552                 :                :             }
                               1553                 :                : 
                               1554                 :                :             /*
                               1555                 :                :              * If we will need to wrap data and didn't already allocate a data
                               1556                 :                :              * newline/wrap marker column, do so and recompute.
                               1557                 :                :              */
 3619 tgl@sss.pgh.pa.us        1558   [ +  +  +  +  :CBC          66 :             if (newdwidth < dwidth && !dmultiline &&
                                              +  + ]
                               1559         [ +  - ]:             12 :                 opt_border < 2 && format != &pg_asciiformat_old)
                               1560                 :                :             {
                               1561                 :             12 :                 dmultiline = true;
                               1562                 :             12 :                 swidth++;
                               1563                 :                :             }
                               1564                 :                :             else
                               1565                 :                :                 break;
                               1566                 :                :         }
                               1567                 :                : 
                               1568                 :             54 :         dwidth = newdwidth;
                               1569                 :                :     }
                               1570                 :                : 
                               1571                 :                :     /* print records */
 6377 alvherre@alvh.no-ip.     1572         [ +  + ]:           2658 :     for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
                               1573                 :                :     {
                               1574                 :                :         printTextRule pos;
                               1575                 :                :         int         dline,
                               1576                 :                :                     hline,
                               1577                 :                :                     dcomplete,
                               1578                 :                :                     hcomplete,
                               1579                 :                :                     offset,
                               1580                 :                :                     chars_to_output;
                               1581                 :                : 
 5858 tgl@sss.pgh.pa.us        1582         [ -  + ]:           2407 :         if (cancel_pressed)
 5858 tgl@sss.pgh.pa.us        1583                 :UBC           0 :             break;
                               1584                 :                : 
 5858 tgl@sss.pgh.pa.us        1585         [ +  + ]:CBC        2407 :         if (i == 0)
 5722 bruce@momjian.us         1586                 :            245 :             pos = PRINT_RULE_TOP;
                               1587                 :                :         else
 5858 tgl@sss.pgh.pa.us        1588                 :           2162 :             pos = PRINT_RULE_MIDDLE;
                               1589                 :                : 
                               1590                 :                :         /* Print record header (e.g. "[ RECORD N ]") above each record */
 6377 alvherre@alvh.no-ip.     1591         [ +  + ]:           2407 :         if (i % cont->ncolumns == 0)
                               1592                 :                :         {
 4088 stark@mit.edu            1593                 :            799 :             unsigned int lhwidth = hwidth;
                               1594                 :                : 
                               1595   [ +  +  +  + ]:            799 :             if ((opt_border < 2) &&
 4085 peter_e@gmx.net          1596         [ +  + ]:             48 :                 (hmultiline) &&
                               1597                 :                :                 (format == &pg_asciiformat_old))
 3810 bruce@momjian.us         1598                 :             24 :                 lhwidth++;      /* for newline indicators */
                               1599                 :                : 
 7410                          1600         [ +  + ]:            799 :             if (!opt_tuples_only)
 1190 andrew@dunslane.net      1601                 :            781 :                 print_aligned_vertical_line(cont->opt, record++,
                               1602                 :                :                                             lhwidth, dwidth, output_columns,
                               1603                 :                :                                             pos, fout);
 6377 alvherre@alvh.no-ip.     1604   [ +  +  +  -  :             18 :             else if (i != 0 || !cont->opt->start_table || opt_border == 2)
                                              -  + ]
 1190 andrew@dunslane.net      1605                 :              9 :                 print_aligned_vertical_line(cont->opt, 0, lhwidth,
                               1606                 :                :                                             dwidth, output_columns, pos, fout);
                               1607                 :                :         }
                               1608                 :                : 
                               1609                 :                :         /* Format the header */
 5160 peter_e@gmx.net          1610                 :           2407 :         pg_wcsformat((const unsigned char *) cont->headers[i % cont->ncolumns],
 6377 alvherre@alvh.no-ip.     1611                 :           2407 :                      strlen(cont->headers[i % cont->ncolumns]),
                               1612                 :                :                      encoding, hlineptr, hheight);
                               1613                 :                :         /* Format the data */
 5160 peter_e@gmx.net          1614                 :           2407 :         pg_wcsformat((const unsigned char *) *ptr, strlen(*ptr), encoding,
                               1615                 :                :                      dlineptr, dheight);
                               1616                 :                : 
                               1617                 :                :         /*
                               1618                 :                :          * Loop through header and data in parallel dealing with newlines and
                               1619                 :                :          * wrapped lines until they're both exhausted
                               1620                 :                :          */
 4200 stark@mit.edu            1621                 :           2407 :         dline = hline = 0;
 7199 bruce@momjian.us         1622                 :           2407 :         dcomplete = hcomplete = 0;
 4200 stark@mit.edu            1623                 :           2407 :         offset = 0;
                               1624                 :           2407 :         chars_to_output = dlineptr[dline].width;
 7199 bruce@momjian.us         1625   [ +  +  +  + ]:           6218 :         while (!dcomplete || !hcomplete)
                               1626                 :                :         {
                               1627                 :                :             /* Left border */
                               1628         [ +  + ]:           3811 :             if (opt_border == 2)
 4200 stark@mit.edu            1629                 :            909 :                 fprintf(fout, "%s", dformat->leftvrule);
                               1630                 :                : 
                               1631                 :                :             /* Header (never wrapped so just need to deal with newlines) */
 7199 bruce@momjian.us         1632         [ +  + ]:           3811 :             if (!hcomplete)
                               1633                 :                :             {
 4088 stark@mit.edu            1634                 :           2623 :                 int         swidth = hwidth,
                               1635                 :           2623 :                             target_width = hwidth;
                               1636                 :                : 
                               1637                 :                :                 /*
                               1638                 :                :                  * Left spacer or new line indicator
                               1639                 :                :                  */
                               1640   [ +  +  +  + ]:           2623 :                 if ((opt_border == 2) ||
                               1641         [ +  + ]:            240 :                     (hmultiline && (format == &pg_asciiformat_old)))
                               1642         [ +  + ]:            600 :                     fputs(hline ? format->header_nl_left : " ", fout);
                               1643                 :                : 
                               1644                 :                :                 /*
                               1645                 :                :                  * Header text
                               1646                 :                :                  */
                               1647                 :           2623 :                 strlen_max_width(hlineptr[hline].ptr, &target_width,
                               1648                 :                :                                  encoding);
 4200                          1649                 :           2623 :                 fprintf(fout, "%-s", hlineptr[hline].ptr);
                               1650                 :                : 
                               1651                 :                :                 /*
                               1652                 :                :                  * Spacer
                               1653                 :                :                  */
 4088                          1654                 :           2623 :                 swidth -= target_width;
                               1655         [ +  + ]:           2623 :                 if (swidth > 0)
 4200                          1656                 :           1645 :                     fprintf(fout, "%*s", swidth, " ");
                               1657                 :                : 
                               1658                 :                :                 /*
                               1659                 :                :                  * New line indicator or separator's space
                               1660                 :                :                  */
                               1661         [ +  + ]:           2623 :                 if (hlineptr[hline + 1].ptr)
                               1662                 :                :                 {
                               1663                 :                :                     /* More lines after this one due to a newline */
 4088                          1664   [ +  +  +  - ]:            216 :                     if ((opt_border > 0) ||
                               1665         [ +  + ]:             72 :                         (hmultiline && (format != &pg_asciiformat_old)))
                               1666                 :            180 :                         fputs(format->header_nl_right, fout);
 4200                          1667                 :            216 :                     hline++;
                               1668                 :                :                 }
                               1669                 :                :                 else
                               1670                 :                :                 {
                               1671                 :                :                     /* This was the last line of the header */
 4088                          1672   [ +  +  +  + ]:           2407 :                     if ((opt_border > 0) ||
                               1673         [ +  + ]:             48 :                         (hmultiline && (format != &pg_asciiformat_old)))
                               1674                 :           2023 :                         fputs(" ", fout);
 7199 bruce@momjian.us         1675                 :           2407 :                     hcomplete = 1;
                               1676                 :                :                 }
                               1677                 :                :             }
                               1678                 :                :             else
                               1679                 :                :             {
 4088 stark@mit.edu            1680                 :           1188 :                 unsigned int swidth = hwidth + opt_border;
                               1681                 :                : 
                               1682   [ +  +  +  + ]:           1188 :                 if ((opt_border < 2) &&
                               1683         [ +  + ]:            354 :                     (hmultiline) &&
                               1684                 :                :                     (format == &pg_asciiformat_old))
                               1685                 :            174 :                     swidth++;
                               1686                 :                : 
 4085 peter_e@gmx.net          1687   [ +  +  +  + ]:           1188 :                 if ((opt_border == 0) &&
 4088 stark@mit.edu            1688         [ +  + ]:            273 :                     (format != &pg_asciiformat_old) &&
                               1689                 :                :                     (hmultiline))
                               1690                 :             90 :                     swidth++;
                               1691                 :                : 
                               1692                 :           1188 :                 fprintf(fout, "%*s", swidth, " ");
                               1693                 :                :             }
                               1694                 :                : 
                               1695                 :                :             /* Separator */
 7199 bruce@momjian.us         1696         [ +  + ]:           3811 :             if (opt_border > 0)
                               1697                 :                :             {
 4200 stark@mit.edu            1698         [ +  + ]:           2974 :                 if (offset)
                               1699                 :            558 :                     fputs(format->midvrule_wrap, fout);
 3619 tgl@sss.pgh.pa.us        1700         [ +  + ]:           2416 :                 else if (dline == 0)
 4200 stark@mit.edu            1701                 :           1999 :                     fputs(dformat->midvrule, fout);
                               1702                 :                :                 else
 3619 tgl@sss.pgh.pa.us        1703                 :            417 :                     fputs(format->midvrule_nl, fout);
                               1704                 :                :             }
                               1705                 :                : 
                               1706                 :                :             /* Data */
 7199 bruce@momjian.us         1707         [ +  + ]:           3811 :             if (!dcomplete)
                               1708                 :                :             {
 4088 stark@mit.edu            1709                 :           3721 :                 int         target_width = dwidth,
                               1710                 :                :                             bytes_to_output,
                               1711                 :           3721 :                             swidth = dwidth;
                               1712                 :                : 
                               1713                 :                :                 /*
                               1714                 :                :                  * Left spacer or wrap indicator
                               1715                 :                :                  */
 3619 tgl@sss.pgh.pa.us        1716         [ +  + ]:           3721 :                 fputs(offset == 0 ? " " : format->wrap_left, fout);
                               1717                 :                : 
                               1718                 :                :                 /*
                               1719                 :                :                  * Data text
                               1720                 :                :                  */
 4200 stark@mit.edu            1721                 :           3721 :                 bytes_to_output = strlen_max_width(dlineptr[dline].ptr + offset,
                               1722                 :                :                                                    &target_width, encoding);
 1946 tgl@sss.pgh.pa.us        1723                 :           3721 :                 fwrite((char *) (dlineptr[dline].ptr + offset),
                               1724                 :                :                        1, bytes_to_output, fout);
                               1725                 :                : 
 4200 stark@mit.edu            1726                 :           3721 :                 chars_to_output -= target_width;
                               1727                 :           3721 :                 offset += bytes_to_output;
                               1728                 :                : 
                               1729                 :                :                 /* Spacer */
 4088                          1730                 :           3721 :                 swidth -= target_width;
                               1731                 :                : 
 4200                          1732         [ +  + ]:           3721 :                 if (chars_to_output)
                               1733                 :                :                 {
                               1734                 :                :                     /* continuing a wrapped column */
 4088                          1735   [ +  +  +  - ]:            705 :                     if ((opt_border > 1) ||
                               1736         [ +  + ]:            426 :                         (dmultiline && (format != &pg_asciiformat_old)))
                               1737                 :                :                     {
                               1738         [ -  + ]:            681 :                         if (swidth > 0)
 4088 stark@mit.edu            1739                 :UBC           0 :                             fprintf(fout, "%*s", swidth, " ");
 4088 stark@mit.edu            1740                 :CBC         681 :                         fputs(format->wrap_right, fout);
                               1741                 :                :                     }
                               1742                 :                :                 }
 4200                          1743         [ +  + ]:           3016 :                 else if (dlineptr[dline + 1].ptr)
                               1744                 :                :                 {
                               1745                 :                :                     /* reached a newline in the column */
 4088                          1746   [ +  +  +  - ]:            609 :                     if ((opt_border > 1) ||
                               1747         [ +  + ]:            417 :                         (dmultiline && (format != &pg_asciiformat_old)))
                               1748                 :                :                     {
                               1749         [ +  + ]:            417 :                         if (swidth > 0)
                               1750                 :            408 :                             fprintf(fout, "%*s", swidth, " ");
                               1751                 :            417 :                         fputs(format->nl_right, fout);
                               1752                 :                :                     }
 4200                          1753                 :            609 :                     dline++;
                               1754                 :            609 :                     offset = 0;
                               1755                 :            609 :                     chars_to_output = dlineptr[dline].width;
                               1756                 :                :                 }
                               1757                 :                :                 else
                               1758                 :                :                 {
                               1759                 :                :                     /* reached the end of the cell */
 4088                          1760         [ +  + ]:           2407 :                     if (opt_border > 1)
                               1761                 :                :                     {
                               1762         [ +  + ]:            408 :                         if (swidth > 0)
                               1763                 :            369 :                             fprintf(fout, "%*s", swidth, " ");
                               1764                 :            408 :                         fputs(" ", fout);
                               1765                 :                :                     }
 6963 bruce@momjian.us         1766                 :           2407 :                     dcomplete = 1;
                               1767                 :                :                 }
                               1768                 :                : 
                               1769                 :                :                 /* Right border */
 4200 stark@mit.edu            1770         [ +  + ]:           3721 :                 if (opt_border == 2)
                               1771                 :            879 :                     fputs(dformat->rightvrule, fout);
                               1772                 :                : 
                               1773                 :           3721 :                 fputs("\n", fout);
                               1774                 :                :             }
                               1775                 :                :             else
                               1776                 :                :             {
                               1777                 :                :                 /*
                               1778                 :                :                  * data exhausted (this can occur if header is longer than the
                               1779                 :                :                  * data due to newlines in the header)
                               1780                 :                :                  */
 6963 bruce@momjian.us         1781         [ +  + ]:             90 :                 if (opt_border < 2)
 4200 stark@mit.edu            1782                 :             60 :                     fputs("\n", fout);
                               1783                 :                :                 else
                               1784                 :             30 :                     fprintf(fout, "%*s  %s\n", dwidth, "", dformat->rightvrule);
                               1785                 :                :             }
                               1786                 :                :         }
                               1787                 :                :     }
                               1788                 :                : 
 6377 alvherre@alvh.no-ip.     1789         [ +  + ]:            251 :     if (cont->opt->stop_table)
                               1790                 :                :     {
 6999 tgl@sss.pgh.pa.us        1791   [ +  +  +  - ]:            245 :         if (opt_border == 2 && !cancel_pressed)
 1190 andrew@dunslane.net      1792                 :             30 :             print_aligned_vertical_line(cont->opt, 0, hwidth, dwidth,
                               1793                 :                :                                         output_columns, PRINT_RULE_BOTTOM, fout);
                               1794                 :                : 
                               1795                 :                :         /* print footers */
 6377 alvherre@alvh.no-ip.     1796   [ +  +  +  +  :            245 :         if (!opt_tuples_only && cont->footers != NULL && !cancel_pressed)
                                              +  - ]
                               1797                 :                :         {
                               1798                 :                :             printTableFooter *f;
                               1799                 :                : 
 6999 tgl@sss.pgh.pa.us        1800         [ +  - ]:              6 :             if (opt_border < 2)
                               1801                 :              6 :                 fputc('\n', fout);
 6377 alvherre@alvh.no-ip.     1802         [ +  + ]:             12 :             for (f = cont->footers; f; f = f->next)
                               1803                 :              6 :                 fprintf(fout, "%s\n", f->data);
                               1804                 :                :         }
                               1805                 :                : 
 6999 tgl@sss.pgh.pa.us        1806                 :            245 :         fputc('\n', fout);
                               1807                 :                :     }
                               1808                 :                : 
 7199 bruce@momjian.us         1809                 :            251 :     free(hlineptr->ptr);
                               1810                 :            251 :     free(dlineptr->ptr);
                               1811                 :            251 :     free(hlineptr);
                               1812                 :            251 :     free(dlineptr);
                               1813                 :                : 
 3617 tgl@sss.pgh.pa.us        1814         [ -  + ]:            251 :     if (is_local_pager)
 5098 peter_e@gmx.net          1815                 :UBC           0 :         ClosePager(fout);
                               1816                 :                : }
                               1817                 :                : 
                               1818                 :                : 
                               1819                 :                : /**********************/
                               1820                 :                : /* CSV format         */
                               1821                 :                : /**********************/
                               1822                 :                : 
                               1823                 :                : 
                               1824                 :                : static void
 2527 tgl@sss.pgh.pa.us        1825                 :CBC          54 : csv_escaped_print(const char *str, FILE *fout)
                               1826                 :                : {
                               1827                 :                :     const char *p;
                               1828                 :                : 
                               1829                 :             54 :     fputc('"', fout);
                               1830         [ +  + ]:            462 :     for (p = str; *p; p++)
                               1831                 :                :     {
                               1832         [ +  + ]:            408 :         if (*p == '"')
                               1833                 :             21 :             fputc('"', fout);  /* double quotes are doubled */
                               1834                 :            408 :         fputc(*p, fout);
                               1835                 :                :     }
                               1836                 :             54 :     fputc('"', fout);
                               1837                 :             54 : }
                               1838                 :                : 
                               1839                 :                : static void
                               1840                 :            312 : csv_print_field(const char *str, FILE *fout, char sep)
                               1841                 :                : {
                               1842                 :                :     /*----------------
                               1843                 :                :      * Enclose and escape field contents when one of these conditions is met:
                               1844                 :                :      * - the field separator is found in the contents.
                               1845                 :                :      * - the field contains a CR or LF.
                               1846                 :                :      * - the field contains a double quote.
                               1847                 :                :      * - the field is exactly "\.".
                               1848                 :                :      * - the field separator is either "\" or ".".
                               1849                 :                :      * The last two cases prevent producing a line that the server's COPY
                               1850                 :                :      * command would interpret as an end-of-data marker.  We only really
                               1851                 :                :      * need to ensure that the complete line isn't exactly "\.", but for
                               1852                 :                :      * simplicity we apply stronger restrictions here.
                               1853                 :                :      *----------------
                               1854                 :                :      */
                               1855         [ +  + ]:            312 :     if (strchr(str, sep) != NULL ||
                               1856         [ +  + ]:            306 :         strcspn(str, "\r\n\"") != strlen(str) ||
                               1857   [ +  +  +  - ]:            273 :         strcmp(str, "\\.") == 0 ||
                               1858         [ +  + ]:            270 :         sep == '\\' || sep == '.')
                               1859                 :             54 :         csv_escaped_print(str, fout);
                               1860                 :                :     else
                               1861                 :            258 :         fputs(str, fout);
                               1862                 :            312 : }
                               1863                 :                : 
                               1864                 :                : static void
                               1865                 :             24 : print_csv_text(const printTableContent *cont, FILE *fout)
                               1866                 :                : {
                               1867                 :                :     const char *const *ptr;
                               1868                 :                :     int         i;
                               1869                 :                : 
                               1870         [ -  + ]:             24 :     if (cancel_pressed)
 2527 tgl@sss.pgh.pa.us        1871                 :UBC           0 :         return;
                               1872                 :                : 
                               1873                 :                :     /*
                               1874                 :                :      * The title and footer are never printed in csv format. The header is
                               1875                 :                :      * printed if opt_tuples_only is false.
                               1876                 :                :      *
                               1877                 :                :      * Despite RFC 4180 saying that end of lines are CRLF, terminate lines
                               1878                 :                :      * with '\n', which prints out as the system-dependent EOL string in text
                               1879                 :                :      * mode (typically LF on Unix and CRLF on Windows).
                               1880                 :                :      */
 2527 tgl@sss.pgh.pa.us        1881   [ +  -  +  + ]:CBC          24 :     if (cont->opt->start_table && !cont->opt->tuples_only)
                               1882                 :                :     {
                               1883                 :                :         /* print headers */
                               1884         [ +  + ]:             81 :         for (ptr = cont->headers; *ptr; ptr++)
                               1885                 :                :         {
                               1886         [ +  + ]:             60 :             if (ptr != cont->headers)
                               1887                 :             39 :                 fputc(cont->opt->csvFieldSep[0], fout);
                               1888                 :             60 :             csv_print_field(*ptr, fout, cont->opt->csvFieldSep[0]);
                               1889                 :                :         }
                               1890                 :             21 :         fputc('\n', fout);
                               1891                 :                :     }
                               1892                 :                : 
                               1893                 :                :     /* print cells */
                               1894         [ +  + ]:            126 :     for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
                               1895                 :                :     {
                               1896                 :            102 :         csv_print_field(*ptr, fout, cont->opt->csvFieldSep[0]);
                               1897         [ +  + ]:            102 :         if ((i + 1) % cont->ncolumns)
                               1898                 :             72 :             fputc(cont->opt->csvFieldSep[0], fout);
                               1899                 :                :         else
                               1900                 :             30 :             fputc('\n', fout);
                               1901                 :                :     }
                               1902                 :                : }
                               1903                 :                : 
                               1904                 :                : static void
                               1905                 :              9 : print_csv_vertical(const printTableContent *cont, FILE *fout)
                               1906                 :                : {
                               1907                 :                :     const char *const *ptr;
                               1908                 :                :     int         i;
                               1909                 :                : 
                               1910                 :                :     /* print records */
                               1911         [ +  + ]:             84 :     for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
                               1912                 :                :     {
                               1913         [ -  + ]:             75 :         if (cancel_pressed)
 2527 tgl@sss.pgh.pa.us        1914                 :UBC           0 :             return;
                               1915                 :                : 
                               1916                 :                :         /* print name of column */
 2527 tgl@sss.pgh.pa.us        1917                 :CBC          75 :         csv_print_field(cont->headers[i % cont->ncolumns], fout,
                               1918                 :             75 :                         cont->opt->csvFieldSep[0]);
                               1919                 :                : 
                               1920                 :                :         /* print field separator */
                               1921                 :             75 :         fputc(cont->opt->csvFieldSep[0], fout);
                               1922                 :                : 
                               1923                 :                :         /* print field value */
                               1924                 :             75 :         csv_print_field(*ptr, fout, cont->opt->csvFieldSep[0]);
                               1925                 :                : 
                               1926                 :             75 :         fputc('\n', fout);
                               1927                 :                :     }
                               1928                 :                : }
                               1929                 :                : 
                               1930                 :                : 
                               1931                 :                : /**********************/
                               1932                 :                : /* HTML               */
                               1933                 :                : /**********************/
                               1934                 :                : 
                               1935                 :                : 
                               1936                 :                : void
 9489 bruce@momjian.us         1937                 :            411 : html_escaped_print(const char *in, FILE *fout)
                               1938                 :                : {
                               1939                 :                :     const char *p;
 7317                          1940                 :            411 :     bool        leading_space = true;
                               1941                 :                : 
 9489                          1942         [ +  + ]:           3450 :     for (p = in; *p; p++)
                               1943                 :                :     {
                               1944   [ +  +  +  +  :           3039 :         switch (*p)
                                           +  +  + ]
                               1945                 :                :         {
                               1946                 :             27 :             case '&':
                               1947                 :             27 :                 fputs("&amp;", fout);
                               1948                 :             27 :                 break;
                               1949                 :             72 :             case '<':
                               1950                 :             72 :                 fputs("&lt;", fout);
                               1951                 :             72 :                 break;
                               1952                 :             72 :             case '>':
                               1953                 :             72 :                 fputs("&gt;", fout);
                               1954                 :             72 :                 break;
                               1955                 :             36 :             case '\n':
 8173                          1956                 :             36 :                 fputs("<br />\n", fout);
                               1957                 :             36 :                 break;
                               1958                 :             48 :             case '"':
                               1959                 :             48 :                 fputs("&quot;", fout);
                               1960                 :             48 :                 break;
 7440                          1961                 :            135 :             case ' ':
                               1962                 :                :                 /* protect leading space, for EXPLAIN output */
                               1963         [ +  + ]:            135 :                 if (leading_space)
                               1964                 :             72 :                     fputs("&nbsp;", fout);
                               1965                 :                :                 else
                               1966                 :             63 :                     fputs(" ", fout);
                               1967                 :            135 :                 break;
 9489                          1968                 :           2649 :             default:
                               1969                 :           2649 :                 fputc(*p, fout);
                               1970                 :                :         }
 7440                          1971         [ +  + ]:           3039 :         if (*p != ' ')
                               1972                 :           2904 :             leading_space = false;
                               1973                 :                :     }
 9489                          1974                 :            411 : }
                               1975                 :                : 
                               1976                 :                : 
                               1977                 :                : static void
 6377 alvherre@alvh.no-ip.     1978                 :             15 : print_html_text(const printTableContent *cont, FILE *fout)
                               1979                 :                : {
                               1980                 :             15 :     bool        opt_tuples_only = cont->opt->tuples_only;
                               1981                 :             15 :     unsigned short opt_border = cont->opt->border;
                               1982                 :             15 :     const char *opt_table_attr = cont->opt->tableAttr;
                               1983                 :                :     unsigned int i;
                               1984                 :                :     const char *const *ptr;
                               1985                 :                : 
 7075 tgl@sss.pgh.pa.us        1986         [ -  + ]:             15 :     if (cancel_pressed)
 7075 tgl@sss.pgh.pa.us        1987                 :UBC           0 :         return;
                               1988                 :                : 
 6377 alvherre@alvh.no-ip.     1989         [ +  - ]:CBC          15 :     if (cont->opt->start_table)
                               1990                 :                :     {
 6999 tgl@sss.pgh.pa.us        1991                 :             15 :         fprintf(fout, "<table border=\"%d\"", opt_border);
                               1992         [ +  + ]:             15 :         if (opt_table_attr)
                               1993                 :              3 :             fprintf(fout, " %s", opt_table_attr);
                               1994                 :             15 :         fputs(">\n", fout);
                               1995                 :                : 
                               1996                 :                :         /* print title */
 6377 alvherre@alvh.no-ip.     1997   [ +  +  +  + ]:             15 :         if (!opt_tuples_only && cont->title)
                               1998                 :                :         {
 6999 tgl@sss.pgh.pa.us        1999                 :              3 :             fputs("  <caption>", fout);
 6377 alvherre@alvh.no-ip.     2000                 :              3 :             html_escaped_print(cont->title, fout);
 6999 tgl@sss.pgh.pa.us        2001                 :              3 :             fputs("</caption>\n", fout);
                               2002                 :                :         }
                               2003                 :                : 
                               2004                 :                :         /* print headers */
 7410 bruce@momjian.us         2005         [ +  + ]:             15 :         if (!opt_tuples_only)
                               2006                 :                :         {
 6999 tgl@sss.pgh.pa.us        2007                 :             12 :             fputs("  <tr>\n", fout);
 6377 alvherre@alvh.no-ip.     2008         [ +  + ]:             69 :             for (ptr = cont->headers; *ptr; ptr++)
                               2009                 :                :             {
 6999 tgl@sss.pgh.pa.us        2010                 :             57 :                 fputs("    <th align=\"center\">", fout);
                               2011                 :             57 :                 html_escaped_print(*ptr, fout);
                               2012                 :             57 :                 fputs("</th>\n", fout);
                               2013                 :                :             }
                               2014                 :             12 :             fputs("  </tr>\n", fout);
                               2015                 :                :         }
                               2016                 :                :     }
                               2017                 :                : 
                               2018                 :                :     /* print cells */
 6377 alvherre@alvh.no-ip.     2019         [ +  + ]:            138 :     for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
                               2020                 :                :     {
                               2021         [ +  + ]:            123 :         if (i % cont->ncolumns == 0)
                               2022                 :                :         {
 7075 tgl@sss.pgh.pa.us        2023         [ -  + ]:             27 :             if (cancel_pressed)
 7075 tgl@sss.pgh.pa.us        2024                 :UBC           0 :                 break;
 8173 bruce@momjian.us         2025                 :CBC          27 :             fputs("  <tr valign=\"top\">\n", fout);
                               2026                 :                :         }
                               2027                 :                : 
 6377 alvherre@alvh.no-ip.     2028         [ +  + ]:            123 :         fprintf(fout, "    <td align=\"%s\">", cont->aligns[(i) % cont->ncolumns] == 'r' ? "right" : "left");
                               2029                 :                :         /* is string only whitespace? */
 7317 bruce@momjian.us         2030         [ +  + ]:            123 :         if ((*ptr)[strspn(*ptr, " \t")] == '\0')
 8173                          2031                 :             18 :             fputs("&nbsp; ", fout);
                               2032                 :                :         else
 9489                          2033                 :            105 :             html_escaped_print(*ptr, fout);
                               2034                 :                : 
                               2035                 :            123 :         fputs("</td>\n", fout);
                               2036                 :                : 
 6377 alvherre@alvh.no-ip.     2037         [ +  + ]:            123 :         if ((i + 1) % cont->ncolumns == 0)
 9489 bruce@momjian.us         2038                 :             27 :             fputs("  </tr>\n", fout);
                               2039                 :                :     }
                               2040                 :                : 
 6377 alvherre@alvh.no-ip.     2041         [ +  - ]:             15 :     if (cont->opt->stop_table)
                               2042                 :                :     {
 4927 rhaas@postgresql.org     2043                 :             15 :         printTableFooter *footers = footers_with_default(cont);
                               2044                 :                : 
 6999 tgl@sss.pgh.pa.us        2045                 :             15 :         fputs("</table>\n", fout);
                               2046                 :                : 
                               2047                 :                :         /* print footers */
 4927 rhaas@postgresql.org     2048   [ +  +  +  -  :             15 :         if (!opt_tuples_only && footers != NULL && !cancel_pressed)
                                              +  - ]
                               2049                 :                :         {
                               2050                 :                :             printTableFooter *f;
                               2051                 :                : 
 6999 tgl@sss.pgh.pa.us        2052                 :             12 :             fputs("<p>", fout);
 4927 rhaas@postgresql.org     2053         [ +  + ]:             24 :             for (f = footers; f; f = f->next)
                               2054                 :                :             {
 6377 alvherre@alvh.no-ip.     2055                 :             12 :                 html_escaped_print(f->data, fout);
 6999 tgl@sss.pgh.pa.us        2056                 :             12 :                 fputs("<br />\n", fout);
                               2057                 :                :             }
                               2058                 :             12 :             fputs("</p>", fout);
                               2059                 :                :         }
                               2060                 :                : 
                               2061                 :             15 :         fputc('\n', fout);
                               2062                 :                :     }
                               2063                 :                : }
                               2064                 :                : 
                               2065                 :                : 
                               2066                 :                : static void
 6377 alvherre@alvh.no-ip.     2067                 :             15 : print_html_vertical(const printTableContent *cont, FILE *fout)
                               2068                 :                : {
                               2069                 :             15 :     bool        opt_tuples_only = cont->opt->tuples_only;
                               2070                 :             15 :     unsigned short opt_border = cont->opt->border;
                               2071                 :             15 :     const char *opt_table_attr = cont->opt->tableAttr;
                               2072                 :             15 :     unsigned long record = cont->opt->prior_records + 1;
                               2073                 :                :     unsigned int i;
                               2074                 :                :     const char *const *ptr;
                               2075                 :                : 
 7075 tgl@sss.pgh.pa.us        2076         [ -  + ]:             15 :     if (cancel_pressed)
 7075 tgl@sss.pgh.pa.us        2077                 :UBC           0 :         return;
                               2078                 :                : 
 6377 alvherre@alvh.no-ip.     2079         [ +  - ]:CBC          15 :     if (cont->opt->start_table)
                               2080                 :                :     {
 6999 tgl@sss.pgh.pa.us        2081                 :             15 :         fprintf(fout, "<table border=\"%d\"", opt_border);
                               2082         [ +  + ]:             15 :         if (opt_table_attr)
                               2083                 :              3 :             fprintf(fout, " %s", opt_table_attr);
                               2084                 :             15 :         fputs(">\n", fout);
                               2085                 :                : 
                               2086                 :                :         /* print title */
 6377 alvherre@alvh.no-ip.     2087   [ +  +  +  + ]:             15 :         if (!opt_tuples_only && cont->title)
                               2088                 :                :         {
 6999 tgl@sss.pgh.pa.us        2089                 :              3 :             fputs("  <caption>", fout);
 6377 alvherre@alvh.no-ip.     2090                 :              3 :             html_escaped_print(cont->title, fout);
 6999 tgl@sss.pgh.pa.us        2091                 :              3 :             fputs("</caption>\n", fout);
                               2092                 :                :         }
                               2093                 :                :     }
                               2094                 :                : 
                               2095                 :                :     /* print records */
 6377 alvherre@alvh.no-ip.     2096         [ +  + ]:            138 :     for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
                               2097                 :                :     {
                               2098         [ +  + ]:            123 :         if (i % cont->ncolumns == 0)
                               2099                 :                :         {
 7075 tgl@sss.pgh.pa.us        2100         [ -  + ]:             27 :             if (cancel_pressed)
 7075 tgl@sss.pgh.pa.us        2101                 :UBC           0 :                 break;
 7410 bruce@momjian.us         2102         [ +  + ]:CBC          27 :             if (!opt_tuples_only)
 6999 tgl@sss.pgh.pa.us        2103                 :             21 :                 fprintf(fout,
                               2104                 :                :                         "\n  <tr><td colspan=\"2\" align=\"center\">Record %lu</td></tr>\n",
                               2105                 :                :                         record++);
                               2106                 :                :             else
 8173 bruce@momjian.us         2107                 :              6 :                 fputs("\n  <tr><td colspan=\"2\">&nbsp;</td></tr>\n", fout);
                               2108                 :                :         }
                               2109                 :            123 :         fputs("  <tr valign=\"top\">\n"
                               2110                 :                :               "    <th>", fout);
 6377 alvherre@alvh.no-ip.     2111                 :            123 :         html_escaped_print(cont->headers[i % cont->ncolumns], fout);
 9489 bruce@momjian.us         2112                 :            123 :         fputs("</th>\n", fout);
                               2113                 :                : 
 6377 alvherre@alvh.no-ip.     2114         [ +  + ]:            123 :         fprintf(fout, "    <td align=\"%s\">", cont->aligns[i % cont->ncolumns] == 'r' ? "right" : "left");
                               2115                 :                :         /* is string only whitespace? */
 7317 bruce@momjian.us         2116         [ +  + ]:            123 :         if ((*ptr)[strspn(*ptr, " \t")] == '\0')
 8173                          2117                 :             18 :             fputs("&nbsp; ", fout);
                               2118                 :                :         else
 9489                          2119                 :            105 :             html_escaped_print(*ptr, fout);
                               2120                 :                : 
                               2121                 :            123 :         fputs("</td>\n  </tr>\n", fout);
                               2122                 :                :     }
                               2123                 :                : 
 6377 alvherre@alvh.no-ip.     2124         [ +  - ]:             15 :     if (cont->opt->stop_table)
                               2125                 :                :     {
 6999 tgl@sss.pgh.pa.us        2126                 :             15 :         fputs("</table>\n", fout);
                               2127                 :                : 
                               2128                 :                :         /* print footers */
 6377 alvherre@alvh.no-ip.     2129   [ +  +  +  +  :             15 :         if (!opt_tuples_only && cont->footers != NULL && !cancel_pressed)
                                              +  - ]
                               2130                 :                :         {
                               2131                 :                :             printTableFooter *f;
                               2132                 :                : 
 6999 tgl@sss.pgh.pa.us        2133                 :              3 :             fputs("<p>", fout);
 6377 alvherre@alvh.no-ip.     2134         [ +  + ]:              6 :             for (f = cont->footers; f; f = f->next)
                               2135                 :                :             {
                               2136                 :              3 :                 html_escaped_print(f->data, fout);
 6999 tgl@sss.pgh.pa.us        2137                 :              3 :                 fputs("<br />\n", fout);
                               2138                 :                :             }
                               2139                 :              3 :             fputs("</p>", fout);
                               2140                 :                :         }
                               2141                 :                : 
                               2142                 :             15 :         fputc('\n', fout);
                               2143                 :                :     }
                               2144                 :                : }
                               2145                 :                : 
                               2146                 :                : 
                               2147                 :                : /*************************/
                               2148                 :                : /* ASCIIDOC              */
                               2149                 :                : /*************************/
                               2150                 :                : 
                               2151                 :                : 
                               2152                 :                : static void
 3863 bruce@momjian.us         2153                 :            327 : asciidoc_escaped_print(const char *in, FILE *fout)
                               2154                 :                : {
                               2155                 :                :     const char *p;
                               2156                 :                : 
                               2157         [ +  + ]:           2295 :     for (p = in; *p; p++)
                               2158                 :                :     {
 3810                          2159         [ +  + ]:           1968 :         switch (*p)
                               2160                 :                :         {
 3863                          2161                 :             63 :             case '|':
                               2162                 :             63 :                 fputs("\\|", fout);
                               2163                 :             63 :                 break;
                               2164                 :           1905 :             default:
                               2165                 :           1905 :                 fputc(*p, fout);
                               2166                 :                :         }
                               2167                 :                :     }
                               2168                 :            327 : }
                               2169                 :                : 
                               2170                 :                : static void
                               2171                 :             15 : print_asciidoc_text(const printTableContent *cont, FILE *fout)
                               2172                 :                : {
                               2173                 :             15 :     bool        opt_tuples_only = cont->opt->tuples_only;
                               2174                 :             15 :     unsigned short opt_border = cont->opt->border;
                               2175                 :                :     unsigned int i;
                               2176                 :                :     const char *const *ptr;
                               2177                 :                : 
                               2178         [ -  + ]:             15 :     if (cancel_pressed)
 3863 bruce@momjian.us         2179                 :UBC           0 :         return;
                               2180                 :                : 
 3863 bruce@momjian.us         2181         [ +  - ]:CBC          15 :     if (cont->opt->start_table)
                               2182                 :                :     {
                               2183                 :                :         /* print table in new paragraph - enforce preliminary new line */
                               2184                 :             15 :         fputs("\n", fout);
                               2185                 :                : 
                               2186                 :                :         /* print title */
                               2187   [ +  +  +  + ]:             15 :         if (!opt_tuples_only && cont->title)
                               2188                 :                :         {
                               2189                 :              3 :             fputs(".", fout);
                               2190                 :              3 :             fputs(cont->title, fout);
                               2191                 :              3 :             fputs("\n", fout);
                               2192                 :                :         }
                               2193                 :                : 
                               2194                 :                :         /* print table [] header definition */
                               2195         [ +  + ]:             15 :         fprintf(fout, "[%scols=\"", !opt_tuples_only ? "options=\"header\"," : "");
 3810                          2196         [ +  + ]:             78 :         for (i = 0; i < cont->ncolumns; i++)
                               2197                 :                :         {
 3863                          2198         [ +  + ]:             63 :             if (i != 0)
                               2199                 :             48 :                 fputs(",", fout);
                               2200         [ +  + ]:             63 :             fprintf(fout, "%s", cont->aligns[(i) % cont->ncolumns] == 'r' ? ">l" : "<l");
                               2201                 :                :         }
                               2202                 :             15 :         fputs("\"", fout);
                               2203   [ +  +  +  - ]:             15 :         switch (opt_border)
                               2204                 :                :         {
                               2205                 :              3 :             case 0:
                               2206                 :              3 :                 fputs(",frame=\"none\",grid=\"none\"", fout);
                               2207                 :              3 :                 break;
                               2208                 :              9 :             case 1:
                               2209                 :              9 :                 fputs(",frame=\"none\"", fout);
                               2210                 :              9 :                 break;
                               2211                 :              3 :             case 2:
                               2212                 :              3 :                 fputs(",frame=\"all\",grid=\"all\"", fout);
                               2213                 :              3 :                 break;
                               2214                 :                :         }
                               2215                 :             15 :         fputs("]\n", fout);
                               2216                 :             15 :         fputs("|====\n", fout);
                               2217                 :                : 
                               2218                 :                :         /* print headers */
                               2219         [ +  + ]:             15 :         if (!opt_tuples_only)
                               2220                 :                :         {
                               2221         [ +  + ]:             60 :             for (ptr = cont->headers; *ptr; ptr++)
                               2222                 :                :             {
                               2223         [ +  + ]:             48 :                 if (ptr != cont->headers)
                               2224                 :             36 :                     fputs(" ", fout);
                               2225                 :             48 :                 fputs("^l|", fout);
                               2226                 :             48 :                 asciidoc_escaped_print(*ptr, fout);
                               2227                 :                :             }
                               2228                 :             12 :             fputs("\n", fout);
                               2229                 :                :         }
                               2230                 :                :     }
                               2231                 :                : 
                               2232                 :                :     /* print cells */
                               2233         [ +  + ]:            120 :     for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
                               2234                 :                :     {
                               2235         [ +  + ]:            105 :         if (i % cont->ncolumns == 0)
                               2236                 :                :         {
                               2237         [ -  + ]:             27 :             if (cancel_pressed)
 3863 bruce@momjian.us         2238                 :UBC           0 :                 break;
                               2239                 :                :         }
                               2240                 :                : 
 3863 bruce@momjian.us         2241         [ +  + ]:CBC         105 :         if (i % cont->ncolumns != 0)
                               2242                 :             78 :             fputs(" ", fout);
                               2243                 :            105 :         fputs("|", fout);
                               2244                 :                : 
                               2245                 :                :         /* protect against needless spaces */
                               2246         [ +  + ]:            105 :         if ((*ptr)[strspn(*ptr, " \t")] == '\0')
                               2247                 :                :         {
                               2248         [ +  - ]:             18 :             if ((i + 1) % cont->ncolumns != 0)
                               2249                 :             18 :                 fputs(" ", fout);
                               2250                 :                :         }
                               2251                 :                :         else
                               2252                 :             87 :             asciidoc_escaped_print(*ptr, fout);
                               2253                 :                : 
                               2254         [ +  + ]:            105 :         if ((i + 1) % cont->ncolumns == 0)
                               2255                 :             27 :             fputs("\n", fout);
                               2256                 :                :     }
                               2257                 :                : 
                               2258                 :             15 :     fputs("|====\n", fout);
                               2259                 :                : 
                               2260         [ +  - ]:             15 :     if (cont->opt->stop_table)
                               2261                 :                :     {
                               2262                 :             15 :         printTableFooter *footers = footers_with_default(cont);
                               2263                 :                : 
                               2264                 :                :         /* print footers */
                               2265   [ +  +  +  -  :             15 :         if (!opt_tuples_only && footers != NULL && !cancel_pressed)
                                              +  - ]
                               2266                 :                :         {
                               2267                 :                :             printTableFooter *f;
                               2268                 :                : 
                               2269                 :             12 :             fputs("\n....\n", fout);
                               2270         [ +  + ]:             24 :             for (f = footers; f; f = f->next)
                               2271                 :                :             {
                               2272                 :             12 :                 fputs(f->data, fout);
                               2273                 :             12 :                 fputs("\n", fout);
                               2274                 :                :             }
                               2275                 :             12 :             fputs("....\n", fout);
                               2276                 :                :         }
                               2277                 :                :     }
                               2278                 :                : }
                               2279                 :                : 
                               2280                 :                : static void
                               2281                 :             15 : print_asciidoc_vertical(const printTableContent *cont, FILE *fout)
                               2282                 :                : {
                               2283                 :             15 :     bool        opt_tuples_only = cont->opt->tuples_only;
                               2284                 :             15 :     unsigned short opt_border = cont->opt->border;
                               2285                 :             15 :     unsigned long record = cont->opt->prior_records + 1;
                               2286                 :                :     unsigned int i;
                               2287                 :                :     const char *const *ptr;
                               2288                 :                : 
                               2289         [ -  + ]:             15 :     if (cancel_pressed)
 3863 bruce@momjian.us         2290                 :UBC           0 :         return;
                               2291                 :                : 
 3863 bruce@momjian.us         2292         [ +  - ]:CBC          15 :     if (cont->opt->start_table)
                               2293                 :                :     {
                               2294                 :                :         /* print table in new paragraph - enforce preliminary new line */
                               2295                 :             15 :         fputs("\n", fout);
                               2296                 :                : 
                               2297                 :                :         /* print title */
                               2298   [ +  +  +  + ]:             15 :         if (!opt_tuples_only && cont->title)
                               2299                 :                :         {
                               2300                 :              3 :             fputs(".", fout);
                               2301                 :              3 :             fputs(cont->title, fout);
                               2302                 :              3 :             fputs("\n", fout);
                               2303                 :                :         }
                               2304                 :                : 
                               2305                 :                :         /* print table [] header definition */
                               2306                 :             15 :         fputs("[cols=\"h,l\"", fout);
                               2307   [ +  +  +  - ]:             15 :         switch (opt_border)
                               2308                 :                :         {
                               2309                 :              3 :             case 0:
                               2310                 :              3 :                 fputs(",frame=\"none\",grid=\"none\"", fout);
                               2311                 :              3 :                 break;
                               2312                 :              9 :             case 1:
                               2313                 :              9 :                 fputs(",frame=\"none\"", fout);
                               2314                 :              9 :                 break;
                               2315                 :              3 :             case 2:
                               2316                 :              3 :                 fputs(",frame=\"all\",grid=\"all\"", fout);
 3810                          2317                 :              3 :                 break;
                               2318                 :                :         }
 3863                          2319                 :             15 :         fputs("]\n", fout);
                               2320                 :             15 :         fputs("|====\n", fout);
                               2321                 :                :     }
                               2322                 :                : 
                               2323                 :                :     /* print records */
                               2324         [ +  + ]:            120 :     for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
                               2325                 :                :     {
                               2326         [ +  + ]:            105 :         if (i % cont->ncolumns == 0)
                               2327                 :                :         {
                               2328         [ -  + ]:             27 :             if (cancel_pressed)
 3863 bruce@momjian.us         2329                 :UBC           0 :                 break;
 3863 bruce@momjian.us         2330         [ +  + ]:CBC          27 :             if (!opt_tuples_only)
                               2331                 :             21 :                 fprintf(fout,
                               2332                 :                :                         "2+^|Record %lu\n",
                               2333                 :                :                         record++);
                               2334                 :                :             else
                               2335                 :              6 :                 fputs("2+|\n", fout);
                               2336                 :                :         }
                               2337                 :                : 
                               2338                 :            105 :         fputs("<l|", fout);
                               2339                 :            105 :         asciidoc_escaped_print(cont->headers[i % cont->ncolumns], fout);
                               2340                 :                : 
                               2341         [ +  + ]:            105 :         fprintf(fout, " %s|", cont->aligns[i % cont->ncolumns] == 'r' ? ">l" : "<l");
                               2342                 :                :         /* is string only whitespace? */
                               2343         [ +  + ]:            105 :         if ((*ptr)[strspn(*ptr, " \t")] == '\0')
                               2344                 :             18 :             fputs(" ", fout);
                               2345                 :                :         else
                               2346                 :             87 :             asciidoc_escaped_print(*ptr, fout);
                               2347                 :            105 :         fputs("\n", fout);
                               2348                 :                :     }
                               2349                 :                : 
                               2350                 :             15 :     fputs("|====\n", fout);
                               2351                 :                : 
                               2352         [ +  - ]:             15 :     if (cont->opt->stop_table)
                               2353                 :                :     {
                               2354                 :                :         /* print footers */
                               2355   [ +  +  +  +  :             15 :         if (!opt_tuples_only && cont->footers != NULL && !cancel_pressed)
                                              +  - ]
                               2356                 :                :         {
                               2357                 :                :             printTableFooter *f;
                               2358                 :                : 
                               2359                 :              3 :             fputs("\n....\n", fout);
                               2360         [ +  + ]:              6 :             for (f = cont->footers; f; f = f->next)
                               2361                 :                :             {
                               2362                 :              3 :                 fputs(f->data, fout);
                               2363                 :              3 :                 fputs("\n", fout);
                               2364                 :                :             }
                               2365                 :              3 :             fputs("....\n", fout);
                               2366                 :                :         }
                               2367                 :                :     }
                               2368                 :                : }
                               2369                 :                : 
                               2370                 :                : 
                               2371                 :                : /*************************/
                               2372                 :                : /* LaTeX                 */
                               2373                 :                : /*************************/
                               2374                 :                : 
                               2375                 :                : 
                               2376                 :                : static void
 9489                          2377                 :           1227 : latex_escaped_print(const char *in, FILE *fout)
                               2378                 :                : {
                               2379                 :                :     const char *p;
                               2380                 :                : 
                               2381         [ +  + ]:          10782 :     for (p = in; *p; p++)
                               2382   [ +  +  +  +  :           9555 :         switch (*p)
                                     +  +  +  +  +  
                                     +  +  +  +  +  
                                                 + ]
                               2383                 :                :         {
                               2384                 :                :                 /*
                               2385                 :                :                  * We convert ASCII characters per the recommendations in
                               2386                 :                :                  * Scott Pakin's "The Comprehensive LATEX Symbol List",
                               2387                 :                :                  * available from CTAN.  For non-ASCII, you're on your own.
                               2388                 :                :                  */
 2527 tgl@sss.pgh.pa.us        2389                 :            108 :             case '#':
                               2390                 :            108 :                 fputs("\\#", fout);
                               2391                 :            108 :                 break;
                               2392                 :             96 :             case '$':
                               2393                 :             96 :                 fputs("\\$", fout);
 9489 bruce@momjian.us         2394                 :             96 :                 break;
                               2395                 :            108 :             case '%':
                               2396                 :            108 :                 fputs("\\%", fout);
                               2397                 :            108 :                 break;
 2527 tgl@sss.pgh.pa.us        2398                 :            108 :             case '&':
                               2399                 :            108 :                 fputs("\\&", fout);
                               2400                 :            108 :                 break;
                               2401                 :            108 :             case '<':
                               2402                 :            108 :                 fputs("\\textless{}", fout);
                               2403                 :            108 :                 break;
                               2404                 :            108 :             case '>':
                               2405                 :            108 :                 fputs("\\textgreater{}", fout);
                               2406                 :            108 :                 break;
                               2407                 :            108 :             case '\\':
                               2408                 :            108 :                 fputs("\\textbackslash{}", fout);
                               2409                 :            108 :                 break;
                               2410                 :            108 :             case '^':
                               2411                 :            108 :                 fputs("\\^{}", fout);
 9489 bruce@momjian.us         2412                 :            108 :                 break;
 7752                          2413                 :            234 :             case '_':
                               2414                 :            234 :                 fputs("\\_", fout);
                               2415                 :            234 :                 break;
 9489                          2416                 :            108 :             case '{':
                               2417                 :            108 :                 fputs("\\{", fout);
                               2418                 :            108 :                 break;
 2527 tgl@sss.pgh.pa.us        2419                 :            108 :             case '|':
                               2420                 :            108 :                 fputs("\\textbar{}", fout);
                               2421                 :            108 :                 break;
 9489 bruce@momjian.us         2422                 :            108 :             case '}':
                               2423                 :            108 :                 fputs("\\}", fout);
                               2424                 :            108 :                 break;
 2527 tgl@sss.pgh.pa.us        2425                 :            108 :             case '~':
                               2426                 :            108 :                 fputs("\\~{}", fout);
 9489 bruce@momjian.us         2427                 :            108 :                 break;
                               2428                 :            108 :             case '\n':
                               2429                 :                :                 /* This is not right, but doing it right seems too hard */
                               2430                 :            108 :                 fputs("\\\\", fout);
                               2431                 :            108 :                 break;
                               2432                 :           7929 :             default:
                               2433                 :           7929 :                 fputc(*p, fout);
                               2434                 :                :         }
                               2435                 :           1227 : }
                               2436                 :                : 
                               2437                 :                : 
                               2438                 :                : static void
 6377 alvherre@alvh.no-ip.     2439                 :             18 : print_latex_text(const printTableContent *cont, FILE *fout)
                               2440                 :                : {
                               2441                 :             18 :     bool        opt_tuples_only = cont->opt->tuples_only;
                               2442                 :             18 :     unsigned short opt_border = cont->opt->border;
                               2443                 :                :     unsigned int i;
                               2444                 :                :     const char *const *ptr;
                               2445                 :                : 
 7075 tgl@sss.pgh.pa.us        2446         [ -  + ]:             18 :     if (cancel_pressed)
 7075 tgl@sss.pgh.pa.us        2447                 :UBC           0 :         return;
                               2448                 :                : 
 4666 bruce@momjian.us         2449         [ -  + ]:CBC          18 :     if (opt_border > 3)
 4666 bruce@momjian.us         2450                 :UBC           0 :         opt_border = 3;
                               2451                 :                : 
 6377 alvherre@alvh.no-ip.     2452         [ +  - ]:CBC          18 :     if (cont->opt->start_table)
                               2453                 :                :     {
                               2454                 :                :         /* print title */
                               2455   [ +  +  +  + ]:             18 :         if (!opt_tuples_only && cont->title)
                               2456                 :                :         {
 6999 tgl@sss.pgh.pa.us        2457                 :              3 :             fputs("\\begin{center}\n", fout);
 6377 alvherre@alvh.no-ip.     2458                 :              3 :             latex_escaped_print(cont->title, fout);
 6999 tgl@sss.pgh.pa.us        2459                 :              3 :             fputs("\n\\end{center}\n\n", fout);
                               2460                 :                :         }
                               2461                 :                : 
                               2462                 :                :         /* begin environment and set alignments and borders */
                               2463                 :             18 :         fputs("\\begin{tabular}{", fout);
                               2464                 :                : 
 4666 bruce@momjian.us         2465         [ +  + ]:             18 :         if (opt_border >= 2)
 6999 tgl@sss.pgh.pa.us        2466                 :              6 :             fputs("| ", fout);
 6377 alvherre@alvh.no-ip.     2467         [ +  + ]:            102 :         for (i = 0; i < cont->ncolumns; i++)
                               2468                 :                :         {
                               2469                 :             84 :             fputc(*(cont->aligns + i), fout);
                               2470   [ +  +  +  + ]:             84 :             if (opt_border != 0 && i < cont->ncolumns - 1)
 6999 tgl@sss.pgh.pa.us        2471                 :             57 :                 fputs(" | ", fout);
                               2472                 :                :         }
 4666 bruce@momjian.us         2473         [ +  + ]:             18 :         if (opt_border >= 2)
 6999 tgl@sss.pgh.pa.us        2474                 :              6 :             fputs(" |", fout);
                               2475                 :                : 
                               2476                 :             18 :         fputs("}\n", fout);
                               2477                 :                : 
 4666 bruce@momjian.us         2478   [ +  +  +  + ]:             18 :         if (!opt_tuples_only && opt_border >= 2)
 6999 tgl@sss.pgh.pa.us        2479                 :              6 :             fputs("\\hline\n", fout);
                               2480                 :                : 
                               2481                 :                :         /* print headers */
 7410 bruce@momjian.us         2482         [ +  + ]:             18 :         if (!opt_tuples_only)
                               2483                 :                :         {
 6377 alvherre@alvh.no-ip.     2484         [ +  + ]:             84 :             for (i = 0, ptr = cont->headers; i < cont->ncolumns; i++, ptr++)
                               2485                 :                :             {
 6999 tgl@sss.pgh.pa.us        2486         [ +  + ]:             69 :                 if (i != 0)
                               2487                 :             54 :                     fputs(" & ", fout);
                               2488                 :             69 :                 fputs("\\textit{", fout);
                               2489                 :             69 :                 latex_escaped_print(*ptr, fout);
                               2490                 :             69 :                 fputc('}', fout);
                               2491                 :                :             }
                               2492                 :             15 :             fputs(" \\\\\n", fout);
                               2493                 :             15 :             fputs("\\hline\n", fout);
                               2494                 :                :         }
                               2495                 :                :     }
                               2496                 :                : 
                               2497                 :                :     /* print cells */
 6377 alvherre@alvh.no-ip.     2498         [ +  + ]:            165 :     for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
                               2499                 :                :     {
 5719 heikki.linnakangas@i     2500                 :            147 :         latex_escaped_print(*ptr, fout);
                               2501                 :                : 
 6377 alvherre@alvh.no-ip.     2502         [ +  + ]:            147 :         if ((i + 1) % cont->ncolumns == 0)
                               2503                 :                :         {
 9489 bruce@momjian.us         2504                 :             33 :             fputs(" \\\\\n", fout);
 4666                          2505         [ +  + ]:             33 :             if (opt_border == 3)
                               2506                 :              6 :                 fputs("\\hline\n", fout);
 7075 tgl@sss.pgh.pa.us        2507         [ -  + ]:             33 :             if (cancel_pressed)
 7075 tgl@sss.pgh.pa.us        2508                 :UBC           0 :                 break;
                               2509                 :                :         }
                               2510                 :                :         else
 9489 bruce@momjian.us         2511                 :CBC         114 :             fputs(" & ", fout);
                               2512                 :                :     }
                               2513                 :                : 
 6377 alvherre@alvh.no-ip.     2514         [ +  - ]:             18 :     if (cont->opt->stop_table)
                               2515                 :                :     {
 4927 rhaas@postgresql.org     2516                 :             18 :         printTableFooter *footers = footers_with_default(cont);
                               2517                 :                : 
 4665 bruce@momjian.us         2518         [ +  + ]:             18 :         if (opt_border == 2)
 6999 tgl@sss.pgh.pa.us        2519                 :              3 :             fputs("\\hline\n", fout);
                               2520                 :                : 
                               2521                 :             18 :         fputs("\\end{tabular}\n\n\\noindent ", fout);
                               2522                 :                : 
                               2523                 :                :         /* print footers */
 4927 rhaas@postgresql.org     2524   [ +  -  +  +  :             18 :         if (footers && !opt_tuples_only && !cancel_pressed)
                                              +  - ]
                               2525                 :                :         {
                               2526                 :                :             printTableFooter *f;
                               2527                 :                : 
                               2528         [ +  + ]:             30 :             for (f = footers; f; f = f->next)
                               2529                 :                :             {
 6377 alvherre@alvh.no-ip.     2530                 :             15 :                 latex_escaped_print(f->data, fout);
 6999 tgl@sss.pgh.pa.us        2531                 :             15 :                 fputs(" \\\\\n", fout);
                               2532                 :                :             }
                               2533                 :                :         }
                               2534                 :                : 
                               2535                 :             18 :         fputc('\n', fout);
                               2536                 :                :     }
                               2537                 :                : }
                               2538                 :                : 
                               2539                 :                : 
                               2540                 :                : /*************************/
                               2541                 :                : /* LaTeX longtable       */
                               2542                 :                : /*************************/
                               2543                 :                : 
                               2544                 :                : 
                               2545                 :                : static void
 4665 bruce@momjian.us         2546                 :             21 : print_latex_longtable_text(const printTableContent *cont, FILE *fout)
                               2547                 :                : {
 4666                          2548                 :             21 :     bool        opt_tuples_only = cont->opt->tuples_only;
                               2549                 :             21 :     unsigned short opt_border = cont->opt->border;
                               2550                 :                :     unsigned int i;
                               2551                 :             21 :     const char *opt_table_attr = cont->opt->tableAttr;
                               2552                 :             21 :     const char *next_opt_table_attr_char = opt_table_attr;
                               2553                 :             21 :     const char *last_opt_table_attr_char = NULL;
                               2554                 :                :     const char *const *ptr;
                               2555                 :                : 
                               2556         [ -  + ]:             21 :     if (cancel_pressed)
 4666 bruce@momjian.us         2557                 :UBC           0 :         return;
                               2558                 :                : 
 4666 bruce@momjian.us         2559         [ -  + ]:CBC          21 :     if (opt_border > 3)
 4666 bruce@momjian.us         2560                 :UBC           0 :         opt_border = 3;
                               2561                 :                : 
 4666 bruce@momjian.us         2562         [ +  - ]:CBC          21 :     if (cont->opt->start_table)
                               2563                 :                :     {
                               2564                 :                :         /* begin environment and set alignments and borders */
                               2565                 :             21 :         fputs("\\begin{longtable}{", fout);
                               2566                 :                : 
                               2567         [ +  + ]:             21 :         if (opt_border >= 2)
                               2568                 :              9 :             fputs("| ", fout);
                               2569                 :                : 
                               2570         [ +  + ]:            117 :         for (i = 0; i < cont->ncolumns; i++)
                               2571                 :                :         {
                               2572                 :                :             /* longtable supports either a width (p) or an alignment (l/r) */
                               2573                 :                :             /* Are we left-justified and was a proportional width specified? */
                               2574   [ +  +  +  + ]:             96 :             if (*(cont->aligns + i) == 'l' && opt_table_attr)
                               2575                 :                :             {
                               2576                 :                : #define LONGTABLE_WHITESPACE    " \t\n"
                               2577                 :                : 
                               2578                 :                :                 /* advance over whitespace */
                               2579                 :              9 :                 next_opt_table_attr_char += strspn(next_opt_table_attr_char,
                               2580                 :                :                                                    LONGTABLE_WHITESPACE);
                               2581                 :                :                 /* We have a value? */
                               2582         [ +  + ]:              9 :                 if (next_opt_table_attr_char[0] != '\0')
                               2583                 :                :                 {
                               2584                 :              3 :                     fputs("p{", fout);
                               2585                 :              3 :                     fwrite(next_opt_table_attr_char, strcspn(next_opt_table_attr_char,
                               2586                 :                :                                                              LONGTABLE_WHITESPACE), 1, fout);
                               2587                 :              3 :                     last_opt_table_attr_char = next_opt_table_attr_char;
                               2588                 :              3 :                     next_opt_table_attr_char += strcspn(next_opt_table_attr_char,
                               2589                 :                :                                                         LONGTABLE_WHITESPACE);
                               2590                 :              3 :                     fputs("\\textwidth}", fout);
                               2591                 :                :                 }
                               2592                 :                :                 /* use previous value */
                               2593         [ +  - ]:              6 :                 else if (last_opt_table_attr_char != NULL)
                               2594                 :                :                 {
                               2595                 :              6 :                     fputs("p{", fout);
                               2596                 :              6 :                     fwrite(last_opt_table_attr_char, strcspn(last_opt_table_attr_char,
                               2597                 :                :                                                              LONGTABLE_WHITESPACE), 1, fout);
                               2598                 :              6 :                     fputs("\\textwidth}", fout);
                               2599                 :                :                 }
                               2600                 :                :                 else
 4666 bruce@momjian.us         2601                 :UBC           0 :                     fputc('l', fout);
                               2602                 :                :             }
                               2603                 :                :             else
 4666 bruce@momjian.us         2604                 :CBC          87 :                 fputc(*(cont->aligns + i), fout);
                               2605                 :                : 
                               2606   [ +  +  +  + ]:             96 :             if (opt_border != 0 && i < cont->ncolumns - 1)
                               2607                 :             66 :                 fputs(" | ", fout);
                               2608                 :                :         }
                               2609                 :                : 
                               2610         [ +  + ]:             21 :         if (opt_border >= 2)
                               2611                 :              9 :             fputs(" |", fout);
                               2612                 :                : 
                               2613                 :             21 :         fputs("}\n", fout);
                               2614                 :                : 
                               2615                 :                :         /* print headers */
                               2616         [ +  + ]:             21 :         if (!opt_tuples_only)
                               2617                 :                :         {
                               2618                 :                :             /* firsthead */
                               2619         [ +  + ]:             18 :             if (opt_border >= 2)
                               2620                 :              9 :                 fputs("\\toprule\n", fout);
                               2621         [ +  + ]:             99 :             for (i = 0, ptr = cont->headers; i < cont->ncolumns; i++, ptr++)
                               2622                 :                :             {
                               2623         [ +  + ]:             81 :                 if (i != 0)
                               2624                 :             63 :                     fputs(" & ", fout);
                               2625                 :             81 :                 fputs("\\small\\textbf{\\textit{", fout);
                               2626                 :             81 :                 latex_escaped_print(*ptr, fout);
                               2627                 :             81 :                 fputs("}}", fout);
                               2628                 :                :             }
                               2629                 :             18 :             fputs(" \\\\\n", fout);
                               2630                 :             18 :             fputs("\\midrule\n\\endfirsthead\n", fout);
                               2631                 :                : 
                               2632                 :                :             /* secondary heads */
                               2633         [ +  + ]:             18 :             if (opt_border >= 2)
                               2634                 :              9 :                 fputs("\\toprule\n", fout);
                               2635         [ +  + ]:             99 :             for (i = 0, ptr = cont->headers; i < cont->ncolumns; i++, ptr++)
                               2636                 :                :             {
                               2637         [ +  + ]:             81 :                 if (i != 0)
                               2638                 :             63 :                     fputs(" & ", fout);
                               2639                 :             81 :                 fputs("\\small\\textbf{\\textit{", fout);
                               2640                 :             81 :                 latex_escaped_print(*ptr, fout);
                               2641                 :             81 :                 fputs("}}", fout);
                               2642                 :                :             }
                               2643                 :             18 :             fputs(" \\\\\n", fout);
                               2644                 :                :             /* If the line under the row already appeared, don't do another */
                               2645         [ +  + ]:             18 :             if (opt_border != 3)
                               2646                 :             12 :                 fputs("\\midrule\n", fout);
                               2647                 :             18 :             fputs("\\endhead\n", fout);
                               2648                 :                : 
                               2649                 :                :             /* table name, caption? */
                               2650   [ +  -  +  + ]:             18 :             if (!opt_tuples_only && cont->title)
                               2651                 :                :             {
                               2652                 :                :                 /* Don't output if we are printing a line under each row */
                               2653         [ -  + ]:              3 :                 if (opt_border == 2)
 4666 bruce@momjian.us         2654                 :UBC           0 :                     fputs("\\bottomrule\n", fout);
 4666 bruce@momjian.us         2655                 :CBC           3 :                 fputs("\\caption[", fout);
                               2656                 :              3 :                 latex_escaped_print(cont->title, fout);
                               2657                 :              3 :                 fputs(" (Continued)]{", fout);
                               2658                 :              3 :                 latex_escaped_print(cont->title, fout);
                               2659                 :              3 :                 fputs("}\n\\endfoot\n", fout);
                               2660         [ -  + ]:              3 :                 if (opt_border == 2)
 4666 bruce@momjian.us         2661                 :UBC           0 :                     fputs("\\bottomrule\n", fout);
 4666 bruce@momjian.us         2662                 :CBC           3 :                 fputs("\\caption[", fout);
                               2663                 :              3 :                 latex_escaped_print(cont->title, fout);
                               2664                 :              3 :                 fputs("]{", fout);
                               2665                 :              3 :                 latex_escaped_print(cont->title, fout);
                               2666                 :              3 :                 fputs("}\n\\endlastfoot\n", fout);
                               2667                 :                :             }
                               2668                 :                :             /* output bottom table line? */
                               2669         [ +  + ]:             15 :             else if (opt_border >= 2)
                               2670                 :                :             {
                               2671                 :              9 :                 fputs("\\bottomrule\n\\endfoot\n", fout);
                               2672                 :              9 :                 fputs("\\bottomrule\n\\endlastfoot\n", fout);
                               2673                 :                :             }
                               2674                 :                :         }
                               2675                 :                :     }
                               2676                 :                : 
                               2677                 :                :     /* print cells */
                               2678         [ +  + ]:            192 :     for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
                               2679                 :                :     {
                               2680                 :                :         /* Add a line under each row? */
                               2681   [ +  +  +  + ]:            171 :         if (i != 0 && i % cont->ncolumns != 0)
                               2682                 :            132 :             fputs("\n&\n", fout);
                               2683                 :            171 :         fputs("\\raggedright{", fout);
                               2684                 :            171 :         latex_escaped_print(*ptr, fout);
                               2685                 :            171 :         fputc('}', fout);
                               2686         [ +  + ]:            171 :         if ((i + 1) % cont->ncolumns == 0)
                               2687                 :                :         {
                               2688                 :             39 :             fputs(" \\tabularnewline\n", fout);
                               2689         [ +  + ]:             39 :             if (opt_border == 3)
                               2690                 :             12 :                 fputs(" \\hline\n", fout);
                               2691                 :                :         }
                               2692         [ -  + ]:            171 :         if (cancel_pressed)
 4666 bruce@momjian.us         2693                 :UBC           0 :             break;
                               2694                 :                :     }
                               2695                 :                : 
 4666 bruce@momjian.us         2696         [ +  - ]:CBC          21 :     if (cont->opt->stop_table)
                               2697                 :             21 :         fputs("\\end{longtable}\n", fout);
                               2698                 :                : }
                               2699                 :                : 
                               2700                 :                : 
                               2701                 :                : static void
 6377 alvherre@alvh.no-ip.     2702                 :             39 : print_latex_vertical(const printTableContent *cont, FILE *fout)
                               2703                 :                : {
                               2704                 :             39 :     bool        opt_tuples_only = cont->opt->tuples_only;
                               2705                 :             39 :     unsigned short opt_border = cont->opt->border;
                               2706                 :             39 :     unsigned long record = cont->opt->prior_records + 1;
                               2707                 :                :     unsigned int i;
                               2708                 :                :     const char *const *ptr;
                               2709                 :                : 
 7075 tgl@sss.pgh.pa.us        2710         [ -  + ]:             39 :     if (cancel_pressed)
 7075 tgl@sss.pgh.pa.us        2711                 :UBC           0 :         return;
                               2712                 :                : 
 6999 tgl@sss.pgh.pa.us        2713         [ +  + ]:CBC          39 :     if (opt_border > 2)
                               2714                 :              9 :         opt_border = 2;
                               2715                 :                : 
 6377 alvherre@alvh.no-ip.     2716         [ +  - ]:             39 :     if (cont->opt->start_table)
                               2717                 :                :     {
                               2718                 :                :         /* print title */
                               2719   [ +  +  +  + ]:             39 :         if (!opt_tuples_only && cont->title)
                               2720                 :                :         {
 6999 tgl@sss.pgh.pa.us        2721                 :              6 :             fputs("\\begin{center}\n", fout);
 6377 alvherre@alvh.no-ip.     2722                 :              6 :             latex_escaped_print(cont->title, fout);
 6999 tgl@sss.pgh.pa.us        2723                 :              6 :             fputs("\n\\end{center}\n\n", fout);
                               2724                 :                :         }
                               2725                 :                : 
                               2726                 :                :         /* begin environment and set alignments and borders */
                               2727                 :             39 :         fputs("\\begin{tabular}{", fout);
                               2728         [ +  + ]:             39 :         if (opt_border == 0)
                               2729                 :              6 :             fputs("cl", fout);
                               2730         [ +  + ]:             33 :         else if (opt_border == 1)
                               2731                 :             18 :             fputs("c|l", fout);
                               2732         [ +  - ]:             15 :         else if (opt_border == 2)
                               2733                 :             15 :             fputs("|c|l|", fout);
                               2734                 :             39 :         fputs("}\n", fout);
                               2735                 :                :     }
                               2736                 :                : 
                               2737                 :                :     /* print records */
 6377 alvherre@alvh.no-ip.     2738         [ +  + ]:            357 :     for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
                               2739                 :                :     {
                               2740                 :                :         /* new record */
                               2741         [ +  + ]:            318 :         if (i % cont->ncolumns == 0)
                               2742                 :                :         {
 7075 tgl@sss.pgh.pa.us        2743         [ -  + ]:             72 :             if (cancel_pressed)
 7075 tgl@sss.pgh.pa.us        2744                 :UBC           0 :                 break;
 7410 bruce@momjian.us         2745         [ +  + ]:CBC          72 :             if (!opt_tuples_only)
                               2746                 :                :             {
 9489                          2747         [ +  + ]:             60 :                 if (opt_border == 2)
                               2748                 :                :                 {
                               2749                 :             30 :                     fputs("\\hline\n", fout);
 6999 tgl@sss.pgh.pa.us        2750                 :             30 :                     fprintf(fout, "\\multicolumn{2}{|c|}{\\textit{Record %lu}} \\\\\n", record++);
                               2751                 :                :                 }
                               2752                 :                :                 else
                               2753                 :             30 :                     fprintf(fout, "\\multicolumn{2}{c}{\\textit{Record %lu}} \\\\\n", record++);
                               2754                 :                :             }
 9489 bruce@momjian.us         2755         [ +  + ]:             72 :             if (opt_border >= 1)
                               2756                 :             60 :                 fputs("\\hline\n", fout);
                               2757                 :                :         }
                               2758                 :                : 
 6377 alvherre@alvh.no-ip.     2759                 :            318 :         latex_escaped_print(cont->headers[i % cont->ncolumns], fout);
 9489 bruce@momjian.us         2760                 :            318 :         fputs(" & ", fout);
                               2761                 :            318 :         latex_escaped_print(*ptr, fout);
                               2762                 :            318 :         fputs(" \\\\\n", fout);
                               2763                 :                :     }
                               2764                 :                : 
 6377 alvherre@alvh.no-ip.     2765         [ +  - ]:             39 :     if (cont->opt->stop_table)
                               2766                 :                :     {
 6999 tgl@sss.pgh.pa.us        2767         [ +  + ]:             39 :         if (opt_border == 2)
                               2768                 :             15 :             fputs("\\hline\n", fout);
                               2769                 :                : 
                               2770                 :             39 :         fputs("\\end{tabular}\n\n\\noindent ", fout);
                               2771                 :                : 
                               2772                 :                :         /* print footers */
 6377 alvherre@alvh.no-ip.     2773   [ +  +  +  -  :             39 :         if (cont->footers && !opt_tuples_only && !cancel_pressed)
                                              +  - ]
                               2774                 :                :         {
                               2775                 :                :             printTableFooter *f;
                               2776                 :                : 
                               2777         [ +  + ]:             12 :             for (f = cont->footers; f; f = f->next)
                               2778                 :                :             {
 5719 heikki.linnakangas@i     2779                 :              6 :                 latex_escaped_print(f->data, fout);
 6999 tgl@sss.pgh.pa.us        2780                 :              6 :                 fputs(" \\\\\n", fout);
                               2781                 :                :             }
                               2782                 :                :         }
                               2783                 :                : 
                               2784                 :             39 :         fputc('\n', fout);
                               2785                 :                :     }
                               2786                 :                : }
                               2787                 :                : 
                               2788                 :                : 
                               2789                 :                : /*************************/
                               2790                 :                : /* Troff -ms             */
                               2791                 :                : /*************************/
                               2792                 :                : 
                               2793                 :                : 
                               2794                 :                : static void
 7445 bruce@momjian.us         2795                 :            447 : troff_ms_escaped_print(const char *in, FILE *fout)
                               2796                 :                : {
                               2797                 :                :     const char *p;
                               2798                 :                : 
                               2799         [ +  + ]:           3594 :     for (p = in; *p; p++)
                               2800         [ +  + ]:           3147 :         switch (*p)
                               2801                 :                :         {
                               2802                 :             63 :             case '\\':
                               2803                 :             63 :                 fputs("\\(rs", fout);
                               2804                 :             63 :                 break;
                               2805                 :           3084 :             default:
                               2806                 :           3084 :                 fputc(*p, fout);
                               2807                 :                :         }
                               2808                 :            447 : }
                               2809                 :                : 
                               2810                 :                : 
                               2811                 :                : static void
 6377 alvherre@alvh.no-ip.     2812                 :             15 : print_troff_ms_text(const printTableContent *cont, FILE *fout)
                               2813                 :                : {
                               2814                 :             15 :     bool        opt_tuples_only = cont->opt->tuples_only;
                               2815                 :             15 :     unsigned short opt_border = cont->opt->border;
                               2816                 :                :     unsigned int i;
                               2817                 :                :     const char *const *ptr;
                               2818                 :                : 
 7075 tgl@sss.pgh.pa.us        2819         [ -  + ]:             15 :     if (cancel_pressed)
 7075 tgl@sss.pgh.pa.us        2820                 :UBC           0 :         return;
                               2821                 :                : 
 6999 tgl@sss.pgh.pa.us        2822         [ -  + ]:CBC          15 :     if (opt_border > 2)
 6999 tgl@sss.pgh.pa.us        2823                 :UBC           0 :         opt_border = 2;
                               2824                 :                : 
 6377 alvherre@alvh.no-ip.     2825         [ +  - ]:CBC          15 :     if (cont->opt->start_table)
                               2826                 :                :     {
                               2827                 :                :         /* print title */
                               2828   [ +  +  +  + ]:             15 :         if (!opt_tuples_only && cont->title)
                               2829                 :                :         {
 6999 tgl@sss.pgh.pa.us        2830                 :              3 :             fputs(".LP\n.DS C\n", fout);
 6377 alvherre@alvh.no-ip.     2831                 :              3 :             troff_ms_escaped_print(cont->title, fout);
 6999 tgl@sss.pgh.pa.us        2832                 :              3 :             fputs("\n.DE\n", fout);
                               2833                 :                :         }
                               2834                 :                : 
                               2835                 :                :         /* begin environment and set alignments and borders */
                               2836                 :             15 :         fputs(".LP\n.TS\n", fout);
                               2837         [ +  + ]:             15 :         if (opt_border == 2)
                               2838                 :              3 :             fputs("center box;\n", fout);
                               2839                 :                :         else
                               2840                 :             12 :             fputs("center;\n", fout);
                               2841                 :                : 
 6377 alvherre@alvh.no-ip.     2842         [ +  + ]:             87 :         for (i = 0; i < cont->ncolumns; i++)
                               2843                 :                :         {
                               2844                 :             72 :             fputc(*(cont->aligns + i), fout);
                               2845   [ +  +  +  + ]:             72 :             if (opt_border > 0 && i < cont->ncolumns - 1)
 6999 tgl@sss.pgh.pa.us        2846                 :             48 :                 fputs(" | ", fout);
                               2847                 :                :         }
                               2848                 :             15 :         fputs(".\n", fout);
                               2849                 :                : 
                               2850                 :                :         /* print headers */
 7410 bruce@momjian.us         2851         [ +  + ]:             15 :         if (!opt_tuples_only)
                               2852                 :                :         {
 6377 alvherre@alvh.no-ip.     2853         [ +  + ]:             69 :             for (i = 0, ptr = cont->headers; i < cont->ncolumns; i++, ptr++)
                               2854                 :                :             {
 6999 tgl@sss.pgh.pa.us        2855         [ +  + ]:             57 :                 if (i != 0)
                               2856                 :             45 :                     fputc('\t', fout);
                               2857                 :             57 :                 fputs("\\fI", fout);
                               2858                 :             57 :                 troff_ms_escaped_print(*ptr, fout);
                               2859                 :             57 :                 fputs("\\fP", fout);
                               2860                 :                :             }
                               2861                 :             12 :             fputs("\n_\n", fout);
                               2862                 :                :         }
                               2863                 :                :     }
                               2864                 :                : 
                               2865                 :                :     /* print cells */
 6377 alvherre@alvh.no-ip.     2866         [ +  + ]:            138 :     for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
                               2867                 :                :     {
 5719 heikki.linnakangas@i     2868                 :            123 :         troff_ms_escaped_print(*ptr, fout);
                               2869                 :                : 
 6377 alvherre@alvh.no-ip.     2870         [ +  + ]:            123 :         if ((i + 1) % cont->ncolumns == 0)
                               2871                 :                :         {
 7445 bruce@momjian.us         2872                 :             27 :             fputc('\n', fout);
 7075 tgl@sss.pgh.pa.us        2873         [ -  + ]:             27 :             if (cancel_pressed)
 7075 tgl@sss.pgh.pa.us        2874                 :UBC           0 :                 break;
                               2875                 :                :         }
                               2876                 :                :         else
 7445 bruce@momjian.us         2877                 :CBC          96 :             fputc('\t', fout);
                               2878                 :                :     }
                               2879                 :                : 
 6377 alvherre@alvh.no-ip.     2880         [ +  - ]:             15 :     if (cont->opt->stop_table)
                               2881                 :                :     {
 4927 rhaas@postgresql.org     2882                 :             15 :         printTableFooter *footers = footers_with_default(cont);
                               2883                 :                : 
 6999 tgl@sss.pgh.pa.us        2884                 :             15 :         fputs(".TE\n.DS L\n", fout);
                               2885                 :                : 
                               2886                 :                :         /* print footers */
 4927 rhaas@postgresql.org     2887   [ +  -  +  +  :             15 :         if (footers && !opt_tuples_only && !cancel_pressed)
                                              +  - ]
                               2888                 :                :         {
                               2889                 :                :             printTableFooter *f;
                               2890                 :                : 
                               2891         [ +  + ]:             24 :             for (f = footers; f; f = f->next)
                               2892                 :                :             {
 6377 alvherre@alvh.no-ip.     2893                 :             12 :                 troff_ms_escaped_print(f->data, fout);
 6999 tgl@sss.pgh.pa.us        2894                 :             12 :                 fputc('\n', fout);
                               2895                 :                :             }
                               2896                 :                :         }
                               2897                 :                : 
                               2898                 :             15 :         fputs(".DE\n", fout);
                               2899                 :                :     }
                               2900                 :                : }
                               2901                 :                : 
                               2902                 :                : 
                               2903                 :                : static void
 6377 alvherre@alvh.no-ip.     2904                 :             15 : print_troff_ms_vertical(const printTableContent *cont, FILE *fout)
                               2905                 :                : {
                               2906                 :             15 :     bool        opt_tuples_only = cont->opt->tuples_only;
                               2907                 :             15 :     unsigned short opt_border = cont->opt->border;
                               2908                 :             15 :     unsigned long record = cont->opt->prior_records + 1;
                               2909                 :                :     unsigned int i;
                               2910                 :                :     const char *const *ptr;
 7317 bruce@momjian.us         2911                 :             15 :     unsigned short current_format = 0;  /* 0=none, 1=header, 2=body */
                               2912                 :                : 
 7075 tgl@sss.pgh.pa.us        2913         [ -  + ]:             15 :     if (cancel_pressed)
 7075 tgl@sss.pgh.pa.us        2914                 :UBC           0 :         return;
                               2915                 :                : 
 6999 tgl@sss.pgh.pa.us        2916         [ -  + ]:CBC          15 :     if (opt_border > 2)
 6999 tgl@sss.pgh.pa.us        2917                 :UBC           0 :         opt_border = 2;
                               2918                 :                : 
 6377 alvherre@alvh.no-ip.     2919         [ +  - ]:CBC          15 :     if (cont->opt->start_table)
                               2920                 :                :     {
                               2921                 :                :         /* print title */
                               2922   [ +  +  +  + ]:             15 :         if (!opt_tuples_only && cont->title)
                               2923                 :                :         {
 6999 tgl@sss.pgh.pa.us        2924                 :              3 :             fputs(".LP\n.DS C\n", fout);
 6377 alvherre@alvh.no-ip.     2925                 :              3 :             troff_ms_escaped_print(cont->title, fout);
 6999 tgl@sss.pgh.pa.us        2926                 :              3 :             fputs("\n.DE\n", fout);
                               2927                 :                :         }
                               2928                 :                : 
                               2929                 :                :         /* begin environment and set alignments and borders */
                               2930                 :             15 :         fputs(".LP\n.TS\n", fout);
                               2931         [ +  + ]:             15 :         if (opt_border == 2)
                               2932                 :              3 :             fputs("center box;\n", fout);
                               2933                 :                :         else
                               2934                 :             12 :             fputs("center;\n", fout);
                               2935                 :                : 
                               2936                 :                :         /* basic format */
                               2937         [ +  + ]:             15 :         if (opt_tuples_only)
                               2938                 :              3 :             fputs("c l;\n", fout);
                               2939                 :                :     }
                               2940                 :                :     else
 6999 tgl@sss.pgh.pa.us        2941                 :UBC           0 :         current_format = 2;     /* assume tuples printed already */
                               2942                 :                : 
                               2943                 :                :     /* print records */
 6377 alvherre@alvh.no-ip.     2944         [ +  + ]:CBC         138 :     for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
                               2945                 :                :     {
                               2946                 :                :         /* new record */
                               2947         [ +  + ]:            123 :         if (i % cont->ncolumns == 0)
                               2948                 :                :         {
 7075 tgl@sss.pgh.pa.us        2949         [ -  + ]:             27 :             if (cancel_pressed)
 7075 tgl@sss.pgh.pa.us        2950                 :UBC           0 :                 break;
 7410 bruce@momjian.us         2951         [ +  + ]:CBC          27 :             if (!opt_tuples_only)
                               2952                 :                :             {
 7445                          2953         [ +  - ]:             21 :                 if (current_format != 1)
                               2954                 :                :                 {
 6999 tgl@sss.pgh.pa.us        2955   [ +  +  +  + ]:             21 :                     if (opt_border == 2 && record > 1)
 7445 bruce@momjian.us         2956                 :              3 :                         fputs("_\n", fout);
                               2957         [ +  + ]:             21 :                     if (current_format != 0)
                               2958                 :              9 :                         fputs(".T&\n", fout);
                               2959                 :             21 :                     fputs("c s.\n", fout);
                               2960                 :             21 :                     current_format = 1;
                               2961                 :                :                 }
 6999 tgl@sss.pgh.pa.us        2962                 :             21 :                 fprintf(fout, "\\fIRecord %lu\\fP\n", record++);
                               2963                 :                :             }
 7445 bruce@momjian.us         2964         [ +  + ]:             27 :             if (opt_border >= 1)
                               2965                 :             21 :                 fputs("_\n", fout);
                               2966                 :                :         }
                               2967                 :                : 
 7410                          2968         [ +  + ]:            123 :         if (!opt_tuples_only)
                               2969                 :                :         {
 7445                          2970         [ +  + ]:             93 :             if (current_format != 2)
                               2971                 :                :             {
                               2972         [ +  - ]:             21 :                 if (current_format != 0)
                               2973                 :             21 :                     fputs(".T&\n", fout);
                               2974         [ +  + ]:             21 :                 if (opt_border != 1)
                               2975                 :             12 :                     fputs("c l.\n", fout);
                               2976                 :                :                 else
                               2977                 :              9 :                     fputs("c | l.\n", fout);
                               2978                 :             21 :                 current_format = 2;
                               2979                 :                :             }
                               2980                 :                :         }
                               2981                 :                : 
 6377 alvherre@alvh.no-ip.     2982                 :            123 :         troff_ms_escaped_print(cont->headers[i % cont->ncolumns], fout);
 7445 bruce@momjian.us         2983                 :            123 :         fputc('\t', fout);
 5719 heikki.linnakangas@i     2984                 :            123 :         troff_ms_escaped_print(*ptr, fout);
                               2985                 :                : 
 7445 bruce@momjian.us         2986                 :            123 :         fputc('\n', fout);
                               2987                 :                :     }
                               2988                 :                : 
 6377 alvherre@alvh.no-ip.     2989         [ +  - ]:             15 :     if (cont->opt->stop_table)
                               2990                 :                :     {
 6999 tgl@sss.pgh.pa.us        2991                 :             15 :         fputs(".TE\n.DS L\n", fout);
                               2992                 :                : 
                               2993                 :                :         /* print footers */
 6377 alvherre@alvh.no-ip.     2994   [ +  +  +  -  :             15 :         if (cont->footers && !opt_tuples_only && !cancel_pressed)
                                              +  - ]
                               2995                 :                :         {
                               2996                 :                :             printTableFooter *f;
                               2997                 :                : 
                               2998         [ +  + ]:              6 :             for (f = cont->footers; f; f = f->next)
                               2999                 :                :             {
                               3000                 :              3 :                 troff_ms_escaped_print(f->data, fout);
 6999 tgl@sss.pgh.pa.us        3001                 :              3 :                 fputc('\n', fout);
                               3002                 :                :             }
                               3003                 :                :         }
                               3004                 :                : 
                               3005                 :             15 :         fputs(".DE\n", fout);
                               3006                 :                :     }
                               3007                 :                : }
                               3008                 :                : 
                               3009                 :                : 
                               3010                 :                : /********************************/
                               3011                 :                : /* Public functions             */
                               3012                 :                : /********************************/
                               3013                 :                : 
                               3014                 :                : 
                               3015                 :                : /*
                               3016                 :                :  * disable_sigpipe_trap
                               3017                 :                :  *
                               3018                 :                :  * Turn off SIGPIPE interrupt --- call this before writing to a temporary
                               3019                 :                :  * query output file that is a pipe.
                               3020                 :                :  *
                               3021                 :                :  * No-op on Windows, where there's no SIGPIPE interrupts.
                               3022                 :                :  */
                               3023                 :                : void
 3616                          3024                 :              7 : disable_sigpipe_trap(void)
                               3025                 :                : {
                               3026                 :                : #ifndef WIN32
                               3027                 :              7 :     pqsignal(SIGPIPE, SIG_IGN);
                               3028                 :                : #endif
                               3029                 :              7 : }
                               3030                 :                : 
                               3031                 :                : /*
                               3032                 :                :  * restore_sigpipe_trap
                               3033                 :                :  *
                               3034                 :                :  * Restore normal SIGPIPE interrupt --- call this when done writing to a
                               3035                 :                :  * temporary query output file that was (or might have been) a pipe.
                               3036                 :                :  *
                               3037                 :                :  * Note: within psql, we enable SIGPIPE interrupts unless the permanent query
                               3038                 :                :  * output file is a pipe, in which case they should be kept off.  This
                               3039                 :                :  * approach works only because psql is not currently complicated enough to
                               3040                 :                :  * have nested usages of short-lived output files.  Otherwise we'd probably
                               3041                 :                :  * need a genuine save-and-restore-state approach; but for now, that would be
                               3042                 :                :  * useless complication.  In non-psql programs, this always enables SIGPIPE.
                               3043                 :                :  *
                               3044                 :                :  * No-op on Windows, where there's no SIGPIPE interrupts.
                               3045                 :                :  */
                               3046                 :                : void
                               3047                 :           8312 : restore_sigpipe_trap(void)
                               3048                 :                : {
                               3049                 :                : #ifndef WIN32
                               3050         [ -  + ]:           8312 :     pqsignal(SIGPIPE, always_ignore_sigpipe ? SIG_IGN : SIG_DFL);
                               3051                 :                : #endif
                               3052                 :           8312 : }
                               3053                 :                : 
                               3054                 :                : /*
                               3055                 :                :  * set_sigpipe_trap_state
                               3056                 :                :  *
                               3057                 :                :  * Set the trap state that restore_sigpipe_trap should restore to.
                               3058                 :                :  */
                               3059                 :                : void
                               3060                 :           8305 : set_sigpipe_trap_state(bool ignore)
                               3061                 :                : {
                               3062                 :           8305 :     always_ignore_sigpipe = ignore;
                               3063                 :           8305 : }
                               3064                 :                : 
                               3065                 :                : 
                               3066                 :                : /*
                               3067                 :                :  * PageOutput
                               3068                 :                :  *
                               3069                 :                :  * Tests if pager is needed and returns appropriate FILE pointer
                               3070                 :                :  * (either a pipe, or stdout if we don't need the pager).
                               3071                 :                :  *
                               3072                 :                :  * lines: number of lines that will be printed
                               3073                 :                :  * topt: print formatting options
                               3074                 :                :  *
                               3075                 :                :  * If the topt argument is NULL no pager is used.
                               3076                 :                :  */
                               3077                 :                : FILE *
 3866 andrew@dunslane.net      3078                 :            437 : PageOutput(int lines, const printTableOpt *topt)
                               3079                 :                : {
   20 tgl@sss.pgh.pa.us        3080                 :GNC         437 :     return PageOutputInternal(lines, topt, NULL, NULL, false);
                               3081                 :                : }
                               3082                 :                : 
                               3083                 :                : /*
                               3084                 :                :  * Private version that allows for line-counting to be avoided when
                               3085                 :                :  * not needed.  If "cont" is not null then the input value of "lines"
                               3086                 :                :  * is ignored and we count lines based on cont + width_wrap + vertical
                               3087                 :                :  * (see count_table_lines).
                               3088                 :                :  */
                               3089                 :                : static FILE *
                               3090                 :          69722 : PageOutputInternal(int lines, const printTableOpt *topt,
                               3091                 :                :                    const printTableContent *cont,
                               3092                 :                :                    const unsigned int *width_wrap,
                               3093                 :                :                    bool vertical)
                               3094                 :                : {
                               3095                 :                :     /* check whether we need / can / are supposed to use pager */
 3866 andrew@dunslane.net      3096   [ +  +  +  +  :CBC       69722 :     if (topt && topt->pager && isatty(fileno(stdin)) && isatty(fileno(stdout)))
                                        +  +  +  - ]
                               3097                 :                :     {
                               3098                 :                :         /* without TIOCGWINSZ, pager == 1 acts the same as pager > 1 */
                               3099                 :                : #ifdef TIOCGWINSZ
 3682 andrew@dunslane.net      3100                 :GBC           4 :         unsigned short int pager = topt->pager;
                               3101                 :              4 :         int         min_lines = topt->pager_min_lines;
                               3102                 :                : 
   20 tgl@sss.pgh.pa.us        3103         [ +  - ]:GNC           4 :         if (pager == 1)
                               3104                 :                :         {
                               3105                 :                :             int         result;
                               3106                 :                :             struct winsize screen_size;
                               3107                 :                : 
                               3108                 :              4 :             result = ioctl(fileno(stdout), TIOCGWINSZ, &screen_size);
                               3109         [ -  + ]:              4 :             if (result < 0)
   20 tgl@sss.pgh.pa.us        3110                 :UNC           0 :                 pager = 2;      /* force use of pager */
                               3111                 :                :             else
                               3112                 :                :             {
   20 tgl@sss.pgh.pa.us        3113                 :GNC           4 :                 int         threshold = Max(screen_size.ws_row, min_lines);
                               3114                 :                : 
                               3115         [ +  - ]:              4 :                 if (cont)       /* caller wants us to calculate lines */
                               3116                 :              4 :                     lines = count_table_lines(cont, width_wrap, vertical,
                               3117                 :                :                                               threshold);
                               3118                 :                :                 /* >= accounts for a one-line prompt */
                               3119         [ +  + ]:              4 :                 if (lines >= threshold)
                               3120                 :              3 :                     pager = 2;
                               3121                 :                :             }
                               3122                 :                :         }
                               3123                 :                : 
                               3124         [ +  + ]:              4 :         if (pager > 1)
                               3125                 :                : #endif
                               3126                 :                :         {
                               3127                 :                :             const char *pagerprog;
                               3128                 :                :             FILE       *pagerpipe;
                               3129                 :                : 
 2974 tgl@sss.pgh.pa.us        3130                 :GBC           3 :             pagerprog = getenv("PSQL_PAGER");
                               3131         [ -  + ]:              3 :             if (!pagerprog)
 2974 tgl@sss.pgh.pa.us        3132                 :UBC           0 :                 pagerprog = getenv("PAGER");
 8259 peter_e@gmx.net          3133         [ -  + ]:GBC           3 :             if (!pagerprog)
 8259 peter_e@gmx.net          3134                 :UBC           0 :                 pagerprog = DEFAULT_PAGER;
                               3135                 :                :             else
                               3136                 :                :             {
                               3137                 :                :                 /* if PAGER is empty or all-white-space, don't use pager */
 3246 tgl@sss.pgh.pa.us        3138         [ -  + ]:GBC           3 :                 if (strspn(pagerprog, " \t\r\n") == strlen(pagerprog))
 3246 tgl@sss.pgh.pa.us        3139                 :UBC           0 :                     return stdout;
                               3140                 :                :             }
 1155 tgl@sss.pgh.pa.us        3141                 :GBC           3 :             fflush(NULL);
 3616                          3142                 :              3 :             disable_sigpipe_trap();
 6999                          3143                 :              3 :             pagerpipe = popen(pagerprog, "w");
                               3144         [ +  - ]:              3 :             if (pagerpipe)
                               3145                 :              3 :                 return pagerpipe;
                               3146                 :                :             /* if popen fails, silently proceed without pager */
 3246 tgl@sss.pgh.pa.us        3147                 :UBC           0 :             restore_sigpipe_trap();
                               3148                 :                :         }
                               3149                 :                :     }
                               3150                 :                : 
 8259 peter_e@gmx.net          3151                 :CBC       69719 :     return stdout;
                               3152                 :                : }
                               3153                 :                : 
                               3154                 :                : /*
                               3155                 :                :  * ClosePager
                               3156                 :                :  *
                               3157                 :                :  * Close previously opened pager pipe, if any
                               3158                 :                :  */
                               3159                 :                : void
 6999 tgl@sss.pgh.pa.us        3160                 :            440 : ClosePager(FILE *pagerpipe)
                               3161                 :                : {
                               3162   [ +  -  +  + ]:            440 :     if (pagerpipe && pagerpipe != stdout)
                               3163                 :                :     {
                               3164                 :                :         /*
                               3165                 :                :          * If printing was canceled midstream, warn about it.
                               3166                 :                :          *
                               3167                 :                :          * Some pagers like less use Ctrl-C as part of their command set. Even
                               3168                 :                :          * so, we abort our processing and warn the user what we did.  If the
                               3169                 :                :          * pager quit as a result of the SIGINT, this message won't go
                               3170                 :                :          * anywhere ...
                               3171                 :                :          */
 6999 tgl@sss.pgh.pa.us        3172         [ -  + ]:GBC           3 :         if (cancel_pressed)
 6999 tgl@sss.pgh.pa.us        3173                 :UBC           0 :             fprintf(pagerpipe, _("Interrupted\n"));
                               3174                 :                : 
 6999 tgl@sss.pgh.pa.us        3175                 :GBC           3 :         pclose(pagerpipe);
 3616                          3176                 :              3 :         restore_sigpipe_trap();
                               3177                 :                :     }
 6999 tgl@sss.pgh.pa.us        3178                 :CBC         440 : }
                               3179                 :                : 
                               3180                 :                : /*
                               3181                 :                :  * Initialise a table contents struct.
                               3182                 :                :  *      Must be called before any other printTable method is used.
                               3183                 :                :  *
                               3184                 :                :  * The title is not duplicated; the caller must ensure that the buffer
                               3185                 :                :  * is available for the lifetime of the printTableContent struct.
                               3186                 :                :  *
                               3187                 :                :  * If you call this, you must call printTableCleanup once you're done with the
                               3188                 :                :  * table.
                               3189                 :                :  */
                               3190                 :                : void
 6377 alvherre@alvh.no-ip.     3191                 :          69705 : printTableInit(printTableContent *const content, const printTableOpt *opt,
                               3192                 :                :                const char *title, const int ncolumns, const int nrows)
                               3193                 :                : {
                               3194                 :                :     uint64      total_cells;
                               3195                 :                : 
                               3196                 :          69705 :     content->opt = opt;
                               3197                 :          69705 :     content->title = title;
                               3198                 :          69705 :     content->ncolumns = ncolumns;
                               3199                 :          69705 :     content->nrows = nrows;
                               3200                 :                : 
 4773 tgl@sss.pgh.pa.us        3201                 :          69705 :     content->headers = pg_malloc0((ncolumns + 1) * sizeof(*content->headers));
                               3202                 :                : 
  706 alvherre@alvh.no-ip.     3203                 :          69705 :     total_cells = (uint64) ncolumns * nrows;
                               3204                 :                :     /* Catch possible overflow.  Using >= here allows adding 1 below */
                               3205         [ -  + ]:          69705 :     if (total_cells >= SIZE_MAX / sizeof(*content->cells))
                               3206                 :                :     {
  185 peter@eisentraut.org     3207                 :UBC           0 :         fprintf(stderr, _("Cannot print table contents: number of cells %" PRIu64 " is equal to or exceeds maximum %zu.\n"),
                               3208                 :                :                 total_cells,
                               3209                 :                :                 SIZE_MAX / sizeof(*content->cells));
  706 alvherre@alvh.no-ip.     3210                 :              0 :         exit(EXIT_FAILURE);
                               3211                 :                :     }
  706 alvherre@alvh.no-ip.     3212                 :CBC       69705 :     content->cells = pg_malloc0((total_cells + 1) * sizeof(*content->cells));
                               3213                 :                : 
 5719 heikki.linnakangas@i     3214                 :          69705 :     content->cellmustfree = NULL;
 6377 alvherre@alvh.no-ip.     3215                 :          69705 :     content->footers = NULL;
                               3216                 :                : 
 4773 tgl@sss.pgh.pa.us        3217                 :          69705 :     content->aligns = pg_malloc0((ncolumns + 1) * sizeof(*content->align));
                               3218                 :                : 
 6377 alvherre@alvh.no-ip.     3219                 :          69705 :     content->header = content->headers;
                               3220                 :          69705 :     content->cell = content->cells;
                               3221                 :          69705 :     content->footer = content->footers;
                               3222                 :          69705 :     content->align = content->aligns;
 5719 heikki.linnakangas@i     3223                 :          69705 :     content->cellsadded = 0;
 6377 alvherre@alvh.no-ip.     3224                 :          69705 : }
                               3225                 :                : 
                               3226                 :                : /*
                               3227                 :                :  * Add a header to the table.
                               3228                 :                :  *
                               3229                 :                :  * Headers are not duplicated; you must ensure that the header string is
                               3230                 :                :  * available for the lifetime of the printTableContent struct.
                               3231                 :                :  *
                               3232                 :                :  * If translate is true, the function will pass the header through gettext.
                               3233                 :                :  * Otherwise, the header will not be translated.
                               3234                 :                :  *
                               3235                 :                :  * align is either 'l' or 'r', and specifies the alignment for cells in this
                               3236                 :                :  * column.
                               3237                 :                :  */
                               3238                 :                : void
 4973 peter_e@gmx.net          3239                 :         132653 : printTableAddHeader(printTableContent *const content, char *header,
                               3240                 :                :                     const bool translate, const char align)
                               3241                 :                : {
                               3242                 :                : #ifndef ENABLE_NLS
                               3243                 :                :     (void) translate;           /* unused parameter */
                               3244                 :                : #endif
                               3245                 :                : 
 6377 alvherre@alvh.no-ip.     3246         [ -  + ]:         132653 :     if (content->header >= content->headers + content->ncolumns)
                               3247                 :                :     {
 6377 alvherre@alvh.no-ip.     3248                 :UBC           0 :         fprintf(stderr, _("Cannot add header to table content: "
                               3249                 :                :                           "column count of %d exceeded.\n"),
                               3250                 :                :                 content->ncolumns);
                               3251                 :              0 :         exit(EXIT_FAILURE);
                               3252                 :                :     }
                               3253                 :                : 
 6377 alvherre@alvh.no-ip.     3254                 :CBC      265306 :     *content->header = (char *) mbvalidate((unsigned char *) header,
                               3255                 :         132653 :                                            content->opt->encoding);
                               3256                 :                : #ifdef ENABLE_NLS
                               3257         [ +  + ]:         132653 :     if (translate)
                               3258                 :          19250 :         *content->header = _(*content->header);
                               3259                 :                : #endif
                               3260                 :         132653 :     content->header++;
                               3261                 :                : 
                               3262                 :         132653 :     *content->align = align;
                               3263                 :         132653 :     content->align++;
                               3264                 :         132653 : }
                               3265                 :                : 
                               3266                 :                : /*
                               3267                 :                :  * Add a cell to the table.
                               3268                 :                :  *
                               3269                 :                :  * Cells are not duplicated; you must ensure that the cell string is available
                               3270                 :                :  * for the lifetime of the printTableContent struct.
                               3271                 :                :  *
                               3272                 :                :  * If translate is true, the function will pass the cell through gettext.
                               3273                 :                :  * Otherwise, the cell will not be translated.
                               3274                 :                :  *
                               3275                 :                :  * If mustfree is true, the cell string is freed by printTableCleanup().
                               3276                 :                :  * Note: Automatic freeing of translatable strings is not supported.
                               3277                 :                :  */
                               3278                 :                : void
 4973 peter_e@gmx.net          3279                 :        2459270 : printTableAddCell(printTableContent *const content, char *cell,
                               3280                 :                :                   const bool translate, const bool mustfree)
                               3281                 :                : {
                               3282                 :                :     uint64      total_cells;
                               3283                 :                : 
                               3284                 :                : #ifndef ENABLE_NLS
                               3285                 :                :     (void) translate;           /* unused parameter */
                               3286                 :                : #endif
                               3287                 :                : 
  706 alvherre@alvh.no-ip.     3288                 :        2459270 :     total_cells = (uint64) content->ncolumns * content->nrows;
                               3289         [ -  + ]:        2459270 :     if (content->cellsadded >= total_cells)
                               3290                 :                :     {
  185 peter@eisentraut.org     3291                 :UBC           0 :         fprintf(stderr, _("Cannot add cell to table content: total cell count of %" PRIu64 " exceeded.\n"),
                               3292                 :                :                 total_cells);
 6377 alvherre@alvh.no-ip.     3293                 :              0 :         exit(EXIT_FAILURE);
                               3294                 :                :     }
                               3295                 :                : 
 6377 alvherre@alvh.no-ip.     3296                 :CBC     4918540 :     *content->cell = (char *) mbvalidate((unsigned char *) cell,
                               3297                 :        2459270 :                                          content->opt->encoding);
                               3298                 :                : 
                               3299                 :                : #ifdef ENABLE_NLS
                               3300         [ +  + ]:        2459270 :     if (translate)
 5719 heikki.linnakangas@i     3301                 :            907 :         *content->cell = _(*content->cell);
                               3302                 :                : #endif
                               3303                 :                : 
                               3304         [ +  + ]:        2459270 :     if (mustfree)
                               3305                 :                :     {
                               3306         [ +  + ]:            260 :         if (content->cellmustfree == NULL)
 4773 tgl@sss.pgh.pa.us        3307                 :            194 :             content->cellmustfree =
  706 alvherre@alvh.no-ip.     3308                 :            194 :                 pg_malloc0((total_cells + 1) * sizeof(bool));
                               3309                 :                : 
 5719 heikki.linnakangas@i     3310                 :            260 :         content->cellmustfree[content->cellsadded] = true;
                               3311                 :                :     }
 6377 alvherre@alvh.no-ip.     3312                 :        2459270 :     content->cell++;
 5719 heikki.linnakangas@i     3313                 :        2459270 :     content->cellsadded++;
 6377 alvherre@alvh.no-ip.     3314                 :        2459270 : }
                               3315                 :                : 
                               3316                 :                : /*
                               3317                 :                :  * Add a footer to the table.
                               3318                 :                :  *
                               3319                 :                :  * Footers are added as elements of a singly-linked list, and the content is
                               3320                 :                :  * strdup'd, so there is no need to keep the original footer string around.
                               3321                 :                :  *
                               3322                 :                :  * Footers are never translated by the function.  If you want the footer
                               3323                 :                :  * translated you must do so yourself, before calling printTableAddFooter.  The
                               3324                 :                :  * reason this works differently to headers and cells is that footers tend to
                               3325                 :                :  * be made of up individually translated components, rather than being
                               3326                 :                :  * translated as a whole.
                               3327                 :                :  */
                               3328                 :                : void
                               3329                 :           6043 : printTableAddFooter(printTableContent *const content, const char *footer)
                               3330                 :                : {
                               3331                 :                :     printTableFooter *f;
                               3332                 :                : 
 4773 tgl@sss.pgh.pa.us        3333                 :           6043 :     f = pg_malloc0(sizeof(*f));
 6377 alvherre@alvh.no-ip.     3334                 :           6043 :     f->data = pg_strdup(footer);
                               3335                 :                : 
                               3336         [ +  + ]:           6043 :     if (content->footers == NULL)
                               3337                 :           1924 :         content->footers = f;
                               3338                 :                :     else
                               3339                 :           4119 :         content->footer->next = f;
                               3340                 :                : 
                               3341                 :           6043 :     content->footer = f;
                               3342                 :           6043 : }
                               3343                 :                : 
                               3344                 :                : /*
                               3345                 :                :  * Change the content of the last-added footer.
                               3346                 :                :  *
                               3347                 :                :  * The current contents of the last-added footer are freed, and replaced by the
                               3348                 :                :  * content given in *footer.  If there was no previous footer, add a new one.
                               3349                 :                :  *
                               3350                 :                :  * The content is strdup'd, so there is no need to keep the original string
                               3351                 :                :  * around.
                               3352                 :                :  */
                               3353                 :                : void
                               3354                 :             15 : printTableSetFooter(printTableContent *const content, const char *footer)
                               3355                 :                : {
                               3356         [ +  - ]:             15 :     if (content->footers != NULL)
                               3357                 :                :     {
                               3358                 :             15 :         free(content->footer->data);
                               3359                 :             15 :         content->footer->data = pg_strdup(footer);
                               3360                 :                :     }
                               3361                 :                :     else
 6377 alvherre@alvh.no-ip.     3362                 :UBC           0 :         printTableAddFooter(content, footer);
 6377 alvherre@alvh.no-ip.     3363                 :CBC          15 : }
                               3364                 :                : 
                               3365                 :                : /*
                               3366                 :                :  * Free all memory allocated to this struct.
                               3367                 :                :  *
                               3368                 :                :  * Once this has been called, the struct is unusable unless you pass it to
                               3369                 :                :  * printTableInit() again.
                               3370                 :                :  */
                               3371                 :                : void
 6368 magnus@hagander.net      3372                 :          69705 : printTableCleanup(printTableContent *const content)
                               3373                 :                : {
 5719 heikki.linnakangas@i     3374         [ +  + ]:          69705 :     if (content->cellmustfree)
                               3375                 :                :     {
                               3376                 :                :         uint64      total_cells;
                               3377                 :                : 
  706 alvherre@alvh.no-ip.     3378                 :            194 :         total_cells = (uint64) content->ncolumns * content->nrows;
                               3379         [ +  + ]:           3230 :         for (uint64 i = 0; i < total_cells; i++)
                               3380                 :                :         {
 5719 heikki.linnakangas@i     3381         [ +  + ]:           3036 :             if (content->cellmustfree[i])
 2463 peter@eisentraut.org     3382                 :            260 :                 free(unconstify(char *, content->cells[i]));
                               3383                 :                :         }
 5719 heikki.linnakangas@i     3384                 :            194 :         free(content->cellmustfree);
                               3385                 :            194 :         content->cellmustfree = NULL;
                               3386                 :                :     }
 6377 alvherre@alvh.no-ip.     3387                 :          69705 :     free(content->headers);
                               3388                 :          69705 :     free(content->cells);
                               3389                 :          69705 :     free(content->aligns);
                               3390                 :                : 
                               3391                 :          69705 :     content->opt = NULL;
                               3392                 :          69705 :     content->title = NULL;
                               3393                 :          69705 :     content->headers = NULL;
                               3394                 :          69705 :     content->cells = NULL;
                               3395                 :          69705 :     content->aligns = NULL;
                               3396                 :          69705 :     content->header = NULL;
                               3397                 :          69705 :     content->cell = NULL;
                               3398                 :          69705 :     content->align = NULL;
                               3399                 :                : 
                               3400         [ +  + ]:          69705 :     if (content->footers)
                               3401                 :                :     {
                               3402         [ +  + ]:           7967 :         for (content->footer = content->footers; content->footer;)
                               3403                 :                :         {
                               3404                 :                :             printTableFooter *f;
                               3405                 :                : 
                               3406                 :           6043 :             f = content->footer;
                               3407                 :           6043 :             content->footer = f->next;
                               3408                 :           6043 :             free(f->data);
                               3409                 :           6043 :             free(f);
                               3410                 :                :         }
                               3411                 :                :     }
                               3412                 :          69705 :     content->footers = NULL;
                               3413                 :          69705 :     content->footer = NULL;
                               3414                 :          69705 : }
                               3415                 :                : 
                               3416                 :                : /*
                               3417                 :                :  * IsPagerNeeded
                               3418                 :                :  *
                               3419                 :                :  * Setup pager if required
                               3420                 :                :  *
                               3421                 :                :  * cont: table data to be printed
                               3422                 :                :  * width_wrap[]: per-column maximum width, or NULL if caller will not wrap
                               3423                 :                :  * vertical: vertical mode?
                               3424                 :                :  * fout: where to print to (in/out argument)
                               3425                 :                :  * is_pager: output argument
                               3426                 :                :  *
                               3427                 :                :  * If we decide pager is needed, *fout is modified and *is_pager is set true
                               3428                 :                :  */
                               3429                 :                : static void
   20 tgl@sss.pgh.pa.us        3430                 :GNC       69313 : IsPagerNeeded(const printTableContent *cont, const unsigned int *width_wrap,
                               3431                 :                :               bool vertical,
                               3432                 :                :               FILE **fout, bool *is_pager)
                               3433                 :                : {
 6373 bruce@momjian.us         3434         [ +  + ]:CBC       69313 :     if (*fout == stdout)
                               3435                 :                :     {
   20 tgl@sss.pgh.pa.us        3436                 :GNC       69285 :         *fout = PageOutputInternal(0, cont->opt, cont, width_wrap, vertical);
                               3437                 :          69285 :         *is_pager = (*fout != stdout);
                               3438                 :                :     }
                               3439                 :                :     else
                               3440                 :             28 :         *is_pager = false;
                               3441                 :          69313 : }
                               3442                 :                : 
                               3443                 :                : /*
                               3444                 :                :  * Count the number of lines needed to print the given table.
                               3445                 :                :  *
                               3446                 :                :  * cont: table data to be printed
                               3447                 :                :  * width_wrap[]: per-column maximum width, or NULL if caller will not wrap
                               3448                 :                :  * vertical: vertical mode?
                               3449                 :                :  * threshold: we can stop counting once we pass this many lines
                               3450                 :                :  *
                               3451                 :                :  * The result is currently only fully accurate for ALIGNED/WRAPPED and
                               3452                 :                :  * UNALIGNED formats; otherwise it's an approximation.
                               3453                 :                :  *
                               3454                 :                :  * Note: while cont->opt will tell us most formatting details, we need the
                               3455                 :                :  * separate "vertical" flag because of the possibility of a dynamic switch
                               3456                 :                :  * from aligned_text to aligned_vertical format.
                               3457                 :                :  *
                               3458                 :                :  * The point of the threshold parameter is that when the table is very long,
                               3459                 :                :  * we'll typically be able to stop scanning after not many rows.
                               3460                 :                :  */
                               3461                 :                : #ifdef NEED_COUNT_TABLE_LINES
                               3462                 :                : static int
                               3463                 :              4 : count_table_lines(const printTableContent *cont,
                               3464                 :                :                   const unsigned int *width_wrap,
                               3465                 :                :                   bool vertical,
                               3466                 :                :                   int threshold)
                               3467                 :                : {
                               3468                 :                :     int        *header_height;
                               3469                 :              4 :     int         lines = 0,
                               3470                 :              4 :                 max_lines = 0,
                               3471                 :                :                 nl_lines,
                               3472                 :                :                 i;
                               3473                 :              4 :     int         encoding = cont->opt->encoding;
                               3474                 :                :     const char *const *cell;
                               3475                 :                : 
                               3476                 :                :     /*
                               3477                 :                :      * Scan all column headers and determine their heights.  Cache the values
                               3478                 :                :      * since vertical mode repeats the headers for every record.
                               3479                 :                :      */
                               3480                 :              4 :     header_height = (int *) pg_malloc(cont->ncolumns * sizeof(int));
                               3481         [ +  + ]:             14 :     for (i = 0; i < cont->ncolumns; i++)
                               3482                 :                :     {
                               3483                 :             10 :         pg_wcssize((const unsigned char *) cont->headers[i],
                               3484                 :             10 :                    strlen(cont->headers[i]), encoding,
                               3485                 :             10 :                    NULL, &header_height[i], NULL);
                               3486                 :                :     }
                               3487                 :                : 
                               3488                 :                :     /*
                               3489                 :                :      * Account for separator lines (if used), as well as the trailing blank
                               3490                 :                :      * line that most formats emit.
                               3491                 :                :      */
                               3492   [ -  +  -  -  :              4 :     switch (cont->opt->format)
                                              -  - ]
                               3493                 :                :     {
   20 tgl@sss.pgh.pa.us        3494                 :UNC           0 :         case PRINT_ALIGNED:
                               3495                 :                :         case PRINT_WRAPPED:
                               3496                 :                : 
                               3497                 :                :             /*
                               3498                 :                :              * Vertical mode writes one separator line per record.  Normal
                               3499                 :                :              * mode writes a single separator line between header and rows.
                               3500                 :                :              */
                               3501         [ #  # ]:              0 :             lines = vertical ? cont->nrows : 1;
                               3502                 :                :             /* Both modes add a blank line at the end */
                               3503                 :              0 :             lines++;
                               3504                 :              0 :             break;
   20 tgl@sss.pgh.pa.us        3505                 :GNC           4 :         case PRINT_UNALIGNED:
                               3506                 :                : 
                               3507                 :                :             /*
                               3508                 :                :              * Vertical mode writes a separator (here assumed to be a newline)
                               3509                 :                :              * between records.  Normal mode writes nothing extra.
                               3510                 :                :              */
                               3511         [ +  + ]:              4 :             if (vertical)
                               3512                 :              1 :                 lines = Max(cont->nrows - 1, 0);
                               3513                 :              4 :             break;
   20 tgl@sss.pgh.pa.us        3514                 :UNC           0 :         case PRINT_CSV:
                               3515                 :                :             /* Nothing extra is added */
                               3516                 :              0 :             break;
                               3517                 :              0 :         case PRINT_HTML:
                               3518                 :                :         case PRINT_ASCIIDOC:
                               3519                 :                :         case PRINT_LATEX:
                               3520                 :                :         case PRINT_LATEX_LONGTABLE:
                               3521                 :                :         case PRINT_TROFF_MS:
                               3522                 :                : 
                               3523                 :                :             /*
                               3524                 :                :              * These formats aren't really meant for interactive consumption,
                               3525                 :                :              * so for now we won't work hard on them.  Treat them like aligned
                               3526                 :                :              * mode.
                               3527                 :                :              */
                               3528         [ #  # ]:              0 :             lines = vertical ? cont->nrows : 1;
                               3529                 :              0 :             lines++;
                               3530                 :              0 :             break;
                               3531                 :              0 :         case PRINT_NOTHING:
                               3532                 :                :             /* Shouldn't get here... */
                               3533                 :              0 :             break;
                               3534                 :                :     }
                               3535                 :                : 
                               3536                 :                :     /* Scan all cells to count their lines */
   20 tgl@sss.pgh.pa.us        3537         [ +  + ]:GNC         119 :     for (i = 0, cell = cont->cells; *cell; cell++)
                               3538                 :                :     {
                               3539                 :                :         int         width;
                               3540                 :                : 
                               3541                 :                :         /* Count the original line breaks */
                               3542                 :            116 :         pg_wcssize((const unsigned char *) *cell, strlen(*cell), encoding,
                               3543                 :                :                    &width, &nl_lines, NULL);
                               3544                 :                : 
                               3545                 :                :         /* Count extra lines due to wrapping */
                               3546   [ +  +  -  +  :            116 :         if (width > 0 && width_wrap && width_wrap[i])
                                              -  - ]
   20 tgl@sss.pgh.pa.us        3547                 :UNC           0 :             nl_lines += (width - 1) / width_wrap[i];
                               3548                 :                : 
   20 tgl@sss.pgh.pa.us        3549         [ +  + ]:GNC         116 :         if (vertical)
                               3550                 :                :         {
                               3551                 :                :             /* Pick the height of the header or cell, whichever is taller */
                               3552         [ -  + ]:              6 :             if (nl_lines > header_height[i])
   20 tgl@sss.pgh.pa.us        3553                 :UNC           0 :                 lines += nl_lines;
                               3554                 :                :             else
   20 tgl@sss.pgh.pa.us        3555                 :GNC           6 :                 lines += header_height[i];
                               3556                 :                :         }
                               3557                 :                :         else
                               3558                 :                :         {
                               3559                 :                :             /* Remember max height in the current row */
                               3560         [ +  + ]:            110 :             if (nl_lines > max_lines)
                               3561                 :             56 :                 max_lines = nl_lines;
                               3562                 :                :         }
                               3563                 :                : 
                               3564                 :                :         /* i is the current column number: increment with wrap */
                               3565         [ +  + ]:            116 :         if (++i >= cont->ncolumns)
                               3566                 :                :         {
                               3567                 :             62 :             i = 0;
                               3568         [ +  + ]:             62 :             if (!vertical)
                               3569                 :                :             {
                               3570                 :                :                 /* At last column of each row, add tallest column height */
                               3571                 :             56 :                 lines += max_lines;
                               3572                 :             56 :                 max_lines = 0;
                               3573                 :                :             }
                               3574                 :                :             /* Stop scanning table body once we pass threshold */
                               3575         [ +  + ]:             62 :             if (lines > threshold)
                               3576                 :              1 :                 break;
                               3577                 :                :         }
                               3578                 :                :     }
                               3579                 :                : 
                               3580                 :                :     /* Account for header and footer decoration */
                               3581   [ +  +  +  - ]:              4 :     if (!cont->opt->tuples_only && lines <= threshold)
                               3582                 :                :     {
                               3583                 :                :         printTableFooter *f;
                               3584                 :                : 
                               3585         [ +  - ]:              1 :         if (cont->title)
                               3586                 :                :         {
                               3587                 :                :             /* Add height of title */
                               3588                 :              1 :             pg_wcssize((const unsigned char *) cont->title, strlen(cont->title),
                               3589                 :                :                        encoding, NULL, &nl_lines, NULL);
                               3590                 :              1 :             lines += nl_lines;
                               3591                 :                :         }
                               3592                 :                : 
                               3593         [ +  - ]:              1 :         if (!vertical)
                               3594                 :                :         {
                               3595                 :                :             /* Add height of tallest header column */
                               3596                 :              1 :             max_lines = 0;
                               3597         [ +  + ]:              8 :             for (i = 0; i < cont->ncolumns; i++)
                               3598                 :                :             {
                               3599         [ +  + ]:              7 :                 if (header_height[i] > max_lines)
                               3600                 :              1 :                     max_lines = header_height[i];
                               3601                 :                :             }
                               3602                 :              1 :             lines += max_lines;
                               3603                 :                :         }
                               3604                 :                : 
                               3605                 :                :         /*
                               3606                 :                :          * Add all footer lines.  Vertical mode does not use the default
                               3607                 :                :          * footer, but we must include that in normal mode.
                               3608                 :                :          */
                               3609         [ -  + ]:              1 :         for (f = (vertical ? cont->footers : footers_with_default(cont));
                               3610         [ +  - ]:              2 :              f != NULL; f = f->next)
                               3611                 :                :         {
                               3612                 :              2 :             pg_wcssize((const unsigned char *) f->data, strlen(f->data),
                               3613                 :                :                        encoding, NULL, &nl_lines, NULL);
                               3614                 :              2 :             lines += nl_lines;
                               3615                 :                :             /* Stop scanning footers once we pass threshold */
                               3616         [ +  + ]:              2 :             if (lines > threshold)
                               3617                 :              1 :                 break;
                               3618                 :                :         }
                               3619                 :                :     }
                               3620                 :                : 
                               3621                 :              4 :     free(header_height);
                               3622                 :                : 
                               3623                 :              4 :     return lines;
 6373 bruce@momjian.us         3624                 :ECB     (68030) : }
                               3625                 :                : #endif                          /* NEED_COUNT_TABLE_LINES */
                               3626                 :                : 
                               3627                 :                : /*
                               3628                 :                :  * Use this to print any table in the supported formats.
                               3629                 :                :  *
                               3630                 :                :  * cont: table data and formatting options
                               3631                 :                :  * fout: where to print to
                               3632                 :                :  * is_pager: true if caller has already redirected fout to be a pager pipe
                               3633                 :                :  * flog: if not null, also print the table there (for --log-file option)
                               3634                 :                :  */
                               3635                 :                : void
 3617 tgl@sss.pgh.pa.us        3636                 :CBC       69702 : printTable(const printTableContent *cont,
                               3637                 :                :            FILE *fout, bool is_pager, FILE *flog)
                               3638                 :                : {
                               3639                 :          69702 :     bool        is_local_pager = false;
                               3640                 :                : 
 6373 bruce@momjian.us         3641         [ -  + ]:          69702 :     if (cancel_pressed)
 6373 bruce@momjian.us         3642                 :UBC           0 :         return;
                               3643                 :                : 
 6373 bruce@momjian.us         3644         [ -  + ]:CBC       69702 :     if (cont->opt->format == PRINT_NOTHING)
 6373 bruce@momjian.us         3645                 :UBC           0 :         return;
                               3646                 :                : 
                               3647                 :                :     /* print_aligned_*() handle the pager themselves */
 3617 tgl@sss.pgh.pa.us        3648         [ +  + ]:CBC       69702 :     if (!is_pager &&
                               3649         [ +  + ]:          69627 :         cont->opt->format != PRINT_ALIGNED &&
 5098 peter_e@gmx.net          3650         [ +  + ]:           5740 :         cont->opt->format != PRINT_WRAPPED)
                               3651                 :                :     {
   20 tgl@sss.pgh.pa.us        3652                 :GNC        5614 :         IsPagerNeeded(cont, NULL, (cont->opt->expanded == 1), &fout, &is_pager);
 3617 tgl@sss.pgh.pa.us        3653                 :CBC        5614 :         is_local_pager = is_pager;
                               3654                 :                :     }
                               3655                 :                : 
                               3656                 :                :     /* clear any pre-existing error indication on the output stream */
 1673 alvherre@alvh.no-ip.     3657                 :          69702 :     clearerr(fout);
                               3658                 :                : 
                               3659                 :                :     /* print the stuff */
 6377                          3660   [ +  +  +  +  :          69702 :     switch (cont->opt->format)
                                        +  +  +  +  
                                                 - ]
                               3661                 :                :     {
 9489 bruce@momjian.us         3662                 :           5413 :         case PRINT_UNALIGNED:
 5098 peter_e@gmx.net          3663         [ +  + ]:           5413 :             if (cont->opt->expanded == 1)
 6373 bruce@momjian.us         3664                 :             52 :                 print_unaligned_vertical(cont, fout);
                               3665                 :                :             else
                               3666                 :           5361 :                 print_unaligned_text(cont, fout);
 9489                          3667                 :           5413 :             break;
                               3668                 :          64088 :         case PRINT_ALIGNED:
                               3669                 :                :         case PRINT_WRAPPED:
                               3670                 :                : 
                               3671                 :                :             /*
                               3672                 :                :              * In expanded-auto mode, force vertical if a pager is passed in;
                               3673                 :                :              * else we may make different decisions for different hunks of the
                               3674                 :                :              * query result.
                               3675                 :                :              */
 3617 tgl@sss.pgh.pa.us        3676         [ +  + ]:          64088 :             if (cont->opt->expanded == 1 ||
                               3677   [ -  +  -  - ]:          63829 :                 (cont->opt->expanded == 2 && is_pager))
                               3678                 :            259 :                 print_aligned_vertical(cont, fout, is_pager);
                               3679                 :                :             else
                               3680                 :          63829 :                 print_aligned_text(cont, fout, is_pager);
 9489 bruce@momjian.us         3681                 :          64088 :             break;
 2527 tgl@sss.pgh.pa.us        3682                 :             33 :         case PRINT_CSV:
                               3683         [ +  + ]:             33 :             if (cont->opt->expanded == 1)
                               3684                 :              9 :                 print_csv_vertical(cont, fout);
                               3685                 :                :             else
                               3686                 :             24 :                 print_csv_text(cont, fout);
                               3687                 :             33 :             break;
 9489 bruce@momjian.us         3688                 :             30 :         case PRINT_HTML:
 5098 peter_e@gmx.net          3689         [ +  + ]:             30 :             if (cont->opt->expanded == 1)
 6373 bruce@momjian.us         3690                 :             15 :                 print_html_vertical(cont, fout);
                               3691                 :                :             else
                               3692                 :             15 :                 print_html_text(cont, fout);
 9489                          3693                 :             30 :             break;
 3863                          3694                 :             30 :         case PRINT_ASCIIDOC:
                               3695         [ +  + ]:             30 :             if (cont->opt->expanded == 1)
                               3696                 :             15 :                 print_asciidoc_vertical(cont, fout);
                               3697                 :                :             else
                               3698                 :             15 :                 print_asciidoc_text(cont, fout);
                               3699                 :             30 :             break;
 9489                          3700                 :             36 :         case PRINT_LATEX:
 5098 peter_e@gmx.net          3701         [ +  + ]:             36 :             if (cont->opt->expanded == 1)
 6373 bruce@momjian.us         3702                 :             18 :                 print_latex_vertical(cont, fout);
                               3703                 :                :             else
                               3704                 :             18 :                 print_latex_text(cont, fout);
 9489                          3705                 :             36 :             break;
 4666                          3706                 :             42 :         case PRINT_LATEX_LONGTABLE:
                               3707         [ +  + ]:             42 :             if (cont->opt->expanded == 1)
                               3708                 :             21 :                 print_latex_vertical(cont, fout);
                               3709                 :                :             else
 4665                          3710                 :             21 :                 print_latex_longtable_text(cont, fout);
 4666                          3711                 :             42 :             break;
 7445                          3712                 :             30 :         case PRINT_TROFF_MS:
 5098 peter_e@gmx.net          3713         [ +  + ]:             30 :             if (cont->opt->expanded == 1)
 6373 bruce@momjian.us         3714                 :             15 :                 print_troff_ms_vertical(cont, fout);
                               3715                 :                :             else
                               3716                 :             15 :                 print_troff_ms_text(cont, fout);
 7445                          3717                 :             30 :             break;
 9489 bruce@momjian.us         3718                 :UBC           0 :         default:
 6043 peter_e@gmx.net          3719                 :              0 :             fprintf(stderr, _("invalid output format (internal error): %d"),
 6377 alvherre@alvh.no-ip.     3720                 :              0 :                     cont->opt->format);
 7441 neilc@samurai.com        3721                 :              0 :             exit(EXIT_FAILURE);
                               3722                 :                :     }
                               3723                 :                : 
 3617 tgl@sss.pgh.pa.us        3724         [ +  + ]:CBC       69702 :     if (is_local_pager)
 6373 bruce@momjian.us         3725                 :GBC           3 :         ClosePager(fout);
                               3726                 :                : 
                               3727                 :                :     /* also produce log output if wanted */
   20 tgl@sss.pgh.pa.us        3728         [ -  + ]:GNC       69702 :     if (flog)
   20 tgl@sss.pgh.pa.us        3729                 :UNC           0 :         print_aligned_text(cont, flog, false);
                               3730                 :                : }
                               3731                 :                : 
                               3732                 :                : /*
                               3733                 :                :  * Use this to print query results
                               3734                 :                :  *
                               3735                 :                :  * result: result of a successful query
                               3736                 :                :  * opt: formatting options
                               3737                 :                :  * fout: where to print to
                               3738                 :                :  * is_pager: true if caller has already redirected fout to be a pager pipe
                               3739                 :                :  * flog: if not null, also print the data there (for --log-file option)
                               3740                 :                :  */
                               3741                 :                : void
 3617 tgl@sss.pgh.pa.us        3742                 :CBC       67549 : printQuery(const PGresult *result, const printQueryOpt *opt,
                               3743                 :                :            FILE *fout, bool is_pager, FILE *flog)
                               3744                 :                : {
                               3745                 :                :     printTableContent cont;
                               3746                 :                :     int         i,
                               3747                 :                :                 r,
                               3748                 :                :                 c;
                               3749                 :                : 
 7075                          3750         [ -  + ]:          67549 :     if (cancel_pressed)
 7075 tgl@sss.pgh.pa.us        3751                 :UBC           0 :         return;
                               3752                 :                : 
 6377 alvherre@alvh.no-ip.     3753                 :CBC       67549 :     printTableInit(&cont, &opt->topt, opt->title,
                               3754                 :                :                    PQnfields(result), PQntuples(result));
                               3755                 :                : 
                               3756                 :                :     /* Assert caller supplied enough translate_columns[] entries */
 4314 tgl@sss.pgh.pa.us        3757   [ +  +  -  + ]:          67549 :     Assert(opt->translate_columns == NULL ||
                               3758                 :                :            opt->n_translate_columns >= cont.ncolumns);
                               3759                 :                : 
 6377 alvherre@alvh.no-ip.     3760         [ +  + ]:         186399 :     for (i = 0; i < cont.ncolumns; i++)
                               3761                 :                :     {
                               3762                 :         118850 :         printTableAddHeader(&cont, PQfname(result, i),
 3489                          3763                 :         118850 :                             opt->translate_header,
                               3764                 :         118850 :                             column_type_alignment(PQftype(result, i)));
                               3765                 :                :     }
                               3766                 :                : 
                               3767                 :                :     /* set cells */
 6377                          3768         [ +  + ]:        1280353 :     for (r = 0; r < cont.nrows; r++)
                               3769                 :                :     {
                               3770         [ +  + ]:        3641192 :         for (c = 0; c < cont.ncolumns; c++)
                               3771                 :                :         {
                               3772                 :                :             char       *cell;
 5719 heikki.linnakangas@i     3773                 :        2428388 :             bool        mustfree = false;
                               3774                 :                :             bool        translate;
                               3775                 :                : 
 6377 alvherre@alvh.no-ip.     3776         [ +  + ]:        2428388 :             if (PQgetisnull(result, r, c))
                               3777         [ +  + ]:          32608 :                 cell = opt->nullPrint ? opt->nullPrint : "";
                               3778                 :                :             else
                               3779                 :                :             {
                               3780                 :        2395780 :                 cell = PQgetvalue(result, r, c);
 5719 heikki.linnakangas@i     3781   [ +  +  +  + ]:        2395780 :                 if (cont.aligns[c] == 'r' && opt->topt.numericLocale)
                               3782                 :                :                 {
                               3783                 :             48 :                     cell = format_numeric_locale(cell);
                               3784                 :             48 :                     mustfree = true;
                               3785                 :                :                 }
                               3786                 :                :             }
                               3787                 :                : 
 6314 bruce@momjian.us         3788   [ +  +  +  + ]:        2428388 :             translate = (opt->translate_columns && opt->translate_columns[c]);
 5719 heikki.linnakangas@i     3789                 :        2428388 :             printTableAddCell(&cont, cell, translate, mustfree);
                               3790                 :                :         }
                               3791                 :                :     }
                               3792                 :                : 
                               3793                 :                :     /* set footers */
 6377 alvherre@alvh.no-ip.     3794         [ +  + ]:          67549 :     if (opt->footers)
                               3795                 :                :     {
                               3796                 :                :         char      **footer;
                               3797                 :                : 
                               3798         [ +  + ]:            195 :         for (footer = opt->footers; *footer; footer++)
                               3799                 :             93 :             printTableAddFooter(&cont, *footer);
                               3800                 :                :     }
                               3801                 :                : 
 3617 tgl@sss.pgh.pa.us        3802                 :          67549 :     printTable(&cont, fout, is_pager, flog);
 6377 alvherre@alvh.no-ip.     3803                 :          67549 :     printTableCleanup(&cont);
                               3804                 :                : }
                               3805                 :                : 
                               3806                 :                : char
 3489                          3807                 :         118934 : column_type_alignment(Oid ftype)
                               3808                 :                : {
                               3809                 :                :     char        align;
                               3810                 :                : 
                               3811         [ +  + ]:         118934 :     switch (ftype)
                               3812                 :                :     {
                               3813                 :          45860 :         case INT2OID:
                               3814                 :                :         case INT4OID:
                               3815                 :                :         case INT8OID:
                               3816                 :                :         case FLOAT4OID:
                               3817                 :                :         case FLOAT8OID:
                               3818                 :                :         case NUMERICOID:
                               3819                 :                :         case OIDOID:
                               3820                 :                :         case XIDOID:
                               3821                 :                :         case XID8OID:
                               3822                 :                :         case CIDOID:
                               3823                 :                :         case MONEYOID:
                               3824                 :          45860 :             align = 'r';
                               3825                 :          45860 :             break;
                               3826                 :          73074 :         default:
                               3827                 :          73074 :             align = 'l';
                               3828                 :          73074 :             break;
                               3829                 :                :     }
                               3830                 :         118934 :     return align;
                               3831                 :                : }
                               3832                 :                : 
                               3833                 :                : void
 7410 bruce@momjian.us         3834                 :           8604 : setDecimalLocale(void)
                               3835                 :                : {
                               3836                 :                :     struct lconv *extlconv;
                               3837                 :                : 
                               3838                 :           8604 :     extlconv = localeconv();
                               3839                 :                : 
                               3840                 :                :     /* Don't accept an empty decimal_point string */
                               3841         [ +  - ]:           8604 :     if (*extlconv->decimal_point)
 6377 alvherre@alvh.no-ip.     3842                 :           8604 :         decimal_point = pg_strdup(extlconv->decimal_point);
                               3843                 :                :     else
 7410 bruce@momjian.us         3844                 :UBC           0 :         decimal_point = ".";  /* SQL output standard */
                               3845                 :                : 
                               3846                 :                :     /*
                               3847                 :                :      * Although the Open Group standard allows locales to supply more than one
                               3848                 :                :      * group width, we consider only the first one, and we ignore any attempt
                               3849                 :                :      * to suppress grouping by specifying CHAR_MAX.  As in the backend's
                               3850                 :                :      * cash.c, we must apply a range check to avoid being fooled by variant
                               3851                 :                :      * CHAR_MAX values.
                               3852                 :                :      */
 3685 tgl@sss.pgh.pa.us        3853                 :CBC        8604 :     groupdigits = *extlconv->grouping;
                               3854   [ -  +  -  - ]:           8604 :     if (groupdigits <= 0 || groupdigits > 6)
 3686                          3855                 :           8604 :         groupdigits = 3;        /* most common */
                               3856                 :                : 
                               3857                 :                :     /* Don't accept an empty thousands_sep string, either */
                               3858                 :                :     /* similar code exists in formatting.c */
 7410 bruce@momjian.us         3859         [ -  + ]:           8604 :     if (*extlconv->thousands_sep)
 6377 alvherre@alvh.no-ip.     3860                 :UBC           0 :         thousands_sep = pg_strdup(extlconv->thousands_sep);
                               3861                 :                :     /* Make sure thousands separator doesn't match decimal point symbol. */
 6550 bruce@momjian.us         3862         [ +  - ]:CBC        8604 :     else if (strcmp(decimal_point, ",") != 0)
 7410                          3863                 :           8604 :         thousands_sep = ",";
                               3864                 :                :     else
 7410 bruce@momjian.us         3865                 :UBC           0 :         thousands_sep = ".";
 7410 bruce@momjian.us         3866                 :CBC        8604 : }
                               3867                 :                : 
                               3868                 :                : /* get selected or default line style */
                               3869                 :                : const printTextFormat *
 5858 tgl@sss.pgh.pa.us        3870                 :          64911 : get_line_style(const printTableOpt *opt)
                               3871                 :                : {
                               3872                 :                :     /*
                               3873                 :                :      * Note: this function mainly exists to preserve the convention that a
                               3874                 :                :      * printTableOpt struct can be initialized to zeroes to get default
                               3875                 :                :      * behavior.
                               3876                 :                :      */
                               3877         [ +  + ]:          64911 :     if (opt->line_style != NULL)
                               3878                 :           1473 :         return opt->line_style;
                               3879                 :                :     else
                               3880                 :          63438 :         return &pg_asciiformat;
                               3881                 :                : }
                               3882                 :                : 
                               3883                 :                : void
 4063 sfrost@snowman.net       3884                 :           8604 : refresh_utf8format(const printTableOpt *opt)
                               3885                 :                : {
 3516 tgl@sss.pgh.pa.us        3886                 :           8604 :     printTextFormat *popt = &pg_utf8format;
                               3887                 :                : 
                               3888                 :                :     const unicodeStyleBorderFormat *border;
                               3889                 :                :     const unicodeStyleRowFormat *header;
                               3890                 :                :     const unicodeStyleColumnFormat *column;
                               3891                 :                : 
 4063 sfrost@snowman.net       3892                 :           8604 :     popt->name = "unicode";
                               3893                 :                : 
                               3894                 :           8604 :     border = &unicode_style.border_style[opt->unicode_border_linestyle];
                               3895                 :           8604 :     header = &unicode_style.row_style[opt->unicode_header_linestyle];
                               3896                 :           8604 :     column = &unicode_style.column_style[opt->unicode_column_linestyle];
                               3897                 :                : 
                               3898                 :           8604 :     popt->lrule[PRINT_RULE_TOP].hrule = border->horizontal;
                               3899                 :           8604 :     popt->lrule[PRINT_RULE_TOP].leftvrule = border->down_and_right;
                               3900                 :           8604 :     popt->lrule[PRINT_RULE_TOP].midvrule = column->down_and_horizontal[opt->unicode_border_linestyle];
                               3901                 :           8604 :     popt->lrule[PRINT_RULE_TOP].rightvrule = border->down_and_left;
                               3902                 :                : 
                               3903                 :           8604 :     popt->lrule[PRINT_RULE_MIDDLE].hrule = header->horizontal;
                               3904                 :           8604 :     popt->lrule[PRINT_RULE_MIDDLE].leftvrule = header->vertical_and_right[opt->unicode_border_linestyle];
                               3905                 :           8604 :     popt->lrule[PRINT_RULE_MIDDLE].midvrule = column->vertical_and_horizontal[opt->unicode_header_linestyle];
                               3906                 :           8604 :     popt->lrule[PRINT_RULE_MIDDLE].rightvrule = header->vertical_and_left[opt->unicode_border_linestyle];
                               3907                 :                : 
                               3908                 :           8604 :     popt->lrule[PRINT_RULE_BOTTOM].hrule = border->horizontal;
                               3909                 :           8604 :     popt->lrule[PRINT_RULE_BOTTOM].leftvrule = border->up_and_right;
                               3910                 :           8604 :     popt->lrule[PRINT_RULE_BOTTOM].midvrule = column->up_and_horizontal[opt->unicode_border_linestyle];
                               3911                 :           8604 :     popt->lrule[PRINT_RULE_BOTTOM].rightvrule = border->left_and_right;
                               3912                 :                : 
                               3913                 :                :     /* N/A */
                               3914                 :           8604 :     popt->lrule[PRINT_RULE_DATA].hrule = "";
                               3915                 :           8604 :     popt->lrule[PRINT_RULE_DATA].leftvrule = border->vertical;
                               3916                 :           8604 :     popt->lrule[PRINT_RULE_DATA].midvrule = column->vertical;
                               3917                 :           8604 :     popt->lrule[PRINT_RULE_DATA].rightvrule = border->vertical;
                               3918                 :                : 
                               3919                 :           8604 :     popt->midvrule_nl = column->vertical;
                               3920                 :           8604 :     popt->midvrule_wrap = column->vertical;
                               3921                 :           8604 :     popt->midvrule_blank = column->vertical;
                               3922                 :                : 
                               3923                 :                :     /* Same for all unicode today */
                               3924                 :           8604 :     popt->header_nl_left = unicode_style.header_nl_left;
                               3925                 :           8604 :     popt->header_nl_right = unicode_style.header_nl_right;
                               3926                 :           8604 :     popt->nl_left = unicode_style.nl_left;
                               3927                 :           8604 :     popt->nl_right = unicode_style.nl_right;
                               3928                 :           8604 :     popt->wrap_left = unicode_style.wrap_left;
                               3929                 :           8604 :     popt->wrap_right = unicode_style.wrap_right;
                               3930                 :           8604 :     popt->wrap_right_border = unicode_style.wrap_right_border;
                               3931                 :           8604 : }
                               3932                 :                : 
                               3933                 :                : /*
                               3934                 :                :  * Compute the byte distance to the end of the string or *target_width
                               3935                 :                :  * display character positions, whichever comes first.  Update *target_width
                               3936                 :                :  * to be the number of display character positions actually filled.
                               3937                 :                :  */
                               3938                 :                : static int
 6381 bruce@momjian.us         3939                 :         567574 : strlen_max_width(unsigned char *str, int *target_width, int encoding)
                               3940                 :                : {
                               3941                 :         567574 :     unsigned char *start = str;
 6379 tgl@sss.pgh.pa.us        3942                 :         567574 :     unsigned char *end = str + strlen((char *) str);
 5982 bruce@momjian.us         3943                 :         567574 :     int         curr_width = 0;
                               3944                 :                : 
 6379 tgl@sss.pgh.pa.us        3945         [ +  + ]:        7097183 :     while (str < end)
                               3946                 :                :     {
 5982 bruce@momjian.us         3947                 :        6530374 :         int         char_width = PQdsplen((char *) str, encoding);
                               3948                 :                : 
                               3949                 :                :         /*
                               3950                 :                :          * If the display width of the new character causes the string to
                               3951                 :                :          * exceed its target width, skip it and return.  However, if this is
                               3952                 :                :          * the first character of the string (curr_width == 0), we have to
                               3953                 :                :          * accept it.
                               3954                 :                :          */
 6379 tgl@sss.pgh.pa.us        3955   [ +  +  +  - ]:        6530374 :         if (*target_width < curr_width + char_width && curr_width != 0)
 6381 bruce@momjian.us         3956                 :            765 :             break;
                               3957                 :                : 
                               3958                 :        6529609 :         curr_width += char_width;
                               3959                 :                : 
 6379 tgl@sss.pgh.pa.us        3960                 :        6529609 :         str += PQmblen((char *) str, encoding);
                               3961                 :                : 
 1603                          3962         [ -  + ]:        6529609 :         if (str > end)           /* Don't overrun invalid string */
 1603 tgl@sss.pgh.pa.us        3963                 :UBC           0 :             str = end;
                               3964                 :                :     }
                               3965                 :                : 
 6381 bruce@momjian.us         3966                 :CBC      567574 :     *target_width = curr_width;
                               3967                 :                : 
                               3968                 :         567574 :     return str - start;
                               3969                 :                : }
        

Generated by: LCOV version 2.4-beta