Commit a147de10 authored by Evan Hunt's avatar Evan Hunt
Browse files

[master] portable strptime/timegm

3709.	[port]		Use built-in versions of strptime() and timegm()
			on all platforms to avoid portability issues.
			[RT #35183]
parent 4882e183
3709. [port] Use built-in versions of strptime() and timegm()
on all platforms to avoid portability issues.
[RT #35183]
3708. [bug] Address a portentry locking issue in dispatch.c.
[RT #35128]
......
......@@ -66,7 +66,8 @@ OBJS = @ISC_EXTRA_OBJS@ \
rwlock.@O@ \
safe.@O@ serial.@O@ sha1.@O@ sha2.@O@ sockaddr.@O@ stats.@O@ \
string.@O@ strtoul.@O@ symtab.@O@ task.@O@ taskpool.@O@ \
timer.@O@ version.@O@ ${UNIXOBJS} ${NLSOBJS} ${THREADOBJS}
tm.@O@ timer.@O@ version.@O@ \
${UNIXOBJS} ${NLSOBJS} ${THREADOBJS}
SYMTBLOBJS = backtrace-emptytbl.@O@
# Alphabetically
......@@ -82,7 +83,7 @@ SRCS = @ISC_EXTRA_SRCS@ \
ratelimiter.c refcount.c region.c regex.c result.c rwlock.c \
safe.c serial.c sha1.c sha2.c sockaddr.c stats.c string.c \
strtoul.c symtab.c symtbl-empty.c task.c taskpool.c timer.c \
version.c
tm.c version.c
LIBS = @LIBS@
......
......@@ -31,16 +31,15 @@ HEADERS = app.h assertions.h base64.h bind9.h bitstring.h boolean.h \
eventclass.h file.h formatcheck.h fsaccess.h \
hash.h heap.h hex.h hmacmd5.h hmacsha.h \
httpd.h \
interfaceiter.h @ISC_IPV6_H@ iterated_hash.h json.h lang.h lex.h \
lfsr.h lib.h list.h log.h \
interfaceiter.h @ISC_IPV6_H@ iterated_hash.h json.h \
lang.h lex.h lfsr.h lib.h list.h log.h \
magic.h md5.h mem.h msgcat.h msgs.h mutexblock.h \
netaddr.h ondestroy.h os.h parseint.h \
print.h quota.h radix.h random.h ratelimiter.h \
refcount.h regex.h region.h resource.h \
result.h resultclass.h rwlock.h safe.h serial.h sha1.h sha2.h \
sockaddr.h socket.h stdio.h stdlib.h string.h \
symtab.h \
task.h taskpool.h timer.h types.h util.h version.h \
sockaddr.h socket.h stdio.h stdlib.h string.h symtab.h \
task.h taskpool.h timer.h tm.h types.h util.h version.h \
xml.h
SUBDIRS =
......
/*
* Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef ISC_TM_H
#define ISC_TM_H 1
/*! \file isc/tm.h
* Provides portable conversion routines for struct tm.
*/
#include <time.h>
ISC_LANG_BEGINDECLS
time_t
isc_tm_timegm(struct tm *tm);
/*
* Convert a tm structure to time_t, using UTC rather than the local
* time zone.
*/
char *
isc_tm_strptime(const char *buf, const char *fmt, struct tm *tm);
/*
* Parse a formatted date string into struct tm.
*/
ISC_LANG_ENDDECLS
#endif /* ISC_TIMER_H */
/*
* Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*-
* Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
* All rights reserved.
......@@ -33,11 +49,20 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/*
* Portable conversion routines for struct tm, replacing
* timegm() and strptime(), which are not available on all
* platforms and don't always behave the same way when they
* are.
*/
/*
* We do not implement alternate representations. However, we always
* check whether a given modifier is allowed for a certain conversion.
......@@ -50,8 +75,6 @@
#define TM_YEAR_BASE 1900
#endif
static int conv_num(const char **, int *, int, int);
static const char *day[7] = {
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday"
......@@ -71,8 +94,57 @@ static const char *am_pm[2] = {
"AM", "PM"
};
static char *
strptime(const char *buf, const char *fmt, struct tm *tm) {
static int
conv_num(const char **buf, int *dest, int llim, int ulim) {
int result = 0;
/* The limit also determines the number of valid digits. */
int rulim = ulim;
if (**buf < '0' || **buf > '9')
return (0);
do {
result *= 10;
result += *(*buf)++ - '0';
rulim /= 10;
} while ((result * 10 <= ulim) &&
rulim && **buf >= '0' && **buf <= '9');
if (result < llim || result > ulim)
return (0);
*dest = result;
return (1);
}
time_t
isc_tm_timegm(struct tm *tm) {
time_t ret;
int i, yday = 0, leapday;
int mdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30 };
leapday = ((((tm->tm_year + 1900 ) % 4) == 0 &&
((tm->tm_year + 1900 ) % 100) != 0) ||
((tm->tm_year + 1900 ) % 400) == 0) ? 1 : 0;
mdays[1] += leapday;
yday = tm->tm_mday - 1;
for (i = 1; i <= tm->tm_mon; i++)
yday += mdays[i - 1];
ret = tm->tm_sec +
(60 * tm->tm_min) +
(3600 * tm->tm_hour) +
(86400 * (yday +
((tm->tm_year - 70) * 365) +
((tm->tm_year - 69) / 4) -
((tm->tm_year - 1) / 100) +
((tm->tm_year + 299) / 400)));
return (ret);
}
char *
isc_tm_strptime(const char *buf, const char *fmt, struct tm *tm) {
char c;
const char *bp;
size_t len = 0;
......@@ -123,43 +195,43 @@ literal:
*/
case 'c': /* Date and time, using the locale's format. */
LEGAL_ALT(ALT_E);
if (!(bp = strptime(bp, "%x %X", tm)))
if (!(bp = isc_tm_strptime(bp, "%x %X", tm)))
return (0);
break;
case 'D': /* The date as "%m/%d/%y". */
LEGAL_ALT(0);
if (!(bp = strptime(bp, "%m/%d/%y", tm)))
if (!(bp = isc_tm_strptime(bp, "%m/%d/%y", tm)))
return (0);
break;
case 'R': /* The time as "%H:%M". */
LEGAL_ALT(0);
if (!(bp = strptime(bp, "%H:%M", tm)))
if (!(bp = isc_tm_strptime(bp, "%H:%M", tm)))
return (0);
break;
case 'r': /* The time in 12-hour clock representation. */
LEGAL_ALT(0);
if (!(bp = strptime(bp, "%I:%M:%S %p", tm)))
if (!(bp = isc_tm_strptime(bp, "%I:%M:%S %p", tm)))
return (0);
break;
case 'T': /* The time as "%H:%M:%S". */
LEGAL_ALT(0);
if (!(bp = strptime(bp, "%H:%M:%S", tm)))
if (!(bp = isc_tm_strptime(bp, "%H:%M:%S", tm)))
return (0);
break;
case 'X': /* The time, using the locale's format. */
LEGAL_ALT(ALT_E);
if (!(bp = strptime(bp, "%H:%M:%S", tm)))
if (!(bp = isc_tm_strptime(bp, "%H:%M:%S", tm)))
return (0);
break;
case 'x': /* The date, using the locale's format. */
LEGAL_ALT(ALT_E);
if (!(bp = strptime(bp, "%m/%d/%y", tm)))
if (!(bp = isc_tm_strptime(bp, "%m/%d/%y", tm)))
return (0);
break;
......@@ -366,27 +438,3 @@ literal:
/* LINTED functional specification */
return ((char *)bp);
}
static int
conv_num(const char **buf, int *dest, int llim, int ulim) {
int result = 0;
/* The limit also determines the number of valid digits. */
int rulim = ulim;
if (**buf < '0' || **buf > '9')
return (0);
do {
result *= 10;
result += *(*buf)++ - '0';
rulim /= 10;
} while ((result * 10 <= ulim) &&
rulim && **buf >= '0' && **buf <= '9');
if (result < llim || result > ulim)
return (0);
*dest = result;
return (1);
}
......@@ -34,6 +34,7 @@
#include <isc/strerror.h>
#include <isc/string.h>
#include <isc/time.h>
#include <isc/tm.h>
#include <isc/util.h>
#define NS_PER_S 1000000000 /*%< Nanoseconds per second. */
......@@ -408,31 +409,6 @@ isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) {
INSIST(flen < len);
}
static time_t
timetfromtm(struct tm *tm) {
time_t ret;
int i, yday = 0, leapday;
int mdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30 };
leapday = ((((tm->tm_year + 1900 ) % 4) == 0 &&
((tm->tm_year + 1900 ) % 100) != 0) ||
((tm->tm_year + 1900 ) % 400) == 0) ? 1 : 0;
mdays[1] += leapday;
yday = tm->tm_mday - 1;
for (i = 1; i <= tm->tm_mon; i++)
yday += mdays[i - 1];
ret = tm->tm_sec +
(60 * tm->tm_min) +
(3600 * tm->tm_hour) +
(86400 * (yday +
((tm->tm_year - 70) * 365) +
((tm->tm_year - 69) / 4) -
((tm->tm_year - 1) / 100) +
((tm->tm_year + 299) / 400)));
return (ret);
}
isc_result_t
isc_time_parsehttptimestamp(char *buf, isc_time_t *t) {
struct tm t_tm;
......@@ -441,10 +417,10 @@ isc_time_parsehttptimestamp(char *buf, isc_time_t *t) {
REQUIRE(buf != NULL);
REQUIRE(t != NULL);
p = strptime(buf, "%a, %d %b %Y %H:%M:%S", &t_tm);
p = isc_tm_strptime(buf, "%a, %d %b %Y %H:%M:%S", &t_tm);
if (p == NULL)
return (ISC_R_UNEXPECTED);
when = timetfromtm(&t_tm);
when = isc_tm_timegm(&t_tm);
if (when == -1)
return (ISC_R_UNEXPECTED);
isc_time_set(t, when, 0);
......
......@@ -605,6 +605,8 @@ isc_timer_touch
isc_timermgr_create
isc_timermgr_destroy
isc_timermgr_poke
isc_tm_timegm
isc_tm_strptime
isc_win32os_majorversion
isc_win32os_minorversion
isc_win32os_servicepackmajor
......
......@@ -597,6 +597,10 @@ SOURCE=..\include\isc\timer.h
# End Source File
# Begin Source File
SOURCE=..\include\isc\tm.h
# End Source File
# Begin Source File
SOURCE=.\include\isc\win32os.h
# End Source File
# Begin Source File
......@@ -855,6 +859,10 @@ SOURCE=..\taskpool.c
SOURCE=..\timer.c
# End Source File
# Begin Source File
SOURCE=..\tm.c
# End Source File
# End Group
@IF ATOMIC
# Begin Source File
......
......@@ -194,6 +194,7 @@ CLEAN :
-@erase "$(INTDIR)\thread.obj"
-@erase "$(INTDIR)\time.obj"
-@erase "$(INTDIR)\timer.obj"
-@erase "$(INTDIR)\tm.obj"
-@erase "$(INTDIR)\vc60.idb"
-@erase "$(INTDIR)\version.obj"
-@erase "$(INTDIR)\win32os.obj"
......@@ -301,6 +302,7 @@ LINK32_OBJS= \
"$(INTDIR)\task.obj" \
"$(INTDIR)\taskpool.obj" \
"$(INTDIR)\timer.obj" \
"$(INTDIR)\tm.obj" \
"$(INTDIR)\parseint.obj" \
"$(INTDIR)\pool.obj" \
"$(INTDIR)\portset.obj" \
......@@ -485,6 +487,8 @@ CLEAN :
-@erase "$(INTDIR)\time.sbr"
-@erase "$(INTDIR)\timer.obj"
-@erase "$(INTDIR)\timer.sbr"
-@erase "$(INTDIR)\tm.obj"
-@erase "$(INTDIR)\tm.sbr"
-@erase "$(INTDIR)\vc60.idb"
-@erase "$(INTDIR)\vc60.pdb"
-@erase "$(INTDIR)\version.obj"
......@@ -589,6 +593,7 @@ BSC32_SBRS= \
"$(INTDIR)\task.sbr" \
"$(INTDIR)\taskpool.sbr" \
"$(INTDIR)\timer.sbr" \
"$(INTDIR)\tm.sbr" \
"$(INTDIR)\parseint.sbr" \
"$(INTDIR)\pool.sbr" \
"$(INTDIR)\portset.sbr" \
......@@ -686,6 +691,7 @@ LINK32_OBJS= \
"$(INTDIR)\task.obj" \
"$(INTDIR)\taskpool.obj" \
"$(INTDIR)\timer.obj" \
"$(INTDIR)\tm.obj" \
"$(INTDIR)\parseint.obj" \
"$(INTDIR)\pool.obj" \
"$(INTDIR)\portset.obj" \
......@@ -2167,6 +2173,24 @@ SOURCE=..\timer.c
$(CPP) $(CPP_PROJ) $(SOURCE)
!ENDIF
SOURCE=..\tm.c
!IF "$(CFG)" == "libisc - @PLATFORM@ Release"
"$(INTDIR)\tm.obj" : $(SOURCE) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug"
"$(INTDIR)\tm.obj" "$(INTDIR)\tm.sbr" : $(SOURCE) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
!ENDIF
......
......@@ -245,6 +245,9 @@
<ClInclude Include="..\include\isc\timer.h">
<Filter>Library Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\isc\tm.h">
<Filter>Library Header Files</Filter>
</ClInclude>
<ClInclude Include="..\include\isc\types.h">
<Filter>Library Header Files</Filter>
</ClInclude>
......@@ -593,5 +596,8 @@
<ClCompile Include="..\timer.c">
<Filter>Library Source Files</Filter>
</ClCompile>
<ClCompile Include="..\tm.c">
<Filter>Library Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
\ No newline at end of file
</Project>
......@@ -332,6 +332,7 @@ copy /Y @VCREDIST_PATH@ ..\Build\Release\
<ClInclude Include="..\include\isc\task.h" />
<ClInclude Include="..\include\isc\taskpool.h" />
<ClInclude Include="..\include\isc\timer.h" />
<ClInclude Include="..\include\isc\tm.h" />
<ClInclude Include="..\include\isc\types.h" />
<ClInclude Include="..\include\isc\util.h" />
<ClInclude Include="..\include\isc\version.h" />
......@@ -426,6 +427,7 @@ copy /Y @VCREDIST_PATH@ ..\Build\Release\
<ClCompile Include="..\task.c" />
<ClCompile Include="..\taskpool.c" />
<ClCompile Include="..\timer.c" />
<ClCompile Include="..\tm.c" />
<ClCompile Include="app.c" />
<ClCompile Include="condition.c" />
<ClCompile Include="dir.c" />
......@@ -455,4 +457,4 @@ copy /Y @VCREDIST_PATH@ ..\Build\Release\
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
\ No newline at end of file
</Project>
......@@ -30,6 +30,7 @@
#include <isc/assertions.h>
#include <isc/time.h>
#include <isc/tm.h>
#include <isc/util.h>
/*
......@@ -318,32 +319,6 @@ isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) {
}
}
static time_t
timetfromtm(struct tm *tm) {
time_t ret;
int i, yday = 0, leapday;
int mdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30 };
leapday = ((((tm->tm_year + 1900 ) % 4) == 0 &&
((tm->tm_year + 1900 ) % 100) != 0) ||
((tm->tm_year + 1900 ) % 400) == 0) ? 1 : 0;
mdays[1] += leapday;
yday = tm->tm_mday - 1;
for (i = 1; i <= tm->tm_mon; i++)
yday += mdays[i - 1];
ret = tm->tm_sec +
(60 * tm->tm_min) +
(3600 * tm->tm_hour) +
(86400 * (yday +
((tm->tm_year - 70) * 365) +
((tm->tm_year - 69) / 4) -
((tm->tm_year - 1) / 100) +
((tm->tm_year + 299) / 400)));
return (ret);
}
#include "strptime.c"
isc_result_t
isc_time_parsehttptimestamp(char *buf, isc_time_t *t) {
struct tm t_tm;
......@@ -352,10 +327,10 @@ isc_time_parsehttptimestamp(char *buf, isc_time_t *t) {
REQUIRE(buf != NULL);
REQUIRE(t != NULL);
p = strptime(buf, "%a, %d %b %Y %H:%M:%S", &t_tm);
p = isc_tm_strptime(buf, "%a, %d %b %Y %H:%M:%S", &t_tm);
if (p == NULL)
return (ISC_R_UNEXPECTED);
when = timetfromtm(&t_tm);
when = isc_tm_timegm(&t_tm);
if (when == -1)
return (ISC_R_UNEXPECTED);
isc_time_set(t, when, 0);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment