On Thu, Aug 27, 2009 at 10:17:32AM -0400, Alvaro Herrera wrote:
> Alvaro Herrera escribió:
> 
> > > I initially left these exactly the same as for ASCII (the ':' and ';'
> > > usage).  However, it's quite possible to make it use other characters.
> > > We could use the same lines, or two, three or four dashed lines
> > > ('╎' and '╏', or ┆' and '┇' or '┊' and '┋').
> > 
> > This works for me (say ╎ for newline-separated strings and ┊ for wrapped
> > output).
> 
> So it'd look like this:
> 
> alvherre=# select * from foo;
>  a │                                     b                                    
>   
> ━━━┿━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
>  1 │ En un lugar de la Mancha, de cuyo nombre no quiero acordarme, no ha 
> mucho 
>    ┊ tiempo que vivía un hidalgo de los de lanza en astillero, adarga 
> antigua, 
>    ┊ rocín flaco y galgo corredor. Una olla de algo más vaca que carnero, 
> salpi
>    ┊ cón las más noches, duelos y quebrantos los sábados, lantejas los 
> viernes,
>    ┊  algún palomino de añadidura los domingos, consumían las tres partes de 
> su
>    ┊  hacienda. El resto della concluían sayo de velarte, calzas de velludo 
> par
>    ┊ a las fiestas, con sus pantuflos de lo mesmo, y los días de entresemana 
> se
>    ┊  honraba con su vellorí de lo más fino.  Tenía en su casa una ama que 
> pasa
>    ┊ ba de los cuarenta, y una sobrina que no llegaba a los veinte, y un mozo 
> d
>    ┊ e campo y plaza, que así ensillaba el rocín como tomaba la podadera.
>  2 │ —«Nunca fuera caballero de
>    ╎ damas tan bien servido
>    ╎ como fuera don Quijote
>    ╎ cuando de su aldea vino:
>    ╎ doncellas curaban dél;
>    ╎ princesas, del su rocino»
> (2 filas)

The attached patch adds support for the above output in wrapped mode.
It also uses single dashes (half lines) to represent lines which
contain no data, just vertical padding.  Output is unchanged for
ASCII output.

The last bit I'm missing is how to handle column wrapping for aligned
text output.  This is was introduced on 8th May 2008 by Bryce Nesbitt,
committed by Bruce Momjian (git commit f92f424d).  This patch
introduced the wrapped format, but I have not been able to activate
the codepaths that wrap column names in the table header (adding '+').

The logic in print_aligned_text goes like this:

col_count = cont->ncolumns;
...
more_col_wrapping = col_count;
curr_nl_line = 0;
while (more_col_wrapping)
{
  for (i = 0; i < cont->ncolumns; i++)
    if (!(this_line + 1)->ptr)   // Surely only true once at end of columns?
      more_col_wrapping--;
  curr_nl_line++;
}

I'm not convinced looking at the code that more_col_wrapping is ever
true except for the first time through the loop, and it's reached
zero after completion of the inner loop, so all of the code used when
curr_nl_line is > 0 is never called.  I'm sure I'm interpreting this
incorrectly, but I can't see under what circumstances I would get the
column name header line wrapped over multiple lines.

It may be that I just haven't got a table with column names of the
correct number and lengths to trigger it?


Regards,
Roger

-- 
  .''`.  Roger Leigh
 : :' :  Debian GNU/Linux             http://people.debian.org/~rleigh/
 `. `'   Printing on GNU/Linux?       http://gutenprint.sourceforge.net/
   `-    GPG Public Key: 0x25BFB848   Please GPG sign your mail.
diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c
index 7505cd4..f85e507 100644
--- a/src/bin/psql/print.c
+++ b/src/bin/psql/print.c
@@ -21,6 +21,9 @@
 #endif
 
 #include <locale.h>
+#ifdef HAVE_LANGINFO_H
+#include <langinfo.h>
+#endif
 
 #include "catalog/pg_type.h"
 #include "pqsignal.h"
@@ -356,38 +359,75 @@ print_unaligned_vertical(const printTableContent *cont, FILE *fout)
 /* Aligned text		*/
 /********************/
 
+static const printTextFormat asciiformat =
+{
+	{
+		{ "-", "+", "+", "+" },
+		{ "-", "+", "+", "+" },
+		{ "-", "+", "+", "+" },
+		{ "",  "|", "|", "|" }
+	},
+	":",
+	";",
+	" "
+};
+
+static const struct printTextFormat utf8format =
+{
+	{
+	  /* ─, ┌, ┬, ┐ */
+	  { "\342\224\200", "\342\224\214", "\342\224\254", "\342\224\220" },
+	  /* ━, ┝, ┿, ┥ */
+	  { "\342\224\201", "\342\224\235", "\342\224\277", "\342\224\245" },
+	  /* ─, └, ┴, ┘ */
+	  { "\342\224\200", "\342\224\224", "\342\224\264", "\342\224\230" },
+	  /* N/A, │, │, │ */
+	  { "", "\342\224\202", "\342\224\202", "\342\224\202" },
+	},
+	  /* ╎ */
+	  "\342\225\216",
+	  /* ┊ */
+	  "\342\224\212",
+	  /* ╷ */
+	  "\342\225\267"
+};
 
 /* draw "line" */
 static void
 _print_horizontal_line(const unsigned int ncolumns, const unsigned int *widths,
-					   unsigned short border, FILE *fout)
+		       unsigned short border, printTextRule pos,
+		       const printTextFormat *format,
+		       FILE *fout)
 {
 	unsigned int i,
 				j;
 
+	const printTextLineFormat *lformat = &format->lrule[pos];
+
 	if (border == 1)
-		fputc('-', fout);
+		fputs(lformat->hrule, fout);
 	else if (border == 2)
-		fputs("+-", fout);
+		fprintf(fout, "%s%s", lformat->leftvrule, lformat->hrule);
 
 	for (i = 0; i < ncolumns; i++)
 	{
 		for (j = 0; j < widths[i]; j++)
-			fputc('-', fout);
+			fputs(lformat->hrule, fout);
 
 		if (i < ncolumns - 1)
 		{
 			if (border == 0)
 				fputc(' ', fout);
 			else
-				fputs("-+-", fout);
+				fprintf(fout, "%s%s%s", lformat->hrule,
+					lformat->midvrule, lformat->hrule);
 		}
 	}
 
 	if (border == 2)
-		fputs("-+", fout);
+		fprintf(fout, "%s%s", lformat->hrule, lformat->rightvrule);
 	else if (border == 1)
-		fputc('-', fout);
+		fputs(lformat->hrule, fout);
 
 	fputc('\n', fout);
 }
