print.c 22.3 KB
Newer Older
Peter Eisentraut's avatar
Peter Eisentraut committed
1 2 3 4 5 6 7
/*
 * psql - the PostgreSQL interactive terminal
 *
 * Copyright 2000 by PostgreSQL Global Development Team
 *
 * $Header: /cvsroot/pgsql/src/bin/psql/print.c,v 1.8 2000/01/18 23:30:24 petere Exp $
 */
8 9 10 11 12 13 14 15
#include <c.h>
#include "print.h"

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <signal.h>
#ifndef WIN32
Bruce Momjian's avatar
Bruce Momjian committed
16 17
#include <unistd.h>				/* for isatty() */
#include <sys/ioctl.h>			/* for ioctl() */
18 19 20 21 22 23 24
#else
#define popen(x,y) _popen(x,y)
#define pclose(x) _pclose(x)
#endif

#include <pqsignal.h>
#include <libpq-fe.h>
Bruce Momjian's avatar
Bruce Momjian committed
25
#include <postgres_ext.h>		/* for Oid type */
26

27
#define DEFAULT_PAGER "more"
28 29 30 31



/*************************/
Bruce Momjian's avatar
Bruce Momjian committed
32
/* Unaligned text		 */
33 34 35 36
/*************************/


static void
Bruce Momjian's avatar
Bruce Momjian committed
37 38
print_unaligned_text(const char *title, const char * const * headers,
		     const char * const * cells, const char * const * footers,
Peter Eisentraut's avatar
Peter Eisentraut committed
39
		     const char *opt_fieldsep, const char *opt_recordsep, bool opt_barebones,
40
		     FILE *fout)
41
{
Bruce Momjian's avatar
Bruce Momjian committed
42 43
	unsigned int col_count = 0;
	unsigned int i;
Bruce Momjian's avatar
Bruce Momjian committed
44
	const char * const * ptr;
Peter Eisentraut's avatar
Peter Eisentraut committed
45
    bool need_recordsep = false;
Bruce Momjian's avatar
Bruce Momjian committed
46 47 48

	if (!opt_fieldsep)
		opt_fieldsep = "";
Peter Eisentraut's avatar
Peter Eisentraut committed
49 50
    if (!opt_recordsep)
        opt_recordsep = "";
Bruce Momjian's avatar
Bruce Momjian committed
51 52 53

	/* print title */
	if (!opt_barebones && title)
Peter Eisentraut's avatar
Peter Eisentraut committed
54
		fprintf(fout, "%s%s", title, opt_recordsep);
Bruce Momjian's avatar
Bruce Momjian committed
55 56 57 58 59 60 61 62 63 64 65 66 67

	/* print headers and count columns */
	for (ptr = headers; *ptr; ptr++)
	{
		col_count++;
		if (!opt_barebones)
		{
			if (col_count > 1)
				fputs(opt_fieldsep, fout);
			fputs(*ptr, fout);
		}
	}
	if (!opt_barebones)
Peter Eisentraut's avatar
Peter Eisentraut committed
68
        need_recordsep = true;
Bruce Momjian's avatar
Bruce Momjian committed
69 70 71 72 73

	/* print cells */
	i = 0;
	for (ptr = cells; *ptr; ptr++)
	{
Peter Eisentraut's avatar
Peter Eisentraut committed
74 75 76 77 78
        if (need_recordsep)
        {
			fputs(opt_recordsep, fout);
            need_recordsep = false;
        }
Bruce Momjian's avatar
Bruce Momjian committed
79 80 81 82
		fputs(*ptr, fout);
		if ((i + 1) % col_count)
			fputs(opt_fieldsep, fout);
		else
Peter Eisentraut's avatar
Peter Eisentraut committed
83
            need_recordsep = true;
Bruce Momjian's avatar
Bruce Momjian committed
84 85
		i++;
	}
86

Bruce Momjian's avatar
Bruce Momjian committed
87
	/* print footers */
88

Bruce Momjian's avatar
Bruce Momjian committed
89 90
	if (!opt_barebones && footers)
		for (ptr = footers; *ptr; ptr++)
Peter Eisentraut's avatar
Peter Eisentraut committed
91 92 93 94 95 96 97 98 99
        {
            if (need_recordsep)
            {
                fputs(opt_recordsep, fout);
                need_recordsep = false;
            }
			fputs(*ptr, fout);
            need_recordsep = true;
        }
100

Peter Eisentraut's avatar
Peter Eisentraut committed
101 102 103
    /* the last record needs to be concluded with a newline */
    if (need_recordsep)
        fputc('\n', fout);
104 105 106 107 108
}



static void
Bruce Momjian's avatar
Bruce Momjian committed
109 110
print_unaligned_vertical(const char *title, const char * const * headers,
			 const char * const * cells, const char * const * footers,
Peter Eisentraut's avatar
Peter Eisentraut committed
111
			 const char *opt_fieldsep, const char *opt_recordsep, bool opt_barebones,
112
			 FILE *fout)
