~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/bin/psql/print.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * psql - the PostgreSQL interactive terminal
 
3
 *
 
4
 * Copyright (c) 2000-2005, PostgreSQL Global Development Group
 
5
 *
 
6
 * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.54 2005-01-01 05:43:08 momjian Exp $
 
7
 */
 
8
#include "postgres_fe.h"
 
9
#include "common.h"
 
10
#include "print.h"
 
11
 
 
12
#include <math.h>
 
13
#include <signal.h>
 
14
 
 
15
#ifndef WIN32_CLIENT_ONLY
 
16
#include <unistd.h>
 
17
#endif
 
18
 
 
19
#ifndef WIN32
 
20
#include <sys/ioctl.h>                  /* for ioctl() */
 
21
#endif
 
22
 
 
23
#ifdef HAVE_TERMIOS_H
 
24
#include <termios.h>
 
25
#endif
 
26
 
 
27
#include "pqsignal.h"
 
28
#include "libpq-fe.h"
 
29
 
 
30
#include "mbprint.h"
 
31
 
 
32
/*************************/
 
33
/* Unaligned text                */
 
34
/*************************/
 
35
 
 
36
 
 
37
static void
 
38
print_unaligned_text(const char *title, const char *const * headers,
 
39
                                  const char *const * cells, const char *const * footers,
 
40
 const char *opt_fieldsep, const char *opt_recordsep, bool opt_barebones,
 
41
                                         FILE *fout)
 
42
{
 
43
        unsigned int col_count = 0;
 
44
        unsigned int i;
 
45
        const char *const * ptr;
 
46
        bool            need_recordsep = false;
 
47
 
 
48
        if (!opt_fieldsep)
 
49
                opt_fieldsep = "";
 
50
        if (!opt_recordsep)
 
51
                opt_recordsep = "";
 
52
 
 
53
        /* print title */
 
54
        if (!opt_barebones && title)
 
55
                fprintf(fout, "%s%s", title, opt_recordsep);
 
56
 
 
57
        /* print headers and count columns */
 
58
        for (ptr = headers; *ptr; ptr++)
 
59
        {
 
60
                col_count++;
 
61
                if (!opt_barebones)
 
62
                {
 
63
                        if (col_count > 1)
 
64
                                fputs(opt_fieldsep, fout);
 
65
                        fputs(*ptr, fout);
 
66
                }
 
67
        }
 
68
        if (!opt_barebones)
 
69
                need_recordsep = true;
 
70
 
 
71
        /* print cells */
 
72
        i = 0;
 
73
        for (ptr = cells; *ptr; ptr++)
 
74
        {
 
75
                if (need_recordsep)
 
76
                {
 
77
                        fputs(opt_recordsep, fout);
 
78
                        need_recordsep = false;
 
79
                }
 
80
                fputs(*ptr, fout);
 
81
                if ((i + 1) % col_count)
 
82
                        fputs(opt_fieldsep, fout);
 
83
                else
 
84
                        need_recordsep = true;
 
85
                i++;
 
86
        }
 
87
 
 
88
        /* print footers */
 
89
 
 
90
        if (!opt_barebones && footers)
 
91
                for (ptr = footers; *ptr; ptr++)
 
92
                {
 
93
                        if (need_recordsep)
 
94
                        {
 
95
                                fputs(opt_recordsep, fout);
 
96
                                need_recordsep = false;
 
97
                        }
 
98
                        fputs(*ptr, fout);
 
99
                        need_recordsep = true;
 
100
                }
 
101
 
 
102
        /* the last record needs to be concluded with a newline */
 
103
        if (need_recordsep)
 
104
                fputc('\n', fout);
 
105
}
 
106
 
 
107
 
 
108
 
 
109
static void
 
110
print_unaligned_vertical(const char *title, const char *const * headers,
 
111
                                  const char *const * cells, const char *const * footers,
 
112
 const char *opt_fieldsep, const char *opt_recordsep, bool opt_barebones,
 
113
                                                 FILE *fout)
 
114
{
 
115
        unsigned int col_count = 0;
 
116
        unsigned int i;
 
117
        const char *const * ptr;
 
118
 
 
119
        if (!opt_fieldsep)
 
120
                opt_fieldsep = "";
 
121
        if (!opt_recordsep)
 
122
                opt_recordsep = "";
 
123
 
 
124
        /* print title */
 
125
        if (!opt_barebones && title)
 
126
                fputs(title, fout);
 
127
 
 
128
        /* count columns */
 
129
        for (ptr = headers; *ptr; ptr++)
 
130
                col_count++;
 
131
 
 
132
        /* print records */
 
133
        for (i = 0, ptr = cells; *ptr; i++, ptr++)
 
134
        {
 
135
                if (i != 0 || (!opt_barebones && title))
 
136
                {
 
137
                        fputs(opt_recordsep, fout);
 
138
                        if (i % col_count == 0)
 
139
                                fputs(opt_recordsep, fout);             /* another one */
 
140
                }
 
141
 
 
142
                fputs(headers[i % col_count], fout);
 
143
                fputs(opt_fieldsep, fout);
 
144
                fputs(*ptr, fout);
 
145
        }
 
146
 
 
147
        /* print footers */
 
148
        if (!opt_barebones && footers && *footers)
 
149
        {
 
150
                fputs(opt_recordsep, fout);
 
151
                for (ptr = footers; *ptr; ptr++)
 
152
                {
 
153
                        fputs(opt_recordsep, fout);
 
154
                        fputs(*ptr, fout);
 
155
                }
 
156
        }
 
157
 
 
158
        fputc('\n', fout);
 
159
}
 
160
 
 
161
 
 
162
 
 
163
/********************/
 
164
/* Aligned text         */
 
165
/********************/
 
166
 
 
167
 
 
168
/* draw "line" */
 
