delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2001/01/29/09:53:13

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
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 <aaganichev AT netscape DOT net> */

#include <locale.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <dpmi.h>
#include <sys/farptr.h>
#include <go32.h>
#include <limits.h>

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, &regs);
    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, &regs);
          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, &regs);
          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 <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
--

-- strcoll.c
/* Copyright (C) 1994 DJ Delorie, see COPYING.DJ for details */
/* Modified 1999 by Alexander S. Aganichev <aaganichev AT netscape DOT net> */

#include <string.h>

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 <aaganichev AT netscape DOT net> */
 #include <string.h>
 #include <time.h>
 #include <ctype.h>
@@ -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/

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019