113
{
Bruce Momjian's avatar
Bruce Momjian committed
114 115
	unsigned int col_count = 0;
	unsigned int i;
Bruce Momjian's avatar
Bruce Momjian committed
116
	const char * const * ptr;
Bruce Momjian's avatar
Bruce Momjian committed
117 118 119

	if (!opt_fieldsep)
		opt_fieldsep = "";
Peter Eisentraut's avatar
Peter Eisentraut committed
120 121
    if (!opt_recordsep)
        opt_recordsep = "";
Bruce Momjian's avatar
Bruce Momjian committed
122 123 124

	/* print title */
	if (!opt_barebones && title)
Peter Eisentraut's avatar
Peter Eisentraut committed
125
        fputs(title, fout);
Bruce Momjian's avatar
Bruce Momjian committed
126 127 128 129 130 131 132 133

	/* count columns */
	for (ptr = headers; *ptr; ptr++)
		col_count++;

	/* print records */
	for (i = 0, ptr = cells; *ptr; i++, ptr++)
	{
Peter Eisentraut's avatar
Peter Eisentraut committed
134 135 136 137 138 139 140 141 142 143
        if (i!=0 || (!opt_barebones && title))
        {
            fputs(opt_recordsep, fout);
            if (i % col_count == 0)
                fputs(opt_recordsep, fout); /* another one */
        }

        fputs(headers[i % col_count], fout);
        fputs(opt_fieldsep, fout);
        fputs(*ptr, fout);
144 145
	}

Bruce Momjian's avatar
Bruce Momjian committed
146
	/* print footers */
Peter Eisentraut's avatar
Peter Eisentraut committed
147
	if (!opt_barebones && footers && *footers)
Bruce Momjian's avatar
Bruce Momjian committed
148
	{
Peter Eisentraut's avatar
Peter Eisentraut committed
149
        fputs(opt_recordsep, fout);
Bruce Momjian's avatar
Bruce Momjian committed
150
		for (ptr = footers; *ptr; ptr++)
Peter Eisentraut's avatar
Peter Eisentraut committed
151 152 153 154
        {
            fputs(opt_recordsep, fout);
            fputs(*ptr, fout);
        }
Bruce Momjian's avatar
Bruce Momjian committed
155
	}
Peter Eisentraut's avatar
Peter Eisentraut committed
156 157

    fputc('\n', fout);
158 159 160 161 162
}



/********************/
Bruce Momjian's avatar
Bruce Momjian committed
163
/* Aligned text		*/
164 165 166 167 168
/********************/


/* draw "line" */
static void
Bruce Momjian's avatar
Bruce Momjian committed
169
_print_horizontal_line(const unsigned int col_count, const unsigned int *widths, unsigned short border, FILE *fout)
170
{
Bruce Momjian's avatar
Bruce Momjian committed
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
	unsigned int i,
				j;

	if (border == 1)
		fputc('-', fout);
	else if (border == 2)
		fputs("+-", fout);

	for (i = 0; i < col_count; i++)
	{
		for (j = 0; j < widths[i]; j++)
			fputc('-', fout);

		if (i < col_count - 1)
		{
			if (border == 0)
				fputc(' ', fout);
			else
				fputs("-+-", fout);
		}
	}

	if (border == 2)
		fputs("-+", fout);
	else if (border == 1)
		fputc('-', fout);

	fputc('\n', fout);
199 200 201 202 203
}



static void
Bruce Momjian's avatar
Bruce Momjian committed
204 205 206
print_aligned_text(const char *title, const char * const * headers,
		   const char * const * cells, const char * const * footers,
		   const char *opt_align, bool opt_barebones, unsigned short int opt_border,
207
		   FILE *fout)
