[Please CC any replies, thanks]

This patch has the same effect as the last one except it now uses the
PQmblen and PQdsplen functions exported by libpq as suggested by Tom.
This clears a lot of stuff from psql's mbprint.c which is a good thing.
This means it should work for all for encodings (though I can't say I
tested them all).

The PQdsplen function in libpq has been improved so it can actually
work and provide the necessary information for formatting. That file
(wchar.c) is actually shared with the backend but the backend doesn't
use the dsplen functions, so it does add some dead code (on top of what
was already there).

Note: this changes the PQdsplen function, it can now return zero or
minus one which was not possible before. It doesn't appear anyone is
actually using the functions other than psql but it is a change. The
functions are not actually documentated anywhere so it's not like we're
breaking a defined interface. The new semantics follow the Unicode
standard.

The other uses of PQdsplen in psql (in ReportSyntaxErrorPosition) would
seem to be slightly affected by the change, except it's not clear how
psql should react to control characters in the string it's trying to
print...

Patch available at:
http://svana.org/kleptog/pgsql/psql-format.patch

Comments welcome,

Have a nice day,
-- 
Martijn van Oosterhout   <kleptog@svana.org>   http://svana.org/kleptog/
> Patent. n. Genius is 5% inspiration and 95% perspiration. A patent is a
> tool for doing 5% of the work and then sitting around waiting for someone
> else to do the other 95% so you can sue them.
Index: src/backend/utils/mb/wchar.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/mb/wchar.c,v
retrieving revision 1.47
diff -c -r1.47 wchar.c
*** src/backend/utils/mb/wchar.c        29 Oct 2005 00:31:52 -0000      1.47
--- src/backend/utils/mb/wchar.c        26 Nov 2005 22:27:57 -0000
***************
*** 23,28 ****
--- 23,35 ----
   * for the particular encoding. Note that if the encoding is only
   * supported in the client, you don't need to define
   * mb2wchar_with_len() function (SJIS is the case).
