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