208
{
Bruce Momjian's avatar
Bruce Momjian committed
209 210 211 212 213
	unsigned int col_count = 0;
	unsigned int i,
				tmp;
	unsigned int *widths,
				total_w;
Bruce Momjian's avatar
Bruce Momjian committed
214
	const char * const * ptr;
Bruce Momjian's avatar
Bruce Momjian committed
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238

	/* count columns */
	for (ptr = headers; *ptr; ptr++)
		col_count++;

	widths = calloc(col_count, sizeof(*widths));
	if (!widths)
	{
		perror("calloc");
		exit(EXIT_FAILURE);
	}

	/* calc column widths */
	for (i = 0; i < col_count; i++)
		if ((tmp = strlen(headers[i])) > widths[i])
			widths[i] = tmp;	/* don't wanna call strlen twice */

	for (i = 0, ptr = cells; *ptr; ptr++, i++)
		if ((tmp = strlen(*ptr)) > widths[i % col_count])
			widths[i % col_count] = tmp;

	if (opt_border == 0)
		total_w = col_count - 1;
	else if (opt_border == 1)
239
		total_w = col_count * 3 - 1;
240
	else
Bruce Momjian's avatar
Bruce Momjian committed
241 242 243 244 245 246 247 248 249 250
		total_w = col_count * 3 + 1;

	for (i = 0; i < col_count; i++)
		total_w += widths[i];

	/* print title */
	if (title && !opt_barebones)
	{
		if (strlen(title) >= total_w)
			fprintf(fout, "%s\n", title);
251
		else
Bruce Momjian's avatar
Bruce Momjian committed
252
			fprintf(fout, "%-*s%s\n", (total_w - strlen(title)) / 2, "", title);
253 254
	}

Bruce Momjian's avatar
Bruce Momjian committed
255 256 257 258 259
	/* print headers */
	if (!opt_barebones)
	{
		if (opt_border == 2)
			_print_horizontal_line(col_count, widths, opt_border, fout);
260

Bruce Momjian's avatar
Bruce Momjian committed
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
		if (opt_border == 2)
			fputs("| ", fout);
		else if (opt_border == 1)
			fputc(' ', fout);

		for (i = 0; i < col_count; i++)
		{
			/* centered */
			fprintf(fout, "%-*s%s%-*s", (int) floor((widths[i] - strlen(headers[i])) / 2.0), "", headers[i], (int) ceil((widths[i] - strlen(headers[i])) / 2.0), "");

			if (i < col_count - 1)
			{
				if (opt_border == 0)
					fputc(' ', fout);
				else
					fputs(" | ", fout);
			}
		}
279

Bruce Momjian's avatar
Bruce Momjian committed
280 281 282 283 284
		if (opt_border == 2)
			fputs(" |", fout);
		else if (opt_border == 1)
			fputc(' ', fout);;
		fputc('\n', fout);
285

Bruce Momjian's avatar
Bruce Momjian committed
286
		_print_horizontal_line(col_count, widths, opt_border, fout);
287 288
	}

Bruce Momjian's avatar
Bruce Momjian committed
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
	/* print cells */
	for (i = 0, ptr = cells; *ptr; i++, ptr++)
	{
		/* beginning of line */
		if (i % col_count == 0)
		{
			if (opt_border == 2)
				fputs("| ", fout);
			else if (opt_border == 1)
				fputc(' ', fout);
		}

		/* content */
		if (opt_align[(i) % col_count] == 'r')
			fprintf(fout, "%*s", widths[i % col_count], cells[i]);
		else
		{
			if ((i + 1) % col_count == 0 && opt_border != 2)
				fputs(cells[i], fout);
			else
				fprintf(fout, "%-*s", widths[i % col_count], cells[i]);
		}

		/* divider */
		if ((i + 1) % col_count)
		{
			if (opt_border == 0)
				fputc(' ', fout);
			else
				fputs(" | ", fout);
		}
		/* end of line */
		else
		{
			if (opt_border == 2)
				fputs(" |", fout);
			fputc('\n', fout);
		}
327 328
	}

Bruce Momjian's avatar
Bruce Momjian committed
329 330
	if (opt_border == 2)
		_print_horizontal_line(col_count, widths, opt_border, fout);
331

Bruce Momjian's avatar
Bruce Momjian committed
332 333 334 335
	/* print footers */
	if (footers && !opt_barebones)
		for (ptr = footers; *ptr; ptr++)
			fprintf(fout, "%s\n", *ptr);
336

Bruce Momjian's avatar
Bruce Momjian committed
337
	fputc('\n', fout);
338

Bruce Momjian's avatar
Bruce Momjian committed
339 340
	/* clean up */
	free(widths);
341 342 343 344 345
}



static void
Bruce Momjian's avatar
Bruce Momjian committed
346 347
print_aligned_vertical(const char *title, const char * const * headers,
		       const char * const * cells, const char * const * footers,
348 349
		       bool opt_barebones, unsigned short int opt_border,
		       FILE *fout)
