Change numericsep to a boolean, and make it locale-aware.
authorBruce Momjian <bruce@momjian.us>
Thu, 14 Jul 2005 08:42:37 +0000 (08:42 +0000)
committerBruce Momjian <bruce@momjian.us>
Thu, 14 Jul 2005 08:42:37 +0000 (08:42 +0000)
doc/src/sgml/ref/psql-ref.sgml
src/bin/psql/command.c
src/bin/psql/print.c
src/bin/psql/print.h
src/bin/psql/startup.c

index 9d76ff207e539222aa28fc3f59c69e5e8f17ef95..d5402bf90df29d752d8a512ed988941dfc584fbc 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.146 2005/07/10 03:46:12 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.147 2005/07/14 08:42:36 momjian Exp $
 PostgreSQL documentation
 -->
 
@@ -1496,10 +1496,9 @@ lo_import 152801
           <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.
+          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 888fa4f55a60572a4f69c580663160b2ad299828..0c4db123db5ab86944917047c89b03f5789531a7 100644 (file)
@@ -3,7 +3,7 @@
  *
  * 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 $
+ * $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,15 +1420,17 @@ do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
                                   : _("Expanded display is off.\n"));
        }
 
+       /* numeric separators */
        else if (strcmp(param, "numericsep") == 0)
        {
-               if (value)
+               popt->topt.numericSep = !popt->topt.numericSep;
+               if (!quiet)
                {
-                       free(popt->topt.numericSep);
-                       popt->topt.numericSep = pg_strdup(value);
+                       if (popt->topt.numericSep)
+                               puts(_("Showing numeric separators."));
+                       else
+                               puts(_("Numeric separators are off."));
                }
-               if (!quiet)
-                       printf(_("Numeric separator is \"%s\".\n"), popt->topt.numericSep);
        }
 
        /* null display */
index 7d4a3a92e5d590015d71987d489cf810059b99fd..27e081870ac4cf20689dc91a1ee6e1266ddd202a 100644 (file)
@@ -3,7 +3,7 @@
  *
  * 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 $
+ * $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"
 #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,6 +53,7 @@ static int
 num_numericseps(const char *my_str)
 {
        int old_len, dec_len, int_len;
+       int     groupdigits = atoi(grouping);
 
        if (my_str[0] == '-')
                my_str++;
@@ -55,10 +62,10 @@ num_numericseps(const char *my_str)
        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;
+       if (int_len % groupdigits != 0)
+               return int_len / groupdigits;
        else
-               return int_len / 3 - 1; /* no leading separator */
+               return int_len / groupdigits - 1;       /* no leading separator */
 }
 
 static int
@@ -68,17 +75,12 @@ len_with_numericsep(const char *my_str)
 }
 
 static void 
-format_numericsep(char *my_str, char *numericsep)
+format_numericsep(char *my_str)
 {
        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 = ",";
+       int     groupdigits = atoi(grouping);
     
        if (my_str[0] == '-')
                my_str++;
@@ -86,9 +88,9 @@ format_numericsep(char *my_str, char *numericsep)
        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;
+       digits_before_sep = int_len % groupdigits;
 
-       new_len = int_len + int_len / 3 + dec_len;
+       new_len = int_len + int_len / groupdigits + dec_len;
        if (digits_before_sep == 0)
                new_len--;      /* no leading separator */
 
@@ -99,7 +101,7 @@ format_numericsep(char *my_str, char *numericsep)
                /* hit decimal point */
                if (my_str[i] == '.')
                {
-                       new_str[j] = *dec_point;
+                       new_str[j] = *decimal_point;
                        new_str[j+1] = '\0';
                        dec_value = strchr(my_str, '.');
                        strcat(new_str, ++dec_value);
@@ -115,8 +117,9 @@ format_numericsep(char *my_str, char *numericsep)
     
                /* add separator? */
                if (i != 0 &&
-                       (i - (digits_before_sep ? digits_before_sep : 3)) % 3 == 0)
-                       new_str[j++] = *numericsep;
+                       (i - (digits_before_sep ? digits_before_sep : groupdigits))
+                               % groupdigits == 0)
+                       new_str[j++] = *thousands_sep;
 
                new_str[j] = my_str[i];
        }
@@ -135,7 +138,7 @@ print_unaligned_text(const char *title, const char *const *headers,
                                         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)
+                                        bool opt_numericsep, FILE *fout)
 {
        unsigned int col_count = 0;
        unsigned int i;
@@ -174,13 +177,12 @@ print_unaligned_text(const char *title, const char *const *headers,
                        fputs(opt_recordsep, fout);
                        need_recordsep = false;
                }
-               if ((opt_align[i % col_count] == 'r') && strlen(*ptr) > 0 &&
-                       opt_numericsep != NULL && strlen(opt_numericsep) > 0)
+               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, opt_numericsep);
+                       format_numericsep(my_cell);
                        fputs(my_cell, fout);
                        free(my_cell);
                }