169
static void
 
170
_print_horizontal_line(const unsigned int col_count, const unsigned int *widths, unsigned short border, FILE *fout)
 
171
{
 
172
        unsigned int i,
 
173
                                j;
 
174
 
 
175
        if (border == 1)
 
176
                fputc('-', fout);
 
177
        else if (border == 2)
 
178
                fputs("+-", fout);
 
179
 
 
180
        for (i = 0; i < col_count; i++)
 
181
        {
 
182
                for (j = 0; j < widths[i]; j++)
 
183
                        fputc('-', fout);
 
184
 
 
185
                if (i < col_count - 1)
 
186
                {
 
187
                        if (border == 0)
 
188
                                fputc(' ', fout);
 
189
                        else
 
190
                                fputs("-+-", fout);
 
191
                }
 
192
        }
 
193
 
 
194
        if (border == 2)
 
195
                fputs("-+", fout);
 
196
        else if (border == 1)
 
197
                fputc('-', fout);
 
198
 
 
199
        fputc('\n', fout);
 
200
}
 
201
 
 
202
 
 
203
 
 
204
static void
 
205
print_aligned_text(const char *title, const char *const * headers,
 
206
                                   const char *const * cells, const char *const * footers,
 
207
                                   const char *opt_align, bool opt_barebones,
 
208
                                   unsigned short int opt_border, int encoding,
 
209
                                   FILE *fout)
 
210
{
 
211
        unsigned int col_count = 0;
 
212
        unsigned int cell_count = 0;
 
213
        unsigned int *head_w,
 
214
                           *cell_w;
 
215
        unsigned int i,
 
216
                                tmp;
 
217
        unsigned int *widths,
 
218
                                total_w;
 
219
        const char *const * ptr;
 
220
 
 
221
        /* count columns */
 
222
        for (ptr = headers; *ptr; ptr++)
 
223
                col_count++;
 
224
 
 
225
        if (col_count > 0)
 
226
        {
 
227
                widths = calloc(col_count, sizeof(*widths));
 
228
                if (!widths)
 
229
                {
 
230
                        fprintf(stderr, gettext("out of memory\n"));
 
231
                        exit(EXIT_FAILURE);
 
232
                }
 
233
 
 
234
                head_w = calloc(col_count, sizeof(*head_w));
 
235
                if (!head_w)
 
236
                {
 
237
                        fprintf(stderr, gettext("out of memory\n"));
 
238
                        exit(EXIT_FAILURE);
 
239
                }
 
240
        }
 
241
        else
 
242
        {
 
243
                widths = NULL;
 
244
                head_w = NULL;
 
245
        }
 
246
 
 
247
        /* count cells (rows * cols) */
 
248
        for (ptr = cells; *ptr; ptr++)
 
249
                cell_count++;
 
250
 
 
251
        if (cell_count > 0)
 
252
        {
 
253
                cell_w = calloc(cell_count, sizeof(*cell_w));
 
254
                if (!cell_w)
 
255
                {
 
256
                        fprintf(stderr, gettext("out of memory\n"));
 
257
                        exit(EXIT_FAILURE);
 
258
                }
 
259
        }
 
260
        else
 
261
                cell_w = NULL;
 
262
 
 
263
        /* calc column widths */
 
264
        for (i = 0; i < col_count; i++)
 
265
        {
 
266
                tmp = pg_wcswidth((unsigned char *) headers[i], strlen(headers[i]), encoding);
 
267
                if (tmp > widths[i])
 
268
                        widths[i] = tmp;
 
269
                head_w[i] = tmp;
 
270
        }
 
271
 
 
272
        for (i = 0, ptr = cells; *ptr; ptr++, i++)
 
273
        {
 
274
                tmp = pg_wcswidth((unsigned char *) *ptr, strlen(*ptr), encoding);
 
275
                if (tmp > widths[i % col_count])
 
276
                        widths[i % col_count] = tmp;
 
277
                cell_w[i] = tmp;
 
278
        }
 
279
 
 
280
        if (opt_border == 0)
 
281
                total_w = col_count - 1;
 
282
        else if (opt_border == 1)
 
283
                total_w = col_count * 3 - 1;
 
284
        else
 
285
                total_w = col_count * 3 + 1;
 
286
 
 
287
        for (i = 0; i < col_count; i++)
 
288
                total_w += widths[i];
 
289
 
 
290
        /* print title */
 
291
        if (title && !opt_barebones)
 
292
        {
 
293
                tmp = pg_wcswidth((unsigned char *) title, strlen(title), encoding);
 
294
                if (tmp >= total_w)
 
295
                        fprintf(fout, "%s\n", title);
 
296
                else
 
297
                        fprintf(fout, "%-*s%s\n", (total_w - tmp) / 2, "", title);
 
298
        }
 
299
 
 
300
        /* print headers */
 
301
        if (!opt_barebones)
 
302
        {
 
303
                if (opt_border == 2)
 
304
                        _print_horizontal_line(col_count, widths, opt_border, fout);
 
305
 
 
306
                if (opt_border == 2)
 
307
                        fputs("| ", fout);
 
308
                else if (opt_border == 1)
 
309
                        fputc(' ', fout);
 
310
 
 
311
                for (i = 0; i < col_count; i++)
 
312
                {
 
313
                        unsigned int nbspace;
 
314
 
 
315
                        nbspace = widths[i] - head_w[i];
 
316
 
 
317
                        /* centered */
 
318
                        fprintf(fout, "%-*s%s%-*s",
 
319
                                        nbspace / 2, "", headers[i], (nbspace + 1) / 2, "");
 
320
 
 
321
                        if (i < col_count - 1)
 
322
                        {
 
323
                                if (opt_border == 0)
 
324
                                        fputc(' ', fout);
 
325
                                else
 
326
                                        fputs(" | ", fout);
 
327
                        }
 
328
                }
 
329
 
 
330
                if (opt_border == 2)
 
331
                        fputs(" |", fout);
 
332
                else if (opt_border == 1)
 
333
                        fputc(' ', fout);;
 
334
                fputc('\n', fout);
 
335
 
 
336
                _print_horizontal_line(col_count, widths, opt_border, fout);
 
337
        }
 
338
 
 
339
        /* print cells */
 
340
        for (i = 0, ptr = cells; *ptr; i++, ptr++)
 
341
        {
 
342
                /* beginning of line */
 
343
                if (i % col_count == 0)
 
344
                {
 
345
                        if (opt_border == 2)
 
346
                                fputs("| ", fout);
 
347
                        else if (opt_border == 1)
 
348
                                fputc(' ', fout);
 
349
                }
 
350
 
 
351
                /* content */
 
352
                if (opt_align[i % col_count] == 'r')
 
353
                {
 
354
                        fprintf(fout, "%*s%s",
 
355
                                        widths[i % col_count] - cell_w[i], "", cells[i]);
 
356
                }
 
357
                else
 
358
                {
 
359
                        if ((i + 1) % col_count == 0 && opt_border != 2)
 
360
                                fputs(cells[i], fout);
 
361
                        else
 
362
                                fprintf(fout, "%-s%*s", cells[i],
 
363
                                                widths[i % col_count] - cell_w[i], "");
 
364
                }
 
365
 
 
366
                /* divider */
 
367
                if ((i + 1) % col_count)
 
368
                {
 
369
                        if (opt_border == 0)
 
370
                                fputc(' ', fout);
 
371
                        else
 
372
                                fputs(" | ", fout);
 
373
                }
 
374
                /* end of line */
 
375
                else
 
376
                {
 
377
                        if (opt_border == 2)
 
378
                                fputs(" |", fout);
 
379
                        fputc('\n', fout);
 
380
                }
 
381
        }
 
382
 
 
383
        if (opt_border == 2)
 
384
                _print_horizontal_line(col_count, widths, opt_border, fout);
 
385
 
 
386
        /* print footers */
 
387
        if (footers && !opt_barebones)
 
388
                for (ptr = footers; *ptr; ptr++)
 
389
                        fprintf(fout, "%s\n", *ptr);
 
390
 
 
391
#ifndef __MINGW32__
 
392
 
 
393
        /*
 
394
         * for some reason MinGW outputs an extra newline, so this supresses
 
395
         * it
 
396
         */
 
397
        fputc('\n', fout);
 
398
#endif
 
399
 
 
400
        /* clean up */
 
401
        free(cell_w);
 
402
        free(head_w);
 
403
        free(widths);
 
404
}
 
