mirror of
https://github.com/postgres/postgres.git
synced 2025-07-05 07:21:24 +03:00
Here is a patch to bring both libpq and psql to a state where it compiles on win32 (native) again. A lot of things have changed, and I have not been able to keep up with them all, so it has been broken for quite a while. After this patch, at least it compiles. It also talks "basic talk" to the server, but I have not yet tested all things. Sending queries, and using e.g. \d or \dt works fine. The rest will have to be tested further. It also bumps the version on libpq.dll to 7.0. Everything should be enclosed in #ifdef WIN32, unless I have missed something. Except for one or maybe two places where I have moved a #include that should not be used on win32 from the "global area" into a "#ifndef WIN32 area". //Magnus
797 lines
16 KiB
C
797 lines
16 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* 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.30 2000/01/18 19:05:31 momjian Exp $
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#include <signal.h>
|
|
|
|
#include "postgres.h"
|
|
#include "libpq-fe.h"
|
|
#include "libpq-int.h"
|
|
#include "pqsignal.h"
|
|
|
|
#ifdef WIN32
|
|
#include "win32.h"
|
|
#else
|
|
#include <unistd.h>
|
|
#include <sys/ioctl.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_TERMIOS_H
|
|
#include <termios.h>
|
|
#else
|
|
#ifndef WIN32
|
|
#include <sys/termios.h>
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef MULTIBYTE
|
|
#include "mb/pg_wchar.h"
|
|
#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(const PQprintOpt *po, const PGresult *res,
|
|
const int i, const int j, const int fs_len,
|
|
char **fields,
|
|
const int nFields, const char **fieldNames,
|
|
unsigned char *fieldNotNum, int *fieldMax,
|
|
const int fieldMaxLen, FILE *fout);
|
|
static char *do_header(FILE *fout, const PQprintOpt *po, const int nFields,
|
|
int *fieldMax, const char **fieldNames, unsigned char *fieldNotNum,
|
|
const int fs_len, const PGresult *res);
|
|
static void output_row(FILE *fout, const 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,
|
|
const PGresult *res,
|
|
const 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;
|
|
const char **fieldNames;
|
|
int fieldMaxLen = 0;
|
|
int numFieldName;
|
|
int fs_len = strlen(po->fieldSep);
|
|
int total_line_length = 0;
|
|
int usePipe = 0;
|
|
pqsigfunc oldsigpipehandler = NULL;
|
|
char *pagerenv;
|
|
|
|
nTups = PQntuples(res);
|
|
if (!(fieldNames = (const 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;
|
|
const 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
|
|
#ifndef WIN32
|
|
&&
|
|
isatty(fileno(stdin)) &&
|
|
isatty(fileno(stdout))
|
|
#endif
|
|
)
|
|
{
|
|
/* 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 */
|
|
)))
|
|
{
|
|
#ifdef WIN32
|
|
fout = _popen(pagerenv, "w");
|
|
#else
|
|
fout = popen(pagerenv, "w");
|
|
#endif
|
|
if (fout)
|
|
{
|
|
usePipe = 1;
|
|
#ifndef WIN32
|
|
oldsigpipehandler = pqsignal(SIGPIPE, SIG_IGN);
|
|
#endif
|
|
}
|
|
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++)
|
|
{
|
|
const 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, "<centre><h2>%s</h2></centre>\n", po->caption);
|
|
else
|
|
fprintf(fout,
|
|
"<centre><h2>"
|
|
"Query retrieved %d rows * %d fields"
|
|
"</h2></centre>\n",
|
|
nTups, nFields);
|
|
}
|
|
for (i = 0; i < nTups; i++)
|
|
{
|
|
if (po->expanded)
|
|
{
|
|
if (po->html3)
|
|
fprintf(fout,
|
|
"<table %s><caption align=high>%d</caption>\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, fs_len, fields, nFields,
|
|
fieldNames, fieldNotNum,
|
|
fieldMax, fieldMaxLen, fout);
|
|
if (po->html3 && po->expanded)
|
|
fputs("</table>\n", fout);
|
|
}
|
|
if (!po->expanded && (po->align || po->html3))
|
|
{
|
|
if (po->html3)
|
|
{
|
|
if (po->header)
|
|
{
|
|
if (po->caption)
|
|
fprintf(fout,
|
|
"<table %s><caption align=high>%s</caption>\n",
|
|
po->tableOpt ? po->tableOpt : "",
|
|
po->caption);
|
|
else
|
|
fprintf(fout,
|
|
"<table %s><caption align=high>"
|
|
"Retrieved %d rows * %d fields"
|
|
"</caption>\n",
|
|
po->tableOpt ? po->tableOpt : "", nTups, nFields);
|
|
}
|
|
else
|
|
fprintf(fout, "<table %s>", 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)
|
|
{
|
|
#ifdef WIN32
|
|
_pclose(fout);
|
|
#else
|
|
pclose(fout);
|
|
pqsignal(SIGPIPE, oldsigpipehandler);
|
|
#endif
|
|
}
|
|
if (po->html3 && !po->expanded)
|
|
fputs("</table>\n", fout);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* PQdisplayTuples()
|
|
* kept for backward compatibility
|
|
*/
|
|
|
|
void
|
|
PQdisplayTuples(const 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 = NULL;
|
|
|
|
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;
|
|
|
|
/* Figure the field lengths to align to */
|
|
/* will be somewhat time consuming for very large results */
|
|
if (fillAlign)
|
|
{
|
|
fLength = (int *) malloc(nFields * sizeof(int));
|
|
for (j = 0; j < nFields; j++)
|
|
{
|
|
fLength[j] = strlen(PQfname(res, j));
|
|
for (i = 0; i < nTuples; i++)
|
|
{
|
|
int flen = PQgetlength(res, i, j);
|
|
if (flen > fLength[j])
|
|
fLength[j] = flen;
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
if (fLength)
|
|
free(fLength);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* PQprintTuples()
|
|
*
|
|
* kept for backward compatibility
|
|
*
|
|
*/
|
|
void
|
|
PQprintTuples(const 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++)
|
|
{
|
|
const char *pval = PQgetvalue(res, i, j);
|
|
|
|
fprintf(fout, formatString,
|
|
TerseOutput ? "" : "|",
|
|
pval ? pval : "");
|
|
}
|
|
if (TerseOutput)
|
|
fprintf(fout, "\n");
|
|
else
|
|
fprintf(fout, "|\n%s\n", tborder);
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef MULTIBYTE
|
|
/*
|
|
* returns the byte length of the word beginning s.
|
|
* Client side encoding is determined by the environment variable
|
|
* "PGCLIENTENCODING".
|
|
* if this variable is not defined, the same encoding as
|
|
* the backend is assumed.
|
|
*/
|
|
int
|
|
PQmblen(const unsigned char *s, int encoding)
|
|
{
|
|
return (pg_encoding_mblen(encoding, s));
|
|
}
|
|
|
|
/*
|
|
* Get encoding id from environment variable PGCLIENTENCODING.
|
|
*/
|
|
int
|
|
PQenv2encoding(void)
|
|
{
|
|
char *str;
|
|
int encoding = SQL_ASCII;
|
|
|
|
str = getenv("PGCLIENTENCODING");
|
|
if (str && *str != '\0')
|
|
encoding = pg_char_to_encoding(str);
|
|
return(encoding);
|
|
}
|
|
|
|
#else
|
|
|
|
/* Provide a default definition in case someone calls it anyway */
|
|
int
|
|
PQmblen(const unsigned char *s, int encoding)
|
|
{
|
|
return 1;
|
|
}
|
|
int
|
|
PQenv2encoding(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
#endif /* MULTIBYTE */
|
|
|
|
static void
|
|
do_field(const PQprintOpt *po, const PGresult *res,
|
|
const int i, const int j, const int fs_len,
|
|
char **fields,
|
|
const int nFields, char const **fieldNames,
|
|
unsigned char *fieldNotNum, int *fieldMax,
|
|
const int fieldMaxLen, FILE *fout)
|
|
{
|
|
|
|
const char *pval,
|
|
*p;
|
|
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)
|
|
{
|
|
if (po->align && ! fieldNotNum[j])
|
|
{
|
|
/* Detect whether field contains non-numeric data */
|
|
char ch = '0';
|
|
|
|
#ifdef MULTIBYTE
|
|
for (p = pval; *p; p += PQmblen(p, PQclientencoding(res->conn)))
|
|
#else
|
|
for (p = pval; *p; p++)
|
|
#endif
|
|
{
|
|
ch = *p;
|
|
if (! ((ch >= '0' && ch <= '9') ||
|
|
ch == '.' ||
|
|
ch == 'E' ||
|
|
ch == 'e' ||
|
|
ch == ' ' ||
|
|
ch == '-'))
|
|
{
|
|
fieldNotNum[j] = 1;
|
|
break;
|
|
}
|
|
}
|
|
/*
|
|
* Above loop will believe E in first column is numeric; also, we
|
|
* insist on a digit in the last column for a numeric. This test
|
|
* is still not bulletproof but it handles most cases.
|
|
*/
|
|
if (*pval == 'E' || *pval == 'e' ||
|
|
!(ch >= '0' && ch <= '9'))
|
|
fieldNotNum[j] = 1;
|
|
}
|
|
|
|
if (!po->expanded && (po->align || po->html3))
|
|
{
|
|
if (plen > fieldMax[j])
|
|
fieldMax[j] = plen;
|
|
if (!(fields[i * nFields + j] = (char *) malloc(plen + 1)))
|
|
{
|
|
perror("malloc");
|
|
exit(1);
|
|
}
|
|
strcpy(fields[i * nFields + j], pval);
|
|
}
|
|
else
|
|
{
|
|
if (po->expanded)
|
|
{
|
|
if (po->html3)
|
|
fprintf(fout,
|
|
"<tr><td align=left><b>%s</b></td>"
|
|
"<td align=%s>%s</td></tr>\n",
|
|
fieldNames[j],
|
|
fieldNotNum[j] ? "left" : "right",
|
|
pval);
|
|
else
|
|
{
|
|
if (po->align)
|
|
fprintf(fout,
|
|
"%-*s%s %s\n",
|
|
fieldMaxLen - fs_len, fieldNames[j],
|
|
po->fieldSep,
|
|
pval);
|
|
else
|
|
fprintf(fout,
|
|
"%s%s%s\n",
|
|
fieldNames[j], po->fieldSep, pval);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!po->html3)
|
|
{
|
|
fputs(pval, fout);
|
|
efield:
|
|
if ((j + 1) < nFields)
|
|
fputs(po->fieldSep, fout);
|
|
else
|
|
fputc('\n', fout);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static char *
|
|
do_header(FILE *fout, const PQprintOpt *po, const int nFields, int *fieldMax,
|
|
const char **fieldNames, unsigned char *fieldNotNum,
|
|
const int fs_len, const PGresult *res)
|
|
{
|
|
|
|
int j; /* for loop index */
|
|
char *border = NULL;
|
|
|
|
if (po->html3)
|
|
fputs("<tr>", 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++)
|
|
{
|
|
const char *s = PQfname(res, j);
|
|
|
|
if (po->html3)
|
|
{
|
|
fprintf(fout, "<th align=%s>%s</th>",
|
|
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("</tr>\n", fout);
|
|
else
|
|
fprintf(fout, "\n%s\n", border);
|
|
return border;
|
|
}
|
|
|
|
|
|
static void
|
|
output_row(FILE *fout, const 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("<tr>", 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, "<td align=%s>%s</td>",
|
|
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("</tr>", 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);
|
|
}
|