@@ -220,7 +222,7 @@ print_unaligned_vertical(const char *title, const char *const *headers,
                                                 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)
+                                                bool opt_tuples_only, bool opt_numericsep, FILE *fout)
 {
        unsigned int col_count = 0;
        unsigned int i;
@@ -251,13 +253,12 @@ print_unaligned_vertical(const char *title, const char *const *headers,
 
                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)
+               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, opt_numericsep);
+                       format_numericsep(my_cell);
                        fputs(my_cell, fout);
                        free(my_cell);
                }
@@ -325,7 +326,7 @@ _print_horizontal_line(const unsigned int col_count, const unsigned int *widths,
 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,
+                                  const char *opt_align, bool opt_tuples_only, bool opt_numericsep,
                                   unsigned short int opt_border, int encoding,
                                   FILE *fout)
 {
@@ -394,8 +395,7 @@ print_aligned_text(const char *title, const char *const *headers,
        {
                int numericseps;
 
-               if ((opt_align[i % col_count] == 'r') && strlen(*ptr) != 0 &&
-                       opt_numericsep != NULL && strlen(opt_numericsep) > 0)
+               if (opt_align[i % col_count] == 'r' && opt_numericsep)
                    numericseps = num_numericseps(*ptr);
                else 
                    numericseps = 0;
@@ -480,12 +480,12 @@ print_aligned_text(const char *title, const char *const *headers,
                /* content */
                if (opt_align[i % col_count] == 'r')
                {
-                   if (strlen(*ptr) > 0 && opt_numericsep != NULL && strlen(opt_numericsep) > 0)
+                   if (opt_numericsep)
                    {
                                char *my_cell = pg_local_malloc(cell_w[i] + 1);
 
                                strcpy(my_cell, *ptr);
-                               format_numericsep(my_cell, opt_numericsep);
+                               format_numericsep(my_cell);
                                fprintf(fout, "%*s%s", widths[i % col_count] - cell_w[i], "", my_cell);
                                free(my_cell);
                    }
@@ -547,7 +547,7 @@ static void
 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,
+                                          bool opt_numericsep, unsigned short int opt_border,
                                           int encoding, FILE *fout)
 {
        unsigned int col_count = 0;
@@ -612,8 +612,7 @@ print_aligned_vertical(const char *title, const char *const *headers,
        {
                int numericseps;
 
-               if ((opt_align[i % col_count] == 'r') && strlen(*ptr) != 0 &&
-                       opt_numericsep != NULL && strlen(opt_numericsep) > 0)
+               if (opt_align[i % col_count] == 'r' && opt_numericsep)
                    numericseps = num_numericseps(*ptr);
                else 
                    numericseps = 0;
@@ -696,9 +695,8 @@ print_aligned_vertical(const char *title, const char *const *headers,
                        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_align[i % col_count] == 'r' && opt_numericsep)
+                           format_numericsep(my_cell);
                        if (opt_border < 2)
                                puts(my_cell);
                        else
@@ -785,7 +783,7 @@ static void
 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,
+                               bool opt_numericsep, unsigned short int opt_border,
                                const char *opt_table_attr, FILE *fout)
 {
        unsigned int col_count = 0;
@@ -831,13 +829,12 @@ print_html_text(const char *title, const char *const *headers,
                /* 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)
+               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, opt_numericsep);
+                   format_numericsep(my_cell);
                    html_escaped_print(my_cell, fout);
                    free(my_cell);
                }
@@ -873,7 +870,7 @@ static void
 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,
+                                 bool opt_numericsep, unsigned short int opt_border,
                                  const char *opt_table_attr, FILE *fout)
 {
        unsigned int col_count = 0;
@@ -917,13 +914,12 @@ print_html_vertical(const char *title, const char *const *headers,
                /* 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)
+               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, opt_numericsep);
+                   format_numericsep(my_cell);
                    html_escaped_print(my_cell, fout);
                    free(my_cell);
                }
@@ -999,7 +995,7 @@ static void
 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,
+                                bool opt_numericsep, unsigned short int opt_border,
                                 FILE *fout)
 {
        unsigned int col_count = 0;
@@ -1060,13 +1056,12 @@ print_latex_text(const char *title, const char *const *headers,
        /* print cells */
        for (i = 0, ptr = cells; *ptr; i++, ptr++)
        {
-               if (strlen(*ptr) != 0 &&
-                       opt_numericsep != NULL && strlen(opt_numericsep) > 0)
+               if (opt_numericsep)
                {
                        char *my_cell = pg_local_malloc(len_with_numericsep(*ptr) + 1);
                    
                        strcpy(my_cell, *ptr);
-                       format_numericsep(my_cell, opt_numericsep);
+                       format_numericsep(my_cell);
                        latex_escaped_print(my_cell, fout);
                        free(my_cell);
                }
@@ -1103,7 +1098,7 @@ static void
 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,
+                                 bool opt_numericsep, unsigned short int opt_border,
                                  FILE *fout)
 {
        unsigned int col_count = 0;
@@ -1174,13 +1169,12 @@ print_latex_vertical(const char *title, const char *const *headers,
        if (footers && !opt_tuples_only)
                for (ptr = footers; *ptr; ptr++)
                {
-                       if (strlen(*ptr) != 0 &&
-                               opt_numericsep != NULL && strlen(opt_numericsep) > 0)
+                       if (opt_numericsep)
                        {
                                char *my_cell = pg_local_malloc(len_with_numericsep(*ptr) + 1);
 
                                strcpy(my_cell, *ptr);
-                               format_numericsep(my_cell, opt_numericsep);
+                               format_numericsep(my_cell);
                                latex_escaped_print(my_cell, fout);
                                free(my_cell);
                        }
@@ -1221,7 +1215,7 @@ static void
 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,
+                                bool opt_numericsep, unsigned short int opt_border,
                                 FILE *fout)
 {
        unsigned int col_count = 0;
@@ -1275,13 +1269,12 @@ print_troff_ms_text(const char *title, const char *const *headers,
        /* print cells */
        for (i = 0, ptr = cells; *ptr; i++, ptr++)
        {
-               if (strlen(*ptr) != 0 &&
-                       opt_numericsep != NULL && strlen(opt_numericsep) > 0)
+               if (opt_numericsep)
                {
                        char *my_cell = pg_local_malloc(len_with_numericsep(*ptr) + 1);
                    
                        strcpy(my_cell, *ptr);
-                       format_numericsep(my_cell, opt_numericsep);
+                       format_numericsep(my_cell);
                        troff_ms_escaped_print(my_cell, fout);
                        free(my_cell);
                }
@@ -1315,7 +1308,7 @@ static void
 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,
+                                 bool opt_numericsep, unsigned short int opt_border,
                                  FILE *fout)
 {
        unsigned int col_count = 0;
@@ -1345,12 +1338,10 @@ print_troff_ms_vertical(const char *title, const char *const *headers,
         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++)
        {
@@ -1390,13 +1381,12 @@ print_troff_ms_vertical(const char *title, const char *const *headers,
 
                troff_ms_escaped_print(headers[i % col_count], fout);
                fputc('\t', fout);
-               if (strlen(*ptr) != 0 &&
-                       opt_numericsep != NULL && strlen(opt_numericsep) > 0)
+               if (opt_numericsep)
                {
                        char *my_cell = pg_local_malloc(len_with_numericsep(*ptr) + 1);
                    
                        strcpy(my_cell, *ptr);
-                       format_numericsep(my_cell, opt_numericsep);
+                       format_numericsep(my_cell);
                        troff_ms_escaped_print(my_cell, fout);
                        free(my_cell);
                }
@@ -1714,4 +1704,26 @@ printQuery(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *f
 }
 
 
-/* the end */
+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 f64f8ba0f8edf455f9da5038e27c83daa5abb355..bb23b7c08c4e7df54e1befc96dd9ed87747f521f 100644 (file)
@@ -3,7 +3,7 @@
  *
  * 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 $
+ * $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,7 +40,8 @@ typedef struct _printTableOpt
        char       *fieldSep;           /* field separator for unaligned text mode */
        char       *recordSep;          /* record separator for unaligned text
                                                                 * mode */
-       char       *numericSep;         /* numeric units separator */
+       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,6 +87,8 @@ typedef struct _printQueryOpt
 void           printQuery(const PGresult *result, const printQueryOpt *opt,
                                           FILE *fout, FILE *flog);
 
+void   setDecimalLocale(void);
+
 #ifndef __CYGWIN__
 #define DEFAULT_PAGER "more"
 #else
index 9caecbe44986906eb2701d7b632ca49abcfb784e..3f603757c4adf072e0b321797d3ff74e5995360f 100644 (file)
@@ -3,7 +3,7 @@
  *
  * 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 $
+ * $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.119 2005/07/14 08:42:37 momjian Exp $
  */
 #include "postgres_fe.h"
 
@@ -130,6 +130,7 @@ main(int argc, char *argv[])
        setvbuf(stderr, NULL, _IONBF, 0);
        setup_win32_locks();
 #endif
+       setDecimalLocale();
        pset.cur_cmd_source = stdin;
        pset.cur_cmd_interactive = false;
        pset.encoding = PQenv2encoding();