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$ 00037 * Revision 1.4 2009/01/17 15:37:52 haraldkipp 00038 * Added some NUTASSERT macros to check function parameters. 00039 * 00040 * Revision 1.3 2008/08/11 06:59:40 haraldkipp 00041 * BSD types replaced by stdint types (feature request #1282721). 00042 * 00043 * Revision 1.2 2003/12/19 22:26:37 drsung 00044 * Dox written. 00045 * 00046 * Revision 1.1 2003/11/24 18:07:37 drsung 00047 * first release 00048 * 00049 * 00050 */ 00051 00052 #include <stdint.h> 00053 00054 #include <time.h> 00055 #include "ctime.h" 00056 00057 #include <sys/nutdebug.h> 00058 00059 #define __need_NULL 00060 #include <stddef.h> 00061 00062 /* 00063 * ChkAdd evaluates to TRUE if dest = src1 + src2 has overflowed 00064 */ 00065 #define ChkAdd(dest, src1, src2) ( ((src1 >= 0L) && (src2 >= 0L) \ 00066 && (dest < 0L)) || ((src1 < 0L) && (src2 < 0L) && (dest >= 0L)) ) 00067 00068 /* 00069 * ChkMul evaluates to TRUE if dest = src1 * src2 has overflowed 00070 */ 00071 #define ChkMul(dest, src1, src2) ( src1 ? (dest/src1 != src2) : 0 ) 00072 00078 static time_t _make_time_t(tm * tb, int ultflag) 00079 { 00080 long tmptm1, tmptm2, tmptm3; 00081 tm *tbtemp; 00082 00083 NUTASSERT(tb != NULL); 00084 00085 /* 00086 * First, make sure tm_year is reasonably close to being in range. 00087 */ 00088 if (((tmptm1 = tb->tm_year) < _BASE_YEAR - 1) || (tmptm1 > _MAX_YEAR + 1)) 00089 goto err_mktime; 00090 00091 00092 /* 00093 * Adjust month value so it is in the range 0 - 11. This is because 00094 * we don't know how many days are in months 12, 13, 14, etc. 00095 */ 00096 00097 if ((tb->tm_mon < 0) || (tb->tm_mon > 11)) { 00098 00099 /* 00100 * no danger of overflow because the range check above. 00101 */ 00102 tmptm1 += (tb->tm_mon / 12); 00103 00104 if ((tb->tm_mon %= 12) < 0) { 00105 tb->tm_mon += 12; 00106 tmptm1--; 00107 } 00108 00109 /* 00110 * Make sure year count is still in range. 00111 */ 00112 if ((tmptm1 < _BASE_YEAR - 1) || (tmptm1 > _MAX_YEAR + 1)) 00113 goto err_mktime; 00114 } 00115 00116 /***** HERE: tmptm1 holds number of elapsed years *****/ 00117 00118 /* 00119 * Calculate days elapsed minus one, in the given year, to the given 00120 * month. Check for leap year and adjust if necessary. 00121 */ 00122 tmptm2 = _days[tb->tm_mon]; 00123 if (!(tmptm1 & 3) && (tb->tm_mon > 1)) 00124 tmptm2++; 00125 00126 /* 00127 * Calculate elapsed days since base date (midnight, 1/1/70, UTC) 00128 * 00129 * 00130 * 365 days for each elapsed year since 1970, plus one more day for 00131 * each elapsed leap year. no danger of overflow because of the range 00132 * check (above) on tmptm1. 00133 */ 00134 tmptm3 = (tmptm1 - _BASE_YEAR) * 365L + ((tmptm1 - 1L) >> 2) 00135 - _LEAP_YEAR_ADJUST; 00136 00137 /* 00138 * elapsed days to current month (still no possible overflow) 00139 */ 00140 tmptm3 += tmptm2; 00141 00142 /* 00143 * elapsed days to current date. overflow is now possible. 00144 */ 00145 tmptm1 = tmptm3 + (tmptm2 = (long) (tb->tm_mday)); 00146 if (ChkAdd(tmptm1, tmptm3, tmptm2)) 00147 goto err_mktime; 00148 00149 /***** HERE: tmptm1 holds number of elapsed days *****/ 00150 00151 /* 00152 * Calculate elapsed hours since base date 00153 */ 00154 tmptm2 = tmptm1 * 24L; 00155 if (ChkMul(tmptm2, tmptm1, 24L)) 00156 goto err_mktime; 00157 00158 tmptm1 = tmptm2 + (tmptm3 = (long) tb->tm_hour); 00159 if (ChkAdd(tmptm1, tmptm2, tmptm3)) 00160 goto err_mktime; 00161 00162 /***** HERE: tmptm1 holds number of elapsed hours *****/ 00163 00164 /* 00165 * Calculate elapsed minutes since base date 00166 */ 00167 00168 tmptm2 = tmptm1 * 60L; 00169 if (ChkMul(tmptm2, tmptm1, 60L)) 00170 goto err_mktime; 00171 00172 tmptm1 = tmptm2 + (tmptm3 = (long) tb->tm_min); 00173 if (ChkAdd(tmptm1, tmptm2, tmptm3)) 00174 goto err_mktime; 00175 00176 /***** HERE: tmptm1 holds number of elapsed minutes *****/ 00177 00178 /* 00179 * Calculate elapsed seconds since base date 00180 */ 00181 00182 tmptm2 = tmptm1 * 60L; 00183 if (ChkMul(tmptm2, tmptm1, 60L)) 00184 goto err_mktime; 00185 00186 tmptm1 = tmptm2 + (tmptm3 = (long) tb->tm_sec); 00187 if (ChkAdd(tmptm1, tmptm2, tmptm3)) 00188 goto err_mktime; 00189 00190 /***** HERE: tmptm1 holds number of elapsed seconds *****/ 00191 00192 if (ultflag) { 00193 00194 /* 00195 * Adjust for timezone. No need to check for overflow since 00196 * localtime() will check its arg value 00197 */ 00198 00199 tmptm1 += _timezone; 00200 00201 /* 00202 * Convert this second count back into a time block structure. 00203 * If localtime returns NULL, return an error. 00204 */ 00205 if ((tbtemp = localtime(&tmptm1)) == NULL) 00206 goto err_mktime; 00207 00208 /* 00209 * Now must compensate for DST. The ANSI rules are to use the 00210 * passed-in tm_isdst flag if it is non-negative. Otherwise, 00211 * compute if DST applies. Recall that tbtemp has the time without 00212 * DST compensation, but has set tm_isdst correctly. 00213 */ 00214 if ((tb->tm_isdst > 0) || ((tb->tm_isdst < 0) && (tbtemp->tm_isdst > 0))) { 00215 tmptm1 += _dstbias; 00216 tbtemp = localtime(&tmptm1); /* reconvert, can't get NULL */ 00217 } 00218 00219 } else { 00220 if ((tbtemp = gmtime(&tmptm1)) == NULL) 00221 goto err_mktime; 00222 } 00223 00224 /***** HERE: tmptm1 holds number of elapsed seconds, adjusted *****/ 00225 /***** for local time if requested *****/ 00226 00227 *tb = *tbtemp; 00228 return (time_t) tmptm1; 00229 00230 err_mktime: 00231 /* 00232 * All errors come to here 00233 */ 00234 return (time_t) (-1); 00235 } 00236 00279 time_t mktime(tm * timeptr) 00280 { 00281 return (_make_time_t(timeptr, 1)); 00282 } 00283 00284 time_t _mkgmtime(tm * timeptr) 00285 { 00286 return (_make_time_t(timeptr, 0)); 00287 } 00288