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