Mail Archives: djgpp-workers/2001/02/23/12:31:37
Hi, that's me again :-)
That's a third edition of locale support (I haven't changed strcoll() and strftime() any more, so please peek them from previous patch).
I wonder if someone intrested in these patches. Any comments except of formatting style? ;-)
/* 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 <aaganichev AT netscape DOT net> */
#include <locale.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <dpmi.h>
#include <libc/farptrgs.h>
#include <go32.h>
#include <limits.h>
#define LOCALE_NAME_MAX (5+1+10) /* "ru_RU.866" */
static char lcn_collate[LOCALE_NAME_MAX + 1] = "C";
static char lcn_ctype[LOCALE_NAME_MAX + 1] = "C";
static char lcn_monetary[LOCALE_NAME_MAX + 1] = "C";
static char lcn_numeric[LOCALE_NAME_MAX + 1] = "C";
static char lcn_time[LOCALE_NAME_MAX + 1] = "C";
static char currency_symbol[6] = "";
static char mon_decimal_point[2] = "";
static char mon_thousands_sep[2] = "";
static char decimal_point[2] = ".";
static char thousands_sep[2] = "";
static struct __loc2id {
int id;
const char loc[LOCALE_NAME_MAX + 1];
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[LOCALE_NAME_MAX + 1];
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++) {
__dj_ctype_tolower[i + 1] = i;
__dj_ctype_toupper[i + 1] = 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) &(__dj_ctype_toupper[128 + 1]), 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))
__dj_ctype_tolower[c + 1] = 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))
__dj_ctype_tolower[i + 1] = __dj_ctype_toupper[i + 1] = i;
if (toupper(tolower(i)) != toupper(i))
__dj_ctype_toupper[i + 1] = i;
if (tolower(toupper(i)) != tolower(i))
__dj_ctype_tolower[i + 1] = 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;
static char rv[5 * (LOCALE_NAME_MAX + 1)];
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(rv, ",");
strcat(rv, lcn_ctype);
strcat(rv, ",");
strcat(rv, lcn_monetary);
strcat(rv, ",");
strcat(rv, lcn_numeric);
strcat(rv, ",");
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;
char buf[5 * (LOCALE_NAME_MAX + 1)];
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 <stdio.h>
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
--
Alexander Aganichev
Hypercom Europe Limited, Inc.
Software Engineer
__________________________________________________________________
Get your own FREE, personal Netscape Webmail account today at http://webmail.netscape.com/
- Raw text -