+  *
+  * Note: for the display output of psql to work properly, the return values
+  * of these functions must conform to the Unicode standard. In particular
+  * the NUL character is zero width and control characters are generally
+  * width -1. It is recommended that non-ASCII encodings refer their ASCII
+  * subset to the ASCII routines to ensure consistancy.
+  *
   */
  
  /*
***************
*** 52,57 ****
--- 59,69 ----
  static int
  pg_ascii_dsplen(const unsigned char *s)
  {
+       if( *s == '\0' )
+               return 0;
+       if( *s < 32 || *s == 127 )
+               return -1;
+               
        return (1);
  }
  
***************
*** 125,131 ****
        else if (*s & 0x80)
                len = 2;
        else
!               len = 1;
        return (len);
  }
  
--- 137,143 ----
        else if (*s & 0x80)
                len = 2;
        else
!               len = pg_ascii_dsplen(s);
        return (len);
  }
  
***************
*** 156,162 ****
        else if (*s & 0x80)
                len = 2;
        else
!               len = 1;
        return (len);
  }
  
--- 168,174 ----
        else if (*s & 0x80)
                len = 2;
        else
!               len = pg_ascii_dsplen(s);
        return (len);
  }
  
***************
*** 243,249 ****
        if (*s & 0x80)
                len = 2;
        else
!               len = 1;
        return (len);
  }
  
--- 255,261 ----
        if (*s & 0x80)
                len = 2;
        else
!               len = pg_ascii_dsplen(s);
        return (len);
  }
  
***************
*** 318,324 ****
        else if (*s & 0x80)
                len = 2;
        else
!               len = 1;
        return (len);
  }
  
--- 330,336 ----
        else if (*s & 0x80)
                len = 2;
        else
!               len = pg_ascii_dsplen(s);
        return (len);
  }
  
***************
*** 417,426 ****
        return (len);
  }
  
  static int
  pg_utf_dsplen(const unsigned char *s)
  {
!       return 1;                                       /* XXX fix me! */
  }
  
  /*
--- 429,615 ----
        return (len);
  }
  
+ /*
+  * This is an implementation of wcwidth() and wcswidth() as defined in
+  * "The Single UNIX Specification, Version 2, The Open Group, 1997"
+  * <http://www.UNIX-systems.org/online.html>
+  *
+  * Markus Kuhn -- 2001-09-08 -- public domain
+  *
+  * customised for PostgreSQL
+  *
+  * original available at : http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+  */
+ 
+ struct mbinterval
+ {
+       unsigned short first;
+       unsigned short last;
+ };
+ 
+ /* auxiliary function for binary search in interval table */
+ static int
+ mbbisearch(pg_wchar ucs, const struct mbinterval * table, int max)
+ {
+       int                     min = 0;
+       int                     mid;
+ 
+       if (ucs < table[0].first || ucs > table[max].last)
+               return 0;
+       while (max >= min)
+       {
+               mid = (min + max) / 2;
+               if (ucs > table[mid].last)
+                       min = mid + 1;
+               else if (ucs < table[mid].first)
+                       max = mid - 1;
+               else
+                       return 1;
+       }
+ 
+       return 0;
+ }
+ 
+ 
+ /* The following functions define the column width of an ISO 10646
+  * character as follows:
+  *
+  *      - The null character (U+0000) has a column width of 0.
+  *
+  *      - Other C0/C1 control characters and DEL will lead to a return
+  *            value of -1.
+  *
+  *      - Non-spacing and enclosing combining characters (general
+  *            category code Mn or Me in the Unicode database) have a
+  *            column width of 0.
+  *
+  *      - Other format characters (general category code Cf in the Unicode
+  *            database) and ZERO WIDTH SPACE (U+200B) have a column width of 
0.
+  *
+  *      - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
+  *            have a column width of 0.
+  *
+  *      - Spacing characters in the East Asian Wide (W) or East Asian
+  *            FullWidth (F) category as defined in Unicode Technical
+  *            Report #11 have a column width of 2.
+  *
+  *      - All remaining characters (including all printable
+  *            ISO 8859-1 and WGL4 characters, Unicode control characters,
+  *            etc.) have a column width of 1.
+  *
+  * This implementation assumes that wchar_t characters are encoded
+  * in ISO 10646.
+  */
+ 
+ static int
+ ucs_wcwidth(pg_wchar ucs)
+ {
+       /* sorted list of non-overlapping intervals of non-spacing characters */
+       static const struct mbinterval combining[] = {
+               {0x0300, 0x034E}, {0x0360, 0x0362}, {0x0483, 0x0486},
+               {0x0488, 0x0489}, {0x0591, 0x05A1}, {0x05A3, 0x05B9},
+               {0x05BB, 0x05BD}, {0x05BF, 0x05BF}, {0x05C1, 0x05C2},
+               {0x05C4, 0x05C4}, {0x064B, 0x0655}, {0x0670, 0x0670},
+               {0x06D6, 0x06E4}, {0x06E7, 0x06E8}, {0x06EA, 0x06ED},
+               {0x070F, 0x070F}, {0x0711, 0x0711}, {0x0730, 0x074A},
+               {0x07A6, 0x07B0}, {0x0901, 0x0902}, {0x093C, 0x093C},
+               {0x0941, 0x0948}, {0x094D, 0x094D}, {0x0951, 0x0954},
+               {0x0962, 0x0963}, {0x0981, 0x0981}, {0x09BC, 0x09BC},
+               {0x09C1, 0x09C4}, {0x09CD, 0x09CD}, {0x09E2, 0x09E3},
+               {0x0A02, 0x0A02}, {0x0A3C, 0x0A3C}, {0x0A41, 0x0A42},
+               {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A70, 0x0A71},
+               {0x0A81, 0x0A82}, {0x0ABC, 0x0ABC}, {0x0AC1, 0x0AC5},
+               {0x0AC7, 0x0AC8}, {0x0ACD, 0x0ACD}, {0x0B01, 0x0B01},
+               {0x0B3C, 0x0B3C}, {0x0B3F, 0x0B3F}, {0x0B41, 0x0B43},
+               {0x0B4D, 0x0B4D}, {0x0B56, 0x0B56}, {0x0B82, 0x0B82},
+               {0x0BC0, 0x0BC0}, {0x0BCD, 0x0BCD}, {0x0C3E, 0x0C40},
+               {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56},
+               {0x0CBF, 0x0CBF}, {0x0CC6, 0x0CC6}, {0x0CCC, 0x0CCD},
+               {0x0D41, 0x0D43}, {0x0D4D, 0x0D4D}, {0x0DCA, 0x0DCA},
+               {0x0DD2, 0x0DD4}, {0x0DD6, 0x0DD6}, {0x0E31, 0x0E31},
+               {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E}, {0x0EB1, 0x0EB1},
+               {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC}, {0x0EC8, 0x0ECD},
+               {0x0F18, 0x0F19}, {0x0F35, 0x0F35}, {0x0F37, 0x0F37},
+               {0x0F39, 0x0F39}, {0x0F71, 0x0F7E}, {0x0F80, 0x0F84},
+               {0x0F86, 0x0F87}, {0x0F90, 0x0F97}, {0x0F99, 0x0FBC},
+               {0x0FC6, 0x0FC6}, {0x102D, 0x1030}, {0x1032, 0x1032},
+               {0x1036, 0x1037}, {0x1039, 0x1039}, {0x1058, 0x1059},
+               {0x1160, 0x11FF}, {0x17B7, 0x17BD}, {0x17C6, 0x17C6},
+               {0x17C9, 0x17D3}, {0x180B, 0x180E}, {0x18A9, 0x18A9},
+               {0x200B, 0x200F}, {0x202A, 0x202E}, {0x206A, 0x206F},
+               {0x20D0, 0x20E3}, {0x302A, 0x302F}, {0x3099, 0x309A},
+               {0xFB1E, 0xFB1E}, {0xFE20, 0xFE23}, {0xFEFF, 0xFEFF},
+               {0xFFF9, 0xFFFB}
+       };
+ 
+       /* test for 8-bit control characters */
+       if (ucs == 0)
+               return 0;
+ 
+       if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0) || ucs > 0x0010ffff)
+               return -1;
+ 
+       /* binary search in table of non-spacing characters */
+       if (mbbisearch(ucs, combining,
+                                  sizeof(combining) / sizeof(struct 
mbinterval) - 1))
+               return 0;
+ 
+       /*
+        * if we arrive here, ucs is not a combining or C0/C1 control character
+        */
+ 
+       return 1 +
+               (ucs >= 0x1100 &&
+                (ucs <= 0x115f ||              /* Hangul Jamo init. consonants 
*/
+                 (ucs >= 0x2e80 && ucs <= 0xa4cf && (ucs & ~0x0011) != 0x300a 
&&
+                  ucs != 0x303f) ||    /* CJK ... Yi */
+                 (ucs >= 0xac00 && ucs <= 0xd7a3) ||   /* Hangul Syllables */
+                 (ucs >= 0xf900 && ucs <= 0xfaff) ||   /* CJK Compatibility
+                                                                               
                 * Ideographs */
+                 (ucs >= 0xfe30 && ucs <= 0xfe6f) ||   /* CJK Compatibility 
Forms */
+                 (ucs >= 0xff00 && ucs <= 0xff5f) ||   /* Fullwidth Forms */
+                 (ucs >= 0xffe0 && ucs <= 0xffe6) ||
+                 (ucs >= 0x20000 && ucs <= 0x2ffff)));
+ }
+ 
+ static pg_wchar
+ utf2ucs(const unsigned char *c)
+ {
+       /*
+        * one char version of pg_utf2wchar_with_len. no control here, c must
+        * point to a large enough string
+        */
+       if ((*c & 0x80) == 0)
+               return (pg_wchar) c[0];
+       else if ((*c & 0xe0) == 0xc0)
+       {
+               return (pg_wchar) (((c[0] & 0x1f) << 6) |
+                                                  (c[1] & 0x3f));
+       }
+       else if ((*c & 0xf0) == 0xe0)
+       {
+               return (pg_wchar) (((c[0] & 0x0f) << 12) |
+                                                  ((c[1] & 0x3f) << 6) |
+                                                  (c[2] & 0x3f));
+       }
+       else if ((*c & 0xf0) == 0xf0)
+       {
+               return (pg_wchar) (((c[0] & 0x07) << 18) |
+                                                  ((c[1] & 0x3f) << 12) |
+                                                  ((c[2] & 0x3f) << 6) |
+                                                  (c[3] & 0x3f));
+       }
+       else
+       {
+               /* that is an invalid code on purpose */
+               return 0xffffffff;
+       }
+ }
+ 
  static int
  pg_utf_dsplen(const unsigned char *s)
  {
!       return ucs_wcwidth(utf2ucs(s));
  }
  
  /*
***************
*** 529,535 ****
  static int
  pg_latin1_dsplen(const unsigned char *s)
  {
!       return (1);
  }
  
  /*
--- 718,724 ----
  static int
  pg_latin1_dsplen(const unsigned char *s)
  {
!       return pg_ascii_dsplen(s);
  }
  
  /*
***************
*** 570,576 ****
        }
        else
        {                                                       /* should be 
ASCII */
!               len = 1;
        }
        return (len);
  }
--- 759,765 ----
        }
        else
        {                                                       /* should be 
ASCII */
!               len = pg_ascii_dsplen(s);
        }
        return (len);
  }
***************
*** 605,611 ****
        }
        else
        {                                                       /* should be 
ASCII */
!               len = 1;
        }
        return (len);
  }
--- 794,800 ----
        }
        else
        {                                                       /* should be 
ASCII */
!               len = pg_ascii_dsplen(s);
        }
        return (len);
  }
***************
*** 640,646 ****
        }
        else
        {                                                       /* should be 
ASCII */
!               len = 1;
        }
        return (len);
  }
--- 829,835 ----
        }
        else
        {                                                       /* should be 
ASCII */
!               len = pg_ascii_dsplen(s);
        }
        return (len);
  }
***************
*** 675,681 ****
        }
        else
        {                                                       /* should be 
ASCII */
!               len = 1;
        }
        return (len);
  }
