LCOV - differential code coverage report
Current view: top level - src/fe_utils - print.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 92.3 % 1580 1459 11 31 47 32 38 565 21 835 51 583 10
Current Date: 2023-04-08 17:13:01 Functions: 97.9 % 47 46 1 36 1 9 1 36 1
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (180,240] days: 0.0 % 1 0 1
Legend: Lines: hit not hit (240..) days: 92.4 % 1579 1459 10 31 47 32 38 565 21 835 50 564
Function coverage date bins:
(240..) days: 55.4 % 83 46 1 36 1 9 1 35

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

Generated by: LCOV version v1.16-55-g56c0a2a