Nut/OS  4.10.3
API Reference
mktime.c
Go to the documentation of this file.
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