--- 864,870 ----
        }
        else
        {                                                       /* should be 
ASCII */
!               len = pg_ascii_dsplen(s);
        }
        return (len);
  }
***************
*** 712,718 ****
  
        if (*s <= 0x7f)
        {                                                       /* ASCII */
!               len = 1;
        }
        else
                len = 2;
--- 901,907 ----
  
        if (*s <= 0x7f)
        {                                                       /* ASCII */
!               len = pg_ascii_dsplen(s);
        }
        else
                len = 2;
Index: src/bin/psql/mbprint.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/psql/mbprint.c,v
retrieving revision 1.18
diff -c -r1.18 mbprint.c
*** src/bin/psql/mbprint.c      15 Oct 2005 02:49:40 -0000      1.18
--- src/bin/psql/mbprint.c      26 Nov 2005 22:27:57 -0000
***************
*** 14,162 ****
  
  #include "mb/pg_wchar.h"
  
- /*
-  * This is an implementation of wcwidth() and wcswidth() as defined in
-  * "The Single UNIX Specification, Version 2, The Open Group, 1997"
-  * <http://www.UNIX-systems.org/online.html>
-  *
-  * Markus Kuhn -- 2001-09-08 -- public domain
-  *
-  * customised for PostgreSQL
-  *
-  * original available at : http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
-  */
- 
- struct mbinterval
- {
-       unsigned short first;
-       unsigned short last;
- };
- 
- /* auxiliary function for binary search in interval table */
- static int
- mbbisearch(pg_wchar ucs, const struct mbinterval * table, int max)
- {
-       int                     min = 0;
-       int                     mid;
- 
-       if (ucs < table[0].first || ucs > table[max].last)
-               return 0;
-       while (max >= min)
-       {
-               mid = (min + max) / 2;
-               if (ucs > table[mid].last)
-                       min = mid + 1;
-               else if (ucs < table[mid].first)
-                       max = mid - 1;
-               else
-                       return 1;
-       }
- 
-       return 0;
- }
- 
- 
- /* The following functions define the column width of an ISO 10646
-  * character as follows:
-  *
-  *      - The null character (U+0000) has a column width of 0.
-  *
-  *      - Other C0/C1 control characters and DEL will lead to a return
-  *            value of -1.
-  *
-  *      - Non-spacing and enclosing combining characters (general
-  *            category code Mn or Me in the Unicode database) have a
-  *            column width of 0.
-  *
-  *      - Other format characters (general category code Cf in the Unicode
-  *            database) and ZERO WIDTH SPACE (U+200B) have a column width of 
0.
-  *
-  *      - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
-  *            have a column width of 0.
-  *
-  *      - Spacing characters in the East Asian Wide (W) or East Asian
-  *            FullWidth (F) category as defined in Unicode Technical
-  *            Report #11 have a column width of 2.
-  *
-  *      - All remaining characters (including all printable
-  *            ISO 8859-1 and WGL4 characters, Unicode control characters,
-  *            etc.) have a column width of 1.
-  *
-  * This implementation assumes that wchar_t characters are encoded
-  * in ISO 10646.
-  */
- 
- static int
- ucs_wcwidth(pg_wchar ucs)
- {
-       /* sorted list of non-overlapping intervals of non-spacing characters */
-       static const struct mbinterval combining[] = {
-               {0x0300, 0x034E}, {0x0360, 0x0362}, {0x0483, 0x0486},
-               {0x0488, 0x0489}, {0x0591, 0x05A1}, {0x05A3, 0x05B9},
-               {0x05BB, 0x05BD}, {0x05BF, 0x05BF}, {0x05C1, 0x05C2},
-               {0x05C4, 0x05C4}, {0x064B, 0x0655}, {0x0670, 0x0670},
-               {0x06D6, 0x06E4}, {0x06E7, 0x06E8}, {0x06EA, 0x06ED},
-               {0x070F, 0x070F}, {0x0711, 0x0711}, {0x0730, 0x074A},
-               {0x07A6, 0x07B0}, {0x0901, 0x0902}, {0x093C, 0x093C},
-               {0x0941, 0x0948}, {0x094D, 0x094D}, {0x0951, 0x0954},
-               {0x0962, 0x0963}, {0x0981, 0x0981}, {0x09BC, 0x09BC},
-               {0x09C1, 0x09C4}, {0x09CD, 0x09CD}, {0x09E2, 0x09E3},
-               {0x0A02, 0x0A02}, {0x0A3C, 0x0A3C}, {0x0A41, 0x0A42},
-               {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A70, 0x0A71},
-               {0x0A81, 0x0A82}, {0x0ABC, 0x0ABC}, {0x0AC1, 0x0AC5},
-               {0x0AC7, 0x0AC8}, {0x0ACD, 0x0ACD}, {0x0B01, 0x0B01},
-               {0x0B3C, 0x0B3C}, {0x0B3F, 0x0B3F}, {0x0B41, 0x0B43},
-               {0x0B4D, 0x0B4D}, {0x0B56, 0x0B56}, {0x0B82, 0x0B82},
-               {0x0BC0, 0x0BC0}, {0x0BCD, 0x0BCD}, {0x0C3E, 0x0C40},
-               {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56},
-               {0x0CBF, 0x0CBF}, {0x0CC6, 0x0CC6}, {0x0CCC, 0x0CCD},
-               {0x0D41, 0x0D43}, {0x0D4D, 0x0D4D}, {0x0DCA, 0x0DCA},
-               {0x0DD2, 0x0DD4}, {0x0DD6, 0x0DD6}, {0x0E31, 0x0E31},
-               {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E}, {0x0EB1, 0x0EB1},
-               {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC}, {0x0EC8, 0x0ECD},
-               {0x0F18, 0x0F19}, {0x0F35, 0x0F35}, {0x0F37, 0x0F37},
-               {0x0F39, 0x0F39}, {0x0F71, 0x0F7E}, {0x0F80, 0x0F84},
-               {0x0F86, 0x0F87}, {0x0F90, 0x0F97}, {0x0F99, 0x0FBC},
-               {0x0FC6, 0x0FC6}, {0x102D, 0x1030}, {0x1032, 0x1032},
-               {0x1036, 0x1037}, {0x1039, 0x1039}, {0x1058, 0x1059},
-               {0x1160, 0x11FF}, {0x17B7, 0x17BD}, {0x17C6, 0x17C6},
-               {0x17C9, 0x17D3}, {0x180B, 0x180E}, {0x18A9, 0x18A9},
-               {0x200B, 0x200F}, {0x202A, 0x202E}, {0x206A, 0x206F},
-               {0x20D0, 0x20E3}, {0x302A, 0x302F}, {0x3099, 0x309A},
-               {0xFB1E, 0xFB1E}, {0xFE20, 0xFE23}, {0xFEFF, 0xFEFF},
-               {0xFFF9, 0xFFFB}
-       };
- 
-       /* test for 8-bit control characters */
-       if (ucs == 0)
-               return 0;
- 
-       if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0) || ucs > 0x0010ffff)
-               return -1;
- 
-       /* binary search in table of non-spacing characters */
-       if (mbbisearch(ucs, combining,
-                                  sizeof(combining) / sizeof(struct 
mbinterval) - 1))
-               return 0;
- 
-       /*
-        * if we arrive here, ucs is not a combining or C0/C1 control character
-        */
- 
-       return 1 +
-               (ucs >= 0x1100 &&
-                (ucs <= 0x115f ||              /* Hangul Jamo init. consonants 
*/
-                 (ucs >= 0x2e80 && ucs <= 0xa4cf && (ucs & ~0x0011) != 0x300a 
&&
-                  ucs != 0x303f) ||    /* CJK ... Yi */
-                 (ucs >= 0xac00 && ucs <= 0xd7a3) ||   /* Hangul Syllables */
-                 (ucs >= 0xf900 && ucs <= 0xfaff) ||   /* CJK Compatibility
-                                                                               
                 * Ideographs */
-                 (ucs >= 0xfe30 && ucs <= 0xfe6f) ||   /* CJK Compatibility 
Forms */
-                 (ucs >= 0xff00 && ucs <= 0xff5f) ||   /* Fullwidth Forms */
-                 (ucs >= 0xffe0 && ucs <= 0xffe6) ||
-                 (ucs >= 0x20000 && ucs <= 0x2ffff)));
- }
- 
  static pg_wchar
  utf2ucs(const unsigned char *c)
  {
--- 14,19 ----
***************
*** 191,216 ****
        }
  }
  
