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.
Showing
6 changed files
with
424 additions
and
28 deletions
... | @@ -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; | ... | ... |
-
Please register or sign in to post a comment