405
 
 
406
 
 
407
 
 
408
static void
 
409
print_aligned_vertical(const char *title, const char *const * headers,
 
410
                                  const char *const * cells, const char *const * footers,
 
411
                                           bool opt_barebones, unsigned short int opt_border,
 
412
                                           int encoding, FILE *fout)
 
413
{
 
414
        unsigned int col_count = 0;
 
415
        unsigned int record = 1;
 
416
        const char *const * ptr;
 
417
        unsigned int i,
 
418
                                tmp = 0,
 
419
                                hwidth = 0,
 
420
                                dwidth = 0;
 
421
        char       *divider;
 
422
        unsigned int cell_count = 0;
 
423
        unsigned int *cell_w,
 
424
                           *head_w;
 
425
 
 
426
        if (cells[0] == NULL)
 
427
        {
 
428
                puts(gettext("(No rows)\n"));
 
429
                return;
 
430
        }
 
431
 
 
432
        /* count headers and find longest one */
 
433
        for (ptr = headers; *ptr; ptr++)
 
434
                col_count++;
 
435
        if (col_count > 0)
 
436
        {
 
437
                head_w = calloc(col_count, sizeof(*head_w));
 
438
                if (!head_w)
 
439
                {
 
440
                        fprintf(stderr, gettext("out of memory\n"));
 
441
                        exit(EXIT_FAILURE);
 
442
                }
 
443
        }
 
444
        else
 
445
                head_w = NULL;
 
446
 
 
447
        for (i = 0; i < col_count; i++)
 
448
        {
 
449
                tmp = pg_wcswidth((unsigned char *) headers[i], strlen(headers[i]), encoding);
 
450
                if (tmp > hwidth)
 
451
                        hwidth = tmp;
 
452
                head_w[i] = tmp;
 
453
        }
 
454
 
 
455
        /* Count cells, find their lengths */
 
456
        for (ptr = cells; *ptr; ptr++)
 
457
                cell_count++;
 
458
 
 
459
        if (cell_count > 0)
 
460
        {
 
461
                cell_w = calloc(cell_count, sizeof(*cell_w));
 
462
                if (!cell_w)
 
463
                {
 
464
                        fprintf(stderr, gettext("out of memory\n"));
 
465
                        exit(EXIT_FAILURE);
 
466
                }
 
467
        }
 
468
        else
 
469
                cell_w = NULL;
 
470
 
 
471
        /* find longest data cell */
 
472
        for (i = 0, ptr = cells; *ptr; ptr++, i++)
 
473
        {
 
474
                tmp = pg_wcswidth((unsigned char *) *ptr, strlen(*ptr), encoding);
 
475
                if (tmp > dwidth)
 
476
                        dwidth = tmp;
 
477
                cell_w[i] = tmp;
 
478
        }
 
479
 
 
480
        /* print title */
 
481
        if (!opt_barebones && title)
 
482
                fprintf(fout, "%s\n", title);
 
483
 
 
484
        /* make horizontal border */
 
485
        divider = malloc(hwidth + dwidth + 10);
 
486
        if (!divider)
 
487
        {
 
488
                fprintf(stderr, gettext("out of memory\n"));
 
489
                exit(EXIT_FAILURE);
 
490
        }
 
491
        divider[0] = '\0';
 
492
        if (opt_border == 2)
 
493
                strcat(divider, "+-");
 
494
        for (i = 0; i < hwidth; i++)
 
495
                strcat(divider, opt_border > 0 ? "-" : " ");
 
496
        if (opt_border > 0)
 
497
                strcat(divider, "-+-");
 
498
        else
 
499
                strcat(divider, " ");
 
500
        for (i = 0; i < dwidth; i++)
 
501
                strcat(divider, opt_border > 0 ? "-" : " ");
 
502
        if (opt_border == 2)
 
503
                strcat(divider, "-+");
 
504
 
 
505
        /* print records */
 
506
        for (i = 0, ptr = cells; *ptr; i++, ptr++)
 
507
        {
 
508
                if (i % col_count == 0)
 
509
                {
 
510
                        if (!opt_barebones)
 
511
                        {
 
512
                                char       *record_str = malloc(32);
 
513
                                size_t          record_str_len;
 
514
 
 
515
                                if (!record_str)
 
516
                                {
 
517
                                        fprintf(stderr, gettext("out of memory\n"));
 
518
                                        exit(EXIT_FAILURE);
 
519
                                }
 
520
 
 
521
                                if (opt_border == 0)
 
522
                                        snprintf(record_str, 32, "* Record %d", record++);
 
523
                                else
 
524
                                        snprintf(record_str, 32, "[ RECORD %d ]", record++);
 
525
                                record_str_len = strlen(record_str);
 
526
 
 
527
                                if (record_str_len + opt_border > strlen(divider))
 
528
                                        fprintf(fout, "%.*s%s\n", opt_border, divider, record_str);
 
529
                                else
 
530
                                {
 
531
                                        char       *div_copy = strdup(divider);
 
532
 
 
533
                                        if (!div_copy)
 
534
                                        {
 
535
                                                fprintf(stderr, gettext("out of memory\n"));
 
536
                                                exit(EXIT_FAILURE);
 
537
                                        }
 
538
 
 
539
                                        strncpy(div_copy + opt_border, record_str, record_str_len);
 
540
                                        fprintf(fout, "%s\n", div_copy);
 
541
                                        free(div_copy);
 
542
                                }
 
543
                                free(record_str);
 
544
                        }
 
545
                        else if (i != 0 || opt_border == 2)
 
546
                                fprintf(fout, "%s\n", divider);
 
547
                }
 
548
 
 
549
                if (opt_border == 2)
 
550
                        fputs("| ", fout);
 
551
                fprintf(fout, "%-s%*s", headers[i % col_count],
 
552
                                hwidth - head_w[i % col_count], "");
 
553
 
 
554
                if (opt_border > 0)
 
555
                        fputs(" | ", fout);
 
556
                else
 
557
                        fputs(" ", fout);
 
558
 
 
559
                if (opt_border < 2)
 
560
                        fprintf(fout, "%s\n", *ptr);
 
561
                else
 
562
                        fprintf(fout, "%-s%*s |\n", *ptr, dwidth - cell_w[i], "");
 
563
        }
 
564
 
 
565
        if (opt_border == 2)
 
566
                fprintf(fout, "%s\n", divider);
 
567
 
 
568
        /* print footers */
 
569
 
 
570
        if (!opt_barebones && footers && *footers)
 
571
        {
 
572
                if (opt_border < 2)
 
573
                        fputc('\n', fout);
 
574
                for (ptr = footers; *ptr; ptr++)
 
575
                        fprintf(fout, "%s\n", *ptr);
 
576
        }
 
577
 
 
578
        fputc('\n', fout);
 
579
        free(divider);
 
580
 
 
581
        free(cell_w);
 
582
        free(head_w);
 
583
}
 