350
{
Bruce Momjian's avatar
Bruce Momjian committed
351 352
	unsigned int col_count = 0;
	unsigned int record = 1;
Bruce Momjian's avatar
Bruce Momjian committed
353
	const char * const *ptr;
Bruce Momjian's avatar
Bruce Momjian committed
354 355 356 357 358 359
	unsigned int i,
				tmp,
				hwidth = 0,
				dwidth = 0;
	char	   *divider;

360 361 362 363 364
    if (cells[0] == NULL) {
        puts("(No rows)\n");
        return;
    }

Bruce Momjian's avatar
Bruce Momjian committed
365 366 367 368 369 370 371
	/* count columns and find longest header */
	for (ptr = headers; *ptr; ptr++)
	{
		col_count++;
		if ((tmp = strlen(*ptr)) > hwidth)
			hwidth = tmp;		/* don't wanna call strlen twice */
	}
372

Bruce Momjian's avatar
Bruce Momjian committed
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
	/* find longest data cell */
	for (ptr = cells; *ptr; ptr++)
		if ((tmp = strlen(*ptr)) > dwidth)
			dwidth = tmp;

	/* print title */
	if (!opt_barebones && title)
		fprintf(fout, "%s\n", title);

	/* make horizontal border */
	divider = malloc(hwidth + dwidth + 10);
	if (!divider)
	{
		perror("malloc");
		exit(EXIT_FAILURE);
388
	}
Bruce Momjian's avatar
Bruce Momjian committed
389
	divider[0] = '\0';
390
	if (opt_border == 2)
Bruce Momjian's avatar
Bruce Momjian committed
391 392 393
		strcat(divider, "+-");
	for (i = 0; i < hwidth; i++)
		strcat(divider, opt_border > 0 ? "-" : " ");
394
	if (opt_border > 0)
Bruce Momjian's avatar
Bruce Momjian committed
395
		strcat(divider, "-+-");
396
	else
Bruce Momjian's avatar
Bruce Momjian committed
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
		strcat(divider, " ");
	for (i = 0; i < dwidth; i++)
		strcat(divider, opt_border > 0 ? "-" : " ");
	if (opt_border == 2)
		strcat(divider, "-+");


	/* print records */
	for (i = 0, ptr = cells; *ptr; i++, ptr++)
	{
		if (i % col_count == 0)
		{
			if (!opt_barebones)
			{
				char	   *record_str = malloc(32);
				size_t		record_str_len;

414
				if (!record_str)
Bruce Momjian's avatar
Bruce Momjian committed
415 416 417 418 419 420 421 422 423 424
				{
					perror("malloc");
					exit(EXIT_FAILURE);
				}

				if (opt_border == 0)
					sprintf(record_str, "* Record %d", record++);
				else
					sprintf(record_str, "[ RECORD %d ]", record++);
				record_str_len = strlen(record_str);
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440

				if (record_str_len + opt_border > strlen(divider))
                    fprintf(fout, "%.*s%s\n", opt_border, divider, record_str);
                else
                {
                    char	   *div_copy = strdup(divider);

                    if (!div_copy) {
                        perror("malloc");
                        exit(EXIT_FAILURE);
                    }

                    strncpy(div_copy + opt_border, record_str, record_str_len);
                    fprintf(fout, "%s\n", div_copy);
                    free(div_copy);
                }
Bruce Momjian's avatar
Bruce Momjian committed
441 442
				free(record_str);
			}
443
			else if (i != 0 || opt_border == 2)
Bruce Momjian's avatar
Bruce Momjian committed
444 445
				fprintf(fout, "%s\n", divider);
		}
446

Bruce Momjian's avatar
Bruce Momjian committed
447 448 449
		if (opt_border == 2)
			fputs("| ", fout);
		fprintf(fout, "%-*s", hwidth, headers[i % col_count]);
450

Bruce Momjian's avatar
Bruce Momjian committed
451 452 453 454
		if (opt_border > 0)
			fputs(" | ", fout);
		else
			fputs(" ", fout);
455

Bruce Momjian's avatar
Bruce Momjian committed
456 457 458 459 460
		if (opt_border < 2)
			fprintf(fout, "%s\n", *ptr);
		else
			fprintf(fout, "%-*s |\n", dwidth, *ptr);
	}
461

Bruce Momjian's avatar
Bruce Momjian committed
462 463
	if (opt_border == 2)
		fprintf(fout, "%s\n", divider);
464 465


Bruce Momjian's avatar
Bruce Momjian committed
466
	/* print footers */
467

Bruce Momjian's avatar
Bruce Momjian committed
468 469 470 471 472 473 474
	if (!opt_barebones && footers && *footers)
	{
		if (opt_border < 2)
			fputc('\n', fout);
		for (ptr = footers; *ptr; ptr++)
			fprintf(fout, "%s\n", *ptr);
	}
475

Bruce Momjian's avatar
Bruce Momjian committed
476 477
	fputc('\n', fout);
	free(divider);
478 479 480 481 482 483 484 485 486 487 488 489
}





/**********************/
/* HTML printing ******/
/**********************/


static void
Bruce Momjian's avatar
Bruce Momjian committed
490
html_escaped_print(const char *in, FILE *fout)
491
{
Bruce Momjian's avatar
Bruce Momjian committed
492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
	const char *p;

	for (p = in; *p; p++)
		switch (*p)
		{
			case '&':
				fputs("&amp;", fout);
				break;
			case '<':
				fputs("&lt;", fout);
				break;
			case '>':
				fputs("&gt;", fout);
				break;
			case '\n':
				fputs("<br>", fout);
				break;
			default:
				fputc(*p, fout);
		}
512 513 514 515 516
}



static void
Bruce Momjian's avatar
Bruce Momjian committed
517 518 519 520
print_html_text(const char *title, const char * const * headers,
		const char * const * cells, const char * const * footers,
		const char *opt_align, bool opt_barebones, unsigned short int opt_border,
		const char *opt_table_attr,
521
		FILE *fout)
522
{
Bruce Momjian's avatar
Bruce Momjian committed
523 524
	unsigned int col_count = 0;
	unsigned int i;
Bruce Momjian's avatar
Bruce Momjian committed
525
	const char * const *ptr;
Bruce Momjian's avatar
Bruce Momjian committed
526 527 528 529 530 531 532 533 534 535 536 537 538

	fprintf(fout, "<table border=%d", opt_border);
	if (opt_table_attr)
		fprintf(fout, " %s", opt_table_attr);
	fputs(">\n", fout);

	/* print title */
	if (!opt_barebones && title)
	{
		fputs("  <caption>", fout);
		html_escaped_print(title, fout);
		fputs("</caption>\n", fout);
	}
539

Bruce Momjian's avatar
Bruce Momjian committed
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
	/* print headers and count columns */
	if (!opt_barebones)
		fputs("  <tr>\n", fout);
	for (i = 0, ptr = headers; *ptr; i++, ptr++)
	{
		col_count++;
		if (!opt_barebones)
		{
			fputs("    <th align=center>", fout);
			html_escaped_print(*ptr, fout);
			fputs("</th>\n", fout);
		}
	}
	if (!opt_barebones)
		fputs("  </tr>\n", fout);

	/* print cells */
	for (i = 0, ptr = cells; *ptr; i++, ptr++)
	{
		if (i % col_count == 0)
			fputs("  <tr valign=top>\n", fout);

		fprintf(fout, "    <td align=%s>", opt_align[(i) % col_count] == 'r' ? "right" : "left");
		if ((*ptr)[strspn(*ptr, " \t")] == '\0')		/* is string only
														 * whitespace? */
			fputs("&nbsp;", fout);
		else
			html_escaped_print(*ptr, fout);
		fputs("</td>\n", fout);
569

Bruce Momjian's avatar
Bruce Momjian committed
570 571 572
		if ((i + 1) % col_count == 0)
			fputs("  </tr>\n", fout);
	}
573

Bruce Momjian's avatar
Bruce Momjian committed
574
	fputs("</table>\n", fout);
575

Bruce Momjian's avatar
Bruce Momjian committed
576 577 578 579 580 581 582 583
	/* print footers */

	if (footers && !opt_barebones)
		for (ptr = footers; *ptr; ptr++)
		{
			html_escaped_print(*ptr, fout);
			fputs("<br>\n", fout);
		}
584

Bruce Momjian's avatar
Bruce Momjian committed
585
	fputc('\n', fout);
586 587 588 589 590
}



