Index: doc/src/sgml/ref/psql-ref.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/ref/psql-ref.sgml,v
retrieving revision 1.146
retrieving revision 1.147
diff -c -r1.146 -r1.147
*** doc/src/sgml/ref/psql-ref.sgml	10 Jul 2005 03:46:12 -0000	1.146
--- doc/src/sgml/ref/psql-ref.sgml	14 Jul 2005 08:42:36 -0000	1.147
***************
*** 1,5 ****
  <!--
! $PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.146 2005/07/10 03:46:12 momjian Exp $
  PostgreSQL documentation
  -->
  
--- 1,5 ----
  <!--
! $PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.147 2005/07/14 08:42:36 momjian Exp $
  PostgreSQL documentation
  -->
  
***************
*** 1496,1505 ****
            <term><literal>numericsep</literal></term>
            <listitem>
            <para>
!           Specifies the character separator between groups of three digits
!           to the left of the decimal marker.  The default is <literal>''</>
!           (none).  Setting this to a period also changes the decimal marker 
!           to a comma.
            </para>
            </listitem>
            </varlistentry>
--- 1496,1504 ----
            <term><literal>numericsep</literal></term>
            <listitem>
            <para>
!           Toggles the display of a locale-aware character to separate groups
!           of digits to the left of the decimal marker.  It also enables
!           a locale-aware decimal marker.
            </para>
            </listitem>
            </varlistentry>
Index: src/bin/psql/command.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/command.c,v
retrieving revision 1.148
retrieving revision 1.149
diff -c -r1.148 -r1.149
*** src/bin/psql/command.c	14 Jul 2005 06:49:58 -0000	1.148
--- src/bin/psql/command.c	14 Jul 2005 08:42:37 -0000	1.149
***************
*** 3,9 ****
   *
   * Copyright (c) 2000-2005, PostgreSQL Global Development Group
   *
!  * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.148 2005/07/14 06:49:58 momjian Exp $
   */
  #include "postgres_fe.h"
  #include "command.h"
--- 3,9 ----
   *
   * Copyright (c) 2000-2005, PostgreSQL Global Development Group
   *
!  * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.149 2005/07/14 08:42:37 momjian Exp $
   */
  #include "postgres_fe.h"
  #include "command.h"
***************
*** 1420,1434 ****
  				   : _("Expanded display is off.\n"));
  	}
  
  	else if (strcmp(param, "numericsep") == 0)
  	{
! 		if (value)
  		{
! 			free(popt->topt.numericSep);
! 			popt->topt.numericSep = pg_strdup(value);
  		}
- 		if (!quiet)
- 			printf(_("Numeric separator is \"%s\".\n"), popt->topt.numericSep);
  	}
  
  	/* null display */
--- 1420,1436 ----
  				   : _("Expanded display is off.\n"));
  	}
  
+ 	/* numeric separators */
  	else if (strcmp(param, "numericsep") == 0)
  	{
! 		popt->topt.numericSep = !popt->topt.numericSep;
! 		if (!quiet)
  		{
! 			if (popt->topt.numericSep)
! 				puts(_("Showing numeric separators."));
! 			else
! 				puts(_("Numeric separators are off."));
  		}
  	}
  
  	/* null display */
Index: src/bin/psql/print.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/print.c,v
retrieving revision 1.66
retrieving revision 1.67
diff -c -r1.66 -r1.67
*** src/bin/psql/print.c	14 Jul 2005 07:32:01 -0000	1.66
--- src/bin/psql/print.c	14 Jul 2005 08:42:37 -0000	1.67
***************
*** 3,9 ****
   *
   * Copyright (c) 2000-2005, PostgreSQL Global Development Group
   *
!  * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.66 2005/07/14 07:32:01 momjian Exp $
   */
  #include "postgres_fe.h"
  #include "common.h"
--- 3,9 ----
   *
   * Copyright (c) 2000-2005, PostgreSQL Global Development Group
   *
