grub2: bring back build of aros-side grub2 tools
[AROS.git] / workbench / libs / locale / parsedate.c
bloba16fc3bb5d9861bd54b4f40514ea1c0bbe0e61e8
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <exec/types.h>
7 #include <dos/dos.h>
8 #include <dos/stdio.h>
9 #include <proto/dos.h>
10 #include <aros/asmcall.h>
11 #include "locale_intern.h"
13 static const UWORD monthdays[12] =
14 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
15 static const UBYTE monthday[12] =
16 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
18 BOOL _getnum(LONG numchars,
19 LONG * valPtr,
20 ULONG * cPtr,
21 CONST_STRPTR * fmtTemplatePtr,
22 BOOL * checkEOFPtr,
23 const struct Locale *locale,
24 const struct Hook *getCharFunc, struct LocaleBase *LocaleBase);
25 #define get2num(x) _getnum(2, (x), &c, &fmtTemplate, &checkEOF, locale, getCharFunc, LocaleBase)
26 #define get4num(x) _getnum(4, (x), &c, &fmtTemplate, &checkEOF, locale, getCharFunc, LocaleBase)
28 /*****************************************************************************
30 NAME */
31 #include <proto/locale.h>
33 AROS_LH4(BOOL, ParseDate,
35 /* SYNOPSIS */
36 AROS_LHA(const struct Locale *, locale, A0),
37 AROS_LHA(struct DateStamp *, date, A1),
38 AROS_LHA(CONST_STRPTR , fmtTemplate, A2),
39 AROS_LHA(const struct Hook *, getCharFunc, A3),
41 /* LOCATION */
42 struct LocaleBase *, LocaleBase, 27, Locale)
44 /* FUNCTION
45 This function will convert a stream of characters into an AmigaDOS
46 DateStamp structure. It will obtain its characters from the
47 getCharFunc callback hook, and the given formatting template will
48 be used to direct the parse.
50 INPUTS
51 locale - the locale to use for the formatting
52 date - where to put the converted date. If this is NULL,
53 then this function can be used to verify a date
54 string.
55 fmtTemplate - the date template used to direct the parse of the
56 data. The following FormatDate() formatting
57 controls can be used:
58 %a %A %b %B %d %e %h %H %I %m %M %p %S %y %Y
60 See FormatDate() autodoc for more information.
61 getCharFunc - A callback Hook which is used to read the data
62 from a stream. The hook is called with:
64 A0 - address of the Hook structure
65 A2 - locale pointer
66 A1 - NULL
68 BTW: The AmigaOS autodocs which state that A1
69 gets locale pointer and A2 NULL are wrong!!
71 The read character should be returned in D0. Note
72 that this is a 32 bit character not an 8 bit
73 character. Return a NULL character if you reach the
74 end of the stream.
76 RESULT
77 TRUE - If the parse could be performed.
78 FALSE - If the format of the data did not match the formatting
79 string.
81 NOTES
82 This has a few differences from the implementation in locale.library
83 v38. In particular:
84 - %p does not have to be at the end of the line.
85 - %d and %e are not effectively the same: leading spaces are
86 allowed before %e, but not before %d.
88 EXAMPLE
90 BUGS
91 %p, %b, %A and probably others accept substrings and superstrings of
92 valid strings.
94 SEE ALSO
95 FormatDate()
97 INTERNALS
99 *****************************************************************************/
101 AROS_LIBFUNC_INIT
103 ULONG c;
104 LONG day = 0, month = 0, hour = 0, min = 0, sec = 0;
105 LONG year = 1978;
106 BOOL leap, am = FALSE, pm = FALSE, checkEOF = TRUE;
107 if ((fmtTemplate == NULL)
108 || (getCharFunc == NULL)
109 || (locale == NULL) || (*fmtTemplate == '\0'))
110 return FALSE;
112 #define GetChar()\
113 AROS_UFC3(ULONG, getCharFunc->h_Entry, \
114 AROS_UFCA(const struct Hook *, getCharFunc, A0), \
115 AROS_UFCA(const struct Locale *, locale, A2), \
116 AROS_UFCA(ULONG, 0, A1))
118 while (*fmtTemplate)
120 /* Check for EOF if we leave the loop */
121 checkEOF = TRUE;
123 if (*fmtTemplate == '%')
125 UBYTE strOffs = 0;
126 fmtTemplate++;
128 switch (*fmtTemplate++)
130 /* abbreviated weekday name */
131 case 'a':
132 strOffs = 7;
133 /* weekday name */
134 case 'A':
136 CONST_STRPTR dayStr[7];
137 BOOL dayOk[7];
138 ULONG i, a;
140 for (i = 0; i < 7; i++)
142 dayOk[i] = TRUE;
143 dayStr[i] = GetLocaleStr(locale, i + strOffs + 1);
146 c = GetChar();
147 while ((c != '\0') && (c != *fmtTemplate))
149 for (i = 0; i < 7; i++)
151 a = ConvToUpper(locale, *(dayStr[i])++);
152 c = ConvToUpper(locale, c);
154 if (dayOk[i] && a)
155 if (a != c)
156 dayOk[i] = FALSE;
158 c = GetChar();
161 /* End of stream in wrong place, or invalid */
162 if (((c == '\0') && *fmtTemplate)
163 || (c != *fmtTemplate))
164 return FALSE;
166 /* If we didn't get a valid day, fail */
167 i = 0;
168 while ((i < 7) && !dayOk[i++])
170 if ((i == 7) && !dayOk[6])
171 return FALSE;
173 if (*fmtTemplate)
174 fmtTemplate++;
175 checkEOF = FALSE;
177 break; /* case 'A': */
179 /* abbreviated month name */
180 case 'b':
181 /* abbreviated month name */
182 case 'h':
183 /* month name */
184 case 'B':
186 CONST_STRPTR monthStr[24];
187 BOOL monthOk[24];
188 ULONG i, a;
190 for (i = 0; i < 24; i++)
192 monthOk[i] = TRUE;
193 monthStr[i] =
194 GetLocaleStr(locale, i + strOffs + MON_1);
197 c = GetChar();
198 while ((c != '\0') && (c != *fmtTemplate))
200 for (i = 0; i < 24; i++)
202 a = ConvToUpper(locale, *monthStr[i]);
203 if (a != '\0')
204 monthStr[i]++;
205 c = ConvToUpper(locale, c);
207 if (monthOk[i])
208 if (a != c)
209 monthOk[i] = FALSE;
211 c = GetChar();
213 for (i = 0; i < 24; i++)
215 if (monthOk[i] && *monthStr[i] == '\0')
216 month = i % 12 + 1;
219 /* If we didn't get a valid month, fail */
220 if (month == 0)
221 return FALSE;
223 /* End of stream in wrong place, or invalid */
224 if (((c == '\0') && *fmtTemplate)
225 || (c != *fmtTemplate))
226 return FALSE;
228 if (*fmtTemplate)
229 fmtTemplate++;
230 checkEOF = FALSE;
232 break;
233 } /* case 'B': */
235 /* Day no */
236 case 'd':
237 day = 0;
238 c = GetChar();
239 if (!get2num(&day))
240 return FALSE;
241 if (day-- == 0)
242 return FALSE;
244 break;
245 /* Day no., leading spaces. */
246 case 'e':
247 day = 0;
248 c = GetChar();
249 while (IsSpace(locale, c))
250 c = GetChar();
251 if (!get2num(&day))
252 return FALSE;
253 if (day-- == 0)
254 return FALSE;
256 break;
258 /* hour 24-hr style */
259 case 'H':
260 am = pm = FALSE;
261 c = GetChar();
262 if (!get2num(&hour))
263 return FALSE;
264 if (hour > 23)
265 return FALSE;
266 break;
268 /* hour 12-hr style */
269 case 'I':
270 c = GetChar();
271 if (!get2num(&hour))
272 return FALSE;
273 if ((hour > 12) || (hour == 0))
274 return FALSE;
275 break;
277 /* month num */
278 case 'm':
279 c = GetChar();
280 if (!get2num(&month))
281 return FALSE;
282 if ((month > 12) || (month == 0))
283 return FALSE;
284 break;
286 /* minutes */
287 case 'M':
288 c = GetChar();
289 if (!get2num(&min))
290 return FALSE;
292 if (min > 59)
293 return FALSE;
294 break;
296 /* AM or PM string */
297 case 'p':
299 CONST_STRPTR amStr, pmStr;
300 BOOL amOk = TRUE, pmOk = TRUE;
301 ULONG a, b;
302 amStr = GetLocaleStr(locale, AM_STR);
303 pmStr = GetLocaleStr(locale, PM_STR);
305 c = GetChar();
306 while ((c != '\0') && (c != *fmtTemplate))
308 a = ConvToUpper(locale, *amStr++);
309 b = ConvToUpper(locale, *pmStr++);
310 c = ConvToUpper(locale, c);
312 if (amOk && a)
313 if (a != c)
314 amOk = FALSE;
316 if (pmOk && b)
317 if (b != c)
318 pmOk = FALSE;
320 c = GetChar();
323 /* End of stream in wrong place, or invalid */
324 if (c != *fmtTemplate)
325 return FALSE;
327 /* Check whether we got AM or PM */
328 am = amOk;
329 pm = pmOk;
331 if (*fmtTemplate)
332 fmtTemplate++;
333 checkEOF = FALSE;
334 break;
337 /* the number of seconds */
338 case 'S':
339 c = GetChar();
340 if (!get2num(&sec))
341 return FALSE;
342 if (sec > 59)
343 return FALSE;
344 break;
346 /* the year using two or four digits */
347 case 'y':
348 c = GetChar();
349 if (!get4num(&year))
350 return FALSE;
352 if (year >= 100 && year < 1978)
353 return FALSE;
354 if (year < 78)
355 year += 100;
356 if (year < 1900)
357 year += 1900;
358 break;
360 /* the year using four digits */
361 case 'Y':
362 c = GetChar();
363 if (IsDigit(locale, c) == FALSE)
364 return FALSE;
365 year = (c - '0') * 1000;
367 c = GetChar();
368 if (IsDigit(locale, c) == FALSE)
369 return FALSE;
370 year += (c - '0') * 100;
372 c = GetChar();
373 if (IsDigit(locale, c) == FALSE)
374 return FALSE;
375 year += (c - '0') * 10;
377 c = GetChar();
378 if (IsDigit(locale, c) == FALSE)
379 return FALSE;
380 year += (c - '0');
382 if (year < 1978)
383 return FALSE;
384 break;
386 default:
387 return FALSE;
388 break;
389 } /* switch() */
390 } /* if (char == '%') */
391 else
393 c = GetChar();
394 if (c != *fmtTemplate++)
395 return FALSE;
397 } /* while (*fmtTemplate) */
399 /* Reached end of fmtTemplate, end of input stream? */
400 if (checkEOF)
401 if ((GetChar() != 0))
402 return FALSE;
404 /* Is this year a leap year ? */
405 leap = (((year % 400) == 0) ||
406 (((year % 4) == 0) && !((year % 100) == 0)));
408 /* Sanity check */
409 if (month != 0 && day >=
410 (monthday[month - 1] + ((leap && (month == 2)) ? 1 : 0)))
412 return FALSE;
415 if (date)
417 /* Add the days for all years (without leap years) */
418 day += (year - 1978) * 365;
420 year--;
422 /* Add leap years */
423 day += ((year / 4) - (year / 100) + (year / 400) - (494 - 19 + 4));
425 /* Add days of months */
426 day += monthdays[month - 1];
429 in monthdays, February has 28 days. Correct this in
430 leap years if month is >= March.
433 if (leap && (month >= 3))
434 day++;
436 date->ds_Days = day;
438 date->ds_Minute = hour * 60 + min;
439 if ((hour == 12) && am)
440 date->ds_Minute -= 720;
441 if ((hour < 12) && pm)
442 date->ds_Minute += 720;
443 date->ds_Tick = sec * TICKS_PER_SECOND;
445 return TRUE;
447 AROS_LIBFUNC_EXIT
451 BOOL _getnum(LONG numchars,
452 LONG * valPtr,
453 ULONG * cPtr,
454 CONST_STRPTR * fmtTemplatePtr,
455 BOOL * checkEOFPtr,
456 const struct Locale * locale,
457 const struct Hook * getCharFunc, struct LocaleBase * LocaleBase)
459 LONG val;
460 ULONG c;
462 c = *cPtr;
463 //*c = GetChar();
464 if (IsDigit(locale, c) == FALSE)
465 return FALSE;
467 val = c - '0';
469 while (--numchars >= 1)
471 c = GetChar();
472 if (IsDigit(locale, c))
473 val = val * 10 + c - '0';
474 else
476 *cPtr = c;
477 if (c != **fmtTemplatePtr)
478 return FALSE;
479 if (c == '\0')
480 *checkEOFPtr = FALSE;
481 else
482 (*fmtTemplatePtr)++;
484 break;
488 *valPtr = val;
490 return TRUE;