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