static void
Bruce Momjian's avatar
Bruce Momjian committed
591 592 593 594
print_html_vertical(const char *title, const char * const * headers,
		    const char * const * cells, const char * const * footers,
		    const char *opt_align, bool opt_barebones, unsigned short int opt_border,
		    const char *opt_table_attr,
Bruce Momjian's avatar
Bruce Momjian committed
595
					FILE *fout)
596
{
Bruce Momjian's avatar
Bruce Momjian committed
597 598 599
	unsigned int col_count = 0;
	unsigned int i;
	unsigned int record = 1;
Bruce Momjian's avatar
Bruce Momjian committed
600
	const char * const *ptr;
Bruce Momjian's avatar
Bruce Momjian committed
601 602 603 604 605 606 607 608 609 610 611 612 613

	fprintf(fout, "<table border=%d", opt_border);
	if (opt_table_attr)
		fprintf(fout, " %s", opt_table_attr);
	fputs(">\n", fout);

	/* print title */
	if (!opt_barebones && title)
	{
		fputs("  <caption>", fout);
		html_escaped_print(title, fout);
		fputs("</caption>\n", fout);
	}
614

Bruce Momjian's avatar
Bruce Momjian committed
615 616 617
	/* count columns */
	for (ptr = headers; *ptr; ptr++)
		col_count++;
618

Bruce Momjian's avatar
Bruce Momjian committed
619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640
	/* print records */
	for (i = 0, ptr = cells; *ptr; i++, ptr++)
	{
		if (i % col_count == 0)
		{
			if (!opt_barebones)
				fprintf(fout, "\n  <tr><td colspan=2 align=center>Record %d</td></tr>\n", record++);
			else
				fputs("\n  <tr><td colspan=2>&nbsp;</td></tr>\n", fout);
		}
		fputs("  <tr valign=top>\n"
			  "    <th>", fout);
		html_escaped_print(headers[i % col_count], fout);
		fputs("</th>\n", fout);

		fprintf(fout, "    <td align=%s>", opt_align[i % col_count] == 'r' ? "right" : "left");
		if ((*ptr)[strspn(*ptr, " \t")] == '\0')		/* is string only
														 * whitespace? */
			fputs("&nbsp;", fout);
		else
			html_escaped_print(*ptr, fout);
		fputs("</td>\n  </tr>\n", fout);
641 642
	}

Bruce Momjian's avatar
Bruce Momjian committed
643 644 645 646 647 648 649 650 651 652 653
	fputs("</table>\n", fout);

	/* print footers */
	if (footers && !opt_barebones)
		for (ptr = footers; *ptr; ptr++)
		{
			html_escaped_print(*ptr, fout);
			fputs("<br>\n", fout);
		}

	fputc('\n', fout);
654 655 656 657 658
}



/*************************/
Bruce Momjian's avatar
Bruce Momjian committed
659
/* LaTeX				 */
660 661 662 663
/*************************/


static void
Bruce Momjian's avatar
Bruce Momjian committed
664
latex_escaped_print(const char *in, FILE *fout)
665
{
Bruce Momjian's avatar
Bruce Momjian committed
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694
	const char *p;

	for (p = in; *p; p++)
		switch (*p)
		{
			case '&':
				fputs("\\&", fout);
				break;
			case '%':
				fputs("\\%", fout);
				break;
			case '$':
				fputs("\\$", fout);
				break;
			case '{':
				fputs("\\{", fout);
				break;
			case '}':
				fputs("\\}", fout);
				break;
			case '\\':
				fputs("\\backslash", fout);
				break;
			case '\n':
				fputs("\\\\", fout);
				break;
			default:
				fputc(*p, fout);
		}
695 696 697 698 699
}



static void
Bruce Momjian's avatar
Bruce Momjian committed
700 701 702
print_latex_text(const char *title, const char * const * headers,
		 const char * const * cells, const char * const * footers,
		 const char *opt_align, bool opt_barebones, unsigned short int opt_border,
703
		 FILE *fout)