@@ -397,7 +437,8 @@ _print_horizontal_line(const unsigned int ncolumns, const unsigned int *widths,
  *	Print pretty boxes around cells.
  */
 static void
-print_aligned_text(const printTableContent *cont, FILE *fout)
+print_aligned_text(const printTableContent *cont, const printTextFormat *format,
+		   FILE *fout)
 {
 	bool		opt_tuples_only = cont->opt->tuples_only;
 	bool		opt_numeric_locale = cont->opt->numericLocale;
@@ -431,6 +472,7 @@ print_aligned_text(const printTableContent *cont, FILE *fout)
 	int		   *bytes_output;	/* Bytes output for column value */
 	int			output_columns = 0;		/* Width of interactive console */
 	bool		is_pager = false;
+	const printTextLineFormat	*dformat = &format->lrule[PRINT_RULE_DATA];
 
 	if (cancel_pressed)
 		return;
@@ -709,7 +751,7 @@ print_aligned_text(const printTableContent *cont, FILE *fout)
 			int			curr_nl_line;
 
 			if (opt_border == 2)
-				_print_horizontal_line(col_count, width_wrap, opt_border, fout);
+				_print_horizontal_line(col_count, width_wrap, opt_border, PRINT_RULE_TOP, format, fout);
 
 			for (i = 0; i < col_count; i++)
 				pg_wcsformat((unsigned char *) cont->headers[i],
@@ -722,7 +764,7 @@ print_aligned_text(const printTableContent *cont, FILE *fout)
 			while (more_col_wrapping)
 			{
 				if (opt_border == 2)
-					fprintf(fout, "|%c", curr_nl_line ? '+' : ' ');
+					fprintf(fout, "%s%c", dformat->leftvrule, curr_nl_line ? '+' : ' ');
 				else if (opt_border == 1)
 					fputc(curr_nl_line ? '+' : ' ', fout);
 
@@ -753,19 +795,20 @@ print_aligned_text(const printTableContent *cont, FILE *fout)
 						if (opt_border == 0)
 							fputc(curr_nl_line ? '+' : ' ', fout);
 						else
-							fprintf(fout, " |%c", curr_nl_line ? '+' : ' ');
+							fprintf(fout, " %s%c", dformat->midvrule, curr_nl_line ? '+' : ' ');
 					}
 				}
 				curr_nl_line++;
 
 				if (opt_border == 2)
-					fputs(" |", fout);
+					fprintf(fout, " %s",
+						dformat->rightvrule);
 				else if (opt_border == 1)
 					fputc(' ', fout);
 				fputc('\n', fout);
 			}
 
-			_print_horizontal_line(col_count, width_wrap, opt_border, fout);
+			_print_horizontal_line(col_count, width_wrap, opt_border, PRINT_RULE_MIDDLE, format, fout);
 		}
 	}
 
