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