584
 
 
585
 
 
586
 
 
587
 
 
588
 
 
589
/**********************/
 
590
/* HTML printing ******/
 
591
/**********************/
 
592
 
 
593
 
 
594
void
 
595
html_escaped_print(const char *in, FILE *fout)
 
596
{
 
597
        const char *p;
 
598
 
 
599
        for (p = in; *p; p++)
 
600
                switch (*p)
 
601
                {
 
602
                        case '&':
 
603
                                fputs("&amp;", fout);
 
604
                                break;
 
605
                        case '<':
 
606
                                fputs("&lt;", fout);
 
607
                                break;
 
608
                        case '>':
 
609
                                fputs("&gt;", fout);
 
610
                                break;
 
611
                        case '\n':
 
612
                                fputs("<br />\n", fout);
 
613
                                break;
 
614
                        case '"':
 
615
                                fputs("&quot;", fout);
 
616
                                break;
 
617
                        case '\'':
 
618
                                fputs("&apos;", fout);
 
619
                                break;
 
620
                        default:
 
621
                                fputc(*p, fout);
 
622
                }
 
623
}
 
624
 
 
625
 
 
626
 
 
627
static void
 
628
print_html_text(const char *title, const char *const * headers,
 
629
                                const char *const * cells, const char *const * footers,
 
630
const char *opt_align, bool opt_barebones, unsigned short int opt_border,
 
631
                                const char *opt_table_attr,
 
632
                                FILE *fout)
 