- /* mb_utf_wcwidth : calculate column length for the utf8 string pwcs
-  */
- static int
- mb_utf_wcswidth(const unsigned char *pwcs, size_t len)
- {
-       int                     w,
-                               l = 0;
-       int                     width = 0;
- 
-       for (; *pwcs && len > 0; pwcs += l)
-       {
-               l = pg_utf_mblen(pwcs);
-               if ((len < (size_t) l) || ((w = ucs_wcwidth(utf2ucs(pwcs))) < 
0))
-                       return width;
-               len -= l;
-               width += w;
-       }
-       return width;
- }
- 
  static int
  utf_charcheck(const unsigned char *c)
  {
--- 48,53 ----
***************
*** 308,330 ****
   * public functions : wcswidth and mbvalidate
   */
  
  int
! pg_wcswidth(const char *pwcs, size_t len, int encoding)
  {
!       if (encoding == PG_UTF8)
!               return mb_utf_wcswidth((const unsigned char *) pwcs, len);
!       else
        {
!               /*
!                * obviously, other encodings may want to fix this, but I don't 
know
!                * them myself, unfortunately.
!                */
!               return len;
        }
  }
  
! char *
! mbvalidate(char *pwcs, int encoding)
  {
        if (encoding == PG_UTF8)
                mb_utf_validate((unsigned char *) pwcs);
--- 145,331 ----
   * public functions : wcswidth and mbvalidate
   */
  
+ /*
+  * pg_wcswidth is the dumb width function. It assumes that everything will
+  * only appear on one line. OTOH it is easier to use if this applies to you.
+  */
  int
! pg_wcswidth(const unsigned char *pwcs, size_t len, int encoding)
  {
!       int width = 0;
!       while( len > 0 )
        {
!               int chlen, chwidth;
!               chlen = PQmblen( pwcs, encoding );
!               if( chlen > len )
!                       break;     /* Invalid string */
!                       
!               chwidth = PQdsplen( pwcs, encoding );
!               
!               if( chwidth > 0 )
!                       width += chwidth;
!               pwcs += chlen;
!       }
!       return width;
! }
! 
! /*
!  * pg_wcssize takes the given string in the given encoding and returns three
!  * values:
!  *    result_width: Width in display character of longest line in string
!  *    result_hieght: Number of lines in display output
!  *    result_format_size: Number of bytes required to store formatted 
representation of string
!  */
! int
! pg_wcssize( unsigned char *pwcs, size_t len, int encoding, int *result_width, 
int *result_height, int *result_format_size )
! {
!       int                     w,
!                               l = 0,
!                               linewidth = 0;
!       int width = 0;
!       int height = 1;
!       int format_size = 0;
! 
!       for (; *pwcs && len > 0; pwcs += l)
!       {
!               l = PQmblen(pwcs, encoding);
!               if ( len < (size_t) l)
!                       break;
!               w = PQdsplen(pwcs, encoding);
! 
!               if( l == 1 )   /* ASCII char */
!               {
!                       if( *pwcs == '\n' ) /* Newline */
!                       {
!                               if( linewidth > width )
!                                       width = linewidth;
!                               linewidth = 0;
!                               height+=1;
!                               format_size += 1;  /* For NUL char */
!                       }
!                       else if( *pwcs == '\r' )   /* Linefeed */
!                       {
!                               linewidth+=2;
!                               format_size+=2;
!                       }
!                       else if( w <= 0 )  /* Other control char */
!                       {
!                               linewidth+=4;
!                               format_size+=4;
!                       }
!                       else  /* Output itself */
!                       {
!                               linewidth++;
!                               format_size += 1;
!                       }
!               }
!               else if( w <= 0 )  /* Non-ascii control char */
!               {
!                       linewidth+=6;   /* \u0000 */
!                       format_size += 6;
!               }
!               else  /* All other chars */
!               {
!                       linewidth += w;
!                       format_size += l;
!               }
!               len -= l;
!       }
!       if( linewidth > width )
!               width = linewidth;
!       format_size += 1;
!       
!       /* Set results */
!       if( result_width )
!               *result_width = width;
!       if( result_height )
!               *result_height = height;
!       if( result_format_size )
!               *result_format_size = format_size;
!               
!       return width;
! }
! 
! void
! pg_wcsformat( unsigned char *pwcs, size_t len, int encoding, struct lineptr 
*lines, int count )
! {
!       int                     w,
!                               l = 0;
!       int linewidth = 0;
!       
!       char *ptr = lines->ptr;   /* Pointer to data area */
! 
!       for (; *pwcs && len > 0; pwcs += l)
!       {
!               l = PQmblen(pwcs,encoding);
!               if ( len < (size_t) l)
!                       break;
!               w = PQdsplen(pwcs,encoding);
! 
!               if( l == 1 )   /* single byte char char */
!               {
!                       if( *pwcs == '\n' ) /* Newline */
!                       {
!                               *ptr++ = 0;   /* NULL char */
!                               lines->width = linewidth;
!                               linewidth = 0;
!                               lines++, count--;
!                               if( count == 0 )
!                                       exit(1);   /* Screwup */        
!                                       
!                               lines->ptr = ptr;
!                       }
!                       else if( *pwcs == '\r' )   /* Linefeed */
!                       {
!                               strcpy( ptr, "\\r" );
!                               linewidth += 2;
!                               ptr+=2;
!                       }
!                       else if( w <= 0 )  /* Other control char */
!                       {
!                               sprintf( ptr, "\\x%02X", *pwcs );
!                               linewidth += 4;
!                               ptr += 4;
!                       }
!                       else  /* Output itself */
!                       {
!                               linewidth++;
!                               *ptr++ = *pwcs;
!                       }
!               }
!               else if( w <= 0 )  /* Non-ascii control char */
!               {
!                       if( encoding == PG_UTF8 )
!                               sprintf( ptr, "\\u%04X", utf2ucs(pwcs) );
!                       else
!                               /* This case cannot happen in the current
!                                * code because only UTF-8 signals multibyte
!                                * control characters. But we may need to
!                                * support it at some stage */
!                               sprintf( ptr, "\\u????" );
!                               
!                       ptr += 6;
!                       linewidth += 6;
!               }
!               else  /* All other chars */
!               {
!                       int i;
!                       for( i=0; i<l; i++ )
!                               *ptr++ = pwcs[i];
!                       linewidth += w;
!               }
!               len -= l;
        }
+       *ptr++ = 0;
+       lines->width = linewidth;
+       lines++, count--;
+       if( count > 0 )
+               lines->ptr = NULL;
+       return;
  }
  
! unsigned char *
! mbvalidate(unsigned char *pwcs, int encoding)
  {
        if (encoding == PG_UTF8)
                mb_utf_validate((unsigned char *) pwcs);
Index: src/bin/psql/mbprint.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/psql/mbprint.h,v
retrieving revision 1.8
diff -c -r1.8 mbprint.h
*** src/bin/psql/mbprint.h      24 Sep 2005 17:53:27 -0000      1.8
--- src/bin/psql/mbprint.h      26 Nov 2005 22:27:57 -0000
***************
*** 4,11 ****
  
  #include "mb/pg_wchar.h"
  
! extern char *mbvalidate(char *pwcs, int encoding);
  
! extern int    pg_wcswidth(const char *pwcs, size_t len, int encoding);
  
  #endif   /* MBPRINT_H */
--- 4,18 ----
  
  #include "mb/pg_wchar.h"
  
! struct lineptr {
!       unsigned char *ptr;
!       int width;
! };
  
! extern unsigned char *mbvalidate(unsigned char *pwcs, int encoding);
! 
! extern int    pg_wcswidth(const unsigned char *pwcs, size_t len, int 
encoding);
! extern void   pg_wcsformat( unsigned char *pwcs, size_t len, int encoding, 
struct lineptr *lines, int count );
! extern int    pg_wcssize( unsigned char *pwcs, size_t len, int encoding, int 
*width, int *height, int *format_size );
  
  #endif   /* MBPRINT_H */
Index: src/bin/psql/print.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/psql/print.c,v
retrieving revision 1.79
diff -c -r1.79 print.c
*** src/bin/psql/print.c        27 Oct 2005 13:34:47 -0000      1.79
--- src/bin/psql/print.c        26 Nov 2005 22:27:57 -0000
***************
*** 49,54 ****
--- 49,68 ----
        return tmp;
  }
  
+ static void *
+ pg_local_calloc(int count, size_t size)
+ {
+       void       *tmp;
+ 
+       tmp = calloc(count, size);
+       if (!tmp)
+       {
+               fprintf(stderr, _("out of memory\n"));
+               exit(EXIT_FAILURE);
+       }
+       return tmp;
+ }
+ 
  static int
  integer_digits(const char *my_str)
  {
***************
*** 87,92 ****
--- 101,107 ----
        return strlen(my_str) + additional_numeric_locale_len(my_str);
  }
  
+ /* Returns the appropriately formatted string in a new allocated block, 
caller must free */
  static char *
  format_numeric_locale(const char *my_str)
  {
***************
*** 342,354 ****
  {
        unsigned int col_count = 0;
        unsigned int cell_count = 0;
-       unsigned int *head_w,
-                          *cell_w;
        unsigned int i,
                                tmp;
        unsigned int *widths,
                                total_w;
!       const char *const * ptr;
  
        /* count columns */
        for (ptr = headers; *ptr; ptr++)
--- 357,376 ----
  {
        unsigned int col_count = 0;
        unsigned int cell_count = 0;
        unsigned int i,
                                tmp;
        unsigned int *widths,
                                total_w;
!       unsigned int *heights;
!       unsigned int *format_space;
!       unsigned char **format_buf;
!       
!       const char *const *ptr;
!       
!       struct lineptr **col_lineptrs;   /* pointers to line pointer for each 
column */
!       struct lineptr *lineptr_list;    /* complete list of linepointers */
!       
!       int *complete;                  /* Array remembering which columns have 
completed output */
  
        /* count columns */
        for (ptr = headers; *ptr; ptr++)
***************
*** 356,419 ****
  
        if (col_count > 0)
        {
!               widths = calloc(col_count, sizeof(*widths));
!               if (!widths)
!               {
!                       fprintf(stderr, _("out of memory\n"));
!                       exit(EXIT_FAILURE);
!               }
! 
!               head_w = calloc(col_count, sizeof(*head_w));
!               if (!head_w)
!               {
!                       fprintf(stderr, _("out of memory\n"));
!                       exit(EXIT_FAILURE);
!               }
        }
        else
        {
                widths = NULL;
!               head_w = NULL;
        }
! 
        /* count cells (rows * cols) */
        for (ptr = cells; *ptr; ptr++)
                cell_count++;
  
-       if (cell_count > 0)
-       {
-               cell_w = calloc(cell_count, sizeof(*cell_w));
-               if (!cell_w)
-               {
-                       fprintf(stderr, _("out of memory\n"));
-                       exit(EXIT_FAILURE);
-               }
-       }
-       else
-               cell_w = NULL;
- 
        /* calc column widths */
        for (i = 0; i < col_count; i++)
        {
!               tmp = pg_wcswidth(headers[i], strlen(headers[i]), encoding);
                if (tmp > widths[i])
                        widths[i] = tmp;
!               head_w[i] = tmp;
        }
  
        for (i = 0, ptr = cells; *ptr; ptr++, i++)
        {
!               int                     add_numeric_locale_len;
  
                if (opt_align[i % col_count] == 'r' && opt_numeric_locale)
!                       add_numeric_locale_len = 
additional_numeric_locale_len(*ptr);
!               else
!                       add_numeric_locale_len = 0;
! 
!               tmp = pg_wcswidth(*ptr, strlen(*ptr), encoding) + 
add_numeric_locale_len;
                if (tmp > widths[i % col_count])
                        widths[i % col_count] = tmp;
!               cell_w[i] = tmp;
        }
  
        if (opt_border == 0)
--- 378,438 ----
  
        if (col_count > 0)
        {
!               widths = pg_local_calloc(col_count, sizeof(*widths));
!               heights = pg_local_calloc(col_count, sizeof(*heights));
!               col_lineptrs = pg_local_calloc( col_count, 
sizeof(*col_lineptrs) );
!               format_space = pg_local_calloc( col_count, 
sizeof(*format_space) );
!               format_buf = pg_local_calloc( col_count, sizeof(*format_buf) );
!               complete = pg_local_calloc( col_count, sizeof(*complete) );
!       
        }
        else
        {
                widths = NULL;
!               heights = NULL;
!               col_lineptrs = NULL;
!               format_space = NULL;
!               format_buf = NULL;
!               complete = NULL;
        }
!       
        /* count cells (rows * cols) */
        for (ptr = cells; *ptr; ptr++)
                cell_count++;
  
        /* calc column widths */
        for (i = 0; i < col_count; i++)
        {
!               /* Get width & height */
!               int height, space;
!               pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), 
encoding, &tmp, &height, &space);
                if (tmp > widths[i])
                        widths[i] = tmp;
!               if (height > heights[i])
!                       heights[i] = height;
!               if (space > format_space[i])
!                       format_space[i] = space;
        }
  
        for (i = 0, ptr = cells; *ptr; ptr++, i++)
        {
!               int numeric_locale_len;
!               int height, space;
  
                if (opt_align[i % col_count] == 'r' && opt_numeric_locale)
!                       numeric_locale_len = 
additional_numeric_locale_len(*ptr);
!               else 
!                       numeric_locale_len = 0;
!               
!               /* Get width, ignore height */
!               pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding, 
&tmp, &height, &space);
!               tmp += numeric_locale_len;
                if (tmp > widths[i % col_count])
                        widths[i % col_count] = tmp;
!               if (height > heights[i % col_count])
!                       heights[i % col_count] = height;
!               if (space > format_space[i % col_count])
!                       format_space[i % col_count] = space;
        }
  
        if (opt_border == 0)
***************
*** 426,435 ****
        for (i = 0; i < col_count; i++)
                total_w += widths[i];
  
        /* print title */
        if (title && !opt_tuples_only)
        {
!               tmp = pg_wcswidth(title, strlen(title), encoding);
                if (tmp >= total_w)
                        fprintf(fout, "%s\n", title);
                else
--- 445,482 ----
        for (i = 0; i < col_count; i++)
                total_w += widths[i];
  
+       /* At this point:
+        *  widths contains the max width of each column
+        *  heights contains the max height of a cell of each column
+        *  format_space contains maximum space required to store formatted 
string
+        * so we prepare the formatting structures
+        */
+       {
+               int heights_total = 0;
+               struct lineptr *lineptr;
+               
+               for( i=0; i < col_count; i++ )
+                       heights_total += heights[i];
+                       
+               lineptr = lineptr_list = pg_local_calloc( heights_total, 
sizeof(*lineptr_list) );
+                       
+               for( i=0; i < col_count; i++ )
+               {
+                       col_lineptrs[i] = lineptr;
+                       lineptr += heights[i];
+                       
+                       format_buf[i] = pg_local_malloc( format_space[i] );
+                       
+                       col_lineptrs[i]->ptr = format_buf[i];
+               }
+       }
+                       
        /* print title */
        if (title && !opt_tuples_only)
        {
!               /* Get width & height */
!               int height;
!               pg_wcssize((unsigned char *) title, strlen(title), encoding, 
&tmp, &height, NULL );
                if (tmp >= total_w)
                        fprintf(fout, "%s\n", title);
                else
***************
*** 439,528 ****
        /* print headers */
        if (!opt_tuples_only)
        {
                if (opt_border == 2)
                        _print_horizontal_line(col_count, widths, opt_border, 
fout);
  
-               if (opt_border == 2)
-                       fputs("| ", fout);
-               else if (opt_border == 1)
-                       fputc(' ', fout);
- 
                for (i = 0; i < col_count; i++)
                {
!                       unsigned int nbspace;
  
!                       nbspace = widths[i] - head_w[i];
  
!                       /* centered */
!                       fprintf(fout, "%-*s%s%-*s",
!                                       nbspace / 2, "", headers[i], (nbspace + 
1) / 2, "");
  
!                       if (i < col_count - 1)
!                       {
!                               if (opt_border == 0)
!                                       fputc(' ', fout);
                                else
!                                       fputs(" | ", fout);
                        }
                }
  
-               if (opt_border == 2)
-                       fputs(" |", fout);
-               else if (opt_border == 1)
-                       fputc(' ', fout);;
-               fputc('\n', fout);
  
                _print_horizontal_line(col_count, widths, opt_border, fout);
        }
  
        /* 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')
!               {
!                       if (opt_numeric_locale)
                        {
!                               char       *my_cell = 
format_numeric_locale(*ptr);
  
!                               fprintf(fout, "%*s%s", widths[i % col_count] - 
cell_w[i], "", my_cell);
!                               free(my_cell);
                        }
-                       else
-                               fprintf(fout, "%*s%s", widths[i % col_count] - 
cell_w[i], "", *ptr);
-               }
-               else
-               {
-                       if ((i + 1) % col_count == 0 && opt_border != 2)
-                               fputs(cells[i], fout);
-                       else
-                               fprintf(fout, "%-s%*s", cells[i],
-                                               widths[i % col_count] - 
cell_w[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);
                }
        }
  
--- 486,629 ----
        /* print headers */
        if (!opt_tuples_only)
        {
+               int cols_todo;
+               int line_count;
+               
                if (opt_border == 2)
                        _print_horizontal_line(col_count, widths, opt_border, 
fout);
  
                for (i = 0; i < col_count; i++)
+                       pg_wcsformat( (unsigned char *)headers[i], 
strlen(headers[i]), encoding, col_lineptrs[i], heights[i] );
+       
+               cols_todo = col_count;
+               line_count = 0;
+               memset( complete, 0, col_count*sizeof(int) );
+               while( cols_todo )
                {
!                       if (opt_border == 2)
!                               fprintf(fout, "|%c", line_count ? '+' : ' ' );
!                       else if (opt_border == 1)
!                               fputc(line_count ? '+' : ' ', fout);
  
!                       for (i = 0; i < col_count; i++)
!                       {
!                               unsigned int nbspace;
  
!                               struct lineptr *this_line = col_lineptrs[i] + 
line_count;
!                               if( !complete[i] )
!                               {
!                                       nbspace = widths[i] - this_line->width;
  
!                                       /* centered */
!                                       fprintf(fout, "%-*s%s%-*s",
!                                                       nbspace / 2, "", 
this_line->ptr, (nbspace + 1) / 2, "");
! 
!                                       if( line_count == (heights[i]-1) || 
!(this_line+1)->ptr )
!                                       {
!                                               cols_todo--;
!                                               complete[i] = 1;
!                                       }
!                               }
                                else
!                               {
!                                       fprintf( fout, "%*s", widths[i], "" );
!                               }
!                               if (i < col_count - 1)
!                               {
!                                       if (opt_border == 0)
!                                               fputc(line_count ? '+' : ' ', 
fout);
!                                       else
!                                               fprintf( fout, " |%c", 
line_count ? '+' : ' ');
!                               }
                        }
+                       line_count++;
+ 
+                       if (opt_border == 2)
+                               fputs(" |", fout);
+                       else if (opt_border == 1)
+                               fputc(' ', fout);;
+                       fputc('\n', fout);
                }
  
  
                _print_horizontal_line(col_count, widths, opt_border, fout);
        }
  
        /* print cells */
!       for (i = 0, ptr = cells; *ptr; i+=col_count, ptr+=col_count)
        {
!               int j;
!               int cols_todo = col_count;
!               int line_count;                 /* Number of lines output so 
far in row */
!               
!               for (j = 0; j < col_count; j++)
!                       pg_wcsformat( (unsigned char*)ptr[j], strlen(ptr[j]), 
encoding, col_lineptrs[j], heights[j] );
!       
!               line_count = 0;
!               memset( complete, 0, col_count*sizeof(int) );
!               while( cols_todo )
                {
+                       /* beginning of line */
                        if (opt_border == 2)
                                fputs("| ", fout);
                        else if (opt_border == 1)
                                fputc(' ', fout);
  
!                       for (j = 0; j < col_count; j++)
                        {
!                               struct lineptr *this_line = col_lineptrs[j] + 
line_count;
!                               if( complete[j] )  /* Just print spaces... */
!                               {
!                                       fprintf(fout, "%*s", widths[j], "");
!                               }
!                               else
!                               {
  
!                                       /* content */
!                                       if (opt_align[j] == 'r')
!                                       {
!                                               if (opt_numeric_locale)
!                                               {
!                                                       /* Assumption: This 
code used only on strings
!                                                        * without multibyte 
characters, otherwise
!                                                        * this_line->width < 
strlen(this_ptr) and we
!                                                        * get an overflow */
! 
!                                                       char *my_cell = 
format_numeric_locale(this_line->ptr);
!                                                       fprintf(fout, "%*s%s", 
widths[i % col_count] - strlen(my_cell), "", my_cell);
!                                                       free(my_cell);
!                                               }
!                                               else
!                                                       fprintf(fout, "%*s%s", 
widths[j] - this_line->width, "", this_line->ptr);
!                                       }
!                                       else
!                                       {
!                                               fprintf(fout, "%-s%*s", 
this_line->ptr,
!                                                               widths[j] - 
this_line->width, "");
!                                       }
!                                       /* If at the right height, done this 
col */
!                                       if( line_count == heights[j]-1 || 
!this_line[1].ptr )
!                                       {
!                                               complete[j] = 1;
!                                               cols_todo--;
!                                       }
!                               }
!       
!                               /* divider */
!                               if ((j + 1) % col_count)
!                               {
!                                       if (opt_border == 0)
!                                               fputc(' ', fout);
!                                       else if( line_count == 0 )
!                                               fputs(" | ", fout);
!                                       else
!                                               fprintf(fout, " %c ", 
complete[j+1] ? ' ' : ':');
!                               }
                        }
                        if (opt_border == 2)
                                fputs(" |", fout);
                        fputc('\n', fout);
+                       line_count++;
                }
        }
  
***************
*** 543,551 ****
  #endif
  
        /* clean up */
-       free(cell_w);
-       free(head_w);
        free(widths);
  }
  
  
--- 644,658 ----
  #endif
  
        /* clean up */
        free(widths);
+       free(heights);
+       free(col_lineptrs);
+       free(format_space);
+       free(complete);
+       free(lineptr_list);
+       for( i=0; i<col_count; i++ )
+               free(format_buf[i] );
+       free(format_buf);
  }
  
  
***************
*** 563,574 ****
        unsigned int i,
                                tmp = 0,
                                hwidth = 0,
!                               dwidth = 0;
        char       *divider;
        unsigned int cell_count = 0;
!       unsigned int *cell_w,
!                          *head_w;
! 
        if (cells[0] == NULL)
        {
                fprintf(fout, _("(No rows)\n"));
--- 670,684 ----
        unsigned int i,
                                tmp = 0,
                                hwidth = 0,
!                               dwidth = 0,
!                               hheight = 1,
!                               dheight = 1,
!                               hformatsize = 0,
!                               dformatsize = 0;
        char       *divider;
        unsigned int cell_count = 0;
!       struct lineptr *hlineptr, *dlineptr;
!       
        if (cells[0] == NULL)
        {
                fprintf(fout, _("(No rows)\n"));
***************
*** 578,635 ****
        /* count headers and find longest one */
        for (ptr = headers; *ptr; ptr++)
                col_count++;
-       if (col_count > 0)
-       {
-               head_w = calloc(col_count, sizeof(*head_w));
-               if (!head_w)
-               {
-                       fprintf(stderr, _("out of memory\n"));
-                       exit(EXIT_FAILURE);
-               }
-       }
-       else
-               head_w = NULL;
  
        for (i = 0; i < col_count; i++)
        {
!               tmp = pg_wcswidth(headers[i], strlen(headers[i]), encoding);
                if (tmp > hwidth)
                        hwidth = tmp;
!               head_w[i] = tmp;
        }
  
        /* Count cells, find their lengths */
        for (ptr = cells; *ptr; ptr++)
                cell_count++;
  
-       if (cell_count > 0)
-       {
-               cell_w = calloc(cell_count, sizeof(*cell_w));
-               if (!cell_w)
-               {
-                       fprintf(stderr, _("out of memory\n"));
-                       exit(EXIT_FAILURE);
-               }
-       }
-       else
-               cell_w = NULL;
- 
        /* find longest data cell */
        for (i = 0, ptr = cells; *ptr; ptr++, i++)
        {
!               int                     add_numeric_locale_len;
  
                if (opt_align[i % col_count] == 'r' && opt_numeric_locale)
!                       add_numeric_locale_len = 
additional_numeric_locale_len(*ptr);
!               else
!                       add_numeric_locale_len = 0;
  
!               tmp = pg_wcswidth(*ptr, strlen(*ptr), encoding) + 
add_numeric_locale_len;
                if (tmp > dwidth)
                        dwidth = tmp;
!               cell_w[i] = tmp;
!       }
! 
        /* print title */
        if (!opt_tuples_only && title)
                fprintf(fout, "%s\n", title);
--- 688,739 ----
        /* count headers and find longest one */
        for (ptr = headers; *ptr; ptr++)
                col_count++;
  
+       /* Find the maximum dimensions for the headers */
        for (i = 0; i < col_count; i++)
        {
!               int height, fs;
!               pg_wcssize((unsigned char *) headers[i], strlen(headers[i]), 
encoding, &tmp, &height, &fs);
                if (tmp > hwidth)
                        hwidth = tmp;
!               if (height > hheight )
!                       hheight = height;
!               if (fs > hformatsize)
!                       hformatsize = fs;
        }
  
        /* Count cells, find their lengths */
        for (ptr = cells; *ptr; ptr++)
                cell_count++;
  
        /* find longest data cell */
        for (i = 0, ptr = cells; *ptr; ptr++, i++)
        {
!               int numeric_locale_len;
!               int height, fs;
  
                if (opt_align[i % col_count] == 'r' && opt_numeric_locale)
!                       numeric_locale_len = 
additional_numeric_locale_len(*ptr);
!               else 
!                       numeric_locale_len = 0;
  
!               pg_wcssize((unsigned char *) *ptr, strlen(*ptr), encoding, 
&tmp, &height, &fs);
!               tmp += numeric_locale_len;
                if (tmp > dwidth)
                        dwidth = tmp;
!               if (height > dheight)
!                       dheight = height;
!               if (fs > dformatsize)
!                       dformatsize = fs;
!       }
!       
!       /* We now have all the information we need to setup the formatting 
structures */
!       dlineptr = pg_local_malloc( sizeof(*dlineptr) * dheight );
!       hlineptr = pg_local_malloc( sizeof(*hlineptr) * hheight );
!       
!       dlineptr->ptr = pg_local_malloc( dformatsize );
!       hlineptr->ptr = pg_local_malloc( hformatsize );
!       
        /* print title */
        if (!opt_tuples_only && title)
                fprintf(fout, "%s\n", title);
***************
*** 653,658 ****
--- 757,764 ----
        /* print records */
        for (i = 0, ptr = cells; *ptr; i++, ptr++)
        {
+               int line_count, dcomplete, hcomplete;
+               
                if (i % col_count == 0)
                {
                        if (!opt_tuples_only)
***************
*** 688,720 ****
                                fprintf(fout, "%s\n", divider);
                }
  
!               if (opt_border == 2)
!                       fputs("| ", fout);
!               fprintf(fout, "%-s%*s", headers[i % col_count],
!                               hwidth - head_w[i % col_count], "");
! 
!               if (opt_border > 0)
!                       fputs(" | ", fout);
!               else
!                       fputs(" ", fout);
! 
!               if (opt_align[i % col_count] == 'r' && opt_numeric_locale)
                {
!                       char       *my_cell = format_numeric_locale(*ptr);
! 
!                       if (opt_border < 2)
!                               fprintf(fout, "%s\n", my_cell);
                        else
!                               fprintf(fout, "%-s%*s |\n", my_cell, dwidth - 
cell_w[i], "");
!                       free(my_cell);
!               }
!               else
!               {
!                       if (opt_border < 2)
!                               fprintf(fout, "%s\n", *ptr);
                        else
!                               fprintf(fout, "%-s%*s |\n", *ptr, dwidth - 
cell_w[i], "");
!               }
        }
  
        if (opt_border == 2)
--- 794,859 ----
                                fprintf(fout, "%s\n", divider);
                }
  
!               /* Format the header */
!               pg_wcsformat( (unsigned char*)headers[i % col_count], 
strlen(headers[i % col_count]), encoding, hlineptr, hheight );
!               /* Format the data */
!               pg_wcsformat( (unsigned char*)*ptr, strlen(*ptr), encoding, 
dlineptr, dheight );
!               
!               line_count = 0;
!               dcomplete = hcomplete = 0;
!               while( !dcomplete || !hcomplete )
                {
!                       if (opt_border == 2)
!                               fputs("| ", fout);
!                       if( !hcomplete )
!                       {
!                               fprintf(fout, "%-s%*s", 
hlineptr[line_count].ptr,
!                                               hwidth - 
hlineptr[line_count].width, "");
!                                               
!                               if( line_count == (hheight-1) || 
!hlineptr[line_count+1].ptr )
!                                       hcomplete = 1;
!                       }
                        else
!                       {
!                               fprintf( fout, "%*s", hwidth, "" );
!                       }
!       
!                       if (opt_border > 0)
!                               fprintf(fout, " %c ", (line_count==0)?'|':':' );
                        else
!                               fputs(" ", fout);
! 
!                       if( !dcomplete )
!                       {
!                               if (opt_align[i % col_count] == 'r' && 
opt_numeric_locale)
!                               {
!                                       char *my_cell = 
format_numeric_locale(dlineptr[line_count].ptr);
!                                       if (opt_border < 2)
!                                               fprintf(fout, "%s\n", my_cell);
!                                       else
!                                               fprintf(fout, "%-s%*s |\n", 
my_cell, dwidth - strlen(my_cell), "");
!                                       free(my_cell);
!                               }
!                               else
!                               {
!                                       if (opt_border < 2)
!                                               fprintf(fout, "%s\n", 
dlineptr[line_count].ptr);
!                                       else
!                                               fprintf(fout, "%-s%*s |\n", 
dlineptr[line_count].ptr, dwidth - dlineptr[line_count].width, "");
!                               }
!                               
!                               if( line_count == (dheight-1) || 
!dlineptr[line_count+1].ptr )
!                                       dcomplete = 1;
!                       }
!                       else
!                       {
!                               if( opt_border < 2 )
!                                       fputc('\n', fout);
!                               else
!                                       fprintf( fout, "%*s |\n", dwidth, "" );
!                       }
!                       line_count++;
!               }
        }
  
        if (opt_border == 2)
***************
*** 732,740 ****
  
        fputc('\n', fout);
        free(divider);
! 
!       free(cell_w);
!       free(head_w);
  }
  
  
--- 871,880 ----
  
        fputc('\n', fout);
        free(divider);
!       free(hlineptr->ptr);
!       free(dlineptr->ptr);
!       free(hlineptr);
!       free(dlineptr);
  }
  
  
