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

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

New build system, multimedia, other misc fixes.

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