Restore psql's former behavior that padding spaces to the right of the last
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 10 May 2008 03:31:58 +0000 (03:31 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 10 May 2008 03:31:58 +0000 (03:31 +0000)
output column are not emitted.  (That change already caused more noise in
the regression test output files than I would like.)  Provide some needed
editorial help for comments, clean up code formatting.

src/bin/psql/print.c

index 0e615d8cb8fdfbc3d8415c887919abab95873a13..68c675c06f80435509d682fabca3b54d12bb2f30 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2008, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.98 2008/05/08 17:04:26 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.99 2008/05/10 03:31:58 tgl Exp $
  */
 #include "postgres_fe.h"
 
@@ -28,8 +28,6 @@
 
 #include "mbprint.h"
 
-static int strlen_max_width(unsigned char *str, int *target_width, int encoding);
-
 /*
  * We define the cancel_pressed flag in this file, rather than common.c where
  * it naturally belongs, because this file is also used by non-psql programs
@@ -45,6 +43,9 @@ static char *decimal_point;
 static char *grouping;
 static char *thousands_sep;
 
+/* Local functions */
+static int strlen_max_width(unsigned char *str, int *target_width, int encoding);
+
 
 static void *
 pg_local_malloc(size_t size)
@@ -400,7 +401,7 @@ _print_horizontal_line(const unsigned int col_count, const unsigned int *widths,
 
 
 /*
- * Prety pretty boxes around cells.
+ * Print pretty boxes around cells.
  */
 static void
 print_aligned_text(const char *title, const char *const * headers,
@@ -411,7 +412,7 @@ print_aligned_text(const char *title, const char *const * headers,
    bool        opt_tuples_only = opt->tuples_only;
    bool        opt_numeric_locale = opt->numericLocale;
    int         encoding = opt->encoding;
-   unsigned short int opt_border = opt->border;
+   unsigned short opt_border = opt->border;
 
    unsigned int col_count = 0, cell_count = 0;
 
@@ -483,7 +484,8 @@ print_aligned_text(const char *title, const char *const * headers,
                    nl_lines,
                    bytes_required;
 
-       pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding, &width, &nl_lines, &bytes_required);
+       pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding,
+                  &width, &nl_lines, &bytes_required);
        if (width > max_width[i])
            max_width[i] = width;
        if (nl_lines > max_nl_lines[i])
@@ -502,7 +504,8 @@ print_aligned_text(const char *title, const char *const * headers,
                    bytes_required;
 
        /* Get width, ignore nl_lines */
-       pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding, &width, &nl_lines, &bytes_required);
+       pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding,
+                  &width, &nl_lines, &bytes_required);
        if (opt_numeric_locale && opt_align[i % col_count] == 'r')
        {
            width += additional_numeric_locale_len(*ptr);
@@ -567,12 +570,14 @@ print_aligned_text(const char *title, const char *const * headers,
 
    if (opt->format == PRINT_WRAPPED)
    {
-       /* Get terminal width */
+       /*
+        * Choose target output width: \pset columns, or $COLUMNS, or ioctl
+        */
        if (opt->columns > 0)
            output_columns = opt->columns;
        else if ((fout == stdout && isatty(fileno(stdout))) || is_pager)
        {
-           if (opt->env_columns)
+           if (opt->env_columns > 0)
                output_columns = opt->env_columns;
 #ifdef TIOCGWINSZ
            else
@@ -586,11 +591,11 @@ print_aligned_text(const char *title, const char *const * headers,
        }
 
        /*
-        * Optional optimized word wrap. Shrink columns with a high max/avg ratio.
-        * Slighly bias against wider columns. (Increases chance a narrow column
-        * will fit in its cell.)
-        * If available columns is positive...
-        * and greater than the width of the unshrinkable column headers
+        * Optional optimized word wrap. Shrink columns with a high max/avg
+        * ratio.  Slighly bias against wider columns. (Increases chance a
+        * narrow column will fit in its cell.)  If available columns is
+        * positive...  and greater than the width of the unshrinkable column
+        * headers
         */
        if (output_columns > 0 && output_columns >= total_header_width)
        {
@@ -610,10 +615,11 @@ print_aligned_text(const char *title, const char *const * headers,
                {
                    if (width_average[i] && width_wrap[i] > width_header[i])
                    {
-                       /* Penalize wide columns by +1% of their width (0.01) */
-                       double ratio = (double)width_wrap[i] / width_average[i] +
-                                   max_width[i] * 0.01;
+                       /* Penalize wide columns by 1% of their width */
+                       double ratio;
 
+                       ratio = (double) width_wrap[i] / width_average[i] +
+                           max_width[i] * 0.01;
                        if (ratio > max_ratio)
                        {
                            max_ratio = ratio;
@@ -641,7 +647,8 @@ print_aligned_text(const char *title, const char *const * headers,
        {
            int         width, height;
 
-           pg_wcssize((unsigned char *) title, strlen(title), encoding, &width, &height, NULL);
+           pg_wcssize((unsigned char *) title, strlen(title), encoding,
+                      &width, &height, NULL);
            if (width >= width_total)
                fprintf(fout, "%s\n", title);   /* Aligned */
            else
@@ -723,12 +730,13 @@ print_aligned_text(const char *title, const char *const * headers,
            break;
 
        /*
-        * Format each cell.  Format again, it is a numeric formatting locale
+        * Format each cell.  Format again, if it's a numeric formatting locale
         * (e.g. 123,456 vs. 123456)
         */
        for (j = 0; j < col_count; j++)
        {
-           pg_wcsformat((unsigned char *) ptr[j], strlen(ptr[j]), encoding, col_lineptrs[j], max_nl_lines[j]);
+           pg_wcsformat((unsigned char *) ptr[j], strlen(ptr[j]), encoding,
+                        col_lineptrs[j], max_nl_lines[j]);
            curr_nl_line[j] = 0;
 
            if (opt_numeric_locale && opt_align[j % col_count] == 'r')
@@ -736,8 +744,8 @@ print_aligned_text(const char *title, const char *const * headers,
                char       *my_cell;
 
                my_cell = format_numeric_locale((char *) col_lineptrs[j]->ptr);
-               strcpy((char *) col_lineptrs[j]->ptr, my_cell); /* Buffer IS large
-                                                                * enough... now */
+               /* Buffer IS large enough... now */
+               strcpy((char *) col_lineptrs[j]->ptr, my_cell);
                free(my_cell);
            }
        }
@@ -764,16 +772,22 @@ print_aligned_text(const char *title, const char *const * headers,
            {
                /* We have a valid array element, so index it */
                struct lineptr *this_line = &col_lineptrs[j][curr_nl_line[j]];
-               int     bytes_to_output,  chars_to_output = width_wrap[j];
+               int     bytes_to_output;
+               int     chars_to_output = width_wrap[j];
+               bool    finalspaces = (opt_border == 2 || j < col_count - 1);
 
-               /* Past newline lines so pad for other columns */
                if (!this_line->ptr)
-                   fprintf(fout, "%*s", width_wrap[j], "");
+               {
+                   /* Past newline lines so just pad for other columns */
+                   if (finalspaces)
+                       fprintf(fout, "%*s", chars_to_output, "");
+               }
                else
                {
-                   /* Get strlen() of the width_wrap character */
-                   bytes_to_output = strlen_max_width(this_line->ptr +
-                                   bytes_output[j], &chars_to_output, encoding);
+                   /* Get strlen() of the characters up to width_wrap */
+                   bytes_to_output =
+                       strlen_max_width(this_line->ptr + bytes_output[j],
+                                        &chars_to_output, encoding);
 
                    /*
                     *  If we exceeded width_wrap, it means the display width
@@ -796,13 +810,14 @@ print_aligned_text(const char *title, const char *const * headers,
                        /* spaces second */
                        fprintf(fout, "%.*s", bytes_to_output,
                                this_line->ptr + bytes_output[j]);
-                       fprintf(fout, "%*s", width_wrap[j] - chars_to_output, "");
+                       if (finalspaces)
+                           fprintf(fout, "%*s", width_wrap[j] - chars_to_output, "");
                    }
 
                    bytes_output[j] += bytes_to_output;
 
                    /* Do we have more text to wrap? */
-                   if (*(this_line->ptr + bytes_output[j]) != 0)
+                   if (*(this_line->ptr + bytes_output[j]) != '\0')
                        more_lines = true;
                    else
                    {
@@ -814,8 +829,8 @@ print_aligned_text(const char *title, const char *const * headers,
                    }
                }
 
-               /* print a divider, middle columns only */
-               if ((j + 1) % col_count)
+               /* print a divider, if not the last column */
+               if (j < col_count - 1)
                {
                    if (opt_border == 0)
                        fputc(' ', fout);
@@ -832,10 +847,9 @@ print_aligned_text(const char *title, const char *const * headers,
                    /* Ordinary line */
                        fputs(" | ", fout);
                }
-
            }
 
-           /* end of row border */
+           /* end-of-row border */
            if (opt_border == 2)
                fputs(" |", fout);
            fputc('\n', fout);
@@ -887,7 +901,7 @@ print_aligned_vertical(const char *title, const char *const * headers,
 {
    bool        opt_tuples_only = opt->tuples_only;
    bool        opt_numeric_locale = opt->numericLocale;
-   unsigned short int opt_border = opt->border;
+   unsigned short opt_border = opt->border;
    int         encoding = opt->encoding;
    unsigned int col_count = 0;
    unsigned long record = opt->prior_records + 1;
@@ -927,7 +941,8 @@ print_aligned_vertical(const char *title, const char *const * headers,
                    height,
                    fs;
 
-       pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding, &width, &height, &fs);
+       pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), encoding,
+                  &width, &height, &fs);
        if (width > hwidth)
            hwidth = width;
        if (height > hheight)
@@ -953,7 +968,8 @@ print_aligned_vertical(const char *title, const char *const * headers,
        else
            numeric_locale_len = 0;
 
-       pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding, &width, &height, &fs);
+       pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding,
+                  &width, &height, &fs);
        width += numeric_locale_len;
        if (width > dwidth)
            dwidth = width;
@@ -1041,9 +1057,11 @@ print_aligned_vertical(const char *title, const char *const * headers,
 
        /* Format the header */
        pg_wcsformat((unsigned char *) headers[i % col_count],
-               strlen(headers[i % col_count]), encoding, hlineptr, hheight);
+                    strlen(headers[i % col_count]),
+                    encoding, hlineptr, hheight);
        /* Format the data */
-       pg_wcsformat((unsigned char *) *ptr, strlen(*ptr), encoding, dlineptr, dheight);
+       pg_wcsformat((unsigned char *) *ptr, strlen(*ptr), encoding,
+                    dlineptr, dheight);
 
        line_count = 0;
        dcomplete = hcomplete = 0;
@@ -1182,7 +1200,7 @@ print_html_text(const char *title, const char *const * headers,
 {
    bool        opt_tuples_only = opt->tuples_only;
    bool        opt_numeric_locale = opt->numericLocale;
-   unsigned short int opt_border = opt->border;
+   unsigned short opt_border = opt->border;
    const char *opt_table_attr = opt->tableAttr;
    unsigned int col_count = 0;
    unsigned int i;
@@ -1283,7 +1301,7 @@ print_html_vertical(const char *title, const char *const * headers,
 {
    bool        opt_tuples_only = opt->tuples_only;
    bool        opt_numeric_locale = opt->numericLocale;
-   unsigned short int opt_border = opt->border;
+   unsigned short opt_border = opt->border;
    const char *opt_table_attr = opt->tableAttr;
    unsigned int col_count = 0;
    unsigned long record = opt->prior_records + 1;
@@ -1421,7 +1439,7 @@ print_latex_text(const char *title, const char *const * headers,
 {
    bool        opt_tuples_only = opt->tuples_only;
    bool        opt_numeric_locale = opt->numericLocale;
-   unsigned short int opt_border = opt->border;
+   unsigned short opt_border = opt->border;
    unsigned int col_count = 0;
    unsigned int i;
    const char *const * ptr;
@@ -1534,7 +1552,7 @@ print_latex_vertical(const char *title, const char *const * headers,
 {
    bool        opt_tuples_only = opt->tuples_only;
    bool        opt_numeric_locale = opt->numericLocale;
-   unsigned short int opt_border = opt->border;
+   unsigned short opt_border = opt->border;
    unsigned int col_count = 0;
    unsigned long record = opt->prior_records + 1;
    unsigned int i;
@@ -1661,7 +1679,7 @@ print_troff_ms_text(const char *title, const char *const * headers,
 {
    bool        opt_tuples_only = opt->tuples_only;
    bool        opt_numeric_locale = opt->numericLocale;
-   unsigned short int opt_border = opt->border;
+   unsigned short opt_border = opt->border;
    unsigned int col_count = 0;
    unsigned int i;
    const char *const * ptr;
@@ -1764,7 +1782,7 @@ print_troff_ms_vertical(const char *title, const char *const * headers,
 {
    bool        opt_tuples_only = opt->tuples_only;
    bool        opt_numeric_locale = opt->numericLocale;
-   unsigned short int opt_border = opt->border;
+   unsigned short opt_border = opt->border;
    unsigned int col_count = 0;
    unsigned long record = opt->prior_records + 1;
    unsigned int i;
@@ -1970,7 +1988,7 @@ printTable(const char *title,
    static const char *default_footer[] = {NULL};
    FILE       *output;
    bool        is_pager = false;
-   
+
    if (cancel_pressed)
        return;
 
@@ -2216,17 +2234,18 @@ setDecimalLocale(void)
 }
 
 /*
- * Returns the byte length to the end of the specified character
- *  and number of display characters processed (useful if the string
- * is shorter then dpylen).
+ * Compute the byte distance to the end of the string or *target_width
+ * display character positions, whichever comes first.  Update *target_width
+ * to be the number of display character positions actually filled.
  */
 static int
 strlen_max_width(unsigned char *str, int *target_width, int encoding)
 {
    unsigned char *start = str;
+   unsigned char *end = str + strlen((char *) str);
    int curr_width = 0;
 
-   while (*str && curr_width < *target_width)
+   while (str < end)
    {
        int char_width = PQdsplen((char *) str, encoding);
 
@@ -2234,18 +2253,17 @@ strlen_max_width(unsigned char *str, int *target_width, int encoding)
         *  If the display width of the new character causes
         *  the string to exceed its target width, skip it
         *  and return.  However, if this is the first character
-        *  of the string (*width == 0), we have to accept it.
+        *  of the string (curr_width == 0), we have to accept it.
         */
-       if (*target_width - curr_width < char_width && curr_width != 0)
+       if (*target_width < curr_width + char_width && curr_width != 0)
            break;
-           
-       str += PQmblen((char *)str, encoding);
 
        curr_width += char_width;
+           
+       str += PQmblen((char *) str, encoding);
    }
 
    *target_width = curr_width;
    
-   /* last byte */
    return str - start;
 }