1 /*-------------------------------------------------------------------------
3 * Query-result printing support for frontend code
5 * This file used to be part of psql, but now it's separated out to allow
6 * other frontend programs to use it. Because the printing code needs
7 * access to the cancel_pressed flag as well as SIGPIPE trapping and
8 * pager open/close functions, all that stuff came with it.
11 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
12 * Portions Copyright (c) 1994, Regents of the University of California
14 * src/fe_utils/print.c
16 *-------------------------------------------------------------------------
18 #include "postgres_fe.h"
26 #include <sys/ioctl.h> /* for ioctl() */
33 #include "catalog/pg_type_d.h"
34 #include "fe_utils/mbprint.h"
35 #include "fe_utils/print.h"
38 * If the calling program doesn't have any mechanism for setting
39 * cancel_pressed, it will have no effect.
41 * Note: print.c's general strategy for when to check cancel_pressed is to do
42 * so at completion of each row of output.
44 volatile bool cancel_pressed = false;
46 static bool always_ignore_sigpipe = false;
48 /* info for locale-aware numeric formatting; set up by setDecimalLocale() */
49 static char *decimal_point;
50 static int groupdigits;
51 static char *thousands_sep;
53 static char default_footer[100];
54 static printTableFooter default_footer_cell = {default_footer, NULL};
56 /* Line style control structures */
57 const printTextFormat pg_asciiformat =
78 const printTextFormat pg_asciiformat_old =
99 /* Default unicode linestyle format */
100 printTextFormat pg_utf8format;
102 typedef struct unicodeStyleRowFormat
104 const char *horizontal;
105 const char *vertical_and_right[2];
106 const char *vertical_and_left[2];
107 } unicodeStyleRowFormat;
109 typedef struct unicodeStyleColumnFormat
111 const char *vertical;
112 const char *vertical_and_horizontal[2];
113 const char *up_and_horizontal[2];
114 const char *down_and_horizontal[2];
115 } unicodeStyleColumnFormat;
117 typedef struct unicodeStyleBorderFormat
119 const char *up_and_right;
120 const char *vertical;
121 const char *down_and_right;
122 const char *horizontal;
123 const char *down_and_left;
124 const char *left_and_right;
125 } unicodeStyleBorderFormat;
127 typedef struct unicodeStyleFormat
129 unicodeStyleRowFormat row_style[2];
130 unicodeStyleColumnFormat column_style[2];
131 unicodeStyleBorderFormat border_style[2];
132 const char *header_nl_left;
133 const char *header_nl_right;
135 const char *nl_right;
136 const char *wrap_left;
137 const char *wrap_right;
138 bool wrap_right_border;
139 } unicodeStyleFormat;
141 static const unicodeStyleFormat unicode_style = {
147 {"\342\224\234", "\342\225\237"},
149 {"\342\224\244", "\342\225\242"},
155 {"\342\225\236", "\342\225\240"},
157 {"\342\225\241", "\342\225\243"},
165 {"\342\224\274", "\342\225\252"},
167 {"\342\224\264", "\342\225\247"},
169 {"\342\224\254", "\342\225\244"},
175 {"\342\225\253", "\342\225\254"},
177 {"\342\225\250", "\342\225\251"},
179 {"\342\225\245", "\342\225\246"},
184 {"\342\224\224", "\342\224\202", "\342\224\214", "\342\224\200", "\342\224\220", "\342\224\230"},
186 {"\342\225\232", "\342\225\221", "\342\225\224", "\342\225\220", "\342\225\227", "\342\225\235"},
189 "\342\206\265", /* ↵ */
191 "\342\206\265", /* ↵ */
192 "\342\200\246", /* … */
193 "\342\200\246", /* … */
198 /* Local functions */
199 static int strlen_max_width(unsigned char *str, int *target_width, int encoding);
200 static void IsPagerNeeded(const printTableContent *cont, int extra_lines, bool expanded,
201 FILE **fout, bool *is_pager);
203 static void print_aligned_vertical(const printTableContent *cont,
204 FILE *fout, bool is_pager);
207 /* Count number of digits in integral part of number */
209 integer_digits(const char *my_str)
211 /* ignoring any sign ... */
212 if (my_str[0] == '-' || my_str[0] == '+')
214 /* ... count initial integral digits */
215 return strspn(my_str, "0123456789");
218 /* Compute additional length required for locale-aware numeric output */
220 additional_numeric_locale_len(const char *my_str)
222 int int_len = integer_digits(my_str),
225 /* Account for added thousands_sep instances */
226 if (int_len > groupdigits)
227 len += ((int_len - 1) / groupdigits) * strlen(thousands_sep);
229 /* Account for possible additional length of decimal_point */
230 if (strchr(my_str, '.') != NULL)
231 len += strlen(decimal_point) - 1;
237 * Format a numeric value per current LC_NUMERIC locale setting
239 * Returns the appropriately formatted string in a new allocated block,
242 * setDecimalLocale() must have been called earlier.
245 format_numeric_locale(const char *my_str)
255 * If the string doesn't look like a number, return it unchanged. This
256 * check is essential to avoid mangling already-localized "money" values.
258 if (strspn(my_str, "0123456789+-.eE") != strlen(my_str))
259 return pg_strdup(my_str);
261 new_len = strlen(my_str) + additional_numeric_locale_len(my_str);
262 new_str = pg_malloc(new_len + 1);
264 int_len = integer_digits(my_str);
266 /* number of digits in first thousands group */
267 leading_digits = int_len % groupdigits;
268 if (leading_digits == 0)
269 leading_digits = groupdigits;
272 if (my_str[0] == '-' || my_str[0] == '+')
274 new_str[new_str_pos++] = my_str[0];
278 /* process integer part of number */
279 for (i = 0; i < int_len; i++)
281 /* Time to insert separator? */
282 if (i > 0 && --leading_digits == 0)
284 strcpy(&new_str[new_str_pos], thousands_sep);
285 new_str_pos += strlen(thousands_sep);
286 leading_digits = groupdigits;
288 new_str[new_str_pos++] = my_str[i];
291 /* handle decimal point if any */
292 if (my_str[i] == '.')
294 strcpy(&new_str[new_str_pos], decimal_point);
295 new_str_pos += strlen(decimal_point);
299 /* copy the rest (fractional digits and/or exponent, and \0 terminator) */
300 strcpy(&new_str[new_str_pos], &my_str[i]);
302 /* assert we didn't underestimate new_len (an overestimate is OK) */
303 Assert(strlen(new_str) <= new_len);
310 * fputnbytes: print exactly N bytes to a file
312 * We avoid using %.*s here because it can misbehave if the data
313 * is not valid in what libc thinks is the prevailing encoding.
316 fputnbytes(FILE *f, const char *str, size_t n)
324 print_separator(struct separator sep, FILE *fout)
326 if (sep.separator_zero)
328 else if (sep.separator)
329 fputs(sep.separator, fout);
334 * Return the list of explicitly-requested footers or, when applicable, the
335 * default "(xx rows)" footer. Always omit the default footer when given
336 * non-default footers, "\pset footer off", or a specific instruction to that
337 * effect from a calling backslash command. Vertical formats number each row,
338 * making the default footer redundant; they do not call this function.
340 * The return value may point to static storage; do not keep it across calls.
342 static printTableFooter *
343 footers_with_default(const printTableContent *cont)
345 if (cont->footers == NULL && cont->opt->default_footer)
347 unsigned long total_records;
349 total_records = cont->opt->prior_records + cont->nrows;
350 snprintf(default_footer, sizeof(default_footer),
351 ngettext("(%lu row)", "(%lu rows)", total_records),
354 return &default_footer_cell;
357 return cont->footers;
361 /*************************/
363 /*************************/
367 print_unaligned_text(const printTableContent *cont, FILE *fout)
369 bool opt_tuples_only = cont->opt->tuples_only;
371 const char *const *ptr;
372 bool need_recordsep = false;
377 if (cont->opt->start_table)
380 if (!opt_tuples_only && cont->title)
382 fputs(cont->title, fout);
383 print_separator(cont->opt->recordSep, fout);
387 if (!opt_tuples_only)
389 for (ptr = cont->headers; *ptr; ptr++)
391 if (ptr != cont->headers)
392 print_separator(cont->opt->fieldSep, fout);
395 need_recordsep = true;
399 /* assume continuing printout */
400 need_recordsep = true;
403 for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
407 print_separator(cont->opt->recordSep, fout);
408 need_recordsep = false;
414 if ((i + 1) % cont->ncolumns)
415 print_separator(cont->opt->fieldSep, fout);
417 need_recordsep = true;
421 if (cont->opt->stop_table)
423 printTableFooter *footers = footers_with_default(cont);
425 if (!opt_tuples_only && footers != NULL && !cancel_pressed)
429 for (f = footers; f; f = f->next)
433 print_separator(cont->opt->recordSep, fout);
434 need_recordsep = false;
436 fputs(f->data, fout);
437 need_recordsep = true;
442 * The last record is terminated by a newline, independent of the set
443 * record separator. But when the record separator is a zero byte, we
444 * use that (compatible with find -print0 and xargs).
448 if (cont->opt->recordSep.separator_zero)
449 print_separator(cont->opt->recordSep, fout);
458 print_unaligned_vertical(const printTableContent *cont, FILE *fout)
460 bool opt_tuples_only = cont->opt->tuples_only;
462 const char *const *ptr;
463 bool need_recordsep = false;
468 if (cont->opt->start_table)
471 if (!opt_tuples_only && cont->title)
473 fputs(cont->title, fout);
474 need_recordsep = true;
478 /* assume continuing printout */
479 need_recordsep = true;
482 for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
486 /* record separator is 2 occurrences of recordsep in this mode */
487 print_separator(cont->opt->recordSep, fout);
488 print_separator(cont->opt->recordSep, fout);
489 need_recordsep = false;
494 fputs(cont->headers[i % cont->ncolumns], fout);
495 print_separator(cont->opt->fieldSep, fout);
498 if ((i + 1) % cont->ncolumns)
499 print_separator(cont->opt->recordSep, fout);
501 need_recordsep = true;
504 if (cont->opt->stop_table)
507 if (!opt_tuples_only && cont->footers != NULL && !cancel_pressed)
511 print_separator(cont->opt->recordSep, fout);
512 for (f = cont->footers; f; f = f->next)
514 print_separator(cont->opt->recordSep, fout);
515 fputs(f->data, fout);
519 /* see above in print_unaligned_text() */
522 if (cont->opt->recordSep.separator_zero)
523 print_separator(cont->opt->recordSep, fout);
531 /********************/
533 /********************/
538 _print_horizontal_line(const unsigned int ncolumns, const unsigned int *widths,
539 unsigned short border, printTextRule pos,
540 const printTextFormat *format,
543 const printTextLineFormat *lformat = &format->lrule[pos];
548 fputs(lformat->hrule, fout);
549 else if (border == 2)
550 fprintf(fout, "%s%s", lformat->leftvrule, lformat->hrule);
552 for (i = 0; i < ncolumns; i++)
554 for (j = 0; j < widths[i]; j++)
555 fputs(lformat->hrule, fout);
557 if (i < ncolumns - 1)
562 fprintf(fout, "%s%s%s", lformat->hrule,
563 lformat->midvrule, lformat->hrule);
568 fprintf(fout, "%s%s", lformat->hrule, lformat->rightvrule);
569 else if (border == 1)
570 fputs(lformat->hrule, fout);
577 * Print pretty boxes around cells.
580 print_aligned_text(const printTableContent *cont, FILE *fout, bool is_pager)
582 bool opt_tuples_only = cont->opt->tuples_only;
583 int encoding = cont->opt->encoding;
584 unsigned short opt_border = cont->opt->border;
585 const printTextFormat *format = get_line_style(cont->opt);
586 const printTextLineFormat *dformat = &format->lrule[PRINT_RULE_DATA];
588 unsigned int col_count = 0,
594 unsigned int *width_header,
598 unsigned int *max_nl_lines, /* value split by newlines */
601 unsigned char **format_buf;
602 unsigned int width_total;
603 unsigned int total_header_width;
604 unsigned int extra_row_output_lines = 0;
605 unsigned int extra_output_lines = 0;
607 const char *const *ptr;
609 struct lineptr **col_lineptrs; /* pointers to line pointer per column */
611 bool *header_done; /* Have all header lines been output? */
612 int *bytes_output; /* Bytes output for column value */
613 printTextLineWrap *wrap; /* Wrap status for each column */
614 int output_columns = 0; /* Width of interactive console */
615 bool is_local_pager = false;
623 if (cont->ncolumns > 0)
625 col_count = cont->ncolumns;
626 width_header = pg_malloc0(col_count * sizeof(*width_header));
627 width_average = pg_malloc0(col_count * sizeof(*width_average));
628 max_width = pg_malloc0(col_count * sizeof(*max_width));
629 width_wrap = pg_malloc0(col_count * sizeof(*width_wrap));
630 max_nl_lines = pg_malloc0(col_count * sizeof(*max_nl_lines));
631 curr_nl_line = pg_malloc0(col_count * sizeof(*curr_nl_line));
632 col_lineptrs = pg_malloc0(col_count * sizeof(*col_lineptrs));
633 max_bytes = pg_malloc0(col_count * sizeof(*max_bytes));
634 format_buf = pg_malloc0(col_count * sizeof(*format_buf));
635 header_done = pg_malloc0(col_count * sizeof(*header_done));
636 bytes_output = pg_malloc0(col_count * sizeof(*bytes_output));
637 wrap = pg_malloc0(col_count * sizeof(*wrap));
642 width_average = NULL;
655 /* scan all column headers, find maximum width and max max_nl_lines */
656 for (i = 0; i < col_count; i++)
662 pg_wcssize((const unsigned char *) cont->headers[i], strlen(cont->headers[i]),
663 encoding, &width, &nl_lines, &bytes_required);
664 if (width > max_width[i])
665 max_width[i] = width;
666 if (nl_lines > max_nl_lines[i])
667 max_nl_lines[i] = nl_lines;
668 if (bytes_required > max_bytes[i])
669 max_bytes[i] = bytes_required;
670 if (nl_lines > extra_row_output_lines)
671 extra_row_output_lines = nl_lines;
673 width_header[i] = width;
675 /* Add height of tallest header column */
676 extra_output_lines += extra_row_output_lines;
677 extra_row_output_lines = 0;
679 /* scan all cells, find maximum width, compute cell_count */
680 for (i = 0, ptr = cont->cells; *ptr; ptr++, i++, cell_count++)
686 pg_wcssize((const unsigned char *) *ptr, strlen(*ptr), encoding,
687 &width, &nl_lines, &bytes_required);
689 if (width > max_width[i % col_count])
690 max_width[i % col_count] = width;
691 if (nl_lines > max_nl_lines[i % col_count])
692 max_nl_lines[i % col_count] = nl_lines;
693 if (bytes_required > max_bytes[i % col_count])
694 max_bytes[i % col_count] = bytes_required;
696 width_average[i % col_count] += width;
699 /* If we have rows, compute average */
700 if (col_count != 0 && cell_count != 0)
702 int rows = cell_count / col_count;
704 for (i = 0; i < col_count; i++)
705 width_average[i] /= rows;
708 /* adjust the total display width based on border style */
710 width_total = col_count;
711 else if (opt_border == 1)
712 width_total = col_count * 3 - ((col_count > 0) ? 1 : 0);
714 width_total = col_count * 3 + 1;
715 total_header_width = width_total;
717 for (i = 0; i < col_count; i++)
719 width_total += max_width[i];
720 total_header_width += width_header[i];
724 * At this point: max_width[] contains the max width of each column,
725 * max_nl_lines[] contains the max number of lines in each column,
726 * max_bytes[] contains the maximum storage space for formatting strings,
727 * width_total contains the giant width sum. Now we allocate some memory
730 for (i = 0; i < col_count; i++)
732 /* Add entry for ptr == NULL array termination */
733 col_lineptrs[i] = pg_malloc0((max_nl_lines[i] + 1) *
734 sizeof(**col_lineptrs));
736 format_buf[i] = pg_malloc(max_bytes[i] + 1);
738 col_lineptrs[i]->ptr = format_buf[i];
741 /* Default word wrap to the full width, i.e. no word wrap */
742 for (i = 0; i < col_count; i++)
743 width_wrap[i] = max_width[i];
746 * Choose target output width: \pset columns, or $COLUMNS, or ioctl
748 if (cont->opt->columns > 0)
749 output_columns = cont->opt->columns;
750 else if ((fout == stdout && isatty(fileno(stdout))) || is_pager)
752 if (cont->opt->env_columns > 0)
753 output_columns = cont->opt->env_columns;
757 struct winsize screen_size;
759 if (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) != -1)
760 output_columns = screen_size.ws_col;
765 if (cont->opt->format == PRINT_WRAPPED)
768 * Optional optimized word wrap. Shrink columns with a high max/avg
769 * ratio. Slightly bias against wider columns. (Increases chance a
770 * narrow column will fit in its cell.) If available columns is
771 * positive... and greater than the width of the unshrinkable column
774 if (output_columns > 0 && output_columns >= total_header_width)
776 /* While there is still excess width... */
777 while (width_total > output_columns)
779 double max_ratio = 0;
783 * Find column that has the highest ratio of its maximum width
784 * compared to its average width. This tells us which column
785 * will produce the fewest wrapped values if shortened.
786 * width_wrap starts as equal to max_width.
788 for (i = 0; i < col_count; i++)
790 if (width_average[i] && width_wrap[i] > width_header[i])
792 /* Penalize wide columns by 1% of their width */
795 ratio = (double) width_wrap[i] / width_average[i] +
797 if (ratio > max_ratio)
805 /* Exit loop if we can't squeeze any more. */
809 /* Decrease width of target column by one. */
810 width_wrap[worst_col]--;
817 * If in expanded auto mode, we have now calculated the expected width, so
818 * we can now escape to vertical mode if necessary. If the output has
819 * only one column, the expanded format would be wider than the regular
820 * format, so don't use it in that case.
822 if (cont->opt->expanded == 2 && output_columns > 0 && cont->ncolumns > 1 &&
823 (output_columns < total_header_width || output_columns < width_total))
825 print_aligned_vertical(cont, fout, is_pager);
829 /* If we wrapped beyond the display width, use the pager */
830 if (!is_pager && fout == stdout && output_columns > 0 &&
831 (output_columns < total_header_width || output_columns < width_total))
833 fout = PageOutput(INT_MAX, cont->opt); /* force pager */
834 is_pager = is_local_pager = true;
837 /* Check if newlines or our wrapping now need the pager */
838 if (!is_pager && fout == stdout)
840 /* scan all cells, find maximum width, compute cell_count */
841 for (i = 0, ptr = cont->cells; *ptr; ptr++, cell_count++)
847 pg_wcssize((const unsigned char *) *ptr, strlen(*ptr), encoding,
848 &width, &nl_lines, &bytes_required);
851 * A row can have both wrapping and newlines that cause it to
852 * display across multiple lines. We check for both cases below.
854 if (width > 0 && width_wrap[i])
856 unsigned int extra_lines;
858 /* don't count the first line of nl_lines - it's not "extra" */
859 extra_lines = ((width - 1) / width_wrap[i]) + nl_lines - 1;
860 if (extra_lines > extra_row_output_lines)
861 extra_row_output_lines = extra_lines;
864 /* i is the current column number: increment with wrap */
865 if (++i >= col_count)
868 /* At last column of each row, add tallest column height */
869 extra_output_lines += extra_row_output_lines;
870 extra_row_output_lines = 0;
873 IsPagerNeeded(cont, extra_output_lines, false, &fout, &is_pager);
874 is_local_pager = is_pager;
878 if (cont->opt->start_table)
881 if (cont->title && !opt_tuples_only)
886 pg_wcssize((const unsigned char *) cont->title, strlen(cont->title),
887 encoding, &width, &height, NULL);
888 if (width >= width_total)
890 fprintf(fout, "%s\n", cont->title);
893 fprintf(fout, "%-*s%s\n", (width_total - width) / 2, "",
898 if (!opt_tuples_only)
900 int more_col_wrapping;
904 _print_horizontal_line(col_count, width_wrap, opt_border,
905 PRINT_RULE_TOP, format, fout);
907 for (i = 0; i < col_count; i++)
908 pg_wcsformat((const unsigned char *) cont->headers[i],
909 strlen(cont->headers[i]), encoding,
910 col_lineptrs[i], max_nl_lines[i]);
912 more_col_wrapping = col_count;
914 memset(header_done, false, col_count * sizeof(bool));
915 while (more_col_wrapping)
918 fputs(dformat->leftvrule, fout);
920 for (i = 0; i < cont->ncolumns; i++)
922 struct lineptr *this_line = col_lineptrs[i] + curr_nl_line;
923 unsigned int nbspace;
925 if (opt_border != 0 ||
926 (!format->wrap_right_border && i > 0))
927 fputs(curr_nl_line ? format->header_nl_left : " ",
932 nbspace = width_wrap[i] - this_line->width;
935 fprintf(fout, "%-*s%s%-*s",
936 nbspace / 2, "", this_line->ptr, (nbspace + 1) / 2, "");
938 if (!(this_line + 1)->ptr)
945 fprintf(fout, "%*s", width_wrap[i], "");
947 if (opt_border != 0 || format->wrap_right_border)
948 fputs(!header_done[i] ? format->header_nl_right : " ",
951 if (opt_border != 0 && col_count > 0 && i < col_count - 1)
952 fputs(dformat->midvrule, fout);
957 fputs(dformat->rightvrule, fout);
961 _print_horizontal_line(col_count, width_wrap, opt_border,
962 PRINT_RULE_MIDDLE, format, fout);
966 /* print cells, one loop per row */
967 for (i = 0, ptr = cont->cells; *ptr; i += col_count, ptr += col_count)
977 for (j = 0; j < col_count; j++)
979 pg_wcsformat((const unsigned char *) ptr[j], strlen(ptr[j]), encoding,
980 col_lineptrs[j], max_nl_lines[j]);
984 memset(bytes_output, 0, col_count * sizeof(int));
987 * Each time through this loop, one display line is output. It can
988 * either be a full value or a partial value if embedded newlines
989 * exist or if 'format=wrapping' mode is enabled.
997 fputs(dformat->leftvrule, fout);
999 /* for each column */
1000 for (j = 0; j < col_count; j++)
1002 /* We have a valid array element, so index it */
1003 struct lineptr *this_line = &col_lineptrs[j][curr_nl_line[j]];
1004 int bytes_to_output;
1005 int chars_to_output = width_wrap[j];
1006 bool finalspaces = (opt_border == 2 ||
1007 (col_count > 0 && j < col_count - 1));
1009 /* Print left-hand wrap or newline mark */
1010 if (opt_border != 0)
1012 if (wrap[j] == PRINT_LINE_WRAP_WRAP)
1013 fputs(format->wrap_left, fout);
1014 else if (wrap[j] == PRINT_LINE_WRAP_NEWLINE)
1015 fputs(format->nl_left, fout);
1020 if (!this_line->ptr)
1022 /* Past newline lines so just pad for other columns */
1024 fprintf(fout, "%*s", chars_to_output, "");
1028 /* Get strlen() of the characters up to width_wrap */
1030 strlen_max_width(this_line->ptr + bytes_output[j],
1031 &chars_to_output, encoding);
1034 * If we exceeded width_wrap, it means the display width
1035 * of a single character was wider than our target width.
1036 * In that case, we have to pretend we are only printing
1037 * the target display width and make the best of it.
1039 if (chars_to_output > width_wrap[j])
1040 chars_to_output = width_wrap[j];
1042 if (cont->aligns[j] == 'r') /* Right aligned cell */
1045 fprintf(fout, "%*s", width_wrap[j] - chars_to_output, "");
1047 (char *) (this_line->ptr + bytes_output[j]),
1050 else /* Left aligned cell */
1054 (char *) (this_line->ptr + bytes_output[j]),
1058 bytes_output[j] += bytes_to_output;
1060 /* Do we have more text to wrap? */
1061 if (*(this_line->ptr + bytes_output[j]) != '\0')
1065 /* Advance to next newline line */
1067 if (col_lineptrs[j][curr_nl_line[j]].ptr != NULL)
1069 bytes_output[j] = 0;
1073 /* Determine next line's wrap status for this column */
1074 wrap[j] = PRINT_LINE_WRAP_NONE;
1075 if (col_lineptrs[j][curr_nl_line[j]].ptr != NULL)
1077 if (bytes_output[j] != 0)
1078 wrap[j] = PRINT_LINE_WRAP_WRAP;
1079 else if (curr_nl_line[j] != 0)
1080 wrap[j] = PRINT_LINE_WRAP_NEWLINE;
1084 * If left-aligned, pad out remaining space if needed (not
1085 * last column, and/or wrap marks required).
1087 if (cont->aligns[j] != 'r') /* Left aligned cell */
1090 wrap[j] == PRINT_LINE_WRAP_WRAP ||
1091 wrap[j] == PRINT_LINE_WRAP_NEWLINE)
1092 fprintf(fout, "%*s",
1093 width_wrap[j] - chars_to_output, "");
1096 /* Print right-hand wrap or newline mark */
1097 if (wrap[j] == PRINT_LINE_WRAP_WRAP)
1098 fputs(format->wrap_right, fout);
1099 else if (wrap[j] == PRINT_LINE_WRAP_NEWLINE)
1100 fputs(format->nl_right, fout);
1101 else if (opt_border == 2 || (col_count > 0 && j < col_count - 1))
1104 /* Print column divider, if not the last column */
1105 if (opt_border != 0 && (col_count > 0 && j < col_count - 1))
1107 if (wrap[j + 1] == PRINT_LINE_WRAP_WRAP)
1108 fputs(format->midvrule_wrap, fout);
1109 else if (wrap[j + 1] == PRINT_LINE_WRAP_NEWLINE)
1110 fputs(format->midvrule_nl, fout);
1111 else if (col_lineptrs[j + 1][curr_nl_line[j + 1]].ptr == NULL)
1112 fputs(format->midvrule_blank, fout);
1114 fputs(dformat->midvrule, fout);
1118 /* end-of-row border */
1119 if (opt_border == 2)
1120 fputs(dformat->rightvrule, fout);
1123 } while (more_lines);
1126 if (cont->opt->stop_table)
1128 printTableFooter *footers = footers_with_default(cont);
1130 if (opt_border == 2 && !cancel_pressed)
1131 _print_horizontal_line(col_count, width_wrap, opt_border,
1132 PRINT_RULE_BOTTOM, format, fout);
1135 if (footers && !opt_tuples_only && !cancel_pressed)
1137 printTableFooter *f;
1139 for (f = footers; f; f = f->next)
1140 fprintf(fout, "%s\n", f->data);
1148 for (i = 0; i < col_count; i++)
1150 free(col_lineptrs[i]);
1151 free(format_buf[i]);
1154 free(width_average);
1172 print_aligned_vertical_line(const printTextFormat *format,
1173 const unsigned short opt_border,
1174 unsigned long record,
1175 unsigned int hwidth,
1176 unsigned int dwidth,
1180 const printTextLineFormat *lformat = &format->lrule[pos];
1184 if (opt_border == 2)
1185 fprintf(fout, "%s%s", lformat->leftvrule, lformat->hrule);
1186 else if (opt_border == 1)
1187 fputs(lformat->hrule, fout);
1191 if (opt_border == 0)
1192 reclen = fprintf(fout, "* Record %lu", record);
1194 reclen = fprintf(fout, "[ RECORD %lu ]", record);
1196 if (opt_border != 2)
1200 for (i = reclen; i < hwidth; i++)
1201 fputs(opt_border > 0 ? lformat->hrule : " ", fout);
1207 fputs(lformat->hrule, fout);
1209 fputs(lformat->midvrule, fout);
1211 fputs(lformat->hrule, fout);
1220 for (i = reclen; i < dwidth; i++)
1221 fputs(opt_border > 0 ? lformat->hrule : " ", fout);
1222 if (opt_border == 2)
1223 fprintf(fout, "%s%s", lformat->hrule, lformat->rightvrule);
1228 print_aligned_vertical(const printTableContent *cont,
1229 FILE *fout, bool is_pager)
1231 bool opt_tuples_only = cont->opt->tuples_only;
1232 unsigned short opt_border = cont->opt->border;
1233 const printTextFormat *format = get_line_style(cont->opt);
1234 const printTextLineFormat *dformat = &format->lrule[PRINT_RULE_DATA];
1235 int encoding = cont->opt->encoding;
1236 unsigned long record = cont->opt->prior_records + 1;
1237 const char *const *ptr;
1245 struct lineptr *hlineptr,
1247 bool is_local_pager = false,
1250 int output_columns = 0; /* Width of interactive console */
1258 if (cont->cells[0] == NULL && cont->opt->start_table &&
1259 cont->opt->stop_table)
1261 printTableFooter *footers = footers_with_default(cont);
1263 if (!opt_tuples_only && !cancel_pressed && footers)
1265 printTableFooter *f;
1267 for (f = footers; f; f = f->next)
1268 fprintf(fout, "%s\n", f->data);
1277 * Deal with the pager here instead of in printTable(), because we could
1278 * get here via print_aligned_text() in expanded auto mode, and so we have
1279 * to recalculate the pager requirement based on vertical output.
1283 IsPagerNeeded(cont, 0, true, &fout, &is_pager);
1284 is_local_pager = is_pager;
1287 /* Find the maximum dimensions for the headers */
1288 for (i = 0; i < cont->ncolumns; i++)
1294 pg_wcssize((const unsigned char *) cont->headers[i], strlen(cont->headers[i]),
1295 encoding, &width, &height, &fs);
1298 if (height > hheight)
1303 if (fs > hformatsize)
1307 /* find longest data cell */
1308 for (i = 0, ptr = cont->cells; *ptr; ptr++, i++)
1314 pg_wcssize((const unsigned char *) *ptr, strlen(*ptr), encoding,
1315 &width, &height, &fs);
1318 if (height > dheight)
1323 if (fs > dformatsize)
1328 * We now have all the information we need to setup the formatting
1331 dlineptr = pg_malloc((sizeof(*dlineptr)) * (dheight + 1));
1332 hlineptr = pg_malloc((sizeof(*hlineptr)) * (hheight + 1));
1334 dlineptr->ptr = pg_malloc(dformatsize);
1335 hlineptr->ptr = pg_malloc(hformatsize);
1337 if (cont->opt->start_table)
1340 if (!opt_tuples_only && cont->title)
1341 fprintf(fout, "%s\n", cont->title);
1345 * Choose target output width: \pset columns, or $COLUMNS, or ioctl
1347 if (cont->opt->columns > 0)
1348 output_columns = cont->opt->columns;
1349 else if ((fout == stdout && isatty(fileno(stdout))) || is_pager)
1351 if (cont->opt->env_columns > 0)
1352 output_columns = cont->opt->env_columns;
1356 struct winsize screen_size;
1358 if (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) != -1)
1359 output_columns = screen_size.ws_col;
1365 * Calculate available width for data in wrapped mode
1367 if (cont->opt->format == PRINT_WRAPPED)
1369 unsigned int swidth,
1373 if (opt_border == 0)
1376 * For border = 0, one space in the middle. (If we discover we
1377 * need to wrap, the spacer column will be replaced by a wrap
1378 * marker, and we'll make room below for another wrap marker at
1379 * the end of the line. But for now, assume no wrap is needed.)
1383 /* We might need a column for header newline markers, too */
1387 else if (opt_border == 1)
1390 * For border = 1, two spaces and a vrule in the middle. (As
1391 * above, we might need one more column for a wrap marker.)
1395 /* We might need a column for left header newline markers, too */
1396 if (hmultiline && (format == &pg_asciiformat_old))
1402 * For border = 2, two more for the vrules at the beginning and
1403 * end of the lines, plus spacer columns adjacent to these. (We
1404 * won't need extra columns for wrap/newline markers, we'll just
1405 * repurpose the spacers.)
1410 /* Reserve a column for data newline indicators, too, if needed */
1412 opt_border < 2 && format != &pg_asciiformat_old)
1415 /* Determine width required for record header lines */
1416 if (!opt_tuples_only)
1418 if (cont->nrows > 0)
1419 rwidth = 1 + (int) log10(cont->nrows);
1420 if (opt_border == 0)
1421 rwidth += 9; /* "* RECORD " */
1422 else if (opt_border == 1)
1423 rwidth += 12; /* "-[ RECORD ]" */
1425 rwidth += 15; /* "+-[ RECORD ]-+" */
1428 /* We might need to do the rest of the calculation twice */
1433 /* Total width required to not wrap data */
1434 width = hwidth + swidth + dwidth;
1435 /* ... and not the header lines, either */
1439 if (output_columns > 0)
1441 unsigned int min_width;
1443 /* Minimum acceptable width: room for just 3 columns of data */
1444 min_width = hwidth + swidth + 3;
1445 /* ... but not less than what the record header lines need */
1446 if (min_width < rwidth)
1449 if (output_columns >= width)
1451 /* Plenty of room, use native data width */
1452 /* (but at least enough for the record header lines) */
1453 newdwidth = width - hwidth - swidth;
1455 else if (output_columns < min_width)
1457 /* Set data width to match min_width */
1458 newdwidth = min_width - hwidth - swidth;
1462 /* Set data width to match output_columns */
1463 newdwidth = output_columns - hwidth - swidth;
1468 /* Don't know the wrap limit, so use native data width */
1469 /* (but at least enough for the record header lines) */
1470 newdwidth = width - hwidth - swidth;
1474 * If we will need to wrap data and didn't already allocate a data
1475 * newline/wrap marker column, do so and recompute.
1477 if (newdwidth < dwidth && !dmultiline &&
1478 opt_border < 2 && format != &pg_asciiformat_old)
1491 for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
1505 pos = PRINT_RULE_TOP;
1507 pos = PRINT_RULE_MIDDLE;
1509 /* Print record header (e.g. "[ RECORD N ]") above each record */
1510 if (i % cont->ncolumns == 0)
1512 unsigned int lhwidth = hwidth;
1514 if ((opt_border < 2) &&
1516 (format == &pg_asciiformat_old))
1517 lhwidth++; /* for newline indicators */
1519 if (!opt_tuples_only)
1520 print_aligned_vertical_line(format, opt_border, record++,
1521 lhwidth, dwidth, pos, fout);
1522 else if (i != 0 || !cont->opt->start_table || opt_border == 2)
1523 print_aligned_vertical_line(format, opt_border, 0, lhwidth,
1527 /* Format the header */
1528 pg_wcsformat((const unsigned char *) cont->headers[i % cont->ncolumns],
1529 strlen(cont->headers[i % cont->ncolumns]),
1530 encoding, hlineptr, hheight);
1531 /* Format the data */
1532 pg_wcsformat((const unsigned char *) *ptr, strlen(*ptr), encoding,
1536 * Loop through header and data in parallel dealing with newlines and
1537 * wrapped lines until they're both exhausted
1540 dcomplete = hcomplete = 0;
1542 chars_to_output = dlineptr[dline].width;
1543 while (!dcomplete || !hcomplete)
1546 if (opt_border == 2)
1547 fprintf(fout, "%s", dformat->leftvrule);
1549 /* Header (never wrapped so just need to deal with newlines) */
1552 int swidth = hwidth,
1553 target_width = hwidth;
1556 * Left spacer or new line indicator
1558 if ((opt_border == 2) ||
1559 (hmultiline && (format == &pg_asciiformat_old)))
1560 fputs(hline ? format->header_nl_left : " ", fout);
1565 strlen_max_width(hlineptr[hline].ptr, &target_width,
1567 fprintf(fout, "%-s", hlineptr[hline].ptr);
1572 swidth -= target_width;
1574 fprintf(fout, "%*s", swidth, " ");
1577 * New line indicator or separator's space
1579 if (hlineptr[hline + 1].ptr)
1581 /* More lines after this one due to a newline */
1582 if ((opt_border > 0) ||
1583 (hmultiline && (format != &pg_asciiformat_old)))
1584 fputs(format->header_nl_right, fout);
1589 /* This was the last line of the header */
1590 if ((opt_border > 0) ||
1591 (hmultiline && (format != &pg_asciiformat_old)))
1598 unsigned int swidth = hwidth + opt_border;
1600 if ((opt_border < 2) &&
1602 (format == &pg_asciiformat_old))
1605 if ((opt_border == 0) &&
1606 (format != &pg_asciiformat_old) &&
1610 fprintf(fout, "%*s", swidth, " ");
1617 fputs(format->midvrule_wrap, fout);
1618 else if (dline == 0)
1619 fputs(dformat->midvrule, fout);
1621 fputs(format->midvrule_nl, fout);
1627 int target_width = dwidth,
1632 * Left spacer or wrap indicator
1634 fputs(offset == 0 ? " " : format->wrap_left, fout);
1639 bytes_to_output = strlen_max_width(dlineptr[dline].ptr + offset,
1640 &target_width, encoding);
1641 fputnbytes(fout, (char *) (dlineptr[dline].ptr + offset),
1644 chars_to_output -= target_width;
1645 offset += bytes_to_output;
1648 swidth -= target_width;
1650 if (chars_to_output)
1652 /* continuing a wrapped column */
1653 if ((opt_border > 1) ||
1654 (dmultiline && (format != &pg_asciiformat_old)))
1657 fprintf(fout, "%*s", swidth, " ");
1658 fputs(format->wrap_right, fout);
1661 else if (dlineptr[dline + 1].ptr)
1663 /* reached a newline in the column */
1664 if ((opt_border > 1) ||
1665 (dmultiline && (format != &pg_asciiformat_old)))
1668 fprintf(fout, "%*s", swidth, " ");
1669 fputs(format->nl_right, fout);
1673 chars_to_output = dlineptr[dline].width;
1677 /* reached the end of the cell */
1681 fprintf(fout, "%*s", swidth, " ");
1688 if (opt_border == 2)
1689 fputs(dformat->rightvrule, fout);
1696 * data exhausted (this can occur if header is longer than the
1697 * data due to newlines in the header)
1702 fprintf(fout, "%*s %s\n", dwidth, "", dformat->rightvrule);
1707 if (cont->opt->stop_table)
1709 if (opt_border == 2 && !cancel_pressed)
1710 print_aligned_vertical_line(format, opt_border, 0, hwidth, dwidth,
1711 PRINT_RULE_BOTTOM, fout);
1714 if (!opt_tuples_only && cont->footers != NULL && !cancel_pressed)
1716 printTableFooter *f;
1720 for (f = cont->footers; f; f = f->next)
1721 fprintf(fout, "%s\n", f->data);
1727 free(hlineptr->ptr);
1728 free(dlineptr->ptr);
1737 /**********************/
1739 /**********************/
1743 csv_escaped_print(const char *str, FILE *fout)
1748 for (p = str; *p; p++)
1751 fputc('"', fout); /* double quotes are doubled */
1758 csv_print_field(const char *str, FILE *fout, char sep)
1761 * Enclose and escape field contents when one of these conditions is met:
1762 * - the field separator is found in the contents.
1763 * - the field contains a CR or LF.
1764 * - the field contains a double quote.
1765 * - the field is exactly "\.".
1766 * - the field separator is either "\" or ".".
1767 * The last two cases prevent producing a line that the server's COPY
1768 * command would interpret as an end-of-data marker. We only really
1769 * need to ensure that the complete line isn't exactly "\.", but for
1770 * simplicity we apply stronger restrictions here.
1773 if (strchr(str, sep) != NULL ||
1774 strcspn(str, "\r\n\"") != strlen(str) ||
1775 strcmp(str, "\\.") == 0 ||
1776 sep == '\\' || sep == '.')
1777 csv_escaped_print(str, fout);
1783 print_csv_text(const printTableContent *cont, FILE *fout)
1785 const char *const *ptr;
1792 * The title and footer are never printed in csv format. The header is
1793 * printed if opt_tuples_only is false.
1795 * Despite RFC 4180 saying that end of lines are CRLF, terminate lines
1796 * with '\n', which prints out as the system-dependent EOL string in text
1797 * mode (typically LF on Unix and CRLF on Windows).
1799 if (cont->opt->start_table && !cont->opt->tuples_only)
1802 for (ptr = cont->headers; *ptr; ptr++)
1804 if (ptr != cont->headers)
1805 fputc(cont->opt->csvFieldSep[0], fout);
1806 csv_print_field(*ptr, fout, cont->opt->csvFieldSep[0]);
1812 for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
1814 csv_print_field(*ptr, fout, cont->opt->csvFieldSep[0]);
1815 if ((i + 1) % cont->ncolumns)
1816 fputc(cont->opt->csvFieldSep[0], fout);
1823 print_csv_vertical(const printTableContent *cont, FILE *fout)
1825 const char *const *ptr;
1829 for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
1834 /* print name of column */
1835 csv_print_field(cont->headers[i % cont->ncolumns], fout,
1836 cont->opt->csvFieldSep[0]);
1838 /* print field separator */
1839 fputc(cont->opt->csvFieldSep[0], fout);
1841 /* print field value */
1842 csv_print_field(*ptr, fout, cont->opt->csvFieldSep[0]);
1849 /**********************/
1851 /**********************/
1855 html_escaped_print(const char *in, FILE *fout)
1858 bool leading_space = true;
1860 for (p = in; *p; p++)
1865 fputs("&", fout);
1868 fputs("<", fout);
1871 fputs(">", fout);
1874 fputs("<br />\n", fout);
1877 fputs(""", fout);
1880 /* protect leading space, for EXPLAIN output */
1882 fputs(" ", fout);
1890 leading_space = false;
1896 print_html_text(const printTableContent *cont, FILE *fout)
1898 bool opt_tuples_only = cont->opt->tuples_only;
1899 unsigned short opt_border = cont->opt->border;
1900 const char *opt_table_attr = cont->opt->tableAttr;
1902 const char *const *ptr;
1907 if (cont->opt->start_table)
1909 fprintf(fout, "<table border=\"%d\"", opt_border);
1911 fprintf(fout, " %s", opt_table_attr);
1915 if (!opt_tuples_only && cont->title)
1917 fputs(" <caption>", fout);
1918 html_escaped_print(cont->title, fout);
1919 fputs("</caption>\n", fout);
1923 if (!opt_tuples_only)
1925 fputs(" <tr>\n", fout);
1926 for (ptr = cont->headers; *ptr; ptr++)
1928 fputs(" <th align=\"center\">", fout);
1929 html_escaped_print(*ptr, fout);
1930 fputs("</th>\n", fout);
1932 fputs(" </tr>\n", fout);
1937 for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
1939 if (i % cont->ncolumns == 0)
1943 fputs(" <tr valign=\"top\">\n", fout);
1946 fprintf(fout, " <td align=\"%s\">", cont->aligns[(i) % cont->ncolumns] == 'r' ? "right" : "left");
1947 /* is string only whitespace? */
1948 if ((*ptr)[strspn(*ptr, " \t")] == '\0')
1949 fputs(" ", fout);
1951 html_escaped_print(*ptr, fout);
1953 fputs("</td>\n", fout);
1955 if ((i + 1) % cont->ncolumns == 0)
1956 fputs(" </tr>\n", fout);
1959 if (cont->opt->stop_table)
1961 printTableFooter *footers = footers_with_default(cont);
1963 fputs("</table>\n", fout);
1966 if (!opt_tuples_only && footers != NULL && !cancel_pressed)
1968 printTableFooter *f;
1971 for (f = footers; f; f = f->next)
1973 html_escaped_print(f->data, fout);
1974 fputs("<br />\n", fout);
1976 fputs("</p>", fout);
1985 print_html_vertical(const printTableContent *cont, FILE *fout)
1987 bool opt_tuples_only = cont->opt->tuples_only;
1988 unsigned short opt_border = cont->opt->border;
1989 const char *opt_table_attr = cont->opt->tableAttr;
1990 unsigned long record = cont->opt->prior_records + 1;
1992 const char *const *ptr;
1997 if (cont->opt->start_table)
1999 fprintf(fout, "<table border=\"%d\"", opt_border);
2001 fprintf(fout, " %s", opt_table_attr);
2005 if (!opt_tuples_only && cont->title)
2007 fputs(" <caption>", fout);
2008 html_escaped_print(cont->title, fout);
2009 fputs("</caption>\n", fout);
2014 for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
2016 if (i % cont->ncolumns == 0)
2020 if (!opt_tuples_only)
2022 "\n <tr><td colspan=\"2\" align=\"center\">Record %lu</td></tr>\n",
2025 fputs("\n <tr><td colspan=\"2\"> </td></tr>\n", fout);
2027 fputs(" <tr valign=\"top\">\n"
2029 html_escaped_print(cont->headers[i % cont->ncolumns], fout);
2030 fputs("</th>\n", fout);
2032 fprintf(fout, " <td align=\"%s\">", cont->aligns[i % cont->ncolumns] == 'r' ? "right" : "left");
2033 /* is string only whitespace? */
2034 if ((*ptr)[strspn(*ptr, " \t")] == '\0')
2035 fputs(" ", fout);
2037 html_escaped_print(*ptr, fout);
2039 fputs("</td>\n </tr>\n", fout);
2042 if (cont->opt->stop_table)
2044 fputs("</table>\n", fout);
2047 if (!opt_tuples_only && cont->footers != NULL && !cancel_pressed)
2049 printTableFooter *f;
2052 for (f = cont->footers; f; f = f->next)
2054 html_escaped_print(f->data, fout);
2055 fputs("<br />\n", fout);
2057 fputs("</p>", fout);
2065 /*************************/
2067 /*************************/
2071 asciidoc_escaped_print(const char *in, FILE *fout)
2075 for (p = in; *p; p++)
2089 print_asciidoc_text(const printTableContent *cont, FILE *fout)
2091 bool opt_tuples_only = cont->opt->tuples_only;
2092 unsigned short opt_border = cont->opt->border;
2094 const char *const *ptr;
2099 if (cont->opt->start_table)
2101 /* print table in new paragraph - enforce preliminary new line */
2105 if (!opt_tuples_only && cont->title)
2108 fputs(cont->title, fout);
2112 /* print table [] header definition */
2113 fprintf(fout, "[%scols=\"", !opt_tuples_only ? "options=\"header\"," : "");
2114 for (i = 0; i < cont->ncolumns; i++)
2118 fprintf(fout, "%s", cont->aligns[(i) % cont->ncolumns] == 'r' ? ">l" : "<l");
2124 fputs(",frame=\"none\",grid=\"none\"", fout);
2127 fputs(",frame=\"none\"", fout);
2130 fputs(",frame=\"all\",grid=\"all\"", fout);
2134 fputs("|====\n", fout);
2137 if (!opt_tuples_only)
2139 for (ptr = cont->headers; *ptr; ptr++)
2141 if (ptr != cont->headers)
2144 asciidoc_escaped_print(*ptr, fout);
2151 for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
2153 if (i % cont->ncolumns == 0)
2159 if (i % cont->ncolumns != 0)
2163 /* protect against needless spaces */
2164 if ((*ptr)[strspn(*ptr, " \t")] == '\0')
2166 if ((i + 1) % cont->ncolumns != 0)
2170 asciidoc_escaped_print(*ptr, fout);
2172 if ((i + 1) % cont->ncolumns == 0)
2176 fputs("|====\n", fout);
2178 if (cont->opt->stop_table)
2180 printTableFooter *footers = footers_with_default(cont);
2183 if (!opt_tuples_only && footers != NULL && !cancel_pressed)
2185 printTableFooter *f;
2187 fputs("\n....\n", fout);
2188 for (f = footers; f; f = f->next)
2190 fputs(f->data, fout);
2193 fputs("....\n", fout);
2199 print_asciidoc_vertical(const printTableContent *cont, FILE *fout)
2201 bool opt_tuples_only = cont->opt->tuples_only;
2202 unsigned short opt_border = cont->opt->border;
2203 unsigned long record = cont->opt->prior_records + 1;
2205 const char *const *ptr;
2210 if (cont->opt->start_table)
2212 /* print table in new paragraph - enforce preliminary new line */
2216 if (!opt_tuples_only && cont->title)
2219 fputs(cont->title, fout);
2223 /* print table [] header definition */
2224 fputs("[cols=\"h,l\"", fout);
2228 fputs(",frame=\"none\",grid=\"none\"", fout);
2231 fputs(",frame=\"none\"", fout);
2234 fputs(",frame=\"all\",grid=\"all\"", fout);
2238 fputs("|====\n", fout);
2242 for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
2244 if (i % cont->ncolumns == 0)
2248 if (!opt_tuples_only)
2253 fputs("2+|\n", fout);
2257 asciidoc_escaped_print(cont->headers[i % cont->ncolumns], fout);
2259 fprintf(fout, " %s|", cont->aligns[i % cont->ncolumns] == 'r' ? ">l" : "<l");
2260 /* is string only whitespace? */
2261 if ((*ptr)[strspn(*ptr, " \t")] == '\0')
2264 asciidoc_escaped_print(*ptr, fout);
2268 fputs("|====\n", fout);
2270 if (cont->opt->stop_table)
2273 if (!opt_tuples_only && cont->footers != NULL && !cancel_pressed)
2275 printTableFooter *f;
2277 fputs("\n....\n", fout);
2278 for (f = cont->footers; f; f = f->next)
2280 fputs(f->data, fout);
2283 fputs("....\n", fout);
2289 /*************************/
2291 /*************************/
2295 latex_escaped_print(const char *in, FILE *fout)
2299 for (p = in; *p; p++)
2303 * We convert ASCII characters per the recommendations in
2304 * Scott Pakin's "The Comprehensive LATEX Symbol List",
2305 * available from CTAN. For non-ASCII, you're on your own.
2320 fputs("\\textless{}", fout);
2323 fputs("\\textgreater{}", fout);
2326 fputs("\\textbackslash{}", fout);
2329 fputs("\\^{}", fout);
2338 fputs("\\textbar{}", fout);
2344 fputs("\\~{}", fout);
2347 /* This is not right, but doing it right seems too hard */
2348 fputs("\\\\", fout);
2357 print_latex_text(const printTableContent *cont, FILE *fout)
2359 bool opt_tuples_only = cont->opt->tuples_only;
2360 unsigned short opt_border = cont->opt->border;
2362 const char *const *ptr;
2370 if (cont->opt->start_table)
2373 if (!opt_tuples_only && cont->title)
2375 fputs("\\begin{center}\n", fout);
2376 latex_escaped_print(cont->title, fout);
2377 fputs("\n\\end{center}\n\n", fout);
2380 /* begin environment and set alignments and borders */
2381 fputs("\\begin{tabular}{", fout);
2383 if (opt_border >= 2)
2385 for (i = 0; i < cont->ncolumns; i++)
2387 fputc(*(cont->aligns + i), fout);
2388 if (opt_border != 0 && i < cont->ncolumns - 1)
2391 if (opt_border >= 2)
2396 if (!opt_tuples_only && opt_border >= 2)
2397 fputs("\\hline\n", fout);
2400 if (!opt_tuples_only)
2402 for (i = 0, ptr = cont->headers; i < cont->ncolumns; i++, ptr++)
2406 fputs("\\textit{", fout);
2407 latex_escaped_print(*ptr, fout);
2410 fputs(" \\\\\n", fout);
2411 fputs("\\hline\n", fout);
2416 for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
2418 latex_escaped_print(*ptr, fout);
2420 if ((i + 1) % cont->ncolumns == 0)
2422 fputs(" \\\\\n", fout);
2423 if (opt_border == 3)
2424 fputs("\\hline\n", fout);
2432 if (cont->opt->stop_table)
2434 printTableFooter *footers = footers_with_default(cont);
2436 if (opt_border == 2)
2437 fputs("\\hline\n", fout);
2439 fputs("\\end{tabular}\n\n\\noindent ", fout);
2442 if (footers && !opt_tuples_only && !cancel_pressed)
2444 printTableFooter *f;
2446 for (f = footers; f; f = f->next)
2448 latex_escaped_print(f->data, fout);
2449 fputs(" \\\\\n", fout);
2458 /*************************/
2459 /* LaTeX longtable */
2460 /*************************/
2464 print_latex_longtable_text(const printTableContent *cont, FILE *fout)
2466 bool opt_tuples_only = cont->opt->tuples_only;
2467 unsigned short opt_border = cont->opt->border;
2469 const char *opt_table_attr = cont->opt->tableAttr;
2470 const char *next_opt_table_attr_char = opt_table_attr;
2471 const char *last_opt_table_attr_char = NULL;
2472 const char *const *ptr;
2480 if (cont->opt->start_table)
2482 /* begin environment and set alignments and borders */
2483 fputs("\\begin{longtable}{", fout);
2485 if (opt_border >= 2)
2488 for (i = 0; i < cont->ncolumns; i++)
2490 /* longtable supports either a width (p) or an alignment (l/r) */
2491 /* Are we left-justified and was a proportional width specified? */
2492 if (*(cont->aligns + i) == 'l' && opt_table_attr)
2494 #define LONGTABLE_WHITESPACE " \t\n"
2496 /* advance over whitespace */
2497 next_opt_table_attr_char += strspn(next_opt_table_attr_char,
2498 LONGTABLE_WHITESPACE);
2499 /* We have a value? */
2500 if (next_opt_table_attr_char[0] != '\0')
2503 fwrite(next_opt_table_attr_char, strcspn(next_opt_table_attr_char,
2504 LONGTABLE_WHITESPACE), 1, fout);
2505 last_opt_table_attr_char = next_opt_table_attr_char;
2506 next_opt_table_attr_char += strcspn(next_opt_table_attr_char,
2507 LONGTABLE_WHITESPACE);
2508 fputs("\\textwidth}", fout);
2510 /* use previous value */
2511 else if (last_opt_table_attr_char != NULL)
2514 fwrite(last_opt_table_attr_char, strcspn(last_opt_table_attr_char,
2515 LONGTABLE_WHITESPACE), 1, fout);
2516 fputs("\\textwidth}", fout);
2522 fputc(*(cont->aligns + i), fout);
2524 if (opt_border != 0 && i < cont->ncolumns - 1)
2528 if (opt_border >= 2)
2534 if (!opt_tuples_only)
2537 if (opt_border >= 2)
2538 fputs("\\toprule\n", fout);
2539 for (i = 0, ptr = cont->headers; i < cont->ncolumns; i++, ptr++)
2543 fputs("\\small\\textbf{\\textit{", fout);
2544 latex_escaped_print(*ptr, fout);
2547 fputs(" \\\\\n", fout);
2548 fputs("\\midrule\n\\endfirsthead\n", fout);
2550 /* secondary heads */
2551 if (opt_border >= 2)
2552 fputs("\\toprule\n", fout);
2553 for (i = 0, ptr = cont->headers; i < cont->ncolumns; i++, ptr++)
2557 fputs("\\small\\textbf{\\textit{", fout);
2558 latex_escaped_print(*ptr, fout);
2561 fputs(" \\\\\n", fout);
2562 /* If the line under the row already appeared, don't do another */
2563 if (opt_border != 3)
2564 fputs("\\midrule\n", fout);
2565 fputs("\\endhead\n", fout);
2567 /* table name, caption? */
2568 if (!opt_tuples_only && cont->title)
2570 /* Don't output if we are printing a line under each row */
2571 if (opt_border == 2)
2572 fputs("\\bottomrule\n", fout);
2573 fputs("\\caption[", fout);
2574 latex_escaped_print(cont->title, fout);
2575 fputs(" (Continued)]{", fout);
2576 latex_escaped_print(cont->title, fout);
2577 fputs("}\n\\endfoot\n", fout);
2578 if (opt_border == 2)
2579 fputs("\\bottomrule\n", fout);
2580 fputs("\\caption[", fout);
2581 latex_escaped_print(cont->title, fout);
2583 latex_escaped_print(cont->title, fout);
2584 fputs("}\n\\endlastfoot\n", fout);
2586 /* output bottom table line? */
2587 else if (opt_border >= 2)
2589 fputs("\\bottomrule\n\\endfoot\n", fout);
2590 fputs("\\bottomrule\n\\endlastfoot\n", fout);
2596 for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
2598 /* Add a line under each row? */
2599 if (i != 0 && i % cont->ncolumns != 0)
2600 fputs("\n&\n", fout);
2601 fputs("\\raggedright{", fout);
2602 latex_escaped_print(*ptr, fout);
2604 if ((i + 1) % cont->ncolumns == 0)
2606 fputs(" \\tabularnewline\n", fout);
2607 if (opt_border == 3)
2608 fputs(" \\hline\n", fout);
2614 if (cont->opt->stop_table)
2615 fputs("\\end{longtable}\n", fout);
2620 print_latex_vertical(const printTableContent *cont, FILE *fout)
2622 bool opt_tuples_only = cont->opt->tuples_only;
2623 unsigned short opt_border = cont->opt->border;
2624 unsigned long record = cont->opt->prior_records + 1;
2626 const char *const *ptr;
2634 if (cont->opt->start_table)
2637 if (!opt_tuples_only && cont->title)
2639 fputs("\\begin{center}\n", fout);
2640 latex_escaped_print(cont->title, fout);
2641 fputs("\n\\end{center}\n\n", fout);
2644 /* begin environment and set alignments and borders */
2645 fputs("\\begin{tabular}{", fout);
2646 if (opt_border == 0)
2648 else if (opt_border == 1)
2650 else if (opt_border == 2)
2651 fputs("|c|l|", fout);
2656 for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
2659 if (i % cont->ncolumns == 0)
2663 if (!opt_tuples_only)
2665 if (opt_border == 2)
2667 fputs("\\hline\n", fout);
2668 fprintf(fout, "\\multicolumn{2}{|c|}{\\textit{Record %lu}} \\\\\n", record++);
2671 fprintf(fout, "\\multicolumn{2}{c}{\\textit{Record %lu}} \\\\\n", record++);
2673 if (opt_border >= 1)
2674 fputs("\\hline\n", fout);
2677 latex_escaped_print(cont->headers[i % cont->ncolumns], fout);
2679 latex_escaped_print(*ptr, fout);
2680 fputs(" \\\\\n", fout);
2683 if (cont->opt->stop_table)
2685 if (opt_border == 2)
2686 fputs("\\hline\n", fout);
2688 fputs("\\end{tabular}\n\n\\noindent ", fout);
2691 if (cont->footers && !opt_tuples_only && !cancel_pressed)
2693 printTableFooter *f;
2695 for (f = cont->footers; f; f = f->next)
2697 latex_escaped_print(f->data, fout);
2698 fputs(" \\\\\n", fout);
2707 /*************************/
2709 /*************************/
2713 troff_ms_escaped_print(const char *in, FILE *fout)
2717 for (p = in; *p; p++)
2721 fputs("\\(rs", fout);
2730 print_troff_ms_text(const printTableContent *cont, FILE *fout)
2732 bool opt_tuples_only = cont->opt->tuples_only;
2733 unsigned short opt_border = cont->opt->border;
2735 const char *const *ptr;
2743 if (cont->opt->start_table)
2746 if (!opt_tuples_only && cont->title)
2748 fputs(".LP\n.DS C\n", fout);
2749 troff_ms_escaped_print(cont->title, fout);
2750 fputs("\n.DE\n", fout);
2753 /* begin environment and set alignments and borders */
2754 fputs(".LP\n.TS\n", fout);
2755 if (opt_border == 2)
2756 fputs("center box;\n", fout);
2758 fputs("center;\n", fout);
2760 for (i = 0; i < cont->ncolumns; i++)
2762 fputc(*(cont->aligns + i), fout);
2763 if (opt_border > 0 && i < cont->ncolumns - 1)
2769 if (!opt_tuples_only)
2771 for (i = 0, ptr = cont->headers; i < cont->ncolumns; i++, ptr++)
2775 fputs("\\fI", fout);
2776 troff_ms_escaped_print(*ptr, fout);
2777 fputs("\\fP", fout);
2779 fputs("\n_\n", fout);
2784 for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
2786 troff_ms_escaped_print(*ptr, fout);
2788 if ((i + 1) % cont->ncolumns == 0)
2798 if (cont->opt->stop_table)
2800 printTableFooter *footers = footers_with_default(cont);
2802 fputs(".TE\n.DS L\n", fout);
2805 if (footers && !opt_tuples_only && !cancel_pressed)
2807 printTableFooter *f;
2809 for (f = footers; f; f = f->next)
2811 troff_ms_escaped_print(f->data, fout);
2816 fputs(".DE\n", fout);
2822 print_troff_ms_vertical(const printTableContent *cont, FILE *fout)
2824 bool opt_tuples_only = cont->opt->tuples_only;
2825 unsigned short opt_border = cont->opt->border;
2826 unsigned long record = cont->opt->prior_records + 1;
2828 const char *const *ptr;
2829 unsigned short current_format = 0; /* 0=none, 1=header, 2=body */
2837 if (cont->opt->start_table)
2840 if (!opt_tuples_only && cont->title)
2842 fputs(".LP\n.DS C\n", fout);
2843 troff_ms_escaped_print(cont->title, fout);
2844 fputs("\n.DE\n", fout);
2847 /* begin environment and set alignments and borders */
2848 fputs(".LP\n.TS\n", fout);
2849 if (opt_border == 2)
2850 fputs("center box;\n", fout);
2852 fputs("center;\n", fout);
2855 if (opt_tuples_only)
2856 fputs("c l;\n", fout);
2859 current_format = 2; /* assume tuples printed already */
2862 for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
2865 if (i % cont->ncolumns == 0)
2869 if (!opt_tuples_only)
2871 if (current_format != 1)
2873 if (opt_border == 2 && record > 1)
2875 if (current_format != 0)
2876 fputs(".T&\n", fout);
2877 fputs("c s.\n", fout);
2880 fprintf(fout, "\\fIRecord %lu\\fP\n", record++);
2882 if (opt_border >= 1)
2886 if (!opt_tuples_only)
2888 if (current_format != 2)
2890 if (current_format != 0)
2891 fputs(".T&\n", fout);
2892 if (opt_border != 1)
2893 fputs("c l.\n", fout);
2895 fputs("c | l.\n", fout);
2900 troff_ms_escaped_print(cont->headers[i % cont->ncolumns], fout);
2902 troff_ms_escaped_print(*ptr, fout);
2907 if (cont->opt->stop_table)
2909 fputs(".TE\n.DS L\n", fout);
2912 if (cont->footers && !opt_tuples_only && !cancel_pressed)
2914 printTableFooter *f;
2916 for (f = cont->footers; f; f = f->next)
2918 troff_ms_escaped_print(f->data, fout);
2923 fputs(".DE\n", fout);
2928 /********************************/
2929 /* Public functions */
2930 /********************************/
2934 * disable_sigpipe_trap
2936 * Turn off SIGPIPE interrupt --- call this before writing to a temporary
2937 * query output file that is a pipe.
2939 * No-op on Windows, where there's no SIGPIPE interrupts.
2942 disable_sigpipe_trap(void)
2945 pqsignal(SIGPIPE, SIG_IGN);
2950 * restore_sigpipe_trap
2952 * Restore normal SIGPIPE interrupt --- call this when done writing to a
2953 * temporary query output file that was (or might have been) a pipe.
2955 * Note: within psql, we enable SIGPIPE interrupts unless the permanent query
2956 * output file is a pipe, in which case they should be kept off. This
2957 * approach works only because psql is not currently complicated enough to
2958 * have nested usages of short-lived output files. Otherwise we'd probably
2959 * need a genuine save-and-restore-state approach; but for now, that would be
2960 * useless complication. In non-psql programs, this always enables SIGPIPE.
2962 * No-op on Windows, where there's no SIGPIPE interrupts.
2965 restore_sigpipe_trap(void)
2968 pqsignal(SIGPIPE, always_ignore_sigpipe ? SIG_IGN : SIG_DFL);
2973 * set_sigpipe_trap_state
2975 * Set the trap state that restore_sigpipe_trap should restore to.
2978 set_sigpipe_trap_state(bool ignore)
2980 always_ignore_sigpipe = ignore;
2987 * Tests if pager is needed and returns appropriate FILE pointer.
2989 * If the topt argument is NULL no pager is used.
2992 PageOutput(int lines, const printTableOpt *topt)
2994 /* check whether we need / can / are supposed to use pager */
2995 if (topt && topt->pager && isatty(fileno(stdin)) && isatty(fileno(stdout)))
2998 unsigned short int pager = topt->pager;
2999 int min_lines = topt->pager_min_lines;
3001 struct winsize screen_size;
3003 result = ioctl(fileno(stdout), TIOCGWINSZ, &screen_size);
3005 /* >= accounts for a one-line prompt */
3007 || (lines >= screen_size.ws_row && lines >= min_lines)
3011 const char *pagerprog;
3014 pagerprog = getenv("PSQL_PAGER");
3016 pagerprog = getenv("PAGER");
3018 pagerprog = DEFAULT_PAGER;
3021 /* if PAGER is empty or all-white-space, don't use pager */
3022 if (strspn(pagerprog, " \t\r\n") == strlen(pagerprog))
3025 disable_sigpipe_trap();
3026 pagerpipe = popen(pagerprog, "w");
3029 /* if popen fails, silently proceed without pager */
3030 restore_sigpipe_trap();
3040 * Close previously opened pager pipe, if any
3043 ClosePager(FILE *pagerpipe)
3045 if (pagerpipe && pagerpipe != stdout)
3048 * If printing was canceled midstream, warn about it.
3050 * Some pagers like less use Ctrl-C as part of their command set. Even
3051 * so, we abort our processing and warn the user what we did. If the
3052 * pager quit as a result of the SIGINT, this message won't go
3056 fprintf(pagerpipe, _("Interrupted\n"));
3059 restore_sigpipe_trap();
3064 * Initialise a table contents struct.
3065 * Must be called before any other printTable method is used.
3067 * The title is not duplicated; the caller must ensure that the buffer
3068 * is available for the lifetime of the printTableContent struct.
3070 * If you call this, you must call printTableCleanup once you're done with the
3074 printTableInit(printTableContent *const content, const printTableOpt *opt,
3075 const char *title, const int ncolumns, const int nrows)
3078 content->title = title;
3079 content->ncolumns = ncolumns;
3080 content->nrows = nrows;
3082 content->headers = pg_malloc0((ncolumns + 1) * sizeof(*content->headers));
3084 content->cells = pg_malloc0((ncolumns * nrows + 1) * sizeof(*content->cells));
3086 content->cellmustfree = NULL;
3087 content->footers = NULL;
3089 content->aligns = pg_malloc0((ncolumns + 1) * sizeof(*content->align));
3091 content->header = content->headers;
3092 content->cell = content->cells;
3093 content->footer = content->footers;
3094 content->align = content->aligns;
3095 content->cellsadded = 0;
3099 * Add a header to the table.
3101 * Headers are not duplicated; you must ensure that the header string is
3102 * available for the lifetime of the printTableContent struct.
3104 * If translate is true, the function will pass the header through gettext.
3105 * Otherwise, the header will not be translated.
3107 * align is either 'l' or 'r', and specifies the alignment for cells in this
3111 printTableAddHeader(printTableContent *const content, char *header,
3112 const bool translate, const char align)
3115 (void) translate; /* unused parameter */
3118 if (content->header >= content->headers + content->ncolumns)
3120 fprintf(stderr, _("Cannot add header to table content: "
3121 "column count of %d exceeded.\n"),
3126 *content->header = (char *) mbvalidate((unsigned char *) header,
3127 content->opt->encoding);
3130 *content->header = _(*content->header);
3134 *content->align = align;
3139 * Add a cell to the table.
3141 * Cells are not duplicated; you must ensure that the cell string is available
3142 * for the lifetime of the printTableContent struct.
3144 * If translate is true, the function will pass the cell through gettext.
3145 * Otherwise, the cell will not be translated.
3147 * If mustfree is true, the cell string is freed by printTableCleanup().
3148 * Note: Automatic freeing of translatable strings is not supported.
3151 printTableAddCell(printTableContent *const content, char *cell,
3152 const bool translate, const bool mustfree)
3155 (void) translate; /* unused parameter */
3158 if (content->cellsadded >= content->ncolumns * content->nrows)
3160 fprintf(stderr, _("Cannot add cell to table content: "
3161 "total cell count of %d exceeded.\n"),
3162 content->ncolumns * content->nrows);
3166 *content->cell = (char *) mbvalidate((unsigned char *) cell,
3167 content->opt->encoding);
3171 *content->cell = _(*content->cell);
3176 if (content->cellmustfree == NULL)
3177 content->cellmustfree =
3178 pg_malloc0((content->ncolumns * content->nrows + 1) * sizeof(bool));
3180 content->cellmustfree[content->cellsadded] = true;
3183 content->cellsadded++;
3187 * Add a footer to the table.
3189 * Footers are added as elements of a singly-linked list, and the content is
3190 * strdup'd, so there is no need to keep the original footer string around.
3192 * Footers are never translated by the function. If you want the footer
3193 * translated you must do so yourself, before calling printTableAddFooter. The
3194 * reason this works differently to headers and cells is that footers tend to
3195 * be made of up individually translated components, rather than being
3196 * translated as a whole.
3199 printTableAddFooter(printTableContent *const content, const char *footer)
3201 printTableFooter *f;
3203 f = pg_malloc0(sizeof(*f));
3204 f->data = pg_strdup(footer);
3206 if (content->footers == NULL)
3207 content->footers = f;
3209 content->footer->next = f;
3211 content->footer = f;
3215 * Change the content of the last-added footer.
3217 * The current contents of the last-added footer are freed, and replaced by the
3218 * content given in *footer. If there was no previous footer, add a new one.
3220 * The content is strdup'd, so there is no need to keep the original string
3224 printTableSetFooter(printTableContent *const content, const char *footer)
3226 if (content->footers != NULL)
3228 free(content->footer->data);
3229 content->footer->data = pg_strdup(footer);
3232 printTableAddFooter(content, footer);
3236 * Free all memory allocated to this struct.
3238 * Once this has been called, the struct is unusable unless you pass it to
3239 * printTableInit() again.
3242 printTableCleanup(printTableContent *const content)
3244 if (content->cellmustfree)
3248 for (i = 0; i < content->nrows * content->ncolumns; i++)
3250 if (content->cellmustfree[i])
3251 free(unconstify(char *, content->cells[i]));
3253 free(content->cellmustfree);
3254 content->cellmustfree = NULL;
3256 free(content->headers);
3257 free(content->cells);
3258 free(content->aligns);
3260 content->opt = NULL;
3261 content->title = NULL;
3262 content->headers = NULL;
3263 content->cells = NULL;
3264 content->aligns = NULL;
3265 content->header = NULL;
3266 content->cell = NULL;
3267 content->align = NULL;
3269 if (content->footers)
3271 for (content->footer = content->footers; content->footer;)
3273 printTableFooter *f;
3275 f = content->footer;
3276 content->footer = f->next;
3281 content->footers = NULL;
3282 content->footer = NULL;
3288 * Setup pager if required
3291 IsPagerNeeded(const printTableContent *cont, int extra_lines, bool expanded,
3292 FILE **fout, bool *is_pager)
3294 if (*fout == stdout)
3299 lines = (cont->ncolumns + 1) * cont->nrows;
3301 lines = cont->nrows + 1;
3303 if (!cont->opt->tuples_only)
3305 printTableFooter *f;
3308 * FIXME -- this is slightly bogus: it counts the number of
3309 * footers, not the number of lines in them.
3311 for (f = cont->footers; f; f = f->next)
3315 *fout = PageOutput(lines + extra_lines, cont->opt);
3316 *is_pager = (*fout != stdout);
3323 * Use this to print any table in the supported formats.
3325 * cont: table data and formatting options
3326 * fout: where to print to
3327 * is_pager: true if caller has already redirected fout to be a pager pipe
3328 * flog: if not null, also print the table there (for --log-file option)
3331 printTable(const printTableContent *cont,
3332 FILE *fout, bool is_pager, FILE *flog)
3334 bool is_local_pager = false;
3339 if (cont->opt->format == PRINT_NOTHING)
3342 /* print_aligned_*() handle the pager themselves */
3344 cont->opt->format != PRINT_ALIGNED &&
3345 cont->opt->format != PRINT_WRAPPED)
3347 IsPagerNeeded(cont, 0, (cont->opt->expanded == 1), &fout, &is_pager);
3348 is_local_pager = is_pager;
3351 /* print the stuff */
3354 print_aligned_text(cont, flog, false);
3356 switch (cont->opt->format)
3358 case PRINT_UNALIGNED:
3359 if (cont->opt->expanded == 1)
3360 print_unaligned_vertical(cont, fout);
3362 print_unaligned_text(cont, fout);
3368 * In expanded-auto mode, force vertical if a pager is passed in;
3369 * else we may make different decisions for different hunks of the
3372 if (cont->opt->expanded == 1 ||
3373 (cont->opt->expanded == 2 && is_pager))
3374 print_aligned_vertical(cont, fout, is_pager);
3376 print_aligned_text(cont, fout, is_pager);
3379 if (cont->opt->expanded == 1)
3380 print_csv_vertical(cont, fout);
3382 print_csv_text(cont, fout);
3385 if (cont->opt->expanded == 1)
3386 print_html_vertical(cont, fout);
3388 print_html_text(cont, fout);
3390 case PRINT_ASCIIDOC:
3391 if (cont->opt->expanded == 1)
3392 print_asciidoc_vertical(cont, fout);
3394 print_asciidoc_text(cont, fout);
3397 if (cont->opt->expanded == 1)
3398 print_latex_vertical(cont, fout);
3400 print_latex_text(cont, fout);
3402 case PRINT_LATEX_LONGTABLE:
3403 if (cont->opt->expanded == 1)
3404 print_latex_vertical(cont, fout);
3406 print_latex_longtable_text(cont, fout);
3408 case PRINT_TROFF_MS:
3409 if (cont->opt->expanded == 1)
3410 print_troff_ms_vertical(cont, fout);
3412 print_troff_ms_text(cont, fout);
3415 fprintf(stderr, _("invalid output format (internal error): %d"),
3425 * Use this to print query results
3427 * result: result of a successful query
3428 * opt: formatting options
3429 * fout: where to print to
3430 * is_pager: true if caller has already redirected fout to be a pager pipe
3431 * flog: if not null, also print the data there (for --log-file option)
3434 printQuery(const PGresult *result, const printQueryOpt *opt,
3435 FILE *fout, bool is_pager, FILE *flog)
3437 printTableContent cont;
3445 printTableInit(&cont, &opt->topt, opt->title,
3446 PQnfields(result), PQntuples(result));
3448 /* Assert caller supplied enough translate_columns[] entries */
3449 Assert(opt->translate_columns == NULL ||
3450 opt->n_translate_columns >= cont.ncolumns);
3452 for (i = 0; i < cont.ncolumns; i++)
3454 printTableAddHeader(&cont, PQfname(result, i),
3455 opt->translate_header,
3456 column_type_alignment(PQftype(result, i)));
3460 for (r = 0; r < cont.nrows; r++)
3462 for (c = 0; c < cont.ncolumns; c++)
3465 bool mustfree = false;
3468 if (PQgetisnull(result, r, c))
3469 cell = opt->nullPrint ? opt->nullPrint : "";
3472 cell = PQgetvalue(result, r, c);
3473 if (cont.aligns[c] == 'r' && opt->topt.numericLocale)
3475 cell = format_numeric_locale(cell);
3480 translate = (opt->translate_columns && opt->translate_columns[c]);
3481 printTableAddCell(&cont, cell, translate, mustfree);
3490 for (footer = opt->footers; *footer; footer++)
3491 printTableAddFooter(&cont, *footer);
3494 printTable(&cont, fout, is_pager, flog);
3495 printTableCleanup(&cont);
3499 column_type_alignment(Oid ftype)
3525 setDecimalLocale(void)
3527 struct lconv *extlconv;
3529 extlconv = localeconv();
3531 /* Don't accept an empty decimal_point string */
3532 if (*extlconv->decimal_point)
3533 decimal_point = pg_strdup(extlconv->decimal_point);
3535 decimal_point = "."; /* SQL output standard */
3538 * Although the Open Group standard allows locales to supply more than one
3539 * group width, we consider only the first one, and we ignore any attempt
3540 * to suppress grouping by specifying CHAR_MAX. As in the backend's
3541 * cash.c, we must apply a range check to avoid being fooled by variant
3544 groupdigits = *extlconv->grouping;
3545 if (groupdigits <= 0 || groupdigits > 6)
3546 groupdigits = 3; /* most common */
3548 /* Don't accept an empty thousands_sep string, either */
3549 /* similar code exists in formatting.c */
3550 if (*extlconv->thousands_sep)
3551 thousands_sep = pg_strdup(extlconv->thousands_sep);
3552 /* Make sure thousands separator doesn't match decimal point symbol. */
3553 else if (strcmp(decimal_point, ",") != 0)
3554 thousands_sep = ",";
3556 thousands_sep = ".";
3559 /* get selected or default line style */
3560 const printTextFormat *
3561 get_line_style(const printTableOpt *opt)
3564 * Note: this function mainly exists to preserve the convention that a
3565 * printTableOpt struct can be initialized to zeroes to get default
3568 if (opt->line_style != NULL)
3569 return opt->line_style;
3571 return &pg_asciiformat;
3575 refresh_utf8format(const printTableOpt *opt)
3577 printTextFormat *popt = &pg_utf8format;
3579 const unicodeStyleBorderFormat *border;
3580 const unicodeStyleRowFormat *header;
3581 const unicodeStyleColumnFormat *column;
3583 popt->name = "unicode";
3585 border = &unicode_style.border_style[opt->unicode_border_linestyle];
3586 header = &unicode_style.row_style[opt->unicode_header_linestyle];
3587 column = &unicode_style.column_style[opt->unicode_column_linestyle];
3589 popt->lrule[PRINT_RULE_TOP].hrule = border->horizontal;
3590 popt->lrule[PRINT_RULE_TOP].leftvrule = border->down_and_right;
3591 popt->lrule[PRINT_RULE_TOP].midvrule = column->down_and_horizontal[opt->unicode_border_linestyle];
3592 popt->lrule[PRINT_RULE_TOP].rightvrule = border->down_and_left;
3594 popt->lrule[PRINT_RULE_MIDDLE].hrule = header->horizontal;
3595 popt->lrule[PRINT_RULE_MIDDLE].leftvrule = header->vertical_and_right[opt->unicode_border_linestyle];
3596 popt->lrule[PRINT_RULE_MIDDLE].midvrule = column->vertical_and_horizontal[opt->unicode_header_linestyle];
3597 popt->lrule[PRINT_RULE_MIDDLE].rightvrule = header->vertical_and_left[opt->unicode_border_linestyle];
3599 popt->lrule[PRINT_RULE_BOTTOM].hrule = border->horizontal;
3600 popt->lrule[PRINT_RULE_BOTTOM].leftvrule = border->up_and_right;
3601 popt->lrule[PRINT_RULE_BOTTOM].midvrule = column->up_and_horizontal[opt->unicode_border_linestyle];
3602 popt->lrule[PRINT_RULE_BOTTOM].rightvrule = border->left_and_right;
3605 popt->lrule[PRINT_RULE_DATA].hrule = "";
3606 popt->lrule[PRINT_RULE_DATA].leftvrule = border->vertical;
3607 popt->lrule[PRINT_RULE_DATA].midvrule = column->vertical;
3608 popt->lrule[PRINT_RULE_DATA].rightvrule = border->vertical;
3610 popt->midvrule_nl = column->vertical;
3611 popt->midvrule_wrap = column->vertical;
3612 popt->midvrule_blank = column->vertical;
3614 /* Same for all unicode today */
3615 popt->header_nl_left = unicode_style.header_nl_left;
3616 popt->header_nl_right = unicode_style.header_nl_right;
3617 popt->nl_left = unicode_style.nl_left;
3618 popt->nl_right = unicode_style.nl_right;
3619 popt->wrap_left = unicode_style.wrap_left;
3620 popt->wrap_right = unicode_style.wrap_right;
3621 popt->wrap_right_border = unicode_style.wrap_right_border;
3627 * Compute the byte distance to the end of the string or *target_width
3628 * display character positions, whichever comes first. Update *target_width
3629 * to be the number of display character positions actually filled.
3632 strlen_max_width(unsigned char *str, int *target_width, int encoding)
3634 unsigned char *start = str;
3635 unsigned char *end = str + strlen((char *) str);
3640 int char_width = PQdsplen((char *) str, encoding);
3643 * If the display width of the new character causes the string to
3644 * exceed its target width, skip it and return. However, if this is
3645 * the first character of the string (curr_width == 0), we have to
3648 if (*target_width < curr_width + char_width && curr_width != 0)
3651 curr_width += char_width;
3653 str += PQmblen((char *) str, encoding);
3656 *target_width = curr_width;