!  * $PostgreSQL: pgsql/src/bin/psql/print.c,v 1.67 2005/07/14 08:42:37 momjian Exp $
   */
  #include "postgres_fe.h"
  #include "common.h"
***************
*** 24,34 ****
--- 24,40 ----
  #include <termios.h>
  #endif
  
+ #include <locale.h>
+ 
  #include "pqsignal.h"
  #include "libpq-fe.h"
  
  #include "mbprint.h"
  
+ static char *decimal_point;
+ static char *grouping;
+ static char *thousands_sep;
+ 
  static void *
  pg_local_malloc(size_t size)
  {
***************
*** 47,52 ****
--- 53,59 ----
  num_numericseps(const char *my_str)
  {
  	int old_len, dec_len, int_len;
+ 	int	groupdigits = atoi(grouping);
  
  	if (my_str[0] == '-')
  		my_str++;
***************
*** 55,64 ****
  	dec_len = strchr(my_str, '.') ? strlen(strchr(my_str, '.')) : 0;
  
  	int_len = old_len - dec_len;
! 	if (int_len % 3 != 0)
! 		return int_len / 3;
  	else
! 		return int_len / 3 - 1;	/* no leading separator */
  }
  
  static int
--- 62,71 ----
  	dec_len = strchr(my_str, '.') ? strlen(strchr(my_str, '.')) : 0;
  
  	int_len = old_len - dec_len;
! 	if (int_len % groupdigits != 0)
! 		return int_len / groupdigits;
  	else
! 		return int_len / groupdigits - 1;	/* no leading separator */
  }
  
  static int
***************
*** 68,84 ****
  }
  
  static void 
! format_numericsep(char *my_str, char *numericsep)
  {
  	int i, j, digits_before_sep, old_len, new_len, dec_len, int_len;
- 	char *dec_point;
  	char *new_str;
  	char *dec_value;
!     
! 	if (strcmp(numericsep, ".") != 0)
! 		dec_point = ".";
! 	else
! 		dec_point = ",";
      
  	if (my_str[0] == '-')
  		my_str++;
--- 75,86 ----
  }
  
  static void 
! format_numericsep(char *my_str)
  {
  	int i, j, digits_before_sep, old_len, new_len, dec_len, int_len;
  	char *new_str;
  	char *dec_value;
! 	int	groupdigits = atoi(grouping);
      
  	if (my_str[0] == '-')
  		my_str++;
***************
*** 86,94 ****
  	old_len = strlen(my_str);
  	dec_len = strchr(my_str, '.') ? strlen(strchr(my_str, '.')) : 0;
  	int_len = old_len - dec_len;
! 	digits_before_sep = int_len % 3;
  
! 	new_len = int_len + int_len / 3 + dec_len;
  	if (digits_before_sep == 0)
  		new_len--;	/* no leading separator */
  
--- 88,96 ----
  	old_len = strlen(my_str);
  	dec_len = strchr(my_str, '.') ? strlen(strchr(my_str, '.')) : 0;
  	int_len = old_len - dec_len;
! 	digits_before_sep = int_len % groupdigits;
  
! 	new_len = int_len + int_len / groupdigits + dec_len;
  	if (digits_before_sep == 0)
  		new_len--;	/* no leading separator */
  
***************
*** 99,105 ****
  		/* hit decimal point */
  		if (my_str[i] == '.')
  		{
! 			new_str[j] = *dec_point;
  			new_str[j+1] = '\0';
  			dec_value = strchr(my_str, '.');
  			strcat(new_str, ++dec_value);
--- 101,107 ----
  		/* hit decimal point */
  		if (my_str[i] == '.')
  		{
! 			new_str[j] = *decimal_point;
  			new_str[j+1] = '\0';
  			dec_value = strchr(my_str, '.');
  			strcat(new_str, ++dec_value);
***************
*** 115,122 ****
      
  		/* add separator? */
  		if (i != 0 &&
! 			(i - (digits_before_sep ? digits_before_sep : 3)) % 3 == 0)
! 			new_str[j++] = *numericsep;
  
  		new_str[j] = my_str[i];
  	}
--- 117,125 ----
      
  		/* add separator? */
  		if (i != 0 &&
! 			(i - (digits_before_sep ? digits_before_sep : groupdigits))
! 				% groupdigits == 0)
! 			new_str[j++] = *thousands_sep;
  
  		new_str[j] = my_str[i];
  	}
***************
*** 135,141 ****
  					 const char *const *cells, const char *const *footers,
  					 const char *opt_align, const char *opt_fieldsep,
  					 const char *opt_recordsep, bool opt_tuples_only,
! 					 char *opt_numericsep, FILE *fout)
  {
  	unsigned int col_count = 0;
  	unsigned int i;
--- 138,144 ----
  					 const char *const *cells, const char *const *footers,
  					 const char *opt_align, const char *opt_fieldsep,
  					 const char *opt_recordsep, bool opt_tuples_only,
! 					 bool opt_numericsep, FILE *fout)
  {
  	unsigned int col_count = 0;
  	unsigned int i;
***************
*** 174,186 ****
  			fputs(opt_recordsep, fout);
  			need_recordsep = false;
  		}
