Index: doc/src/sgml/ref/psql-ref.sgml =================================================================== RCS file: /cvsroot/pgsql/doc/src/sgml/ref/psql-ref.sgml,v retrieving revision 1.145 diff -c -c -r1.145 psql-ref.sgml *** doc/src/sgml/ref/psql-ref.sgml 14 Jun 2005 02:57:38 -0000 1.145 --- doc/src/sgml/ref/psql-ref.sgml 10 Jul 2005 03:24:16 -0000 *************** *** 1493,1498 **** --- 1493,1510 ---- + numericsep + + + Specifies the character separator between groups of three digits + to the left of the decimal marker. The default is '' + (none). Setting this to a period also changes the decimal marker + to a comma. + + + + + recordsep Index: src/bin/psql/command.c =================================================================== RCS file: /cvsroot/pgsql/src/bin/psql/command.c,v retrieving revision 1.146 diff -c -c -r1.146 command.c *** src/bin/psql/command.c 13 Jun 2005 06:36:22 -0000 1.146 --- src/bin/psql/command.c 10 Jul 2005 03:24:17 -0000 *************** *** 838,844 **** else if (strcmp(cmd, "x") == 0) success = do_pset("expanded", NULL, &pset.popt, quiet); - /* \z -- list table rights (equivalent to \dp) */ else if (strcmp(cmd, "z") == 0) { --- 838,843 ---- *************** *** 1421,1426 **** --- 1420,1436 ---- : _("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 */ else if (strcmp(param, "null") == 0) { Index: src/bin/psql/help.c =================================================================== RCS file: /cvsroot/pgsql/src/bin/psql/help.c,v retrieving revision 1.103 diff -c -c -r1.103 help.c *** src/bin/psql/help.c 6 Jul 2005 03:14:48 -0000 1.103 --- src/bin/psql/help.c 10 Jul 2005 03:24:18 -0000 *************** *** 239,245 **** fprintf(output, _(" \\pset NAME [VALUE]\n" " set table output option\n" " (NAME := {format|border|expanded|fieldsep|footer|null|\n" ! " recordsep|tuples_only|title|tableattr|pager})\n")); fprintf(output, _(" \\t show only rows (currently %s)\n"), ON(pset.popt.topt.tuples_only)); fprintf(output, _(" \\T [STRING] set HTML tag attributes, or unset if none\n")); --- 239,245 ---- fprintf(output, _(" \\pset NAME [VALUE]\n" " set table output option\n" " (NAME := {format|border|expanded|fieldsep|footer|null|\n" ! " numericsep|recordsep|tuples_only|title|tableattr|pager})\n")); fprintf(output, _(" \\t show only rows (currently %s)\n"), ON(pset.popt.topt.tuples_only)); fprintf(output, _(" \\T [STRING] set HTML
tag attributes, or unset if none\n")); Index: src/bin/psql/print.c =================================================================== RCS file: /cvsroot/pgsql/src/bin/psql/print.c,v retrieving revision 1.60 diff -c -c -r1.60 print.c *** src/bin/psql/print.c 14 Jun 2005 22:15:57 -0000 1.60 --- src/bin/psql/print.c 10 Jul 2005 03:24:24 -0000 *************** *** 29,48 **** #include "mbprint.h" /*************************/ /* Unaligned text */ /*************************/ static void ! print_unaligned_text(const char *title, const char *const * headers, ! const char *const * cells, const char *const * footers, ! const char *opt_fieldsep, const char *opt_recordsep, bool opt_barebones, ! FILE *fout) { unsigned int col_count = 0; unsigned int i; ! const char *const * ptr; bool need_recordsep = false; if (!opt_fieldsep) --- 29,135 ---- #include "mbprint.h" + static int + num_numericseps(const char *my_str) + { + int old_len, dec_len, int_len; + + 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 % 3 != 0) + return int_len / 3; + else + return int_len / 3 - 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, 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++; + + 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 */ + + new_str = malloc(new_len); + if (!new_str) + { + fprintf(stderr, _("out of memory\n")); + exit(EXIT_FAILURE); + } + + for (i=0, j=0; ; i++, j++) + { + /* 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); + 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 : 3)) % 3 == 0) + new_str[j++] = *numericsep; + + new_str[j] = my_str[i]; + } + + strcpy(my_str, new_str); + free(new_str); + } + /*************************/ /* Unaligned text */ /*************************/ static void ! 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_barebones, ! char *opt_numericsep, FILE *fout) { unsigned int col_count = 0; unsigned int i; ! const char *const *ptr; bool need_recordsep = false; if (!opt_fieldsep) *************** *** 77,83 **** fputs(opt_recordsep, fout); need_recordsep = false; } ! fputs(*ptr, fout); if ((i + 1) % col_count) fputs(opt_fieldsep, fout); else --- 164,187 ---- 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 = malloc(len_with_numericsep(*ptr)); ! ! if (!my_cell) ! { ! fprintf(stderr, _("out of memory\n")); ! exit(EXIT_FAILURE); ! } ! strcpy(my_cell, *ptr); ! format_numericsep(my_cell, opt_numericsep); ! fputs(my_cell, fout); ! free(my_cell); ! } ! else ! fputs(*ptr, fout); ! if ((i + 1) % col_count) fputs(opt_fieldsep, fout); else *************** *** 107,120 **** static void ! print_unaligned_vertical(const char *title, const char *const * headers, ! const char *const * cells, const char *const * footers, ! const char *opt_fieldsep, const char *opt_recordsep, bool opt_barebones, ! FILE *fout) { unsigned int col_count = 0; unsigned int i; ! const char *const * ptr; if (!opt_fieldsep) opt_fieldsep = ""; --- 211,225 ---- static void ! 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_barebones, char *opt_numericsep, FILE *fout) { unsigned int col_count = 0; unsigned int i; ! const char *const *ptr; if (!opt_fieldsep) opt_fieldsep = ""; *************** *** 141,147 **** fputs(headers[i % col_count], fout); fputs(opt_fieldsep, fout); ! fputs(*ptr, fout); } /* print footers */ --- 246,268 ---- 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 = malloc(len_with_numericsep(*ptr)); ! ! if (!my_cell) ! { ! fprintf(stderr, _("out of memory\n")); ! exit(EXIT_FAILURE); ! } ! strcpy(my_cell, *ptr); ! format_numericsep(my_cell, opt_numericsep); ! fputs(my_cell, fout); ! free(my_cell); ! } ! else ! fputs(*ptr, fout); } /* print footers */ *************** *** 202,210 **** 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_barebones, unsigned short int opt_border, int encoding, FILE *fout) { --- 323,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_barebones, char *opt_numericsep, unsigned short int opt_border, int encoding, FILE *fout) { *************** *** 216,222 **** tmp; unsigned int *widths, total_w; ! const char *const * ptr; /* count columns */ for (ptr = headers; *ptr; ptr++) --- 337,343 ---- tmp; unsigned int *widths, total_w; ! const char *const *ptr; /* count columns */ for (ptr = headers; *ptr; ptr++) *************** *** 271,277 **** for (i = 0, ptr = cells; *ptr; ptr++, i++) { ! tmp = pg_wcswidth((unsigned char *) *ptr, strlen(*ptr), encoding); if (tmp > widths[i % col_count]) widths[i % col_count] = tmp; cell_w[i] = tmp; --- 392,406 ---- for (i = 0, ptr = cells; *ptr; ptr++, i++) { ! 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; ! ! tmp = pg_wcswidth((unsigned char *) *ptr, strlen(*ptr), encoding) + numericseps; if (tmp > widths[i % col_count]) widths[i % col_count] = tmp; cell_w[i] = tmp; *************** *** 351,358 **** /* content */ if (opt_align[i % col_count] == 'r') { ! fprintf(fout, "%*s%s", ! widths[i % col_count] - cell_w[i], "", cells[i]); } else { --- 480,501 ---- /* content */ if (opt_align[i % col_count] == 'r') { ! if (strlen(*ptr) > 0 && opt_numericsep != NULL && strlen(opt_numericsep) > 0) ! { ! char *my_cell = malloc(cell_w[i]); ! ! if (!my_cell) ! { ! fprintf(stderr, _("out of memory\n")); ! exit(EXIT_FAILURE); ! } ! 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); ! } ! else ! fprintf(fout, "%*s%s", widths[i % col_count] - cell_w[i], "", *ptr); } else { *************** *** 406,419 **** static void ! print_aligned_vertical(const char *title, const char *const * headers, ! const char *const * cells, const char *const * footers, ! bool opt_barebones, unsigned short int opt_border, int encoding, FILE *fout) { unsigned int col_count = 0; unsigned int record = 1; ! const char *const * ptr; unsigned int i, tmp = 0, hwidth = 0, --- 549,563 ---- 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_barebones, ! char *opt_numericsep, unsigned short int opt_border, int encoding, FILE *fout) { unsigned int col_count = 0; unsigned int record = 1; ! const char *const *ptr; unsigned int i, tmp = 0, hwidth = 0, *************** *** 471,477 **** /* find longest data cell */ for (i = 0, ptr = cells; *ptr; ptr++, i++) { ! tmp = pg_wcswidth((unsigned char *) *ptr, strlen(*ptr), encoding); if (tmp > dwidth) dwidth = tmp; cell_w[i] = tmp; --- 615,629 ---- /* find longest data cell */ for (i = 0, ptr = cells; *ptr; ptr++, i++) { ! 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; ! ! tmp = pg_wcswidth((unsigned char *) *ptr, strlen(*ptr), encoding) + numericseps; if (tmp > dwidth) dwidth = tmp; cell_w[i] = tmp; *************** *** 556,565 **** else fputs(" ", fout); ! if (opt_border < 2) ! fprintf(fout, "%s\n", *ptr); ! else ! fprintf(fout, "%-s%*s |\n", *ptr, dwidth - cell_w[i], ""); } if (opt_border == 2) --- 708,731 ---- else fputs(" ", fout); ! { ! char *my_cell = malloc(cell_w[i]); ! ! if (!my_cell) ! { ! fprintf(stderr, _("out of memory\n")); ! exit(EXIT_FAILURE); ! } ! 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 ! fprintf(fout, "%-s%*s |\n", my_cell, dwidth - cell_w[i], ""); ! free(my_cell); ! } } if (opt_border == 2) *************** *** 637,651 **** 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_barebones, unsigned short int opt_border, ! const char *opt_table_attr, ! FILE *fout) { unsigned int col_count = 0; unsigned int i; ! const char *const * ptr; fprintf(fout, "
\n", fout); fprintf(fout, " \n", fout); if ((i + 1) % col_count == 0) --- 849,875 ---- fputs(" \n", fout); fprintf(fout, " \n", fout); if ((i + 1) % col_count == 0) *************** *** 714,729 **** 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_barebones, unsigned short int opt_border, ! const char *opt_table_attr, ! FILE *fout) { unsigned int col_count = 0; unsigned int i; unsigned int record = 1; ! const char *const * ptr; fprintf(fout, "
", opt_align[(i) % col_count] == 'r' ? "right" : "left"); ! if ((*ptr)[strspn(*ptr, " \t")] == '\0') /* is string only ! * whitespace? */ fputs("  ", fout); else html_escaped_print(*ptr, fout); fputs("
", opt_align[(i) % col_count] == 'r' ? "right" : "left"); ! /* is string only whitespace? */ ! if ((*ptr)[strspn(*ptr, " \t")] == '\0') fputs("  ", fout); + else if ((opt_align[i % col_count] == 'r') && strlen(*ptr) != 0 && + opt_numericsep != NULL && strlen(opt_numericsep) > 0) + { + char *my_cell = malloc(len_with_numericsep(*ptr)); + + if (!my_cell) + { + fprintf(stderr, _("out of memory\n")); + exit(EXIT_FAILURE); + } + strcpy(my_cell, *ptr); + format_numericsep(my_cell, opt_numericsep); + html_escaped_print(my_cell, fout); + free(my_cell); + } else html_escaped_print(*ptr, fout); + fputs("
\n", fout); fprintf(fout, " \n \n", fout); } --- 940,966 ---- fputs("\n", fout); fprintf(fout, " \n \n", fout); } *************** *** 829,842 **** 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_barebones, unsigned short int opt_border, ! FILE *fout) { unsigned int col_count = 0; unsigned int i; ! const char *const * ptr; /* print title */ --- 1027,1040 ---- 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_barebones, ! unsigned short int opt_border, FILE *fout) { unsigned int col_count = 0; unsigned int i; ! const char *const *ptr; /* print title */ *************** *** 921,934 **** 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_barebones, unsigned short int opt_border, ! FILE *fout) { unsigned int col_count = 0; unsigned int i; ! const char *const * ptr; unsigned int record = 1; (void) opt_align; /* currently unused parameter */ --- 1119,1132 ---- 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_barebones, ! unsigned short int opt_border, FILE *fout) { unsigned int col_count = 0; unsigned int i; ! const char *const *ptr; unsigned int record = 1; (void) opt_align; /* currently unused parameter */ *************** *** 1027,1040 **** 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_barebones, unsigned short int opt_border, ! FILE *fout) { unsigned int col_count = 0; unsigned int i; ! const char *const * ptr; /* print title */ --- 1225,1238 ---- 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_barebones, ! unsigned short int opt_border, FILE *fout) { unsigned int col_count = 0; unsigned int i; ! const char *const *ptr; /* print title */ *************** *** 1111,1124 **** 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_barebones, unsigned short int opt_border, ! FILE *fout) { unsigned int col_count = 0; unsigned int i; ! const char *const * ptr; unsigned int record = 1; unsigned short current_format = 0; /* 0=none, 1=header, 2=body */ --- 1309,1322 ---- 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_barebones, ! unsigned short int opt_border, FILE *fout) { unsigned int col_count = 0; unsigned int i; ! const char *const *ptr; unsigned int record = 1; unsigned short current_format = 0; /* 0=none, 1=header, 2=body */ *************** *** 1263,1271 **** void printTable(const char *title, ! const char *const * headers, ! const char *const * cells, ! const char *const * footers, const char *align, const printTableOpt *opt, FILE *fout, FILE *flog) { --- 1461,1469 ---- void printTable(const char *title, ! const char *const *headers, ! const char *const *cells, ! const char *const *footers, const char *align, const printTableOpt *opt, FILE *fout, FILE *flog) { *************** *** 1298,1304 **** int col_count = 0, row_count = 0, lines; ! const char *const * ptr; /* rough estimate of columns and rows */ if (headers) --- 1496,1502 ---- int col_count = 0, row_count = 0, lines; ! const char *const *ptr; /* rough estimate of columns and rows */ if (headers) *************** *** 1325,1362 **** /* print the stuff */ if (flog) ! print_aligned_text(title, headers, cells, footers, align, opt->tuples_only, border, opt->encoding, flog); switch (opt->format) { case PRINT_UNALIGNED: if (use_expanded) ! print_unaligned_vertical(title, headers, cells, footers, opt->fieldSep, opt->recordSep, ! opt->tuples_only, output); else ! print_unaligned_text(title, headers, cells, footers, opt->fieldSep, opt->recordSep, ! opt->tuples_only, output); break; case PRINT_ALIGNED: if (use_expanded) ! print_aligned_vertical(title, headers, cells, footers, ! opt->tuples_only, border, opt->encoding, output); else ! print_aligned_text(title, headers, cells, footers, ! align, opt->tuples_only, border, opt->encoding, output); break; case PRINT_HTML: if (use_expanded) ! print_html_vertical(title, headers, cells, footers, ! align, opt->tuples_only, border, opt->tableAttr, output); else print_html_text(title, headers, cells, footers, ! align, opt->tuples_only, border, opt->tableAttr, output); break; case PRINT_LATEX: --- 1523,1560 ---- /* print the stuff */ if (flog) ! print_aligned_text(title, headers, cells, footers, align, opt->tuples_only, opt->numericSep, border, opt->encoding, flog); switch (opt->format) { case PRINT_UNALIGNED: if (use_expanded) ! print_unaligned_vertical(title, headers, cells, footers, align, opt->fieldSep, opt->recordSep, ! opt->tuples_only, opt->numericSep, output); else ! print_unaligned_text(title, headers, cells, footers, align, opt->fieldSep, opt->recordSep, ! opt->tuples_only, opt->numericSep, output); break; case PRINT_ALIGNED: if (use_expanded) ! print_aligned_vertical(title, headers, cells, footers, align, ! opt->tuples_only, opt->numericSep, border, opt->encoding, output); else ! print_aligned_text(title, headers, cells, footers, align, ! opt->tuples_only, opt->numericSep, border, opt->encoding, output); break; case PRINT_HTML: if (use_expanded) ! print_html_vertical(title, headers, cells, footers, align, ! opt->tuples_only, opt->numericSep, border, opt->tableAttr, output); else print_html_text(title, headers, cells, footers, ! align, opt->tuples_only, opt->numericSep, border, opt->tableAttr, output); break; case PRINT_LATEX: Index: src/bin/psql/print.h =================================================================== RCS file: /cvsroot/pgsql/src/bin/psql/print.h,v retrieving revision 1.25 diff -c -c -r1.25 print.h *** src/bin/psql/print.h 14 Jun 2005 02:57:41 -0000 1.25 --- src/bin/psql/print.h 10 Jul 2005 03:24:24 -0000 *************** *** 40,45 **** --- 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
", opt_align[i % col_count] == 'r' ? "right" : "left"); ! if ((*ptr)[strspn(*ptr, " \t")] == '\0') /* is string only ! * whitespace? */ fputs("  ", fout); else html_escaped_print(*ptr, fout); fputs("
", opt_align[i % col_count] == 'r' ? "right" : "left"); ! /* is string only whitespace? */ ! if ((*ptr)[strspn(*ptr, " \t")] == '\0') fputs("  ", fout); + else if ((opt_align[i % col_count] == 'r') && strlen(*ptr) != 0 && + opt_numericsep != NULL && strlen(opt_numericsep) > 0) + { + char *my_cell = malloc(len_with_numericsep(*ptr)); + + if (!my_cell) + { + fprintf(stderr, _("out of memory\n")); + exit(EXIT_FAILURE); + } + strcpy(my_cell, *ptr); + format_numericsep(my_cell, opt_numericsep); + html_escaped_print(my_cell, fout); + free(my_cell); + } else html_escaped_print(*ptr, fout); + fputs("
*/ int encoding; /* character encoding */ bool normal_query; /* are we presenting the results of a