Index: formats.c =================================================================== RCS file: /cvs/gnome/gnumeric/src/formats.c,v retrieving revision 1.52 diff -u -r1.52 formats.c --- formats.c 4 Sep 2002 20:29:33 -0000 1.52 +++ formats.c 4 Oct 2002 20:43:06 -0000 @@ -15,6 +15,7 @@ #include "format.h" #include +#include /* The various formats */ static char const * const @@ -161,6 +162,10 @@ NULL }; +/* The compiled regexp for cell_format_classify */ +static regex_t re_number_currency; +static regex_t re_percent_science; + void currency_date_format_init (void) { @@ -234,6 +239,40 @@ cell_format_time [4] = "d/m/yy h:mm"; } + + /* Compile the regexps for format classification */ + + /* This is the regexp for FMT_NUMBER and FMT_CURRENCY */ + + /* + * 1. "$ #,##0.000" + * (currency symbol before number) + * 2. "$ " + * 3. "$" + * 4. " " (space after currency) + * 5. "#,##" + * 6. ".000" + * (currency symbol after number) + * 7. " $" + * 8. " " (space before currency) + * 9. "$" + * 10. 11 or 13 + * 11. ";[Red]\1" (\1 means same string as 1) + * 12. "[Red]" + * 13. "_);[Red](\1)" + * 14. "[Red]" + */ + + char const *pattern_number_currency = "^\\(\\(\\(\\$\\|£\\|Â¥\\|€\\|\\[\\$[A-Z][A-Z][A-Z]\\]\\)\\(\\\\\\? \\)\\?\\)\\?\\(#,##\\)\\?0\\(\\.0\\{1,30\\}\\)\\?\\(\\(\\\\\\? \\)\\?\\(\\$\\|£\\|Â¥\\|€\\|\\[\\$[A-Z][A-Z][A-Z]\\]\\)\\)\\?\\)\\(\\(;\\(\\[Red\\]\\)\\?\\1\\)\\|\\(_);\\(\\[Red\\]\\)\\?(\\1)\\)\\)\\?$"; + + /* This one is for FMT_PERCENT and FMT_SCIENCE */ + char const *pattern_percent_science = "^0\\(.0\\{1,30\\}\\)\\?\\(%\\|E+00\\)$"; + + if ((regcomp(&re_number_currency, pattern_number_currency, 0)) != 0) + fprintf(stderr, "Error in regcomp()\n"); + + if ((regcomp(&re_percent_science, pattern_percent_science, 0)) != 0) + fprintf(stderr, "Error in regcomp()\n"); } void @@ -450,141 +489,93 @@ return NULL; } +/* Returns the index in currency_symbols of the symbol in ptr */ +static int +find_currency(char const *ptr, int len) +{ + int i; + + for (i = 0; currency_symbols[i].symbol; i++) { + if (strncmp(currency_symbols[i].symbol, ptr, len) == 0) + return i; + } + + return -1; +} + static FormatFamily cell_format_is_number (char const * const fmt, FormatCharacteristics *info) { FormatFamily result = FMT_NUMBER; - gboolean has_sep = FALSE; - int use_paren = 0; - int use_red = 0; - int num_decimals = 0; - char const *ptr = fmt, *end, *tmp; - int const fmt_len = strlen (fmt); + char const *ptr = fmt; int cur = -1; - - if (fmt_len < 1) - return FMT_UNKNOWN; - - /* Check for prepended currency */ - switch (ptr[0]) { - case '$' : cur = 1; break; - case '£' : cur = 2; break; - case '¥' : cur = 3; break; - case '¤' : cur = 4; break; - default : - if (ptr[0] == '[' && ptr[1] == '$') { - char const * const end = strchr (ptr, ']'); - - if (end != NULL && end[1] == ' ') { - /* FIXME : Look up the correct index */ - info->currency_symbol_index = 1; + +#define MATCH_SIZE 15 + regmatch_t match[MATCH_SIZE]; + + // FMT_CURRENCY or FMT_NUMBER ? + + if (regexec(&re_number_currency, fmt, MATCH_SIZE, match, 0) == 0) { + + /* match[3] and match[9] contain the Currency symbol */ + if (match[3].rm_eo == -1 && match[9].rm_eo == -1) + result = FMT_NUMBER; + else { result = FMT_CURRENCY; - ptr = end + 1; - } else - return FMT_UNKNOWN; - } - }; - - if (cur > 0) { - info->currency_symbol_index = cur; - result = FMT_CURRENCY; - ++ptr; - } - - /* Check for thousands separator */ - if (ptr[0] == '#') { - if (ptr[1] == ',') - ++ptr; - else - return FMT_UNKNOWN; - ptr = strncmp_inc (ptr, "##", 2); - if (ptr == NULL) - return FMT_UNKNOWN; - has_sep = TRUE; - } - - if (ptr[0] != '0') - return FMT_UNKNOWN; - ++ptr; - - /* Check for decimals */ - if (ptr [0] == '.') { - num_decimals = 0; - ptr++; - while (ptr[num_decimals] == '0') - ++num_decimals; - ptr += num_decimals; - } - - if (ptr[0] == '%') { - if (!has_sep && info->currency_symbol_index == 0) { - info->num_decimals = num_decimals; - return FMT_PERCENT; + if (match[9].rm_eo == -1) + cur = find_currency(ptr + match[3].rm_so, + match[3].rm_eo + - match[3].rm_so); + else if (match[3].rm_eo == -1) + cur = find_currency(ptr + match[9].rm_so, + match[9].rm_eo + - match[9].rm_so); + else + return FMT_UNKNOWN; + + if (cur == -1) + return FMT_UNKNOWN; + info->currency_symbol_index = cur; } - return FMT_UNKNOWN; - } - if (NULL != (tmp = strcmp_inc (ptr, "E+00"))) { - if (!has_sep && info->currency_symbol_index == 0 && *tmp == '\0') { - info->num_decimals = num_decimals; - return FMT_SCIENCE; - } - return FMT_UNKNOWN; - } - - if (ptr[0] != ';' && ptr[0] != '_' && ptr[0]) - return FMT_UNKNOWN; - - /* We have now handled decimals, and thousands separators */ - info->thousands_sep = has_sep; - info->num_decimals = num_decimals; - info->negative_fmt = 0; /* Temporary, we may change this below */ - - /* No special negative handling */ - if (ptr[0] == '\0') + + /* match[5] contains the #,## string */ + if (match[5].rm_eo != -1) + info->thousands_sep = TRUE; + + /* match[6] contains the .0000... string */ + info->num_decimals = 0; + if (match[6].rm_eo != -1) + info->num_decimals = match[6].rm_eo - + match[6].rm_so - 1; + + info->negative_fmt = 0; + // match[12] and match[14] contain the [Red] string */ + if ((match[12].rm_eo != -1) || (match[14].rm_eo != -1)) + info->negative_fmt++; + // match[13] contains _);(...) + if (match[13].rm_eo != -1) + info->negative_fmt += 2; + return result; - - /* Save this position */ - end = ptr; - - /* Handle Trailing '_)' */ - if (ptr[0] == '_') { - if (ptr[1] != ')') - return FMT_UNKNOWN; - ptr += 2; - use_paren = 2; } - if (ptr[0] != ';') - return FMT_UNKNOWN; - ++ptr; - - if (ptr[0] == '[') { - if (g_ascii_strncasecmp (_("[Red]"), ptr, 5) != 0) - return FMT_UNKNOWN; - ptr += 5; - use_red = 1; - } - - if (use_paren) { - if (ptr[0] != '(') - return FMT_UNKNOWN; - ++ptr; - } - - /* The next segment should match the original */ - ptr = strncmp_inc (ptr, fmt, end-fmt); - if (ptr == NULL) - return FMT_UNKNOWN; - - if (use_paren) { - if (ptr[0] != ')') - return FMT_UNKNOWN; - ++ptr; + // FMT_PERCENT or FMT_SCIENCE ? + + if (regexec(&re_percent_science, fmt, MATCH_SIZE, match, 0) == 0) { + + info->num_decimals = 0; + if (match[1].rm_eo != -1) + info->num_decimals = match[1].rm_eo - + match[1].rm_so - 1; + + if (ptr[match[2].rm_so] == '%') + return FMT_PERCENT; + else + return FMT_SCIENCE; } - - info->negative_fmt = use_paren + use_red; - - return result; + + return FMT_UNKNOWN; + } FormatFamily