aboutsummaryrefslogtreecommitdiff
path: root/src/fe_utils/print.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fe_utils/print.c')
-rw-r--r--src/fe_utils/print.c131
1 files changed, 128 insertions, 3 deletions
diff --git a/src/fe_utils/print.c b/src/fe_utils/print.c
index cb9a9a06131..6b78f0909cd 100644
--- a/src/fe_utils/print.c
+++ b/src/fe_utils/print.c
@@ -1737,7 +1737,119 @@ print_aligned_vertical(const printTableContent *cont,
/**********************/
-/* HTML printing ******/
+/* CSV format */
+/**********************/
+
+
+static void
+csv_escaped_print(const char *str, FILE *fout)
+{
+ const char *p;
+
+ fputc('"', fout);
+ for (p = str; *p; p++)
+ {
+ if (*p == '"')
+ fputc('"', fout); /* double quotes are doubled */
+ fputc(*p, fout);
+ }
+ fputc('"', fout);
+}
+
+static void
+csv_print_field(const char *str, FILE *fout, char sep)
+{
+ /*----------------
+ * Enclose and escape field contents when one of these conditions is met:
+ * - the field separator is found in the contents.
+ * - the field contains a CR or LF.
+ * - the field contains a double quote.
+ * - the field is exactly "\.".
+ * - the field separator is either "\" or ".".
+ * The last two cases prevent producing a line that the server's COPY
+ * command would interpret as an end-of-data marker. We only really
+ * need to ensure that the complete line isn't exactly "\.", but for
+ * simplicity we apply stronger restrictions here.
+ *----------------
+ */
+ if (strchr(str, sep) != NULL ||
+ strcspn(str, "\r\n\"") != strlen(str) ||
+ strcmp(str, "\\.") == 0 ||
+ sep == '\\' || sep == '.')
+ csv_escaped_print(str, fout);
+ else
+ fputs(str, fout);
+}
+
+static void
+print_csv_text(const printTableContent *cont, FILE *fout)
+{
+ const char *const *ptr;
+ int i;
+
+ if (cancel_pressed)
+ return;
+
+ /*
+ * The title and footer are never printed in csv format. The header is
+ * printed if opt_tuples_only is false.
+ *
+ * Despite RFC 4180 saying that end of lines are CRLF, terminate lines
+ * with '\n', which prints out as the system-dependent EOL string in text
+ * mode (typically LF on Unix and CRLF on Windows).
+ */
+ if (cont->opt->start_table && !cont->opt->tuples_only)
+ {
+ /* print headers */
+ for (ptr = cont->headers; *ptr; ptr++)
+ {
+ if (ptr != cont->headers)
+ fputc(cont->opt->csvFieldSep[0], fout);
+ csv_print_field(*ptr, fout, cont->opt->csvFieldSep[0]);
+ }
+ fputc('\n', fout);
+ }
+
+ /* print cells */
+ for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
+ {
+ csv_print_field(*ptr, fout, cont->opt->csvFieldSep[0]);
+ if ((i + 1) % cont->ncolumns)
+ fputc(cont->opt->csvFieldSep[0], fout);
+ else
+ fputc('\n', fout);
+ }
+}
+
+static void
+print_csv_vertical(const printTableContent *cont, FILE *fout)
+{
+ const char *const *ptr;
+ int i;
+
+ /* print records */
+ for (i = 0, ptr = cont->cells; *ptr; i++, ptr++)
+ {
+ if (cancel_pressed)
+ return;
+
+ /* print name of column */
+ csv_print_field(cont->headers[i % cont->ncolumns], fout,
+ cont->opt->csvFieldSep[0]);
+
+ /* print field separator */
+ fputc(cont->opt->csvFieldSep[0], fout);
+
+ /* print field value */
+ csv_print_field(*ptr, fout, cont->opt->csvFieldSep[0]);
+
+ fputc('\n', fout);
+ }
+}
+
+
+/**********************/
+/* HTML */
/**********************/
@@ -1953,9 +2065,10 @@ print_html_vertical(const printTableContent *cont, FILE *fout)
/*************************/
-/* ASCIIDOC */
+/* ASCIIDOC */
/*************************/
+
static void
asciidoc_escaped_print(const char *in, FILE *fout)
{
@@ -2174,6 +2287,7 @@ print_asciidoc_vertical(const printTableContent *cont, FILE *fout)
}
}
+
/*************************/
/* LaTeX */
/*************************/
@@ -2319,6 +2433,11 @@ print_latex_text(const printTableContent *cont, FILE *fout)
}
+/*************************/
+/* LaTeX longtable */
+/*************************/
+
+
static void
print_latex_longtable_text(const printTableContent *cont, FILE *fout)
{
@@ -2564,7 +2683,7 @@ print_latex_vertical(const printTableContent *cont, FILE *fout)
/*************************/
-/* Troff -ms */
+/* Troff -ms */
/*************************/
@@ -3234,6 +3353,12 @@ printTable(const printTableContent *cont,
else
print_aligned_text(cont, fout, is_pager);
break;
+ case PRINT_CSV:
+ if (cont->opt->expanded == 1)
+ print_csv_vertical(cont, fout);
+ else
+ print_csv_text(cont, fout);
+ break;
case PRINT_HTML:
if (cont->opt->expanded == 1)
print_html_vertical(cont, fout);