source: trunk/src/helpers/nls.c@ 249

Last change on this file since 249 was 249, checked in by umoeller, 23 years ago

Build updates, moved files from warpin.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 26.3 KB
Line 
1
2/*
3 *@@sourcefile nls.c:
4 * contains a few helpers for National Language Support (NLS),
5 * such as printing strings with the format specified by
6 * the "Country" object.
7 *
8 * Usage: All OS/2 programs.
9 *
10 * Function prefixes (new with V0.81):
11 * -- nls* NLS helpers
12 *
13 * This file is new with 0.9.16, but contains functions
14 * formerly in stringh.c.
15 *
16 * Note: Version numbering in this file relates to XWorkplace version
17 * numbering.
18 *
19 *@@header "helpers\nls.h"
20 *@@added V0.9.16 (2001-10-11) [umoeller]
21 */
22
23/*
24 * Copyright (C) 1997-2002 Ulrich M”ller.
25 * This file is part of the "XWorkplace helpers" source package.
26 * This is free software; you can redistribute it and/or modify
27 * it under the terms of the GNU General Public License as published
28 * by the Free Software Foundation, in version 2 as it comes in the
29 * "COPYING" file of the XWorkplace main distribution.
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
34 */
35
36#define OS2EMX_PLAIN_CHAR
37 // this is needed for "os2emx.h"; if this is defined,
38 // emx will define PSZ as _signed_ char, otherwise
39 // as unsigned char
40
41#define INCL_DOSNLS
42#define INCL_DOSDATETIME
43#define INCL_DOSERRORS
44#define INCL_WINSHELLDATA
45#include <os2.h>
46
47#include <stdlib.h>
48#include <stdio.h>
49#include <string.h>
50#include <math.h>
51
52// XWP's setup.h replaces strchr and the like, and
53// we want the originals in here
54#define DONT_REPLACE_FOR_DBCS
55#include "setup.h" // code generation and debugging options
56
57#include "helpers\nls.h"
58#include "helpers\prfh.h"
59#include "helpers\standards.h"
60
61#pragma hdrstop
62
63/*
64 *@@category: Helpers\National Language Support
65 * See nls.c.
66 */
67
68/* ******************************************************************
69 *
70 * DBCS support
71 *
72 ********************************************************************/
73
74#define MAX_LEADBYTE 256
75
76#pragma pack(1)
77
78typedef struct _DBCSVECTOR
79{
80 BYTE bLow;
81 BYTE bHigh;
82} DBCSVECTOR;
83
84#pragma pack()
85
86BOOL G_afLeadByte[MAX_LEADBYTE] = {0};
87ULONG G_fDBCS = 2; // not queried yet
88COUNTRYCODE G_cc = { 0, 0 };
89DBCSVECTOR G_aDBCSVector[8];
90
91/*
92 *@@ nlsQueryCodepage:
93 * returns the current process codepage as a ULONG.
94 *
95 *@@added V1.0.2 (2003-02-07) [umoeller]
96 */
97
98ULONG nlsQueryCodepage(VOID)
99{
100 ULONG acp[8];
101 ULONG cb = 0;
102 if (DosQueryCp(sizeof(acp),
103 acp,
104 &cb))
105 return 437; // I think this is still the system default
106
107 return acp[0];
108}
109
110/*
111 *@@ nlsDBCS:
112 * returns TRUE if the system is currently using DBCS.
113 *
114 *@@added V0.9.19 (2002-06-13) [umoeller]
115 *@@changed V0.9.20 (2002-07-03) [umoeller]: fixed, this never worked
116 */
117
118BOOL nlsDBCS(VOID)
119{
120 APIRET arc;
121
122 if (G_fDBCS != 2)
123 // already queried:
124 return G_fDBCS;
125
126 // V0.9.20 (2002-07-03) [umoeller]
127 // assume a non-DBCS system UNLESS the below
128 // loop gives us something meaningful; even
129 // on non-DBCS systems like mine, DosQueryDBCSEnv
130 // does not return an error
131 G_fDBCS = FALSE;
132
133 if (!(arc = DosQueryDBCSEnv(8 * sizeof(DBCSVECTOR),
134 &G_cc,
135 (PCHAR)G_aDBCSVector)))
136 {
137 int i;
138 for (i = 0;
139 i < 8;
140 ++i)
141 {
142 if ( (G_aDBCSVector[i].bLow)
143 && (G_aDBCSVector[i].bHigh)
144 )
145 {
146 int n;
147 for (n = G_aDBCSVector[i].bLow;
148 n <= G_aDBCSVector[i].bHigh;
149 ++n)
150 G_afLeadByte[n] = TRUE;
151 G_fDBCS = TRUE;
152 }
153 else
154 break;
155 }
156 }
157
158 return G_fDBCS;
159}
160
161/*
162 *@@ nlsQueryDBCSChar:
163 * returns the type of the DBCS character with
164 * the given index. Note that the index is the
165 * DBCS character index, not just the array
166 * index into the CHAR array.
167 *
168 * Returns:
169 *
170 * -- TYPE_SBCS: ulOfs is single byte.
171 *
172 * -- TYPE_DBCS_1ST: ulOfs is a double-byte lead char.
173 *
174 * -- TYPE_DBCS_2ND: ulOfs is a double-byte trail char.
175 *
176 * Preconditions:
177 *
178 * -- nlsDBCS must have been called to initialize our
179 * globals, and must have returned TRUE.
180 *
181 *@@added V0.9.19 (2002-06-13) [umoeller]
182 */
183
184ULONG nlsQueryDBCSChar(PCSZ pcszString,
185 ULONG ulOfs)
186
187{
188 ULONG ulDBCSType = TYPE_SBCS;
189 ULONG i;
190
191 for (i = 0;
192 i <= ulOfs;
193 ++i)
194 {
195 switch (ulDBCSType)
196 {
197 case TYPE_SBCS:
198 case TYPE_DBCS_2ND:
199 ulDBCSType = G_afLeadByte[pcszString[i]];
200 break;
201
202 case TYPE_DBCS_1ST :
203 ulDBCSType = TYPE_DBCS_2ND;
204 break;
205 }
206 }
207
208 return ulDBCSType;
209}
210
211/*
212 *@@ nlschr:
213 * replacement for strchr with DBCS support.
214 *
215 * If the system is not running with DBCS,
216 * this calls plain strchr automatically.
217 *
218 *@@added V0.9.19 (2002-06-13) [umoeller]
219 *@@changed V0.9.20 (2002-07-22) [umoeller]: optimized
220 *@@changed V0.9.20 (2002-07-22) [lafaix]: optimized
221 */
222
223PSZ nlschr(PCSZ p, char c)
224{
225 PCSZ p2;
226 ULONG ulDBCSType = TYPE_SBCS;
227
228 if (!nlsDBCS())
229 // not DBCS:
230 return strchr(p, c);
231
232 // we're on DBCS:
233
234 // we can't find c if it is a leading byte
235 if (G_afLeadByte[c] != TYPE_SBCS)
236 return NULL;
237
238 for (p2 = p;
239 *p2;
240 ++p2)
241 {
242 // check _previous_ DBCS type and refresh
243 // DBCS type accordingly
244 switch (ulDBCSType)
245 {
246 case TYPE_SBCS:
247 case TYPE_DBCS_2ND:
248 ulDBCSType = G_afLeadByte[*p2];
249 // we can safely do the test here (and skip rechecking
250 // the type) because c can't possibly be a leading byte
251 // V0.9.20 (2002-07-22) [lafaix]
252 if (*p2 == c)
253 return (PSZ)p2;
254 break;
255
256 case TYPE_DBCS_1ST :
257 ulDBCSType = TYPE_DBCS_2ND;
258 break;
259 }
260 }
261
262 /* old code V0.9.20 (2002-07-22) [umoeller]
263 // we're on DBCS:
264 for (p2 = p;
265 *p2;
266 ++p2)
267 {
268 if (*p2 == c)
269 {
270 // match: return this only if it's SBCS;
271 // if it's a DBCS lead char, skip it
272 switch (ulDBCS = nlsQueryDBCSChar(p, p2 - p))
273 {
274 case TYPE_SBCS:
275 return (PSZ)p2;
276
277 case TYPE_DBCS_1ST:
278 ++p2;
279 }
280 }
281 }
282 */
283
284 return NULL;
285}
286
287/*
288 *@@ nlsrchr:
289 * replacement for strrchr with DBCS support.
290 *
291 * If the system is not running with DBCS,
292 * this calls plain strrchr automatically.
293 *
294 *@@added V0.9.19 (2002-06-13) [umoeller]
295 *@@changed V0.9.20 (2002-07-22) [lafaix]: optimized
296 */
297
298PSZ nlsrchr(PCSZ p, char c)
299{
300 PCSZ p2,
301 pLast = NULL;
302 ULONG ulDBCSType = TYPE_SBCS;
303
304 if (!nlsDBCS())
305 // not DBCS:
306 return strrchr(p, c);
307
308 // we're on DBCS:
309
310 // we can't find c if it is a leading byte
311 if (G_afLeadByte[c] != TYPE_SBCS)
312 return NULL;
313
314 for (p2 = p;
315 *p2;
316 ++p2)
317 {
318 // check _previous_ DBCS type and refresh
319 // DBCS type accordingly
320 switch (ulDBCSType)
321 {
322 case TYPE_SBCS:
323 case TYPE_DBCS_2ND:
324 ulDBCSType = G_afLeadByte[*p2];
325 if (*p2 == c)
326 pLast = p2;
327 break;
328
329 case TYPE_DBCS_1ST :
330 ulDBCSType = TYPE_DBCS_2ND;
331 break;
332 }
333 }
334
335 return (PSZ)pLast;
336
337 // old code V0.9.20 (2002-07-22) [lafaix]
338 /*
339 ulLength = strlen(p);
340 for (p2 = p + ulLength - 1;
341 p2 >= p;
342 --p2)
343 {
344 if (*p2 == c)
345 {
346 // match: return this only if it's SBCS;
347 // if it's a DBCS trail char, skip it
348 switch (ulDBCS = nlsQueryDBCSChar(p, p2 - p))
349 {
350 case TYPE_SBCS:
351 return (PSZ)p2;
352
353 case TYPE_DBCS_2ND:
354 --p2;
355 }
356 }
357 }
358
359 return NULL;
360 */
361}
362
363/* ******************************************************************
364 *
365 * Country-dependent formatting
366 *
367 ********************************************************************/
368
369/*
370 *@@ nlsGetAMPM:
371 *
372 *@@added V1.0.1 (2003-01-17) [umoeller]
373 */
374
375VOID nlsGetAMPM(PCOUNTRYAMPM pampm)
376{
377 PrfQueryProfileString(HINI_USER,
378 "PM_National",
379 "s2359", // key
380 "PM", // default
381 pampm->sz2359,
382 sizeof(pampm->sz2359));
383
384 PrfQueryProfileString(HINI_USER,
385 "PM_National",
386 "s1159", // key
387 "AM", // default
388 pampm->sz1159,
389 sizeof(pampm->sz1159));
390}
391
392/*
393 *@@ nlsQueryCountrySettings:
394 * this returns the most frequently used country settings
395 * all at once into a COUNTRYSETTINGS structure (prfh.h).
396 * This data corresponds to the user settings in the
397 * WPS "Country" object (which writes the data in "PM_National"
398 * in OS2.INI).
399 *
400 * In case a key cannot be found, the following (English)
401 * default values are set:
402 * -- ulDateFormat = 0 (English date format, mm.dd.yyyy);
403 * -- ulTimeFormat = 0 (12-hour clock);
404 * -- cDateSep = '/' (date separator);
405 * -- cTimeSep = ':' (time separator);
406 * -- cDecimal = '.' (decimal separator).
407 * -- cThousands = ',' (thousands separator).
408 *
409 *@@added V0.9.0 [umoeller]
410 *@@changed V0.9.7 (2000-12-02) [umoeller]: added cDecimal
411 */
412
413VOID nlsQueryCountrySettings(PCOUNTRYSETTINGS2 pcs2)
414{
415 if (pcs2)
416 {
417 PCOUNTRYSETTINGS pcs = &pcs2->cs;
418 pcs->ulDateFormat = PrfQueryProfileInt(HINI_USER,
419 (PSZ)PMINIAPP_NATIONAL,
420 "iDate",
421 0);
422 pcs->ulTimeFormat = PrfQueryProfileInt(HINI_USER,
423 (PSZ)PMINIAPP_NATIONAL,
424 "iTime",
425 0);
426 pcs->cDateSep = prfhQueryProfileChar(HINI_USER,
427 (PSZ)PMINIAPP_NATIONAL,
428 "sDate",
429 '/');
430 pcs->cTimeSep = prfhQueryProfileChar(HINI_USER,
431 (PSZ)PMINIAPP_NATIONAL,
432 "sTime",
433 ':');
434 pcs->cDecimal = prfhQueryProfileChar(HINI_USER,
435 (PSZ)PMINIAPP_NATIONAL,
436 "sDecimal",
437 '.');
438 pcs->cThousands = prfhQueryProfileChar(HINI_USER,
439 (PSZ)PMINIAPP_NATIONAL,
440 "sThousand",
441 ',');
442
443 nlsGetAMPM(&pcs2->ampm);
444 }
445}
446
447/*
448 *@@ nlsThousandsULong:
449 * converts a ULONG into a decimal string, while
450 * inserting thousands separators into it. Specify
451 * the separator character in cThousands.
452 *
453 * Returns pszTarget so you can use it directly
454 * with sprintf and the "%s" flag.
455 *
456 * For cThousands, you should use the data in
457 * OS2.INI ("PM_National" application), which is
458 * always set according to the "Country" object.
459 * You can use nlsQueryCountrySettings to
460 * retrieve this setting.
461 *
462 * Use nlsThousandsDouble for "double" values.
463 *
464 *@@changed V0.9.20 (2002-07-03) [umoeller]: optimized
465 */
466
467PSZ nlsThousandsULong(PSZ pszTarget, // out: decimal as string
468 ULONG ul, // in: decimal to convert
469 CHAR cThousands) // in: separator char (e.g. '.')
470{
471 CHAR szTemp[30];
472 USHORT ust = 0,
473 uss,
474 usLen = sprintf(szTemp, "%lu", ul); // V0.9.20 (2002-07-03) [umoeller]
475
476 for (uss = 0;
477 uss < usLen;
478 ++uss)
479 {
480 if (uss)
481 if (0 == ((usLen - uss) % 3))
482 {
483 pszTarget[ust] = cThousands;
484 ust++;
485 }
486
487 pszTarget[ust++] = szTemp[uss];
488 }
489
490 pszTarget[ust] = '\0';
491
492 return pszTarget;
493}
494
495/*
496 * strhThousandsULong:
497 * wrapper around nlsThousandsULong for those
498 * who used the XFLDR.DLL export.
499 *
500 *added V0.9.16 (2001-10-11) [umoeller]
501 */
502
503PSZ APIENTRY strhThousandsULong(PSZ pszTarget, // out: decimal as string
504 ULONG ul, // in: decimal to convert
505 CHAR cThousands) // in: separator char (e.g. '.')
506{
507 return nlsThousandsULong(pszTarget, ul, cThousands);
508}
509
510/*
511 *@@ nlsThousandsDouble:
512 * like nlsThousandsULong, but for a "double"
513 * value. Note that after-comma values are truncated.
514 *
515 *@@changed V0.9.20 (2002-07-03) [umoeller]: optimized
516 */
517
518PSZ nlsThousandsDouble(PSZ pszTarget,
519 double dbl,
520 CHAR cThousands)
521{
522 USHORT ust, uss, usLen;
523 CHAR szTemp[40];
524 usLen = sprintf(szTemp, "%.0f", floor(dbl)); // V0.9.20 (2002-07-03) [umoeller]
525
526 ust = 0;
527 for (uss = 0; uss < usLen; uss++)
528 {
529 if (uss)
530 if (((usLen - uss) % 3) == 0)
531 {
532 pszTarget[ust] = cThousands;
533 ust++;
534 }
535 pszTarget[ust] = szTemp[uss];
536 ust++;
537 }
538 pszTarget[ust] = '\0';
539
540 return pszTarget;
541}
542
543/*
544 *@@ nlsVariableDouble:
545 * like nlsThousandsULong, but for a "double" value, and
546 * with a variable number of decimal places depending on the
547 * size of the quantity.
548 *
549 *@@added V0.9.6 (2000-11-12) [pr]
550 *@@changed V0.9.20 (2002-07-03) [umoeller]: now using PCSZ pcszUnits
551 */
552
553PSZ nlsVariableDouble(PSZ pszTarget,
554 double dbl,
555 PCSZ pcszUnits,
556 CHAR cThousands)
557{
558 if (dbl < 100.0)
559 sprintf(pszTarget, "%.2f%s", dbl, pcszUnits);
560 else
561 if (dbl < 1000.0)
562 sprintf(pszTarget, "%.1f%s", dbl, pcszUnits);
563 else
564 strcat(nlsThousandsDouble(pszTarget, dbl, cThousands),
565 pcszUnits);
566
567 return pszTarget;
568}
569
570/*
571 *@@ nlsFileDate:
572 * converts file date data to a string (to pszBuf).
573 * You can pass any FDATE structure to this function,
574 * which are returned in those FILEFINDBUF* or
575 * FILESTATUS* structs by the Dos* functions.
576 *
577 * ulDateFormat is the PM setting for the date format,
578 * as set in the "Country" object, and can be queried using
579 + PrfQueryProfileInt(HINI_USER, "PM_National", "iDate", 0);
580 *
581 * meaning:
582 * -- 0 mm.dd.yyyy (English)
583 * -- 1 dd.mm.yyyy (e.g. German)
584 * -- 2 yyyy.mm.dd (Japanese, ISO)
585 * -- 3 yyyy.dd.mm
586 *
587 * cDateSep is used as a date separator (e.g. '.').
588 * This can be queried using:
589 + prfhQueryProfileChar(HINI_USER, "PM_National", "sDate", '/');
590 *
591 * Alternatively, you can query all the country settings
592 * at once using nlsQueryCountrySettings (prfh.c).
593 *
594 *@@changed V0.9.0 (99-11-07) [umoeller]: now calling nlsDateTime
595 *@@changed V1.0.1 (2003-01-17) [umoeller]: prototype changed for optimization, this was not exported
596 */
597
598VOID nlsFileDate(PSZ pszBuf, // out: string returned
599 const FDATE *pfDate, // in: date information
600 const COUNTRYSETTINGS2 *pcs)
601{
602 nlsDate(pcs,
603 pszBuf,
604 pfDate->year + 1980,
605 pfDate->month,
606 pfDate->day);
607}
608
609/*
610 *@@ nlsFileTime:
611 * converts file time data to a string (to pszBuf).
612 * You can pass any FTIME structure to this function,
613 * which are returned in those FILEFINDBUF* or
614 * FILESTATUS* structs by the Dos* functions.
615 *
616 * ulTimeFormat is the PM setting for the time format,
617 * as set in the "Country" object, and can be queried using
618 + PrfQueryProfileInt(HINI_USER, "PM_National", "iTime", 0);
619 * meaning:
620 * -- 0 12-hour clock
621 * -- >0 24-hour clock
622 *
623 * cDateSep is used as a time separator (e.g. ':').
624 * This can be queried using:
625 + prfhQueryProfileChar(HINI_USER, "PM_National", "sTime", ':');
626 *
627 * Alternatively, you can query all the country settings
628 * at once using nlsQueryCountrySettings (prfh.c).
629 *
630 *@@changed V0.8.5 (99-03-15) [umoeller]: fixed 12-hour crash
631 *@@changed V0.9.0 (99-11-07) [umoeller]: now calling nlsDateTime
632 *@@changed V1.0.1 (2003-01-17) [umoeller]: prototype changed for optimization, this was not exported
633 */
634
635VOID nlsFileTime(PSZ pszBuf, // out: string returned
636 const FTIME *pfTime, // in: time information
637 const COUNTRYSETTINGS2 *pcs)
638{
639 nlsTime(pcs,
640 pszBuf,
641 pfTime->hours,
642 pfTime->minutes,
643 pfTime->twosecs * 2);
644}
645
646/*
647 *@@ nlsDate:
648 *
649 *@@added V1.0.1 (2003-01-17) [umoeller]
650 */
651
652VOID nlsDate(const COUNTRYSETTINGS2 *pcs2,
653 PSZ pszDate, // out: date string returned
654 USHORT year,
655 BYTE month,
656 BYTE day)
657{
658 switch (pcs2->cs.ulDateFormat)
659 {
660 case 0: // mm.dd.yyyy (English)
661 sprintf(pszDate, "%02d%c%02d%c%04d",
662 month,
663 pcs2->cs.cDateSep,
664 day,
665 pcs2->cs.cDateSep,
666 year);
667 break;
668
669 case 1: // dd.mm.yyyy (e.g. German)
670 sprintf(pszDate, "%02d%c%02d%c%04d",
671 day,
672 pcs2->cs.cDateSep,
673 month,
674 pcs2->cs.cDateSep,
675 year);
676 break;
677
678 case 2: // yyyy.mm.dd (ISO and Japanese)
679 sprintf(pszDate, "%04d%c%02d%c%02d",
680 year,
681 pcs2->cs.cDateSep,
682 month,
683 pcs2->cs.cDateSep,
684 day);
685 break;
686
687 default: // yyyy.dd.mm
688 sprintf(pszDate, "%04d%c%02d%c%02d",
689 year,
690 pcs2->cs.cDateSep,
691 day,
692 pcs2->cs.cDateSep,
693 month);
694 break;
695 }
696}
697
698/*
699 *@@ nlsTime:
700 *
701 *@@added V1.0.1 (2003-01-17) [umoeller]
702 */
703
704VOID nlsTime(const COUNTRYSETTINGS2 *pcs2,
705 PSZ pszTime, // out: time string returned
706 BYTE hours,
707 BYTE minutes,
708 BYTE seconds)
709{
710 if (!pcs2->cs.ulTimeFormat)
711 {
712 // for 12-hour clock, we need additional INI data
713 if (hours >= 12) // V0.9.16 (2001-12-05) [pr] if (hours > 12)
714 {
715 // yeah cool Paul, now we get 00:20 PM if it's 20 past noon
716 // V0.9.18 (2002-02-13) [umoeller]
717 ULONG ulHours;
718 if (!(ulHours = hours % 12))
719 ulHours = 12;
720
721 // >= 12h: PM.
722 sprintf(pszTime, "%02d%c%02d%c%02d %s",
723 // leave 12 == 12 (not 0)
724 ulHours,
725 pcs2->cs.cTimeSep,
726 minutes,
727 pcs2->cs.cTimeSep,
728 seconds,
729 pcs2->ampm.sz2359);
730 }
731 else
732 {
733 // < 12h: AM
734 sprintf(pszTime, "%02d%c%02d%c%02d %s",
735 hours,
736 pcs2->cs.cTimeSep,
737 minutes,
738 pcs2->cs.cTimeSep,
739 seconds,
740 pcs2->ampm.sz1159);
741 }
742 }
743 else
744 // 24-hour clock
745 sprintf(pszTime, "%02d%c%02d%c%02d",
746 hours,
747 pcs2->cs.cTimeSep,
748 minutes,
749 pcs2->cs.cTimeSep,
750 seconds);
751}
752
753/*
754 *@@ nlsDateTime:
755 * converts Control Program DATETIME info
756 * into two strings. See nlsFileDate and nlsFileTime
757 * for more detailed parameter descriptions.
758 *
759 * Use of this function is deprecated. Use the
760 * speedier nlsDateTime2 instead.
761 *
762 *@@added V0.9.0 (99-11-07) [umoeller]
763 *@@changed V0.9.16 (2001-12-05) [pr]: fixed AM/PM hour bug
764 *@@changed V0.9.18 (2002-02-13) [umoeller]: fixed AM/PM hour bug fix
765 *@@changed V1.0.1 (2003-01-17) [umoeller]: extracted nlsDate, nlsTime
766 */
767
768VOID nlsDateTime(PSZ pszDate, // out: date string returned (can be NULL)
769 PSZ pszTime, // out: time string returned (can be NULL)
770 const DATETIME *pDateTime, // in: date/time information
771 ULONG ulDateFormat, // in: date format (0-3); see nlsFileDate
772 CHAR cDateSep, // in: date separator (e.g. '.')
773 ULONG ulTimeFormat, // in: 24-hour time format (0 or 1); see nlsFileTime
774 CHAR cTimeSep) // in: time separator (e.g. ':')
775{
776 COUNTRYSETTINGS2 cs2;
777 if (pszDate)
778 {
779 cs2.cs.ulDateFormat = ulDateFormat;
780 cs2.cs.cDateSep = cDateSep;
781 nlsDate(&cs2,
782 pszDate, // out: date string returned
783 pDateTime->year,
784 pDateTime->month,
785 pDateTime->day);
786 }
787
788 if (pszTime)
789 {
790 cs2.cs.ulTimeFormat = ulTimeFormat;
791 cs2.cs.cTimeSep = cTimeSep;
792 nlsGetAMPM(&cs2.ampm);
793 nlsTime(&cs2,
794 pszTime,
795 pDateTime->hours,
796 pDateTime->minutes,
797 pDateTime->seconds);
798 }
799}
800
801/*
802 * strhDateTime:
803 * wrapper around nlsDateTime for those who used
804 * the XFLDR.DLL export.
805 */
806
807VOID APIENTRY strhDateTime(PSZ pszDate, // out: date string returned (can be NULL)
808 PSZ pszTime, // out: time string returned (can be NULL)
809 DATETIME *pDateTime, // in: date/time information
810 ULONG ulDateFormat, // in: date format (0-3); see nlsFileDate
811 CHAR cDateSep, // in: date separator (e.g. '.')
812 ULONG ulTimeFormat, // in: 24-hour time format (0 or 1); see nlsFileTime
813 CHAR cTimeSep) // in: time separator (e.g. ':')
814{
815 nlsDateTime(pszDate,
816 pszTime,
817 pDateTime,
818 ulDateFormat,
819 cDateSep,
820 ulTimeFormat,
821 cTimeSep);
822}
823
824/*
825 *@@ nlsDateTime2:
826 * speedier version of nlsDateTime that caches
827 * all information and needs _no_ Prf* call
828 * any more.
829 *
830 *@@added V1.0.1 (2003-01-17) [umoeller]
831 */
832
833VOID nlsDateTime2(PSZ pszDate,
834 PSZ pszTime,
835 const DATETIME *pDateTime,
836 const COUNTRYSETTINGS2 *pcs2)
837{
838 if (pszDate)
839 nlsDate(pcs2,
840 pszDate,
841 pDateTime->year,
842 pDateTime->month,
843 pDateTime->day);
844
845 if (pszTime)
846 nlsTime(pcs2,
847 pszTime,
848 pDateTime->hours,
849 pDateTime->minutes,
850 pDateTime->seconds);
851}
852
853CHAR G_szUpperMap[257];
854BOOL G_fUpperMapInited = FALSE;
855
856/*
857 *@@ InitUpperMap:
858 * initializes the case map for nlsUpper.
859 *
860 *@@added V0.9.20 (2002-07-25) [umoeller]
861 */
862
863STATIC VOID InitUpperMap(VOID)
864{
865 ULONG ul;
866 COUNTRYCODE cc;
867 BOOL fDBCS = nlsDBCS();
868
869 for (ul = 0;
870 ul < 256;
871 ++ul)
872 {
873 G_szUpperMap[ul] = (CHAR)ul;
874
875 if ( (fDBCS)
876 && (G_afLeadByte[ul] != TYPE_SBCS)
877 )
878 G_szUpperMap[ul] = ' ';
879 }
880
881 G_szUpperMap[256] = '\0';
882
883 cc.country = 0; // use system country code
884 cc.codepage = 0; // use process default codepage
885 DosMapCase(255,
886 &cc,
887 G_szUpperMap + 1);
888
889 G_fUpperMapInited = TRUE;
890}
891
892/*
893 *@@ nlsUpper:
894 * quick hack for upper-casing a string.
895 *
896 * This now returns the length of the given string always
897 * (V0.9.20).
898 *
899 * Remarks:
900 *
901 * -- On the first call, we build a case map table by
902 * calling DosMapCase with the default system country
903 * code and the process's codepage. Since DosMapCase
904 * is terribly slow with all the 16-bit thunking
905 * involved, we can then use our table without having
906 * to use the API ever again.
907 *
908 * -- As a result, if the process codepage changes for
909 * any reason, this function will not pick up the
910 * change.
911 *
912 * -- This has provisions for DBCS, which hopefully
913 * work.
914 *
915 *@@added V0.9.16 (2001-10-25) [umoeller]
916 *@@changed V0.9.20 (2002-07-25) [umoeller]: speedup, changed prototype
917 */
918
919ULONG nlsUpper(PSZ psz) // in/out: string
920{
921 ULONG ul = 0;
922 PSZ p;
923
924 if (!G_fUpperMapInited)
925 InitUpperMap();
926
927 if (p = psz)
928 {
929 while (*p++ = G_szUpperMap[*p])
930 ++ul;
931 }
932
933 return ul;
934}
935
936
Note: See TracBrowser for help on using the repository browser.