@@ -811,7 +854,7 @@ print_aligned_text(const printTableContent *cont, FILE *fout)
 
 			/* left border */
 			if (opt_border == 2)
-				fputs("| ", fout);
+				fprintf(fout, "%s ", dformat->leftvrule);
 			else if (opt_border == 1)
 				fputc(' ', fout);
 
@@ -884,22 +927,26 @@ print_aligned_text(const printTableContent *cont, FILE *fout)
 						fputc(' ', fout);
 					/* Next value is beyond past newlines? */
 					else if (col_lineptrs[j + 1][curr_nl_line[j + 1]].ptr == NULL)
-						fputs("   ", fout);
+						fprintf(fout, " %s ",
+							format->midvrule_blank);
 					/* In wrapping of value? */
 					else if (bytes_output[j + 1] != 0)
-						fputs(" ; ", fout);
+						fprintf(fout, " %s ",
+							format->midvrule_wrap);
 					/* After first newline value */
 					else if (curr_nl_line[j + 1] != 0)
-						fputs(" : ", fout);
+						fprintf(fout, " %s ",
+							format->midvrule_cont);
+					/* Ordinary line */
 					else
-						/* Ordinary line */
-						fputs(" | ", fout);
+						fprintf(fout, " %s ",
+							dformat->midvrule);
 				}
 			}
 
 			/* end-of-row border */
 			if (opt_border == 2)
-				fputs(" |", fout);
+				fprintf(fout, " %s", dformat->rightvrule);
 			fputc('\n', fout);
 
 		} while (more_lines);
@@ -908,7 +955,7 @@ print_aligned_text(const printTableContent *cont, FILE *fout)
 	if (cont->opt->stop_table)
 	{
 		if (opt_border == 2 && !cancel_pressed)
-			_print_horizontal_line(col_count, width_wrap, opt_border, fout);
+			_print_horizontal_line(col_count, width_wrap, opt_border, PRINT_RULE_BOTTOM, format, fout);
 
 		/* print footers */
 		if (cont->footers && !opt_tuples_only && !cancel_pressed)
@@ -941,9 +988,67 @@ print_aligned_text(const printTableContent *cont, FILE *fout)
 		ClosePager(fout);
 }
 
+static inline void
+print_aligned_vertical_line(const printTableContent *cont,
+			    unsigned long record,
+			    unsigned int hwidth,
+			    unsigned int dwidth,
+			    printTextRule pos,
+			    const printTextFormat *format,
+			    FILE *fout)
+{
+	unsigned short	opt_border = cont->opt->border;
+	unsigned int	i;
+	int		reclen = 0;
+	const printTextLineFormat	*lformat = &format->lrule[pos];
+
+	if (opt_border == 2)
+		fprintf(fout, "%s%s", lformat->leftvrule, lformat->hrule);
+	else if (opt_border == 1)
+		fputs(lformat->hrule, fout);
+
+	if (record)
+	{
+		if (opt_border == 0)
+			reclen = fprintf(fout, "* Record %lu", record);
+		else
+			reclen = fprintf(fout, "[ RECORD %lu ]", record);
+	}
+	if (opt_border != 2)
+		reclen++;
+	if (reclen < 0)
+		reclen = 0;
+	for (i = reclen; i < hwidth; i++)
+		fputs(opt_border > 0 ? lformat->hrule : " ", fout);
+	reclen -= hwidth;
+
+	if (opt_border > 0)
+	{
+		if (reclen-- <= 0)
+			fputs(lformat->hrule, fout);
+		if (reclen-- <= 0)
+			fputs(lformat->midvrule, fout);
+		if (reclen-- <= 0)
+			fputs(lformat->hrule, fout);
+	}
+	else
+	{
+		if (reclen-- <= 0)
+			fputc(' ', fout);
+	}
+	if (reclen < 0)
+		reclen = 0;
+	for (i = reclen; i < dwidth; i++)
+		fputs(opt_border > 0 ? lformat->hrule : " ", fout);
+	if (opt_border == 2)
+		fprintf(fout, "%s%s", lformat->hrule, lformat->rightvrule);
+	fputc('\n', fout);
+}
 
 static void
