mutt stable branch with some hacks
at jcs 218 lines 5.4 kB view raw
1/* 2 * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 */ 18 19#if HAVE_CONFIG_H 20# include "config.h" 21#endif 22 23#include "mutt.h" 24#include <string.h> 25 26/* returns the seconds east of UTC given `g' and its corresponding gmtime() 27 representation */ 28static time_t compute_tz (time_t g, struct tm *utc) 29{ 30 struct tm *lt = localtime (&g); 31 time_t t; 32 int yday; 33 34 t = (((lt->tm_hour - utc->tm_hour) * 60) + (lt->tm_min - utc->tm_min)) * 60; 35 36 if ((yday = (lt->tm_yday - utc->tm_yday))) 37 { 38 /* This code is optimized to negative timezones (West of Greenwich) */ 39 if (yday == -1 || /* UTC passed midnight before localtime */ 40 yday > 1) /* UTC passed new year before localtime */ 41 t -= 24 * 60 * 60; 42 else 43 t += 24 * 60 * 60; 44 } 45 46 return t; 47} 48 49/* Returns the local timezone in seconds east of UTC for the time t, 50 * or for the current time if t is zero. 51 */ 52time_t mutt_local_tz (time_t t) 53{ 54 struct tm *ptm; 55 struct tm utc; 56 57 if (!t) 58 t = time (NULL); 59 ptm = gmtime (&t); 60 /* need to make a copy because gmtime/localtime return a pointer to 61 static memory (grr!) */ 62 memcpy (&utc, ptm, sizeof (utc)); 63 return (compute_tz (t, &utc)); 64} 65 66/* theoretically time_t can be float but it is integer on most (if not all) systems */ 67#define TIME_T_MAX ((((time_t) 1 << (sizeof(time_t) * 8 - 2)) - 1) * 2 + 1) 68#define TM_YEAR_MAX (1970 + (((((TIME_T_MAX - 59) / 60) - 59) / 60) - 23) / 24 / 366) 69 70/* converts struct tm to time_t, but does not take the local timezone into 71 account unless ``local'' is nonzero */ 72time_t mutt_mktime (struct tm *t, int local) 73{ 74 time_t g; 75 int year; 76 77 static const int AccumDaysPerMonth[12] = { 78 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 79 }; 80 81 /* Large years, even those that are less than INT_MAX, seem to give 82 * gmtime() and localtime() indigestion. Cap the year at 9999 to 83 * prevent those from returning NULL. */ 84 year = (t->tm_year > 9999-1900) ? 9999-1900 : t->tm_year; 85 86 /* Prevent an integer overflow for 32-bit time_t platforms. 87 * The time_t cast is an attempt to silence a clang range warning. */ 88 if ((time_t)year > TM_YEAR_MAX) 89 return TIME_T_MAX; 90 91 /* Compute the number of days since January 1 in the same year */ 92 g = AccumDaysPerMonth [t->tm_mon % 12]; 93 94 /* The leap years are 1972 and every 4. year until 2096, 95 * but this algorithm will fail after year 2099 */ 96 g += t->tm_mday; 97 if ((year % 4) || t->tm_mon < 2) 98 g--; 99 t->tm_yday = g; 100 101 /* Compute the number of days since January 1, 1970 */ 102 g += (year - 70) * (time_t)365; 103 g += (year - 69) / 4; 104 105 /* Compute the number of hours */ 106 g *= 24; 107 g += t->tm_hour; 108 109 /* Compute the number of minutes */ 110 g *= 60; 111 g += t->tm_min; 112 113 /* Compute the number of seconds */ 114 g *= 60; 115 g += t->tm_sec; 116 117 if (local) 118 g -= compute_tz (g, t); 119 120 return (g); 121} 122 123/* Safely add a timeout to a given time_t value, truncating instead of 124 * overflowing. */ 125time_t mutt_add_timeout (time_t now, long timeout) 126{ 127 if (timeout < 0) 128 return now; 129 130 if (TIME_T_MAX - now < timeout) 131 return TIME_T_MAX; 132 133 return now + timeout; 134} 135 136/* Return 1 if month is February of leap year, else 0 */ 137static int isLeapYearFeb (struct tm *tm) 138{ 139 if (tm->tm_mon == 1) 140 { 141 int y = tm->tm_year + 1900; 142 return (((y & 3) == 0) && (((y % 100) != 0) || ((y % 400) == 0))); 143 } 144 return (0); 145} 146 147void mutt_normalize_time (struct tm *tm) 148{ 149 static const char DaysPerMonth[12] = { 150 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 151 }; 152 int nLeap; 153 154 while (tm->tm_sec < 0) 155 { 156 tm->tm_sec += 60; 157 tm->tm_min--; 158 } 159 while (tm->tm_sec >= 60) 160 { 161 tm->tm_sec -= 60; 162 tm->tm_min++; 163 } 164 while (tm->tm_min < 0) 165 { 166 tm->tm_min += 60; 167 tm->tm_hour--; 168 } 169 while (tm->tm_min >= 60) 170 { 171 tm->tm_min -= 60; 172 tm->tm_hour++; 173 } 174 while (tm->tm_hour < 0) 175 { 176 tm->tm_hour += 24; 177 tm->tm_mday--; 178 } 179 while (tm->tm_hour >= 24) 180 { 181 tm->tm_hour -= 24; 182 tm->tm_mday++; 183 } 184 /* use loops on NNNdwmy user input values? */ 185 while (tm->tm_mon < 0) 186 { 187 tm->tm_mon += 12; 188 tm->tm_year--; 189 } 190 while (tm->tm_mon >= 12) 191 { 192 tm->tm_mon -= 12; 193 tm->tm_year++; 194 } 195 while (tm->tm_mday <= 0) 196 { 197 if (tm->tm_mon) 198 tm->tm_mon--; 199 else 200 { 201 tm->tm_mon = 11; 202 tm->tm_year--; 203 } 204 tm->tm_mday += DaysPerMonth[tm->tm_mon] + isLeapYearFeb (tm); 205 } 206 while (tm->tm_mday > (DaysPerMonth[tm->tm_mon] + 207 (nLeap = isLeapYearFeb (tm)))) 208 { 209 tm->tm_mday -= DaysPerMonth[tm->tm_mon] + nLeap; 210 if (tm->tm_mon < 11) 211 tm->tm_mon++; 212 else 213 { 214 tm->tm_mon = 0; 215 tm->tm_year++; 216 } 217 } 218}