2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
6 #include <exec/types.h>
10 #include <aros/asmcall.h>
11 #include "locale_intern.h"
13 #define STOP_BRAIN_DAMAGE 1 /* Oh please, do single char numbers! - Piru */
15 static const UWORD monthdays
[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
16 static const UBYTE monthday
[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
19 BOOL
_getnum(LONG numchars
,
22 STRPTR
*fmtTemplatePtr
,
24 struct Locale
*locale
,
25 struct Hook
*getCharFunc
,
26 struct LocaleBase
*LocaleBase
);
27 #define get2num(x) _getnum(2, (x), &c, &fmtTemplate, &checkEOF, locale, getCharFunc, LocaleBase)
28 #define get4num(x) _getnum(4, (x), &c, &fmtTemplate, &checkEOF, locale, getCharFunc, LocaleBase)
31 /*****************************************************************************
34 #include <proto/locale.h>
36 AROS_LH4(BOOL
, ParseDate
,
39 AROS_LHA(struct Locale
*, locale
, A0
),
40 AROS_LHA(struct DateStamp
*, date
, A1
),
41 AROS_LHA(STRPTR
, fmtTemplate
, A2
),
42 AROS_LHA(struct Hook
*, getCharFunc
, A3
),
45 struct LocaleBase
*, LocaleBase
, 27, Locale
)
48 This function will convert a stream of characters into an AmigaDOS
49 DateStamp structure. It will obtain its characters from the
50 getCharFunc callback hook, and the given formatting template will
51 be used to direct the parse.
54 locale - the locale to use for the formatting
55 date - where to put the converted date. If this is NULL,
56 then this function can be used to verify a date
58 fmtTemplate - the date template used to direct the parse of the
59 data. The following FormatDate() formatting
61 %a %A %b %B %d %e %h %H %I %m %M %p %S %y %Y
63 See FormatDate() autodoc for more information.
64 getCharFunc - A callback Hook which is used to read the data
65 from a stream. The hook is called with:
67 A0 - address of the Hook structure
71 BTW: The AmigaOS autodocs which state that A1
72 gets locale pointer and A2 NULL are wrong!!
74 The read character should be returned in D0. Note
75 that this is a 32 bit character not an 8 bit
76 character. Return a NULL character if you reach the
80 TRUE - If the parse could be performed.
81 FALSE - If the format of the data did not match the formatting
85 This has a few differences from the implementation in locale.library
87 - %p does not have to be at the end of the line.
88 - %d and %e are not effectively the same, ie %d requires a leading
89 zero, but %e can not handle leading 0's.
94 %d, %e probably needs some work.
101 *****************************************************************************/
106 LONG day
= 0, month
= 0, hour
= 0, min
= 0, sec
= 0;
108 BOOL leap
, ampm
= FALSE
, checkEOF
= TRUE
;
109 if ( (fmtTemplate
== NULL
)
110 || (getCharFunc
== NULL
)
112 || (*fmtTemplate
== '\0')
117 AROS_UFC3(ULONG, getCharFunc->h_Entry, \
118 AROS_UFCA(struct Hook *, getCharFunc, A0), \
119 AROS_UFCA(struct Locale *, locale, A2), \
120 AROS_UFCA(ULONG, 0, A1))
124 /* Check for EOF if we leave the loop */
127 if (*fmtTemplate
== '%')
132 switch(*fmtTemplate
++)
134 /* abbreviated weekday name */
144 for (i
= 0; i
< 7; i
++)
147 dayStr
[i
] = GetLocaleStr(locale
, i
+ strOffs
+ 1);
151 while ((c
!= '\0') && (c
!= *fmtTemplate
))
153 for (i
=0; i
< 7; i
++)
155 a
= ConvToUpper(locale
, *(dayStr
[i
])++);
156 c
= ConvToUpper(locale
, c
);
159 if (a
!= c
) dayOk
[i
] = FALSE
;
164 /* End of stream in wrong place, or invalid */
165 if (((c
== '\0') && *fmtTemplate
) || (c
!= *fmtTemplate
))
168 /* If we didn't get a valid day, fail */
170 while ((i
< 7) && (dayOk
[i
++] == FALSE
))
172 if ((i
== 7) && (dayOk
[6] == FALSE
))
175 if (*fmtTemplate
) fmtTemplate
++;
177 } break; /* case 'A': */
179 /* abbreviated month name */
181 /* abbreviated month name */
191 for (i
= 0; i
< 12; i
++)
194 monthStr
[i
] = GetLocaleStr(locale
, i
+ strOffs
+ MON_1
);
198 while ((c
!= '\0') && (c
!= *fmtTemplate
))
200 for (i
=0; i
< 12; i
++)
202 a
= ConvToUpper(locale
, *(monthStr
[i
])++);
203 c
= ConvToUpper(locale
, c
);
206 if (a
!= c
) monthOk
[i
] = FALSE
;
211 /* End of stream in wrong place, or invalid */
212 if (((c
== '\0') && *fmtTemplate
) || (c
!= *fmtTemplate
))
215 /* If we didn't get a valid month, fail */
217 while ((i
< 12) && (monthOk
[i
++] == FALSE
))
219 if ((i
== 12) && (monthOk
[11] == FALSE
))
223 if (*fmtTemplate
) fmtTemplate
++;
233 if (IsDigit(locale
, c
) == FALSE
)
236 day
= (c
- '0') * 10;
238 if (IsDigit(locale
, c
) == FALSE
)
242 /* Day 0 is undefined. */
243 if (day
== 0) return FALSE
;
246 /* day is unsigned, so day < 0 is not possible */
253 /* These are really the same - Piru. */
257 /* Day no., leading spaces. */
262 while (IsSpace(locale
, c
) == TRUE
)
268 /* Day 0 is undefined. */
273 /* day is unsigned, so day < 0 is not possible */
279 /* Day no., leading spaces. */
284 while (IsSpace(locale
, c
) == TRUE
)
287 if (IsDigit(locale
, c
) == FALSE
)
292 if (IsDigit(locale
, c
) == TRUE
)
299 if (c
!= *fmtTemplate
++)
304 if (day
== 0) return FALSE
;
310 /* hour 24-hr style */
313 #if STOP_BRAIN_DAMAGE
319 if (IsDigit(locale
, c
) == FALSE
)
326 if (IsDigit(locale
, c
) == FALSE
)
330 if (hour
> 23) return FALSE
;
333 /* hour 12-hr style */
335 #if STOP_BRAIN_DAMAGE
341 if (IsDigit(locale
, c
) == FALSE
)
348 if (IsDigit(locale
, c
) == FALSE
)
352 if (hour
> 11) return FALSE
;
357 #if STOP_BRAIN_DAMAGE
359 if (!get2num(&month
))
363 if (IsDigit(locale
, c
) == FALSE
)
366 month
= (c
- '0') * 10;
368 if (IsDigit(locale
, c
) == FALSE
)
372 if ((month
> 12) || (month
== 0))
378 #if STOP_BRAIN_DAMAGE
384 if (IsDigit(locale
, c
) == FALSE
)
387 min
= (c
- '0') * 10;
389 if (IsDigit(locale
, c
) == FALSE
)
394 if (min
> 59) return FALSE
;
397 /* AM or PM string */
401 BOOL amOk
= TRUE
, pmOk
= TRUE
;
403 amStr
= GetLocaleStr(locale
, AM_STR
);
404 pmStr
= GetLocaleStr(locale
, PM_STR
);
407 while ((c
!= '\0') && (c
!= *fmtTemplate
))
409 a
= ConvToUpper(locale
, *amStr
++);
410 b
= ConvToUpper(locale
, *pmStr
++);
411 c
= ConvToUpper(locale
, c
);
414 if (a
!= c
) amOk
= FALSE
;
417 if (b
!= c
) pmOk
= FALSE
;
422 /* End of stream in wrong place, or invalid */
423 if (((c
== '\0') && *fmtTemplate
) || (c
!= *fmtTemplate
))
426 /* Check whether we got AM or PM */
427 if (pmOk
== TRUE
) ampm
= TRUE
;
428 else if (amOk
== TRUE
) ampm
= FALSE
;
430 if (*fmtTemplate
) fmtTemplate
++;
435 /* the number of seconds */
437 #if STOP_BRAIN_DAMAGE
443 if (IsDigit(locale
, c
) == FALSE
)
446 sec
= (c
- '0') * 10;
448 if (IsDigit(locale
, c
) == FALSE
)
452 if (sec
> 59) return FALSE
;
455 /* the year using two or four digits */
457 #if STOP_BRAIN_DAMAGE
472 if (IsDigit(locale
, c
) == FALSE
)
475 year
= (c
- '0') * 10;
477 if (IsDigit(locale
, c
) == FALSE
)
480 year
+= (year
< 78) ? 2000 : 1900;
484 /* the year using four digits */
487 if (IsDigit(locale
, c
) == FALSE
)
489 year
= (c
- '0') * 1000;
492 if (IsDigit(locale
, c
) == FALSE
)
494 year
+= (c
- '0') * 100;
497 if (IsDigit(locale
, c
) == FALSE
)
499 year
+= (c
- '0') * 10;
502 if (IsDigit(locale
, c
) == FALSE
)
514 } /* if (char == '%') */
518 if (c
!= *fmtTemplate
++)
521 } /* while (*fmtTemplate) */
523 /* Reached end of fmtTemplate, end of input stream? */
525 if ((GetChar() != 0)) return FALSE
;
527 /* Is this year a leap year ? */
528 leap
= (((year
% 400) == 0) ||
529 (((year
% 4) == 0) && !((year
% 100) == 0)));
531 /* Sanity check - Piru */
533 (monthday
[month
- 1] + ((leap
&& (month
== 2)) ? 1 : 0)))
541 /* stegerg: based on dos.library/strtodate */
543 /* First year must be 1978 */
547 /* Add the days for all years (without leap years) */
548 day
+= (year
- 1978) * 365;
553 day
+= ((year
/ 4) - (year
/ 100) + (year
/ 400)
556 /* Add days of months */
557 day
+= monthdays
[month
- 1];
560 in monthdays, February has 28 days. Correct this in
561 leap years if month is >= March.
564 if (leap
&& (month
>= 3)) day
++;
572 day
+= (year
-3) / 4 + 1;
573 else if ((year
== 2) && (month
> 2))
576 date
->ds_Days
= year
* 365 + day
+ monthdays
[month
- 1];
579 date
->ds_Minute
= hour
* 60 + min
;
580 if ((hour
< 12) && ampm
)
581 date
->ds_Minute
+= 720;
582 date
->ds_Tick
= sec
* TICKS_PER_SECOND
;
590 #if STOP_BRAIN_DAMAGE
592 BOOL
_getnum(LONG numchars
,
595 STRPTR
*fmtTemplatePtr
,
597 struct Locale
*locale
,
598 struct Hook
*getCharFunc
,
599 struct LocaleBase
*LocaleBase
)
606 if (IsDigit(locale
, c
) == FALSE
)
611 while (--numchars
>= 1)
614 if (IsDigit(locale
, c
))
615 val
= val
* 10 + c
- '0';
619 if (c
!= *(*fmtTemplatePtr
)++)
622 *checkEOFPtr
= FALSE
;