-print_aligned_vertical(const printTableContent *cont, FILE *fout)
+print_aligned_vertical(const printTableContent *cont,
+		       const printTextFormat *format,
+		       FILE *fout)
 {
 	bool		opt_tuples_only = cont->opt->tuples_only;
 	bool		opt_numeric_locale = cont->opt->numericLocale;
@@ -958,9 +1063,9 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
 				dheight = 1,
 				hformatsize = 0,
 				dformatsize = 0;
-	char	   *divider;
 	struct lineptr *hlineptr,
 			   *dlineptr;
+	const printTextLineFormat	*dformat = &format->lrule[PRINT_RULE_DATA];
 
 	if (cancel_pressed)
 		return;
@@ -1026,21 +1131,6 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
 	dlineptr->ptr = pg_local_malloc(dformatsize);
 	hlineptr->ptr = pg_local_malloc(hformatsize);
 
-	/* make horizontal border */
-	divider = pg_local_malloc(hwidth + dwidth + 10);
-	divider[0] = '\0';
-	if (opt_border == 2)
-		strcat(divider, "+-");
-	for (i = 0; i < hwidth; i++)
-		strcat(divider, opt_border > 0 ? "-" : " ");
-	if (opt_border > 0)
-		strcat(divider, "-+-");
-	else
-		strcat(divider, " ");
-	for (i = 0; i < dwidth; i++)
-		strcat(divider, opt_border > 0 ? "-" : " ");
-	if (opt_border == 2)
-		strcat(divider, "-+");
 
 	if (cont->opt->start_table)
 	{
@@ -1052,40 +1142,25 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
 	/* print records */
 	for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
 	{
-		int			line_count,
-					dcomplete,
-					hcomplete;
+		int		line_count,
+	    			dcomplete,
+				hcomplete;
+		printTextRule	pos = PRINT_RULE_MIDDLE;
+		if (i == 0)
+	  		pos = PRINT_RULE_TOP;
+		else if (!(*(ptr+1)))
+			pos = PRINT_RULE_BOTTOM;
+
+		if (cancel_pressed)
+			break;
 
 		if (i % cont->ncolumns == 0)
 		{
-			if (cancel_pressed)
-				break;
-			if (!opt_tuples_only)
-			{
-				char		record_str[64];
-				size_t		record_str_len;
-
-				if (opt_border == 0)
-					snprintf(record_str, 64, "* Record %lu", record++);
-				else
-					snprintf(record_str, 64, "[ RECORD %lu ]", record++);
-				record_str_len = strlen(record_str);
-
-				if (record_str_len + opt_border > strlen(divider))
-					fprintf(fout, "%.*s%s\n", opt_border, divider, record_str);
-				else
-				{
-					char	   *div_copy = pg_strdup(divider);
-
-					strncpy(div_copy + opt_border, record_str, record_str_len);
-					fprintf(fout, "%s\n", div_copy);
-					free(div_copy);
-				}
-			}
+	    		if (!opt_tuples_only)
+				print_aligned_vertical_line(cont, record++, hwidth, dwidth, pos, format, fout);
 			else if (i != 0 || !cont->opt->start_table || opt_border == 2)
-				fprintf(fout, "%s\n", divider);
+				print_aligned_vertical_line(cont, 0, hwidth, dwidth, pos, format, fout);
 		}
-
 		/* Format the header */
 		pg_wcsformat((unsigned char *) cont->headers[i % cont->ncolumns],
 					 strlen(cont->headers[i % cont->ncolumns]),
@@ -1099,7 +1174,7 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
 		while (!dcomplete || !hcomplete)
 		{
 			if (opt_border == 2)
-				fputs("| ", fout);
+				fprintf(fout, "%s ", dformat->leftvrule);
 			if (!hcomplete)
 			{
 				fprintf(fout, "%-s%*s", hlineptr[line_count].ptr,
@@ -1112,9 +1187,13 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
 				fprintf(fout, "%*s", hwidth, "");
 
 			if (opt_border > 0)
-				fprintf(fout, " %c ", (line_count == 0) ? '|' : ':');
+			{
+				fprintf(fout, " %s ",
+					(line_count == 0) ?
+					format->midvrule_cont : dformat->midvrule);
+			}
 			else
-				fputs(" ", fout);
+				fputc(' ', fout);
 
 			if (!dcomplete)
 			{
@@ -1125,8 +1204,8 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
 					if (opt_border < 2)
 						fprintf(fout, "%s\n", my_cell);
 					else
-						fprintf(fout, "%-s%*s |\n", my_cell,
-								(int) (dwidth - strlen(my_cell)), "");
+						fprintf(fout, "%-s%*s %s\n", my_cell,
+								(int) (dwidth - strlen(my_cell)), "", dformat->rightvrule);
 					free(my_cell);
 				}
 				else
@@ -1134,8 +1213,8 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
 					if (opt_border < 2)
 						fprintf(fout, "%s\n", dlineptr[line_count].ptr);
 					else
-						fprintf(fout, "%-s%*s |\n", dlineptr[line_count].ptr,
-								dwidth - dlineptr[line_count].width, "");
+						fprintf(fout, "%-s%*s %s\n", dlineptr[line_count].ptr,
+								dwidth - dlineptr[line_count].width, "", dformat->rightvrule);
 				}
 
 				if (!dlineptr[line_count + 1].ptr)
@@ -1146,7 +1225,7 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
 				if (opt_border < 2)
 					fputc('\n', fout);
 				else
-					fprintf(fout, "%*s |\n", dwidth, "");
+					fprintf(fout, "%*s %s\n", dwidth, "", dformat->rightvrule);
 			}
 			line_count++;
 		}
@@ -1155,7 +1234,7 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
 	if (cont->opt->stop_table)
 	{
 		if (opt_border == 2 && !cancel_pressed)
-			fprintf(fout, "%s\n", divider);
+			print_aligned_vertical_line(cont, 0, hwidth, dwidth, PRINT_RULE_BOTTOM, format, fout);
 
 		/* print footers */
 		if (!opt_tuples_only && cont->footers != NULL && !cancel_pressed)
@@ -1171,7 +1250,6 @@ print_aligned_vertical(const printTableContent *cont, FILE *fout)
 		fputc('\n', fout);
 	}
 
-	free(divider);
 	free(hlineptr->ptr);
 	free(dlineptr->ptr);
 	free(hlineptr);
@@ -2208,7 +2286,15 @@ IsPagerNeeded(const printTableContent *cont, const int extra_lines, FILE **fout,
 void
 printTable(const printTableContent *cont, FILE *fout, FILE *flog)
 {
-	bool		is_pager = false;
+	bool			is_pager = false;
+	const printTextFormat	*text_format = &asciiformat;
+
+#if (defined(HAVE_LANGINFO_H) && defined(CODESET))
+	if (pg_strcasecmp(nl_langinfo(CODESET), "UTF-8") == 0 ||
+	    pg_strcasecmp(nl_langinfo(CODESET), "utf8") == 0 ||
+	    pg_strcasecmp(nl_langinfo(CODESET), "CP65001") == 0)
+		text_format = &utf8format;
+#endif
 
 	if (cancel_pressed)
 		return;
@@ -2225,7 +2311,7 @@ printTable(const printTableContent *cont, FILE *fout, FILE *flog)
 	/* print the stuff */
 
 	if (flog)
-		print_aligned_text(cont, flog);
+		print_aligned_text(cont, text_format, flog);
 
 	switch (cont->opt->format)
 	{
@@ -2238,9 +2324,9 @@ printTable(const printTableContent *cont, FILE *fout, FILE *flog)
 		case PRINT_ALIGNED:
 		case PRINT_WRAPPED:
 			if (cont->opt->expanded)
-				print_aligned_vertical(cont, fout);
+				print_aligned_vertical(cont, text_format, fout);
 			else
-				print_aligned_text(cont, fout);
+				print_aligned_text(cont, text_format, fout);
 			break;
 		case PRINT_HTML:
 			if (cont->opt->expanded)
diff --git a/src/bin/psql/print.h b/src/bin/psql/print.h
index 55122d7..64d34f0 100644
--- a/src/bin/psql/print.h
+++ b/src/bin/psql/print.h
@@ -95,6 +95,30 @@ typedef struct printQueryOpt
 										 * gettext on col i */
 } printQueryOpt;
 
+typedef struct printTextLineFormat
+{
+	const char *hrule;
+	const char *leftvrule;
+	const char *midvrule;
+	const char *rightvrule;
+} printTextLineFormat;
+
+typedef struct printTextFormat
+{
+	printTextLineFormat	lrule[4];
+	const char		*midvrule_cont;
+	const char		*midvrule_wrap;
+	const char		*midvrule_blank;
+} printTextFormat;
+
+typedef enum printTextRule
+{
+	PRINT_RULE_TOP,
+	PRINT_RULE_MIDDLE,
+	PRINT_RULE_BOTTOM,
+	PRINT_RULE_DATA,
+} printTextRule;
+
 
 extern FILE *PageOutput(int lines, unsigned short int pager);
 extern void ClosePager(FILE *pagerpipe);

Attachment: signature.asc
Description: Digital signature

Reply via email to