Date: Mon, 29 Jan 2001 09:53:01 -0500 From: AAganichev AT netscape DOT net (Alexander Aganichev) To: djgpp-workers AT delorie DOT com Subject: Re: locale support: 2nd approach Mime-Version: 1.0 Message-ID: <75955792.7119524B.09ACFA57@netscape.net> X-Mailer: Franklin Webmailer 1.0 Content-Type: text/plain; charset="us-ascii" Reply-To: djgpp-workers AT delorie DOT com >> I've made a second approach to the locale under DJGPP v2. This version >> provides support for is*() family of functions from ctype as well, so >> now we have: [...] > To start with you need to send it unzipped in plain text. It's hard to > read compressed... Plus, preferably NOT as an attachment. -- setlocal.c /* Copyright (C) 1994 DJ Delorie, see COPYING.DJ for details */ /* Portions copyright (C) 1994-1996 by Eberhard Mattes */ /* Modified 1999-2001 by Alexander S. Aganichev */ #include #include #include #include #include #include #include #include static char lcn_collate[256] = "C"; static char lcn_ctype[256] = "C"; static char lcn_monetary[256] = "C"; static char lcn_numeric[256] = "C"; static char lcn_time[256] = "C"; static char currency_symbol[16] = ""; static char mon_decimal_point[16] = ""; static char mon_thousands_sep[16] = ""; static char decimal_point[16] = "."; static char thousands_sep[16] = ""; static struct __loc2id { int id; const char *loc; int len; } loc2id[] = { /* add your country here ;-) */ {1, "en_US", 5}, {7, "ru_RU", 5}, {33, "fr_FR", 5}, {49, "de_DE", 5} }; static const int cat[5] = {LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME}; extern unsigned char __dj_collate_table[]; extern char __dj_date_format[]; extern char __dj_time_format[]; static int setlocale2(int category, const char *locale) { int segment, selector; __dpmi_regs regs; struct lconv *lcnv = localeconv(); int i, rv = 0; char buf[256]; if (category == LC_ALL) { rv = !setlocale2(LC_COLLATE, locale); rv += !setlocale2(LC_CTYPE, locale); rv += !setlocale2(LC_MONETARY, locale); rv += !setlocale2(LC_NUMERIC, locale); rv += !setlocale2(LC_TIME, locale); return !rv; } if (!strcmp(locale, "C") || !strcmp(locale, "POSIX")) { switch(category) { case LC_COLLATE: for (i = 0; i < 256; i++) __dj_collate_table[i] = i; strcpy (lcn_collate, locale); return 1; case LC_CTYPE: for (i = 128; i < 256; i++) { tolower(i) = i; toupper(i) = i; __dj_ctype_flags[i+1] = 0; } strcpy (lcn_ctype, locale); return 1; case LC_MONETARY: if(lcnv) { strcpy (currency_symbol, ""); lcnv->int_curr_symbol = lcnv->currency_symbol = currency_symbol; strcpy (mon_thousands_sep, ""); lcnv->mon_thousands_sep = mon_thousands_sep; strcpy (mon_decimal_point, ""); lcnv->mon_decimal_point = mon_decimal_point; /* lcnv->mon_grouping = ""; */ /* lcnv->negative_sign = ""; */ /* lcnv->positive_sign = ""; */ lcnv->int_frac_digits = lcnv->frac_digits = CHAR_MAX; lcnv->p_cs_precedes = lcnv->n_cs_precedes = CHAR_MAX; lcnv->p_sep_by_space = lcnv->n_sep_by_space = CHAR_MAX; /* lcnv->p_sign_posn = lcnv->n_sign_posn = CHAR_MAX; */ strcpy (lcn_monetary, locale); return 1; } else return 0; case LC_NUMERIC: if(lcnv) { strcpy (thousands_sep, ""); lcnv->thousands_sep = thousands_sep; strcpy (decimal_point, "."); lcnv->decimal_point = decimal_point; /* lcnv->grouping = ""; */ strcpy (lcn_numeric, locale); return 1; } else return 0; case LC_TIME: strcpy(__dj_date_format, "%m/%d/%y"); strcpy(__dj_time_format, "%H:%M:%S"); strcpy (lcn_time, locale); return 1; } } if((segment = __dpmi_allocate_dos_memory(3, &selector)) != -1) { int CID = 0xffff, CCP = 0xffff; if(*locale) { int len; const char *p = strchr(locale, '.'); if(p == NULL) p = locale + strlen (locale); len = p - locale; for (i = 0; i < sizeof(loc2id)/sizeof(struct __loc2id); i++) if(!strncmp (locale, loc2id[i].loc, len >= loc2id[i].len ? len : loc2id[i].len)) { CID = loc2id[i].id; break; } if(*p == '.') CCP = atoi(p+1); } regs.h.ah = 0x65; regs.h.al = 0x01; regs.x.bx = CCP; regs.x.dx = CID; regs.x.cx = 41; regs.x.es = segment; regs.x.di = 0; __dpmi_int(0x21, ®s); if(!(regs.x.flags & 1) && regs.x.cx == 41) { if (!*locale) { CID = _farpeekw(selector, 3); CCP = _farpeekw(selector, 5); locale = buf; strcpy (buf, "en_US."); for (i = 0; i < sizeof(loc2id)/sizeof(struct __loc2id); i++) if(loc2id[i].id == CID) { strcpy (buf, loc2id[i].loc); buf[loc2id[i].len] = '.'; break; } itoa (CCP, &buf[strlen (buf)], 10); } switch(category) { case LC_COLLATE: regs.h.ah = 0x65; regs.h.al = 0x06; regs.x.bx = CCP; regs.x.dx = CID; regs.x.cx = 5; regs.x.es = segment; regs.x.di = 0; __dpmi_int(0x21, ®s); if(!(regs.x.flags & 1) && (regs.x.cx == 5)) { unsigned int table = _farpeekw(selector, 3) * 16 + _farpeekw(selector, 1); int size = _farpeekw(_dos_ds, table); movedata(_dos_ds, table + 2, _my_ds(), (unsigned int)__dj_collate_table, size); rv = 1; } else rv = 0; strcpy (lcn_collate, locale); rv = 1; break; case LC_CTYPE: regs.h.ah = 0x65; regs.h.al = 0x02; regs.x.bx = CCP; regs.x.dx = CID; regs.x.cx = 5; regs.x.es = segment; regs.x.di = 0; __dpmi_int(0x21, ®s); if(!(regs.x.flags & 1) && (regs.x.cx == 5)) { unsigned int table = _farpeekw(selector, 3) * 16 + _farpeekw(selector, 1); int size = _farpeekw(_dos_ds, table); movedata(_dos_ds, table + 2, _my_ds(), (unsigned int)&(toupper(128)), size); /* let's build lowercase table from uppercase... */ for(i = 0; i < size; i++) { int c = toupper(i + 128); if((c != i + 128) && (c > 127)) tolower(c) = i + 128; } for(i=128; i<256; i++) { /* By this conversion we could break something like 0xe1 in CP437 * but in most cases it better works this way */ if((toupper(tolower(i)) != i) && (tolower(toupper(i)) != i)) tolower(i) = toupper(i) = i; if(toupper(tolower(i)) != toupper(i)) toupper(i) = i; if(tolower(toupper(i)) != tolower(i)) tolower(i) = i; /* Actually isgraph(), ispunct() and isspace() will return wrong * results for some letters like 0xff in CP866 but we can't * detect them reliably */ __dj_ctype_flags[i+1] = __dj_ISPRINT | __dj_ISGRAPH; if(tolower(i) != toupper(i)) __dj_ctype_flags[i+1] |= __dj_ISALPHA | __dj_ISALNUM | ((i == toupper(i)) ? __dj_ISUPPER : __dj_ISLOWER); else __dj_ctype_flags[i+1] |= __dj_ISPUNCT; } rv = 1; } else rv = 0; strcpy (lcn_ctype, locale); break; case LC_MONETARY: if(lcnv) { movedata(selector, 9, _my_ds(), (unsigned)currency_symbol, 5); lcnv->int_curr_symbol = lcnv->currency_symbol = currency_symbol; movedata(selector, 14, _my_ds(), (unsigned)mon_thousands_sep, 2); lcnv->mon_thousands_sep = mon_thousands_sep; movedata(selector, 16, _my_ds(), (unsigned)mon_decimal_point, 2); lcnv->mon_decimal_point = mon_decimal_point; /* lcnv->mon_grouping = ""; */ /* lcnv->negative_sign = ""; */ /* lcnv->positive_sign = ""; */ lcnv->int_frac_digits = lcnv->frac_digits = _farpeekb (selector, 24); lcnv->p_cs_precedes = lcnv->n_cs_precedes = _farpeekb (selector, 23) & 1; lcnv->p_sep_by_space = lcnv->n_sep_by_space = _farpeekb (selector, 23) & 2; /* lcnv->p_sign_posn = lcnv->n_sign_posn = CHAR_MAX; */ strcpy (lcn_monetary, locale); rv = 1; } else rv = 0; break; case LC_NUMERIC: if(lcnv) { movedata(selector, 14, _my_ds(), (unsigned)thousands_sep, 2); lcnv->thousands_sep = thousands_sep; movedata(selector, 16, _my_ds(), (unsigned)decimal_point, 2); lcnv->decimal_point = decimal_point; /* lcnv->grouping = ""; */ strcpy (lcn_numeric, locale); rv = 1; } else rv = 0; break; case LC_TIME: switch(_farpeekw(selector, 7)) { case 0: default: strcpy(__dj_date_format, "%m/%d/%y"); break; case 1: strcpy(__dj_date_format, "%d/%m/%y"); break; case 2: strcpy(__dj_date_format, "%y/%m/%d"); break; } __dj_date_format[2] = __dj_date_format[5] = _farpeekb(selector, 18); if(_farpeekb(selector, 24) & 1) strcpy(__dj_time_format, "%H:%M:%S"); else strcpy(__dj_time_format, "%I:%M:%S %p"); __dj_time_format[2] = __dj_time_format[5] = _farpeekb(selector, 20); strcpy (lcn_time, locale); rv = 1; break; } } else rv = 0; __dpmi_free_dos_memory(selector); return rv; } else return 0; } char *setlocale(int category, const char *locale) { int i; char buf[256]; static char rv[256]; switch (category) { case LC_ALL: if (stricmp (lcn_collate, lcn_ctype) == 0 && stricmp (lcn_collate, lcn_monetary) == 0 && stricmp (lcn_collate, lcn_numeric) == 0 && stricmp (lcn_collate, lcn_time) == 0) strcpy(rv, lcn_collate); else { /* Create a comma-separated list of locales for all the categories. */ strcpy (rv, lcn_collate); strcat (buf, ","); strcat (rv, lcn_ctype); strcat (buf, ","); strcat (rv, lcn_monetary); strcat (buf, ","); strcat (rv, lcn_numeric); strcat (buf, ","); strcat (rv, lcn_time); } break; case LC_COLLATE: strcpy(rv, lcn_collate); break; case LC_CTYPE: strcpy(rv, lcn_ctype); break; case LC_MONETARY: strcpy(rv, lcn_monetary); break; case LC_NUMERIC: strcpy(rv, lcn_numeric); break; case LC_TIME: strcpy(rv, lcn_time); break; default: return NULL; } if(locale != 0) { if(*locale == '\0') { char *lc = getenv ("LANG"); if (lc != NULL) locale = lc; } if ((category != LC_ALL) || (strchr (locale, ',') == NULL)) return setlocale2 (category, locale) ? rv : NULL; else { char *s1, *s2; strcpy(buf, locale); s1 = buf; for (i = 0; i < 5; i++) { s2 = strchr(s1, ','); if(s2 != NULL) *s2 = '\0'; if(!setlocale2 (cat[i], s1) || ((s2 == NULL) && (i != 4))) return NULL; } } } return rv; } #ifdef TEST #include unsigned char __dj_collate_table[256]; char __dj_date_format[10] = "%m/%d/%y"; char __dj_time_format[16] = "%H:%M:%S"; int main(int ac, char *av[]) { int i; const char *loc = (ac == 1) ? "" : av[1]; char *lc = setlocale(LC_ALL, loc); lc = setlocale(LC_ALL, NULL); printf("Locale: %s\n", lc ? lc : "not detected"); for(i = 0; i < 256; i++) printf("%c%c%c|", (char)i, tolower(i), toupper(i)); printf("\n"); for(i = 0; i < 256; i++) printf("%02xh ", __dj_collate_table[i]); printf("\n%f\n%s %s\n", 1000456.23, __dj_date_format, __dj_time_format); } #endif -- -- strcoll.c /* Copyright (C) 1994 DJ Delorie, see COPYING.DJ for details */ /* Modified 1999 by Alexander S. Aganichev */ #include unsigned char __dj_collate_table[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; #define coll(c) __dj_collate_table[(unsigned char)c] int strcoll(const char *s1, const char *s2) { while (coll(*s1) == coll(*s2)) { if (*s1 == 0) return 0; s1++; s2++; } return coll(*s1) - coll(*s2); } -- diff -ru src/time/strftime.c src.localized/time/strftime.c --- src/time/strftime.c Thu Jun 3 13:27:34 1999 +++ src.localized/time/strftime.c Mon Jan 29 17:48:43 2001 @@ -1,6 +1,7 @@ /* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1994 DJ Delorie, see COPYING.DJ for details */ +/* Modified 1999 by Alexander S. Aganichev */ #include #include #include @@ -22,6 +23,8 @@ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", }; +char __dj_date_format[10] = "%m/%d/%y"; +char __dj_time_format[16] = "%H:%M:%S"; static size_t gsize; static char *pt; @@ -176,7 +179,6 @@ return 0; continue; case 'T': - case 'X': if (!_fmt("%H:%M:%S", t, upcase)) return 0; continue; @@ -203,8 +205,12 @@ if (!_conv(t->tm_wday, 1, pad)) return 0; continue; + case 'X': + if (!_fmt(__dj_time_format, t, upcase)) + return 0; + continue; case 'x': - if (!_fmt("%m/%d/%y", t, upcase)) + if (!_fmt(__dj_date_format, t, upcase)) return 0; continue; case 'y': -- Alexander Aganichev Hypercom Europe Limited, Inc. Software Engineer __________________________________________________________________ Get your own FREE, personal Netscape Webmail account today at http://webmail.netscape.com/