Modified patch attached and applied. I made some style changes and had
some merge conflicts because wchar.c has changed since 8.1.
The change to libpq's PQdsplen() seems like a good one and I will
mention it in the release notes.
---------------------------------------------------------------------------
Martijn van Oosterhout wrote:
-- Start of PGP signed section.
> [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.
[ Attachment, skipping... ]
-- End of PGP section, PGP failed!
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Index: src/backend/utils/mb/wchar.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/mb/wchar.c,v
retrieving revision 1.52
diff -c -c -r1.52 wchar.c
*** src/backend/utils/mb/wchar.c 26 Dec 2005 19:30:44 -0000 1.52
--- src/backend/utils/mb/wchar.c 10 Feb 2006 00:23:32 -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.
+ *
*/
/*
***************
*** 53,58 ****
--- 60,70 ----
static int
pg_ascii_dsplen(const unsigned char *s)
{
+ if (*s == '\0')
+ return 0;
+ if (*s < 0x20 || *s == 0x7f)
+ return -1;
+
return 1;
}
***************
*** 125,131 ****
else if (IS_HIGHBIT_SET(*s))
len = 2;
else
! len = 1;
return len;
}
--- 137,143 ----
else if (IS_HIGHBIT_SET(*s))
len = 2;
else
! len = pg_ascii_dsplen(s);
return len;
}
***************
*** 156,162 ****
else if (IS_HIGHBIT_SET(*s))
len = 2;
else
! len = 1;
return len;
}
--- 168,174 ----
else if (IS_HIGHBIT_SET(*s))
len = 2;
else
! len = pg_ascii_dsplen(s);
return len;
}
***************
*** 244,250 ****
if (IS_HIGHBIT_SET(*s))
len = 2;
else
! len = 1;
return len;
}
--- 256,262 ----
if (IS_HIGHBIT_SET(*s))
len = 2;
else
! len = pg_ascii_dsplen(s);
return len;
}
***************
*** 304,310 ****
else if (IS_HIGHBIT_SET(*s))
len = 2;
else
! len = 1;
return len;
}
--- 316,322 ----
else if (IS_HIGHBIT_SET(*s))
len = 2;
else
! len = pg_ascii_dsplen(s);
return len;
}
***************
*** 320,326 ****
else if (IS_HIGHBIT_SET(*s))
len = 2;
else
! len = 1;
return len;
}
--- 332,338 ----
else if (IS_HIGHBIT_SET(*s))
len = 2;
else
! len = pg_ascii_dsplen(s);
return len;
}
***************
*** 419,428 ****
return len;
}
static int
pg_utf_dsplen(const unsigned char *s)
{
! return 1; /* XXX fix me! */
}
/*
--- 431,609 ----
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 < 0x20 || (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));
}
/*
***************
*** 499,505 ****
static int
pg_mule_dsplen(const unsigned char *s)
{
! return 1; /* XXX fix me! */
}
/*
--- 680,686 ----
static int
pg_mule_dsplen(const unsigned char *s)
{
! return pg_ascii_dsplen(s); /* XXX fix me! */
}
/*
***************
*** 529,535 ****
static int
pg_latin1_dsplen(const unsigned char *s)
{
! return 1;
}
/*
--- 710,716 ----
static int
pg_latin1_dsplen(const unsigned char *s)
{
! return pg_ascii_dsplen(s);
}
/*
***************
*** 559,565 ****
else if (IS_HIGHBIT_SET(*s))
len = 2; /* kanji? */
else
! len = 1; /* should be ASCII */
return len;
}
--- 740,746 ----
else if (IS_HIGHBIT_SET(*s))
len = 2; /* kanji? */
else
! len = pg_ascii_dsplen(s); /* should be ASCII */
return len;
}
***************
*** 586,592 ****
if (IS_HIGHBIT_SET(*s))
len = 2; /* kanji? */
else
! len = 1; /* should be ASCII */
return len;
}
--- 767,773 ----
if (IS_HIGHBIT_SET(*s))
len = 2; /* kanji? */
else
! len = pg_ascii_dsplen(s); /* should be ASCII */
return len;
}
***************
*** 613,619 ****
if (IS_HIGHBIT_SET(*s))
len = 2; /* kanji? */
else
! len = 1; /* should be ASCII */
return len;
}
--- 794,800 ----
if (IS_HIGHBIT_SET(*s))
len = 2; /* kanji? */
else
! len = pg_ascii_dsplen(s); /* should be ASCII */
return len;
}
***************
*** 640,646 ****
if (IS_HIGHBIT_SET(*s))
len = 2; /* 2byte? */
else
! len = 1; /* should be ASCII */
return len;
}
--- 821,827 ----
if (IS_HIGHBIT_SET(*s))
len = 2; /* 2byte? */
else
! len = pg_ascii_dsplen(s); /* should be ASCII */
return len;
}
***************
*** 672,681 ****
{
int len;
! if (!IS_HIGHBIT_SET(*s))
! len = 1; /* ASCII */
! else
len = 2;
return len;
}
--- 853,862 ----
{
int len;
! if (IS_HIGHBIT_SET(*s))
len = 2;
+ else
+ len = pg_ascii_dsplen(s); /* ASCII */
return len;
}
Index: src/bin/psql/mbprint.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/mbprint.c,v
retrieving revision 1.18
diff -c -c -r1.18 mbprint.c
*** src/bin/psql/mbprint.c 15 Oct 2005 02:49:40 -0000 1.18
--- src/bin/psql/mbprint.c 10 Feb 2006 00:23:33 -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,225 ****
}
}
- /* 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)
{
- /*
- * Unicode 3.1 compliant validation : for each category, it checks the
- * combination of each byte to make sur it maps to a valid range. It also
- * returns -1 for the following UCS values: ucs > 0x10ffff ucs & 0xfffe =
- * 0xfffe 0xfdd0 < ucs < 0xfdef ucs & 0xdb00 = 0xd800 (surrogates)
- */
if ((*c & 0x80) == 0)
return 1;
else if ((*c & 0xe0) == 0xc0)
--- 48,63 ----
}
}
+ /*
+ * Unicode 3.1 compliant validation : for each category, it checks the
+ * combination of each byte to make sure it maps to a valid range. It also
+ * returns -1 for the following UCS values: ucs > 0x10ffff ucs & 0xfffe =
+ * 0xfffe 0xfdd0 < ucs < 0xfdef ucs & 0xdb00 = 0xd800 (surrogates)
+ */
static int
utf_charcheck(const unsigned char *c)
{
if ((*c & 0x80) == 0)
return 1;
else if ((*c & 0xe0) == 0xc0)
***************
*** 270,275 ****
--- 108,114 ----
return -1;
}
+
static void
mb_utf_validate(unsigned char *pwcs)
{
***************
*** 277,304 ****
while (*pwcs)
{
! int l;
! if ((l = utf_charcheck(pwcs)) > 0)
{
if (p != pwcs)
{
int i;
! for (i = 0; i < l; i++)
*p++ = *pwcs++;
}
else
{
! pwcs += l;
! p += l;
}
}
else
- {
/* we skip the char */
pwcs++;
- }
}
if (p != pwcs)
*p = '\0';
--- 116,141 ----
while (*pwcs)
{
! int len;
! if ((len = utf_charcheck(pwcs)) > 0)
{
if (p != pwcs)
{
int i;
! for (i = 0; i < len; i++)
*p++ = *pwcs++;
}
else
{
! pwcs += len;
! p += len;
}
}
else
/* we skip the char */
pwcs++;
}
if (p != pwcs)
*p = '\0';
***************
*** 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,337 ----
* 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,
! chlen = 0,
! linewidth = 0;
! int width = 0;
! int height = 1;
! int format_size = 0;
!
! for (; *pwcs && len > 0; pwcs += chlen)
! {
! chlen = PQmblen(pwcs, encoding);
! if (len < (size_t)chlen)
! break;
! w = PQdsplen(pwcs, encoding);
!
! if (chlen == 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 += chlen;
! }
! len -= chlen;
! }
! 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,
! chlen = 0;
! int linewidth = 0;
!
! char *ptr = lines->ptr; /* Pointer to data area */
!
! for (; *pwcs && len > 0; pwcs += chlen)
! {
! chlen = PQmblen(pwcs,encoding);
! if (len < (size_t)chlen)
! break;
! w = PQdsplen(pwcs,encoding);
!
! if (chlen == 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 < chlen; i++)
! *ptr++ = pwcs[i];
! linewidth += w;
! }
! len -= chlen;
}
+ *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: /cvsroot/pgsql/src/bin/psql/mbprint.h,v
retrieving revision 1.8
diff -c -c -r1.8 mbprint.h
*** src/bin/psql/mbprint.h 24 Sep 2005 17:53:27 -0000 1.8
--- src/bin/psql/mbprint.h 10 Feb 2006 00:23:33 -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: /cvsroot/pgsql/src/bin/psql/print.c,v
retrieving revision 1.79
diff -c -c -r1.79 print.c
*** src/bin/psql/print.c 27 Oct 2005 13:34:47 -0000 1.79
--- src/bin/psql/print.c 10 Feb 2006 00:23:33 -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,623 ----
/* 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);
}
--- 638,652 ----
#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"));
--- 664,678 ----
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);
--- 682,733 ----
/* 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 ****
--- 751,758 ----
/* 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)
--- 788,853 ----
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);
}
--- 865,874 ----
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++)
{
--- 1747,1760 ----
/* 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)
--- 1770,1776 ----
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++)
{
--- 1782,1788 ----
footers = NULL;
/* set alignment */
! align = pg_local_calloc(nfields + 1, sizeof(*align));
for (i = 0; i < nfields; i++)
{