aboutsummaryrefslogtreecommitdiffstats
path: root/nls.c
diff options
context:
space:
mode:
Diffstat (limited to 'nls.c')
-rw-r--r--nls.c644
1 files changed, 644 insertions, 0 deletions
diff --git a/nls.c b/nls.c
new file mode 100644
index 0000000..f377003
--- /dev/null
+++ b/nls.c
@@ -0,0 +1,644 @@
+/* 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