00001 /* 00002 * Copyright (C) 2001-2003 by egnite Software GmbH. All rights reserved. 00003 * 00004 * Redistribution and use in source and binary forms, with or without 00005 * modification, are permitted provided that the following conditions 00006 * are met: 00007 * 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. Neither the name of the copyright holders nor the names of 00014 * contributors may be used to endorse or promote products derived 00015 * from this software without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS 00018 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00019 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00020 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE 00021 * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00022 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00023 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 00024 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 00025 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 00026 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 00027 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00028 * SUCH DAMAGE. 00029 * 00030 * For additional information see http://www.ethernut.de/ 00031 * 00032 * Portions of the following functions are derived from material which is 00033 * Copyright (c) 1985 by Microsoft Corporation. All rights are reserved. 00034 */ 00035 /* 00036 * $Log: mktime.c,v $ 00037 * Revision 1.3 2008/08/11 06:59:40 haraldkipp 00038 * BSD types replaced by stdint types (feature request #1282721). 00039 * 00040 * Revision 1.2 2003/12/19 22:26:37 drsung 00041 * Dox written. 00042 * 00043 * Revision 1.1 2003/11/24 18:07:37 drsung 00044 * first release 00045 * 00046 * 00047 */ 00048 00049 #include <stdint.h> 00050 00051 #include <time.h> 00052 #include "ctime.h" 00053 00054 #define __need_NULL 00055 #include <stddef.h> 00056 00057 /* 00058 * ChkAdd evaluates to TRUE if dest = src1 + src2 has overflowed 00059 */ 00060 #define ChkAdd(dest, src1, src2) ( ((src1 >= 0L) && (src2 >= 0L) \ 00061 && (dest < 0L)) || ((src1 < 0L) && (src2 < 0L) && (dest >= 0L)) ) 00062 00063 /* 00064 * ChkMul evaluates to TRUE if dest = src1 * src2 has overflowed 00065 */ 00066 #define ChkMul(dest, src1, src2) ( src1 ? (dest/src1 != src2) : 0 ) 00067 00073 static time_t _make_time_t(tm * tb, int ultflag) 00074 { 00075 long tmptm1, tmptm2, tmptm3; 00076 tm *tbtemp; 00077 00078 /* 00079 * First, make sure tm_year is reasonably close to being in range. 00080 */ 00081 if (((tmptm1 = tb->tm_year) < _BASE_YEAR - 1) || (tmptm1 > _MAX_YEAR + 1)) 00082 goto err_mktime; 00083 00084 00085 /* 00086 * Adjust month value so it is in the range 0 - 11. This is because 00087 * we don't know how many days are in months 12, 13, 14, etc. 00088 */ 00089 00090 if ((tb->tm_mon < 0) || (tb->tm_mon > 11)) { 00091 00092 /* 00093 * no danger of overflow because the range check above. 00094 */ 00095 tmptm1 += (tb->tm_mon / 12); 00096 00097 if ((tb->tm_mon %= 12) < 0) { 00098 tb->tm_mon += 12; 00099 tmptm1--; 00100 } 00101 00102 /* 00103 * Make sure year count is still in range. 00104 */ 00105 if ((tmptm1 < _BASE_YEAR - 1) || (tmptm1 > _MAX_YEAR + 1)) 00106 goto err_mktime; 00107 } 00108 00109 /***** HERE: tmptm1 holds number of elapsed years *****/ 00110 00111 /* 00112 * Calculate days elapsed minus one, in the given year, to the given 00113 * month. Check for leap year and adjust if necessary. 00114 */ 00115 tmptm2 = _days[tb->tm_mon]; 00116 if (!(tmptm1 & 3) && (tb->tm_mon > 1)) 00117 tmptm2++; 00118 00119 /* 00120 * Calculate elapsed days since base date (midnight, 1/1/70, UTC) 00121 * 00122 * 00123 * 365 days for each elapsed year since 1970, plus one more day for 00124 * each elapsed leap year. no danger of overflow because of the range 00125 * check (above) on tmptm1. 00126 */ 00127 tmptm3 = (tmptm1 - _BASE_YEAR) * 365L + ((tmptm1 - 1L) >> 2) 00128 - _LEAP_YEAR_ADJUST; 00129 00130 /* 00131 * elapsed days to current month (still no possible overflow) 00132 */ 00133 tmptm3 += tmptm2; 00134 00135 /* 00136 * elapsed days to current date. overflow is now possible. 00137 */ 00138 tmptm1 = tmptm3 + (tmptm2 = (long) (tb->tm_mday)); 00139 if (ChkAdd(tmptm1, tmptm3, tmptm2)) 00140 goto err_mktime; 00141 00142 /***** HERE: tmptm1 holds number of elapsed days *****/ 00143 00144 /* 00145 * Calculate elapsed hours since base date 00146 */ 00147 tmptm2 = tmptm1 * 24L; 00148 if (ChkMul(tmptm2, tmptm1, 24L)) 00149 goto err_mktime; 00150 00151 tmptm1 = tmptm2 + (tmptm3 = (long) tb->tm_hour); 00152 if (ChkAdd(tmptm1, tmptm2, tmptm3)) 00153 goto err_mktime; 00154 00155 /***** HERE: tmptm1 holds number of elapsed hours *****/ 00156 00157 /* 00158 * Calculate elapsed minutes since base date 00159 */ 00160 00161 tmptm2 = tmptm1 * 60L; 00162 if (ChkMul(tmptm2, tmptm1, 60L)) 00163 goto err_mktime; 00164 00165 tmptm1 = tmptm2 + (tmptm3 = (long) tb->tm_min); 00166 if (ChkAdd(tmptm1, tmptm2, tmptm3)) 00167 goto err_mktime; 00168 00169 /***** HERE: tmptm1 holds number of elapsed minutes *****/ 00170 00171 /* 00172 * Calculate elapsed seconds since base date 00173 */ 00174 00175 tmptm2 = tmptm1 * 60L; 00176 if (ChkMul(tmptm2, tmptm1, 60L)) 00177 goto err_mktime; 00178 00179 tmptm1 = tmptm2 + (tmptm3 = (long) tb->tm_sec); 00180 if (ChkAdd(tmptm1, tmptm2, tmptm3)) 00181 goto err_mktime; 00182 00183 /***** HERE: tmptm1 holds number of elapsed seconds *****/ 00184 00185 if (ultflag) { 00186 00187 /* 00188 * Adjust for timezone. No need to check for overflow since 00189 * localtime() will check its arg value 00190 */ 00191 00192 tmptm1 += _timezone; 00193 00194 /* 00195 * Convert this second count back into a time block structure. 00196 * If localtime returns NULL, return an error. 00197 */ 00198 if ((tbtemp = localtime(&tmptm1)) == NULL) 00199 goto err_mktime; 00200 00201 /* 00202 * Now must compensate for DST. The ANSI rules are to use the 00203 * passed-in tm_isdst flag if it is non-negative. Otherwise, 00204 * compute if DST applies. Recall that tbtemp has the time without 00205 * DST compensation, but has set tm_isdst correctly. 00206 */ 00207 if ((tb->tm_isdst > 0) || ((tb->tm_isdst < 0) && (tbtemp->tm_isdst > 0))) { 00208 tmptm1 += _dstbias; 00209 tbtemp = localtime(&tmptm1); /* reconvert, can't get NULL */ 00210 } 00211 00212 } else { 00213 if ((tbtemp = gmtime(&tmptm1)) == NULL) 00214 goto err_mktime; 00215 } 00216 00217 /***** HERE: tmptm1 holds number of elapsed seconds, adjusted *****/ 00218 /***** for local time if requested *****/ 00219 00220 *tb = *tbtemp; 00221 return (time_t) tmptm1; 00222 00223 err_mktime: 00224 /* 00225 * All errors come to here 00226 */ 00227 return (time_t) (-1); 00228 } 00229 00272 time_t mktime(tm * timeptr) 00273 { 00274 return (_make_time_t(timeptr, 1)); 00275 } 00276 00277 time_t _mkgmtime(tm * timeptr) 00278 { 00279 return (_make_time_t(timeptr, 0)); 00280 } 00281