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