From 9527ce3efe74c4a1db22eb79af0f04b5e5394a83 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Thu, 7 May 1998 14:52:52 +0000 Subject: [PATCH] Add missing file from Tom Lane. --- src/interfaces/libpq/fe-print.c | 714 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 714 insertions(+) create mode 100644 src/interfaces/libpq/fe-print.c diff --git a/src/interfaces/libpq/fe-print.c b/src/interfaces/libpq/fe-print.c new file mode 100644 index 0000000000..2ecccb87ee --- /dev/null +++ b/src/interfaces/libpq/fe-print.c @@ -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, + "\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("
%d
\n", fout); + } + if (!po->expanded && (po->align || po->html3)) + { + if (po->html3) + { + if (po->header) + { + if (po->caption) + fprintf(fout, + "\n", + po->tableOpt ? po->tableOpt : "", + po->caption); + else + fprintf(fout, + "
%s
\n", + po->tableOpt ? po->tableOpt : "", nTups, nFields); + } + else + fprintf(fout, "
" + "Retrieved %d rows * %d fields" + "
", 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); +} -- 2.11.0