dect
/
asl
Archived
13
0
Fork 0
This repository has been archived on 2022-02-17. You can view files and clone it, but cannot push or open issues or pull requests.
asl/nls.c

645 lines
17 KiB
C

/* nls.c */
/*****************************************************************************/
/* AS-Portierung */
/* */
/* Abhandlung landesspezifischer Unterschiede */
/* */
/* Historie: 16. 5.1996 Grundsteinlegung */
/* 28. 7.1999 %T ist Abkuerzung fuer %H:%M:%S */
/* */
/*****************************************************************************/
#undef DEBUG_NLS
#include "stdinc.h"
#include <string.h>
#include <time.h>
#include <ctype.h>
#ifdef LOCALE_NLS
#include <locale.h>
#include <langinfo.h>
#endif
#ifdef OS2_NLS
#define INCL_DOSNLS
#include <os2.h>
#endif
#ifdef DOS_NLS
#include <dos.h>
#endif
#include "strutil.h"
#include "nls.h"
CharTable UpCaseTable; /* Umsetzungstabellen */
CharTable LowCaseTable;
static NLS_CountryInfo NLSInfo;
static CharTable CollateTable;
/*-------------------------------------------------------------------------------*/
/* einen String anhand einer Tabelle uebersetzen: */
static void TranslateString(char *s, CharTable Table)
BEGIN
for (; *s!='\0'; s++) *s=Table[((unsigned int) *s)&0xff];
END
/*-------------------------------------------------------------------------------*/
/* Da es moeglich ist, die aktuelle Codeseite im Programmlauf zu wechseln,
ist die Initialisierung in einer getrennten Routine untergebracht. Nach
einem Wechsel stellt ein erneuter Aufruf wieder korrekte Verhaeltnisse
her. Wen das stoert, der schreibe einfach einen Aufruf in den Initiali-
sierungsteil der Unit hinein. */
#ifdef DOS_NLS
typedef struct
{
Byte TimeFmt;
Byte DateFmt;
char Currency[2];
char ThouSep[2];
char DecSep[2];
Byte Reserved[24];
} Dos2CountryInfo;
typedef struct
{
Word DateFmt;
char Currency[5];
char ThouSep[2];
char DecSep[2];
char DateSep[2];
char TimeSep[2];
Byte CurrFmt;
Byte CurrDecimals;
Byte TimeFmt;
char *UpCasePtr;
char DataSep[2];
Byte Dummy[8];
} Dos3CountryInfo;
typedef struct
{
Byte SubFuncNo;
char *Result;
} DosTableRec;
char *DosCopy(char *Src, int Len)
BEGIN
char *res=malloc(sizeof(char)*(Len+1));
memcpy(res,Src,Len); res[Len]='\0';
return res;
END
void StandardUpCases(void)
BEGIN
char *s1,*s2;
s1=CH_ae; s2=CH_Ae; UpCaseTable[((unsigned int) *s1)&0xff]=*s2;
s1=CH_oe; s2=CH_Oe; UpCaseTable[((unsigned int) *s1)&0xff]=*s2;
s1=CH_ue; s2=CH_Ue; UpCaseTable[((unsigned int) *s1)&0xff]=*s2;
END
#endif
void NLS_Initialize(void)
BEGIN
char *tmpstr,*run,*cpy;
Word FmtBuffer;
int z;
#ifdef DEBUG_NLS
int z2;
#endif
Boolean DidDate;
#ifdef LOCALE_NLS
struct lconv *lc;
#endif
#ifdef OS2_NLS
COUNTRYCODE ccode;
COUNTRYINFO cinfo;
ULONG erglen;
#endif
#ifdef DOS_NLS
union REGS Regs;
struct SREGS SRegs;
void *info;
Dos2CountryInfo DOS2Info;
Dos3CountryInfo DOS3Info;
DosTableRec DOSTablePtr;
#endif
/* get currency format, separators */
#ifdef NO_NLS
NLSInfo.DecSep=".";
NLSInfo.DataSep=",";
NLSInfo.ThouSep=",";
NLSInfo.Currency="$";
NLSInfo.CurrDecimals=2;
NLSInfo.CurrFmt=CurrFormatPreNoBlank;
#endif
#ifdef LOCALE_NLS
lc=localeconv();
NLSInfo.DecSep=(lc->mon_decimal_point!=Nil)?lc->decimal_point:".";
NLSInfo.ThouSep=(lc->mon_thousands_sep!=Nil)?lc->mon_thousands_sep:",";
NLSInfo.DataSep=",";
NLSInfo.Currency=(lc->currency_symbol!=Nil)?lc->currency_symbol:"$";
NLSInfo.CurrDecimals=lc->int_frac_digits;
if (NLSInfo.CurrDecimals>4) NLSInfo.CurrDecimals=2;
if (lc->p_cs_precedes)
if (lc->p_sep_by_space) NLSInfo.CurrFmt=CurrFormatPreBlank;
else NLSInfo.CurrFmt=CurrFormatPreNoBlank;
else
if (lc->p_sep_by_space) NLSInfo.CurrFmt=CurrFormatPostBlank;
else NLSInfo.CurrFmt=CurrFormatPostNoBlank;
#endif
#ifdef OS2_NLS
ccode.country=0; ccode.codepage=0;
DosQueryCtryInfo(sizeof(cinfo),&ccode,&cinfo,&erglen);
NLSInfo.Country=cinfo.country;
NLSInfo.CodePage=cinfo.codepage;
NLSInfo.DecSep=strdup(cinfo.szDecimal);
NLSInfo.DataSep=strdup(cinfo.szDataSeparator);
NLSInfo.ThouSep=strdup(cinfo.szThousandsSeparator);
NLSInfo.Currency=strdup(cinfo.szCurrency);
NLSInfo.CurrDecimals=cinfo.cDecimalPlace;
NLSInfo.CurrFmt=(CurrFormat) cinfo.fsCurrencyFmt;
#endif
#ifdef DOS_NLS
if (_osmajor<3) NLSInfo.CodePage=437;
else if (_osminor<30) NLSInfo.CodePage=437;
else
BEGIN
Regs.x.ax=0x6601;
int86(0x21,&Regs,&Regs);
NLSInfo.CodePage=Regs.x.bx;
END
Regs.x.ax=0x3800;
if (_osmajor<3) info=&DOS2Info; else info=&DOS3Info;
SRegs.ds=FP_SEG(info); Regs.x.dx=FP_OFF(info);
int86x(0x21,&Regs,&Regs,&SRegs);
NLSInfo.Country=Regs.x.bx;
if (_osmajor>=3)
BEGIN
NLSInfo.DecSep=DosCopy(DOS3Info.DecSep,2);
NLSInfo.DataSep=DosCopy(DOS3Info.DataSep,2);
NLSInfo.ThouSep=DosCopy(DOS3Info.ThouSep,2);
NLSInfo.Currency=DosCopy(DOS3Info.Currency,5);
NLSInfo.CurrDecimals=DOS3Info.CurrDecimals;
NLSInfo.CurrFmt=(CurrFormat) DOS3Info.CurrFmt;
END
/* DOS 2 kennt noch nicht soviel, daher muessen wir selber etwas beisteuern */
else
BEGIN
NLSInfo.DecSep=DosCopy(DOS2Info.DecSep,2);
NLSInfo.DataSep=",";
NLSInfo.ThouSep=DosCopy(DOS2Info.ThouSep,2);
NLSInfo.Currency=DosCopy(DOS2Info.Currency,2);
NLSInfo.CurrDecimals=(NLSInfo.Country==39) ? 0 : 2;
switch (NLSInfo.Country)
BEGIN
case 1: case 39:
NLSInfo.CurrFmt=CurrFormatPreNoBlank; break;
case 3: case 33: case 34: case 358:
NLSInfo.CurrFmt=CurrFormatPostBlank; break;
default:
NLSInfo.CurrFmt=CurrFormatPreBlank;
END
END
#endif
/* get date format */
#ifdef NO_NLS
tmpstr="%m/%d/%y"; DidDate=False;
#endif
#ifdef LOCALE_NLS
tmpstr=nl_langinfo(D_FMT);
if ((tmpstr==Nil) OR (*tmpstr == '\0')) tmpstr="%m/%d/%y";
DidDate=False;
#endif
#ifdef OS2_NLS
NLSInfo.DateFmt=(DateFormat) cinfo.fsDateFmt;
NLSInfo.DateSep=strdup(cinfo.szDateSeparator);
DidDate=True;
#endif
#ifdef DOS_NLS
if (_osmajor>=3)
BEGIN
NLSInfo.DateFmt=(DateFormat) DOS3Info.DateFmt;
NLSInfo.DateSep=DosCopy(DOS3Info.DateSep,2);
END
else
BEGIN
NLSInfo.DateFmt=(DateFormat) DOS2Info.DateFmt;
switch (NLSInfo.Country)
BEGIN
case 3: case 47: case 351: case 32: case 33: case 39: case 34:
NLSInfo.DateSep="/"; break;
case 49: case 358: case 41:
NLSInfo.DateSep="."; break;
case 972:
NLSInfo.DateSep=" "; break;
default:
NLSInfo.DateSep="-";
END
END
DidDate=True;
#endif
if (NOT DidDate)
BEGIN
NLSInfo.DateSep=Nil; FmtBuffer=0; run=tmpstr;
while (*run!='\0')
if (*run=='%')
BEGIN
FmtBuffer<<=4;
switch (toupper(*(++run)))
BEGIN
case 'D': FmtBuffer+=1; break;
case 'M': FmtBuffer+=2; break;
case 'Y': FmtBuffer+=3; break;
END
if (NLSInfo.DateSep==Nil)
BEGIN
run++; cpy=NLSInfo.DateSep=strdup(" ");
while ((*run!=' ') AND (*run!='%')) *(cpy++)=(*(run++));
*cpy='\0';
END
else run++;
END
else run++;
if (FmtBuffer==0x213) NLSInfo.DateFmt=DateFormatMTY;
else if (FmtBuffer==0x123) NLSInfo.DateFmt=DateFormatTMY;
else NLSInfo.DateFmt=DateFormatYMT;
END
/* get time format */
#ifdef NO_NLS
tmpstr="%H:%M:%S"; DidDate=False;
#endif
#ifdef LOCALE_NLS
tmpstr=nl_langinfo(T_FMT);
if ((tmpstr==Nil) OR (*tmpstr == '\0')) tmpstr="%H:%M:%S";
DidDate=False;
#endif
#ifdef OS2_NLS
NLSInfo.TimeFmt=(TimeFormat) cinfo.fsTimeFmt;
NLSInfo.TimeSep=strdup(cinfo.szTimeSeparator);
DidDate=True;
#endif
#ifdef DOS_NLS
if (_osmajor>=3)
BEGIN
NLSInfo.TimeFmt=(TimeFormat) DOS3Info.TimeFmt;
NLSInfo.TimeSep=DosCopy(DOS3Info.TimeSep,2);
END
else
BEGIN
NLSInfo.TimeFmt=(TimeFormat) DOS2Info.TimeFmt;
switch (NLSInfo.Country)
BEGIN
case 41: case 46: case 47: case 358:
NLSInfo.TimeSep=".";
default:
NLSInfo.TimeSep=":";
END
END
DidDate=True;
#endif
if (NOT DidDate)
BEGIN
NLSInfo.TimeSep=Nil; FmtBuffer=0; run=tmpstr;
while (*run!='\0')
if (*run=='%')
BEGIN
FmtBuffer<<=4;
switch (toupper(*(++run)))
BEGIN
case 'S': FmtBuffer+=1; break;
case 'M': FmtBuffer+=2; break;
case 'H': FmtBuffer+=3; break;
case 'T': fprintf(stderr, "\nwarning, detected non-ANSI time format specifier '%%T'");
run = "H:%M:%S"; break;
case 'R': fprintf(stderr, "\nwarning, detected non-ANSI time format specifier '%%R'");
run = "H:%M"; break;
END
if (NLSInfo.TimeSep==Nil)
BEGIN
run++; cpy=NLSInfo.TimeSep=strdup(" ");
while ((*run != '\0') AND (*run!=' ') AND (*run!='%'))
*(cpy++)=(*(run++));
*cpy='\0';
END
else run++;
END
else run++;
NLSInfo.TimeFmt=TimeFormatEurope;
END
/* get lower->upper case table */
#if defined(NO_NLS) || defined(LOCALE_NLS)
for (z=0; z<256; z++) UpCaseTable[z]=toupper(z);
#endif
#ifdef OS2_NLS
for (z=0; z<256; z++) UpCaseTable[z]=(char) z;
for (z='a'; z<='z'; z++) UpCaseTable[z]-='a'-'A';
DosMapCase(sizeof(UpCaseTable),&ccode,UpCaseTable);
#endif
#ifdef DOS_NLS
for (z=0; z<256; z++) UpCaseTable[z]=(char) z;
for (z='a'; z<='z'; z++) UpCaseTable[z]-='a'-'A';
#ifdef __DPMI16__
StandardUpCases();
#else
if ((((Word)_osmajor)*100)+_osminor>=330)
BEGIN
Regs.x.ax=0x6502;
Regs.x.bx=NLSInfo.CodePage;
Regs.x.dx=NLSInfo.Country;
Regs.x.cx=sizeof(DOSTablePtr);
info=&DOSTablePtr; SRegs.es=FP_SEG(info); Regs.x.di=FP_OFF(info);
int86x(0x21,&Regs,&Regs,&SRegs);
if (Regs.x.cx==sizeof(DOSTablePtr))
BEGIN
DOSTablePtr.Result+=sizeof(Word);
memcpy(UpCaseTable+128,DOSTablePtr.Result,128);
END
else StandardUpCases();
END
else StandardUpCases();
#endif
#endif
/* get upper->lower case table */
#if defined(NO_NLS) || defined(LOCALE_NLS)
for (z=0; z<256; z++) LowCaseTable[z]=tolower(z);
#endif
#if defined(OS2_NLS) || defined(DOS_NLS)
for (z=0; z<256; z++) LowCaseTable[z]=(char) z;
for (z=255; z>=0; z--)
if (UpCaseTable[z]!=(char) z)
LowCaseTable[((unsigned int) UpCaseTable[z])&0xff]=(char) z;
#endif
/* get collation table */
#if defined(NO_NLS) || defined(LOCALE_NLS)
for (z=0; z<256; z++) CollateTable[z]=z;
for (z='a'; z<='z'; z++) CollateTable[z]=toupper(z);
#endif
#ifdef OS2_NLS
for (z=0; z<256; z++) CollateTable[z]=(char) z;
DosQueryCollate(sizeof(CollateTable),&ccode,CollateTable,&erglen);
#endif
#ifdef DOS_NLS
for (z=0; z<256; z++) CollateTable[z]=(char) z;
for (z='a'; z<='z'; z++) CollateTable[z]=(char) (z-('a'-'A'));
#ifndef __DPMI16__
if ((((Word)_osmajor)*100)+_osminor>=330)
BEGIN
Regs.x.ax=0x6506;
Regs.x.bx=NLSInfo.CodePage;
Regs.x.dx=NLSInfo.Country;
Regs.x.cx=sizeof(DOSTablePtr);
info=&DOSTablePtr; SRegs.es=FP_SEG(info); Regs.x.di=FP_OFF(info);
int86x(0x21,&Regs,&Regs,&SRegs);
if (Regs.x.cx==sizeof(DOSTablePtr))
BEGIN
DOSTablePtr.Result+=sizeof(Word);
memcpy(CollateTable,DOSTablePtr.Result,256);
END
END
#endif
#endif
#ifdef DEBUG_NLS
printf("Country = %d\n",NLSInfo.Country);
printf("CodePage = %d\n",NLSInfo.CodePage);
printf("DateFmt = ");
switch(NLSInfo.DateFmt)
BEGIN
case DateFormatMTY: printf("MTY\n"); break;
case DateFormatTMY: printf("TMY\n"); break;
case DateFormatYMT: printf("YMT\n"); break;
default: printf("???\n");
END
printf("DateSep = %s\n",NLSInfo.DateSep);
printf("TimeFmt = ");
switch(NLSInfo.TimeFmt)
BEGIN
case TimeFormatUSA: printf("USA\n"); break;
case TimeFormatEurope: printf("Europe\n"); break;
case TimeFormatJapan: printf("Japan\n"); break;
default: printf("???\n");
END
printf("TimeSep = %s\n",NLSInfo.TimeSep);
printf("Currency = %s\n",NLSInfo.Currency);
printf("CurrFmt = ");
switch (NLSInfo.CurrFmt)
BEGIN
case CurrFormatPreNoBlank: printf("PreNoBlank\n"); break;
case CurrFormatPostNoBlank: printf("PostNoBlank\n"); break;
case CurrFormatPreBlank: printf("PreBlank\n"); break;
case CurrFormatPostBlank: printf("PostBlank\n"); break;
default: printf("???\n");
END
printf("CurrDecimals = %d\n",NLSInfo.CurrDecimals);
printf("ThouSep = %s\n",NLSInfo.ThouSep);
printf("DecSep = %s\n",NLSInfo.DecSep);
printf("DataSep = %s\n",NLSInfo.DataSep);
printf("\nUpcaseTable:\n");
for (z=0; z<4; z++)
BEGIN
for (z2=0; z2<63; z2++) if (z*64+z2>32) putchar(z*64+z2); putchar ('\n');
for (z2=0; z2<63; z2++) if (z*64+z2>32) putchar(UpCaseTable[z*64+z2]); putchar ('\n');
putchar('\n');
END
printf("\nLowcaseTable:\n");
for (z=0; z<4; z++)
BEGIN
for (z2=0; z2<63; z2++) if (z*64+z2>32) putchar(z*64+z2); putchar ('\n');
for (z2=0; z2<63; z2++) if (z*64+z2>32) putchar(LowCaseTable[z*64+z2]); putchar ('\n');
putchar('\n');
END
printf("\nCollateTable:\n");
for (z=0; z<4; z++)
BEGIN
for (z2=0; z2<63; z2++) if (z*64+z2>32) putchar(z*64+z2); putchar ('\n');
for (z2=0; z2<63; z2++) if (z*64+z2>32) putchar(CollateTable[z*64+z2]); putchar ('\n');
putchar('\n');
END
exit(0);
#endif
END
void NLS_GetCountryInfo(NLS_CountryInfo *Info)
BEGIN
*Info=NLSInfo;
END
void NLS_DateString(Word Year, Word Month, Word Day, char *Dest)
BEGIN
switch (NLSInfo.DateFmt)
BEGIN
case DateFormatMTY:
sprintf(Dest,"%d%s%d%s%d",Month,NLSInfo.DateSep,Day,NLSInfo.DateSep,Year); break;
case DateFormatTMY:
sprintf(Dest,"%d%s%d%s%d",Day,NLSInfo.DateSep,Month,NLSInfo.DateSep,Year); break;
case DateFormatYMT:
sprintf(Dest,"%d%s%d%s%d",Year,NLSInfo.DateSep,Month,NLSInfo.DateSep,Day); break;
END
END
void NLS_CurrDateString(char *Dest)
BEGIN
time_t timep;
struct tm *trec;
time(&timep); trec=localtime(&timep);
NLS_DateString(trec->tm_year+1900,trec->tm_mon+1,trec->tm_mday,Dest);
END
void NLS_TimeString(Word Hour, Word Minute, Word Second, Word Sec100, char *Dest)
BEGIN
Word OriHour;
String ext;
OriHour=Hour;
if (NLSInfo.TimeFmt==TimeFormatUSA)
BEGIN
Hour%=12; if (Hour==0) Hour=12;
END
sprintf(Dest,"%d%s%02d%s%02d",Hour,NLSInfo.TimeSep,Minute,NLSInfo.TimeSep,Second);
if (Sec100<100)
BEGIN
sprintf(ext,"%s%02d",NLSInfo.DecSep,Sec100); strcat(Dest,ext);
END
if (NLSInfo.TimeFmt==TimeFormatUSA)
strcat(Dest,(OriHour>12)?"p":"a");
END
void NLS_CurrTimeString(Boolean Use100, char *Dest)
BEGIN
time_t timep;
struct tm *trec;
time(&timep); trec=localtime(&timep);
NLS_TimeString(trec->tm_hour,trec->tm_min,trec->tm_sec,Use100?0:100,Dest);
END
void NLS_CurrencyString(double inp, char *erg)
BEGIN
char s[1024],form[1024];
char *p,*z;
/* Schritt 1: mit passender Nachkommastellenzahl wandeln */
sprintf(form,"%%0.%df",NLSInfo.CurrDecimals);
sprintf(s,form,inp);
/* Schritt 2: vorne den Punkt suchen */
p=(NLSInfo.CurrDecimals==0) ? s+strlen(s) : strchr(s,'.');
/* Schritt 3: Tausenderstellen einfuegen */
z=p;
while (z-s>3)
BEGIN
strins(s,NLSInfo.ThouSep,z-s-3); z-=3; p+=strlen(NLSInfo.ThouSep);
END;
/* Schritt 4: Komma anpassen */
strcpy(p,p+1); strins(s,NLSInfo.DecSep,p-s);
/* Schritt 5: Einheit anbauen */
switch (NLSInfo.CurrFmt)
BEGIN
case CurrFormatPreNoBlank:
sprintf(erg,"%s%s",NLSInfo.Currency,s); break;
case CurrFormatPreBlank:
sprintf(erg,"%s %s",NLSInfo.Currency,s); break;
case CurrFormatPostNoBlank:
sprintf(erg,"%s%s",s,NLSInfo.Currency); break;
case CurrFormatPostBlank:
sprintf(erg,"%s%s",s,NLSInfo.Currency); break;
default:
strcpy(p,p+strlen(NLSInfo.DecSep)); strins(NLSInfo.Currency,s,p-s);
END
END
char Upcase(char inp)
BEGIN
return UpCaseTable[((unsigned int) inp)&0xff];
END
void NLS_UpString(char *s)
BEGIN
char *z;
for (z=s; *z!='\0'; z++) *z=UpCaseTable[((unsigned int)*z)&0xff];
END
void NLS_LowString(char *s)
BEGIN
char *z;
for (z=s; *z!='\0'; z++) *z=LowCaseTable[((unsigned int)*z)&0xff];
END
int NLS_StrCmp(const char *s1, const char *s2)
BEGIN
while (CollateTable[((unsigned int)*s1)&0xff]==CollateTable[((unsigned int)*s2)&0xff])
BEGIN
if ((NOT *s1) AND (NOT *s2)) return 0;
s1++; s2++;
END
return ((int) CollateTable[((unsigned int)*s1)&0xff]-CollateTable[((unsigned int)*s2)&0xff]);
END
void nls_init(void)
BEGIN
#ifdef LOCALE_NLS
(void) setlocale(LC_TIME,"");
(void) setlocale(LC_MONETARY,"");
#endif
END