633
{
 
634
        unsigned int col_count = 0;
 
635
        unsigned int i;
 
636
        const char *const * ptr;
 
637
 
 
638
        fprintf(fout, "<table border=\"%d\"", opt_border);
 
639
        if (opt_table_attr)
 
640
                fprintf(fout, " %s", opt_table_attr);
 
641
        fputs(">\n", fout);
 
642
 
 
643
        /* print title */
 
644
        if (!opt_barebones && title)
 
645
        {
 
646
                fputs("  <caption>", fout);
 
647
                html_escaped_print(title, fout);
 
648
                fputs("</caption>\n", fout);
 
649
        }
 
650
 
 
651
        /* print headers and count columns */
 
652
        if (!opt_barebones)
 
653
                fputs("  <tr>\n", fout);
 
654
        for (i = 0, ptr = headers; *ptr; i++, ptr++)
 
655
        {
 
656
                col_count++;
 
657
                if (!opt_barebones)
 
658
                {
 
659
                        fputs("    <th align=\"center\">", fout);
 
660
                        html_escaped_print(*ptr, fout);
 
661
                        fputs("</th>\n", fout);
 
662
                }
 
663
        }
 
664
        if (!opt_barebones)
 
665
                fputs("  </tr>\n", fout);
 
666
 
 
667
        /* print cells */
 
668
        for (i = 0, ptr = cells; *ptr; i++, ptr++)
 
669
        {
 
670
                if (i % col_count == 0)
 
671
                        fputs("  <tr valign=\"top\">\n", fout);
 
672
 
 
673
                fprintf(fout, "    <td align=\"%s\">", opt_align[(i) % col_count] == 'r' ? "right" : "left");
 
674
                if ((*ptr)[strspn(*ptr, " \t")] == '\0')                /* is string only
 
675
                                                                                                                 * whitespace? */
 
676
                        fputs("&nbsp; ", fout);
 
677
                else
 
678
                        html_escaped_print(*ptr, fout);
 
679
                fputs("</td>\n", fout);
 
680
 
 
681
                if ((i + 1) % col_count == 0)
 
682
                        fputs("  </tr>\n", fout);
 
683
        }
 
684
 
 
685
        fputs("</table>\n", fout);
 
686
 
 
687
        /* print footers */
 
688
 
 
689
        if (!opt_barebones && footers && *footers)
 
690
        {
 
691
                fputs("<p>", fout);
 
692
                for (ptr = footers; *ptr; ptr++)
 
693
                {
 
694
                        html_escaped_print(*ptr, fout);
 
695
                        fputs("<br />\n", fout);
 
696
                }
 
697
                fputs("</p>", fout);
 
698
        }
 
699
        fputc('\n', fout);
 
700
}
 
701
 
 
702
 
 
703
 
 
704
static void
 
705
print_html_vertical(const char *title, const char *const * headers,
 
706
                                  const char *const * cells, const char *const * footers,
 
707
const char *opt_align, bool opt_barebones, unsigned short int opt_border,
 
708
                                        const char *opt_table_attr,
 
709
                                        FILE *fout)
 
710
{
 
711
        unsigned int col_count = 0;
 
712
        unsigned int i;
 
713
        unsigned int record = 1;
 
714
        const char *const * ptr;
 
715
 
 
716
        fprintf(fout, "<table border=\"%d\"", opt_border);
 
717
        if (opt_table_attr)
 
718
                fprintf(fout, " %s", opt_table_attr);
 
719
        fputs(">\n", fout);
 
720
 
 
721
        /* print title */
 
722
        if (!opt_barebones && title)
 
723
        {
 
724
                fputs("  <caption>", fout);
 
725
                html_escaped_print(title, fout);
 
726
                fputs("</caption>\n", fout);
 
727
        }
 
728
 
 
729
        /* count columns */
 
730
        for (ptr = headers; *ptr; ptr++)
 
731
                col_count++;
 
732
 
 
733
        /* print records */
 
734
        for (i = 0, ptr = cells; *ptr; i++, ptr++)
 
735
        {
 
736
                if (i % col_count == 0)
 
737
                {
 
738
                        if (!opt_barebones)
 
739
                                fprintf(fout, "\n  <tr><td colspan=\"2\" align=\"center\">Record %d</td></tr>\n", record++);
 
740
                        else
 
741
                                fputs("\n  <tr><td colspan=\"2\">&nbsp;</td></tr>\n", fout);
 
742
                }
 
743
                fputs("  <tr valign=\"top\">\n"
 
744
                          "    <th>", fout);
 
745
                html_escaped_print(headers[i % col_count], fout);
 
746
                fputs("</th>\n", fout);
 
747
 
 
748
                fprintf(fout, "    <td align=\"%s\">", opt_align[i % col_count] == 'r' ? "right" : "left");
 
749
                if ((*ptr)[strspn(*ptr, " \t")] == '\0')                /* is string only
 
750
                                                                                                                 * whitespace? */
 
751
                        fputs("&nbsp; ", fout);
 
752
                else
 
753
                        html_escaped_print(*ptr, fout);
 
754
                fputs("</td>\n  </tr>\n", fout);
 
755
        }
 
756
 
 
757
        fputs("</table>\n", fout);
 
758
 
 
759
        /* print footers */
 
760
        if (!opt_barebones && footers && *footers)
 
761
        {
 
762
                fputs("<p>", fout);
 
763
                for (ptr = footers; *ptr; ptr++)
 
764
                {
 
765
                        html_escaped_print(*ptr, fout);
 
766
                        fputs("<br />\n", fout);
 
767
                }
 
768
                fputs("</p>", fout);
 
769
        }
 
770
        fputc('\n', fout);
 
771
}
 
772
 
 
773
 
 
774
 
 
775
/*************************/
 
776
/* LaTeX                 */
 
777
/*************************/
 
778
 
 
779
 
 
780
static void
 
781
latex_escaped_print(const char *in, FILE *fout)
 
782
{
 
783
        const char *p;
 
784
 
 
785
        for (p = in; *p; p++)
 
786
                switch (*p)
 
787
                {
 
788
                        case '&':
 
789
                                fputs("\\&", fout);
 
790
                                break;
 
791
                        case '%':
 
792
                                fputs("\\%", fout);
 
793
                                break;
 
794
                        case '$':
 
795
                                fputs("\\$", fout);
 
796
                                break;
 
797
                        case '_':
 
798
                                fputs("\\_", fout);
 
799
                                break;
 
800
                        case '{':
 
801
                                fputs("\\{", fout);
 
802
                                break;
 
803
                        case '}':
 
804
                                fputs("\\}", fout);
 
805
                                break;
 
806
                        case '\\':
 
807
                                fputs("\\backslash", fout);
 
808
                                break;
 
809
                        case '\n':
 
810
                                fputs("\\\\", fout);
 
811
                                break;
 
812
                        default:
 
813
                                fputc(*p, fout);
 
814
                }
 
815
}
 
816
 
 
817
 
 
818
 
 
819
static void
 
820
print_latex_text(const char *title, const char *const * headers,
 
821
                                 const char *const * cells, const char *const * footers,
 
822
const char *opt_align, bool opt_barebones, unsigned short int opt_border,
 
823
                                 FILE *fout)
 
824
{
 
825
        unsigned int col_count = 0;
 
826
        unsigned int i;
 
827
        const char *const * ptr;
 
828
 
 
829
 
 
830
        /* print title */
 
831
        if (!opt_barebones && title)
 
832
        {
 
833
                fputs("\\begin{center}\n", fout);
 
834
                latex_escaped_print(title, fout);
 
835
                fputs("\n\\end{center}\n\n", fout);
 
836
        }
 
837
 
 
838
        /* count columns */
 
839
        for (ptr = headers; *ptr; ptr++)
 
840
                col_count++;
 
841
 
 
842
        /* begin environment and set alignments and borders */
 
843
        fputs("\\begin{tabular}{", fout);
 
844
 
 
845
        if (opt_border == 2)
 
846
                fputs("| ", fout);
 
847
        for (i = 0; i < col_count; i++)
 
848
        {
 
849
                fputc(*(opt_align + i), fout);
 
850
                if (opt_border != 0 && i < col_count - 1)
 
851
                        fputs(" | ", fout);
 
852
        }
 
853
        if (opt_border == 2)
 
854
                fputs(" |", fout);
 
855
 
 
856
        fputs("}\n", fout);
 
857
 
 
858
        if (!opt_barebones && opt_border == 2)
 
859
                fputs("\\hline\n", fout);
 
860
 
 
861
        /* print headers and count columns */
 
862
        for (i = 0, ptr = headers; i < col_count; i++, ptr++)
 
863
        {
 
864
                if (!opt_barebones)
 
865
                {
 
866
                        if (i != 0)
 
867
                                fputs(" & ", fout);
 
868
                        fputs("\\textit{", fout);
 
869
                        latex_escaped_print(*ptr, fout);
 
870
                        fputc('}', fout);
 
871
                }
 
872
        }
 
873
 
 
874
        if (!opt_barebones)
 
875
        {
 
876
                fputs(" \\\\\n", fout);
 
877
                fputs("\\hline\n", fout);
 
878
        }
 
879
 
 
880
        /* print cells */
 
881
        for (i = 0, ptr = cells; *ptr; i++, ptr++)
 
882
        {
 
883
                latex_escaped_print(*ptr, fout);
 
884
 
 
885
                if ((i + 1) % col_count == 0)
 
886
                        fputs(" \\\\\n", fout);
 
887
                else
 
888
                        fputs(" & ", fout);
 
889
        }
 
890
 
 
891
        if (opt_border == 2)
 
892
                fputs("\\hline\n", fout);
 
893
 
 
894
        fputs("\\end{tabular}\n\n\\noindent ", fout);
 
895
 
 
896
 
 
897
        /* print footers */
 
898
 
 
899
        if (footers && !opt_barebones)
 
900
                for (ptr = footers; *ptr; ptr++)
 
901
                {
 
902
                        latex_escaped_print(*ptr, fout);
 
903
                        fputs(" \\\\\n", fout);
 
904
                }
 
905
 
 
906
        fputc('\n', fout);
 
907
}
 
908
 
 
909
 
 
910
 
 
911
static void
 
912
print_latex_vertical(const char *title, const char *const * headers,
 
913
                                  const char *const * cells, const char *const * footers,
 
914
const char *opt_align, bool opt_barebones, unsigned short int opt_border,
 
915
                                         FILE *fout)
 
916
{
 
917
        unsigned int col_count = 0;
 
918
        unsigned int i;
 
919
        const char *const * ptr;
 
920
        unsigned int record = 1;
 
921
 
 
922
        (void) opt_align;                       /* currently unused parameter */
 
923
 
 
924
        /* print title */
 
925
        if (!opt_barebones && title)
 
926
        {
 
927
                fputs("\\begin{center}\n", fout);
 
928
                latex_escaped_print(title, fout);
 
929
                fputs("\n\\end{center}\n\n", fout);
 
930
        }
 
931
 
 
932
        /* begin environment and set alignments and borders */
 
933
        fputs("\\begin{tabular}{", fout);
 
934
        if (opt_border == 0)
 
935
                fputs("cl", fout);
 
936
        else if (opt_border == 1)
 
937
                fputs("c|l", fout);
 
938
        else if (opt_border == 2)
 
939
                fputs("|c|l|", fout);
 
940
        fputs("}\n", fout);
 
941
 
 
942
 
 
943
        /* count columns */
 
944
        for (ptr = headers; *ptr; ptr++)
 
945
                col_count++;
 
946
 
 
947
 
 
948
        /* print records */
 
949
        for (i = 0, ptr = cells; *ptr; i++, ptr++)
 
950
        {
 
951
                /* new record */
 
952
                if (i % col_count == 0)
 
953
                {
 
954
                        if (!opt_barebones)
 
955
                        {
 
956
                                if (opt_border == 2)
 
957
                                {
 
958
                                        fputs("\\hline\n", fout);
 
959
                                        fprintf(fout, "\\multicolumn{2}{|c|}{\\textit{Record %d}} \\\\\n", record++);
 
960
                                }
 
961
                                else
 
962
                                        fprintf(fout, "\\multicolumn{2}{c}{\\textit{Record %d}} \\\\\n", record++);
 
963
                        }
 
964
                        if (opt_border >= 1)
 
965
                                fputs("\\hline\n", fout);
 
966
                }
 
967
 
 
968
                latex_escaped_print(headers[i % col_count], fout);
 
969
                fputs(" & ", fout);
 
970
                latex_escaped_print(*ptr, fout);
 
971
                fputs(" \\\\\n", fout);
 
972
        }
 
973
 
 
974
        if (opt_border == 2)
 
975
                fputs("\\hline\n", fout);
 
976
 
 
977
        fputs("\\end{tabular}\n\n\\noindent ", fout);
 
978
 
 
979
 
 
980
        /* print footers */
 
981
 
 
982
        if (footers && !opt_barebones)
 
983
                for (ptr = footers; *ptr; ptr++)
 
984
                {
 
985
                        latex_escaped_print(*ptr, fout);
 
986
                        fputs(" \\\\\n", fout);
 
987
                }
 
988
 
 
989
        fputc('\n', fout);
 
990
}
 
