Add missing file from Tom Lane.
authorBruce Momjian
Thu, 7 May 1998 14:52:52 +0000 (14:52 +0000)
committerBruce Momjian
Thu, 7 May 1998 14:52:52 +0000 (14:52 +0000)
src/interfaces/libpq/fe-print.c [new file with mode: 0644]

diff --git a/src/interfaces/libpq/fe-print.c b/src/interfaces/libpq/fe-print.c
new file mode 100644 (file)
index 0000000..2ecccb8
--- /dev/null
@@ -0,0 +1,714 @@
+/*-------------------------------------------------------------------------
+ *
+ * fe-print.c--
+ *   functions for pretty-printing query results
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * These functions were formerly part of fe-exec.c, but they
+ * didn't really belong there.
+ *
+ * IDENTIFICATION
+ *   $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-print.c,v 1.1 1998/05/07 14:52:52 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "libpq/pqsignal.h"
+#include "libpq-fe.h"
+#ifndef HAVE_TERMIOS_H
+#include 
+#else
+#include 
+#endif
+
+
+#ifdef TIOCGWINSZ
+static struct winsize screen_size;
+
+#else
+static struct winsize
+{
+   int         ws_row;
+   int         ws_col;
+}          screen_size;
+
+#endif
+
+
+static void
+do_field(PQprintOpt *po, PGresult *res,
+        const int i, const int j, char *buf, const int fs_len,
+        char *fields[],
+        const int nFields, char *fieldNames[],
+        unsigned char fieldNotNum[], int fieldMax[],
+        const int fieldMaxLen, FILE *fout);
+static char *
+do_header(FILE *fout, PQprintOpt *po, const int nFields,
+         int fieldMax[], char *fieldNames[], unsigned char fieldNotNum[],
+         const int fs_len, PGresult *res);
+static void
+output_row(FILE *fout, PQprintOpt *po, const int nFields, char *fields[],
+          unsigned char fieldNotNum[], int fieldMax[], char *border,
+          const int row_index);
+static void fill(int length, int max, char filler, FILE *fp);
+
+
+/*
+ * PQprint()
+ *
+ * Format results of a query for printing.
+ *
+ * PQprintOpt is a typedef (structure) that containes
+ * various flags and options. consult libpq-fe.h for
+ * details
+ *
+ * Obsoletes PQprintTuples.
+ */
+
+void
+PQprint(FILE *fout,
+       PGresult *res,
+       PQprintOpt *po)
+{
+   int         nFields;
+
+   nFields = PQnfields(res);
+
+   if (nFields > 0)
+   {                           /* only print rows with at least 1 field.  */
+       int         i,
+                   j;
+       int         nTups;
+       int        *fieldMax = NULL;    /* in case we don't use them */
+       unsigned char *fieldNotNum = NULL;
+       char       *border = NULL;
+       char      **fields = NULL;
+       char      **fieldNames;
+       int         fieldMaxLen = 0;
+       int         numFieldName;
+       int         fs_len = strlen(po->fieldSep);
+       int         total_line_length = 0;
+       int         usePipe = 0;
+       char       *pagerenv;
+       char        buf[8192 * 2 + 1];
+
+       nTups = PQntuples(res);
+       if (!(fieldNames = (char **) calloc(nFields, sizeof(char *))))
+       {
+           perror("calloc");
+           exit(1);
+       }
+       if (!(fieldNotNum = (unsigned char *) calloc(nFields, 1)))
+       {
+           perror("calloc");
+           exit(1);
+       }
+       if (!(fieldMax = (int *) calloc(nFields, sizeof(int))))
+       {
+           perror("calloc");
+           exit(1);
+       }
+       for (numFieldName = 0;
+            po->fieldName && po->fieldName[numFieldName];
+            numFieldName++)
+           ;
+       for (j = 0; j < nFields; j++)
+       {
+           int         len;
+           char       *s =
+           (j < numFieldName && po->fieldName[j][0]) ?
+           po->fieldName[j] : PQfname(res, j);
+
+           fieldNames[j] = s;
+           len = s ? strlen(s) : 0;
+           fieldMax[j] = len;
+           len += fs_len;
+           if (len > fieldMaxLen)
+               fieldMaxLen = len;
+           total_line_length += len;
+       }
+
+       total_line_length += nFields * strlen(po->fieldSep) + 1;
+
+       if (fout == NULL)
+           fout = stdout;
+       if (po->pager && fout == stdout &&
+           isatty(fileno(stdin)) &&
+           isatty(fileno(stdout)))
+       {
+           /* try to pipe to the pager program if possible */
+#ifdef TIOCGWINSZ
+           if (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) == -1 ||
+               screen_size.ws_col == 0 ||
+               screen_size.ws_row == 0)
+           {
+#endif
+               screen_size.ws_row = 24;
+               screen_size.ws_col = 80;
+#ifdef TIOCGWINSZ
+           }
+#endif
+           pagerenv = getenv("PAGER");
+           if (pagerenv != NULL &&
+               pagerenv[0] != '\0' &&
+               !po->html3 &&
+               ((po->expanded &&
+                 nTups * (nFields + 1) >= screen_size.ws_row) ||
+                (!po->expanded &&
+                 nTups * (total_line_length / screen_size.ws_col + 1) *
+                 (1 + (po->standard != 0)) >=
+                 screen_size.ws_row -
+                 (po->header != 0) *
+                 (total_line_length / screen_size.ws_col + 1) * 2
+                 - (po->header != 0) * 2       /* row count and newline */
+                 )))
+           {
+               fout = popen(pagerenv, "w");
+               if (fout)
+               {
+                   usePipe = 1;
+                   pqsignal(SIGPIPE, SIG_IGN);
+               }
+               else
+                   fout = stdout;
+           }
+       }
+
+       if (!po->expanded && (po->align || po->html3))
+       {
+           if (!(fields = (char **) calloc(nFields * (nTups + 1), sizeof(char *))))
+           {
+               perror("calloc");
+               exit(1);
+           }
+       }
+       else if (po->header && !po->html3)
+       {
+           if (po->expanded)
+           {
+               if (po->align)
+                   fprintf(fout, "%-*s%s Value\n",
+                           fieldMaxLen - fs_len, "Field", po->fieldSep);
+               else
+                   fprintf(fout, "%s%sValue\n", "Field", po->fieldSep);
+           }
+           else
+           {
+               int         len = 0;
+
+               for (j = 0; j < nFields; j++)
+               {
+                   char       *s = fieldNames[j];
+
+                   fputs(s, fout);
+                   len += strlen(s) + fs_len;
+                   if ((j + 1) < nFields)
+                       fputs(po->fieldSep, fout);
+               }
+               fputc('\n', fout);
+               for (len -= fs_len; len--; fputc('-', fout));
+               fputc('\n', fout);
+           }
+       }
+       if (po->expanded && po->html3)
+       {
+           if (po->caption)
+               fprintf(fout, "

%s

\n", po->caption);
+           else
+               fprintf(fout,
+                       "

"

+                       "Query retrieved %d rows * %d fields"
+                       "\n",
+                       nTups, nFields);
+       }
+       for (i = 0; i < nTups; i++)
+       {
+           if (po->expanded)
+           {
+               if (po->html3)
+                   fprintf(fout,
+                         "%d\n",
+                           po->tableOpt ? po->tableOpt : "", i);
+               else
+                   fprintf(fout, "-- RECORD %d --\n", i);
+           }
+           for (j = 0; j < nFields; j++)
+               do_field(po, res, i, j, buf, fs_len, fields, nFields,
+                        fieldNames, fieldNotNum,
+                        fieldMax, fieldMaxLen, fout);
+           if (po->html3 && po->expanded)
+               fputs("\n", fout);
+       }
+       if (!po->expanded && (po->align || po->html3))
+       {
+           if (po->html3)
+           {
+               if (po->header)
+               {
+                   if (po->caption)
+                       fprintf(fout,
+                         "%s\n",
+                               po->tableOpt ? po->tableOpt : "",
+                               po->caption);
+                   else
+                       fprintf(fout,
+                               ""
+                               "Retrieved %d rows * %d fields"
+                               "\n",
+                       po->tableOpt ? po->tableOpt : "", nTups, nFields);
+               }
+               else
+                   fprintf(fout, "", po->tableOpt ? po->tableOpt : "");
+           }
+           if (po->header)
+               border = do_header(fout, po, nFields, fieldMax, fieldNames,
+                                  fieldNotNum, fs_len, res);
+           for (i = 0; i < nTups; i++)
+               output_row(fout, po, nFields, fields,
+                          fieldNotNum, fieldMax, border, i);
+           free(fields);
+           if (border)
+               free(border);
+       }
+       if (po->header && !po->html3)
+           fprintf(fout, "(%d row%s)\n\n", PQntuples(res),
+                   (PQntuples(res) == 1) ? "" : "s");
+       free(fieldMax);
+       free(fieldNotNum);
+       free(fieldNames);
+       if (usePipe)
+       {
+           pclose(fout);
+           pqsignal(SIGPIPE, SIG_DFL);
+       }
+       if (po->html3 && !po->expanded)
+           fputs("\n", fout);
+   }
+}
+
+
+/*
+ * PQdisplayTuples()
+ * kept for backward compatibility
+ */
+
+void
+PQdisplayTuples(PGresult *res,
+               FILE *fp,       /* where to send the output */
+               int fillAlign,  /* pad the fields with spaces */
+               const char *fieldSep,   /* field separator */
+               int printHeader,/* display headers? */
+               int quiet
+)
+{
+#define DEFAULT_FIELD_SEP " "
+
+   int         i,
+               j;
+   int         nFields;
+   int         nTuples;
+   int         fLength[MAX_FIELDS];
+
+   if (fieldSep == NULL)
+       fieldSep = DEFAULT_FIELD_SEP;
+
+   /* Get some useful info about the results */
+   nFields = PQnfields(res);
+   nTuples = PQntuples(res);
+
+   if (fp == NULL)
+       fp = stdout;
+
+   /* Zero the initial field lengths */
+   for (j = 0; j < nFields; j++)
+   {
+       fLength[j] = strlen(PQfname(res, j));
+   }
+   /* Find the max length of each field in the result */
+   /* will be somewhat time consuming for very large results */
+   if (fillAlign)
+   {
+       for (i = 0; i < nTuples; i++)
+       {
+           for (j = 0; j < nFields; j++)
+           {
+               if (PQgetlength(res, i, j) > fLength[j])
+                   fLength[j] = PQgetlength(res, i, j);
+           }
+       }
+   }
+
+   if (printHeader)
+   {
+       /* first, print out the attribute names */
+       for (i = 0; i < nFields; i++)
+       {
+           fputs(PQfname(res, i), fp);
+           if (fillAlign)
+               fill(strlen(PQfname(res, i)), fLength[i], ' ', fp);
+           fputs(fieldSep, fp);
+       }
+       fprintf(fp, "\n");
+
+       /* Underline the attribute names */
+       for (i = 0; i < nFields; i++)
+       {
+           if (fillAlign)
+               fill(0, fLength[i], '-', fp);
+           fputs(fieldSep, fp);
+       }
+       fprintf(fp, "\n");
+   }
+
+   /* next, print out the instances */
+   for (i = 0; i < nTuples; i++)
+   {
+       for (j = 0; j < nFields; j++)
+       {
+           fprintf(fp, "%s", PQgetvalue(res, i, j));
+           if (fillAlign)
+               fill(strlen(PQgetvalue(res, i, j)), fLength[j], ' ', fp);
+           fputs(fieldSep, fp);
+       }
+       fprintf(fp, "\n");
+   }
+
+   if (!quiet)
+       fprintf(fp, "\nQuery returned %d row%s.\n", PQntuples(res),
+               (PQntuples(res) == 1) ? "" : "s");
+
+   fflush(fp);
+}
+
+
+
+/*
+ * PQprintTuples()
+ *
+ * kept for backward compatibility
+ *
+ */
+void
+PQprintTuples(PGresult *res,
+             FILE *fout,       /* output stream */
+             int PrintAttNames,/* print attribute names or not */
+             int TerseOutput,  /* delimiter bars or not? */
+             int colWidth      /* width of column, if 0, use variable
+                                * width */
+)
+{
+   int         nFields;
+   int         nTups;
+   int         i,
+               j;
+   char        formatString[80];
+
+   char       *tborder = NULL;
+
+   nFields = PQnfields(res);
+   nTups = PQntuples(res);
+
+   if (colWidth > 0)
+   {
+       sprintf(formatString, "%%s %%-%ds", colWidth);
+   }
+   else
+       sprintf(formatString, "%%s %%s");
+
+   if (nFields > 0)
+   {                           /* only print rows with at least 1 field.  */
+
+       if (!TerseOutput)
+       {
+           int         width;
+
+           width = nFields * 14;
+           tborder = malloc(width + 1);
+           for (i = 0; i <= width; i++)
+               tborder[i] = '-';
+           tborder[i] = '\0';
+           fprintf(fout, "%s\n", tborder);
+       }
+
+       for (i = 0; i < nFields; i++)
+       {
+           if (PrintAttNames)
+           {
+               fprintf(fout, formatString,
+                       TerseOutput ? "" : "|",
+                       PQfname(res, i));
+           }
+       }
+
+       if (PrintAttNames)
+       {
+           if (TerseOutput)
+               fprintf(fout, "\n");
+           else
+               fprintf(fout, "|\n%s\n", tborder);
+       }
+
+       for (i = 0; i < nTups; i++)
+       {
+           for (j = 0; j < nFields; j++)
+           {
+               char       *pval = PQgetvalue(res, i, j);
+
+               fprintf(fout, formatString,
+                       TerseOutput ? "" : "|",
+                       pval ? pval : "");
+           }
+           if (TerseOutput)
+               fprintf(fout, "\n");
+           else
+               fprintf(fout, "|\n%s\n", tborder);
+       }
+   }
+}
+
+
+
+static void
+do_field(PQprintOpt *po, PGresult *res,
+        const int i, const int j, char *buf, const int fs_len,
+        char *fields[],
+        const int nFields, char *fieldNames[],
+        unsigned char fieldNotNum[], int fieldMax[],
+        const int fieldMaxLen, FILE *fout)
+{
+
+   char       *pval,
+              *p,
+              *o;
+   int         plen;
+   bool        skipit;
+
+   plen = PQgetlength(res, i, j);
+   pval = PQgetvalue(res, i, j);
+
+   if (plen < 1 || !pval || !*pval)
+   {
+       if (po->align || po->expanded)
+           skipit = true;
+       else
+       {
+           skipit = false;
+           goto efield;
+       }
+   }
+   else
+       skipit = false;
+
+   if (!skipit)
+   {
+       for (p = pval, o = buf; *p; *(o++) = *(p++))
+       {
+           if ((fs_len == 1 && (*p == *(po->fieldSep))) || *p == '\\' || *p == '\n')
+               *(o++) = '\\';
+           if (po->align && (*pval == 'E' || *pval == 'e' ||
+                             !((*p >= '0' && *p <= '9') ||
+                               *p == '.' ||
+                               *p == 'E' ||
+                               *p == 'e' ||
+                               *p == ' ' ||
+                               *p == '-')))
+               fieldNotNum[j] = 1;
+       }
+       *o = '\0';
+       if (!po->expanded && (po->align || po->html3))
+       {
+           int         n = strlen(buf);
+
+           if (n > fieldMax[j])
+               fieldMax[j] = n;
+           if (!(fields[i * nFields + j] = (char *) malloc(n + 1)))
+           {
+               perror("malloc");
+               exit(1);
+           }
+           strcpy(fields[i * nFields + j], buf);
+       }
+       else
+       {
+           if (po->expanded)
+           {
+               if (po->html3)
+                   fprintf(fout,
+                           "%s"
+                           "%s\n",
+                           fieldNames[j],
+                           fieldNotNum[j] ? "left" : "right",
+                           buf);
+               else
+               {
+                   if (po->align)
+                       fprintf(fout,
+                               "%-*s%s %s\n",
+                       fieldMaxLen - fs_len, fieldNames[j], po->fieldSep,
+                               buf);
+                   else
+                       fprintf(fout, "%s%s%s\n", fieldNames[j], po->fieldSep, buf);
+               }
+           }
+           else
+           {
+               if (!po->html3)
+               {
+                   fputs(buf, fout);
+           efield:
+                   if ((j + 1) < nFields)
+                       fputs(po->fieldSep, fout);
+                   else
+                       fputc('\n', fout);
+               }
+           }
+       }
+   }
+}
+
+
+static char *
+do_header(FILE *fout, PQprintOpt *po, const int nFields, int fieldMax[],
+         char *fieldNames[], unsigned char fieldNotNum[],
+         const int fs_len, PGresult *res)
+{
+
+   int         j;              /* for loop index */
+   char       *border = NULL;
+
+   if (po->html3)
+       fputs("", fout);
+   else
+   {
+       int         j;          /* for loop index */
+       int         tot = 0;
+       int         n = 0;
+       char       *p = NULL;
+
+       for (; n < nFields; n++)
+           tot += fieldMax[n] + fs_len + (po->standard ? 2 : 0);
+       if (po->standard)
+           tot += fs_len * 2 + 2;
+       border = malloc(tot + 1);
+       if (!border)
+       {
+           perror("malloc");
+           exit(1);
+       }
+       p = border;
+       if (po->standard)
+       {
+           char       *fs = po->fieldSep;
+
+           while (*fs++)
+               *p++ = '+';
+       }
+       for (j = 0; j < nFields; j++)
+       {
+           int         len;
+
+           for (len = fieldMax[j] + (po->standard ? 2 : 0); len--; *p++ = '-');
+           if (po->standard || (j + 1) < nFields)
+           {
+               char       *fs = po->fieldSep;
+
+               while (*fs++)
+                   *p++ = '+';
+           }
+       }
+       *p = '\0';
+       if (po->standard)
+           fprintf(fout, "%s\n", border);
+   }
+   if (po->standard)
+       fputs(po->fieldSep, fout);
+   for (j = 0; j < nFields; j++)
+   {
+       char       *s = PQfname(res, j);
+
+       if (po->html3)
+       {
+           fprintf(fout, "%s",
+                   fieldNotNum[j] ? "left" : "right", fieldNames[j]);
+       }
+       else
+       {
+           int         n = strlen(s);
+
+           if (n > fieldMax[j])
+               fieldMax[j] = n;
+           if (po->standard)
+               fprintf(fout,
+                       fieldNotNum[j] ? " %-*s " : " %*s ",
+                       fieldMax[j], s);
+           else
+               fprintf(fout, fieldNotNum[j] ? "%-*s" : "%*s", fieldMax[j], s);
+           if (po->standard || (j + 1) < nFields)
+               fputs(po->fieldSep, fout);
+       }
+   }
+   if (po->html3)
+       fputs("\n", fout);
+   else
+       fprintf(fout, "\n%s\n", border);
+   return border;
+}
+
+
+static void
+output_row(FILE *fout, PQprintOpt *po, const int nFields, char *fields[],
+          unsigned char fieldNotNum[], int fieldMax[], char *border,
+          const int row_index)
+{
+
+   int         field_index;    /* for loop index */
+
+   if (po->html3)
+       fputs("", fout);
+   else if (po->standard)
+       fputs(po->fieldSep, fout);
+   for (field_index = 0; field_index < nFields; field_index++)
+   {
+       char       *p = fields[row_index * nFields + field_index];
+
+       if (po->html3)
+           fprintf(fout, "%s",
+               fieldNotNum[field_index] ? "left" : "right", p ? p : "");
+       else
+       {
+           fprintf(fout,
+                   fieldNotNum[field_index] ?
+                   (po->standard ? " %-*s " : "%-*s") :
+                   (po->standard ? " %*s " : "%*s"),
+                   fieldMax[field_index],
+                   p ? p : "");
+           if (po->standard || field_index + 1 < nFields)
+               fputs(po->fieldSep, fout);
+       }
+       if (p)
+           free(p);
+   }
+   if (po->html3)
+       fputs("", fout);
+   else if (po->standard)
+       fprintf(fout, "\n%s", border);
+   fputc('\n', fout);
+}
+
+
+/* simply send out max-length number of filler characters to fp */
+
+static void
+fill(int length, int max, char filler, FILE *fp)
+{
+   int         count;
+
+   count = max - length;
+   while (count-- >= 0)
+       putc(filler, fp);
+}