summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_datetimemodule.c165
1 files changed, 93 insertions, 72 deletions
diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c
index cdfa235..bc4caa0 100644
--- a/Modules/_datetimemodule.c
+++ b/Modules/_datetimemodule.c
@@ -668,8 +668,8 @@ set_date_fields(PyDateTime_Date *self, int y, int m, int d)
* String parsing utilities and helper functions
*/
-static const char*
-parse_digits(const char* ptr, int* var, size_t num_digits)
+static const char *
+parse_digits(const char *ptr, int *var, size_t num_digits)
{
for (size_t i = 0; i < num_digits; ++i) {
unsigned int tmp = (unsigned int)(*(ptr++) - '0');
@@ -683,15 +683,16 @@ parse_digits(const char* ptr, int* var, size_t num_digits)
return ptr;
}
-static int parse_isoformat_date(const char *dtstr,
- int* year, int *month, int* day) {
+static int
+parse_isoformat_date(const char *dtstr, int *year, int *month, int *day)
+{
/* Parse the date components of the result of date.isoformat()
- *
- * Return codes:
- * 0: Success
- * -1: Failed to parse date component
- * -2: Failed to parse dateseparator
- */
+ *
+ * Return codes:
+ * 0: Success
+ * -1: Failed to parse date component
+ * -2: Failed to parse dateseparator
+ */
const char *p = dtstr;
p = parse_digits(p, year, 4);
if (NULL == p) {
@@ -720,8 +721,9 @@ static int parse_isoformat_date(const char *dtstr,
}
static int
-parse_hh_mm_ss_ff(const char *tstr, const char *tstr_end,
- int* hour, int* minute, int *second, int *microsecond) {
+parse_hh_mm_ss_ff(const char *tstr, const char *tstr_end, int *hour,
+ int *minute, int *second, int *microsecond)
+{
const char *p = tstr;
const char *p_end = tstr_end;
int *vals[3] = {hour, minute, second};
@@ -736,12 +738,15 @@ parse_hh_mm_ss_ff(const char *tstr, const char *tstr_end,
char c = *(p++);
if (p >= p_end) {
return c != '\0';
- } else if (c == ':') {
+ }
+ else if (c == ':') {
continue;
- } else if (c == '.') {
+ }
+ else if (c == '.') {
break;
- } else {
- return -4; // Malformed time separator
+ }
+ else {
+ return -4; // Malformed time separator
}
}
@@ -765,9 +770,10 @@ parse_hh_mm_ss_ff(const char *tstr, const char *tstr_end,
}
static int
-parse_isoformat_time(const char *dtstr, size_t dtlen,
- int* hour, int *minute, int *second, int *microsecond,
- int* tzoffset, int *tzmicrosecond) {
+parse_isoformat_time(const char *dtstr, size_t dtlen, int *hour, int *minute,
+ int *second, int *microsecond, int *tzoffset,
+ int *tzmicrosecond)
+{
// Parse the time portion of a datetime.isoformat() string
//
// Return codes:
@@ -785,19 +791,21 @@ parse_isoformat_time(const char *dtstr, size_t dtlen,
if (*tzinfo_pos == '+' || *tzinfo_pos == '-') {
break;
}
- } while(++tzinfo_pos < p_end);
+ } while (++tzinfo_pos < p_end);
- int rv = parse_hh_mm_ss_ff(dtstr, tzinfo_pos,
- hour, minute, second, microsecond);
+ int rv = parse_hh_mm_ss_ff(dtstr, tzinfo_pos, hour, minute, second,
+ microsecond);
if (rv < 0) {
return rv;
- } else if (tzinfo_pos == p_end) {
+ }
+ else if (tzinfo_pos == p_end) {
// We know that there's no time zone, so if there's stuff at the
// end of the string it's an error.
if (rv == 1) {
return -5;
- } else {
+ }
+ else {
return 0;
}
}
@@ -812,19 +820,18 @@ parse_isoformat_time(const char *dtstr, size_t dtlen,
return -5;
}
- int tzsign = (*tzinfo_pos == '-')?-1:1;
+ int tzsign = (*tzinfo_pos == '-') ? -1 : 1;
tzinfo_pos++;
int tzhour = 0, tzminute = 0, tzsecond = 0;
- rv = parse_hh_mm_ss_ff(tzinfo_pos, p_end,
- &tzhour, &tzminute, &tzsecond, tzmicrosecond);
+ rv = parse_hh_mm_ss_ff(tzinfo_pos, p_end, &tzhour, &tzminute, &tzsecond,
+ tzmicrosecond);
*tzoffset = tzsign * ((tzhour * 3600) + (tzminute * 60) + tzsecond);
*tzmicrosecond *= tzsign;
- return rv?-5:1;
+ return rv ? -5 : 1;
}
-
/* ---------------------------------------------------------------------------
* Create various objects, mostly without range checking.
*/
@@ -839,30 +846,33 @@ new_date_ex(int year, int month, int day, PyTypeObject *type)
return NULL;
}
- self = (PyDateTime_Date *) (type->tp_alloc(type, 0));
+ self = (PyDateTime_Date *)(type->tp_alloc(type, 0));
if (self != NULL)
set_date_fields(self, year, month, day);
- return (PyObject *) self;
+ return (PyObject *)self;
}
#define new_date(year, month, day) \
new_date_ex(year, month, day, &PyDateTime_DateType)
// Forward declaration
-static PyObject * new_datetime_ex(int, int, int, int, int, int, int,
- PyObject*, PyTypeObject*);
+static PyObject *
+new_datetime_ex(int, int, int, int, int, int, int, PyObject *, PyTypeObject *);
/* Create date instance with no range checking, or call subclass constructor */
static PyObject *
-new_date_subclass_ex(int year, int month, int day, PyObject *cls) {
+new_date_subclass_ex(int year, int month, int day, PyObject *cls)
+{
PyObject *result;
// We have "fast path" constructors for two subclasses: date and datetime
if ((PyTypeObject *)cls == &PyDateTime_DateType) {
result = new_date_ex(year, month, day, (PyTypeObject *)cls);
- } else if ((PyTypeObject *)cls == &PyDateTime_DateTimeType) {
+ }
+ else if ((PyTypeObject *)cls == &PyDateTime_DateTimeType) {
result = new_datetime_ex(year, month, day, 0, 0, 0, 0, Py_None,
(PyTypeObject *)cls);
- } else {
+ }
+ else {
result = PyObject_CallFunction(cls, "iii", year, month, day);
}
@@ -1281,7 +1291,8 @@ append_keyword_fold(PyObject *repr, int fold)
}
static inline PyObject *
-tzinfo_from_isoformat_results(int rv, int tzoffset, int tz_useconds) {
+tzinfo_from_isoformat_results(int rv, int tzoffset, int tz_useconds)
+{
PyObject *tzinfo;
if (rv == 1) {
// Create a timezone from offset in seconds (0 returns UTC)
@@ -1296,7 +1307,8 @@ tzinfo_from_isoformat_results(int rv, int tzoffset, int tz_useconds) {
}
tzinfo = new_timezone(delta, NULL);
Py_DECREF(delta);
- } else {
+ }
+ else {
tzinfo = Py_None;
Py_INCREF(Py_None);
}
@@ -2886,17 +2898,19 @@ date_fromordinal(PyObject *cls, PyObject *args)
/* Return the new date from a string as generated by date.isoformat() */
static PyObject *
-date_fromisoformat(PyObject *cls, PyObject *dtstr) {
+date_fromisoformat(PyObject *cls, PyObject *dtstr)
+{
assert(dtstr != NULL);
if (!PyUnicode_Check(dtstr)) {
- PyErr_SetString(PyExc_TypeError, "fromisoformat: argument must be str");
+ PyErr_SetString(PyExc_TypeError,
+ "fromisoformat: argument must be str");
return NULL;
}
Py_ssize_t len;
- const char * dt_ptr = PyUnicode_AsUTF8AndSize(dtstr, &len);
+ const char *dt_ptr = PyUnicode_AsUTF8AndSize(dtstr, &len);
if (dt_ptr == NULL) {
goto invalid_string_error;
}
@@ -2906,7 +2920,8 @@ date_fromisoformat(PyObject *cls, PyObject *dtstr) {
int rv;
if (len == 10) {
rv = parse_isoformat_date(dt_ptr, &year, &month, &day);
- } else {
+ }
+ else {
rv = -1;
}
@@ -2917,12 +2932,10 @@ date_fromisoformat(PyObject *cls, PyObject *dtstr) {
return new_date_subclass_ex(year, month, day, cls);
invalid_string_error:
- PyErr_Format(PyExc_ValueError, "Invalid isoformat string: %R",
- dtstr);
+ PyErr_Format(PyExc_ValueError, "Invalid isoformat string: %R", dtstr);
return NULL;
}
-
/*
* Date arithmetic.
*/
@@ -4863,52 +4876,65 @@ datetime_combine(PyObject *cls, PyObject *args, PyObject *kw)
}
static PyObject *
-_sanitize_isoformat_str(PyObject *dtstr, int *needs_decref) {
+_sanitize_isoformat_str(PyObject *dtstr)
+{
// `fromisoformat` allows surrogate characters in exactly one position,
// the separator; to allow datetime_fromisoformat to make the simplifying
// assumption that all valid strings can be encoded in UTF-8, this function
// replaces any surrogate character separators with `T`.
+ //
+ // The result of this, if not NULL, returns a new reference
Py_ssize_t len = PyUnicode_GetLength(dtstr);
- *needs_decref = 0;
- if (len <= 10 || !Py_UNICODE_IS_SURROGATE(PyUnicode_READ_CHAR(dtstr, 10))) {
+ if (len < 0) {
+ return NULL;
+ }
+
+ if (len <= 10 ||
+ !Py_UNICODE_IS_SURROGATE(PyUnicode_READ_CHAR(dtstr, 10))) {
+ Py_INCREF(dtstr);
return dtstr;
}
- PyObject *str_out = PyUnicode_New(len, PyUnicode_MAX_CHAR_VALUE(dtstr));
+ PyObject *str_out = _PyUnicode_Copy(dtstr);
if (str_out == NULL) {
return NULL;
}
- if (PyUnicode_CopyCharacters(str_out, 0, dtstr, 0, len) == -1 ||
- PyUnicode_WriteChar(str_out, 10, (Py_UCS4)'T')) {
+ if (PyUnicode_WriteChar(str_out, 10, (Py_UCS4)'T')) {
Py_DECREF(str_out);
return NULL;
}
- *needs_decref = 1;
return str_out;
}
static PyObject *
-datetime_fromisoformat(PyObject* cls, PyObject *dtstr) {
+datetime_fromisoformat(PyObject *cls, PyObject *dtstr)
+{
assert(dtstr != NULL);
if (!PyUnicode_Check(dtstr)) {
- PyErr_SetString(PyExc_TypeError, "fromisoformat: argument must be str");
+ PyErr_SetString(PyExc_TypeError,
+ "fromisoformat: argument must be str");
return NULL;
}
- int needs_decref = 0;
- dtstr = _sanitize_isoformat_str(dtstr, &needs_decref);
- if (dtstr == NULL) {
+ PyObject *dtstr_clean = _sanitize_isoformat_str(dtstr);
+ if (dtstr_clean == NULL) {
goto error;
}
Py_ssize_t len;
- const char * dt_ptr = PyUnicode_AsUTF8AndSize(dtstr, &len);
+ const char *dt_ptr = PyUnicode_AsUTF8AndSize(dtstr_clean, &len);
if (dt_ptr == NULL) {
- goto invalid_string_error;
+ if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) {
+ // Encoding errors are invalid string errors at this point
+ goto invalid_string_error;
+ }
+ else {
+ goto error;
+ }
}
const char *p = dt_ptr;
@@ -4924,8 +4950,9 @@ datetime_fromisoformat(PyObject* cls, PyObject *dtstr) {
// In UTF-8, the length of multi-byte characters is encoded in the MSB
if ((p[10] & 0x80) == 0) {
p += 11;
- } else {
- switch(p[10] & 0xf0) {
+ }
+ else {
+ switch (p[10] & 0xf0) {
case 0xe0:
p += 13;
break;
@@ -4939,15 +4966,14 @@ datetime_fromisoformat(PyObject* cls, PyObject *dtstr) {
}
len -= (p - dt_ptr);
- rv = parse_isoformat_time(p, len,
- &hour, &minute, &second, &microsecond,
- &tzoffset, &tzusec);
+ rv = parse_isoformat_time(p, len, &hour, &minute, &second,
+ &microsecond, &tzoffset, &tzusec);
}
if (rv < 0) {
goto invalid_string_error;
}
- PyObject* tzinfo = tzinfo_from_isoformat_results(rv, tzoffset, tzusec);
+ PyObject *tzinfo = tzinfo_from_isoformat_results(rv, tzoffset, tzusec);
if (tzinfo == NULL) {
goto error;
}
@@ -4956,23 +4982,18 @@ datetime_fromisoformat(PyObject* cls, PyObject *dtstr) {
second, microsecond, tzinfo, cls);
Py_DECREF(tzinfo);
- if (needs_decref) {
- Py_DECREF(dtstr);
- }
+ Py_DECREF(dtstr_clean);
return dt;
invalid_string_error:
PyErr_Format(PyExc_ValueError, "Invalid isoformat string: %R", dtstr);
error:
- if (needs_decref) {
- Py_DECREF(dtstr);
- }
+ Py_XDECREF(dtstr_clean);
return NULL;
}
-
/*
* Destructor.
*/