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

Last change on this file since 118 was 116, checked in by umoeller, 24 years ago

More updates.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 16.1 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-2001 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_DOSERRORS
43#define INCL_WINSHELLDATA
44#include <os2.h>
45
46#include <stdlib.h>
47#include <stdio.h>
48#include <string.h>
49#include <math.h>
50
51#include "setup.h" // code generation and debugging options
52
53#include "helpers\prfh.h"
54#include "helpers\nls.h"
55
56#pragma hdrstop
57
58/*
59 *@@category: Helpers\C helpers\National Language Support
60 * See stringh.c and xstring.c.
61 */
62
63/*
64 *@@ nlsQueryCountrySettings:
65 * this returns the most frequently used country settings
66 * all at once into a COUNTRYSETTINGS structure (prfh.h).
67 * This data corresponds to the user settings in the
68 * WPS "Country" object (which writes the data in "PM_National"
69 * in OS2.INI).
70 *
71 * In case a key cannot be found, the following (English)
72 * default values are set:
73 * -- ulDateFormat = 0 (English date format, mm.dd.yyyy);
74 * -- ulTimeFormat = 0 (12-hour clock);
75 * -- cDateSep = '/' (date separator);
76 * -- cTimeSep = ':' (time separator);
77 * -- cDecimal = '.' (decimal separator).
78 * -- cThousands = ',' (thousands separator).
79 *
80 *@@added V0.9.0 [umoeller]
81 *@@changed V0.9.7 (2000-12-02) [umoeller]: added cDecimal
82 */
83
84VOID nlsQueryCountrySettings(PCOUNTRYSETTINGS pcs)
85{
86 if (pcs)
87 {
88 pcs->ulDateFormat = PrfQueryProfileInt(HINI_USER,
89 (PSZ)PMINIAPP_NATIONAL,
90 "iDate",
91 0);
92 pcs->ulTimeFormat = PrfQueryProfileInt(HINI_USER,
93 (PSZ)PMINIAPP_NATIONAL,
94 "iTime",
95 0);
96 pcs->cDateSep = prfhQueryProfileChar(HINI_USER,
97 (PSZ)PMINIAPP_NATIONAL,
98 "sDate",
99 '/');
100 pcs->cTimeSep = prfhQueryProfileChar(HINI_USER,
101 (PSZ)PMINIAPP_NATIONAL,
102 "sTime",
103 ':');
104 pcs->cDecimal = prfhQueryProfileChar(HINI_USER,
105 (PSZ)PMINIAPP_NATIONAL,
106 "sDecimal",
107 '.');
108 pcs->cThousands = prfhQueryProfileChar(HINI_USER,
109 (PSZ)PMINIAPP_NATIONAL,
110 "sThousand",
111 ',');
112 }
113}
114
115/*
116 *@@ nlsThousandsULong:
117 * converts a ULONG into a decimal string, while
118 * inserting thousands separators into it. Specify
119 * the separator character in cThousands.
120 *
121 * Returns pszTarget so you can use it directly
122 * with sprintf and the "%s" flag.
123 *
124 * For cThousands, you should use the data in
125 * OS2.INI ("PM_National" application), which is
126 * always set according to the "Country" object.
127 * You can use nlsQueryCountrySettings to
128 * retrieve this setting.
129 *
130 * Use nlsThousandsDouble for "double" values.
131 */
132
133PSZ nlsThousandsULong(PSZ pszTarget, // out: decimal as string
134 ULONG ul, // in: decimal to convert
135 CHAR cThousands) // in: separator char (e.g. '.')
136{
137 USHORT ust, uss, usc;
138 CHAR szTemp[40];
139 sprintf(szTemp, "%lu", ul);
140
141 ust = 0;
142 usc = strlen(szTemp);
143 for (uss = 0; uss < usc; uss++)
144 {
145 if (uss)
146 if (((usc - uss) % 3) == 0)
147 {
148 pszTarget[ust] = cThousands;
149 ust++;
150 }
151 pszTarget[ust] = szTemp[uss];
152 ust++;
153 }
154 pszTarget[ust] = '\0';
155
156 return (pszTarget);
157}
158
159/*
160 * strhThousandsULong:
161 * wrapper around nlsThousandsULong for those
162 * who used the XFLDR.DLL export.
163 *
164 *added V0.9.16 (2001-10-11) [umoeller]
165 */
166
167PSZ APIENTRY strhThousandsULong(PSZ pszTarget, // out: decimal as string
168 ULONG ul, // in: decimal to convert
169 CHAR cThousands) // in: separator char (e.g. '.')
170{
171 return (nlsThousandsULong(pszTarget, ul, cThousands));
172}
173
174/*
175 *@@ nlsThousandsDouble:
176 * like nlsThousandsULong, but for a "double"
177 * value. Note that after-comma values are truncated.
178 */
179
180PSZ nlsThousandsDouble(PSZ pszTarget,
181 double dbl,
182 CHAR cThousands)
183{
184 USHORT ust, uss, usc;
185 CHAR szTemp[40];
186 sprintf(szTemp, "%.0f", floor(dbl));
187
188 ust = 0;
189 usc = strlen(szTemp);
190 for (uss = 0; uss < usc; uss++)
191 {
192 if (uss)
193 if (((usc - uss) % 3) == 0)
194 {
195 pszTarget[ust] = cThousands;
196 ust++;
197 }
198 pszTarget[ust] = szTemp[uss];
199 ust++;
200 }
201 pszTarget[ust] = '\0';
202
203 return (pszTarget);
204}
205
206/*
207 *@@ nlsVariableDouble:
208 * like nlsThousandsULong, but for a "double" value, and
209 * with a variable number of decimal places depending on the
210 * size of the quantity.
211 *
212 *@@added V0.9.6 (2000-11-12) [pr]
213 */
214
215PSZ nlsVariableDouble(PSZ pszTarget,
216 double dbl,
217 PSZ pszUnits,
218 CHAR cThousands)
219{
220 if (dbl < 100.0)
221 sprintf(pszTarget, "%.2f%s", dbl, pszUnits);
222 else
223 if (dbl < 1000.0)
224 sprintf(pszTarget, "%.1f%s", dbl, pszUnits);
225 else
226 strcat(nlsThousandsDouble(pszTarget, dbl, cThousands),
227 pszUnits);
228
229 return(pszTarget);
230}
231
232/*
233 *@@ nlsFileDate:
234 * converts file date data to a string (to pszBuf).
235 * You can pass any FDATE structure to this function,
236 * which are returned in those FILEFINDBUF* or
237 * FILESTATUS* structs by the Dos* functions.
238 *
239 * ulDateFormat is the PM setting for the date format,
240 * as set in the "Country" object, and can be queried using
241 + PrfQueryProfileInt(HINI_USER, "PM_National", "iDate", 0);
242 *
243 * meaning:
244 * -- 0 mm.dd.yyyy (English)
245 * -- 1 dd.mm.yyyy (e.g. German)
246 * -- 2 yyyy.mm.dd (Japanese, ISO)
247 * -- 3 yyyy.dd.mm
248 *
249 * cDateSep is used as a date separator (e.g. '.').
250 * This can be queried using:
251 + prfhQueryProfileChar(HINI_USER, "PM_National", "sDate", '/');
252 *
253 * Alternatively, you can query all the country settings
254 * at once using nlsQueryCountrySettings (prfh.c).
255 *
256 *@@changed V0.9.0 (99-11-07) [umoeller]: now calling nlsDateTime
257 */
258
259VOID nlsFileDate(PSZ pszBuf, // out: string returned
260 FDATE *pfDate, // in: date information
261 ULONG ulDateFormat, // in: date format (0-3)
262 CHAR cDateSep) // in: date separator (e.g. '.')
263{
264 DATETIME dt;
265 dt.day = pfDate->day;
266 dt.month = pfDate->month;
267 dt.year = pfDate->year + 1980;
268
269 nlsDateTime(pszBuf,
270 NULL, // no time
271 &dt,
272 ulDateFormat,
273 cDateSep,
274 0, 0); // no time
275}
276
277/*
278 *@@ nlsFileTime:
279 * converts file time data to a string (to pszBuf).
280 * You can pass any FTIME structure to this function,
281 * which are returned in those FILEFINDBUF* or
282 * FILESTATUS* structs by the Dos* functions.
283 *
284 * ulTimeFormat is the PM setting for the time format,
285 * as set in the "Country" object, and can be queried using
286 + PrfQueryProfileInt(HINI_USER, "PM_National", "iTime", 0);
287 * meaning:
288 * -- 0 12-hour clock
289 * -- >0 24-hour clock
290 *
291 * cDateSep is used as a time separator (e.g. ':').
292 * This can be queried using:
293 + prfhQueryProfileChar(HINI_USER, "PM_National", "sTime", ':');
294 *
295 * Alternatively, you can query all the country settings
296 * at once using nlsQueryCountrySettings (prfh.c).
297 *
298 *@@changed V0.8.5 (99-03-15) [umoeller]: fixed 12-hour crash
299 *@@changed V0.9.0 (99-11-07) [umoeller]: now calling nlsDateTime
300 */
301
302VOID nlsFileTime(PSZ pszBuf, // out: string returned
303 FTIME *pfTime, // in: time information
304 ULONG ulTimeFormat, // in: 24-hour time format (0 or 1)
305 CHAR cTimeSep) // in: time separator (e.g. ':')
306{
307 DATETIME dt;
308 dt.hours = pfTime->hours;
309 dt.minutes = pfTime->minutes;
310 dt.seconds = pfTime->twosecs * 2;
311
312 nlsDateTime(NULL, // no date
313 pszBuf,
314 &dt,
315 0, 0, // no date
316 ulTimeFormat,
317 cTimeSep);
318}
319
320/*
321 *@@ nlsDateTime:
322 * converts Control Program DATETIME info
323 * into two strings. See nlsFileDate and nlsFileTime
324 * for more detailed parameter descriptions.
325 *
326 *@@added V0.9.0 (99-11-07) [umoeller]
327 */
328
329VOID nlsDateTime(PSZ pszDate, // out: date string returned (can be NULL)
330 PSZ pszTime, // out: time string returned (can be NULL)
331 DATETIME *pDateTime, // in: date/time information
332 ULONG ulDateFormat, // in: date format (0-3); see nlsFileDate
333 CHAR cDateSep, // in: date separator (e.g. '.')
334 ULONG ulTimeFormat, // in: 24-hour time format (0 or 1); see nlsFileTime
335 CHAR cTimeSep) // in: time separator (e.g. ':')
336{
337 if (pszDate)
338 {
339 switch (ulDateFormat)
340 {
341 case 0: // mm.dd.yyyy (English)
342 sprintf(pszDate, "%02d%c%02d%c%04d",
343 pDateTime->month,
344 cDateSep,
345 pDateTime->day,
346 cDateSep,
347 pDateTime->year);
348 break;
349
350 case 1: // dd.mm.yyyy (e.g. German)
351 sprintf(pszDate, "%02d%c%02d%c%04d",
352 pDateTime->day,
353 cDateSep,
354 pDateTime->month,
355 cDateSep,
356 pDateTime->year);
357 break;
358
359 case 2: // yyyy.mm.dd (Japanese)
360 sprintf(pszDate, "%04d%c%02d%c%02d",
361 pDateTime->year,
362 cDateSep,
363 pDateTime->month,
364 cDateSep,
365 pDateTime->day);
366 break;
367
368 default: // yyyy.dd.mm
369 sprintf(pszDate, "%04d%c%02d%c%02d",
370 pDateTime->year,
371 cDateSep,
372 pDateTime->day,
373 cDateSep,
374 pDateTime->month);
375 break;
376 }
377 }
378
379 if (pszTime)
380 {
381 if (ulTimeFormat == 0)
382 {
383 // for 12-hour clock, we need additional INI data
384 CHAR szAMPM[10] = "err";
385
386 if (pDateTime->hours > 12)
387 {
388 // > 12h: PM.
389
390 // Note: 12:xx noon is 12 AM, not PM (even though
391 // AM stands for "ante meridiam", but English is just
392 // not logical), so that's handled below.
393
394 PrfQueryProfileString(HINI_USER,
395 "PM_National",
396 "s2359", // key
397 "PM", // default
398 szAMPM, sizeof(szAMPM)-1);
399 sprintf(pszTime, "%02d%c%02d%c%02d %s",
400 // leave 12 == 12 (not 0)
401 pDateTime->hours % 12,
402 cTimeSep,
403 pDateTime->minutes,
404 cTimeSep,
405 pDateTime->seconds,
406 szAMPM);
407 }
408 else
409 {
410 // <= 12h: AM
411 PrfQueryProfileString(HINI_USER,
412 "PM_National",
413 "s1159", // key
414 "AM", // default
415 szAMPM, sizeof(szAMPM)-1);
416 sprintf(pszTime, "%02d%c%02d%c%02d %s",
417 pDateTime->hours,
418 cTimeSep,
419 pDateTime->minutes,
420 cTimeSep,
421 pDateTime->seconds,
422 szAMPM);
423 }
424 }
425 else
426 // 24-hour clock
427 sprintf(pszTime, "%02d%c%02d%c%02d",
428 pDateTime->hours,
429 cTimeSep,
430 pDateTime->minutes,
431 cTimeSep,
432 pDateTime->seconds);
433 }
434}
435
436/*
437 * strhDateTime:
438 * wrapper around nlsDateTime for those who used
439 * the XFLDR.DLL export.
440 */
441
442VOID APIENTRY strhDateTime(PSZ pszDate, // out: date string returned (can be NULL)
443 PSZ pszTime, // out: time string returned (can be NULL)
444 DATETIME *pDateTime, // in: date/time information
445 ULONG ulDateFormat, // in: date format (0-3); see nlsFileDate
446 CHAR cDateSep, // in: date separator (e.g. '.')
447 ULONG ulTimeFormat, // in: 24-hour time format (0 or 1); see nlsFileTime
448 CHAR cTimeSep) // in: time separator (e.g. ':')
449{
450 nlsDateTime(pszDate,
451 pszTime,
452 pDateTime,
453 ulDateFormat,
454 cDateSep,
455 ulTimeFormat,
456 cTimeSep);
457}
458
459
460/*
461 *@@ nlsUpper:
462 * quick hack for upper-casing a string.
463 *
464 * This uses DosMapCase with the default system country
465 * code and the process's codepage.
466 *
467 *@@added V0.9.16 (2001-10-25) [umoeller]
468 */
469
470APIRET nlsUpper(PSZ psz, // in/out: string
471 ULONG ulLength) // in: string length; if 0, we run strlen(psz)
472{
473 COUNTRYCODE cc;
474
475 if (psz)
476 {
477 if (!ulLength)
478 ulLength = strlen(psz);
479
480 if (ulLength)
481 {
482 cc.country = 0; // use system country code
483 cc.codepage = 0; // use process default codepage
484 return (DosMapCase(ulLength,
485 &cc,
486 psz));
487 }
488 }
489
490 return (ERROR_INVALID_PARAMETER);
491}
Note: See TracBrowser for help on using the repository browser.