Mercurial > pidgin
comparison libpurple/util.c @ 31123:c61d3e5ec1da
Fix purple_str_to_time(). Fixes #13131.
committer: John Bailey <rekkanoryo@rekkanoryo.org>
author | morshed.nader@gmail.com |
---|---|
date | Sun, 09 Jan 2011 20:08:29 +0000 |
parents | a8cc50c2279f |
children | 1e1b598c725e 73b005a20d06 |
comparison
equal
deleted
inserted
replaced
31115:80db1ca54fb6 | 31123:c61d3e5ec1da |
---|---|
662 tm.tm_sec = sec >= 0 ? sec : time(NULL) % 60; | 662 tm.tm_sec = sec >= 0 ? sec : time(NULL) % 60; |
663 | 663 |
664 return mktime(&tm); | 664 return mktime(&tm); |
665 } | 665 } |
666 | 666 |
667 /* originally taken from GLib trunk 1-6-11 */ | |
668 /* originally licensed as LGPL 2+ */ | |
669 static time_t | |
670 mktime_utc(struct tm *tm) | |
671 { | |
672 time_t retval; | |
673 | |
674 #ifndef HAVE_TIMEGM | |
675 static const gint days_before[] = | |
676 { | |
677 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 | |
678 }; | |
679 #endif | |
680 | |
681 #ifndef HAVE_TIMEGM | |
682 if (tm->tm_mon < 0 || tm->tm_mon > 11) | |
683 return (time_t) -1; | |
684 | |
685 retval = (tm->tm_year - 70) * 365; | |
686 retval += (tm->tm_year - 68) / 4; | |
687 retval += days_before[tm->tm_mon] + tm->tm_mday - 1; | |
688 | |
689 if (tm->tm_year % 4 == 0 && tm->tm_mon < 2) | |
690 retval -= 1; | |
691 | |
692 retval = ((((retval * 24) + tm->tm_hour) * 60) + tm->tm_min) * 60 + tm->tm_sec; | |
693 #else | |
694 retval = timegm (tm); | |
695 #endif /* !HAVE_TIMEGM */ | |
696 | |
697 return retval; | |
698 } | |
699 | |
667 time_t | 700 time_t |
668 purple_str_to_time(const char *timestamp, gboolean utc, | 701 purple_str_to_time(const char *timestamp, gboolean utc, |
669 struct tm *tm, long *tz_off, const char **rest) | 702 struct tm *tm, long *tz_off, const char **rest) |
670 { | 703 { |
671 time_t retval = 0; | 704 struct tm t; |
672 static struct tm t; | 705 const gchar *str; |
673 const char *c = timestamp; | 706 gint year = 0; |
674 int year = 0; | |
675 long tzoff = PURPLE_NO_TZ_OFF; | 707 long tzoff = PURPLE_NO_TZ_OFF; |
676 | 708 time_t retval; |
677 time(&retval); | 709 gboolean mktime_with_utc = TRUE; |
678 localtime_r(&retval, &t); | |
679 | 710 |
680 if (rest != NULL) | 711 if (rest != NULL) |
681 *rest = NULL; | 712 *rest = NULL; |
682 | 713 |
714 g_return_val_if_fail(timestamp != NULL, 0); | |
715 | |
716 str = timestamp; | |
717 | |
718 /* Strip leading whitespace */ | |
719 while (g_ascii_isspace(*str)) | |
720 str++; | |
721 | |
722 if (*str == '\0') { | |
723 if (rest != NULL && *str != '\0') | |
724 *rest = str; | |
725 | |
726 return 0; | |
727 } | |
728 | |
729 if (!g_ascii_isdigit(*str) && *str != '-' && *str != '+') { | |
730 if (rest != NULL && *str != '\0') | |
731 *rest = str; | |
732 | |
733 return 0; | |
734 } | |
735 | |
683 /* 4 digit year */ | 736 /* 4 digit year */ |
684 if (sscanf(c, "%04d", &year) && year > 1900) | 737 if (sscanf(str, "%04d", &year) && year >= 1900) { |
685 { | 738 str += 4; |
686 c += 4; | 739 |
687 if (*c == '-') | 740 if (*str == '-' || *str == '/') |
688 c++; | 741 str++; |
742 | |
689 t.tm_year = year - 1900; | 743 t.tm_year = year - 1900; |
690 } | 744 } |
691 | 745 |
692 /* 2 digit month */ | 746 /* 2 digit month */ |
693 if (!sscanf(c, "%02d", &t.tm_mon)) | 747 if (!sscanf(str, "%02d", &t.tm_mon)) { |
694 { | 748 if (rest != NULL && *str != '\0') |
695 if (rest != NULL && *c != '\0') | 749 *rest = str; |
696 *rest = c; | 750 |
697 return 0; | 751 return 0; |
698 } | 752 } |
699 c += 2; | 753 |
700 if (*c == '-' || *c == '/') | 754 str += 2; |
701 c++; | |
702 t.tm_mon -= 1; | 755 t.tm_mon -= 1; |
703 | 756 |
757 if (*str == '-' || *str == '/') | |
758 str++; | |
759 | |
704 /* 2 digit day */ | 760 /* 2 digit day */ |
705 if (!sscanf(c, "%02d", &t.tm_mday)) | 761 if (!sscanf(str, "%02d", &t.tm_mday)) { |
706 { | 762 if (rest != NULL && *str != '\0') |
707 if (rest != NULL && *c != '\0') | 763 *rest = str; |
708 *rest = c; | 764 |
709 return 0; | 765 return 0; |
710 } | 766 } |
711 c += 2; | 767 |
712 if (*c == '/') | 768 str += 2; |
713 { | 769 |
714 c++; | 770 /* Grab the year off the end if there's still stuff */ |
715 | 771 if (*str == '/' || *str == '-') { |
716 if (!sscanf(c, "%04d", &t.tm_year)) | 772 /* But make sure we don't read the year twice */ |
773 if (year >= 1900) { | |
774 if (rest != NULL && *str != '\0') | |
775 *rest = str; | |
776 | |
777 return 0; | |
778 } | |
779 | |
780 str++; | |
781 | |
782 if (!sscanf(str, "%04d", &t.tm_year)) { | |
783 if (rest != NULL && *str != '\0') | |
784 *rest = str; | |
785 | |
786 return 0; | |
787 } | |
788 | |
789 t.tm_year -= 1900; | |
790 } else if (*str == 'T' || *str == '.') { | |
791 str++; | |
792 | |
793 /* Continue grabbing the hours/minutes/seconds */ | |
794 if ((sscanf(str, "%02d:%02d:%02d", &t.tm_hour, &t.tm_min, &t.tm_sec) == 3 && | |
795 (str += 8)) || | |
796 (sscanf(str, "%02d%02d%02d", &t.tm_hour, &t.tm_min, &t.tm_sec) == 3 && | |
797 (str += 6))) | |
717 { | 798 { |
718 if (rest != NULL && *c != '\0') | 799 gint sign, tzhrs, tzmins; |
719 *rest = c; | 800 |
720 return 0; | 801 if (*str == '.') { |
721 } | 802 /* Cut off those pesky micro-seconds */ |
722 t.tm_year -= 1900; | |
723 } | |
724 else if (*c == 'T' || *c == '.') | |
725 { | |
726 c++; | |
727 /* we have more than a date, keep going */ | |
728 | |
729 /* 2 digit hour */ | |
730 if ((sscanf(c, "%02d:%02d:%02d", &t.tm_hour, &t.tm_min, &t.tm_sec) == 3 && (c = c + 8)) || | |
731 (sscanf(c, "%02d%02d%02d", &t.tm_hour, &t.tm_min, &t.tm_sec) == 3 && (c = c + 6))) | |
732 { | |
733 gboolean offset_positive = FALSE; | |
734 int tzhrs; | |
735 int tzmins; | |
736 | |
737 t.tm_isdst = -1; | |
738 | |
739 if (*c == '.') { | |
740 do { | 803 do { |
741 c++; | 804 str++; |
742 } while (*c >= '0' && *c <= '9'); /* dealing with precision we don't care about */ | 805 } while (*str >= '0' && *str <= '9'); |
743 } | 806 } |
744 if (*c == '+') | 807 |
745 offset_positive = TRUE; | 808 sign = (*str == '+') ? -1 : 1; |
746 if (((*c == '+' || *c == '-') && (c = c + 1)) && | 809 |
747 ((sscanf(c, "%02d:%02d", &tzhrs, &tzmins) == 2 && (c = c + 5)) || | 810 /* Process the timezone */ |
748 (sscanf(c, "%02d%02d", &tzhrs, &tzmins) == 2 && (c = c + 4)))) | 811 if (*str == '+' || *str == '-') { |
749 { | 812 str++; |
750 tzoff = tzhrs*60*60 + tzmins*60; | 813 |
751 if (offset_positive) | 814 if (((sscanf(str, "%02d:%02d", &tzhrs, &tzmins) == 2 && (str += 5)) || |
752 tzoff *= -1; | 815 (sscanf(str, "%02d%02d", &tzhrs, &tzmins) == 2 && (str += 4)))) |
816 { | |
817 tzoff = tzhrs * 60 * 60 + tzmins * 60; | |
818 tzoff *= sign; | |
819 } else { | |
820 if (rest != NULL && *str != '\0') | |
821 *rest = str; | |
822 | |
823 return 0; | |
824 } | |
825 } else if (*str == 'Z') { | |
826 /* 'Z' = Zulu = UTC */ | |
827 str++; | |
828 utc = TRUE; | |
829 } else if (!utc) { | |
830 /* Local Time */ | |
831 t.tm_isdst = -1; | |
832 mktime_with_utc = FALSE; | |
753 } | 833 } |
754 else if ((*c == 'Z') && (c = c + 1)) | 834 |
755 { | 835 if (utc) |
756 /* 'Z' = Zulu = UTC */ | |
757 tzoff = 0; | 836 tzoff = 0; |
758 } | 837 } |
759 else if (utc) | 838 } |
760 { | 839 |
761 static struct tm tmptm; | 840 if (rest != NULL && *str != '\0') { |
762 time_t tmp; | 841 /* Strip trailing whitespace */ |
763 tmp = mktime(&t); | 842 while (g_ascii_isspace(*str)) |
764 /* we care about whether it *was* dst, and the offset, here on this | 843 str++; |
765 * date, not whether we are currently observing dst locally *now*. | 844 |
766 * This isn't perfect, because we would need to know in advance the | 845 if (*str != '\0') |
767 * offset we are trying to work out in advance to be sure this | 846 *rest = str; |
768 * works for times around dst transitions but it'll have to do. */ | 847 } |
769 localtime_r(&tmp, &tmptm); | 848 |
770 t.tm_isdst = tmptm.tm_isdst; | 849 if (mktime_with_utc) |
771 #ifdef HAVE_TM_GMTOFF | 850 retval = mktime_utc(&t); |
772 t.tm_gmtoff = tmptm.tm_gmtoff; | 851 else |
773 #endif | 852 retval = mktime(&t); |
774 } | |
775 | |
776 if (rest != NULL && *c != '\0') | |
777 { | |
778 if (*c == ' ') | |
779 c++; | |
780 if (*c != '\0') | |
781 *rest = c; | |
782 } | |
783 | |
784 if (tzoff != PURPLE_NO_TZ_OFF || utc) | |
785 { | |
786 #if defined(_WIN32) | |
787 long sys_tzoff; | |
788 #endif | |
789 | |
790 #if defined(_WIN32) || defined(HAVE_TM_GMTOFF) || defined (HAVE_TIMEZONE) | |
791 if (tzoff == PURPLE_NO_TZ_OFF) | |
792 tzoff = 0; | |
793 #endif | |
794 | |
795 #ifdef _WIN32 | |
796 if ((sys_tzoff = wpurple_get_tz_offset()) == -1) | |
797 tzoff = PURPLE_NO_TZ_OFF; | |
798 else | |
799 tzoff += sys_tzoff; | |
800 #else | |
801 #ifdef HAVE_TM_GMTOFF | |
802 tzoff += t.tm_gmtoff; | |
803 #else | |
804 # ifdef HAVE_TIMEZONE | |
805 tzset(); /* making sure */ | |
806 tzoff -= timezone; | |
807 # endif | |
808 #endif | |
809 #endif /* _WIN32 */ | |
810 } | |
811 } | |
812 else | |
813 { | |
814 if (rest != NULL && *c != '\0') | |
815 *rest = c; | |
816 } | |
817 } | |
818 | |
819 retval = mktime(&t); | |
820 | 853 |
821 if (tm != NULL) | 854 if (tm != NULL) |
822 *tm = t; | 855 *tm = t; |
823 | 856 |
824 if (tzoff != PURPLE_NO_TZ_OFF) | 857 if (tzoff != PURPLE_NO_TZ_OFF) |