! 		if ((opt_align[i % col_count] == 'r') && strlen(*ptr) > 0 &&
! 			opt_numericsep != NULL && strlen(opt_numericsep) > 0)
  		{
  			char *my_cell = pg_local_malloc(len_with_numericsep(*ptr) + 1);
  		
  			strcpy(my_cell, *ptr);
! 			format_numericsep(my_cell, opt_numericsep);
  			fputs(my_cell, fout);
  			free(my_cell);
  		}
--- 177,188 ----
  			fputs(opt_recordsep, fout);
  			need_recordsep = false;
  		}
! 		if (opt_align[i % col_count] == 'r' && opt_numericsep)
  		{
  			char *my_cell = pg_local_malloc(len_with_numericsep(*ptr) + 1);
  		
  			strcpy(my_cell, *ptr);
! 			format_numericsep(my_cell);
  			fputs(my_cell, fout);
  			free(my_cell);
  		}
***************
*** 220,226 ****
  						 const char *const *cells,
  						 const char *const *footers, const char *opt_align,
  						 const char *opt_fieldsep, const char *opt_recordsep,
! 						 bool opt_tuples_only, char *opt_numericsep, FILE *fout)
  {
  	unsigned int col_count = 0;
  	unsigned int i;
--- 222,228 ----
  						 const char *const *cells,
  						 const char *const *footers, const char *opt_align,
  						 const char *opt_fieldsep, const char *opt_recordsep,
! 						 bool opt_tuples_only, bool opt_numericsep, FILE *fout)
  {
  	unsigned int col_count = 0;
  	unsigned int i;
***************
*** 251,263 ****
  
  		fputs(headers[i % col_count], fout);
  		fputs(opt_fieldsep, fout);
! 		if ((opt_align[i % col_count] == 'r') && strlen(*ptr) != 0 &&
! 			opt_numericsep != NULL && strlen(opt_numericsep) > 0)
  		{
  			char *my_cell = pg_local_malloc(len_with_numericsep(*ptr) + 1);
  		
  			strcpy(my_cell, *ptr);
! 			format_numericsep(my_cell, opt_numericsep);
  			fputs(my_cell, fout);
  			free(my_cell);
  		}
--- 253,264 ----
  
  		fputs(headers[i % col_count], fout);
  		fputs(opt_fieldsep, fout);
! 		if (opt_align[i % col_count] == 'r' && opt_numericsep)
  		{
  			char *my_cell = pg_local_malloc(len_with_numericsep(*ptr) + 1);
  		
  			strcpy(my_cell, *ptr);
! 			format_numericsep(my_cell);
  			fputs(my_cell, fout);
  			free(my_cell);
  		}
***************
*** 325,331 ****
  static void
  print_aligned_text(const char *title, const char *const *headers,
  				   const char *const *cells, const char *const *footers,
! 				   const char *opt_align, bool opt_tuples_only, char *opt_numericsep,
  				   unsigned short int opt_border, int encoding,
  				   FILE *fout)
  {
--- 326,332 ----
  static void
  print_aligned_text(const char *title, const char *const *headers,
  				   const char *const *cells, const char *const *footers,
! 				   const char *opt_align, bool opt_tuples_only, bool opt_numericsep,
  				   unsigned short int opt_border, int encoding,
  				   FILE *fout)
  {
***************
*** 394,401 ****
  	{
  		int numericseps;
  
! 		if ((opt_align[i % col_count] == 'r') && strlen(*ptr) != 0 &&
! 			opt_numericsep != NULL && strlen(opt_numericsep) > 0)
  		    numericseps = num_numericseps(*ptr);
  		else 
  		    numericseps = 0;
--- 395,401 ----
  	{
  		int numericseps;
  
! 		if (opt_align[i % col_count] == 'r' && opt_numericsep)
  		    numericseps = num_numericseps(*ptr);
  		else 
  		    numericseps = 0;
***************
*** 480,491 ****
  		/* content */
  		if (opt_align[i % col_count] == 'r')
  		{
! 		    if (strlen(*ptr) > 0 && opt_numericsep != NULL && strlen(opt_numericsep) > 0)
  		    {
  				char *my_cell = pg_local_malloc(cell_w[i] + 1);
  
  				strcpy(my_cell, *ptr);
! 				format_numericsep(my_cell, opt_numericsep);
  				fprintf(fout, "%*s%s", widths[i % col_count] - cell_w[i], "", my_cell);
  				free(my_cell);
  		    }
--- 480,491 ----
  		/* content */
  		if (opt_align[i % col_count] == 'r')
  		{
! 		    if (opt_numericsep)
  		    {
  				char *my_cell = pg_local_malloc(cell_w[i] + 1);
  
  				strcpy(my_cell, *ptr);
! 				format_numericsep(my_cell);
  				fprintf(fout, "%*s%s", widths[i % col_count] - cell_w[i], "", my_cell);
  				free(my_cell);
  		    }
***************
*** 547,553 ****
  print_aligned_vertical(const char *title, const char *const *headers,
  					   const char *const *cells, const char *const *footers,
  					   const char *opt_align, bool opt_tuples_only,
! 					   char *opt_numericsep, unsigned short int opt_border,
  					   int encoding, FILE *fout)
  {
  	unsigned int col_count = 0;
--- 547,553 ----
  print_aligned_vertical(const char *title, const char *const *headers,
  					   const char *const *cells, const char *const *footers,
  					   const char *opt_align, bool opt_tuples_only,
! 					   bool opt_numericsep, unsigned short int opt_border,
  					   int encoding, FILE *fout)
  {
  	unsigned int col_count = 0;
***************
*** 612,619 ****
  	{
  		int numericseps;
  
! 		if ((opt_align[i % col_count] == 'r') && strlen(*ptr) != 0 &&
! 			opt_numericsep != NULL && strlen(opt_numericsep) > 0)
  		    numericseps = num_numericseps(*ptr);
  		else 
  		    numericseps = 0;
--- 612,618 ----
  	{
  		int numericseps;
  
! 		if (opt_align[i % col_count] == 'r' && opt_numericsep)
  		    numericseps = num_numericseps(*ptr);
  		else 
  		    numericseps = 0;
***************
*** 696,704 ****
  			char *my_cell = pg_local_malloc(cell_w[i] + 1);
  
  			strcpy(my_cell, *ptr);
! 			if ((opt_align[i % col_count] == 'r') && strlen(*ptr) != 0 &&
! 				opt_numericsep != NULL && strlen(opt_numericsep) > 0)
! 			    format_numericsep(my_cell, opt_numericsep);
  			if (opt_border < 2)
  				puts(my_cell);
  			else
--- 695,702 ----
  			char *my_cell = pg_local_malloc(cell_w[i] + 1);
  
  			strcpy(my_cell, *ptr);
! 			if (opt_align[i % col_count] == 'r' && opt_numericsep)
! 			    format_numericsep(my_cell);
  			if (opt_border < 2)
  				puts(my_cell);
  			else
***************
*** 785,791 ****
  print_html_text(const char *title, const char *const *headers,
  				const char *const *cells, const char *const *footers,
  				const char *opt_align, bool opt_tuples_only,
! 				char *opt_numericsep, unsigned short int opt_border,
  				const char *opt_table_attr, FILE *fout)
  {
  	unsigned int col_count = 0;
--- 783,789 ----
  print_html_text(const char *title, const char *const *headers,
  				const char *const *cells, const char *const *footers,
  				const char *opt_align, bool opt_tuples_only,
! 				bool opt_numericsep, unsigned short int opt_border,
  				const char *opt_table_attr, FILE *fout)
  {
  	unsigned int col_count = 0;
***************
*** 831,843 ****
  		/* is string only whitespace? */
  		if ((*ptr)[strspn(*ptr, " \t")] == '\0')		
  			fputs("&nbsp; ", fout);
! 		else if ((opt_align[i % col_count] == 'r') && strlen(*ptr) != 0 &&
! 				 opt_numericsep != NULL && strlen(opt_numericsep) > 0)
  		{
  			char *my_cell = pg_local_malloc(len_with_numericsep(*ptr) + 1);
  
  		    strcpy(my_cell, *ptr);
! 		    format_numericsep(my_cell, opt_numericsep);
  		    html_escaped_print(my_cell, fout);
  		    free(my_cell);
  		}
--- 829,840 ----
  		/* is string only whitespace? */
  		if ((*ptr)[strspn(*ptr, " \t")] == '\0')		
  			fputs("&nbsp; ", fout);
! 		else if (opt_align[i % col_count] == 'r' && opt_numericsep)
  		{
  			char *my_cell = pg_local_malloc(len_with_numericsep(*ptr) + 1);
  
  		    strcpy(my_cell, *ptr);
! 		    format_numericsep(my_cell);
  		    html_escaped_print(my_cell, fout);
  		    free(my_cell);
  		}
***************
*** 873,879 ****
  print_html_vertical(const char *title, const char *const *headers,
  				  const char *const *cells, const char *const *footers,
  				  const char *opt_align, bool opt_tuples_only,
! 				  char *opt_numericsep, unsigned short int opt_border,
  				  const char *opt_table_attr, FILE *fout)
  {
  	unsigned int col_count = 0;
--- 870,876 ----
  print_html_vertical(const char *title, const char *const *headers,
  				  const char *const *cells, const char *const *footers,
  				  const char *opt_align, bool opt_tuples_only,
! 				  bool opt_numericsep, unsigned short int opt_border,
  				  const char *opt_table_attr, FILE *fout)
  {
  	unsigned int col_count = 0;
***************
*** 917,929 ****
  		/* is string only whitespace? */
  		if ((*ptr)[strspn(*ptr, " \t")] == '\0')		
  			fputs("&nbsp; ", fout);
! 		else if ((opt_align[i % col_count] == 'r') && strlen(*ptr) != 0 &&
! 			opt_numericsep != NULL && strlen(opt_numericsep) > 0)
  		{
  			char *my_cell = pg_local_malloc(len_with_numericsep(*ptr) + 1);
  		    
  		    strcpy(my_cell, *ptr);
! 		    format_numericsep(my_cell, opt_numericsep);
  		    html_escaped_print(my_cell, fout);
  		    free(my_cell);
  		}
--- 914,925 ----
  		/* is string only whitespace? */
  		if ((*ptr)[strspn(*ptr, " \t")] == '\0')		
  			fputs("&nbsp; ", fout);
! 		else if (opt_align[i % col_count] == 'r' && opt_numericsep)
  		{
  			char *my_cell = pg_local_malloc(len_with_numericsep(*ptr) + 1);
  		    
  		    strcpy(my_cell, *ptr);
! 		    format_numericsep(my_cell);
  		    html_escaped_print(my_cell, fout);
  		    free(my_cell);
  		}
***************
*** 999,1005 ****
  print_latex_text(const char *title, const char *const *headers,
  				 const char *const *cells, const char *const *footers,
  				 const char *opt_align, bool opt_tuples_only,
! 				 char *opt_numericsep, unsigned short int opt_border,
  				 FILE *fout)
  {
  	unsigned int col_count = 0;
--- 995,1001 ----
  print_latex_text(const char *title, const char *const *headers,
  				 const char *const *cells, const char *const *footers,
  				 const char *opt_align, bool opt_tuples_only,
! 				 bool opt_numericsep, unsigned short int opt_border,
  				 FILE *fout)
  {
  	unsigned int col_count = 0;
***************
*** 1060,1072 ****
  	/* print cells */
  	for (i = 0, ptr = cells; *ptr; i++, ptr++)
  	{
! 		if (strlen(*ptr) != 0 &&
! 			opt_numericsep != NULL && strlen(opt_numericsep) > 0)
  		{
  			char *my_cell = pg_local_malloc(len_with_numericsep(*ptr) + 1);
  		    
  			strcpy(my_cell, *ptr);
! 			format_numericsep(my_cell, opt_numericsep);
  			latex_escaped_print(my_cell, fout);
  			free(my_cell);
  		}
--- 1056,1067 ----
  	/* print cells */
  	for (i = 0, ptr = cells; *ptr; i++, ptr++)
  	{
! 		if (opt_numericsep)
  		{
  			char *my_cell = pg_local_malloc(len_with_numericsep(*ptr) + 1);
  		    
  			strcpy(my_cell, *ptr);
! 			format_numericsep(my_cell);
  			latex_escaped_print(my_cell, fout);
  			free(my_cell);
  		}
***************
*** 1103,1109 ****
  print_latex_vertical(const char *title, const char *const *headers,
  				  const char *const *cells, const char *const *footers,
  				  const char *opt_align, bool opt_tuples_only,
! 				  char *opt_numericsep, unsigned short int opt_border,
  				  FILE *fout)
  {
  	unsigned int col_count = 0;
--- 1098,1104 ----
  print_latex_vertical(const char *title, const char *const *headers,
  				  const char *const *cells, const char *const *footers,
  				  const char *opt_align, bool opt_tuples_only,
! 				  bool opt_numericsep, unsigned short int opt_border,
  				  FILE *fout)
  {
  	unsigned int col_count = 0;
***************
*** 1174,1186 ****
  	if (footers && !opt_tuples_only)
  		for (ptr = footers; *ptr; ptr++)
  		{
! 			if (strlen(*ptr) != 0 &&
! 				opt_numericsep != NULL && strlen(opt_numericsep) > 0)
  			{
  				char *my_cell = pg_local_malloc(len_with_numericsep(*ptr) + 1);
  
  				strcpy(my_cell, *ptr);
! 				format_numericsep(my_cell, opt_numericsep);
  				latex_escaped_print(my_cell, fout);
  				free(my_cell);
  			}
--- 1169,1180 ----
  	if (footers && !opt_tuples_only)
  		for (ptr = footers; *ptr; ptr++)
  		{
! 			if (opt_numericsep)
  			{
  				char *my_cell = pg_local_malloc(len_with_numericsep(*ptr) + 1);
  
  				strcpy(my_cell, *ptr);
! 				format_numericsep(my_cell);
  				latex_escaped_print(my_cell, fout);
  				free(my_cell);
  			}
***************
*** 1221,1227 ****
  print_troff_ms_text(const char *title, const char *const *headers,
  				 const char *const *cells, const char *const *footers,
  				 const char *opt_align, bool opt_tuples_only,
! 				 char *opt_numericsep, unsigned short int opt_border,
  				 FILE *fout)
  {
  	unsigned int col_count = 0;
--- 1215,1221 ----
  print_troff_ms_text(const char *title, const char *const *headers,
  				 const char *const *cells, const char *const *footers,
  				 const char *opt_align, bool opt_tuples_only,
! 				 bool opt_numericsep, unsigned short int opt_border,
  				 FILE *fout)
  {
  	unsigned int col_count = 0;
***************
*** 1275,1287 ****
  	/* print cells */
  	for (i = 0, ptr = cells; *ptr; i++, ptr++)
  	{
! 		if (strlen(*ptr) != 0 &&
! 			opt_numericsep != NULL && strlen(opt_numericsep) > 0)
  		{
  			char *my_cell = pg_local_malloc(len_with_numericsep(*ptr) + 1);
  		    
  			strcpy(my_cell, *ptr);
! 			format_numericsep(my_cell, opt_numericsep);
  			troff_ms_escaped_print(my_cell, fout);
  			free(my_cell);
  		}
--- 1269,1280 ----
  	/* print cells */
  	for (i = 0, ptr = cells; *ptr; i++, ptr++)
  	{
! 		if (opt_numericsep)
  		{
  			char *my_cell = pg_local_malloc(len_with_numericsep(*ptr) + 1);
  		    
  			strcpy(my_cell, *ptr);
! 			format_numericsep(my_cell);
  			troff_ms_escaped_print(my_cell, fout);
  			free(my_cell);
  		}
***************
*** 1315,1321 ****
  print_troff_ms_vertical(const char *title, const char *const *headers,
  				  const char *const *cells, const char *const *footers,
  				  const char *opt_align, bool opt_tuples_only,
! 				  char *opt_numericsep, unsigned short int opt_border,
  				  FILE *fout)
  {
  	unsigned int col_count = 0;
--- 1308,1314 ----
  print_troff_ms_vertical(const char *title, const char *const *headers,
  				  const char *const *cells, const char *const *footers,
  				  const char *opt_align, bool opt_tuples_only,
! 				  bool opt_numericsep, unsigned short int opt_border,
  				  FILE *fout)
  {
  	unsigned int col_count = 0;
***************
*** 1345,1356 ****
          if (opt_tuples_only)
   		fputs("c l;\n", fout);
  
- 
  	/* count columns */
  	for (ptr = headers; *ptr; ptr++)
  		col_count++;
  
- 
  	/* print records */
  	for (i = 0, ptr = cells; *ptr; i++, ptr++)
  	{
--- 1338,1347 ----
***************
*** 1390,1402 ****
  
  		troff_ms_escaped_print(headers[i % col_count], fout);
  		fputc('\t', fout);
! 		if (strlen(*ptr) != 0 &&
! 			opt_numericsep != NULL && strlen(opt_numericsep) > 0)
  		{
  			char *my_cell = pg_local_malloc(len_with_numericsep(*ptr) + 1);
  		    
  			strcpy(my_cell, *ptr);
! 			format_numericsep(my_cell, opt_numericsep);
  			troff_ms_escaped_print(my_cell, fout);
  			free(my_cell);
  		}
--- 1381,1392 ----
  
  		troff_ms_escaped_print(headers[i % col_count], fout);
  		fputc('\t', fout);
! 		if (opt_numericsep)
  		{
  			char *my_cell = pg_local_malloc(len_with_numericsep(*ptr) + 1);
  		    
  			strcpy(my_cell, *ptr);
! 			format_numericsep(my_cell);
  			troff_ms_escaped_print(my_cell, fout);
  			free(my_cell);
  		}
***************
*** 1714,1717 ****
  }
  
  
! /* the end */
--- 1704,1729 ----
  }
  
  
! void
! setDecimalLocale(void)
! {
! 	struct lconv *extlconv;
! 
! 	extlconv = localeconv();
! 
! 	/* These are treated as single-byte strings in the code */
! 	if (*extlconv->decimal_point)
! 		decimal_point = strdup(extlconv->decimal_point);
! 	else
! 		decimal_point = ".";	/* SQL output standard */
! 	if (*extlconv->grouping && atoi(extlconv->grouping) > 0)
! 		grouping = strdup(extlconv->grouping);
! 	else
! 		grouping = "3";		/* most common */
! 	if (*extlconv->thousands_sep)
! 		thousands_sep = strdup(extlconv->thousands_sep);
! 	else
! 		thousands_sep = ",";	/* matches SQL standard decimal marker */
! }
! 	
! 
Index: src/bin/psql/print.h
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/print.h,v
retrieving revision 1.26
retrieving revision 1.27
diff -c -r1.26 -r1.27
*** src/bin/psql/print.h	10 Jul 2005 03:46:13 -0000	1.26
--- src/bin/psql/print.h	14 Jul 2005 08:42:37 -0000	1.27
***************
*** 3,9 ****
   *
   * Copyright (c) 2000-2005, PostgreSQL Global Development Group
   *
!  * $PostgreSQL: pgsql/src/bin/psql/print.h,v 1.26 2005/07/10 03:46:13 momjian Exp $
   */
  #ifndef PRINT_H
  #define PRINT_H
--- 3,9 ----
   *
   * Copyright (c) 2000-2005, PostgreSQL Global Development Group
   *
!  * $PostgreSQL: pgsql/src/bin/psql/print.h,v 1.27 2005/07/14 08:42:37 momjian Exp $
   */
  #ifndef PRINT_H
  #define PRINT_H
***************
*** 40,46 ****
  	char	   *fieldSep;		/* field separator for unaligned text mode */
  	char	   *recordSep;		/* record separator for unaligned text
  								 * mode */
! 	char	   *numericSep;		/* numeric units separator */
  	char	   *tableAttr;		/* attributes for HTML <table ...> */
  	int			encoding;		/* character encoding */
  	bool		normal_query;	/* are we presenting the results of a
--- 40,47 ----
  	char	   *fieldSep;		/* field separator for unaligned text mode */
  	char	   *recordSep;		/* record separator for unaligned text
  								 * mode */
! 	bool		numericSep;		/* locale-aware numeric units separator and
! 								 *  decimal marker */
  	char	   *tableAttr;		/* attributes for HTML <table ...> */
  	int			encoding;		/* character encoding */
  	bool		normal_query;	/* are we presenting the results of a
***************
*** 86,91 ****
--- 87,94 ----
  void		printQuery(const PGresult *result, const printQueryOpt *opt,
  					   FILE *fout, FILE *flog);
  
+ void	setDecimalLocale(void);
+ 
  #ifndef __CYGWIN__
  #define DEFAULT_PAGER "more"
  #else
Index: src/bin/psql/startup.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/startup.c,v
retrieving revision 1.118
retrieving revision 1.119
diff -c -r1.118 -r1.119
*** src/bin/psql/startup.c	21 Jun 2005 04:02:33 -0000	1.118
--- src/bin/psql/startup.c	14 Jul 2005 08:42:37 -0000	1.119
***************
*** 3,9 ****
   *
   * Copyright (c) 2000-2005, PostgreSQL Global Development Group
   *
!  * $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.118 2005/06/21 04:02:33 tgl Exp $
   */
  #include "postgres_fe.h"
  
--- 3,9 ----
   *
   * Copyright (c) 2000-2005, PostgreSQL Global Development Group
   *
!  * $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.119 2005/07/14 08:42:37 momjian Exp $
   */
  #include "postgres_fe.h"
  
***************
*** 130,135 ****
--- 130,136 ----
  	setvbuf(stderr, NULL, _IONBF, 0);
  	setup_win32_locks();
  #endif
+ 	setDecimalLocale();
  	pset.cur_cmd_source = stdin;
  	pset.cur_cmd_interactive = false;
  	pset.encoding = PQenv2encoding();
