Re: thousands comma numeric formatting in psql - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: thousands comma numeric formatting in psql
Date
Msg-id 200507142113.j6ELDhR16663@candle.pha.pa.us
Whole thread Raw
In response to Re: thousands comma numeric formatting in psql  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-patches
Tom Lane wrote:
> > The only question I have is whether those locale values are single-byte
> > strings in all locals, or could they be multi-byte or multi-character,
> > in which case I have to treat them as strings.
>
> I think you have to assume they could be strings.

OK, the following applied patch enables multi-byte locale strings for
numericsep.  I also reorganized the code a little.

--
  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/bin/psql/print.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/psql/print.c,v
retrieving revision 1.68
diff -c -c -r1.68 print.c
*** src/bin/psql/print.c    14 Jul 2005 15:54:21 -0000    1.68
--- src/bin/psql/print.c    14 Jul 2005 20:54:05 -0000
***************
*** 50,125 ****
  }

  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++;

!     old_len = strlen(my_str);
!     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
  len_with_numericsep(const char *my_str)
  {
!     return strlen(my_str) + num_numericseps(my_str);
  }

  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++;
!
!     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 */

!     new_str = pg_local_malloc(new_len + 1);

      for (i=0, j=0; ; i++, j++)
      {
!         /* 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);
              break;
          }

!         /* end of string */
          if (my_str[i] == '\0')
          {
              new_str[j] = '\0';
              break;
          }

!         /* 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];
      }
--- 50,128 ----
  }

  static int
! integer_digits(const char *my_str)
  {
!     int frac_len;

      if (my_str[0] == '-')
          my_str++;

!     frac_len = strchr(my_str, '.') ? strlen(strchr(my_str, '.')) : 0;
!
!     return strlen(my_str) - frac_len;
! }
!
! static int
! len_numericseps(const char *my_str)
! {
!     int int_len = integer_digits(my_str), sep_len;
!     int    groupdigits = atoi(grouping);

      if (int_len % groupdigits != 0)
!         sep_len = int_len / groupdigits;
      else
!         sep_len = int_len / groupdigits - 1;    /* no leading separator */
!
!     return sep_len * strlen(thousands_sep) -
!            strlen(".") + strlen(decimal_point);
  }

  static int
  len_with_numericsep(const char *my_str)
  {
!     return strlen(my_str) + len_numericseps(my_str);
  }

  static void
  format_numericsep(char *my_str)
  {
!     int i, j, int_len = integer_digits(my_str), leading_digits;
      int    groupdigits = atoi(grouping);
+     char *new_str;

      if (my_str[0] == '-')
          my_str++;
!
!     new_str = pg_local_malloc(len_numericseps(my_str) + 1);

!     leading_digits = (int_len % groupdigits != 0) ?
!                      int_len % groupdigits : groupdigits;

      for (i=0, j=0; ; i++, j++)
      {
!         /* Hit decimal point? */
          if (my_str[i] == '.')
          {
!             strcpy(&new_str[j], decimal_point);
!             j += strlen(decimal_point);
!             /* add fractional part */
!             strcpy(&new_str[j], &my_str[i] + 1);
              break;
          }

!         /* End of string? */
          if (my_str[i] == '\0')
          {
              new_str[j] = '\0';
              break;
          }

!         /* Add separator? */
!         if (i != 0 && (i - leading_digits) % groupdigits == 0)
!         {
!             strcpy(&new_str[j], thousands_sep);
!             j += strlen(thousands_sep);
!         }

          new_str[j] = my_str[i];
      }
***************
*** 396,402 ****
          int numericseps;

          if (opt_align[i % col_count] == 'r' && opt_numericsep)
!             numericseps = num_numericseps(*ptr);
          else
              numericseps = 0;

--- 399,405 ----
          int numericseps;

          if (opt_align[i % col_count] == 'r' && opt_numericsep)
!             numericseps = len_numericseps(*ptr);
          else
              numericseps = 0;

***************
*** 613,619 ****
          int numericseps;

          if (opt_align[i % col_count] == 'r' && opt_numericsep)
!             numericseps = num_numericseps(*ptr);
          else
              numericseps = 0;

--- 616,622 ----
          int numericseps;

          if (opt_align[i % col_count] == 'r' && opt_numericsep)
!             numericseps = len_numericseps(*ptr);
          else
              numericseps = 0;

***************
*** 1711,1717 ****

      extlconv = localeconv();

-     /* These are treated as single-byte strings in the code */
      if (*extlconv->decimal_point)
          decimal_point = strdup(extlconv->decimal_point);
      else
--- 1714,1719 ----

pgsql-patches by date:

Previous
From: Simon Riggs
Date:
Subject: Re: Final cleanup of SQL:1999 references
Next
From: Bruce Momjian
Date:
Subject: Re: thousands comma numeric formatting in psql