2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: dos/dos32krnl/country.c
5 * PURPOSE: DOS32 Country support
6 * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 * NOTE: Support for default (english) language only.
9 * For other languages, please use COUNTRY.SYS
12 /* INCLUDES *******************************************************************/
22 /* PRIVATE VARIABLES **********************************************************/
24 /* CaseMap routine: should call INT 65h, AL=20h */
25 // ATM, just do nothing.
26 static const BYTE CaseMapRoutine
[] =
33 #define DATATABLE(name, type, len) \
34 typedef struct _##name \
40 DATATABLE(UPPERCASE
, CHAR
, 0xFF-0x80+1);
41 DATATABLE(LOWERCASE
, CHAR
, 0xFF-0x00+1);
42 DATATABLE(FNAMETERM
, BYTE
, 22);
43 DATATABLE(COLLATE
, BYTE
, 0xFF-0x00+1);
44 DATATABLE(DBCSLEAD
, WORD
, 0x00+1);
46 typedef struct _COUNTRY_DATA
48 BYTE CaseMapRoutine
[sizeof(CaseMapRoutine
)];
49 UPPERCASE UpCaseTbl
; // Used also for filename uppercase
51 FNAMETERM FNameTermTbl
;
54 } COUNTRY_DATA
, *PCOUNTRY_DATA
;
58 /* Global data contained in guest memory */
59 static WORD CountryDataSegment
;
60 static PCOUNTRY_DATA CountryData
;
62 WORD YesNoTable
[2] = { MAKEWORD('Y', 0), MAKEWORD('N', 0) };
65 * See: http://www.ctyme.com/intr/rb-3163.htm#Table1754
66 * http://www.ctyme.com/intr/rb-3164.htm
67 * http://www.ctyme.com/intr/rb-3166.htm
70 /* PRIVATE FUNCTIONS **********************************************************/
72 /* PUBLIC FUNCTIONS ***********************************************************/
75 DosGetCountryInfo(IN OUT PWORD CountryId
,
76 OUT PDOS_COUNTRY_INFO CountryInfo
)
81 Return
= GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_IDATE
| LOCALE_RETURN_NUMBER
, // LOCALE_ILDATE | LOCALE_RETURN_NUMBER
84 if (Return
== 0) return LOWORD(GetLastError());
85 CountryInfo
->DateTimeFormat
= (WORD
)NumVal
;
87 Return
= GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_SCURRENCY
,
88 (LPSTR
)&CountryInfo
->CurrencySymbol
,
89 sizeof(CountryInfo
->CurrencySymbol
));
90 if (Return
== 0) return LOWORD(GetLastError());
92 Return
= GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_STHOUSAND
,
93 (LPSTR
)&CountryInfo
->ThousandSep
,
94 sizeof(CountryInfo
->ThousandSep
));
95 if (Return
== 0) return LOWORD(GetLastError());
97 Return
= GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_SDECIMAL
,
98 (LPSTR
)&CountryInfo
->DecimalSep
,
99 sizeof(CountryInfo
->DecimalSep
));
100 if (Return
== 0) return LOWORD(GetLastError());
102 Return
= GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_SDATE
,
103 (LPSTR
)&CountryInfo
->DateSep
,
104 sizeof(CountryInfo
->DateSep
));
105 if (Return
== 0) return LOWORD(GetLastError());
107 Return
= GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_STIME
,
108 (LPSTR
)&CountryInfo
->TimeSep
,
109 sizeof(CountryInfo
->TimeSep
));
110 if (Return
== 0) return LOWORD(GetLastError());
112 // NOTE: '4: Symbol replace decimal separator' is unsupported.
113 Return
= GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_ICURRENCY
| LOCALE_RETURN_NUMBER
,
116 if (Return
== 0) return LOWORD(GetLastError());
117 CountryInfo
->CurrencyFormat
= (BYTE
)NumVal
;
119 Return
= GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_ICURRDIGITS
| LOCALE_RETURN_NUMBER
, // LOCALE_IDIGITS | LOCALE_RETURN_NUMBER
122 if (Return
== 0) return LOWORD(GetLastError());
123 CountryInfo
->CurrencyDigitsNum
= (BYTE
)NumVal
;
125 Return
= GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_ITIME
| LOCALE_RETURN_NUMBER
,
128 if (Return
== 0) return LOWORD(GetLastError());
129 CountryInfo
->TimeFormat
= (BYTE
)NumVal
;
131 CountryInfo
->CaseMapPtr
= MAKELONG(FIELD_OFFSET(COUNTRY_DATA
, CaseMapRoutine
), CountryDataSegment
);
133 // CountryInfo->DataListSep;
135 return ERROR_SUCCESS
;
139 DosGetCountryInfoEx(IN BYTE InfoId
,
142 OUT PDOS_COUNTRY_INFO_2 CountryInfo
,
143 IN OUT PWORD BufferSize
)
145 // FIXME: use: CodePage; CountryId
146 // FIXME: Check BufferSize
147 // FIXME: Use NLSFUNC resident?
151 /* Get General Internationalization Info (similar to AX=3800h) */
155 ErrorCode
= DosGetCountryInfo(&CountryId
,
156 &CountryInfo
->CountryInfoEx
.CountryInfo
);
157 if (ErrorCode
!= ERROR_SUCCESS
) return ErrorCode
;
158 CountryInfo
->CountryInfoEx
.Size
= sizeof(CountryInfo
->CountryInfoEx
);
159 CountryInfo
->CountryInfoEx
.CountryId
= CountryId
;
160 // CountryInfo->CodePage;
164 /* Get Pointer to Uppercase Table */
166 CountryInfo
->UpCaseTblPtr
= MAKELONG(FIELD_OFFSET(COUNTRY_DATA
, UpCaseTbl
), CountryDataSegment
);
169 /* Get Pointer to Lowercase Table */
171 CountryInfo
->LoCaseTblPtr
= MAKELONG(FIELD_OFFSET(COUNTRY_DATA
, LoCaseTbl
), CountryDataSegment
);
174 /* Get Pointer to Filename Uppercase Table */
176 CountryInfo
->FNameUpCaseTblPtr
= MAKELONG(FIELD_OFFSET(COUNTRY_DATA
, UpCaseTbl
), CountryDataSegment
);
179 /* Get Pointer to Filename Terminator Table */
181 CountryInfo
->FNameTermTblPtr
= MAKELONG(FIELD_OFFSET(COUNTRY_DATA
, FNameTermTbl
), CountryDataSegment
);
184 /* Get Pointer to Collating Sequence Table */
186 CountryInfo
->CollateTblPtr
= MAKELONG(FIELD_OFFSET(COUNTRY_DATA
, CollateTbl
), CountryDataSegment
);
189 /* Get Pointer to Double-Byte Character Set Table */
191 CountryInfo
->DBCSLeadTblPtr
= MAKELONG(FIELD_OFFSET(COUNTRY_DATA
, DBCSLeadTbl
), CountryDataSegment
);
195 return ERROR_CALL_NOT_IMPLEMENTED
;
197 CountryInfo
->InfoId
= InfoId
;
199 return ERROR_SUCCESS
;
202 WORD
DosIfCharYesNo(WORD Char
)
204 Char
= toupper(Char
);
207 if (Char
== YesNoTable
[1])
210 if (Char
== YesNoTable
[0])
216 CHAR
DosToUpper(CHAR Char
)
218 // FIXME: Use the current locale
219 return toupper(Char
);
222 VOID
DosToUpperStrN(PCHAR DestStr
, PCHAR SrcStr
, WORD Length
)
225 *DestStr
++ = toupper(*SrcStr
++);
228 VOID
DosToUpperStrZ(PSTR DestStr
, PSTR SrcStr
)
231 *DestStr
++ = toupper(*SrcStr
++);
234 BOOLEAN
DosCountryInitialize(VOID
)
238 /* Initialize some memory to store country information */
239 // FIXME: Can we use instead some static area from the DOS data structure??
240 CountryDataSegment
= DosAllocateMemory(sizeof(COUNTRY_DATA
), NULL
);
241 if (CountryDataSegment
== 0) return FALSE
;
242 CountryData
= (PCOUNTRY_DATA
)SEG_OFF_TO_PTR(CountryDataSegment
, 0x0000);
244 RtlMoveMemory(CountryData
->CaseMapRoutine
,
246 sizeof(CaseMapRoutine
));
248 CountryData
->UpCaseTbl
.Size
= ARRAYSIZE(CountryData
->UpCaseTbl
.Data
);
249 for (i
= 0; i
< CountryData
->UpCaseTbl
.Size
; ++i
)
250 CountryData
->UpCaseTbl
.Data
[i
] = 0x80 + i
;
252 CountryData
->LoCaseTbl
.Size
= ARRAYSIZE(CountryData
->LoCaseTbl
.Data
);
253 for (i
= 0; i
< CountryData
->LoCaseTbl
.Size
; ++i
)
254 CountryData
->LoCaseTbl
.Data
[i
] = i
;
256 CountryData
->FNameTermTbl
.Size
= ARRAYSIZE(CountryData
->FNameTermTbl
.Data
);
257 CountryData
->FNameTermTbl
.Data
[ 0] = 0x01; // Dummy Byte
258 CountryData
->FNameTermTbl
.Data
[ 1] = 0x00; // Lowest permissible Character Value for Filename
259 CountryData
->FNameTermTbl
.Data
[ 2] = 0xFF; // Highest permissible Character Value for Filename
260 CountryData
->FNameTermTbl
.Data
[ 3] = 0x00; // Dummy Byte
261 CountryData
->FNameTermTbl
.Data
[ 4] = 0x00; // First excluded Character in Range \ all characters in this
262 CountryData
->FNameTermTbl
.Data
[ 5] = 0x20; // Last excluded Character in Range / range are illegal
263 CountryData
->FNameTermTbl
.Data
[ 6] = 0x02; // Dummy Byte
264 CountryData
->FNameTermTbl
.Data
[ 7] = 14; // Number of illegal (terminator) Characters
265 // CountryData->FNameTermTbl.Data[ 8] = ".\"/\\[]:|<>+=;,"; // Characters which terminate a Filename
266 CountryData
->FNameTermTbl
.Data
[ 8] = '.';
267 CountryData
->FNameTermTbl
.Data
[ 9] = '\"';
268 CountryData
->FNameTermTbl
.Data
[10] = '/';
269 CountryData
->FNameTermTbl
.Data
[11] = '\\';
270 CountryData
->FNameTermTbl
.Data
[12] = '[';
271 CountryData
->FNameTermTbl
.Data
[13] = ']';
272 CountryData
->FNameTermTbl
.Data
[14] = ':';
273 CountryData
->FNameTermTbl
.Data
[15] = '|';
274 CountryData
->FNameTermTbl
.Data
[16] = '<';
275 CountryData
->FNameTermTbl
.Data
[17] = '>';
276 CountryData
->FNameTermTbl
.Data
[18] = '+';
277 CountryData
->FNameTermTbl
.Data
[19] = '=';
278 CountryData
->FNameTermTbl
.Data
[20] = ';';
279 CountryData
->FNameTermTbl
.Data
[21] = ',';
281 CountryData
->CollateTbl
.Size
= ARRAYSIZE(CountryData
->CollateTbl
.Data
);
282 for (i
= 0; i
< CountryData
->LoCaseTbl
.Size
; ++i
)
283 CountryData
->LoCaseTbl
.Data
[i
] = i
;
285 CountryData
->DBCSLeadTbl
.Size
= 0; // Empty DBCS table
286 CountryData
->DBCSLeadTbl
.Data
[0] = 0x0000;