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

Last change on this file since 133 was 121, checked in by umoeller, 24 years ago

Misc changes.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 16.2 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 *@@changed V0.9.16 (2001-12-05) [pr]: fixed AM/PM hour bug
328 */
329
330VOID nlsDateTime(PSZ pszDate, // out: date string returned (can be NULL)
331 PSZ pszTime, // out: time string returned (can be NULL)
332 DATETIME *pDateTime, // in: date/time information
333 ULONG ulDateFormat, // in: date format (0-3); see nlsFileDate
334 CHAR cDateSep, // in: date separator (e.g. '.')
335 ULONG ulTimeFormat, // in: 24-hour time format (0 or 1); see nlsFileTime
336 CHAR cTimeSep) // in: time separator (e.g. ':')
337{
338 if (pszDate)
339 {
340 switch (ulDateFormat)
341 {
342 case 0: // mm.dd.yyyy (English)
343 sprintf(pszDate, "%02d%c%02d%c%04d",
344 pDateTime->month,
345 cDateSep,
346 pDateTime->day,
347 cDateSep,
348 pDateTime->year);
349 break;
350
351 case 1: // dd.mm.yyyy (e.g. German)
352 sprintf(pszDate, "%02d%c%02d%c%04d",
353 pDateTime->day,
354 cDateSep,
355 pDateTime->month,
356 cDateSep,
357 pDateTime->year);
358 break;
359
360 case 2: // yyyy.mm.dd (Japanese)
361 sprintf(pszDate, "%04d%c%02d%c%02d",
362 pDateTime->year,
363 cDateSep,
364 pDateTime->month,
365 cDateSep,
366 pDateTime->day);
367 break;
368
369 default: // yyyy.dd.mm
370 sprintf(pszDate, "%04d%c%02d%c%02d",
371 pDateTime->year,
372 cDateSep,
373 pDateTime->day,
374 cDateSep,
375 pDateTime->month);
376 break;
377 }
378 }
379
380 if (pszTime)
381 {
382 if (ulTimeFormat == 0)
383 {
384 // for 12-hour clock, we need additional INI data
385 CHAR szAMPM[10] = "err";
386
387 if (pDateTime->hours >= 12) // V0.9.16 (2001-12-05) [pr] if (pDateTime->hours > 12)
388 {
389 // >= 12h: PM.
390 PrfQueryProfileString(HINI_USER,
391 "PM_National",
392 "s2359", // key
393 "PM", // default
394 szAMPM, sizeof(szAMPM)-1);
395 sprintf(pszTime, "%02d%c%02d%c%02d %s",
396 // leave 12 == 12 (not 0)
397 pDateTime->hours % 12,
398 cTimeSep,
399 pDateTime->minutes,
400 cTimeSep,
401 pDateTime->seconds,
402 szAMPM);
403 }
404 else
405 {
406 // < 12h: AM
407 PrfQueryProfileString(HINI_USER,
408 "PM_National",
409 "s1159", // key
410 "AM", // default
411 szAMPM, sizeof(szAMPM)-1);
412 sprintf(pszTime, "%02d%c%02d%c%02d %s",
413 pDateTime->hours,
414 cTimeSep,
415 pDateTime->minutes,
416 cTimeSep,
417 pDateTime->seconds,
418 szAMPM);
419 }
420 }
421 else
422 // 24-hour clock
423 sprintf(pszTime, "%02d%c%02d%c%02d",
424 pDateTime->hours,
425 cTimeSep,
426 pDateTime->minutes,
427 cTimeSep,
428 pDateTime->seconds);
429 }
430}
431
432/*
433 * strhDateTime:
434 * wrapper around nlsDateTime for those who used
435 * the XFLDR.DLL export.
436 */
437
438VOID APIENTRY strhDateTime(PSZ pszDate, // out: date string returned (can be NULL)
439 PSZ pszTime, // out: time string returned (can be NULL)
440 DATETIME *pDateTime, // in: date/time information
441 ULONG ulDateFormat, // in: date format (0-3); see nlsFileDate
442 CHAR cDateSep, // in: date separator (e.g. '.')
443 ULONG ulTimeFormat, // in: 24-hour time format (0 or 1); see nlsFileTime
444 CHAR cTimeSep) // in: time separator (e.g. ':')
445{
446 nlsDateTime(pszDate,
447 pszTime,
448 pDateTime,
449 ulDateFormat,
450 cDateSep,
451 ulTimeFormat,
452 cTimeSep);
453}
454
455
456/*
457 *@@ nlsUpper:
458 * quick hack for upper-casing a string.
459 *
460 * This uses DosMapCase with the default system country
461 * code and the process's codepage.
462 *
463 *@@added V0.9.16 (2001-10-25) [umoeller]
464 */
465
466APIRET nlsUpper(PSZ psz, // in/out: string
467 ULONG ulLength) // in: string length; if 0, we run strlen(psz)
468{
469 COUNTRYCODE cc;
470
471 if (psz)
472 {
473 if (!ulLength)
474 ulLength = strlen(psz);
475
476 if (ulLength)
477 {
478 cc.country = 0; // use system country code
479 cc.codepage = 0; // use process default codepage
480 return (DosMapCase(ulLength,
481 &cc,
482 psz));
483 }
484 }
485
486 return (ERROR_INVALID_PARAMETER);
487}
Note: See TracBrowser for help on using the repository browser.