991
 
 
992
 
 
993
 
 
994
/********************************/
 
995
/* Public functions             */
 
996
/********************************/
 
997
 
 
998
 
 
999
/*
 
1000
 * PageOutput
 
1001
 *
 
1002
 * Tests if pager is needed and returns appropriate FILE pointer.
 
1003
 */
 
1004
FILE *
 
1005
PageOutput(int lines, unsigned short int pager)
 
1006
{
 
1007
        /* check whether we need / can / are supposed to use pager */
 
1008
        if (pager
 
1009
#ifndef WIN32
 
1010
                &&
 
1011
                isatty(fileno(stdin)) &&
 
1012
                isatty(fileno(stdout))
 
1013
#endif
 
1014
                )
 
1015
        {
 
1016
                const char *pagerprog;
 
1017
 
 
1018
#ifdef TIOCGWINSZ
 
1019
                int                     result;
 
1020
                struct winsize screen_size;
 
1021
 
 
1022
                result = ioctl(fileno(stdout), TIOCGWINSZ, &screen_size);
 
1023
 
 
1024
                /* >= accounts for a one-line prompt */
 
1025
                if (result == -1 || lines >= screen_size.ws_row || pager > 1)
 
1026
                {
 
1027
#endif
 
1028
                        pagerprog = getenv("PAGER");
 
1029
                        if (!pagerprog)
 
1030
                                pagerprog = DEFAULT_PAGER;
 
1031
#ifndef WIN32
 
1032
                        pqsignal(SIGPIPE, SIG_IGN);
 
1033
#endif
 
1034
                        return popen(pagerprog, "w");
 
1035
#ifdef TIOCGWINSZ
 
1036
                }
 
1037
#endif
 
1038
        }
 
1039
 
 
1040
        return stdout;
 
1041
}
 
1042
 
 
1043
 
 
1044
 
 
1045
void
 
1046
printTable(const char *title,
 
1047
                   const char *const * headers,
 
1048
                   const char *const * cells,
 
1049
                   const char *const * footers,
 
1050
                   const char *align,
 
1051
                   const printTableOpt *opt, FILE *fout)
 
1052
{
 
1053
        const char *default_footer[] = {NULL};
 
1054
        unsigned short int border = opt->border;
 
1055
        FILE       *output;
 
1056
 
 
1057
        if (opt->format == PRINT_NOTHING)
 
1058
                return;
 
1059
 
 
1060
        if (!footers)
 
1061
                footers = default_footer;
 
1062
 
 
1063
        if (opt->format != PRINT_HTML && border > 2)
 
1064
                border = 2;
 
1065
 
 
1066
        if (fout == stdout)
 
1067
        {
 
1068
                int                     col_count = 0,
 
1069
                                        row_count = 0,
 
1070
                                        lines;
 
1071
                const char *const * ptr;
 
1072
 
 
1073
                /* rough estimate of columns and rows */
 
1074
                if (headers)
 
1075
                        for (ptr = headers; *ptr; ptr++)
 
1076
                                col_count++;
 
1077
                if (cells)
 
1078
                        for (ptr = cells; *ptr; ptr++)
 
1079
                                row_count++;
 
1080
                if (col_count > 0)
 
1081
                        row_count /= col_count;
 
1082
 
 
1083
                if (opt->expanded)
 
1084
                        lines = (col_count + 1) * row_count;
 
1085
                else
 
1086
                        lines = row_count + 1;
 
1087
                if (footers && !opt->tuples_only)
 
1088
                        for (ptr = footers; *ptr; ptr++)
 
1089
                                lines++;
 
1090
                output = PageOutput(lines, opt->pager);
 
1091
        }
 
1092
        else
 
1093
                output = fout;
 
1094
 
 
1095
        /* print the stuff */
 
1096
 
 
1097
        switch (opt->format)
 
1098
        {
 
1099
                case PRINT_UNALIGNED:
 
1100
                        if (opt->expanded)
 
1101
                                print_unaligned_vertical(title, headers, cells, footers, opt->fieldSep, opt->recordSep, opt->tuples_only, output);
 
1102
                        else
 
1103
                                print_unaligned_text(title, headers, cells, footers, opt->fieldSep, opt->recordSep, opt->tuples_only, output);
 
1104
                        break;
 
1105
                case PRINT_ALIGNED:
 
1106
                        if (opt->expanded)
 
1107
                                print_aligned_vertical(title, headers, cells, footers, opt->tuples_only, border, opt->encoding, output);
 
1108
                        else
 
1109
                                print_aligned_text(title, headers, cells, footers, align, opt->tuples_only, border, opt->encoding, output);
 
1110
                        break;
 
1111
                case PRINT_HTML:
 
1112
                        if (opt->expanded)
 
1113
                                print_html_vertical(title, headers, cells, footers, align, opt->tuples_only, border, opt->tableAttr, output);
 
1114
                        else
 
1115
                                print_html_text(title, headers, cells, footers, align, opt->tuples_only, border, opt->tableAttr, output);
 
1116
                        break;
 
1117
                case PRINT_LATEX:
 
1118
                        if (opt->expanded)
 
1119
                                print_latex_vertical(title, headers, cells, footers, align, opt->tuples_only, border, output);
 
1120
                        else
 
1121
                                print_latex_text(title, headers, cells, footers, align, opt->tuples_only, border, output);
 
1122
                        break;
 
1123
                default:
 
1124
                        fprintf(stderr, "+ Oops, you shouldn't see this!\n");
 
1125
        }
 
1126
 
 
1127
        /* Only close if we used the pager */
 
1128
        if (fout == stdout && output != stdout)
 
1129
        {
 
1130
                pclose(output);
 
1131
#ifndef WIN32
 
1132
                pqsignal(SIGPIPE, SIG_DFL);
 
1133
#endif
 
1134
        }
 
1135
}
 