***************
*** 1613,1636 ****
        /* extract headers */
        nfields = PQnfields(result);
  
!       headers = calloc(nfields + 1, sizeof(*headers));
!       if (!headers)
!       {
!               fprintf(stderr, _("out of memory\n"));
!               exit(EXIT_FAILURE);
!       }
  
        for (i = 0; i < nfields; i++)
                headers[i] = mbvalidate(PQfname(result, i), opt->topt.encoding);
  
        /* set cells */
        ncells = PQntuples(result) * nfields;
!       cells = calloc(ncells + 1, sizeof(*cells));
!       if (!cells)
!       {
!               fprintf(stderr, _("out of memory\n"));
!               exit(EXIT_FAILURE);
!       }
  
        for (i = 0; i < ncells; i++)
        {
--- 1753,1766 ----
        /* extract headers */
        nfields = PQnfields(result);
  
!       headers = pg_local_calloc(nfields + 1, sizeof(*headers));
  
        for (i = 0; i < nfields; i++)
                headers[i] = mbvalidate(PQfname(result, i), opt->topt.encoding);
  
        /* set cells */
        ncells = PQntuples(result) * nfields;
!       cells = pg_local_calloc(ncells + 1, sizeof(*cells));
  
        for (i = 0; i < ncells; i++)
        {
***************
*** 1646,1657 ****
                footers = opt->footers;
        else if (!opt->topt.expanded && opt->default_footer)
        {
!               footers = calloc(2, sizeof(*footers));
!               if (!footers)
!               {
!                       fprintf(stderr, _("out of memory\n"));
!                       exit(EXIT_FAILURE);
!               }
  
                footers[0] = pg_local_malloc(100);
                if (PQntuples(result) == 1)
--- 1776,1782 ----
                footers = opt->footers;
        else if (!opt->topt.expanded && opt->default_footer)
        {
!               footers = pg_local_calloc(2, sizeof(*footers));
  
                footers[0] = pg_local_malloc(100);
                if (PQntuples(result) == 1)
***************
*** 1663,1674 ****
                footers = NULL;
  
        /* set alignment */
!       align = calloc(nfields + 1, sizeof(*align));
!       if (!align)
!       {
!               fprintf(stderr, _("out of memory\n"));
!               exit(EXIT_FAILURE);
!       }
  
        for (i = 0; i < nfields; i++)
        {
--- 1788,1794 ----
                footers = NULL;
  
        /* set alignment */
!       align = pg_local_calloc(nfields + 1, sizeof(*align));
  
        for (i = 0; i < nfields; i++)
        {

Attachment: pgphWU0i9ioL0.pgp
Description: PGP signature

Reply via email to