/* 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 #include #include #ifdef LOCALE_NLS #include #include #endif #ifdef OS2_NLS #define INCL_DOSNLS #include #endif #ifdef DOS_NLS #include #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