Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / workbench / libs / locale / formatdate.c
blob6b52842e3863b3a5ae8d611595afb7c2bdac1129
1 /*
2 Copyright © 1995-2008, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc:
6 Lang: English
7 */
9 #include "locale_intern.h"
10 #include <exec/types.h>
11 #include <utility/hooks.h>
12 #include <utility/date.h>
13 #include <proto/utility.h>
14 #include <clib/alib_protos.h>
16 #include <stdio.h>
18 VOID PrintDigits(UWORD number, char fill, UWORD len, const struct Hook *hook,
19 const struct Locale *locale);
20 VOID _WriteChar(char token, const struct Hook *hook,
21 const struct Locale *locale);
22 VOID _WriteString(CONST_STRPTR string, const struct Hook *hook,
23 const struct Locale *locale);
25 static const ULONG dayspermonth[13] =
26 {0 /* not used */,0,31,59,90,120,151,181,212,243,273,304,334};
28 /*****************************************************************************
30 NAME */
31 #include <proto/locale.h>
33 AROS_LH4(VOID, FormatDate,
35 /* SYNOPSIS */
36 AROS_LHA(const struct Locale *, locale, A0),
37 AROS_LHA(CONST_STRPTR, formatString, A1),
38 AROS_LHA(const struct DateStamp *, date, A2),
39 AROS_LHA(const struct Hook *, hook, A3),
41 /* LOCATION */
42 struct LocaleBase *, LocaleBase, 10, Locale)
44 /* FUNCTION
46 Generate a date string based on a template. The bytes generated are sent
47 to a user specified callback function.
49 INPUTS
51 locale -- the locale to use when formatting the string
52 formatString -- the formatting template string; this is much like the
53 printf() formatting style, i.e. a % followed by a
54 formatting command. The following commands exist:
56 %a -- abbreviated weekday name
57 %A -- weekday name
58 %b -- abbreviated month name
59 %B -- month name
60 %c -- the same as "%a %b %d %H:%M:%S %Y"
61 %C -- the same as "%a %b %e %T %Z %Y"
62 %d -- day number with leading zeros
63 %D -- the same as "%m/%d/%y"
64 %e -- day number with leading spaces
65 %h -- abbreviated month name
66 %H -- hour using 24 hour style with leading zeros
67 %I -- hour using 12 hour style with leading zeros
68 %j -- julian date
69 %m -- month number with leading zeros
70 %M -- the number of minutes with leading zeros
71 %n -- linefeed
72 %p -- AM or PM string
73 %q -- hour using 24 hour style
74 %Q -- hour using 12 hour style
75 %r -- the same as "%I:%M:%S %p"
76 %R -- the same as "%H:%M"
77 %S -- the number of seconds with leading zeros
78 %t -- tab
79 %T -- the same as "%H:%M:%S"
80 %U -- the week number, taking Sunday as the first day
81 of the week
82 %w -- the weekday number
83 %W -- the week number, taking Monday as the first day
84 of the week
85 %x -- the same as "%m/%d/%y"
86 %X -- the same as "%H:%M:%S"
87 %y -- the year using two digits with leading zeros
88 %Y -- the year using four digits with leading zeros
90 If the template parameter is NULL, a single null byte
91 is sent to the callback function.
93 date -- the current date
94 hook -- callback function; this is called for every character
95 generated with the following arguments:
97 * pointer to hook structure
98 * character
99 * pointer to locale
101 RESULT
103 NOTES
105 EXAMPLE
107 BUGS
109 SEE ALSO
111 ParseDate(), <libraries/locale.h>
113 INTERNALS
115 *****************************************************************************/
117 AROS_LIBFUNC_INIT
119 struct ClockData cData;
120 ULONG week, days, tmp;
122 if(/* locale == NULL || */ hook == NULL)
123 return;
125 if(formatString == NULL)
127 _WriteChar(0, hook, locale);
128 return;
131 #warning Amiga2Date will fail around year 2114, because then the numer of seconds since 1978 dont fit in a 32 bit variable anymore!
133 Amiga2Date(date->ds_Days*86400 + date->ds_Minute*60 + date->ds_Tick / 50,
134 &cData);
136 while(*formatString != 0)
138 if(*formatString == '%')
140 switch(*(++formatString))
142 case 'a':
143 _WriteString(GetLocaleStr(locale, ABDAY_1 + cData.wday), hook,
144 locale);
145 break;
147 case 'A':
148 _WriteString(GetLocaleStr(locale, DAY_1 + cData.wday), hook,
149 locale);
150 break;
152 case 'b':
153 _WriteString(GetLocaleStr(locale, ABMON_1 + cData.month - 1),
154 hook, locale);
155 break;
157 case 'B':
158 _WriteString(GetLocaleStr(locale, MON_1 + cData.month - 1), hook,
159 locale);
160 break;
162 case 'c':
163 FormatDate(locale, "%a %b %d %H:%M:%S %Y", date, hook);
164 break;
166 case 'C':
167 FormatDate(locale, "%a %b %e %T %Z %Y", date, hook);
168 break;
170 case 'd':
171 PrintDigits(cData.mday, '0', 2, hook, locale);
172 break;
174 case 'x':
175 case 'D':
176 FormatDate(locale, "%m/%d/%y", date, hook);
177 break;
179 case 'e':
180 PrintDigits(cData.mday, ' ', 2, hook, locale);
181 break;
183 case 'h':
184 _WriteString(GetLocaleStr(locale, ABMON_1 + cData.month - 1),
185 hook, locale);
186 break;
188 case 'H':
189 PrintDigits(cData.hour, '0', 2, hook, locale);
190 break;
192 case 'I':
193 PrintDigits(cData.hour % 12, '0', 2, hook, locale);
194 break;
196 case 'j':
197 /* TODO */
198 #warning Julian date not tested.
199 /* Julian date is DDD (1 - 366)*/
200 PrintDigits(
201 cData.mday + dayspermonth[cData.month],
202 '0',
204 hook,
205 locale
207 break;
209 case 'm':
210 PrintDigits(cData.month, '0', 2, hook, locale);
211 break;
213 case 'M':
214 PrintDigits(cData.min, '0', 2, hook, locale);
215 break;
217 case 'n':
218 _WriteChar('\n', hook, locale);
219 break;
221 case 'p':
222 _WriteString(GetLocaleStr(locale,
223 cData.hour < 12 ? AM_STR : PM_STR),
224 hook, locale);
225 break;
227 case 'q':
228 PrintDigits(cData.hour, -1, 2, hook, locale);
229 break;
231 case 'Q':
232 PrintDigits(cData.hour % 12, -1, 2, hook, locale);
233 break;
235 case 'r':
236 FormatDate(locale, "%I:%M:%S %p", date, hook);
237 break;
239 case 'R':
240 FormatDate(locale, "%H:%M", date, hook);
241 break;
243 case 'S':
244 PrintDigits(cData.sec, '0', 2, hook, locale);
245 break;
247 case 't':
248 _WriteChar('\t', hook, locale);
249 break;
251 case 'X':
252 case 'T':
253 FormatDate(locale, "%H:%M:%S", date, hook);
254 break;
256 case 'W': /* week number, Monday first day of week */
257 case 'U': /* week number, Sunday first day of week */
258 days = cData.mday + dayspermonth[cData.month];
260 /* leap year ? */
261 if (0 == (cData.year % 4) && cData.month > 2)
264 ** 1700, 1800, 1900, 2100, 2200 re not leap years.
265 ** 2000 is a leap year.
266 ** -> if a year is divisible by 100 but not by 400 then
267 ** it is not a leap year!
269 if (0 == (cData.year % 100) && 0 != (cData.year % 400))
271 else
272 days++;
276 ** If January 1st is a Monday then the first week
277 ** will start with a Sunday January 7th if Sunday is the first day of the week
278 ** but if Monday is the first day of the week then Jan 1st will also be the
279 ** first day of the first week.
282 ** Go to Saturday = last day of week if Sunday is first day of week
283 ** Go to Sunday = last day of week if Monday is first day of week
285 if ('U' == *formatString)
287 /* Sunday is first day of the week */
288 tmp = days + (6 - cData.wday);
290 else
292 /* Monday is first day of week */
293 if (0 != cData.wday)
294 tmp = days + (7 - cData.wday);
295 else
296 tmp = days;
299 if (tmp < 7)
300 week = 0;
301 else
303 /* cut off the few days that belong to week 0 */
304 tmp -= (tmp % 7);
305 /* Calculate the full amount of weeks */
306 week = tmp / 7;
309 PrintDigits(week, '0', 2, hook, locale);
310 break;
312 case 'w':
313 PrintDigits(cData.wday, -1, 1, hook, locale);
314 break;
316 case 'y':
317 PrintDigits(cData.year % 100, '0', 2, hook, locale);
318 break;
320 case 'Y':
321 PrintDigits(cData.year, '0', 4, hook, locale);
322 break;
324 case 'Z':
325 /* cuurent time zone Unimplemented in 3.1 */
326 break;
328 case 0:
329 break;
331 default:
332 _WriteChar(*formatString, hook, locale);
333 break;
336 else
338 _WriteChar(*formatString, hook, locale);
341 formatString++;
344 _WriteChar(0, hook, locale); /* Write null terminator */
346 AROS_LIBFUNC_EXIT
347 } /* FormatDate */
350 VOID _WriteString(CONST_STRPTR string, const struct Hook *hook,
351 const struct Locale *locale)
353 while(*string != 0)
355 _WriteChar(*string++, hook, locale);
360 VOID _WriteChar(char token, const struct Hook *hook,
361 const struct Locale *locale)
363 AROS_UFC3(VOID, hook->h_Entry,
364 AROS_UFCA(const struct Hook *, hook, A0),
365 AROS_UFCA(const struct Locale *, locale, A2),
366 AROS_UFCA(char, token, A1)
371 VOID PrintDigits(UWORD number, char fill, UWORD len, const struct Hook *hook,
372 const struct Locale *locale)
374 char buf[7];
375 char *ptr = &buf[6];
376 int i = 0;
378 buf[6] = 0;
380 while((number || !i) && i < len)
382 *--ptr = number % 10 + '0';
383 number /= 10;
384 i++;
387 while(len - i > 0 && (char)-1 != fill)
389 len--;
390 _WriteChar(fill, hook, locale);
393 _WriteString((char *)ptr, hook, locale);