Commit ea8772cd ea8772cd3bb401e2a3e2f992a1ae570d3b99abdb by Sergey Poznyakoff

Improve mu_scan_datetime

* libmailutils/base/date.c (mu_scan_datetime): Handle optional
blocks (%[ %| %], alternatives %( %| %), "any character"
wildcards (%?) and strict character matches (%\C).  Return
MU_ERR_FORMAT on errors in format string.
Compute tm->tm_yday.
* libmailutils/diag/errors (MU_ERR_FORMAT): New error code.
* libmailutils/tests/scantime.c: Print yday.  Print input line with
diagnostic messages.
* libmailutils/tests/scantime.at: Add more tests.
* include/mailutils/util.h (MU_DATETIME_RFC822): Split into two
formats: MU_DATETIME_FORM_RFC822, for output formatting, and
MU_DATETIME_SCAN_RFC822 for input scanning.  All uses changed.
1 parent 561a4274
...@@ -75,9 +75,12 @@ int mu_scan_datetime (const char *input, const char *fmt, struct tm *tm, ...@@ -75,9 +75,12 @@ int mu_scan_datetime (const char *input, const char *fmt, struct tm *tm,
75 #define MU_DATETIME_FROM "%a %b %e %H:%M:%S %Y" 75 #define MU_DATETIME_FROM "%a %b %e %H:%M:%S %Y"
76 #define MU_DATETIME_IMAP "%d-%b-%Y %H:%M:%S %z" 76 #define MU_DATETIME_IMAP "%d-%b-%Y %H:%M:%S %z"
77 #define MU_DATETIME_INTERNALDATE "%d-%b-%Y%$ %H:%M:%S %z" 77 #define MU_DATETIME_INTERNALDATE "%d-%b-%Y%$ %H:%M:%S %z"
78 /* FIXME: [%a, ] part is actually optional */
79 #define MU_DATETIME_RFC822 "%a, %e %b %Y %H:%M:%S %z"
80 78
79 /* RFC2822 date. Scan format contains considerable allowances which would
80 stun formatting functions, therefore two distinct formats are provided:
81 one for outputting and one for scanning: */
82 #define MU_DATETIME_FORM_RFC822 "%a, %e %b %Y %H:%M:%S %z"
83 #define MU_DATETIME_SCAN_RFC822 "%[%a, %]%e %b %Y %H:%M%[:%S%] %z"
81 84
82 /* ----------------------- */ 85 /* ----------------------- */
83 /* File & path names. */ 86 /* File & path names. */
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
22 #include <stdio.h> 22 #include <stdio.h>
23 #include <stdlib.h> 23 #include <stdlib.h>
24 #include <string.h> 24 #include <string.h>
25 #include <mailutils/diag.h>
25 #include <mailutils/util.h> 26 #include <mailutils/util.h>
26 #include <mailutils/stream.h> 27 #include <mailutils/stream.h>
27 #include <mailutils/errno.h> 28 #include <mailutils/errno.h>
...@@ -53,8 +54,7 @@ static int month_start[]= ...@@ -53,8 +54,7 @@ static int month_start[]=
53 31 28 31 30 31 30 31 31 30 31 30 31 54 31 28 31 30 31 30 31 31 30 31 30 31
54 */ 55 */
55 56
56 /* NOTE: ignore GCC warning. The precedence of operators is OK here */ 57 #define leap_year(y) ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))
57 #define leap_year(y) ((y) % 4 == 0 && (y) % 100 != 0 || (y) % 400 == 0)
58 58
59 static int 59 static int
60 dayofyear (int year, int month, int day) 60 dayofyear (int year, int month, int day)
...@@ -625,6 +625,203 @@ get_num (const char *str, char **endp, int ndig, int minval, int maxval, ...@@ -625,6 +625,203 @@ get_num (const char *str, char **endp, int ndig, int minval, int maxval,
625 #define DT_MIN 0x20 625 #define DT_MIN 0x20
626 #define DT_SEC 0x40 626 #define DT_SEC 0x40
627 627
628 #define ST_NON -1
629 #define ST_OPT 0
630 #define ST_ALT 1
631
632 struct save_input
633 {
634 int state;
635 const char *input;
636 };
637
638 static int
639 push_input (mu_list_t *plist, int state, const char *input)
640 {
641 mu_list_t list = *plist;
642 struct save_input *inp = malloc (sizeof (*inp));
643 if (!inp)
644 return ENOMEM;
645 if (!list)
646 {
647 int rc = mu_list_create (&list);
648 if (rc)
649 {
650 free (inp);
651 return rc;
652 }
653 mu_list_set_destroy_item (list, mu_list_free_item);
654 *plist = list;
655 }
656 inp->state = state;
657 inp->input = input;
658 return mu_list_push (list, (void*)inp);
659 }
660
661 static int
662 peek_state (mu_list_t list, int *state, const char **input)
663 {
664 int rc;
665 struct save_input *inp;
666
667 rc = mu_list_tail (list, (void**)&inp);
668 if (rc)
669 return rc;
670 *state = inp->state;
671 if (input)
672 *input = inp->input;
673 return 0;
674 }
675
676 static int
677 change_top_input (mu_list_t list, const char *input)
678 {
679 int rc;
680 struct save_input *inp;
681
682 rc = mu_list_tail (list, (void**)&inp);
683 if (rc)
684 return rc;
685 inp->input = input;
686 return 0;
687 }
688
689 static int
690 pop_input (mu_list_t list, int *state, const char **input)
691 {
692 int rc;
693 struct save_input *inp;
694
695 rc = mu_list_pop (list, (void**)&inp);
696 if (rc)
697 return rc;
698 *state = inp->state;
699 if (input)
700 *input = inp->input;
701 return 0;
702 }
703
704 static int
705 bracket_to_state (int c)
706 {
707 switch (c)
708 {
709 case '[':
710 case ']':
711 return ST_OPT;
712 case '(':
713 case ')':
714 return ST_ALT;
715 }
716 return ST_NON;
717 }
718
719 static int
720 state_to_closing_bracket (int st)
721 {
722 switch (st)
723 {
724 case ST_OPT:
725 return ']';
726 case ST_ALT:
727 return ')';
728 }
729 return '?';
730 }
731
732 static int
733 scan_recovery (const char *fmt, mu_list_t *plist, int skip_alt,
734 const char **endp,
735 const char **input)
736 {
737 int c, rc = 0;
738 int nesting_level = 1;
739 int st;
740 const char *p;
741
742 while (*fmt)
743 {
744 c = *fmt++;
745
746 if (c == '%')
747 {
748 c = *fmt++;
749 if (!c)
750 {
751 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
752 ("%s:%d: error in format: %% at the end of input",
753 __FILE__, __LINE__));
754 rc = MU_ERR_FORMAT;
755 break;
756 }
757
758 switch (c)
759 {
760 case '[':
761 case '(':
762 nesting_level++;
763 rc = push_input (plist, bracket_to_state (c), NULL);
764 break;
765
766 case ')':
767 case ']':
768 rc = pop_input (*plist, &st, &p);
769 if (rc || st != bracket_to_state (c))
770 {
771 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
772 ("%s:%d: error in format: %%%c out of context",
773 __FILE__, __LINE__, c));
774 rc = MU_ERR_FORMAT;
775 break;
776 }
777 if (--nesting_level == 0)
778 {
779 *endp = fmt;
780 if (skip_alt)
781 return 0;
782 *input = p;
783 if (st == ST_ALT)
784 {
785 if (*fmt == '%' && (fmt[1] == '|' || fmt[1] == ']'))
786 return 0;
787 return MU_ERR_PARSE; /* No match found */
788 }
789 return 0;
790 }
791 break;
792
793 case '|':
794 if (skip_alt)
795 continue;
796 if (nesting_level == 1)
797 {
798 *endp = fmt;
799 return peek_state (*plist, &st, input);
800 }
801 break;
802
803 case '\\':
804 if (*++fmt == 0)
805 {
806 peek_state (*plist, &st, NULL);
807 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
808 ("%s:%d: error in format: missing closing %%%c",
809 __FILE__, __LINE__,
810 state_to_closing_bracket (st)));
811 return MU_ERR_FORMAT;
812 }
813 }
814 }
815 }
816
817 peek_state (*plist, &st, NULL);
818 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
819 ("%s:%d: error in format: missing closing %%%c",
820 __FILE__, __LINE__,
821 state_to_closing_bracket (st)));
822 return MU_ERR_FORMAT;
823 }
824
628 int 825 int
629 mu_scan_datetime (const char *input, const char *fmt, 826 mu_scan_datetime (const char *input, const char *fmt,
630 struct tm *tm, struct mu_timezone *tz, char **endp) 827 struct tm *tm, struct mu_timezone *tz, char **endp)
...@@ -632,8 +829,12 @@ mu_scan_datetime (const char *input, const char *fmt, ...@@ -632,8 +829,12 @@ mu_scan_datetime (const char *input, const char *fmt,
632 int rc = 0; 829 int rc = 0;
633 char *p; 830 char *p;
634 int n; 831 int n;
832 int c;
833 int st;
834 int recovery = 0;
635 int eof_ok = 0; 835 int eof_ok = 0;
636 int datetime_parts = 0; 836 int datetime_parts = 0;
837 mu_list_t save_input_list = NULL;
637 838
638 memset (tm, 0, sizeof *tm); 839 memset (tm, 0, sizeof *tm);
639 #ifdef HAVE_STRUCT_TM_TM_ISDST 840 #ifdef HAVE_STRUCT_TM_TM_ISDST
...@@ -661,7 +862,17 @@ mu_scan_datetime (const char *input, const char *fmt, ...@@ -661,7 +862,17 @@ mu_scan_datetime (const char *input, const char *fmt,
661 862
662 if (*fmt == '%') 863 if (*fmt == '%')
663 { 864 {
664 switch (*++fmt) 865 c = *++fmt;
866 if (!c)
867 {
868 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
869 ("%s:%d: error in format: %% at the end of input",
870 __FILE__, __LINE__));
871 rc = MU_ERR_FORMAT;
872 break;
873 }
874
875 switch (c)
665 { 876 {
666 case 'a': 877 case 'a':
667 /* The abbreviated weekday name. */ 878 /* The abbreviated weekday name. */
...@@ -853,26 +1064,109 @@ mu_scan_datetime (const char *input, const char *fmt, ...@@ -853,26 +1064,109 @@ mu_scan_datetime (const char *input, const char *fmt,
853 rc = MU_ERR_PARSE; 1064 rc = MU_ERR_PARSE;
854 break; 1065 break;
855 1066
1067 rc = push_input (&save_input_list, ST_ALT, (void*)input);
1068 break;
1069
1070 case '(':
1071 case '[':
1072 rc = push_input (&save_input_list, bracket_to_state (c),
1073 (void*)input);
1074 break;
1075
1076 case ')':
1077 case ']':
1078 if (pop_input (save_input_list, &st, NULL))
1079 {
1080 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
1081 ("%s:%d: error in format: unbalanced %%%c near %s",
1082 __FILE__, __LINE__, c, fmt));
1083 rc = MU_ERR_FORMAT;
1084 }
1085 else if (st != bracket_to_state (c))
1086 {
1087 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
1088 ("%s:%d: error in format: %%%c out of context",
1089 __FILE__, __LINE__, c));
1090 rc = MU_ERR_FORMAT;
1091 }
1092 break;
1093
1094 case '|':
1095 rc = scan_recovery (fmt, &save_input_list, 1, &fmt, NULL);
1096 if (rc == 0)
1097 fmt--;
1098 break;
1099
856 case '$': 1100 case '$':
857 eof_ok = 1; 1101 eof_ok = 1;
858 break; 1102 break;
1103
1104 case '\\':
1105 c = *++fmt;
1106 if (!c)
1107 {
1108 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
1109 ("%s:%d: error in format: %% at the end of input",
1110 __FILE__, __LINE__));
1111 rc = MU_ERR_FORMAT;
859 } 1112 }
1113 else if (c == *input)
1114 input++;
1115 else
1116 rc = MU_ERR_PARSE;
1117 break;
1118
1119 case '?':
1120 input++;
1121 break;
1122
1123 default:
1124 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
1125 ("%s:%d: error in format: unrecognized conversion type"
1126 " near %s",
1127 __FILE__, __LINE__, fmt));
1128 rc = MU_ERR_FORMAT;
1129 break;
1130 }
1131
860 if (eof_ok && rc == 0 && *input == 0) 1132 if (eof_ok && rc == 0 && *input == 0)
861 break; 1133 break;
862 } 1134 }
863 else if (*input != *fmt) 1135 else if (!recovery && *input != *fmt)
864 rc = MU_ERR_PARSE; 1136 rc = MU_ERR_PARSE;
865 else 1137 else
866 input++; 1138 input++;
1139
1140 if (rc == MU_ERR_PARSE && !mu_list_is_empty (save_input_list))
1141 {
1142 rc = scan_recovery (fmt, &save_input_list, 0, &fmt, &input);
1143 if (rc == 0)
1144 --fmt;
1145 }
867 } 1146 }
868 1147
1148 if (!mu_list_is_empty (save_input_list))
1149 {
1150 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
1151 ("%s:%d: error in format: closing bracket missing",
1152 __FILE__, __LINE__));
1153 rc = MU_ERR_FORMAT;
1154 }
1155 mu_list_destroy (&save_input_list);
1156
1157 if (rc == 0 && recovery)
1158 rc = MU_ERR_PARSE;
1159
869 if (!eof_ok && rc == 0 && *input == 0 && *fmt) 1160 if (!eof_ok && rc == 0 && *input == 0 && *fmt)
870 rc = MU_ERR_PARSE; 1161 rc = MU_ERR_PARSE;
871 1162
872 if (!(datetime_parts & DT_WDAY) && 1163 if ((datetime_parts & (DT_YEAR|DT_MONTH|DT_MDAY)) ==
873 (datetime_parts & (DT_YEAR|DT_MONTH|DT_MDAY)) ==
874 (DT_YEAR|DT_MONTH|DT_MDAY)) 1164 (DT_YEAR|DT_MONTH|DT_MDAY))
1165 {
1166 if (!(datetime_parts & DT_WDAY))
875 tm->tm_wday = dayofweek (tm->tm_year + 1900, tm->tm_mon, tm->tm_mday); 1167 tm->tm_wday = dayofweek (tm->tm_year + 1900, tm->tm_mon, tm->tm_mday);
1168 tm->tm_yday = dayofyear (tm->tm_year + 1900, tm->tm_mon, tm->tm_mday);
1169 }
876 1170
877 if (endp) 1171 if (endp)
878 *endp = (char*) input; 1172 *endp = (char*) input;
......
...@@ -123,3 +123,5 @@ MU_ERR_PERM_DIR_IWGRP _("File in group writable directory") ...@@ -123,3 +123,5 @@ MU_ERR_PERM_DIR_IWGRP _("File in group writable directory")
123 MU_ERR_PERM_DIR_IWOTH _("File in world writable directory") 123 MU_ERR_PERM_DIR_IWOTH _("File in world writable directory")
124 124
125 MU_ERR_DISABLED _("Requested feature disabled in configuration") 125 MU_ERR_DISABLED _("Requested feature disabled in configuration")
126
127 MU_ERR_FORMAT _("Error in format string")
......
...@@ -30,34 +30,127 @@ m4_popdef([MU_TEST_GROUP]) ...@@ -30,34 +30,127 @@ m4_popdef([MU_TEST_GROUP])
30 ]) 30 ])
31 dnl --------------------------------------------------------------------- 31 dnl ---------------------------------------------------------------------
32 32
33 SCANTIME([RFC-822 time],[rfc822], 33 SCANTIME([Envelope (From) time],[envelope],
34 [%a %b %e %H:%M:%S %Y], 34 [%a %b %e %H:%M:%S %Y],
35 [Tue May 3 13:25:26 2011 35 [Tue May 3 13:25:26 2011
36 Fri Nov 11 11:55:01 2011], 36 Fri Nov 11 11:55:01 2011],
37 [sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,tz=0 37 [sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=0
38 sec=1,min=55,hour=11,mday=11,mon=10,year=111,wday=5,tz=0 38 sec=1,min=55,hour=11,mday=11,mon=10,year=111,wday=5,yday=315,tz=0
39 ]) 39 ])
40 40
41 SCANTIME([IMAP time format],[imap], 41 SCANTIME([IMAP INTERNALDATE],[imap-internaldate],
42 [%d-%b-%Y %H:%M:%S %z], 42 [%d-%b-%Y %H:%M:%S %z],
43 [03-May-2011 13:25:26 +0100 43 [03-May-2011 13:25:26 +0100
44 11-Nov-2011 11:55:01 +0100], 44 11-Nov-2011 11:55:01 +0100],
45 [sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,tz=3600 45 [sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=3600
46 sec=1,min=55,hour=11,mday=11,mon=10,year=111,wday=5,tz=3600 46 sec=1,min=55,hour=11,mday=11,mon=10,year=111,wday=5,yday=315,tz=3600
47 ]) 47 ])
48 48
49 SCANTIME([IMAP search time format],[imap-search], 49 SCANTIME([IMAP INTERNALDATE (optional time)],[imap-search],
50 [%d-%b-%Y%$ %H:%M:%S %z], 50 [%d-%b-%Y%$ %H:%M:%S %z],
51 [03-May-2011 13:25:26 +0100 51 [03-May-2011 13:25:26 +0100
52 03-May-2011], 52 03-May-2011],
53 [sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,tz=3600 53 [sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=3600
54 sec=0,min=0,hour=0,mday=3,mon=4,year=111,wday=2,tz=0 54 sec=0,min=0,hour=0,mday=3,mon=4,year=111,wday=2,yday=123,tz=0
55 ]) 55 ])
56 56
57 SCANTIME([IMAP INTERNALDATE],[imap-internaldate], 57 SCANTIME([RFC-822 Strict],[rfc822-strict],
58 [%a, %d %b %Y %H:%M:%S %z], 58 [%a, %d %b %Y %H:%M:%S %z],
59 [Tue, 03 May 2011 13:25:26 +0200], 59 [Tue, 03 May 2011 13:25:26 +0200],
60 [sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,tz=7200 60 [sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=7200
61 ])
62
63 SCANTIME([RFC-822],[rfc822],
64 [[%[%a, %]%d %b %Y %H:%M%[:%S%] %z]],
65 [Tue, 03 May 2011 13:25:26 +0200
66 03 May 2011 13:25:26 +0200
67 Tue, 03 May 2011 13:25 +0200
68 03 May 2011 13:25 +0200],
69 [sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=7200
70 sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=7200
71 sec=0,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=7200
72 sec=0,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=7200
73 ])
74
75 SCANTIME([Any char],[anychar],
76 [%a%? %d %b %Y %H:%M:%S %z],
77 [Tue, 03 May 2011 13:25:26 +0200
78 Tue: 03 May 2011 13:25:26 +0200
79 Tue; 03 May 2011 13:25:26 +0200
80 Tue 03 May 2011 13:25:26 +0200],
81 [sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=7200
82 sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=7200
83 sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=7200
84 sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=7200
85 ])
86
87 SCANTIME([Percent],[percent],
88 [%d%%%b%%%Y %H:%M:%S %z],
89 [03%May%2011 13:25:26 +0100],
90 [sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=3600
91 ])
92
93 SCANTIME([Fixed WS],[fixws],
94 [%d-%b-%Y%\ %H:%M:%S %z],
95 [03-May-2011 13:25:26 +0100
96 03-May-2011 13:25:26 +0100],
97 [sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=3600
98 ],
99 [scantime: 2: parse failed near 13:25:26 +0100
100 ])
101
102 SCANTIME([endp return],[endp],
103 [%a, %d %b %Y %H:%M:%S %z],
104 [Tue, 03 May 2011 13:25:26 +0100 other data
105 ],
106 [# 1: stopped at other data
107 sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=3600
108 ])
109
110 SCANTIME([Optional blocks],[opt],
111 [[%[%a, %]%d %b %Y %H:%M:%S %z]],
112 [Tue, 03 May 2011 13:25:26 +0200
113 03 May 2011 13:25:26 +0200],
114 [sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=7200
115 sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=7200
116 ])
117
118 SCANTIME([Nested optional blocks],[nested-opt],
119 [[%[%a%[,%] %]%d %b %Y %H:%M:%S %z]],
120 [Tue, 03 May 2011 13:25:26 +0200
121 Tue 03 May 2011 13:25:26 +0200
122 03 May 2011 13:25:26 +0200],
123 [sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=7200
124 sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=7200
125 sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=7200
126 ])
127
128 SCANTIME([Optional alternatives],[opt-alt],
129 [[%a%[,%|:%] %d %b %Y %H:%M:%S %z]],
130 [Tue, 03 May 2011 13:25:26 +0200
131 Tue: 03 May 2011 13:25:26 +0200
132 Tue 03 May 2011 13:25:26 +0200
133 Tue; 03 May 2011 13:25:26 +0200],
134 [sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=7200
135 sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=7200
136 sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=7200
137 ],
138 [scantime: 4: parse failed near ; 03 May 2011 13:25:26 +0200
139 ])
140
141 SCANTIME([Alternatives],[alt],
142 [%a%(,%|:%|/%) %d %b %Y %H:%M:%S %z],
143 [Tue, 03 May 2011 13:25:26 +0200
144 Tue: 03 May 2011 13:25:26 +0200
145 Tue/ 03 May 2011 13:25:26 +0200
146 Tue 03 May 2011 13:25:26 +0200
147 Tue; 03 May 2011 13:25:26 +0200],
148 [sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=7200
149 sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=7200
150 sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,yday=123,tz=7200
151 ],
152 [scantime: 4: parse failed near 03 May 2011 13:25:26 +0200
153 scantime: 5: parse failed near ; 03 May 2011 13:25:26 +0200
61 ]) 154 ])
62 155
63 m4_popdef([SCANTIME]) 156 m4_popdef([SCANTIME])
......
...@@ -45,6 +45,7 @@ main (int argc, char **argv) ...@@ -45,6 +45,7 @@ main (int argc, char **argv)
45 char *buf = NULL; 45 char *buf = NULL;
46 size_t size = 0; 46 size_t size = 0;
47 size_t n; 47 size_t n;
48 int line;
48 49
49 mu_set_program_name (argv[0]); 50 mu_set_program_name (argv[0]);
50 51
...@@ -65,31 +66,34 @@ main (int argc, char **argv) ...@@ -65,31 +66,34 @@ main (int argc, char **argv)
65 } 66 }
66 } 67 }
67 68
69 line = 0;
68 while ((rc = mu_stream_getline (mu_strin, &buf, &size, &n)) == 0 && n > 0) 70 while ((rc = mu_stream_getline (mu_strin, &buf, &size, &n)) == 0 && n > 0)
69 { 71 {
70 char *endp; 72 char *endp;
71 struct tm tm; 73 struct tm tm;
72 struct mu_timezone tz; 74 struct mu_timezone tz;
73 75
76 line++;
77 mu_ltrim_class (buf, MU_CTYPE_BLANK);
74 mu_rtrim_class (buf, MU_CTYPE_ENDLN); 78 mu_rtrim_class (buf, MU_CTYPE_ENDLN);
75 79 if (!*buf)
80 continue;
76 rc = mu_scan_datetime (buf, format, &tm, &tz, &endp); 81 rc = mu_scan_datetime (buf, format, &tm, &tz, &endp);
77 if (rc) 82 if (rc)
78 { 83 {
79 if (*endp) 84 if (*endp)
80 mu_error ("parse failed near %s", endp); 85 mu_error ("%d: parse failed near %s", line, endp);
81 else 86 else
82 mu_error ("parse failed at end of input"); 87 mu_error ("%d: parse failed at end of input", line);
83 continue; 88 continue;
84 } 89 }
85 if (*endp) 90 if (*endp)
86 mu_printf ("# stopped at %s\n", endp); 91 mu_printf ("# %d: stopped at %s\n", line, endp);
87 /* FIXME: add tm_yday? */ 92 mu_printf ("sec=%d,min=%d,hour=%d,mday=%d,mon=%d,year=%d,wday=%d,yday=%d,tz=%d\n",
88 mu_printf ("sec=%d,min=%d,hour=%d,mday=%d,mon=%d,year=%d,wday=%d,tz=%d\n",
89 tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mday, tm.tm_mon, 93 tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mday, tm.tm_mon,
90 tm.tm_year, tm.tm_wday, tz.utc_offset); 94 tm.tm_year, tm.tm_wday, tm.tm_yday, tz.utc_offset);
91 95
92 //mu_c_streamftime (mu_strout, "%c %z%n", &tm, &tz); 96 /*mu_c_streamftime (mu_strout, "%c %z%n", &tm, &tz);*/
93 } 97 }
94 98
95 if (rc) 99 if (rc)
......
...@@ -472,7 +472,7 @@ _fill_response (void *item, void *data) ...@@ -472,7 +472,7 @@ _fill_response (void *item, void *data)
472 else 472 else
473 { 473 {
474 if (mu_scan_datetime (elt->v.string, 474 if (mu_scan_datetime (elt->v.string,
475 MU_DATETIME_RFC822, 475 MU_DATETIME_SCAN_RFC822,
476 &env->envelope->date, 476 &env->envelope->date,
477 &env->envelope->tz, NULL)) 477 &env->envelope->tz, NULL))
478 rc = MU_ERR_FAILURE; 478 rc = MU_ERR_FAILURE;
......