1136
 
 
1137
 
 
1138
 
 
1139
void
 
1140
printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout)
 
1141
{
 
1142
        int                     nfields;
 
1143
        int                     ncells;
 
1144
        const char **headers;
 
1145
        const char **cells;
 
1146
        char      **footers;
 
1147
        char       *align;
 
1148
        int                     i;
 
1149
 
 
1150
        /* extract headers */
 
1151
        nfields = PQnfields(result);
 
1152
 
 
1153
        headers = calloc(nfields + 1, sizeof(*headers));
 
1154
        if (!headers)
 
1155
        {
 
1156
                fprintf(stderr, gettext("out of memory\n"));
 
1157
                exit(EXIT_FAILURE);
 
1158
        }
 
1159
 
 
1160
        for (i = 0; i < nfields; i++)
 
1161
                headers[i] = mbvalidate(PQfname(result, i), opt->topt.encoding);
 
1162
 
 
1163
        /* set cells */
 
1164
        ncells = PQntuples(result) * nfields;
 
1165
        cells = calloc(ncells + 1, sizeof(*cells));
 
1166
        if (!cells)
 
1167
        {
 
1168
                fprintf(stderr, gettext("out of memory\n"));
 
1169
                exit(EXIT_FAILURE);
 
1170
        }
 
1171
 
 
1172
        for (i = 0; i < ncells; i++)
 
1173
        {
 
1174
                if (PQgetisnull(result, i / nfields, i % nfields))
 
1175
                        cells[i] = opt->nullPrint ? opt->nullPrint : "";
 
1176
                else
 
1177
                        cells[i] = mbvalidate(PQgetvalue(result, i / nfields, i % nfields), opt->topt.encoding);
 
1178
        }
 
1179
 
 
1180
        /* set footers */
 
1181
 
 
1182
        if (opt->footers)
 
1183
                footers = opt->footers;
 
1184
        else if (!opt->topt.expanded && opt->default_footer)
 
1185
        {
 
1186
                footers = calloc(2, sizeof(*footers));
 
1187
                if (!footers)
 
1188
                {
 
1189
                        fprintf(stderr, gettext("out of memory\n"));
 
1190
                        exit(EXIT_FAILURE);
 
1191
                }
 
1192
 
 
1193
                footers[0] = malloc(100);
 
1194
                if (!footers[0])
 
1195
                {
 
1196
                        fprintf(stderr, gettext("out of memory\n"));
 
1197
                        exit(EXIT_FAILURE);
 
1198
                }
 
1199
                if (PQntuples(result) == 1)
 
1200
                        snprintf(footers[0], 100, gettext("(1 row)"));
 
1201
                else
 
1202
                        snprintf(footers[0], 100, gettext("(%d rows)"), PQntuples(result));
 
1203
        }
 
1204
        else
 
1205
                footers = NULL;
 
1206
 
 
1207
        /* set alignment */
 
1208
        align = calloc(nfields + 1, sizeof(*align));
 
1209
        if (!align)
 
1210
        {
 
1211
                fprintf(stderr, gettext("out of memory\n"));
 
1212
                exit(EXIT_FAILURE);
 
1213
        }
 
1214
 
 
1215
        for (i = 0; i < nfields; i++)
 
1216
        {
 
1217
                Oid                     ftype = PQftype(result, i);
 
1218
 
 
1219
                if (ftype == 20 ||              /* int8 */
 
1220
                        ftype == 21 ||          /* int2 */
 
1221
                        ftype == 23 ||          /* int4 */
 
1222
                        (ftype >= 26 && ftype <= 30) ||         /* ?id */
 
1223
                        ftype == 700 ||         /* float4 */
 
1224
                        ftype == 701 ||         /* float8 */
 
1225
                        ftype == 790 ||         /* money */
 
1226
                        ftype == 1700           /* numeric */
 
1227
                        )
 
1228
                        align[i] = 'r';
 
1229
                else
 
1230
                        align[i] = 'l';
 
1231
        }
 
1232
 
 
1233
        /* call table printer */
 
1234
        printTable(opt->title, headers, cells,
 
1235
                           (const char *const *) footers,
 
1236
                           align, &opt->topt, fout);
 
1237
 
 
1238
        free(headers);
 
1239
        free(cells);
 
1240
        if (footers)
 
1241
        {
 
1242
                free(footers[0]);
 
1243
                free(footers);
 
1244
        }
 
1245
        free(align);
 
1246
}
 
1247
 
 
1248
 
 
1249
/* the end */