1 /*-------------------------------------------------------------------------
2  *
3  * Query-result printing support for frontend code
4  *
5  * This file used to be part of psql, but now it's separated out to allow
6  * other frontend programs to use it.  Because the printing code needs
7  * access to the cancel_pressed flag as well as SIGPIPE trapping and
8  * pager open/close functions, all that stuff came with it.
9  *
10  *
11  * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
12  * Portions Copyright (c) 1994, Regents of the University of California
13  *
14  * src/fe_utils/print.c
15  *
16  *-------------------------------------------------------------------------
17  */
18 #include "postgres_fe.h"
19 
20 #include <limits.h>
21 #include <locale.h>
22 #include <math.h>
23 #include <signal.h>
24 #include <unistd.h>
25 
26 #ifndef WIN32
27 #include <sys/ioctl.h>			/* for ioctl() */
28 #endif
29 
30 #ifdef HAVE_TERMIOS_H
31 #include <termios.h>
32 #endif
33 
34 #include "fe_utils/print.h"
35 
36 #include "catalog/pg_type.h"
37 #include "fe_utils/mbprint.h"
38 
39 
40 /*
41  * If the calling program doesn't have any mechanism for setting
42  * cancel_pressed, it will have no effect.
43  *
44  * Note: print.c's general strategy for when to check cancel_pressed is to do
45  * so at completion of each row of output.
46  */
47 volatile bool cancel_pressed = false;
48 
49 static bool always_ignore_sigpipe = false;
50 
51 /* info for locale-aware numeric formatting; set up by setDecimalLocale() */
52 static char *decimal_point;
53 static int	groupdigits;
54 static char *thousands_sep;
55 
56 static char default_footer[100];
57 static printTableFooter default_footer_cell = {default_footer, NULL};
58 
59 /* Line style control structures */
60 const printTextFormat pg_asciiformat =
61 {
62 	"ascii",
63 	{
64 		{"-", "+", "+", "+"},
65 		{"-", "+", "+", "+"},
66 		{"-", "+", "+", "+"},
67 		{"", "|", "|", "|"}
68 	},
69 	"|",
70 	"|",
71 	"|",
72 	" ",
73 	"+",
74 	" ",
75 	"+",
76 	".",
77 	".",
78 	true
79 };
80 
81 const printTextFormat pg_asciiformat_old =
82 {
83 	"old-ascii",
84 	{
85 		{"-", "+", "+", "+"},
86 		{"-", "+", "+", "+"},
87 		{"-", "+", "+", "+"},
88 		{"", "|", "|", "|"}
89 	},
90 	":",
91 	";",
92 	" ",
93 	"+",
94 	" ",
95 	" ",
96 	" ",
97 	" ",
98 	" ",
99 	false
100 };
101 
102 /* Default unicode linestyle format */
103 printTextFormat pg_utf8format;
104 
105 typedef struct unicodeStyleRowFormat
106 {
107 	const char *horizontal;
108 	const char *vertical_and_right[2];
109 	const char *vertical_and_left[2];
110 } unicodeStyleRowFormat;
111 
112 typedef struct unicodeStyleColumnFormat
113 {
114 	const char *vertical;
115 	const char *vertical_and_horizontal[2];
116 	const char *up_and_horizontal[2];
117 	const char *down_and_horizontal[2];
118 } unicodeStyleColumnFormat;
119 
120 typedef struct unicodeStyleBorderFormat
121 {
122 	const char *up_and_right;
123 	const char *vertical;
124 	const char *down_and_right;
125 	const char *horizontal;
126 	const char *down_and_left;
127 	const char *left_and_right;
128 } unicodeStyleBorderFormat;
129 
130 typedef struct unicodeStyleFormat
131 {
132 	unicodeStyleRowFormat row_style[2];
133 	unicodeStyleColumnFormat column_style[2];
134 	unicodeStyleBorderFormat border_style[2];
135 	const char *header_nl_left;
136 	const char *header_nl_right;
137 	const char *nl_left;
138 	const char *nl_right;
139 	const char *wrap_left;
140 	const char *wrap_right;
141 	bool		wrap_right_border;
142 } unicodeStyleFormat;
143 
144 static const unicodeStyleFormat unicode_style = {
145 	{
146 		{
147 			/* ─ */
148 			"\342\224\200",
149 			/* ├╟ */
150 			{"\342\224\234", "\342\225\237"},
151 			/* ┤╢ */
152 			{"\342\224\244", "\342\225\242"},
153 		},
154 		{
155 			/* ═ */
156 			"\342\225\220",
157 			/* ╞╠ */
158 			{"\342\225\236", "\342\225\240"},
159 			/* ╡╣ */
160 			{"\342\225\241", "\342\225\243"},
161 		},
162 	},
163 	{
164 		{
165 			/* │ */
166 			"\342\224\202",
167 			/* ┼╪ */
168 			{"\342\224\274", "\342\225\252"},
169 			/* ┴╧ */
170 			{"\342\224\264", "\342\225\247"},
171 			/* ┬╤ */
172 			{"\342\224\254", "\342\225\244"},
173 		},
174 		{
175 			/* ║ */
176 			"\342\225\221",
177 			/* ╫╬ */
178 			{"\342\225\253", "\342\225\254"},
179 			/* ╨╩ */
180 			{"\342\225\250", "\342\225\251"},
181 			/* ╥╦ */
182 			{"\342\225\245", "\342\225\246"},
183 		},
184 	},
185 	{
186 		/* └│┌─┐┘ */
187 		{"\342\224\224", "\342\224\202", "\342\224\214", "\342\224\200", "\342\224\220", "\342\224\230"},
188 		/* ╚║╔═╗╝ */
189 		{"\342\225\232", "\342\225\221", "\342\225\224", "\342\225\220", "\342\225\227", "\342\225\235"},
190 	},
191 	" ",
192 	"\342\206\265",				/* ↵ */
193 	" ",
194 	"\342\206\265",				/* ↵ */
195 	"\342\200\246",				/* … */
196 	"\342\200\246",				/* … */
197 	true
198 };
199 
200 
201 /* Local functions */
202 static int	strlen_max_width(unsigned char *str, int *target_width, int encoding);
203 static void IsPagerNeeded(const printTableContent *cont, int extra_lines, bool expanded,
204 			  FILE **fout, bool *is_pager);
205 
206 static void print_aligned_vertical(const printTableContent *cont,
207 					   FILE *fout, bool is_pager);
208 
209 
210 /* Count number of digits in integral part of number */
211 static int
integer_digits(const char * my_str)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
additional_numeric_locale_len(const char * my_str)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 *
format_numeric_locale(const char * my_str)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
fputnbytes(FILE * f,const char * str,size_t n)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
print_separator(struct separator sep,FILE * fout)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 *
footers_with_default(const printTableContent * cont)346 footers_with_default(const printTableContent *cont)
347 {
348 	if (cont->footers == NULL && cont->opt->default_footer)
349 	{
350 		unsigned long total_records;
351 
352 		total_records = cont->opt->prior_records + cont->nrows;
353 		snprintf(default_footer, sizeof(default_footer),
354 				 ngettext("(%lu row)", "(%lu rows)", total_records),
355 				 total_records);
356 
357 		return &default_footer_cell;
358 	}
359 	else
360 		return cont->footers;
361 }
362 
363 
364 /*************************/
365 /* Unaligned text		 */
366 /*************************/
367 
368 
369 static void
print_unaligned_text(const printTableContent * cont,FILE * fout)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
print_unaligned_vertical(const printTableContent * cont,FILE * fout)461 print_unaligned_vertical(const printTableContent *cont, FILE *fout)
462 {
463 	bool		opt_tuples_only = cont->opt->tuples_only;
464 	unsigned int i;
465 	const char *const * ptr;
466 	bool		need_recordsep = false;
467 
468 	if (cancel_pressed)
469 		return;
470 
471 	if (cont->opt->start_table)
472 	{
473 		/* print title */
474 		if (!opt_tuples_only && cont->title)
475 		{
476 			fputs(cont->title, fout);
477 			need_recordsep = true;
478 		}
479 	}
480 	else
481 		/* assume continuing printout */
482 		need_recordsep = true;
483 
484 	/* print records */
485 	for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
486 	{
487 		if (need_recordsep)
488 		{
489 			/* record separator is 2 occurrences of recordsep in this mode */
490 			print_separator(cont->opt->recordSep, fout);
491 			print_separator(cont->opt->recordSep, fout);
492 			need_recordsep = false;
493 			if (cancel_pressed)
494 				break;
495 		}
496 
497 		fputs(cont->headers[i % cont->ncolumns], fout);
498 		print_separator(cont->opt->fieldSep, fout);
499 		fputs(*ptr, fout);
500 
501 		if ((i + 1) % cont->ncolumns)
502 			print_separator(cont->opt->recordSep, fout);
503 		else
504 			need_recordsep = true;
505 	}
506 
507 	if (cont->opt->stop_table)
508 	{
509 		/* print footers */
510 		if (!opt_tuples_only && cont->footers != NULL && !cancel_pressed)
511 		{
512 			printTableFooter *f;
513 
514 			print_separator(cont->opt->recordSep, fout);
515 			for (f = cont->footers; f; f = f->next)
516 			{
517 				print_separator(cont->opt->recordSep, fout);
518 				fputs(f->data, fout);
519 			}
520 		}
521 
522 		/* see above in print_unaligned_text() */
523 		if (need_recordsep)
524 		{
525 			if (cont->opt->recordSep.separator_zero)
526 				print_separator(cont->opt->recordSep, fout);
527 			else
528 				fputc('\n', fout);
529 		}
530 	}
531 }
532 
533 
534 /********************/
535 /* Aligned text		*/
536 /********************/
537 
538 
539 /* draw "line" */
540 static void
_print_horizontal_line(const unsigned int ncolumns,const unsigned int * widths,unsigned short border,printTextRule pos,const printTextFormat * format,FILE * fout)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
print_aligned_text(const printTableContent * cont,FILE * fout,bool is_pager)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
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)1175 print_aligned_vertical_line(const printTextFormat *format,
1176 							const unsigned short opt_border,
1177 							unsigned long record,
1178 							unsigned int hwidth,
1179 							unsigned int dwidth,
1180 							printTextRule pos,
1181 							FILE *fout)
1182 {
1183 	const printTextLineFormat *lformat = &format->lrule[pos];
1184 	unsigned int i;
1185 	int			reclen = 0;
1186 
1187 	if (opt_border == 2)
1188 		fprintf(fout, "%s%s", lformat->leftvrule, lformat->hrule);
1189 	else if (opt_border == 1)
1190 		fputs(lformat->hrule, fout);
1191 
1192 	if (record)
1193 	{
1194 		if (opt_border == 0)
1195 			reclen = fprintf(fout, "* Record %lu", record);
1196 		else
1197 			reclen = fprintf(fout, "[ RECORD %lu ]", record);
1198 	}
1199 	if (opt_border != 2)
1200 		reclen++;
1201 	if (reclen < 0)
1202 		reclen = 0;
1203 	for (i = reclen; i < hwidth; i++)
1204 		fputs(opt_border > 0 ? lformat->hrule : " ", fout);
1205 	reclen -= hwidth;
1206 
1207 	if (opt_border > 0)
1208 	{
1209 		if (reclen-- <= 0)
1210 			fputs(lformat->hrule, fout);
1211 		if (reclen-- <= 0)
1212 			fputs(lformat->midvrule, fout);
1213 		if (reclen-- <= 0)
1214 			fputs(lformat->hrule, fout);
1215 	}
1216 	else
1217 	{
1218 		if (reclen-- <= 0)
1219 			fputc(' ', fout);
1220 	}
1221 	if (reclen < 0)
1222 		reclen = 0;
1223 	for (i = reclen; i < dwidth; i++)
1224 		fputs(opt_border > 0 ? lformat->hrule : " ", fout);
1225 	if (opt_border == 2)
1226 		fprintf(fout, "%s%s", lformat->hrule, lformat->rightvrule);
1227 	fputc('\n', fout);
1228 }
1229 
1230 static void
print_aligned_vertical(const printTableContent * cont,FILE * fout,bool is_pager)1231 print_aligned_vertical(const printTableContent *cont,
1232 					   FILE *fout, bool is_pager)
1233 {
1234 	bool		opt_tuples_only = cont->opt->tuples_only;
1235 	unsigned short opt_border = cont->opt->border;
1236 	const printTextFormat *format = get_line_style(cont->opt);
1237 	const printTextLineFormat *dformat = &format->lrule[PRINT_RULE_DATA];
1238 	int			encoding = cont->opt->encoding;
1239 	unsigned long record = cont->opt->prior_records + 1;
1240 	const char *const * ptr;
1241 	unsigned int i,
1242 				hwidth = 0,
1243 				dwidth = 0,
1244 				hheight = 1,
1245 				dheight = 1,
1246 				hformatsize = 0,
1247 				dformatsize = 0;
1248 	struct lineptr *hlineptr,
1249 			   *dlineptr;
1250 	bool		is_local_pager = false,
1251 				hmultiline = false,
1252 				dmultiline = false;
1253 	int			output_columns = 0;		/* Width of interactive console */
1254 
1255 	if (cancel_pressed)
1256 		return;
1257 
1258 	if (opt_border > 2)
1259 		opt_border = 2;
1260 
1261 	if (cont->cells[0] == NULL && cont->opt->start_table &&
1262 		cont->opt->stop_table)
1263 	{
1264 		printTableFooter *footers = footers_with_default(cont);
1265 
1266 		if (!opt_tuples_only && !cancel_pressed && footers)
1267 		{
1268 			printTableFooter *f;
1269 
1270 			for (f = footers; f; f = f->next)
1271 				fprintf(fout, "%s\n", f->data);
1272 		}
1273 
1274 		fputc('\n', fout);
1275 
1276 		return;
1277 	}
1278 
1279 	/*
1280 	 * Deal with the pager here instead of in printTable(), because we could
1281 	 * get here via print_aligned_text() in expanded auto mode, and so we have
1282 	 * to recalculate the pager requirement based on vertical output.
1283 	 */
1284 	if (!is_pager)
1285 	{
1286 		IsPagerNeeded(cont, 0, true, &fout, &is_pager);
1287 		is_local_pager = is_pager;
1288 	}
1289 
1290 	/* Find the maximum dimensions for the headers */
1291 	for (i = 0; i < cont->ncolumns; i++)
1292 	{
1293 		int			width,
1294 					height,
1295 					fs;
1296 
1297 		pg_wcssize((const unsigned char *) cont->headers[i], strlen(cont->headers[i]),
1298 				   encoding, &width, &height, &fs);
1299 		if (width > hwidth)
1300 			hwidth = width;
1301 		if (height > hheight)
1302 		{
1303 			hheight = height;
1304 			hmultiline = true;
1305 		}
1306 		if (fs > hformatsize)
1307 			hformatsize = fs;
1308 	}
1309 
1310 	/* find longest data cell */
1311 	for (i = 0, ptr = cont->cells; *ptr; ptr++, i++)
1312 	{
1313 		int			width,
1314 					height,
1315 					fs;
1316 
1317 		pg_wcssize((const unsigned char *) *ptr, strlen(*ptr), encoding,
1318 				   &width, &height, &fs);
1319 		if (width > dwidth)
1320 			dwidth = width;
1321 		if (height > dheight)
1322 		{
1323 			dheight = height;
1324 			dmultiline = true;
1325 		}
1326 		if (fs > dformatsize)
1327 			dformatsize = fs;
1328 	}
1329 
1330 	/*
1331 	 * We now have all the information we need to setup the formatting
1332 	 * structures
1333 	 */
1334 	dlineptr = pg_malloc((sizeof(*dlineptr)) * (dheight + 1));
1335 	hlineptr = pg_malloc((sizeof(*hlineptr)) * (hheight + 1));
1336 
1337 	dlineptr->ptr = pg_malloc(dformatsize);
1338 	hlineptr->ptr = pg_malloc(hformatsize);
1339 
1340 	if (cont->opt->start_table)
1341 	{
1342 		/* print title */
1343 		if (!opt_tuples_only && cont->title)
1344 			fprintf(fout, "%s\n", cont->title);
1345 	}
1346 
1347 	/*
1348 	 * Choose target output width: \pset columns, or $COLUMNS, or ioctl
1349 	 */
1350 	if (cont->opt->columns > 0)
1351 		output_columns = cont->opt->columns;
1352 	else if ((fout == stdout && isatty(fileno(stdout))) || is_pager)
1353 	{
1354 		if (cont->opt->env_columns > 0)
1355 			output_columns = cont->opt->env_columns;
1356 #ifdef TIOCGWINSZ
1357 		else
1358 		{
1359 			struct winsize screen_size;
1360 
1361 			if (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) != -1)
1362 				output_columns = screen_size.ws_col;
1363 		}
1364 #endif
1365 	}
1366 
1367 	/*
1368 	 * Calculate available width for data in wrapped mode
1369 	 */
1370 	if (cont->opt->format == PRINT_WRAPPED)
1371 	{
1372 		unsigned int swidth,
1373 					rwidth = 0,
1374 					newdwidth;
1375 
1376 		if (opt_border == 0)
1377 		{
1378 			/*
1379 			 * For border = 0, one space in the middle.  (If we discover we
1380 			 * need to wrap, the spacer column will be replaced by a wrap
1381 			 * marker, and we'll make room below for another wrap marker at
1382 			 * the end of the line.  But for now, assume no wrap is needed.)
1383 			 */
1384 			swidth = 1;
1385 
1386 			/* We might need a column for header newline markers, too */
1387 			if (hmultiline)
1388 				swidth++;
1389 		}
1390 		else if (opt_border == 1)
1391 		{
1392 			/*
1393 			 * For border = 1, two spaces and a vrule in the middle.  (As
1394 			 * above, we might need one more column for a wrap marker.)
1395 			 */
1396 			swidth = 3;
1397 
1398 			/* We might need a column for left header newline markers, too */
1399 			if (hmultiline && (format == &pg_asciiformat_old))
1400 				swidth++;
1401 		}
1402 		else
1403 		{
1404 			/*
1405 			 * For border = 2, two more for the vrules at the beginning and
1406 			 * end of the lines, plus spacer columns adjacent to these.  (We
1407 			 * won't need extra columns for wrap/newline markers, we'll just
1408 			 * repurpose the spacers.)
1409 			 */
1410 			swidth = 7;
1411 		}
1412 
1413 		/* Reserve a column for data newline indicators, too, if needed */
1414 		if (dmultiline &&
1415 			opt_border < 2 && format != &pg_asciiformat_old)
1416 			swidth++;
1417 
1418 		/* Determine width required for record header lines */
1419 		if (!opt_tuples_only)
1420 		{
1421 			if (cont->nrows > 0)
1422 				rwidth = 1 + (int) log10(cont->nrows);
1423 			if (opt_border == 0)
1424 				rwidth += 9;	/* "* RECORD " */
1425 			else if (opt_border == 1)
1426 				rwidth += 12;	/* "-[ RECORD  ]" */
1427 			else
1428 				rwidth += 15;	/* "+-[ RECORD  ]-+" */
1429 		}
1430 
1431 		/* We might need to do the rest of the calculation twice */
1432 		for (;;)
1433 		{
1434 			unsigned int width;
1435 
1436 			/* Total width required to not wrap data */
1437 			width = hwidth + swidth + dwidth;
1438 			/* ... and not the header lines, either */
1439 			if (width < rwidth)
1440 				width = rwidth;
1441 
1442 			if (output_columns > 0)
1443 			{
1444 				unsigned int min_width;
1445 
1446 				/* Minimum acceptable width: room for just 3 columns of data */
1447 				min_width = hwidth + swidth + 3;
1448 				/* ... but not less than what the record header lines need */
1449 				if (min_width < rwidth)
1450 					min_width = rwidth;
1451 
1452 				if (output_columns >= width)
1453 				{
1454 					/* Plenty of room, use native data width */
1455 					/* (but at least enough for the record header lines) */
1456 					newdwidth = width - hwidth - swidth;
1457 				}
1458 				else if (output_columns < min_width)
1459 				{
1460 					/* Set data width to match min_width */
1461 					newdwidth = min_width - hwidth - swidth;
1462 				}
1463 				else
1464 				{
1465 					/* Set data width to match output_columns */
1466 					newdwidth = output_columns - hwidth - swidth;
1467 				}
1468 			}
1469 			else
1470 			{
1471 				/* Don't know the wrap limit, so use native data width */
1472 				/* (but at least enough for the record header lines) */
1473 				newdwidth = width - hwidth - swidth;
1474 			}
1475 
1476 			/*
1477 			 * If we will need to wrap data and didn't already allocate a data
1478 			 * newline/wrap marker column, do so and recompute.
1479 			 */
1480 			if (newdwidth < dwidth && !dmultiline &&
1481 				opt_border < 2 && format != &pg_asciiformat_old)
1482 			{
1483 				dmultiline = true;
1484 				swidth++;
1485 			}
1486 			else
1487 				break;
1488 		}
1489 
1490 		dwidth = newdwidth;
1491 	}
1492 
1493 	/* print records */
1494 	for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
1495 	{
1496 		printTextRule pos;
1497 		int			dline,
1498 					hline,
1499 					dcomplete,
1500 					hcomplete,
1501 					offset,
1502 					chars_to_output;
1503 
1504 		if (cancel_pressed)
1505 			break;
1506 
1507 		if (i == 0)
1508 			pos = PRINT_RULE_TOP;
1509 		else
1510 			pos = PRINT_RULE_MIDDLE;
1511 
1512 		/* Print record header (e.g. "[ RECORD N ]") above each record */
1513 		if (i % cont->ncolumns == 0)
1514 		{
1515 			unsigned int lhwidth = hwidth;
1516 
1517 			if ((opt_border < 2) &&
1518 				(hmultiline) &&
1519 				(format == &pg_asciiformat_old))
1520 				lhwidth++;		/* for newline indicators */
1521 
1522 			if (!opt_tuples_only)
1523 				print_aligned_vertical_line(format, opt_border, record++,
1524 											lhwidth, dwidth, pos, fout);
1525 			else if (i != 0 || !cont->opt->start_table || opt_border == 2)
1526 				print_aligned_vertical_line(format, opt_border, 0, lhwidth,
1527 											dwidth, pos, fout);
1528 		}
1529 
1530 		/* Format the header */
1531 		pg_wcsformat((const unsigned char *) cont->headers[i % cont->ncolumns],
1532 					 strlen(cont->headers[i % cont->ncolumns]),
1533 					 encoding, hlineptr, hheight);
1534 		/* Format the data */
1535 		pg_wcsformat((const unsigned char *) *ptr, strlen(*ptr), encoding,
1536 					 dlineptr, dheight);
1537 
1538 		/*
1539 		 * Loop through header and data in parallel dealing with newlines and
1540 		 * wrapped lines until they're both exhausted
1541 		 */
1542 		dline = hline = 0;
1543 		dcomplete = hcomplete = 0;
1544 		offset = 0;
1545 		chars_to_output = dlineptr[dline].width;
1546 		while (!dcomplete || !hcomplete)
1547 		{
1548 			/* Left border */
1549 			if (opt_border == 2)
1550 				fprintf(fout, "%s", dformat->leftvrule);
1551 
1552 			/* Header (never wrapped so just need to deal with newlines) */
1553 			if (!hcomplete)
1554 			{
1555 				int			swidth = hwidth,
1556 							target_width = hwidth;
1557 
1558 				/*
1559 				 * Left spacer or new line indicator
1560 				 */
1561 				if ((opt_border == 2) ||
1562 					(hmultiline && (format == &pg_asciiformat_old)))
1563 					fputs(hline ? format->header_nl_left : " ", fout);
1564 
1565 				/*
1566 				 * Header text
1567 				 */
1568 				strlen_max_width(hlineptr[hline].ptr, &target_width,
1569 								 encoding);
1570 				fprintf(fout, "%-s", hlineptr[hline].ptr);
1571 
1572 				/*
1573 				 * Spacer
1574 				 */
1575 				swidth -= target_width;
1576 				if (swidth > 0)
1577 					fprintf(fout, "%*s", swidth, " ");
1578 
1579 				/*
1580 				 * New line indicator or separator's space
1581 				 */
1582 				if (hlineptr[hline + 1].ptr)
1583 				{
1584 					/* More lines after this one due to a newline */
1585 					if ((opt_border > 0) ||
1586 						(hmultiline && (format != &pg_asciiformat_old)))
1587 						fputs(format->header_nl_right, fout);
1588 					hline++;
1589 				}
1590 				else
1591 				{
1592 					/* This was the last line of the header */
1593 					if ((opt_border > 0) ||
1594 						(hmultiline && (format != &pg_asciiformat_old)))
1595 						fputs(" ", fout);
1596 					hcomplete = 1;
1597 				}
1598 			}
1599 			else
1600 			{
1601 				unsigned int swidth = hwidth + opt_border;
1602 
1603 				if ((opt_border < 2) &&
1604 					(hmultiline) &&
1605 					(format == &pg_asciiformat_old))
1606 					swidth++;
1607 
1608 				if ((opt_border == 0) &&
1609 					(format != &pg_asciiformat_old) &&
1610 					(hmultiline))
1611 					swidth++;
1612 
1613 				fprintf(fout, "%*s", swidth, " ");
1614 			}
1615 
1616 			/* Separator */
1617 			if (opt_border > 0)
1618 			{
1619 				if (offset)
1620 					fputs(format->midvrule_wrap, fout);
1621 				else if (dline == 0)
1622 					fputs(dformat->midvrule, fout);
1623 				else
1624 					fputs(format->midvrule_nl, fout);
1625 			}
1626 
1627 			/* Data */
1628 			if (!dcomplete)
1629 			{
1630 				int			target_width = dwidth,
1631 							bytes_to_output,
1632 							swidth = dwidth;
1633 
1634 				/*
1635 				 * Left spacer or wrap indicator
1636 				 */
1637 				fputs(offset == 0 ? " " : format->wrap_left, fout);
1638 
1639 				/*
1640 				 * Data text
1641 				 */
1642 				bytes_to_output = strlen_max_width(dlineptr[dline].ptr + offset,
1643 												   &target_width, encoding);
1644 				fputnbytes(fout, (char *) (dlineptr[dline].ptr + offset),
1645 						   bytes_to_output);
1646 
1647 				chars_to_output -= target_width;
1648 				offset += bytes_to_output;
1649 
1650 				/* Spacer */
1651 				swidth -= target_width;
1652 
1653 				if (chars_to_output)
1654 				{
1655 					/* continuing a wrapped column */
1656 					if ((opt_border > 1) ||
1657 						(dmultiline && (format != &pg_asciiformat_old)))
1658 					{
1659 						if (swidth > 0)
1660 							fprintf(fout, "%*s", swidth, " ");
1661 						fputs(format->wrap_right, fout);
1662 					}
1663 				}
1664 				else if (dlineptr[dline + 1].ptr)
1665 				{
1666 					/* reached a newline in the column */
1667 					if ((opt_border > 1) ||
1668 						(dmultiline && (format != &pg_asciiformat_old)))
1669 					{
1670 						if (swidth > 0)
1671 							fprintf(fout, "%*s", swidth, " ");
1672 						fputs(format->nl_right, fout);
1673 					}
1674 					dline++;
1675 					offset = 0;
1676 					chars_to_output = dlineptr[dline].width;
1677 				}
1678 				else
1679 				{
1680 					/* reached the end of the cell */
1681 					if (opt_border > 1)
1682 					{
1683 						if (swidth > 0)
1684 							fprintf(fout, "%*s", swidth, " ");
1685 						fputs(" ", fout);
1686 					}
1687 					dcomplete = 1;
1688 				}
1689 
1690 				/* Right border */
1691 				if (opt_border == 2)
1692 					fputs(dformat->rightvrule, fout);
1693 
1694 				fputs("\n", fout);
1695 			}
1696 			else
1697 			{
1698 				/*
1699 				 * data exhausted (this can occur if header is longer than the
1700 				 * data due to newlines in the header)
1701 				 */
1702 				if (opt_border < 2)
1703 					fputs("\n", fout);
1704 				else
1705 					fprintf(fout, "%*s  %s\n", dwidth, "", dformat->rightvrule);
1706 			}
1707 		}
1708 	}
1709 
1710 	if (cont->opt->stop_table)
1711 	{
1712 		if (opt_border == 2 && !cancel_pressed)
1713 			print_aligned_vertical_line(format, opt_border, 0, hwidth, dwidth,
1714 										PRINT_RULE_BOTTOM, fout);
1715 
1716 		/* print footers */
1717 		if (!opt_tuples_only && cont->footers != NULL && !cancel_pressed)
1718 		{
1719 			printTableFooter *f;
1720 
1721 			if (opt_border < 2)
1722 				fputc('\n', fout);
1723 			for (f = cont->footers; f; f = f->next)
1724 				fprintf(fout, "%s\n", f->data);
1725 		}
1726 
1727 		fputc('\n', fout);
1728 	}
1729 
1730 	free(hlineptr->ptr);
1731 	free(dlineptr->ptr);
1732 	free(hlineptr);
1733 	free(dlineptr);
1734 
1735 	if (is_local_pager)
1736 		ClosePager(fout);
1737 }
1738 
1739 
1740 /**********************/
1741 /* HTML printing ******/
1742 /**********************/
1743 
1744 
1745 void
html_escaped_print(const char * in,FILE * fout)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
print_html_text(const printTableContent * cont,FILE * fout)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
print_html_vertical(const printTableContent * cont,FILE * fout)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
asciidoc_escaped_print(const char * in,FILE * fout)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
print_asciidoc_text(const printTableContent * cont,FILE * fout)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
print_asciidoc_vertical(const printTableContent * cont,FILE * fout)2089 print_asciidoc_vertical(const printTableContent *cont, FILE *fout)
2090 {
2091 	bool		opt_tuples_only = cont->opt->tuples_only;
2092 	unsigned short opt_border = cont->opt->border;
2093 	unsigned long record = cont->opt->prior_records + 1;
2094 	unsigned int i;
2095 	const char *const * ptr;
2096 
2097 	if (cancel_pressed)
2098 		return;
2099 
2100 	if (cont->opt->start_table)
2101 	{
2102 		/* print table in new paragraph - enforce preliminary new line */
2103 		fputs("\n", fout);
2104 
2105 		/* print title */
2106 		if (!opt_tuples_only && cont->title)
2107 		{
2108 			fputs(".", fout);
2109 			fputs(cont->title, fout);
2110 			fputs("\n", fout);
2111 		}
2112 
2113 		/* print table [] header definition */
2114 		fputs("[cols=\"h,l\"", fout);
2115 		switch (opt_border)
2116 		{
2117 			case 0:
2118 				fputs(",frame=\"none\",grid=\"none\"", fout);
2119 				break;
2120 			case 1:
2121 				fputs(",frame=\"none\"", fout);
2122 				break;
2123 			case 2:
2124 				fputs(",frame=\"all\",grid=\"all\"", fout);
2125 				break;
2126 		}
2127 		fputs("]\n", fout);
2128 		fputs("|====\n", fout);
2129 	}
2130 
2131 	/* print records */
2132 	for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
2133 	{
2134 		if (i % cont->ncolumns == 0)
2135 		{
2136 			if (cancel_pressed)
2137 				break;
2138 			if (!opt_tuples_only)
2139 				fprintf(fout,
2140 						"2+^|Record %lu\n",
2141 						record++);
2142 			else
2143 				fputs("2+|\n", fout);
2144 		}
2145 
2146 		fputs("<l|", fout);
2147 		asciidoc_escaped_print(cont->headers[i % cont->ncolumns], fout);
2148 
2149 		fprintf(fout, " %s|", cont->aligns[i % cont->ncolumns] == 'r' ? ">l" : "<l");
2150 		/* is string only whitespace? */
2151 		if ((*ptr)[strspn(*ptr, " \t")] == '\0')
2152 			fputs(" ", fout);
2153 		else
2154 			asciidoc_escaped_print(*ptr, fout);
2155 		fputs("\n", fout);
2156 	}
2157 
2158 	fputs("|====\n", fout);
2159 
2160 	if (cont->opt->stop_table)
2161 	{
2162 		/* print footers */
2163 		if (!opt_tuples_only && cont->footers != NULL && !cancel_pressed)
2164 		{
2165 			printTableFooter *f;
2166 
2167 			fputs("\n....\n", fout);
2168 			for (f = cont->footers; f; f = f->next)
2169 			{
2170 				fputs(f->data, fout);
2171 				fputs("\n", fout);
2172 			}
2173 			fputs("....\n", fout);
2174 		}
2175 	}
2176 }
2177 
2178 /*************************/
2179 /* LaTeX				 */
2180 /*************************/
2181 
2182 
2183 static void
latex_escaped_print(const char * in,FILE * fout)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 				/*
2192 				 * We convert ASCII characters per the recommendations in
2193 				 * Scott Pakin's "The Comprehensive LATEX Symbol List",
2194 				 * available from CTAN.  For non-ASCII, you're on your own.
2195 				 */
2196 			case '#':
2197 				fputs("\\#", fout);
2198 				break;
2199 			case '$':
2200 				fputs("\\$", fout);
2201 				break;
2202 			case '%':
2203 				fputs("\\%", fout);
2204 				break;
2205 			case '&':
2206 				fputs("\\&", fout);
2207 				break;
2208 			case '<':
2209 				fputs("\\textless{}", fout);
2210 				break;
2211 			case '>':
2212 				fputs("\\textgreater{}", fout);
2213 				break;
2214 			case '\\':
2215 				fputs("\\textbackslash{}", fout);
2216 				break;
2217 			case '^':
2218 				fputs("\\^{}", fout);
2219 				break;
2220 			case '_':
2221 				fputs("\\_", fout);
2222 				break;
2223 			case '{':
2224 				fputs("\\{", fout);
2225 				break;
2226 			case '|':
2227 				fputs("\\textbar{}", fout);
2228 				break;
2229 			case '}':
2230 				fputs("\\}", fout);
2231 				break;
2232 			case '~':
2233 				fputs("\\~{}", fout);
2234 				break;
2235 			case '\n':
2236 				/* This is not right, but doing it right seems too hard */
2237 				fputs("\\\\", fout);
2238 				break;
2239 			default:
2240 				fputc(*p, fout);
2241 		}
2242 }
2243 
2244 
2245 static void
print_latex_text(const printTableContent * cont,FILE * fout)2246 print_latex_text(const printTableContent *cont, FILE *fout)
2247 {
2248 	bool		opt_tuples_only = cont->opt->tuples_only;
2249 	unsigned short opt_border = cont->opt->border;
2250 	unsigned int i;
2251 	const char *const * ptr;
2252 
2253 	if (cancel_pressed)
2254 		return;
2255 
2256 	if (opt_border > 3)
2257 		opt_border = 3;
2258 
2259 	if (cont->opt->start_table)
2260 	{
2261 		/* print title */
2262 		if (!opt_tuples_only && cont->title)
2263 		{
2264 			fputs("\\begin{center}\n", fout);
2265 			latex_escaped_print(cont->title, fout);
2266 			fputs("\n\\end{center}\n\n", fout);
2267 		}
2268 
2269 		/* begin environment and set alignments and borders */
2270 		fputs("\\begin{tabular}{", fout);
2271 
2272 		if (opt_border >= 2)
2273 			fputs("| ", fout);
2274 		for (i = 0; i < cont->ncolumns; i++)
2275 		{
2276 			fputc(*(cont->aligns + i), fout);
2277 			if (opt_border != 0 && i < cont->ncolumns - 1)
2278 				fputs(" | ", fout);
2279 		}
2280 		if (opt_border >= 2)
2281 			fputs(" |", fout);
2282 
2283 		fputs("}\n", fout);
2284 
2285 		if (!opt_tuples_only && opt_border >= 2)
2286 			fputs("\\hline\n", fout);
2287 
2288 		/* print headers */
2289 		if (!opt_tuples_only)
2290 		{
2291 			for (i = 0, ptr = cont->headers; i < cont->ncolumns; i++, ptr++)
2292 			{
2293 				if (i != 0)
2294 					fputs(" & ", fout);
2295 				fputs("\\textit{", fout);
2296 				latex_escaped_print(*ptr, fout);
2297 				fputc('}', fout);
2298 			}
2299 			fputs(" \\\\\n", fout);
2300 			fputs("\\hline\n", fout);
2301 		}
2302 	}
2303 
2304 	/* print cells */
2305 	for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
2306 	{
2307 		latex_escaped_print(*ptr, fout);
2308 
2309 		if ((i + 1) % cont->ncolumns == 0)
2310 		{
2311 			fputs(" \\\\\n", fout);
2312 			if (opt_border == 3)
2313 				fputs("\\hline\n", fout);
2314 			if (cancel_pressed)
2315 				break;
2316 		}
2317 		else
2318 			fputs(" & ", fout);
2319 	}
2320 
2321 	if (cont->opt->stop_table)
2322 	{
2323 		printTableFooter *footers = footers_with_default(cont);
2324 
2325 		if (opt_border == 2)
2326 			fputs("\\hline\n", fout);
2327 
2328 		fputs("\\end{tabular}\n\n\\noindent ", fout);
2329 
2330 		/* print footers */
2331 		if (footers && !opt_tuples_only && !cancel_pressed)
2332 		{
2333 			printTableFooter *f;
2334 
2335 			for (f = footers; f; f = f->next)
2336 			{
2337 				latex_escaped_print(f->data, fout);
2338 				fputs(" \\\\\n", fout);
2339 			}
2340 		}
2341 
2342 		fputc('\n', fout);
2343 	}
2344 }
2345 
2346 
2347 static void
print_latex_longtable_text(const printTableContent * cont,FILE * fout)2348 print_latex_longtable_text(const printTableContent *cont, FILE *fout)
2349 {
2350 	bool		opt_tuples_only = cont->opt->tuples_only;
2351 	unsigned short opt_border = cont->opt->border;
2352 	unsigned int i;
2353 	const char *opt_table_attr = cont->opt->tableAttr;
2354 	const char *next_opt_table_attr_char = opt_table_attr;
2355 	const char *last_opt_table_attr_char = NULL;
2356 	const char *const * ptr;
2357 
2358 	if (cancel_pressed)
2359 		return;
2360 
2361 	if (opt_border > 3)
2362 		opt_border = 3;
2363 
2364 	if (cont->opt->start_table)
2365 	{
2366 		/* begin environment and set alignments and borders */
2367 		fputs("\\begin{longtable}{", fout);
2368 
2369 		if (opt_border >= 2)
2370 			fputs("| ", fout);
2371 
2372 		for (i = 0; i < cont->ncolumns; i++)
2373 		{
2374 			/* longtable supports either a width (p) or an alignment (l/r) */
2375 			/* Are we left-justified and was a proportional width specified? */
2376 			if (*(cont->aligns + i) == 'l' && opt_table_attr)
2377 			{
2378 #define LONGTABLE_WHITESPACE	" \t\n"
2379 
2380 				/* advance over whitespace */
2381 				next_opt_table_attr_char += strspn(next_opt_table_attr_char,
2382 												   LONGTABLE_WHITESPACE);
2383 				/* We have a value? */
2384 				if (next_opt_table_attr_char[0] != '\0')
2385 				{
2386 					fputs("p{", fout);
2387 					fwrite(next_opt_table_attr_char, strcspn(next_opt_table_attr_char,
2388 											 LONGTABLE_WHITESPACE), 1, fout);
2389 					last_opt_table_attr_char = next_opt_table_attr_char;
2390 					next_opt_table_attr_char += strcspn(next_opt_table_attr_char,
2391 														LONGTABLE_WHITESPACE);
2392 					fputs("\\textwidth}", fout);
2393 				}
2394 				/* use previous value */
2395 				else if (last_opt_table_attr_char != NULL)
2396 				{
2397 					fputs("p{", fout);
2398 					fwrite(last_opt_table_attr_char, strcspn(last_opt_table_attr_char,
2399 											 LONGTABLE_WHITESPACE), 1, fout);
2400 					fputs("\\textwidth}", fout);
2401 				}
2402 				else
2403 					fputc('l', fout);
2404 			}
2405 			else
2406 				fputc(*(cont->aligns + i), fout);
2407 
2408 			if (opt_border != 0 && i < cont->ncolumns - 1)
2409 				fputs(" | ", fout);
2410 		}
2411 
2412 		if (opt_border >= 2)
2413 			fputs(" |", fout);
2414 
2415 		fputs("}\n", fout);
2416 
2417 		/* print headers */
2418 		if (!opt_tuples_only)
2419 		{
2420 			/* firsthead */
2421 			if (opt_border >= 2)
2422 				fputs("\\toprule\n", fout);
2423 			for (i = 0, ptr = cont->headers; i < cont->ncolumns; i++, ptr++)
2424 			{
2425 				if (i != 0)
2426 					fputs(" & ", fout);
2427 				fputs("\\small\\textbf{\\textit{", fout);
2428 				latex_escaped_print(*ptr, fout);
2429 				fputs("}}", fout);
2430 			}
2431 			fputs(" \\\\\n", fout);
2432 			fputs("\\midrule\n\\endfirsthead\n", fout);
2433 
2434 			/* secondary heads */
2435 			if (opt_border >= 2)
2436 				fputs("\\toprule\n", fout);
2437 			for (i = 0, ptr = cont->headers; i < cont->ncolumns; i++, ptr++)
2438 			{
2439 				if (i != 0)
2440 					fputs(" & ", fout);
2441 				fputs("\\small\\textbf{\\textit{", fout);
2442 				latex_escaped_print(*ptr, fout);
2443 				fputs("}}", fout);
2444 			}
2445 			fputs(" \\\\\n", fout);
2446 			/* If the line under the row already appeared, don't do another */
2447 			if (opt_border != 3)
2448 				fputs("\\midrule\n", fout);
2449 			fputs("\\endhead\n", fout);
2450 
2451 			/* table name, caption? */
2452 			if (!opt_tuples_only && cont->title)
2453 			{
2454 				/* Don't output if we are printing a line under each row */
2455 				if (opt_border == 2)
2456 					fputs("\\bottomrule\n", fout);
2457 				fputs("\\caption[", fout);
2458 				latex_escaped_print(cont->title, fout);
2459 				fputs(" (Continued)]{", fout);
2460 				latex_escaped_print(cont->title, fout);
2461 				fputs("}\n\\endfoot\n", fout);
2462 				if (opt_border == 2)
2463 					fputs("\\bottomrule\n", fout);
2464 				fputs("\\caption[", fout);
2465 				latex_escaped_print(cont->title, fout);
2466 				fputs("]{", fout);
2467 				latex_escaped_print(cont->title, fout);
2468 				fputs("}\n\\endlastfoot\n", fout);
2469 			}
2470 			/* output bottom table line? */
2471 			else if (opt_border >= 2)
2472 			{
2473 				fputs("\\bottomrule\n\\endfoot\n", fout);
2474 				fputs("\\bottomrule\n\\endlastfoot\n", fout);
2475 			}
2476 		}
2477 	}
2478 
2479 	/* print cells */
2480 	for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
2481 	{
2482 		/* Add a line under each row? */
2483 		if (i != 0 && i % cont->ncolumns != 0)
2484 			fputs("\n&\n", fout);
2485 		fputs("\\raggedright{", fout);
2486 		latex_escaped_print(*ptr, fout);
2487 		fputc('}', fout);
2488 		if ((i + 1) % cont->ncolumns == 0)
2489 		{
2490 			fputs(" \\tabularnewline\n", fout);
2491 			if (opt_border == 3)
2492 				fputs(" \\hline\n", fout);
2493 		}
2494 		if (cancel_pressed)
2495 			break;
2496 	}
2497 
2498 	if (cont->opt->stop_table)
2499 		fputs("\\end{longtable}\n", fout);
2500 }
2501 
2502 
2503 static void
print_latex_vertical(const printTableContent * cont,FILE * fout)2504 print_latex_vertical(const printTableContent *cont, FILE *fout)
2505 {
2506 	bool		opt_tuples_only = cont->opt->tuples_only;
2507 	unsigned short opt_border = cont->opt->border;
2508 	unsigned long record = cont->opt->prior_records + 1;
2509 	unsigned int i;
2510 	const char *const * ptr;
2511 
2512 	if (cancel_pressed)
2513 		return;
2514 
2515 	if (opt_border > 2)
2516 		opt_border = 2;
2517 
2518 	if (cont->opt->start_table)
2519 	{
2520 		/* print title */
2521 		if (!opt_tuples_only && cont->title)
2522 		{
2523 			fputs("\\begin{center}\n", fout);
2524 			latex_escaped_print(cont->title, fout);
2525 			fputs("\n\\end{center}\n\n", fout);
2526 		}
2527 
2528 		/* begin environment and set alignments and borders */
2529 		fputs("\\begin{tabular}{", fout);
2530 		if (opt_border == 0)
2531 			fputs("cl", fout);
2532 		else if (opt_border == 1)
2533 			fputs("c|l", fout);
2534 		else if (opt_border == 2)
2535 			fputs("|c|l|", fout);
2536 		fputs("}\n", fout);
2537 	}
2538 
2539 	/* print records */
2540 	for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
2541 	{
2542 		/* new record */
2543 		if (i % cont->ncolumns == 0)
2544 		{
2545 			if (cancel_pressed)
2546 				break;
2547 			if (!opt_tuples_only)
2548 			{
2549 				if (opt_border == 2)
2550 				{
2551 					fputs("\\hline\n", fout);
2552 					fprintf(fout, "\\multicolumn{2}{|c|}{\\textit{Record %lu}} \\\\\n", record++);
2553 				}
2554 				else
2555 					fprintf(fout, "\\multicolumn{2}{c}{\\textit{Record %lu}} \\\\\n", record++);
2556 			}
2557 			if (opt_border >= 1)
2558 				fputs("\\hline\n", fout);
2559 		}
2560 
2561 		latex_escaped_print(cont->headers[i % cont->ncolumns], fout);
2562 		fputs(" & ", fout);
2563 		latex_escaped_print(*ptr, fout);
2564 		fputs(" \\\\\n", fout);
2565 	}
2566 
2567 	if (cont->opt->stop_table)
2568 	{
2569 		if (opt_border == 2)
2570 			fputs("\\hline\n", fout);
2571 
2572 		fputs("\\end{tabular}\n\n\\noindent ", fout);
2573 
2574 		/* print footers */
2575 		if (cont->footers && !opt_tuples_only && !cancel_pressed)
2576 		{
2577 			printTableFooter *f;
2578 
2579 			for (f = cont->footers; f; f = f->next)
2580 			{
2581 				latex_escaped_print(f->data, fout);
2582 				fputs(" \\\\\n", fout);
2583 			}
2584 		}
2585 
2586 		fputc('\n', fout);
2587 	}
2588 }
2589 
2590 
2591 /*************************/
2592 /* Troff -ms		 */
2593 /*************************/
2594 
2595 
2596 static void
troff_ms_escaped_print(const char * in,FILE * fout)2597 troff_ms_escaped_print(const char *in, FILE *fout)
2598 {
2599 	const char *p;
2600 
2601 	for (p = in; *p; p++)
2602 		switch (*p)
2603 		{
2604 			case '\\':
2605 				fputs("\\(rs", fout);
2606 				break;
2607 			default:
2608 				fputc(*p, fout);
2609 		}
2610 }
2611 
2612 
2613 static void
print_troff_ms_text(const printTableContent * cont,FILE * fout)2614 print_troff_ms_text(const printTableContent *cont, FILE *fout)
2615 {
2616 	bool		opt_tuples_only = cont->opt->tuples_only;
2617 	unsigned short opt_border = cont->opt->border;
2618 	unsigned int i;
2619 	const char *const * ptr;
2620 
2621 	if (cancel_pressed)
2622 		return;
2623 
2624 	if (opt_border > 2)
2625 		opt_border = 2;
2626 
2627 	if (cont->opt->start_table)
2628 	{
2629 		/* print title */
2630 		if (!opt_tuples_only && cont->title)
2631 		{
2632 			fputs(".LP\n.DS C\n", fout);
2633 			troff_ms_escaped_print(cont->title, fout);
2634 			fputs("\n.DE\n", fout);
2635 		}
2636 
2637 		/* begin environment and set alignments and borders */
2638 		fputs(".LP\n.TS\n", fout);
2639 		if (opt_border == 2)
2640 			fputs("center box;\n", fout);
2641 		else
2642 			fputs("center;\n", fout);
2643 
2644 		for (i = 0; i < cont->ncolumns; i++)
2645 		{
2646 			fputc(*(cont->aligns + i), fout);
2647 			if (opt_border > 0 && i < cont->ncolumns - 1)
2648 				fputs(" | ", fout);
2649 		}
2650 		fputs(".\n", fout);
2651 
2652 		/* print headers */
2653 		if (!opt_tuples_only)
2654 		{
2655 			for (i = 0, ptr = cont->headers; i < cont->ncolumns; i++, ptr++)
2656 			{
2657 				if (i != 0)
2658 					fputc('\t', fout);
2659 				fputs("\\fI", fout);
2660 				troff_ms_escaped_print(*ptr, fout);
2661 				fputs("\\fP", fout);
2662 			}
2663 			fputs("\n_\n", fout);
2664 		}
2665 	}
2666 
2667 	/* print cells */
2668 	for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
2669 	{
2670 		troff_ms_escaped_print(*ptr, fout);
2671 
2672 		if ((i + 1) % cont->ncolumns == 0)
2673 		{
2674 			fputc('\n', fout);
2675 			if (cancel_pressed)
2676 				break;
2677 		}
2678 		else
2679 			fputc('\t', fout);
2680 	}
2681 
2682 	if (cont->opt->stop_table)
2683 	{
2684 		printTableFooter *footers = footers_with_default(cont);
2685 
2686 		fputs(".TE\n.DS L\n", fout);
2687 
2688 		/* print footers */
2689 		if (footers && !opt_tuples_only && !cancel_pressed)
2690 		{
2691 			printTableFooter *f;
2692 
2693 			for (f = footers; f; f = f->next)
2694 			{
2695 				troff_ms_escaped_print(f->data, fout);
2696 				fputc('\n', fout);
2697 			}
2698 		}
2699 
2700 		fputs(".DE\n", fout);
2701 	}
2702 }
2703 
2704 
2705 static void
print_troff_ms_vertical(const printTableContent * cont,FILE * fout)2706 print_troff_ms_vertical(const printTableContent *cont, FILE *fout)
2707 {
2708 	bool		opt_tuples_only = cont->opt->tuples_only;
2709 	unsigned short opt_border = cont->opt->border;
2710 	unsigned long record = cont->opt->prior_records + 1;
2711 	unsigned int i;
2712 	const char *const * ptr;
2713 	unsigned short current_format = 0;	/* 0=none, 1=header, 2=body */
2714 
2715 	if (cancel_pressed)
2716 		return;
2717 
2718 	if (opt_border > 2)
2719 		opt_border = 2;
2720 
2721 	if (cont->opt->start_table)
2722 	{
2723 		/* print title */
2724 		if (!opt_tuples_only && cont->title)
2725 		{
2726 			fputs(".LP\n.DS C\n", fout);
2727 			troff_ms_escaped_print(cont->title, fout);
2728 			fputs("\n.DE\n", fout);
2729 		}
2730 
2731 		/* begin environment and set alignments and borders */
2732 		fputs(".LP\n.TS\n", fout);
2733 		if (opt_border == 2)
2734 			fputs("center box;\n", fout);
2735 		else
2736 			fputs("center;\n", fout);
2737 
2738 		/* basic format */
2739 		if (opt_tuples_only)
2740 			fputs("c l;\n", fout);
2741 	}
2742 	else
2743 		current_format = 2;		/* assume tuples printed already */
2744 
2745 	/* print records */
2746 	for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
2747 	{
2748 		/* new record */
2749 		if (i % cont->ncolumns == 0)
2750 		{
2751 			if (cancel_pressed)
2752 				break;
2753 			if (!opt_tuples_only)
2754 			{
2755 				if (current_format != 1)
2756 				{
2757 					if (opt_border == 2 && record > 1)
2758 						fputs("_\n", fout);
2759 					if (current_format != 0)
2760 						fputs(".T&\n", fout);
2761 					fputs("c s.\n", fout);
2762 					current_format = 1;
2763 				}
2764 				fprintf(fout, "\\fIRecord %lu\\fP\n", record++);
2765 			}
2766 			if (opt_border >= 1)
2767 				fputs("_\n", fout);
2768 		}
2769 
2770 		if (!opt_tuples_only)
2771 		{
2772 			if (current_format != 2)
2773 			{
2774 				if (current_format != 0)
2775 					fputs(".T&\n", fout);
2776 				if (opt_border != 1)
2777 					fputs("c l.\n", fout);
2778 				else
2779 					fputs("c | l.\n", fout);
2780 				current_format = 2;
2781 			}
2782 		}
2783 
2784 		troff_ms_escaped_print(cont->headers[i % cont->ncolumns], fout);
2785 		fputc('\t', fout);
2786 		troff_ms_escaped_print(*ptr, fout);
2787 
2788 		fputc('\n', fout);
2789 	}
2790 
2791 	if (cont->opt->stop_table)
2792 	{
2793 		fputs(".TE\n.DS L\n", fout);
2794 
2795 		/* print footers */
2796 		if (cont->footers && !opt_tuples_only && !cancel_pressed)
2797 		{
2798 			printTableFooter *f;
2799 
2800 			for (f = cont->footers; f; f = f->next)
2801 			{
2802 				troff_ms_escaped_print(f->data, fout);
2803 				fputc('\n', fout);
2804 			}
2805 		}
2806 
2807 		fputs(".DE\n", fout);
2808 	}
2809 }
2810 
2811 
2812 /********************************/
2813 /* Public functions				*/
2814 /********************************/
2815 
2816 
2817 /*
2818  * disable_sigpipe_trap
2819  *
2820  * Turn off SIGPIPE interrupt --- call this before writing to a temporary
2821  * query output file that is a pipe.
2822  *
2823  * No-op on Windows, where there's no SIGPIPE interrupts.
2824  */
2825 void
disable_sigpipe_trap(void)2826 disable_sigpipe_trap(void)
2827 {
2828 #ifndef WIN32
2829 	pqsignal(SIGPIPE, SIG_IGN);
2830 #endif
2831 }
2832 
2833 /*
2834  * restore_sigpipe_trap
2835  *
2836  * Restore normal SIGPIPE interrupt --- call this when done writing to a
2837  * temporary query output file that was (or might have been) a pipe.
2838  *
2839  * Note: within psql, we enable SIGPIPE interrupts unless the permanent query
2840  * output file is a pipe, in which case they should be kept off.  This
2841  * approach works only because psql is not currently complicated enough to
2842  * have nested usages of short-lived output files.  Otherwise we'd probably
2843  * need a genuine save-and-restore-state approach; but for now, that would be
2844  * useless complication.  In non-psql programs, this always enables SIGPIPE.
2845  *
2846  * No-op on Windows, where there's no SIGPIPE interrupts.
2847  */
2848 void
restore_sigpipe_trap(void)2849 restore_sigpipe_trap(void)
2850 {
2851 #ifndef WIN32
2852 	pqsignal(SIGPIPE, always_ignore_sigpipe ? SIG_IGN : SIG_DFL);
2853 #endif
2854 }
2855 
2856 /*
2857  * set_sigpipe_trap_state
2858  *
2859  * Set the trap state that restore_sigpipe_trap should restore to.
2860  */
2861 void
set_sigpipe_trap_state(bool ignore)2862 set_sigpipe_trap_state(bool ignore)
2863 {
2864 	always_ignore_sigpipe = ignore;
2865 }
2866 
2867 
2868 /*
2869  * PageOutput
2870  *
2871  * Tests if pager is needed and returns appropriate FILE pointer.
2872  *
2873  * If the topt argument is NULL no pager is used.
2874  */
2875 FILE *
PageOutput(int lines,const printTableOpt * topt)2876 PageOutput(int lines, const printTableOpt *topt)
2877 {
2878 	/* check whether we need / can / are supposed to use pager */
2879 	if (topt && topt->pager && isatty(fileno(stdin)) && isatty(fileno(stdout)))
2880 	{
2881 #ifdef TIOCGWINSZ
2882 		unsigned short int pager = topt->pager;
2883 		int			min_lines = topt->pager_min_lines;
2884 		int			result;
2885 		struct winsize screen_size;
2886 
2887 		result = ioctl(fileno(stdout), TIOCGWINSZ, &screen_size);
2888 
2889 		/* >= accounts for a one-line prompt */
2890 		if (result == -1
2891 			|| (lines >= screen_size.ws_row && lines >= min_lines)
2892 			|| pager > 1)
2893 #endif
2894 		{
2895 			const char *pagerprog;
2896 			FILE	   *pagerpipe;
2897 
2898 			pagerprog = getenv("PAGER");
2899 			if (!pagerprog)
2900 				pagerprog = DEFAULT_PAGER;
2901 			else
2902 			{
2903 				/* if PAGER is empty or all-white-space, don't use pager */
2904 				if (strspn(pagerprog, " \t\r\n") == strlen(pagerprog))
2905 					return stdout;
2906 			}
2907 			disable_sigpipe_trap();
2908 			pagerpipe = popen(pagerprog, "w");
2909 			if (pagerpipe)
2910 				return pagerpipe;
2911 			/* if popen fails, silently proceed without pager */
2912 			restore_sigpipe_trap();
2913 		}
2914 	}
2915 
2916 	return stdout;
2917 }
2918 
2919 /*
2920  * ClosePager
2921  *
2922  * Close previously opened pager pipe, if any
2923  */
2924 void
ClosePager(FILE * pagerpipe)2925 ClosePager(FILE *pagerpipe)
2926 {
2927 	if (pagerpipe && pagerpipe != stdout)
2928 	{
2929 		/*
2930 		 * If printing was canceled midstream, warn about it.
2931 		 *
2932 		 * Some pagers like less use Ctrl-C as part of their command set. Even
2933 		 * so, we abort our processing and warn the user what we did.  If the
2934 		 * pager quit as a result of the SIGINT, this message won't go
2935 		 * anywhere ...
2936 		 */
2937 		if (cancel_pressed)
2938 			fprintf(pagerpipe, _("Interrupted\n"));
2939 
2940 		pclose(pagerpipe);
2941 		restore_sigpipe_trap();
2942 	}
2943 }
2944 
2945 /*
2946  * Initialise a table contents struct.
2947  *		Must be called before any other printTable method is used.
2948  *
2949  * The title is not duplicated; the caller must ensure that the buffer
2950  * is available for the lifetime of the printTableContent struct.
2951  *
2952  * If you call this, you must call printTableCleanup once you're done with the
2953  * table.
2954  */
2955 void
printTableInit(printTableContent * const content,const printTableOpt * opt,const char * title,const int ncolumns,const int nrows)2956 printTableInit(printTableContent *const content, const printTableOpt *opt,
2957 			   const char *title, const int ncolumns, const int nrows)
2958 {
2959 	content->opt = opt;
2960 	content->title = title;
2961 	content->ncolumns = ncolumns;
2962 	content->nrows = nrows;
2963 
2964 	content->headers = pg_malloc0((ncolumns + 1) * sizeof(*content->headers));
2965 
2966 	content->cells = pg_malloc0((ncolumns * nrows + 1) * sizeof(*content->cells));
2967 
2968 	content->cellmustfree = NULL;
2969 	content->footers = NULL;
2970 
2971 	content->aligns = pg_malloc0((ncolumns + 1) * sizeof(*content->align));
2972 
2973 	content->header = content->headers;
2974 	content->cell = content->cells;
2975 	content->footer = content->footers;
2976 	content->align = content->aligns;
2977 	content->cellsadded = 0;
2978 }
2979 
2980 /*
2981  * Add a header to the table.
2982  *
2983  * Headers are not duplicated; you must ensure that the header string is
2984  * available for the lifetime of the printTableContent struct.
2985  *
2986  * If translate is true, the function will pass the header through gettext.
2987  * Otherwise, the header will not be translated.
2988  *
2989  * align is either 'l' or 'r', and specifies the alignment for cells in this
2990  * column.
2991  */
2992 void
printTableAddHeader(printTableContent * const content,char * header,const bool translate,const char align)2993 printTableAddHeader(printTableContent *const content, char *header,
2994 					const bool translate, const char align)
2995 {
2996 #ifndef ENABLE_NLS
2997 	(void) translate;			/* unused parameter */
2998 #endif
2999 
3000 	if (content->header >= content->headers + content->ncolumns)
3001 	{
3002 		fprintf(stderr, _("Cannot add header to table content: "
3003 						  "column count of %d exceeded.\n"),
3004 				content->ncolumns);
3005 		exit(EXIT_FAILURE);
3006 	}
3007 
3008 	*content->header = (char *) mbvalidate((unsigned char *) header,
3009 										   content->opt->encoding);
3010 #ifdef ENABLE_NLS
3011 	if (translate)
3012 		*content->header = _(*content->header);
3013 #endif
3014 	content->header++;
3015 
3016 	*content->align = align;
3017 	content->align++;
3018 }
3019 
3020 /*
3021  * Add a cell to the table.
3022  *
3023  * Cells are not duplicated; you must ensure that the cell string is available
3024  * for the lifetime of the printTableContent struct.
3025  *
3026  * If translate is true, the function will pass the cell through gettext.
3027  * Otherwise, the cell will not be translated.
3028  *
3029  * If mustfree is true, the cell string is freed by printTableCleanup().
3030  * Note: Automatic freeing of translatable strings is not supported.
3031  */
3032 void
printTableAddCell(printTableContent * const content,char * cell,const bool translate,const bool mustfree)3033 printTableAddCell(printTableContent *const content, char *cell,
3034 				  const bool translate, const bool mustfree)
3035 {
3036 #ifndef ENABLE_NLS
3037 	(void) translate;			/* unused parameter */
3038 #endif
3039 
3040 	if (content->cellsadded >= content->ncolumns * content->nrows)
3041 	{
3042 		fprintf(stderr, _("Cannot add cell to table content: "
3043 						  "total cell count of %d exceeded.\n"),
3044 				content->ncolumns * content->nrows);
3045 		exit(EXIT_FAILURE);
3046 	}
3047 
3048 	*content->cell = (char *) mbvalidate((unsigned char *) cell,
3049 										 content->opt->encoding);
3050 
3051 #ifdef ENABLE_NLS
3052 	if (translate)
3053 		*content->cell = _(*content->cell);
3054 #endif
3055 
3056 	if (mustfree)
3057 	{
3058 		if (content->cellmustfree == NULL)
3059 			content->cellmustfree =
3060 				pg_malloc0((content->ncolumns * content->nrows + 1) * sizeof(bool));
3061 
3062 		content->cellmustfree[content->cellsadded] = true;
3063 	}
3064 	content->cell++;
3065 	content->cellsadded++;
3066 }
3067 
3068 /*
3069  * Add a footer to the table.
3070  *
3071  * Footers are added as elements of a singly-linked list, and the content is
3072  * strdup'd, so there is no need to keep the original footer string around.
3073  *
3074  * Footers are never translated by the function.  If you want the footer
3075  * translated you must do so yourself, before calling printTableAddFooter.  The
3076  * reason this works differently to headers and cells is that footers tend to
3077  * be made of up individually translated components, rather than being
3078  * translated as a whole.
3079  */
3080 void
printTableAddFooter(printTableContent * const content,const char * footer)3081 printTableAddFooter(printTableContent *const content, const char *footer)
3082 {
3083 	printTableFooter *f;
3084 
3085 	f = pg_malloc0(sizeof(*f));
3086 	f->data = pg_strdup(footer);
3087 
3088 	if (content->footers == NULL)
3089 		content->footers = f;
3090 	else
3091 		content->footer->next = f;
3092 
3093 	content->footer = f;
3094 }
3095 
3096 /*
3097  * Change the content of the last-added footer.
3098  *
3099  * The current contents of the last-added footer are freed, and replaced by the
3100  * content given in *footer.  If there was no previous footer, add a new one.
3101  *
3102  * The content is strdup'd, so there is no need to keep the original string
3103  * around.
3104  */
3105 void
printTableSetFooter(printTableContent * const content,const char * footer)3106 printTableSetFooter(printTableContent *const content, const char *footer)
3107 {
3108 	if (content->footers != NULL)
3109 	{
3110 		free(content->footer->data);
3111 		content->footer->data = pg_strdup(footer);
3112 	}
3113 	else
3114 		printTableAddFooter(content, footer);
3115 }
3116 
3117 /*
3118  * Free all memory allocated to this struct.
3119  *
3120  * Once this has been called, the struct is unusable unless you pass it to
3121  * printTableInit() again.
3122  */
3123 void
printTableCleanup(printTableContent * const content)3124 printTableCleanup(printTableContent *const content)
3125 {
3126 	if (content->cellmustfree)
3127 	{
3128 		int			i;
3129 
3130 		for (i = 0; i < content->nrows * content->ncolumns; i++)
3131 		{
3132 			if (content->cellmustfree[i])
3133 				free((char *) content->cells[i]);
3134 		}
3135 		free(content->cellmustfree);
3136 		content->cellmustfree = NULL;
3137 	}
3138 	free(content->headers);
3139 	free(content->cells);
3140 	free(content->aligns);
3141 
3142 	content->opt = NULL;
3143 	content->title = NULL;
3144 	content->headers = NULL;
3145 	content->cells = NULL;
3146 	content->aligns = NULL;
3147 	content->header = NULL;
3148 	content->cell = NULL;
3149 	content->align = NULL;
3150 
3151 	if (content->footers)
3152 	{
3153 		for (content->footer = content->footers; content->footer;)
3154 		{
3155 			printTableFooter *f;
3156 
3157 			f = content->footer;
3158 			content->footer = f->next;
3159 			free(f->data);
3160 			free(f);
3161 		}
3162 	}
3163 	content->footers = NULL;
3164 	content->footer = NULL;
3165 }
3166 
3167 /*
3168  * IsPagerNeeded
3169  *
3170  * Setup pager if required
3171  */
3172 static void
IsPagerNeeded(const printTableContent * cont,int extra_lines,bool expanded,FILE ** fout,bool * is_pager)3173 IsPagerNeeded(const printTableContent *cont, int extra_lines, bool expanded,
3174 			  FILE **fout, bool *is_pager)
3175 {
3176 	if (*fout == stdout)
3177 	{
3178 		int			lines;
3179 
3180 		if (expanded)
3181 			lines = (cont->ncolumns + 1) * cont->nrows;
3182 		else
3183 			lines = cont->nrows + 1;
3184 
3185 		if (!cont->opt->tuples_only)
3186 		{
3187 			printTableFooter *f;
3188 
3189 			/*
3190 			 * FIXME -- this is slightly bogus: it counts the number of
3191 			 * footers, not the number of lines in them.
3192 			 */
3193 			for (f = cont->footers; f; f = f->next)
3194 				lines++;
3195 		}
3196 
3197 		*fout = PageOutput(lines + extra_lines, cont->opt);
3198 		*is_pager = (*fout != stdout);
3199 	}
3200 	else
3201 		*is_pager = false;
3202 }
3203 
3204 /*
3205  * Use this to print any table in the supported formats.
3206  *
3207  * cont: table data and formatting options
3208  * fout: where to print to
3209  * is_pager: true if caller has already redirected fout to be a pager pipe
3210  * flog: if not null, also print the table there (for --log-file option)
3211  */
3212 void
printTable(const printTableContent * cont,FILE * fout,bool is_pager,FILE * flog)3213 printTable(const printTableContent *cont,
3214 		   FILE *fout, bool is_pager, FILE *flog)
3215 {
3216 	bool		is_local_pager = false;
3217 
3218 	if (cancel_pressed)
3219 		return;
3220 
3221 	if (cont->opt->format == PRINT_NOTHING)
3222 		return;
3223 
3224 	/* print_aligned_*() handle the pager themselves */
3225 	if (!is_pager &&
3226 		cont->opt->format != PRINT_ALIGNED &&
3227 		cont->opt->format != PRINT_WRAPPED)
3228 	{
3229 		IsPagerNeeded(cont, 0, (cont->opt->expanded == 1), &fout, &is_pager);
3230 		is_local_pager = is_pager;
3231 	}
3232 
3233 	/* print the stuff */
3234 
3235 	if (flog)
3236 		print_aligned_text(cont, flog, false);
3237 
3238 	switch (cont->opt->format)
3239 	{
3240 		case PRINT_UNALIGNED:
3241 			if (cont->opt->expanded == 1)
3242 				print_unaligned_vertical(cont, fout);
3243 			else
3244 				print_unaligned_text(cont, fout);
3245 			break;
3246 		case PRINT_ALIGNED:
3247 		case PRINT_WRAPPED:
3248 
3249 			/*
3250 			 * In expanded-auto mode, force vertical if a pager is passed in;
3251 			 * else we may make different decisions for different hunks of the
3252 			 * query result.
3253 			 */
3254 			if (cont->opt->expanded == 1 ||
3255 				(cont->opt->expanded == 2 && is_pager))
3256 				print_aligned_vertical(cont, fout, is_pager);
3257 			else
3258 				print_aligned_text(cont, fout, is_pager);
3259 			break;
3260 		case PRINT_HTML:
3261 			if (cont->opt->expanded == 1)
3262 				print_html_vertical(cont, fout);
3263 			else
3264 				print_html_text(cont, fout);
3265 			break;
3266 		case PRINT_ASCIIDOC:
3267 			if (cont->opt->expanded == 1)
3268 				print_asciidoc_vertical(cont, fout);
3269 			else
3270 				print_asciidoc_text(cont, fout);
3271 			break;
3272 		case PRINT_LATEX:
3273 			if (cont->opt->expanded == 1)
3274 				print_latex_vertical(cont, fout);
3275 			else
3276 				print_latex_text(cont, fout);
3277 			break;
3278 		case PRINT_LATEX_LONGTABLE:
3279 			if (cont->opt->expanded == 1)
3280 				print_latex_vertical(cont, fout);
3281 			else
3282 				print_latex_longtable_text(cont, fout);
3283 			break;
3284 		case PRINT_TROFF_MS:
3285 			if (cont->opt->expanded == 1)
3286 				print_troff_ms_vertical(cont, fout);
3287 			else
3288 				print_troff_ms_text(cont, fout);
3289 			break;
3290 		default:
3291 			fprintf(stderr, _("invalid output format (internal error): %d"),
3292 					cont->opt->format);
3293 			exit(EXIT_FAILURE);
3294 	}
3295 
3296 	if (is_local_pager)
3297 		ClosePager(fout);
3298 }
3299 
3300 /*
3301  * Use this to print query results
3302  *
3303  * result: result of a successful query
3304  * opt: formatting options
3305  * fout: where to print to
3306  * is_pager: true if caller has already redirected fout to be a pager pipe
3307  * flog: if not null, also print the data there (for --log-file option)
3308  */
3309 void
printQuery(const PGresult * result,const printQueryOpt * opt,FILE * fout,bool is_pager,FILE * flog)3310 printQuery(const PGresult *result, const printQueryOpt *opt,
3311 		   FILE *fout, bool is_pager, FILE *flog)
3312 {
3313 	printTableContent cont;
3314 	int			i,
3315 				r,
3316 				c;
3317 
3318 	if (cancel_pressed)
3319 		return;
3320 
3321 	printTableInit(&cont, &opt->topt, opt->title,
3322 				   PQnfields(result), PQntuples(result));
3323 
3324 	/* Assert caller supplied enough translate_columns[] entries */
3325 	Assert(opt->translate_columns == NULL ||
3326 		   opt->n_translate_columns >= cont.ncolumns);
3327 
3328 	for (i = 0; i < cont.ncolumns; i++)
3329 	{
3330 		printTableAddHeader(&cont, PQfname(result, i),
3331 							opt->translate_header,
3332 							column_type_alignment(PQftype(result, i)));
3333 	}
3334 
3335 	/* set cells */
3336 	for (r = 0; r < cont.nrows; r++)
3337 	{
3338 		for (c = 0; c < cont.ncolumns; c++)
3339 		{
3340 			char	   *cell;
3341 			bool		mustfree = false;
3342 			bool		translate;
3343 
3344 			if (PQgetisnull(result, r, c))
3345 				cell = opt->nullPrint ? opt->nullPrint : "";
3346 			else
3347 			{
3348 				cell = PQgetvalue(result, r, c);
3349 				if (cont.aligns[c] == 'r' && opt->topt.numericLocale)
3350 				{
3351 					cell = format_numeric_locale(cell);
3352 					mustfree = true;
3353 				}
3354 			}
3355 
3356 			translate = (opt->translate_columns && opt->translate_columns[c]);
3357 			printTableAddCell(&cont, cell, translate, mustfree);
3358 		}
3359 	}
3360 
3361 	/* set footers */
3362 	if (opt->footers)
3363 	{
3364 		char	  **footer;
3365 
3366 		for (footer = opt->footers; *footer; footer++)
3367 			printTableAddFooter(&cont, *footer);
3368 	}
3369 
3370 	printTable(&cont, fout, is_pager, flog);
3371 	printTableCleanup(&cont);
3372 }
3373 
3374 char
column_type_alignment(Oid ftype)3375 column_type_alignment(Oid ftype)
3376 {
3377 	char		align;
3378 
3379 	switch (ftype)
3380 	{
3381 		case INT2OID:
3382 		case INT4OID:
3383 		case INT8OID:
3384 		case FLOAT4OID:
3385 		case FLOAT8OID:
3386 		case NUMERICOID:
3387 		case OIDOID:
3388 		case XIDOID:
3389 		case CIDOID:
3390 		case CASHOID:
3391 			align = 'r';
3392 			break;
3393 		default:
3394 			align = 'l';
3395 			break;
3396 	}
3397 	return align;
3398 }
3399 
3400 void
setDecimalLocale(void)3401 setDecimalLocale(void)
3402 {
3403 	struct lconv *extlconv;
3404 
3405 	extlconv = localeconv();
3406 
3407 	/* Don't accept an empty decimal_point string */
3408 	if (*extlconv->decimal_point)
3409 		decimal_point = pg_strdup(extlconv->decimal_point);
3410 	else
3411 		decimal_point = ".";	/* SQL output standard */
3412 
3413 	/*
3414 	 * Although the Open Group standard allows locales to supply more than one
3415 	 * group width, we consider only the first one, and we ignore any attempt
3416 	 * to suppress grouping by specifying CHAR_MAX.  As in the backend's
3417 	 * cash.c, we must apply a range check to avoid being fooled by variant
3418 	 * CHAR_MAX values.
3419 	 */
3420 	groupdigits = *extlconv->grouping;
3421 	if (groupdigits <= 0 || groupdigits > 6)
3422 		groupdigits = 3;		/* most common */
3423 
3424 	/* Don't accept an empty thousands_sep string, either */
3425 	/* similar code exists in formatting.c */
3426 	if (*extlconv->thousands_sep)
3427 		thousands_sep = pg_strdup(extlconv->thousands_sep);
3428 	/* Make sure thousands separator doesn't match decimal point symbol. */
3429 	else if (strcmp(decimal_point, ",") != 0)
3430 		thousands_sep = ",";
3431 	else
3432 		thousands_sep = ".";
3433 }
3434 
3435 /* get selected or default line style */
3436 const printTextFormat *
get_line_style(const printTableOpt * opt)3437 get_line_style(const printTableOpt *opt)
3438 {
3439 	/*
3440 	 * Note: this function mainly exists to preserve the convention that a
3441 	 * printTableOpt struct can be initialized to zeroes to get default
3442 	 * behavior.
3443 	 */
3444 	if (opt->line_style != NULL)
3445 		return opt->line_style;
3446 	else
3447 		return &pg_asciiformat;
3448 }
3449 
3450 void
refresh_utf8format(const printTableOpt * opt)3451 refresh_utf8format(const printTableOpt *opt)
3452 {
3453 	printTextFormat *popt = &pg_utf8format;
3454 
3455 	const unicodeStyleBorderFormat *border;
3456 	const unicodeStyleRowFormat *header;
3457 	const unicodeStyleColumnFormat *column;
3458 
3459 	popt->name = "unicode";
3460 
3461 	border = &unicode_style.border_style[opt->unicode_border_linestyle];
3462 	header = &unicode_style.row_style[opt->unicode_header_linestyle];
3463 	column = &unicode_style.column_style[opt->unicode_column_linestyle];
3464 
3465 	popt->lrule[PRINT_RULE_TOP].hrule = border->horizontal;
3466 	popt->lrule[PRINT_RULE_TOP].leftvrule = border->down_and_right;
3467 	popt->lrule[PRINT_RULE_TOP].midvrule = column->down_and_horizontal[opt->unicode_border_linestyle];
3468 	popt->lrule[PRINT_RULE_TOP].rightvrule = border->down_and_left;
3469 
3470 	popt->lrule[PRINT_RULE_MIDDLE].hrule = header->horizontal;
3471 	popt->lrule[PRINT_RULE_MIDDLE].leftvrule = header->vertical_and_right[opt->unicode_border_linestyle];
3472 	popt->lrule[PRINT_RULE_MIDDLE].midvrule = column->vertical_and_horizontal[opt->unicode_header_linestyle];
3473 	popt->lrule[PRINT_RULE_MIDDLE].rightvrule = header->vertical_and_left[opt->unicode_border_linestyle];
3474 
3475 	popt->lrule[PRINT_RULE_BOTTOM].hrule = border->horizontal;
3476 	popt->lrule[PRINT_RULE_BOTTOM].leftvrule = border->up_and_right;
3477 	popt->lrule[PRINT_RULE_BOTTOM].midvrule = column->up_and_horizontal[opt->unicode_border_linestyle];
3478 	popt->lrule[PRINT_RULE_BOTTOM].rightvrule = border->left_and_right;
3479 
3480 	/* N/A */
3481 	popt->lrule[PRINT_RULE_DATA].hrule = "";
3482 	popt->lrule[PRINT_RULE_DATA].leftvrule = border->vertical;
3483 	popt->lrule[PRINT_RULE_DATA].midvrule = column->vertical;
3484 	popt->lrule[PRINT_RULE_DATA].rightvrule = border->vertical;
3485 
3486 	popt->midvrule_nl = column->vertical;
3487 	popt->midvrule_wrap = column->vertical;
3488 	popt->midvrule_blank = column->vertical;
3489 
3490 	/* Same for all unicode today */
3491 	popt->header_nl_left = unicode_style.header_nl_left;
3492 	popt->header_nl_right = unicode_style.header_nl_right;
3493 	popt->nl_left = unicode_style.nl_left;
3494 	popt->nl_right = unicode_style.nl_right;
3495 	popt->wrap_left = unicode_style.wrap_left;
3496 	popt->wrap_right = unicode_style.wrap_right;
3497 	popt->wrap_right_border = unicode_style.wrap_right_border;
3498 
3499 	return;
3500 }
3501 
3502 /*
3503  * Compute the byte distance to the end of the string or *target_width
3504  * display character positions, whichever comes first.  Update *target_width
3505  * to be the number of display character positions actually filled.
3506  */
3507 static int
strlen_max_width(unsigned char * str,int * target_width,int encoding)3508 strlen_max_width(unsigned char *str, int *target_width, int encoding)
3509 {
3510 	unsigned char *start = str;
3511 	unsigned char *end = str + strlen((char *) str);
3512 	int			curr_width = 0;
3513 
3514 	while (str < end)
3515 	{
3516 		int			char_width = PQdsplen((char *) str, encoding);
3517 
3518 		/*
3519 		 * If the display width of the new character causes the string to
3520 		 * exceed its target width, skip it and return.  However, if this is
3521 		 * the first character of the string (curr_width == 0), we have to
3522 		 * accept it.
3523 		 */
3524 		if (*target_width < curr_width + char_width && curr_width != 0)
3525 			break;
3526 
3527 		curr_width += char_width;
3528 
3529 		str += PQmblen((char *) str, encoding);
3530 
3531 		if (str > end)			/* Don't overrun invalid string */
3532 			str = end;
3533 	}
3534 
3535 	*target_width = curr_width;
3536 
3537 	return str - start;
3538 }
3539