704
{
Bruce Momjian's avatar
Bruce Momjian committed
705 706 707
	unsigned int col_count = 0;
	unsigned int i;
	const char *cp;
Bruce Momjian's avatar
Bruce Momjian committed
708
	const char * const *ptr;
Bruce Momjian's avatar
Bruce Momjian committed
709 710 711 712 713


	/* print title */
	if (!opt_barebones && title)
	{
Peter Eisentraut's avatar
Peter Eisentraut committed
714
		fputs("\\begin{center}\n", fout);
Bruce Momjian's avatar
Bruce Momjian committed
715
		latex_escaped_print(title, fout);
Peter Eisentraut's avatar
Peter Eisentraut committed
716
		fputs("\n\\end{center}\n\n", fout);
717 718
	}

Bruce Momjian's avatar
Bruce Momjian committed
719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741
	/* begin environment and set alignments and borders */
	fputs("\\begin{tabular}{", fout);
	if (opt_border == 0)
		fputs(opt_align, fout);
	else if (opt_border == 1)
	{
		for (cp = opt_align; *cp; cp++)
		{
			if (cp != opt_align)
				fputc('|', fout);
			fputc(*cp, fout);
		}
	}
	else if (opt_border == 2)
	{
		for (cp = opt_align; *cp; cp++)
		{
			fputc('|', fout);
			fputc(*cp, fout);
		}
		fputc('|', fout);
	}
	fputs("}\n", fout);
742

Bruce Momjian's avatar
Bruce Momjian committed
743 744
	if (!opt_barebones && opt_border == 2)
		fputs("\\hline\n", fout);
745

Bruce Momjian's avatar
Bruce Momjian committed
746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767
	/* print headers and count columns */
	for (i = 0, ptr = headers; *ptr; i++, ptr++)
	{
		col_count++;
		if (!opt_barebones)
		{
			if (i != 0)
				fputs(" & ", fout);
			latex_escaped_print(*ptr, fout);
		}
	}

	if (!opt_barebones)
	{
		fputs(" \\\\\n", fout);
		fputs("\\hline\n", fout);
	}

	/* print cells */
	for (i = 0, ptr = cells; *ptr; i++, ptr++)
	{
		latex_escaped_print(*ptr, fout);
768

Bruce Momjian's avatar
Bruce Momjian committed
769 770 771 772 773
		if ((i + 1) % col_count == 0)
			fputs(" \\\\\n", fout);
		else
			fputs(" & ", fout);
	}
774

Bruce Momjian's avatar
Bruce Momjian committed
775 776
	if (opt_border == 2)
		fputs("\\hline\n", fout);
777

Bruce Momjian's avatar
Bruce Momjian committed
778
	fputs("\\end{tabular}\n\n", fout);
779 780


Bruce Momjian's avatar
Bruce Momjian committed
781
	/* print footers */
782

Bruce Momjian's avatar
Bruce Momjian committed
783 784 785 786 787 788 789 790
	if (footers && !opt_barebones)
		for (ptr = footers; *ptr; ptr++)
		{
			latex_escaped_print(*ptr, fout);
			fputs(" \\\\\n", fout);
		}

	fputc('\n', fout);
791 792 793 794 795
}



static void
Bruce Momjian's avatar
Bruce Momjian committed
796 797 798
print_latex_vertical(const char *title, const char * const * headers,
		     const char * const * cells, const char * const * footers,
		     const char *opt_align, bool opt_barebones, unsigned short int opt_border,
799
		     FILE *fout)
800
{
Bruce Momjian's avatar
Bruce Momjian committed
801 802
	unsigned int col_count = 0;
	unsigned int i;
Bruce Momjian's avatar
Bruce Momjian committed
803
	const char * const *ptr;
Bruce Momjian's avatar
Bruce Momjian committed
804 805 806 807 808 809 810
	unsigned int record = 1;

	(void) opt_align;			/* currently unused parameter */

	/* print title */
	if (!opt_barebones && title)
	{
Peter Eisentraut's avatar
Peter Eisentraut committed
811
		fputs("\\begin{center}\n", fout);
Bruce Momjian's avatar
Bruce Momjian committed
812
		latex_escaped_print(title, fout);
Peter Eisentraut's avatar
Peter Eisentraut committed
813
		fputs("\n\\end{center}\n\n", fout);
814 815
	}

Bruce Momjian's avatar
Bruce Momjian committed
816 817 818 819 820 821 822 823 824
	/* begin environment and set alignments and borders */
	fputs("\\begin{tabular}{", fout);
	if (opt_border == 0)
		fputs("cl", fout);
	else if (opt_border == 1)
		fputs("c|l", fout);
	else if (opt_border == 2)
		fputs("|c|l|", fout);
	fputs("}\n", fout);
825 826


Bruce Momjian's avatar
Bruce Momjian committed
827 828 829
	/* count columns */
	for (ptr = headers; *ptr; ptr++)
		col_count++;
830 831


Bruce Momjian's avatar
Bruce Momjian committed
832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
	/* print records */
	for (i = 0, ptr = cells; *ptr; i++, ptr++)
	{
		/* new record */
		if (i % col_count == 0)
		{
			if (!opt_barebones)
			{
				if (opt_border == 2)
					fputs("\\hline\n", fout);
				fprintf(fout, "\\multicolumn{2}{c}{Record %d} \\\\\n", record++);
			}
			if (opt_border >= 1)
				fputs("\\hline\n", fout);
		}
847

Bruce Momjian's avatar
Bruce Momjian committed
848 849 850 851
		latex_escaped_print(headers[i % col_count], fout);
		fputs(" & ", fout);
		latex_escaped_print(*ptr, fout);
		fputs(" \\\\\n", fout);
852 853
	}

Bruce Momjian's avatar
Bruce Momjian committed
854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869
	if (opt_border == 2)
		fputs("\\hline\n", fout);

	fputs("\\end{tabular}\n\n", fout);


	/* print footers */

	if (footers && !opt_barebones)
		for (ptr = footers; *ptr; ptr++)
		{
			latex_escaped_print(*ptr, fout);
			fputs(" \\\\\n", fout);
		}

	fputc('\n', fout);
870 871 872 873 874 875 876 877
}






