Subversion Repositories pentevo

Rev

Blame | Last modification | View Log | Download | RSS feed | ?url?

  1. /* nls.c */
  2. /*****************************************************************************/
  3. /* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
  4. /*                                                                           */
  5. /* AS-Portierung                                                             */
  6. /*                                                                           */
  7. /* Abhandlung landesspezifischer Unterschiede                                */
  8. /*                                                                           */
  9. /*****************************************************************************/
  10.  
  11. #undef DEBUG_NLS
  12.  
  13. #include "stdinc.h"
  14. #include <string.h>
  15. #include <time.h>
  16. #include <ctype.h>
  17.  
  18. #include "strutil.h"
  19.  
  20. #include "nls.h"
  21.  
  22. /*-------------------------------------------------------------------------------*/
  23.  
  24. typedef struct
  25. {
  26.   Word Country;        /* = internationale Vorwahl */
  27.   tCodepage Codepage; /* mom. gewaehlter Zeichensatz */
  28.   void (*DateString)(Word Year, Word Month, Word Day, char *Dest, size_t DestSize);
  29.   void (*TimeString)(Word Hour, Word Minute, Word Second, Word Sec100, char *Dest, size_t DestSize);
  30. #if (defined OS2_NLS) || (defined DOS_NLS)
  31.   DateFormat DateFmt;  /* Datumsreihenfolge */
  32.   const char *DateSep; /* Trennzeichen zwischen Datumskomponenten */
  33.   TimeFormat TimeFmt;  /* 12/24-Stundenanzeige */
  34.   const char *TimeSep; /* Trennzeichen zwischen Zeitkomponenten */
  35. #elif defined LOCALE_NLS
  36.   const char *DateFmtStr;
  37.   const char *TimeFmtStr;
  38. #endif
  39.   const char *Currency;      /* Waehrungsname */
  40.   CurrFormat CurrFmt;  /* Anzeigeformat Waehrung */
  41.   Byte CurrDecimals;   /* Nachkommastellen Waehrungsbetraege */
  42.   const char *ThouSep; /* Trennzeichen fuer Tausenderbloecke */
  43.   const char *DecSep;  /* Trennzeichen fuer Nachkommastellen */
  44.   const char *DataSep; /* ??? */
  45.   Boolean Initialized;
  46. } NLS_CountryInfo;
  47.  
  48. /*-------------------------------------------------------------------------------*/
  49.  
  50. CharTable UpCaseTable;               /* Umsetzungstabellen */
  51. CharTable LowCaseTable;
  52.  
  53. static NLS_CountryInfo NLSInfo;
  54. static CharTable CollateTable;
  55. static tCodepage OverrideCodepage = eCodepageCnt;
  56.  
  57. static const char *CodepageNames[eCodepageCnt] =
  58. {
  59.   "ascii",
  60.   "iso8859-1",
  61.   "iso8859-15",
  62.   "koi8-r",
  63.   "437",
  64.   "850",
  65.   "866",
  66.   "1251",
  67.   "1252",
  68.   "utf-8",
  69. };
  70.  
  71. /*-------------------------------------------------------------------------------*/
  72.  
  73. static void DumpNLSInfo(void)
  74. {
  75. #ifdef DEBUG_NLS
  76.   unsigned z, z2;
  77.  
  78.   printf("Country      = %d\n", NLSInfo.Country);
  79.   printf("Codepage     = %s\n", CodepageNames[NLSInfo.Codepage]);
  80. #if (defined OS2_NLS) || (defined DOS_NLS)
  81.   printf("DateFmt      = ");
  82.   switch(NLSInfo.DateFmt)
  83.   {
  84.     case DateFormatMTY:
  85.       printf("MTY\n");
  86.       break;
  87.     case DateFormatTMY:
  88.       printf("TMY\n");
  89.       break;
  90.     case DateFormatYMT:
  91.       printf("YMT\n");
  92.       break;
  93.     default:
  94.       printf("???\n");
  95.   }
  96.   printf("DateSep      = %s\n", NLSInfo.DateSep);
  97.   printf("TimeFmt      = ");
  98.   switch(NLSInfo.TimeFmt)
  99.   {
  100.     case TimeFormatUSA:
  101.       printf("USA\n");
  102.       break;
  103.     case TimeFormatEurope:
  104.       printf("Europe\n");
  105.       break;
  106.     case TimeFormatJapan:
  107.       printf("Japan\n");
  108.       break;
  109.     default:
  110.       printf("???\n");
  111.   }
  112.   printf("TimeSep      = %s\n", NLSInfo.TimeSep);
  113. #elif defined LOCALE_NLS
  114.   printf("DateFmtStr   = %s\n", NLSInfo.DateFmtStr);
  115.   printf("TimeFmtStr   = %s\n", NLSInfo.TimeFmtStr);
  116. #endif
  117.   printf("Currency     = %s\n", NLSInfo.Currency);
  118.   printf("CurrFmt      = ");
  119.   switch (NLSInfo.CurrFmt)
  120.   {
  121.     case CurrFormatPreNoBlank:
  122.       printf("PreNoBlank\n");
  123.       break;
  124.     case CurrFormatPostNoBlank:
  125.       printf("PostNoBlank\n");
  126.       break;
  127.     case CurrFormatPreBlank:
  128.       printf("PreBlank\n");
  129.       break;
  130.     case CurrFormatPostBlank:
  131.       printf("PostBlank\n");
  132.       break;
  133.     default:
  134.       printf("???\n");
  135.   }
  136.   printf("CurrDecimals = %d\n", NLSInfo.CurrDecimals);
  137.   printf("ThouSep      = %s\n", NLSInfo.ThouSep);
  138.   printf("DecSep       = %s\n", NLSInfo.DecSep);
  139.   printf("DataSep      = %s\n", NLSInfo.DataSep);
  140.  
  141.   printf("\nUpcaseTable:\n");
  142.   for (z = 0; z < 256; z++)
  143.   {
  144.     z2 = (unsigned char)UpCaseTable[z];
  145.     if (z2 != z)
  146.       printf("0x%02x -> %02x\n", z, z2);
  147.   }
  148.  
  149.   printf("\nLowcaseTable:\n");
  150.   for (z = 0; z < 256; z++)
  151.   {
  152.     z2 = (unsigned char)LowCaseTable[z];
  153.     if (z2 != z)
  154.       printf("0x%02x -> %02x\n", z, z2);
  155.   }
  156.  
  157.   printf("\nCollateTable:\n");
  158.   for (z = 0; z < 4; z++)
  159.   {
  160.     for (z2 = 0; z2 < 63; z2++)
  161.       if (z * 64 + z2 > 32)
  162.         putchar(z * 64 + z2);
  163.     putchar ('\n');
  164.     for (z2 = 0; z2 < 63; z2++)
  165.       if (z * 64 + z2 > 32)
  166.         putchar(CollateTable[z * 64 + z2]);
  167.     putchar ('\n');
  168.     putchar('\n');
  169.   }
  170. #endif /* DEBUG_NLS */
  171. }
  172.  
  173. /*-------------------------------------------------------------------------------*/
  174.  
  175. static void SetLoUp(Byte Lo, Byte Up)
  176. {
  177.   UpCaseTable[Lo] = Up;
  178.   LowCaseTable[Up] = Lo;
  179. }
  180.  
  181. void UpCaseFromCodeTable(void)
  182. {
  183.   int z;
  184.  
  185.   for (z = 0; z < 128; z++)
  186.   {
  187.     UpCaseTable[z] = toupper(z);
  188.     LowCaseTable[z] = tolower(z);
  189.   }
  190.   for (; z < 256; z++)
  191.   {
  192.     UpCaseTable[z] = z;
  193.     LowCaseTable[z] = z;
  194.   }
  195.  
  196.   switch (NLSInfo.Codepage)
  197.   {
  198.     case eCodepage866:
  199.       for (z = 0x80; z <= 0x8f; z++)
  200.         SetLoUp(z + 0x20, z);
  201.       for (z = 0x90; z <= 0x9f; z++)
  202.         SetLoUp(z + 0x50, z);
  203.       for (z = 0xf0; z <= 0xf6; z += 2)
  204.         SetLoUp(z + 1, z);
  205.       break;
  206.     case eCodepage850:
  207.       SetLoUp(0xa0, 0xb5); /* &aacute; */
  208.       SetLoUp(0xa1, 0xd6); /* &iacute; */
  209.       SetLoUp(0xa2, 0xe0); /* &oacute; */
  210.       SetLoUp(0xa3, 0xe9); /* &uacute; */
  211.       SetLoUp(0x85, 0xb7); /* &agrave; */
  212.       SetLoUp(0x8a, 0xd4); /* &egrave; */
  213.       SetLoUp(0x8d, 0xde); /* &igrave; */
  214.       SetLoUp(0x95, 0xe3); /* &ograve; */
  215.       SetLoUp(0x97, 0xeb); /* &ugrave; */
  216.       SetLoUp(0x83, 0xb6); /* &acirc; */
  217.       SetLoUp(0x88, 0xd2); /* &ecirc; */
  218.       SetLoUp(0x8c, 0xd6); /* &icirc; */
  219.       SetLoUp(0x93, 0xe2); /* &ocirc; */
  220.       SetLoUp(0x96, 0xea); /* &ucirc; */
  221.       SetLoUp(0xec, 0xed); /* &yacute; */
  222.       SetLoUp(0x9b, 0x9d); /* &oslash; */
  223.       SetLoUp(0xe8, 0xe7); /* &thorn; */
  224.       /* fall-through */
  225.     case eCodepage437:
  226.       SetLoUp(0x80, 0x87); /* &ccedil; */
  227.       SetLoUp(0x84, 0x8e); /* &auml; */
  228.       SetLoUp(0x94, 0x99); /* &ouml; */
  229.       SetLoUp(0x81, 0x9a); /* &uuml; */
  230.       SetLoUp(0x82, 0x90); /* &eacute; */
  231.       SetLoUp(0xa4, 0xa5); /* &ntilde; */
  232.       SetLoUp(0x86, 0x8f); /* &aring; */
  233.       SetLoUp(0x91, 0x92); /* &aelig; */
  234.       break;
  235.     case eCodepage1251:
  236.       SetLoUp(0x90, 0x80);
  237.       SetLoUp(0x9a, 0x8a);
  238.       SetLoUp(0x9c, 0x8c);
  239.       SetLoUp(0x9d, 0x8d);
  240.       SetLoUp(0x9e, 0x8e);
  241.       SetLoUp(0x9f, 0x8f);
  242.       SetLoUp(0xa2, 0xa1);
  243.       SetLoUp(0xb3, 0xb2);
  244.       SetLoUp(0xb4, 0xa5);
  245.       SetLoUp(0xb8, 0xa8);
  246.       SetLoUp(0xba, 0xaa);
  247.       SetLoUp(0xbe, 0xbd);
  248.       SetLoUp(0xbf, 0xaf);
  249.       for (z = 0xc0; z <= 0xdf; z++)
  250.         SetLoUp(z + 0x20, z);
  251.       break;
  252.     case eCodepage1252:
  253.       SetLoUp(0x9a, 0x8a); /* &scaron */
  254.       SetLoUp(0x9e, 0x8e); /* &zcaron; */
  255.       SetLoUp(0x9c, 0x8c); /* &oelog; */
  256.       goto iso8859_1;
  257.     case eCodepageISO8859_15:
  258.       SetLoUp(0xa8, 0xa6); /* &scaron */
  259.       SetLoUp(0xb8, 0xb4); /* &zcaron; */
  260.       SetLoUp(0xbd, 0xbc); /* &oelog; */
  261.       /* fall-through */
  262.     case eCodepageISO8859_1:
  263.     case eCodepageUTF8:
  264.       iso8859_1:
  265.       SetLoUp(0xe0, 0xc0); /* &agrave; */
  266.       SetLoUp(0xe1, 0xc1); /* &aacute; */
  267.       SetLoUp(0xe2, 0xc2); /* &acirc; */
  268.       SetLoUp(0xe3, 0xc3); /* &atilde; */
  269.       SetLoUp(0xe4, 0xc4); /* &auml; */
  270.       SetLoUp(0xe5, 0xc5); /* &aring; */
  271.       SetLoUp(0xe6, 0xc6); /* &aelig; */
  272.       SetLoUp(0xe7, 0xc7); /* &ccedil; */
  273.       SetLoUp(0xe8, 0xc8); /* &egrave; */
  274.       SetLoUp(0xe9, 0xc9); /* &eacute; */
  275.       SetLoUp(0xea, 0xca); /* &ecirc; */
  276.       SetLoUp(0xeb, 0xcb); /* &euml; */
  277.       SetLoUp(0xec, 0xcc); /* &igrave; */
  278.       SetLoUp(0xed, 0xcd); /* &iacute; */
  279.       SetLoUp(0xee, 0xce); /* &icirc; */
  280.       SetLoUp(0xef, 0xcf); /* &iuml; */
  281.       SetLoUp(0xf1, 0xd1); /* &ntilde; */
  282.       SetLoUp(0xf2, 0xd2); /* &ograve; */
  283.       SetLoUp(0xf3, 0xd3); /* &oacute; */
  284.       SetLoUp(0xf4, 0xd4); /* &ocirc; */
  285.       SetLoUp(0xf5, 0xd5); /* &otilde; */
  286.       SetLoUp(0xf6, 0xd6); /* &ouml; */
  287.       SetLoUp(0xf8, 0xd8); /* &oslash; */
  288.       SetLoUp(0xf9, 0xd9); /* &ugrave; */
  289.       SetLoUp(0xfa, 0xda); /* &uacute; */
  290.       SetLoUp(0xfb, 0xdb); /* &ucirc; */
  291.       SetLoUp(0xfc, 0xdc); /* &uuml; */
  292.       SetLoUp(0xfd, 0xdd); /* &yacute; */
  293.       SetLoUp(0xfe, 0xde); /* &thorn; */
  294.       break;
  295.     case eCodepageKOI8_R:
  296.       SetLoUp(0xa3, 0xb3);
  297.       for (z = 0xc0; z <= 0xdf; z++)
  298.         SetLoUp(z, z + 0x20);
  299.     default:
  300.       break;
  301.   }
  302. }
  303.  
  304. #if (defined OS2_NLS) || (defined DOS_NLS)
  305.  
  306. static void DOS_OS2_DateString(Word Year, Word Month, Word Day, char *Dest, size_t DestSize)
  307. {
  308.   switch (NLSInfo.DateFmt)
  309.   {
  310.     case DateFormatMTY:
  311.       as_snprintf(Dest, DestSize, "%d%s%d%s%d", Month, NLSInfo.DateSep, Day, NLSInfo.DateSep, Year);
  312.       break;
  313.     case DateFormatTMY:
  314.       as_snprintf(Dest, DestSize, "%d%s%d%s%d", Day, NLSInfo.DateSep, Month, NLSInfo.DateSep, Year);
  315.       break;
  316.     case DateFormatYMT:
  317.       as_snprintf(Dest, DestSize, "%d%s%d%s%d", Year, NLSInfo.DateSep, Month, NLSInfo.DateSep, Day);
  318.       break;
  319.   }
  320. }
  321.  
  322. static void DOS_OS2_TimeString(Word Hour, Word Minute, Word Second, Word Sec100, char *Dest, size_t DestSize)
  323. {
  324.   Word OriHour;
  325.  
  326.   OriHour = Hour;
  327.   if (NLSInfo.TimeFmt == TimeFormatUSA)
  328.   {
  329.     Hour %= 12;
  330.     if (Hour == 0)
  331.       Hour = 12;
  332.   }
  333.   as_snprintf(Dest, DestSize, "%d%s%02d%s%02d", Hour, NLSInfo.TimeSep, Minute, NLSInfo.TimeSep, Second);
  334.   if (Sec100 < 100)
  335.     as_snprcatf(Dest, DestSize, "%s%02d", NLSInfo.DecSep, Sec100);
  336.   if (NLSInfo.TimeFmt == TimeFormatUSA)
  337.     as_snprcatf(Dest, DestSize, "%c", (OriHour > 12) ? 'p' : 'a');
  338. }
  339. #endif /* OS2_NLS || DOS_NLS */
  340.  
  341. /*-------------------------------------------------------------------------------*/
  342.  
  343. #if defined OS2_NLS
  344.  
  345. #define INCL_DOSNLS
  346. #include <os2.h>
  347.  
  348. static void QueryInfo(void)
  349. {
  350.   COUNTRYCODE ccode;
  351.   COUNTRYINFO cinfo;
  352.   ULONG erglen;
  353.   int z;
  354.  
  355.   ccode.country = 0;
  356.   ccode.codepage = 0;
  357.   DosQueryCtryInfo(sizeof(cinfo), &ccode, &cinfo, &erglen);
  358.  
  359.   NLSInfo.Country = cinfo.country;
  360.   switch (cinfo.codepage)
  361.   {
  362.     case 437: NLSInfo.Codepage = eCodepage437; break;
  363.     case 850: NLSInfo.Codepage = eCodepage850; break;
  364.     case 866: NLSInfo.Codepage = eCodepage866; break;
  365.     case 1251: NLSInfo.Codepage = eCodepage1251; break;
  366.     case 1252: NLSInfo.Codepage = eCodepage1252; break;
  367.     case 20866: NLSInfo.Codepage = eCodepageKOI8_R; break;
  368.     case 28591: NLSInfo.Codepage = eCodepageISO8859_1; break;
  369.     case 28605: NLSInfo.Codepage = eCodepageISO8859_15; break;
  370.     default: NLSInfo.Codepage = eCodepageASCII;
  371.   }
  372.   NLSInfo.DecSep = as_strdup(cinfo.szDecimal);
  373.   NLSInfo.DataSep = as_strdup(cinfo.szDataSeparator);
  374.   NLSInfo.ThouSep = as_strdup(cinfo.szThousandsSeparator);
  375.   NLSInfo.Currency = as_strdup(cinfo.szCurrency);
  376.   NLSInfo.CurrDecimals = cinfo.cDecimalPlace;
  377.   NLSInfo.CurrFmt = (CurrFormat) cinfo.fsCurrencyFmt;
  378.   NLSInfo.DateFmt = (DateFormat) cinfo.fsDateFmt;
  379.   NLSInfo.DateSep = as_strdup(cinfo.szDateSeparator);
  380.   NLSInfo.DateString = DOS_OS2_DateString;
  381.   NLSInfo.TimeFmt = (TimeFormat) cinfo.fsTimeFmt;
  382.   NLSInfo.TimeSep = as_strdup(cinfo.szTimeSeparator);
  383.   NLSInfo.TimeString = DOS_OS2_TimeString;
  384.   for (z = 0; z < 256; z++)
  385.     UpCaseTable[z] = (char) z;
  386.   for (z = 'a'; z <= 'z'; z++)
  387.     UpCaseTable[z] -= 'a' - 'A';
  388.   DosMapCase(sizeof(UpCaseTable), &ccode, UpCaseTable);
  389.   for (z = 0; z < 256; z++)
  390.     LowCaseTable[z] = (char) z;
  391.   for (z = 255; z >= 0; z--)
  392.     if (UpCaseTable[z] != (char) z)
  393.       LowCaseTable[((unsigned int) UpCaseTable[z])&0xff] = (char) z;
  394.   for (z = 0; z < 256; z++)
  395.     CollateTable[z] = (char) z;
  396.   DosQueryCollate(sizeof(CollateTable), &ccode, CollateTable, &erglen);
  397. }
  398.  
  399. #elif defined W32_NLS
  400.  
  401. static void Default_DateString(Word Year, Word Month, Word Day, char *Dest, size_t DestSize)
  402. {
  403.   as_snprintf(Dest, DestSize, "%u/%u/%u", Month, Day, Year);
  404. }
  405.  
  406. static void Default_TimeString(Word Hour, Word Minute, Word Second, Word Sec100, char *Dest, size_t DestSize)
  407. {
  408.   (void)Sec100;
  409.   as_snprintf(Dest, DestSize, "%u:%u:%u", Hour, Minute, Second);
  410. }
  411.  
  412. #include <windows.h>
  413. #include <windef.h>
  414. #include <winbase.h>
  415. #include <winnls.h>
  416.  
  417. static void QueryInfo(void)
  418. {
  419.   int z;
  420.  
  421.   NLSInfo.DecSep = ".";
  422.   NLSInfo.DataSep = ",";
  423.   NLSInfo.ThouSep = ",";
  424.   NLSInfo.Currency = "$";
  425.   NLSInfo.CurrDecimals = 2;
  426.   NLSInfo.CurrFmt = CurrFormatPreNoBlank;
  427.   NLSInfo.DateString = Default_DateString;
  428.   NLSInfo.TimeString = Default_TimeString;
  429.  
  430.   switch (GetACP())
  431.   {
  432.     case 437: NLSInfo.Codepage = eCodepage437; break;
  433.     case 850: NLSInfo.Codepage = eCodepage850; break;
  434.     case 866: NLSInfo.Codepage = eCodepage866; break;
  435.     case 1251: NLSInfo.Codepage = eCodepage1251; break;
  436.     case 1252: NLSInfo.Codepage = eCodepage1252; break;
  437.     case 20866: NLSInfo.Codepage = eCodepageKOI8_R; break;
  438.     case 28591: NLSInfo.Codepage = eCodepageISO8859_1; break;
  439.     case 28605: NLSInfo.Codepage = eCodepageISO8859_15; break;
  440.     default: NLSInfo.Codepage = eCodepageASCII;
  441.   }
  442.  
  443.   UpCaseFromCodeTable();
  444.  
  445.   for (z = 0; z < 256; z++)
  446.     CollateTable[z] = z;
  447.   for (z = 'a'; z <= 'z'; z++)
  448.     CollateTable[z] = toupper(z);
  449. }
  450.  
  451. #elif defined DOS_NLS
  452.  
  453. #include <dos.h>
  454.  
  455. typedef struct
  456. {
  457.   Byte SubFuncNo;
  458.   char *Result;
  459. } DosTableRec;
  460.  
  461. char *DosCopy(char *Src, int Len)
  462. {
  463.   char *res = malloc(sizeof(char)*(Len + 1));
  464.   memcpy(res, Src, Len);
  465.   res[Len] = '\0';
  466.   return res;
  467. }
  468.  
  469. static void QueryInfo(void)
  470. {
  471.   union REGS Regs;
  472.   struct SREGS SRegs;
  473.   struct COUNTRY country_info;
  474.   DosTableRec DOSTablePtr;
  475.   int z;
  476.   Word CodePage;
  477.   Boolean GotTable = False;
  478.  
  479.   if (_osmajor < 3)
  480.   {
  481.     fprintf(stderr, "requires DOS 3.x or above\n");
  482.     exit(255);
  483.   }
  484.  
  485.   if (_osminor < 30)
  486.     CodePage = 437;
  487.   else
  488.   {
  489.     Regs.x.ax = 0x6601;
  490.     int86(0x21, &Regs, &Regs);
  491.     CodePage = Regs.x.bx;
  492.   }
  493.   switch (CodePage)
  494.   {
  495.     case 437: NLSInfo.Codepage = eCodepage437; break;
  496.     case 850: NLSInfo.Codepage = eCodepage850; break;
  497.     case 866: NLSInfo.Codepage = eCodepage866; break;
  498.     case 1251: NLSInfo.Codepage = eCodepage1251; break;
  499.     case 1252: NLSInfo.Codepage = eCodepage1252; break;
  500.     case 20866: NLSInfo.Codepage = eCodepageKOI8_R; break;
  501.     case 28591: NLSInfo.Codepage = eCodepageISO8859_1; break;
  502.     case 28605: NLSInfo.Codepage = eCodepageISO8859_15; break;
  503.     default: NLSInfo.Codepage = eCodepageASCII;
  504.   }
  505.  
  506.   country(0x0000, &country_info);
  507.  
  508.   NLSInfo.DecSep = DosCopy(country_info.co_desep, 2);
  509.   NLSInfo.DataSep = DosCopy(country_info.co_dtsep, 2);
  510.   NLSInfo.ThouSep = DosCopy(country_info.co_thsep, 2);
  511.   NLSInfo.Currency = DosCopy(country_info.co_curr, 5);
  512.   NLSInfo.CurrDecimals = country_info.co_digits;
  513.   NLSInfo.CurrFmt = (CurrFormat) country_info.co_currstyle;
  514.  
  515.   NLSInfo.Country = strcmp(NLSInfo.Currency, "DM") ? 1 : 49;
  516.  
  517.   NLSInfo.DateFmt = (DateFormat) country_info.co_date;
  518.   NLSInfo.DateSep = DosCopy(country_info.co_dtsep, 2);
  519.   NLSInfo.DateString = DOS_OS2_DateString;
  520.  
  521.   NLSInfo.TimeFmt = (TimeFormat) country_info.co_time;
  522.   NLSInfo.TimeSep = DosCopy(country_info.co_tmsep, 2);
  523.   NLSInfo.TimeString = DOS_OS2_TimeString;
  524.  
  525. #ifndef __DPMI16__
  526.   for (z = 0; z < 256; z++)
  527.     UpCaseTable[z] = (char) z;
  528.   for (z = 'a'; z <= 'z'; z++)
  529.     UpCaseTable[z] -= 'a' - 'A';
  530.   if ((((Word)_osmajor) * 100) + _osminor >= 330)
  531.   {
  532.     Regs.x.ax = 0x6502;
  533.     Regs.x.bx = CodePage;
  534.     Regs.x.dx = NLSInfo.Country;
  535.     Regs.x.cx = sizeof(DOSTablePtr);
  536.     info = &DOSTablePtr;
  537.     SRegs.es = FP_SEG(info);
  538.     Regs.x.di = FP_OFF(info);
  539.     int86x(0x21, &Regs, &Regs, &SRegs);
  540.     if (Regs.x.cx == sizeof(DOSTablePtr))
  541.     {
  542.       DOSTablePtr.Result += sizeof(Word);
  543.       memcpy(UpCaseTable + 128, DOSTablePtr.Result, 128);
  544.       GotTable = True;
  545.     }
  546.   }
  547. #endif /* __DPMI16__ */
  548.  
  549.   if (GotTable)
  550.   {
  551.     for (z = 0; z < 256; z++)
  552.       LowCaseTable[z] = (char) z;
  553.     for (z = 255; z >= 0; z--)
  554.       if (UpCaseTable[z] != (char) z)
  555.         LowCaseTable[((unsigned int) UpCaseTable[z])&0xff] = (char) z;
  556.   }
  557.   else
  558.     UpCaseFromCodeTable();
  559.  
  560.   for (z = 0; z < 256; z++)
  561.     CollateTable[z] = (char) z;
  562.   for (z = 'a'; z <= 'z'; z++)
  563.     CollateTable[z] = (char) (z - ('a' - 'A'));
  564. #ifndef __DPMI16__
  565.   if ((((Word)_osmajor)*100) + _osminor >= 330)
  566.   {
  567.     Regs.x.ax = 0x6506;
  568.     Regs.x.bx = CodePage;
  569.     Regs.x.dx = NLSInfo.Country;
  570.     Regs.x.cx = sizeof(DOSTablePtr);
  571.     info = &DOSTablePtr;
  572.     SRegs.es = FP_SEG(info);
  573.     Regs.x.di = FP_OFF(info);
  574.     int86x(0x21, &Regs, &Regs, &SRegs);
  575.     if (Regs.x.cx == sizeof(DOSTablePtr))
  576.     {
  577.       DOSTablePtr.Result += sizeof(Word);
  578.       memcpy(CollateTable, DOSTablePtr.Result, 256);
  579.     }
  580.   }
  581. #endif /* __DPMI16__ */
  582. }
  583.  
  584. #elif defined LOCALE_NLS
  585.  
  586. #include <locale.h>
  587. #include <langinfo.h>
  588.  
  589. static void Locale_DateString(Word Year, Word Month, Word Day, char *Dest, size_t DestSize)
  590. {
  591.   struct tm tm;
  592.  
  593.   tm.tm_year = Year - 1900;
  594.   tm.tm_mon = Month - 1;
  595.   tm.tm_mday = Day;
  596.   tm.tm_hour = 0;
  597.   tm.tm_min = 0;
  598.   tm.tm_sec = 0;
  599.   strftime(Dest, DestSize, NLSInfo.DateFmtStr, &tm);
  600. }
  601.  
  602. static void Locale_TimeString(Word Hour, Word Minute, Word Second, Word Sec100, char *Dest, size_t DestSize)
  603. {
  604.   struct tm tm;
  605.  
  606.   (void)Sec100;
  607.   tm.tm_year = 0;
  608.   tm.tm_mon = 0;
  609.   tm.tm_mday = 1;
  610.   tm.tm_hour = Hour;
  611.   tm.tm_min = Minute;
  612.   tm.tm_sec = Second;
  613.   strftime(Dest, DestSize, NLSInfo.TimeFmtStr, &tm);
  614. }
  615.  
  616. static void QueryInfo(void)
  617. {
  618.   struct lconv *lc;
  619.   int z;
  620.   const char *pCodepage;
  621.  
  622.   lc = localeconv();
  623.  
  624.   NLSInfo.DecSep = lc->mon_decimal_point ? lc->decimal_point : ".";
  625.  
  626.   NLSInfo.ThouSep = lc->mon_thousands_sep ? lc->mon_thousands_sep : ",";
  627.  
  628.   NLSInfo.DataSep = ",";
  629.  
  630.   NLSInfo.Currency = lc->currency_symbol ? lc->currency_symbol : "$";
  631.  
  632.   NLSInfo.CurrDecimals = lc->int_frac_digits;
  633.   if (NLSInfo.CurrDecimals > 4)
  634.     NLSInfo.CurrDecimals = 2;
  635.  
  636.   if (lc->p_cs_precedes)
  637.     NLSInfo.CurrFmt = lc->p_sep_by_space ? CurrFormatPreBlank : CurrFormatPreNoBlank;
  638.   else
  639.     NLSInfo.CurrFmt = lc->p_sep_by_space ? CurrFormatPostBlank : CurrFormatPostNoBlank;
  640.  
  641.   NLSInfo.DateFmtStr = nl_langinfo(D_FMT);
  642.   if (!NLSInfo.DateFmtStr || !*NLSInfo.DateFmtStr)
  643.     NLSInfo.DateFmtStr = "%m/%d/%y";
  644.   NLSInfo.DateString = Locale_DateString;
  645.  
  646.   NLSInfo.TimeFmtStr = nl_langinfo(T_FMT);
  647.   if (!NLSInfo.TimeFmtStr || !*NLSInfo.TimeFmtStr)
  648.     NLSInfo.TimeFmtStr = "%H:%M:%S";
  649.   NLSInfo.TimeString = Locale_TimeString;
  650.  
  651.   NLSInfo.Codepage = eCodepageASCII;
  652.   pCodepage = getenv("LC_CTYPE");
  653.   if (!pCodepage)
  654.     pCodepage = getenv("LC_ALL");
  655.   if (!pCodepage)
  656.     pCodepage = getenv("LANG");
  657.   if (pCodepage)
  658.   {
  659.     pCodepage = strchr(pCodepage, '.');
  660.     if (pCodepage)
  661.     {
  662.       pCodepage++;
  663.       if (!as_strcasecmp(pCodepage, "ISO-8859-1"))
  664.         NLSInfo.Codepage = eCodepageISO8859_1;
  665.       else if (!as_strcasecmp(pCodepage, "ISO-8859-15"))
  666.         NLSInfo.Codepage = eCodepageISO8859_15;
  667.       else if (!as_strcasecmp(pCodepage, "UTF-8") || !as_strcasecmp(pCodepage, "UTF8"))
  668.         NLSInfo.Codepage = eCodepageUTF8;
  669.       else if (!as_strcasecmp(pCodepage, "KOI8-R"))
  670.         NLSInfo.Codepage = eCodepageKOI8_R;
  671.     }
  672.   }
  673.  
  674.   UpCaseFromCodeTable();
  675.  
  676.   for (z = 0; z < 256; z++)
  677.     CollateTable[z] = z;
  678.   for (z = 'a'; z <= 'z'; z++)
  679.     CollateTable[z] = toupper(z);
  680. }
  681.  
  682. #else /* NO_NLS */
  683.  
  684. static void Default_DateString(Word Year, Word Month, Word Day, char *Dest, size_t DestSize)
  685. {
  686.   as_snprintf(Dest, DestSize, "%u/%u/%u", Month, Day, Year);
  687. }
  688.  
  689. static void Default_TimeString(Word Hour, Word Minute, Word Second, Word Sec100, char *Dest, size_t DestSize)
  690. {
  691.   (void)Sec100;
  692.   as_snprintf(Dest, DestSize, "%u:%u:%u", Hour, Minute, Second);
  693. }
  694.  
  695. static void QueryInfo(void)
  696. {
  697.   int z;
  698.  
  699.   NLSInfo.Codepage = eCodepageASCII;
  700.   NLSInfo.DecSep = ".";
  701.   NLSInfo.DataSep = ",";
  702.   NLSInfo.ThouSep = ",";
  703.   NLSInfo.Currency = "$";
  704.   NLSInfo.CurrDecimals = 2;
  705.   NLSInfo.CurrFmt = CurrFormatPreNoBlank;
  706.   NLSInfo.DateString = Default_DateString;
  707.   NLSInfo.TimeString = Default_TimeString;
  708.  
  709.   UpCaseFromCodeTable();
  710.  
  711.   for (z = 0; z < 256; z++)
  712.     CollateTable[z] = z;
  713.   for (z = 'a'; z <= 'z'; z++)
  714.     CollateTable[z] = toupper(z);
  715. }
  716.  
  717. #endif /* xxx_NLS */
  718.  
  719. /*-------------------------------------------------------------------------------*/
  720. /* Da es moeglich ist, die aktuelle Codeseite im Programmlauf zu wechseln,
  721.    ist die Initialisierung in einer getrennten Routine untergebracht.  Nach
  722.    einem Wechsel stellt ein erneuter Aufruf wieder korrekte Verhaeltnisse
  723.    her.  Wen das stoert, der schreibe einfach einen Aufruf in den Initiali-
  724.    sierungsteil der Unit hinein. */
  725.  
  726. Boolean NLS_Initialize(int *argc, char **argv)
  727. {
  728.   QueryInfo();
  729.  
  730.   /* query overrides */
  731.  
  732.   if (argc)
  733.   {
  734.     int z, dest;
  735.  
  736.     z = dest = 1;
  737.     while (z < *argc)
  738.       if ((z < *argc - 1) && !as_strcasecmp(argv[z], "-codepage"))
  739.       {
  740.         for (OverrideCodepage = (tCodepage)0; OverrideCodepage < eCodepageCnt; OverrideCodepage++)
  741.           if (!as_strcasecmp(argv[z + 1], CodepageNames[OverrideCodepage]))
  742.             break;
  743.         if (OverrideCodepage >= eCodepageCnt)
  744.         {
  745.           fprintf(stderr, "unknown codepage: %s\n", argv[z + 1]);
  746.           return False;
  747.         }
  748.         z += 2;
  749.       }
  750.       else
  751.         argv[dest++] = argv[z++];
  752.     *argc = dest;
  753.   }
  754.   if (OverrideCodepage < eCodepageCnt)
  755.     NLSInfo.Codepage = OverrideCodepage;
  756.  
  757.   DumpNLSInfo();
  758.  
  759.   NLSInfo.Initialized = True;
  760.   return True;
  761. }
  762.  
  763. void NLS_DateString(Word Year, Word Month, Word Day, char *Dest, size_t DestSize)
  764. {
  765.   if (!NLSInfo.DateString)
  766.   {
  767.     fprintf(stderr, "NLS not yet initialized\n");
  768.     exit(255);
  769.   }
  770.   NLSInfo.DateString(Year, Month, Day, Dest, DestSize);
  771. }
  772.  
  773. void NLS_CurrDateString(char *Dest, size_t DestSize)
  774. {
  775.   time_t timep;
  776.   struct tm *trec;
  777.  
  778.   time(&timep);
  779.   trec = localtime(&timep);
  780.   NLS_DateString(trec->tm_year + 1900, trec->tm_mon + 1, trec->tm_mday, Dest, DestSize);
  781. }
  782.  
  783. void NLS_TimeString(Word Hour, Word Minute, Word Second, Word Sec100, char *Dest, size_t DestSize)
  784. {
  785.   if (!NLSInfo.TimeString)
  786.   {
  787.     fprintf(stderr, "NLS not yet initialized\n");
  788.     exit(255);
  789.   }
  790.   NLSInfo.TimeString(Hour, Minute, Second, Sec100, Dest, DestSize);
  791. }
  792.  
  793. void NLS_CurrTimeString(Boolean Use100, char *Dest, size_t DestSize)
  794. {
  795.   time_t timep;
  796.   struct tm *trec;
  797.  
  798.   time(&timep); trec = localtime(&timep);
  799.   NLS_TimeString(trec->tm_hour, trec->tm_min, trec->tm_sec, Use100 ? 0 : 100, Dest, DestSize);
  800. }
  801.  
  802. void NLS_CurrencyString(double inp, char *erg, size_t DestSize)
  803. {
  804.   char s[1024];
  805.   char *p, *z;
  806.  
  807.   /* Schritt 1: mit passender Nachkommastellenzahl wandeln */
  808.  
  809.   as_snprintf(s, sizeof(s), "%0.*f", (int)NLSInfo.CurrDecimals, inp);
  810.  
  811.   /* Schritt 2: vorne den Punkt suchen */
  812.  
  813.   p = (NLSInfo.CurrDecimals == 0) ? s + strlen(s) : strchr(s, '.');
  814.  
  815.   /* Schritt 3: Tausenderstellen einfuegen */
  816.  
  817.   z = p;
  818.   while (z - s > 3)
  819.   {
  820.     strins(s, NLSInfo.ThouSep, z - s - 3);
  821.     z -= 3;
  822.     p += strlen(NLSInfo.ThouSep);
  823.   };
  824.  
  825.   /* Schritt 4: Komma anpassen */
  826.  
  827.   strmov(p, p + 1);
  828.   strins(s, NLSInfo.DecSep, p - s);
  829.  
  830.   /* Schritt 5: Einheit anbauen */
  831.  
  832.   switch (NLSInfo.CurrFmt)
  833.   {
  834.     case CurrFormatPreNoBlank:
  835.       as_snprintf(erg, DestSize, "%s%s", NLSInfo.Currency, s);
  836.       break;
  837.     case CurrFormatPreBlank:
  838.       as_snprintf(erg, DestSize, "%s %s", NLSInfo.Currency, s);
  839.       break;
  840.     case CurrFormatPostNoBlank:
  841.       as_snprintf(erg, DestSize, "%s%s", s, NLSInfo.Currency);
  842.       break;
  843.     case CurrFormatPostBlank:
  844.       as_snprintf(erg, DestSize, "%s %s", s, NLSInfo.Currency);
  845.       break;
  846.     default:
  847.       *p = '\0';
  848.       as_snprintf(erg, DestSize, "%s%s%s", s, NLSInfo.Currency, p + strlen(NLSInfo.DecSep));
  849.   }
  850. }
  851.  
  852. char Upcase(char inp)
  853. {
  854.   return UpCaseTable[((unsigned int) inp) & 0xff];
  855. }
  856.  
  857. void NLS_UpString(char *pStr)
  858. {
  859.   unsigned Unicode;
  860.   const char *pSrc = pStr;
  861.  
  862.   /* TODO: assure pSrc & pStr remain in-sync for UTF-8 */
  863.  
  864.   while (*pStr)
  865.   {
  866.     if (eCodepageUTF8 == NLSInfo.Codepage)
  867.       Unicode = UTF8ToUnicode(&pSrc);
  868.     else
  869.       Unicode = ((unsigned int)(*pSrc++)) & 0xff;
  870.     Unicode = (Unicode < 256) ? (unsigned int)(UpCaseTable[Unicode] & 0xff) : Unicode;
  871.     if (eCodepageUTF8 == NLSInfo.Codepage)
  872.       UnicodeToUTF8(&pStr, Unicode);
  873.     else
  874.       *pStr++ = Unicode;
  875.   }
  876. }
  877.  
  878. /*!------------------------------------------------------------------------
  879.  * \fn     NLS_UpString2(char *p_dest, size_t dest_size, const char *p_src, size_t src_len)
  880.  * \brief  comvert string to upper case
  881.  * \param  p_dest destination
  882.  * \param  dest_size capacity of destination
  883.  * \param  p_src source
  884.  * \param  src_len length of source (need not be NUL-terminated)
  885.  * ------------------------------------------------------------------------ */
  886.  
  887. void NLS_UpString2(char *p_dest, size_t dest_size, const char *p_src, size_t src_len)
  888. {
  889.   unsigned unicode;
  890.   char *p_dest_end;
  891.   const char *p_src_end;
  892.  
  893.   if (dest_size < 1)
  894.     return;
  895.   p_src_end = p_src + src_len;
  896.   p_dest_end = p_dest + dest_size - 1;
  897.  
  898.   while (p_src < p_src_end)
  899.   {
  900.     if (eCodepageUTF8 == NLSInfo.Codepage)
  901.       unicode = UTF8ToUnicode(&p_src);
  902.     else
  903.       unicode = ((unsigned int)(*p_src++)) & 0xff;
  904.     unicode = (unicode < 256) ? (unsigned int)(UpCaseTable[unicode] & 0xff) : unicode;
  905.     if (eCodepageUTF8 == NLSInfo.Codepage)
  906.     {
  907.       if (p_dest < p_dest_end - 2)
  908.         UnicodeToUTF8(&p_dest, unicode);
  909.     }
  910.     else
  911.     {
  912.       if (p_dest < p_dest_end)
  913.         *p_dest++ = unicode;
  914.     }
  915.   }
  916.   *p_dest = '\0';
  917. }
  918.  
  919. void NLS_LowString(char *pStr)
  920. {
  921.   unsigned Unicode;
  922.   const char *pSrc = pStr;
  923.  
  924.   /* TODO: assure pSrc & pStr remain in-sync for UTF-8 */
  925.  
  926.   while (*pStr)
  927.   {
  928.     if (eCodepageUTF8 == NLSInfo.Codepage)
  929.       Unicode = UTF8ToUnicode(&pSrc);
  930.     else
  931.       Unicode = ((unsigned int)(*pSrc++)) & 0xff;
  932.     Unicode = (Unicode < 256) ? (unsigned int)(LowCaseTable[Unicode] & 0xff) : Unicode;
  933.     if (eCodepageUTF8 == NLSInfo.Codepage)
  934.       UnicodeToUTF8(&pStr, Unicode);
  935.     else
  936.       *pStr++ = Unicode;
  937.   }
  938. }
  939.  
  940. int NLS_StrCmp(const char *s1, const char *s2)
  941. {
  942.   while (CollateTable[((unsigned int)*s1) & 0xff] == CollateTable[((unsigned int)*s2) & 0xff])
  943.   {
  944.     if ((!*s1) && (!*s2))
  945.       return 0;
  946.     s1++;
  947.     s2++;
  948.   }
  949.   return ((int) CollateTable[((unsigned int)*s1) & 0xff] - CollateTable[((unsigned int)*s2) & 0xff]);
  950. }
  951.  
  952. Word NLS_GetCountryCode(void)
  953. {
  954.   if (!NLSInfo.Initialized)
  955.   {
  956.     fprintf(stderr, "NLS_GetCountryCode() called before initialization\n");
  957.     exit(255);
  958.   }
  959.   return NLSInfo.Country;
  960. }
  961.  
  962. tCodepage NLS_GetCodepage(void)
  963. {
  964.   if (!NLSInfo.Initialized)
  965.   {
  966.     fprintf(stderr, "NLS_GetCodepage() called before initialization\n");
  967.     exit(255);
  968.   }
  969.   return NLSInfo.Codepage;
  970. }
  971.  
  972. void nls_init(void)
  973. {
  974. #ifdef LOCALE_NLS
  975.   (void) setlocale(LC_TIME, "");
  976.   (void) setlocale(LC_MONETARY, "");
  977. #endif
  978. }
  979.