Hi, I'm answering to myself in order to submit an updated version of my patch, fixing the original distance bug, but also adding support for another space+one-digit day format (for the two-digit year formats).
Some code style fixes are also included in this patch. If you don't like the mix of bug fixing, enhancements and code style fixes, I can split this patch into several patches to clarify all this stuff. Comments and reviews are, of course, very welcome. I hope this patch can be part of the just-released apr-util. Regards, - Sam -- Maxime Petazzoni (http://www.bulix.org) -- gone crazy, back soon. leave message.
Index: test/Makefile.in
===================================================================
--- test/Makefile.in (revision 233337)
+++ test/Makefile.in (working copy)
@@ -2,7 +2,7 @@
INCLUDES = @APRUTIL_PRIV_INCLUDES@ @APR_INCLUDES@ @APRUTIL_INCLUDES@
-PROGRAMS = testall testdbm testdate testxml testrmm \
+PROGRAMS = testall testdbm testdate testdaterfc testxml testrmm \
testreslist testqueue testxlate dbd
TARGETS = $(PROGRAMS)
@@ -48,6 +48,11 @@
testdate: $(testdate_OBJECTS) $(testdate_LDADD)
$(LINK) $(APRUTIL_LDFLAGS) $(testdate_OBJECTS) $(testdate_LDADD)
$(PROGRAM_DEPENDENCIES)
+testdaterfc_OBJECTS = testdaterfc.lo
+testdaterfc_LDADD = $(TARGET_LIB_PATH)
+testdaterfc: $(testdaterfc_OBJECTS) $(testdaterfc_LDADD)
+ $(LINK) $(APRUTIL_LDFLAGS) $(testdaterfc_OBJECTS) $(testdaterfc_LDADD)
$(PROGRAM_DEPENDENCIES)
+
testxml_OBJECTS = testxml.lo
testxml_LDADD = $(TARGET_LIB_PATH)
testxml: $(testxml_OBJECTS) $(testxml_LDADD)
Index: test/testdaterfc.c
===================================================================
--- test/testdaterfc.c (revision 0)
+++ test/testdaterfc.c (revision 0)
@@ -0,0 +1,58 @@
+/** testdaterfc.c: an apr_date_parse_rfc() function tester.
+ *
+ * Compile with the following line :
+ * gcc -I${prefix}/include/apr -g -O2 -Wall \
+ * testdaterfc.c -o testdaterfc \
+ * `${prefix}/bin/apr-config --includes --libs \
+ * --cflags --ldflags --cppflags --link-ld` \
+ * `${prefix}/bin/apu-config --includes --libs \
+ * --link-ld`
+ *
+ * Run with :
+ * LD_LIBRARY_PATH=${prefix}/lib ./testdaterfc
+ *
+ * Maxime Petazzoni, August 2005
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "apr_date.h"
+
+/* Data samples. This is a good sample of what I've seen this
+ far. Feel free to add cases here. */
+char *data[] = {
+ "Mon, 27 Feb 1995 20:49:44 -0800",
+ "Fri, 1 Jul 2005 11:34:25 -0400",
+ "Monday, 27-Feb-95 20:49:44 -0800",
+ "Tue, 4 Mar 1997 12:43:52 +0200",
+ "Mon, 27 Feb 95 20:49:44 -0800",
+ "Tue, 4 Mar 97 12:43:52 +0200",
+ "Tue, 4 Mar 97 12:43:52 +0200",
+ "Mon, 27 Feb 95 20:49 GMT",
+ "Tue, 4 Mar 97 12:43 GMT",
+ NULL };
+
+int main(int argc, char **argv)
+{
+ apr_time_t date;
+ char *str_date;
+ int i = 0;
+
+ while (data[i]) {
+ /* Parse date string into an apr_time_t */
+ date = apr_date_parse_rfc(data[i]);
+
+ /* Fetch back and RFC 822 formatted date string */
+ str_date = calloc(APR_RFC822_DATE_LEN, sizeof(char));
+ apr_rfc822_date(str_date, date);
+
+ /* Print all relevant material */
+ printf("%s %"APR_OFF_T_FMT" %s\n", str_date, date, data[i]);
+ free(str_date);
+
+ i++;
+ }
+
+ return 0;
+}
Index: misc/apr_date.c
===================================================================
--- misc/apr_date.c (revision 233337)
+++ misc/apr_date.c (working copy)
@@ -335,21 +335,22 @@
return APR_DATE_BAD;
/* Not all dates have text months at the beginning. */
- if (!apr_isdigit(date[0]))
- {
+ if (!apr_isdigit(date[0])) {
while (*date && apr_isspace(*date)) /* Find first non-whitespace char
*/
++date;
- if (*date == '\0')
+ if (*date == '\0')
return APR_DATE_BAD;
if ((date = strchr(date, ' ')) == NULL) /* Find space after weekday
*/
return APR_DATE_BAD;
- ++date; /* Now pointing to first char after space, which should be
*/ }
+ ++date;
+ }
/* start of the actual date information for all 11 formats. */
- if (apr_date_checkmask(date, "## @$$ #### ##:##:## *")) { /* RFC 1123
format */
+ if (apr_date_checkmask(date, "## @$$ #### ##:##:## *")) {
+ /* RFC 1123 format */
ds.tm_year = ((date[7] - '0') * 10 + (date[8] - '0') - 19) * 100;
if (ds.tm_year < 0)
@@ -361,11 +362,12 @@
monstr = date + 3;
timstr = date + 12;
- gmtstr = date + 20;
+ gmtstr = date + 21;
TIMEPARSE_STD(ds, timstr);
}
- else if (apr_date_checkmask(date, "[EMAIL PROTECTED] ##:##:## *")) {/* RFC
850 format */
+ else if (apr_date_checkmask(date, "[EMAIL PROTECTED] ##:##:## *")) {
+ /* RFC 850 format */
ds.tm_year = ((date[7] - '0') * 10) + (date[8] - '0');
if (ds.tm_year < 70)
@@ -382,7 +384,7 @@
else if (apr_date_checkmask(date, "@$$ ~# ##:##:## ####*")) {
/* asctime format */
ds.tm_year = ((date[16] - '0') * 10 + (date[17] - '0') - 19) * 100;
- if (ds.tm_year < 0)
+ if (ds.tm_year < 0)
return APR_DATE_BAD;
ds.tm_year += ((date[18] - '0') * 10) + (date[19] - '0');
@@ -418,7 +420,9 @@
}
else if (apr_date_checkmask(date, "## @$$ ## ##:##:## *")) {
/* This is the old RFC 1123 date format - many many years ago, people
- * used two-digit years. Oh, how foolish. */
+ * used two-digit years. Oh, how foolish.
+ *
+ * Two-digit day, two-digit year version. */
ds.tm_year = ((date[7] - '0') * 10) + (date[8] - '0');
if (ds.tm_year < 70)
@@ -431,10 +435,30 @@
gmtstr = date + 19;
TIMEPARSE_STD(ds, timstr);
- }
+ }
+ else if (apr_date_checkmask(date, " # @$$ ## ##:##:## *")) {
+ /* This is the old RFC 1123 date format - many many years ago, people
+ * used two-digit years. Oh, how foolish.
+ *
+ * Space + one-digit day, two-digit year version.*/
+ ds.tm_year = ((date[7] - '0') * 10) + (date[8] - '0');
+
+ if (ds.tm_year < 70)
+ ds.tm_year += 100;
+
+ ds.tm_mday = (date[1] - '0');
+
+ monstr = date + 3;
+ timstr = date + 10;
+ gmtstr = date + 19;
+
+ TIMEPARSE_STD(ds, timstr);
+ }
else if (apr_date_checkmask(date, "# @$$ ## ##:##:## *")) {
/* This is the old RFC 1123 date format - many many years ago, people
- * used two-digit years. Oh, how foolish. */
+ * used two-digit years. Oh, how foolish.
+ *
+ * One-digit day, two-digit year version. */
ds.tm_year = ((date[6] - '0') * 10) + (date[7] - '0');
if (ds.tm_year < 70)
@@ -447,7 +471,7 @@
gmtstr = date + 18;
TIMEPARSE_STD(ds, timstr);
- }
+ }
else if (apr_date_checkmask(date, "## @$$ ## ##:## *")) {
/* Loser format. This is quite bogus. */
ds.tm_year = ((date[7] - '0') * 10) + (date[8] - '0');
@@ -462,7 +486,7 @@
gmtstr = NULL;
TIMEPARSE(ds, timstr[0],timstr[1], timstr[3],timstr[4], '0','0');
- }
+ }
else if (apr_date_checkmask(date, "# @$$ ## ##:## *")) {
/* Loser format. This is quite bogus. */
ds.tm_year = ((date[6] - '0') * 10) + (date[7] - '0');
@@ -494,7 +518,7 @@
TIMEPARSE(ds, '0',timstr[1], timstr[3],timstr[4], timstr[6],timstr[7]);
}
else if (apr_date_checkmask(date, "# @$$ ## #:##:## *")) {
- /* Loser format. This is quite bogus. */
+ /* Loser format. This is quite bogus. */
ds.tm_year = ((date[6] - '0') * 10) + (date[7] - '0');
if (ds.tm_year < 70)
@@ -508,7 +532,7 @@
TIMEPARSE(ds, '0',timstr[1], timstr[3],timstr[4], timstr[6],timstr[7]);
}
- else if (apr_date_checkmask(date, " # @$$ #### ##:##:## *")) {
+ else if (apr_date_checkmask(date, " # @$$ #### ##:##:## *")) {
/* RFC 1123 format with a space instead of a leading zero. */
ds.tm_year = ((date[7] - '0') * 10 + (date[8] - '0') - 19) * 100;
@@ -521,7 +545,7 @@
monstr = date + 3;
timstr = date + 12;
- gmtstr = date + 20;
+ gmtstr = date + 21;
TIMEPARSE_STD(ds, timstr);
}
@@ -549,7 +573,7 @@
if (ds.tm_mday <= 0 || ds.tm_mday > 31)
return APR_DATE_BAD;
- if ((ds.tm_hour > 23) || (ds.tm_min > 59) || (ds.tm_sec > 61))
+ if ((ds.tm_hour > 23) || (ds.tm_min > 59) || (ds.tm_sec > 61))
return APR_DATE_BAD;
mint = (monstr[0] << 16) | (monstr[1] << 8) | monstr[2];
@@ -583,34 +607,33 @@
* If there is any confusion, tm_gmtoff will remain 0.
*/
ds.tm_gmtoff = 0;
- if (gmtstr && *gmtstr != '\0') {
- /* Do we have a GMT? */
- if (*(++gmtstr) != '\0') {
- int offset;
- switch (*(gmtstr++)) {
- case '-':
- offset = atoi(gmtstr);
- ds.tm_gmtoff -= (offset / 100) * 60 * 60;
- ds.tm_gmtoff -= (offset % 100) * 60;
- break;
- case '+':
- offset = atoi(gmtstr);
- ds.tm_gmtoff += (offset / 100) * 60 * 60;
- ds.tm_gmtoff += (offset % 100) * 60;
- break;
- }
+
+ /* Do we have a timezone ? */
+ if (gmtstr) {
+ int offset;
+ switch (*gmtstr) {
+ case '-':
+ offset = atoi(gmtstr+1);
+ ds.tm_gmtoff -= (offset / 100) * 60 * 60;
+ ds.tm_gmtoff -= (offset % 100) * 60;
+ break;
+ case '+':
+ offset = atoi(gmtstr+1);
+ ds.tm_gmtoff += (offset / 100) * 60 * 60;
+ ds.tm_gmtoff += (offset % 100) * 60;
+ break;
}
}
- /* apr_time_exp_get uses tm_usec field, but it hasn't been set yet.
+ /* apr_time_exp_get uses tm_usec field, but it hasn't been set yet.
* It should be safe to just zero out this value.
* tm_usec is the number of microseconds into the second. HTTP only
* cares about second granularity.
*/
ds.tm_usec = 0;
- if (apr_time_exp_gmt_get(&result, &ds) != APR_SUCCESS)
+ if (apr_time_exp_gmt_get(&result, &ds) != APR_SUCCESS)
return APR_DATE_BAD;
-
+
return result;
}
signature.asc
Description: Digital signature