/********************************/
878
/* Public functions		*/
879 880 881 882
/********************************/


void
Bruce Momjian's avatar
Bruce Momjian committed
883 884 885 886
printTable(const char *title,
	   const char * const * headers,
	   const char * const * cells,
	   const char * const * footers,
887 888
	   const char *align,
	   const printTableOpt * opt, FILE *fout)
889
{
Bruce Momjian's avatar
Bruce Momjian committed
890
	const char *default_footer[] = {NULL};
Bruce Momjian's avatar
Bruce Momjian committed
891 892 893
	unsigned short int border = opt->border;
	FILE	   *pager = NULL,
			   *output;
894 895


Bruce Momjian's avatar
Bruce Momjian committed
896 897
	if (opt->format == PRINT_NOTHING)
		return;
898

Bruce Momjian's avatar
Bruce Momjian committed
899 900
	if (!footers)
		footers = default_footer;
901

Bruce Momjian's avatar
Bruce Momjian committed
902 903
	if (opt->format != PRINT_HTML && border > 2)
		border = 2;
904 905


Bruce Momjian's avatar
Bruce Momjian committed
906 907
	/* check whether we need / can / are supposed to use pager */
	if (fout == stdout && opt->pager
908
#ifndef WIN32
Bruce Momjian's avatar
Bruce Momjian committed
909 910 911
		&&
		isatty(fileno(stdin)) &&
		isatty(fileno(stdout))
912
#endif
Bruce Momjian's avatar
Bruce Momjian committed
913 914 915
		)
	{
		const char *pagerprog;
916

Bruce Momjian's avatar
Bruce Momjian committed
917 918 919 920
#ifdef TIOCGWINSZ
		unsigned int col_count = 0,
					row_count = 0,
					lines;
Bruce Momjian's avatar
Bruce Momjian committed
921
		const char * const *ptr;
Bruce Momjian's avatar
Bruce Momjian committed
922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939
		int			result;
		struct winsize screen_size;

		/* rough estimate of columns and rows */
		if (headers)
			for (ptr = headers; *ptr; ptr++)
				col_count++;
		if (cells)
			for (ptr = cells; *ptr; ptr++)
				row_count++;
		row_count /= col_count;

		if (opt->expanded)
			lines = (col_count + 1) * row_count;
		else
			lines = row_count + 1;
		if (!opt->tuples_only)
			lines += 5;
940

Bruce Momjian's avatar
Bruce Momjian committed
941 942 943
		result = ioctl(fileno(stdout), TIOCGWINSZ, &screen_size);
		if (result == -1 || lines > screen_size.ws_row)
		{
944
#endif
Bruce Momjian's avatar
Bruce Momjian committed
945 946 947 948
			pagerprog = getenv("PAGER");
			if (!pagerprog)
				pagerprog = DEFAULT_PAGER;
			pager = popen(pagerprog, "w");
949
#ifdef TIOCGWINSZ
Bruce Momjian's avatar
Bruce Momjian committed
950
		}
951
#endif
Bruce Momjian's avatar
Bruce Momjian committed
952
	}
953

Bruce Momjian's avatar
Bruce Momjian committed
954 955 956
	if (pager)
	{
		output = pager;
Bruce Momjian's avatar
Hi!  
Bruce Momjian committed
957
#ifndef WIN32
Bruce Momjian's avatar
Bruce Momjian committed
958
		pqsignal(SIGPIPE, SIG_IGN);
Bruce Momjian's avatar
Hi!  
Bruce Momjian committed
959
#endif
Bruce Momjian's avatar
Bruce Momjian committed
960
	}
961
	else
Bruce Momjian's avatar
Bruce Momjian committed
962 963 964 965 966 967 968 969 970
		output = fout;


	/* print the stuff */

	switch (opt->format)
	{
		case PRINT_UNALIGNED:
			if (opt->expanded)
Peter Eisentraut's avatar
Peter Eisentraut committed
971
				print_unaligned_vertical(title, headers, cells, footers, opt->fieldSep, opt->recordSep, opt->tuples_only, output);
Bruce Momjian's avatar
Bruce Momjian committed
972
			else
Peter Eisentraut's avatar
Peter Eisentraut committed
973
				print_unaligned_text(title, headers, cells, footers, opt->fieldSep, opt->recordSep, opt->tuples_only, output);
Bruce Momjian's avatar
Bruce Momjian committed
974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999
			break;
		case PRINT_ALIGNED:
			if (opt->expanded)
				print_aligned_vertical(title, headers, cells, footers, opt->tuples_only, border, output);
			else
				print_aligned_text(title, headers, cells, footers, align, opt->tuples_only, border, output);
			break;
		case PRINT_HTML:
			if (opt->expanded)
				print_html_vertical(title, headers, cells, footers, align, opt->tuples_only, border, opt->tableAttr, output);
			else
				print_html_text(title, headers, cells, footers, align, opt->tuples_only, border, opt->tableAttr, output);
			break;
		case PRINT_LATEX:
			if (opt->expanded)
				print_latex_vertical(title, headers, cells, footers, align, opt->tuples_only, border, output);
			else
				print_latex_text(title, headers, cells, footers, align, opt->tuples_only, border, output);
			break;
		default:
			fprintf(stderr, "+ Oops, you shouldn't see this!\n");
	}

	if (pager)
	{
		pclose(pager);
Bruce Momjian's avatar
Hi!  
Bruce Momjian committed
1000
#ifndef WIN32
Bruce Momjian's avatar
Bruce Momjian committed
1001
		pqsignal(SIGPIPE, SIG_DFL);
Bruce Momjian's avatar
Hi!  
Bruce Momjian committed
1002 1003
#endif

Bruce Momjian's avatar
Bruce Momjian committed
1004
	}
1005 1006 1007 1008 1009
}



void
Bruce Momjian's avatar
Bruce Momjian committed
1010
printQuery(const PGresult *result, const printQueryOpt * opt, FILE *fout)
1011
{
Bruce Momjian's avatar
Bruce Momjian committed
1012
	int			nfields;
Bruce Momjian's avatar
Bruce Momjian committed
1013 1014
	const char **headers;
	const char **cells;
1015 1016
	char **footers;
	char 	   *align;
Bruce Momjian's avatar
Bruce Momjian committed
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028
	int			i;

	/* extract headers */

	nfields = PQnfields(result);

	headers = calloc(nfields + 1, sizeof(*headers));
	if (!headers)
	{
		perror("calloc");
		exit(EXIT_FAILURE);
	}
1029

Bruce Momjian's avatar
Bruce Momjian committed
1030 1031
	for (i = 0; i < nfields; i++)
		headers[i] = PQfname(result, i);
1032

Bruce Momjian's avatar
Bruce Momjian committed
1033
	/* set cells */
1034

Bruce Momjian's avatar
Bruce Momjian committed
1035 1036 1037 1038 1039 1040
	cells = calloc(nfields * PQntuples(result) + 1, sizeof(*cells));
	if (!cells)
	{
		perror("calloc");
		exit(EXIT_FAILURE);
	}
1041

Bruce Momjian's avatar
Bruce Momjian committed
1042 1043 1044 1045 1046 1047 1048
	for (i = 0; i < nfields * PQntuples(result); i++)
	{
		if (PQgetisnull(result, i / nfields, i % nfields))
			cells[i] = opt->nullPrint ? opt->nullPrint : "";
		else
			cells[i] = PQgetvalue(result, i / nfields, i % nfields);
	}
1049

Bruce Momjian's avatar
Bruce Momjian committed
1050
	/* set footers */
1051

Bruce Momjian's avatar
Bruce Momjian committed
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061
	if (opt->footers)
		footers = opt->footers;
	else if (!opt->topt.expanded)
	{
		footers = calloc(2, sizeof(*footers));
		if (!footers)
		{
			perror("calloc");
			exit(EXIT_FAILURE);
		}
1062

Bruce Momjian's avatar
Bruce Momjian committed
1063 1064 1065 1066 1067 1068
		footers[0] = malloc(100);
		if (PQntuples(result) == 1)
			strcpy(footers[0], "(1 row)");
		else
			sprintf(footers[0], "(%d rows)", PQntuples(result));
	}
1069
	else
Bruce Momjian's avatar
Bruce Momjian committed
1070
		footers = NULL;
1071

Bruce Momjian's avatar
Bruce Momjian committed
1072
	/* set alignment */
1073

Bruce Momjian's avatar
Bruce Momjian committed
1074 1075 1076 1077 1078
	align = calloc(nfields + 1, sizeof(*align));
	if (!align)
	{
		perror("calloc");
		exit(EXIT_FAILURE);
1079 1080
	}

Bruce Momjian's avatar
Bruce Momjian committed
1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
	for (i = 0; i < nfields; i++)
	{
		Oid			ftype = PQftype(result, i);

		if (ftype == 20 ||		/* int8 */
			ftype == 21 ||		/* int2 */
			ftype == 23 ||		/* int4 */
			(ftype >= 26 && ftype <= 30) ||		/* ?id */
			ftype == 700 ||		/* float4 */
			ftype == 701 ||		/* float8 */
			ftype == 790 ||		/* money */
			ftype == 1700		/* numeric */
			)
			align[i] = 'r';
		else
			align[i] = 'l';
	}
1098

Bruce Momjian's avatar
Bruce Momjian committed
1099
	/* call table printer */
1100

Bruce Momjian's avatar
Bruce Momjian committed
1101 1102 1103
	printTable(opt->title, headers, cells,
		   footers ? (const char * const *)footers : (const char * const *)(opt->footers),
		   align, &opt->topt, fout);
1104

Bruce Momjian's avatar
Bruce Momjian committed
1105 1106 1107 1108 1109 1110 1111
	free(headers);
	free(cells);
	if (footers)
	{
		free(footers[0]);
		free(footers);
	}
1112 1113 1114 1115
}


/* the end */