| 
									
										
										
										
											2003-03-23 14:32:54 +00:00
										 |  |  | /* csv module */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This module provides the low-level underpinnings of a CSV reading/writing | 
					
						
							|  |  |  | module.  Users should not use this module directly, but import the csv.py | 
					
						
							|  |  |  | module instead. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-17 14:30:31 +02:00
										 |  |  | // clinic/_csv.c.h uses internal pycore_modsupport.h API
 | 
					
						
							|  |  |  | #ifndef Py_BUILD_CORE_BUILTIN
 | 
					
						
							|  |  |  | #  define Py_BUILD_CORE_MODULE 1
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | #include "Python.h"
 | 
					
						
							| 
									
										
										
										
											2024-10-12 01:55:36 +08:00
										 |  |  | #include "pycore_pyatomic_ft_wrappers.h"
 | 
					
						
							| 
									
										
										
										
											2023-07-25 15:28:30 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <stddef.h>               // offsetof()
 | 
					
						
							| 
									
										
										
										
											2018-07-26 13:21:09 +03:00
										 |  |  | #include <stdbool.h>
 | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-16 10:34:23 -07:00
										 |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | module _csv | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | /*[clinic end generated code: output=da39a3ee5e6b4b0d input=385118b71aa43706]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "clinic/_csv.c.h"
 | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  | #define NOT_SET ((Py_UCS4)-1)
 | 
					
						
							|  |  |  | #define EOL ((Py_UCS4)-2)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-01-10 12:22:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-16 11:33:08 +02:00
										 |  |  | typedef struct { | 
					
						
							|  |  |  |     PyObject *error_obj;   /* CSV exception */ | 
					
						
							|  |  |  |     PyObject *dialects;   /* Dialect registry */ | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     PyTypeObject *dialect_type; | 
					
						
							|  |  |  |     PyTypeObject *reader_type; | 
					
						
							|  |  |  |     PyTypeObject *writer_type; | 
					
						
							| 
									
										
										
										
											2024-10-12 01:55:36 +08:00
										 |  |  |     Py_ssize_t field_limit;   /* max parsed field size */ | 
					
						
							| 
									
										
										
										
											2022-02-17 00:24:03 +09:00
										 |  |  |     PyObject *str_write; | 
					
						
							| 
									
										
										
										
											2012-05-16 11:33:08 +02:00
										 |  |  | } _csvstate; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  | static struct PyModuleDef _csvmodule; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-16 21:15:01 +08:00
										 |  |  | static inline _csvstate* | 
					
						
							|  |  |  | get_csv_state(PyObject *module) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     void *state = PyModule_GetState(module); | 
					
						
							|  |  |  |     assert(state != NULL); | 
					
						
							|  |  |  |     return (_csvstate *)state; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2012-05-16 11:33:08 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  | _csv_clear(PyObject *module) | 
					
						
							| 
									
										
										
										
											2012-05-16 11:33:08 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     _csvstate *module_state = PyModule_GetState(module); | 
					
						
							|  |  |  |     Py_CLEAR(module_state->error_obj); | 
					
						
							|  |  |  |     Py_CLEAR(module_state->dialects); | 
					
						
							|  |  |  |     Py_CLEAR(module_state->dialect_type); | 
					
						
							|  |  |  |     Py_CLEAR(module_state->reader_type); | 
					
						
							|  |  |  |     Py_CLEAR(module_state->writer_type); | 
					
						
							| 
									
										
										
										
											2022-02-17 00:24:03 +09:00
										 |  |  |     Py_CLEAR(module_state->str_write); | 
					
						
							| 
									
										
										
										
											2012-05-16 11:33:08 +02:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  | _csv_traverse(PyObject *module, visitproc visit, void *arg) | 
					
						
							| 
									
										
										
										
											2012-05-16 11:33:08 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     _csvstate *module_state = PyModule_GetState(module); | 
					
						
							|  |  |  |     Py_VISIT(module_state->error_obj); | 
					
						
							|  |  |  |     Py_VISIT(module_state->dialects); | 
					
						
							|  |  |  |     Py_VISIT(module_state->dialect_type); | 
					
						
							|  |  |  |     Py_VISIT(module_state->reader_type); | 
					
						
							|  |  |  |     Py_VISIT(module_state->writer_type); | 
					
						
							| 
									
										
										
										
											2012-05-16 11:33:08 +02:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  | _csv_free(void *module) | 
					
						
							| 
									
										
										
										
											2012-05-16 11:33:08 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  |     (void)_csv_clear((PyObject *)module); | 
					
						
							| 
									
										
										
										
											2012-05-16 11:33:08 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | typedef enum { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     START_RECORD, START_FIELD, ESCAPED_CHAR, IN_FIELD, | 
					
						
							|  |  |  |     IN_QUOTED_FIELD, ESCAPE_IN_QUOTED_FIELD, QUOTE_IN_QUOTED_FIELD, | 
					
						
							| 
									
										
										
										
											2013-03-19 22:41:47 -04:00
										 |  |  |     EAT_CRNL,AFTER_ESCAPED_CRNL | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } ParserState; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef enum { | 
					
						
							| 
									
										
										
										
											2023-04-12 17:32:30 -05:00
										 |  |  |     QUOTE_MINIMAL, QUOTE_ALL, QUOTE_NONNUMERIC, QUOTE_NONE, | 
					
						
							|  |  |  |     QUOTE_STRINGS, QUOTE_NOTNULL | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } QuoteStyle; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     QuoteStyle style; | 
					
						
							| 
									
										
										
										
											2015-12-25 19:53:18 +02:00
										 |  |  |     const char *name; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } StyleDesc; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-25 19:53:18 +02:00
										 |  |  | static const StyleDesc quote_styles[] = { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     { QUOTE_MINIMAL,    "QUOTE_MINIMAL" }, | 
					
						
							|  |  |  |     { QUOTE_ALL,        "QUOTE_ALL" }, | 
					
						
							|  |  |  |     { QUOTE_NONNUMERIC, "QUOTE_NONNUMERIC" }, | 
					
						
							|  |  |  |     { QUOTE_NONE,       "QUOTE_NONE" }, | 
					
						
							| 
									
										
										
										
											2023-04-12 17:32:30 -05:00
										 |  |  |     { QUOTE_STRINGS,    "QUOTE_STRINGS" }, | 
					
						
							|  |  |  |     { QUOTE_NOTNULL,    "QUOTE_NOTNULL" }, | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     { 0 } | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     PyObject_HEAD | 
					
						
							| 
									
										
										
										
											2007-08-06 19:32:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-26 13:21:09 +03:00
										 |  |  |     char doublequote;           /* is " represented by ""? */ | 
					
						
							|  |  |  |     char skipinitialspace;      /* ignore spaces following delimiter? */ | 
					
						
							|  |  |  |     char strict;                /* raise exception on bad CSV */ | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     int quoting;                /* style of quoting to write */ | 
					
						
							| 
									
										
										
										
											2018-07-26 13:21:09 +03:00
										 |  |  |     Py_UCS4 delimiter;          /* field separator */ | 
					
						
							|  |  |  |     Py_UCS4 quotechar;          /* quote character */ | 
					
						
							|  |  |  |     Py_UCS4 escapechar;         /* escape character */ | 
					
						
							|  |  |  |     PyObject *lineterminator;   /* string to write between records */ | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | } DialectObj; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     PyObject_HEAD | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     PyObject *input_iter;   /* iterate over this for input lines */ | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     DialectObj *dialect;    /* parsing dialect */ | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     PyObject *fields;           /* field list for current record */ | 
					
						
							|  |  |  |     ParserState state;          /* current CSV parse state */ | 
					
						
							| 
									
										
										
										
											2011-10-07 04:26:55 +02:00
										 |  |  |     Py_UCS4 *field;             /* temporary buffer */ | 
					
						
							| 
									
										
										
										
											2010-08-15 18:51:10 +00:00
										 |  |  |     Py_ssize_t field_size;      /* size of allocated buffer */ | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     Py_ssize_t field_len;       /* length of current field */ | 
					
						
							| 
									
										
										
										
											2024-01-30 14:21:12 +02:00
										 |  |  |     bool unquoted_field;        /* true if no quotes around the current field */ | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     unsigned long line_num;     /* Source-file line number */ | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } ReaderObj; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     PyObject_HEAD | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-14 15:45:14 +02:00
										 |  |  |     PyObject *write;    /* write output lines to this file */ | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     DialectObj *dialect;    /* parsing dialect */ | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-07 04:26:55 +02:00
										 |  |  |     Py_UCS4 *rec;            /* buffer for parser.join */ | 
					
						
							| 
									
										
										
										
											2010-08-15 18:51:10 +00:00
										 |  |  |     Py_ssize_t rec_size;        /* size of allocated record */ | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     Py_ssize_t rec_len;         /* length of record */ | 
					
						
							|  |  |  |     int num_fields;             /* number of fields in record */ | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     PyObject *error_obj;       /* cached error object */ | 
					
						
							|  |  |  | } WriterObj; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  | #define _DialectObj_CAST(op)    ((DialectObj *)(op))
 | 
					
						
							|  |  |  | #define _ReaderObj_CAST(op)     ((ReaderObj *)(op))
 | 
					
						
							|  |  |  | #define _WriterObj_CAST(op)     ((WriterObj *)(op))
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * DIALECT class | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  | get_dialect_from_registry(PyObject *name_obj, _csvstate *module_state) | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     PyObject *dialect_obj; | 
					
						
							| 
									
										
										
										
											2023-11-27 19:35:52 +02:00
										 |  |  |     if (PyDict_GetItemRef(module_state->dialects, name_obj, &dialect_obj) == 0) { | 
					
						
							|  |  |  |         PyErr_SetString(module_state->error_obj, "unknown dialect"); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |     return dialect_obj; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  | get_char_or_None(Py_UCS4 c) | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  |     if (c == NOT_SET) { | 
					
						
							| 
									
										
										
										
											2017-01-23 09:47:21 +02:00
										 |  |  |         Py_RETURN_NONE; | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							| 
									
										
										
										
											2011-09-28 07:41:54 +02:00
										 |  |  |         return PyUnicode_FromOrdinal(c); | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  | Dialect_get_lineterminator(PyObject *op, void *Py_UNUSED(ignored)) | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  |     DialectObj *self = _DialectObj_CAST(op); | 
					
						
							| 
									
										
										
										
											2022-11-14 13:08:15 +01:00
										 |  |  |     return Py_XNewRef(self->lineterminator); | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-07 23:59:30 +00:00
										 |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  | Dialect_get_delimiter(PyObject *op, void *Py_UNUSED(ignored)) | 
					
						
							| 
									
										
										
										
											2007-08-07 23:59:30 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  |     DialectObj *self = _DialectObj_CAST(op); | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  |     return get_char_or_None(self->delimiter); | 
					
						
							| 
									
										
										
										
											2007-08-07 23:59:30 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  | Dialect_get_escapechar(PyObject *op, void *Py_UNUSED(ignored)) | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  |     DialectObj *self = _DialectObj_CAST(op); | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  |     return get_char_or_None(self->escapechar); | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-01-07 04:42:45 +00:00
										 |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  | Dialect_get_quotechar(PyObject *op, void *Py_UNUSED(ignored)) | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  |     DialectObj *self = _DialectObj_CAST(op); | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  |     return get_char_or_None(self->quotechar); | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  | Dialect_get_quoting(PyObject *op, void *Py_UNUSED(ignored)) | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  |     DialectObj *self = _DialectObj_CAST(op); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     return PyLong_FromLong(self->quoting); | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2018-07-26 13:21:09 +03:00
										 |  |  | _set_bool(const char *name, char *target, PyObject *src, bool dflt) | 
					
						
							| 
									
										
										
										
											2005-01-07 04:42:45 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     if (src == NULL) | 
					
						
							|  |  |  |         *target = dflt; | 
					
						
							| 
									
										
										
										
											2012-08-15 23:18:25 +02:00
										 |  |  |     else { | 
					
						
							|  |  |  |         int b = PyObject_IsTrue(src); | 
					
						
							|  |  |  |         if (b < 0) | 
					
						
							|  |  |  |             return -1; | 
					
						
							| 
									
										
										
										
											2018-07-26 13:21:09 +03:00
										 |  |  |         *target = (char)b; | 
					
						
							| 
									
										
										
										
											2012-08-15 23:18:25 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2005-01-07 04:42:45 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | _set_int(const char *name, int *target, PyObject *src, int dflt) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     if (src == NULL) | 
					
						
							|  |  |  |         *target = dflt; | 
					
						
							|  |  |  |     else { | 
					
						
							| 
									
										
										
										
											2016-10-19 16:00:37 +02:00
										 |  |  |         int value; | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         if (!PyLong_CheckExact(src)) { | 
					
						
							|  |  |  |             PyErr_Format(PyExc_TypeError, | 
					
						
							|  |  |  |                          "\"%s\" must be an integer", name); | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-08-25 01:01:30 +02:00
										 |  |  |         value = PyLong_AsInt(src); | 
					
						
							| 
									
										
										
										
											2016-10-19 16:00:37 +02:00
										 |  |  |         if (value == -1 && PyErr_Occurred()) { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-10-19 16:00:37 +02:00
										 |  |  |         *target = value; | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2005-01-07 04:42:45 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2021-10-09 23:50:12 +09:00
										 |  |  | _set_char_or_none(const char *name, Py_UCS4 *target, PyObject *src, Py_UCS4 dflt) | 
					
						
							| 
									
										
										
										
											2005-01-07 04:42:45 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-10-09 23:50:12 +09:00
										 |  |  |     if (src == NULL) { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         *target = dflt; | 
					
						
							| 
									
										
										
										
											2021-10-09 23:50:12 +09:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     else { | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  |         *target = NOT_SET; | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         if (src != Py_None) { | 
					
						
							| 
									
										
										
										
											2013-12-19 16:27:18 +02:00
										 |  |  |             if (!PyUnicode_Check(src)) { | 
					
						
							|  |  |  |                 PyErr_Format(PyExc_TypeError, | 
					
						
							| 
									
										
										
										
											2021-10-09 23:50:12 +09:00
										 |  |  |                     "\"%s\" must be string or None, not %.200s", name, | 
					
						
							| 
									
										
										
										
											2020-02-07 03:37:06 +01:00
										 |  |  |                     Py_TYPE(src)->tp_name); | 
					
						
							| 
									
										
										
										
											2013-12-19 16:27:18 +02:00
										 |  |  |                 return -1; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-10-09 23:50:12 +09:00
										 |  |  |             Py_ssize_t len = PyUnicode_GetLength(src); | 
					
						
							| 
									
										
										
										
											2021-10-10 00:16:12 +09:00
										 |  |  |             if (len < 0) { | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-10-11 20:08:15 +09:00
										 |  |  |             if (len != 1) { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |                 PyErr_Format(PyExc_TypeError, | 
					
						
							| 
									
										
										
										
											2014-07-27 23:22:34 +03:00
										 |  |  |                     "\"%s\" must be a 1-character string", | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |                     name); | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-10-11 20:08:15 +09:00
										 |  |  |             *target = PyUnicode_READ_CHAR(src, 0); | 
					
						
							| 
									
										
										
										
											2021-10-09 23:50:12 +09:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | _set_char(const char *name, Py_UCS4 *target, PyObject *src, Py_UCS4 dflt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (src == NULL) { | 
					
						
							|  |  |  |         *target = dflt; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         if (!PyUnicode_Check(src)) { | 
					
						
							|  |  |  |             PyErr_Format(PyExc_TypeError, | 
					
						
							|  |  |  |                          "\"%s\" must be string, not %.200s", name, | 
					
						
							|  |  |  |                          Py_TYPE(src)->tp_name); | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         Py_ssize_t len = PyUnicode_GetLength(src); | 
					
						
							| 
									
										
										
										
											2021-10-10 00:16:12 +09:00
										 |  |  |         if (len < 0) { | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-10-11 20:08:15 +09:00
										 |  |  |         if (len != 1) { | 
					
						
							| 
									
										
										
										
											2021-10-09 23:50:12 +09:00
										 |  |  |             PyErr_Format(PyExc_TypeError, | 
					
						
							|  |  |  |                          "\"%s\" must be a 1-character string", | 
					
						
							|  |  |  |                          name); | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-10-11 20:08:15 +09:00
										 |  |  |         *target = PyUnicode_READ_CHAR(src, 0); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2005-01-07 04:42:45 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | _set_str(const char *name, PyObject **target, PyObject *src, const char *dflt) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     if (src == NULL) | 
					
						
							|  |  |  |         *target = PyUnicode_DecodeASCII(dflt, strlen(dflt), NULL); | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         if (src == Py_None) | 
					
						
							|  |  |  |             *target = NULL; | 
					
						
							| 
									
										
										
										
											2012-11-02 14:44:20 +01:00
										 |  |  |         else if (!PyUnicode_Check(src)) { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             PyErr_Format(PyExc_TypeError, | 
					
						
							|  |  |  |                          "\"%s\" must be a string", name); | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							| 
									
										
										
										
											2022-11-14 13:08:15 +01:00
										 |  |  |             Py_XSETREF(*target, Py_NewRef(src)); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2005-01-07 04:42:45 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | dialect_check_quoting(int quoting) | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-12-25 19:53:18 +02:00
										 |  |  |     const StyleDesc *qs; | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for (qs = quote_styles; qs->name; qs++) { | 
					
						
							| 
									
										
										
										
											2014-08-16 01:03:39 +02:00
										 |  |  |         if ((int)qs->style == quoting) | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     PyErr_Format(PyExc_TypeError, "bad \"quoting\" value"); | 
					
						
							|  |  |  |     return -1; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-22 15:34:16 +02:00
										 |  |  | static int | 
					
						
							| 
									
										
										
										
											2024-02-20 18:09:50 +02:00
										 |  |  | dialect_check_char(const char *name, Py_UCS4 c, DialectObj *dialect, bool allowspace) | 
					
						
							| 
									
										
										
										
											2024-01-22 15:34:16 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-02-20 18:09:50 +02:00
										 |  |  |     if (c == '\r' || c == '\n' || (c == ' ' && !allowspace)) { | 
					
						
							| 
									
										
										
										
											2024-01-22 15:34:16 +02:00
										 |  |  |         PyErr_Format(PyExc_ValueError, "bad %s value", name); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (PyUnicode_FindChar( | 
					
						
							|  |  |  |         dialect->lineterminator, c, 0, | 
					
						
							|  |  |  |         PyUnicode_GET_LENGTH(dialect->lineterminator), 1) >= 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         PyErr_Format(PyExc_ValueError, "bad %s or lineterminator value", name); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  static int | 
					
						
							|  |  |  | dialect_check_chars(const char *name1, const char *name2, Py_UCS4 c1, Py_UCS4 c2) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (c1 == c2 && c1 != NOT_SET) { | 
					
						
							|  |  |  |         PyErr_Format(PyExc_ValueError, "bad %s or %s value", name1, name2); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | #define D_OFF(x) offsetof(DialectObj, x)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct PyMemberDef Dialect_memberlist[] = { | 
					
						
							| 
									
										
										
										
											2023-07-25 15:28:30 +02:00
										 |  |  |     { "skipinitialspace",   Py_T_BOOL, D_OFF(skipinitialspace), Py_READONLY }, | 
					
						
							|  |  |  |     { "doublequote",        Py_T_BOOL, D_OFF(doublequote), Py_READONLY }, | 
					
						
							|  |  |  |     { "strict",             Py_T_BOOL, D_OFF(strict), Py_READONLY }, | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     { NULL } | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-07 20:35:56 +03:00
										 |  |  | #undef D_OFF
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | static PyGetSetDef Dialect_getsetlist[] = { | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  |     {"delimiter",          Dialect_get_delimiter}, | 
					
						
							|  |  |  |     {"escapechar",         Dialect_get_escapechar}, | 
					
						
							|  |  |  |     {"lineterminator",     Dialect_get_lineterminator}, | 
					
						
							|  |  |  |     {"quotechar",          Dialect_get_quotechar}, | 
					
						
							|  |  |  |     {"quoting",            Dialect_get_quoting}, | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     {NULL}, | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  | Dialect_dealloc(PyObject *self) | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     PyTypeObject *tp = Py_TYPE(self); | 
					
						
							| 
									
										
										
										
											2021-05-12 20:18:58 +02:00
										 |  |  |     PyObject_GC_UnTrack(self); | 
					
						
							|  |  |  |     tp->tp_clear((PyObject *)self); | 
					
						
							|  |  |  |     PyObject_GC_Del(self); | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     Py_DECREF(tp); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-27 17:20:04 +00:00
										 |  |  | static char *dialect_kws[] = { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     "dialect", | 
					
						
							|  |  |  |     "delimiter", | 
					
						
							|  |  |  |     "doublequote", | 
					
						
							|  |  |  |     "escapechar", | 
					
						
							|  |  |  |     "lineterminator", | 
					
						
							|  |  |  |     "quotechar", | 
					
						
							|  |  |  |     "quoting", | 
					
						
							|  |  |  |     "skipinitialspace", | 
					
						
							|  |  |  |     "strict", | 
					
						
							|  |  |  |     NULL | 
					
						
							| 
									
										
										
										
											2005-01-07 04:42:45 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  | static _csvstate * | 
					
						
							|  |  |  | _csv_state_from_type(PyTypeObject *type, const char *name) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-02-11 17:22:11 +01:00
										 |  |  |     PyObject *module = PyType_GetModuleByDef(type, &_csvmodule); | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     if (module == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     _csvstate *module_state = PyModule_GetState(module); | 
					
						
							|  |  |  |     if (module_state == NULL) { | 
					
						
							|  |  |  |         PyErr_Format(PyExc_SystemError, | 
					
						
							|  |  |  |                      "%s: No _csv module state found", name); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return module_state; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-01-11 04:49:53 +00:00
										 |  |  | static PyObject * | 
					
						
							|  |  |  | dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     DialectObj *self; | 
					
						
							|  |  |  |     PyObject *ret = NULL; | 
					
						
							|  |  |  |     PyObject *dialect = NULL; | 
					
						
							|  |  |  |     PyObject *delimiter = NULL; | 
					
						
							|  |  |  |     PyObject *doublequote = NULL; | 
					
						
							|  |  |  |     PyObject *escapechar = NULL; | 
					
						
							|  |  |  |     PyObject *lineterminator = NULL; | 
					
						
							|  |  |  |     PyObject *quotechar = NULL; | 
					
						
							|  |  |  |     PyObject *quoting = NULL; | 
					
						
							|  |  |  |     PyObject *skipinitialspace = NULL; | 
					
						
							|  |  |  |     PyObject *strict = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!PyArg_ParseTupleAndKeywords(args, kwargs, | 
					
						
							|  |  |  |                                      "|OOOOOOOOO", dialect_kws, | 
					
						
							|  |  |  |                                      &dialect, | 
					
						
							|  |  |  |                                      &delimiter, | 
					
						
							|  |  |  |                                      &doublequote, | 
					
						
							|  |  |  |                                      &escapechar, | 
					
						
							|  |  |  |                                      &lineterminator, | 
					
						
							|  |  |  |                                      "echar, | 
					
						
							|  |  |  |                                      "ing, | 
					
						
							|  |  |  |                                      &skipinitialspace, | 
					
						
							|  |  |  |                                      &strict)) | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     _csvstate *module_state = _csv_state_from_type(type, "dialect_new"); | 
					
						
							|  |  |  |     if (module_state == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     if (dialect != NULL) { | 
					
						
							| 
									
										
										
										
											2012-11-02 14:44:20 +01:00
										 |  |  |         if (PyUnicode_Check(dialect)) { | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |             dialect = get_dialect_from_registry(dialect, module_state); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             if (dialect == NULL) | 
					
						
							|  |  |  |                 return NULL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             Py_INCREF(dialect); | 
					
						
							|  |  |  |         /* Can we reuse this instance? */ | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |         if (PyObject_TypeCheck(dialect, module_state->dialect_type) && | 
					
						
							| 
									
										
										
										
											2017-03-23 17:53:47 +02:00
										 |  |  |             delimiter == NULL && | 
					
						
							|  |  |  |             doublequote == NULL && | 
					
						
							|  |  |  |             escapechar == NULL && | 
					
						
							|  |  |  |             lineterminator == NULL && | 
					
						
							|  |  |  |             quotechar == NULL && | 
					
						
							|  |  |  |             quoting == NULL && | 
					
						
							|  |  |  |             skipinitialspace == NULL && | 
					
						
							|  |  |  |             strict == NULL) | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             return dialect; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     self = (DialectObj *)type->tp_alloc(type, 0); | 
					
						
							|  |  |  |     if (self == NULL) { | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |         Py_CLEAR(dialect); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     self->lineterminator = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Py_XINCREF(delimiter); | 
					
						
							|  |  |  |     Py_XINCREF(doublequote); | 
					
						
							|  |  |  |     Py_XINCREF(escapechar); | 
					
						
							|  |  |  |     Py_XINCREF(lineterminator); | 
					
						
							|  |  |  |     Py_XINCREF(quotechar); | 
					
						
							|  |  |  |     Py_XINCREF(quoting); | 
					
						
							|  |  |  |     Py_XINCREF(skipinitialspace); | 
					
						
							|  |  |  |     Py_XINCREF(strict); | 
					
						
							|  |  |  |     if (dialect != NULL) { | 
					
						
							| 
									
										
										
										
											2021-07-14 00:56:45 +02:00
										 |  |  | #define DIALECT_GETATTR(v, n)                            \
 | 
					
						
							|  |  |  |         do {                                             \ | 
					
						
							|  |  |  |             if (v == NULL) {                             \ | 
					
						
							|  |  |  |                 v = PyObject_GetAttrString(dialect, n);  \ | 
					
						
							|  |  |  |                 if (v == NULL)                           \ | 
					
						
							|  |  |  |                     PyErr_Clear();                       \ | 
					
						
							|  |  |  |             }                                            \ | 
					
						
							|  |  |  |         } while (0) | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         DIALECT_GETATTR(delimiter, "delimiter"); | 
					
						
							|  |  |  |         DIALECT_GETATTR(doublequote, "doublequote"); | 
					
						
							|  |  |  |         DIALECT_GETATTR(escapechar, "escapechar"); | 
					
						
							|  |  |  |         DIALECT_GETATTR(lineterminator, "lineterminator"); | 
					
						
							|  |  |  |         DIALECT_GETATTR(quotechar, "quotechar"); | 
					
						
							|  |  |  |         DIALECT_GETATTR(quoting, "quoting"); | 
					
						
							|  |  |  |         DIALECT_GETATTR(skipinitialspace, "skipinitialspace"); | 
					
						
							|  |  |  |         DIALECT_GETATTR(strict, "strict"); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-10-07 20:35:56 +03:00
										 |  |  | #undef DIALECT_GETATTR
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* check types and convert to C values */ | 
					
						
							| 
									
										
										
										
											2005-01-07 04:42:45 +00:00
										 |  |  | #define DIASET(meth, name, target, src, dflt) \
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     if (meth(name, target, src, dflt)) \ | 
					
						
							|  |  |  |         goto err | 
					
						
							|  |  |  |     DIASET(_set_char, "delimiter", &self->delimiter, delimiter, ','); | 
					
						
							| 
									
										
										
										
											2018-07-26 13:21:09 +03:00
										 |  |  |     DIASET(_set_bool, "doublequote", &self->doublequote, doublequote, true); | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  |     DIASET(_set_char_or_none, "escapechar", &self->escapechar, escapechar, NOT_SET); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     DIASET(_set_str, "lineterminator", &self->lineterminator, lineterminator, "\r\n"); | 
					
						
							| 
									
										
										
										
											2021-10-09 23:50:12 +09:00
										 |  |  |     DIASET(_set_char_or_none, "quotechar", &self->quotechar, quotechar, '"'); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     DIASET(_set_int, "quoting", &self->quoting, quoting, QUOTE_MINIMAL); | 
					
						
							| 
									
										
										
										
											2018-07-26 13:21:09 +03:00
										 |  |  |     DIASET(_set_bool, "skipinitialspace", &self->skipinitialspace, skipinitialspace, false); | 
					
						
							|  |  |  |     DIASET(_set_bool, "strict", &self->strict, strict, false); | 
					
						
							| 
									
										
										
										
											2024-10-07 20:35:56 +03:00
										 |  |  | #undef DIASET
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* validate options */ | 
					
						
							|  |  |  |     if (dialect_check_quoting(self->quoting)) | 
					
						
							|  |  |  |         goto err; | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  |     if (self->delimiter == NOT_SET) { | 
					
						
							| 
									
										
										
										
											2013-12-19 16:27:18 +02:00
										 |  |  |         PyErr_SetString(PyExc_TypeError, | 
					
						
							| 
									
										
										
										
											2014-07-27 23:22:34 +03:00
										 |  |  |                         "\"delimiter\" must be a 1-character string"); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         goto err; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (quotechar == Py_None && quoting == NULL) | 
					
						
							|  |  |  |         self->quoting = QUOTE_NONE; | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  |     if (self->quoting != QUOTE_NONE && self->quotechar == NOT_SET) { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         PyErr_SetString(PyExc_TypeError, | 
					
						
							|  |  |  |                         "quotechar must be set if quoting enabled"); | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  |     if (self->lineterminator == NULL) { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         PyErr_SetString(PyExc_TypeError, "lineterminator must be set"); | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-02-20 18:09:50 +02:00
										 |  |  |     if (dialect_check_char("delimiter", self->delimiter, self, true) || | 
					
						
							|  |  |  |         dialect_check_char("escapechar", self->escapechar, self, | 
					
						
							|  |  |  |                            !self->skipinitialspace) || | 
					
						
							|  |  |  |         dialect_check_char("quotechar", self->quotechar, self, | 
					
						
							|  |  |  |                            !self->skipinitialspace) || | 
					
						
							| 
									
										
										
										
											2024-01-22 15:34:16 +02:00
										 |  |  |         dialect_check_chars("delimiter", "escapechar", | 
					
						
							|  |  |  |                             self->delimiter, self->escapechar) || | 
					
						
							|  |  |  |         dialect_check_chars("delimiter", "quotechar", | 
					
						
							|  |  |  |                             self->delimiter, self->quotechar) || | 
					
						
							|  |  |  |         dialect_check_chars("escapechar", "quotechar", | 
					
						
							|  |  |  |                             self->escapechar, self->quotechar)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-14 13:08:15 +01:00
										 |  |  |     ret = Py_NewRef(self); | 
					
						
							| 
									
										
										
										
											2005-01-07 04:42:45 +00:00
										 |  |  | err: | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     Py_CLEAR(self); | 
					
						
							|  |  |  |     Py_CLEAR(dialect); | 
					
						
							|  |  |  |     Py_CLEAR(delimiter); | 
					
						
							|  |  |  |     Py_CLEAR(doublequote); | 
					
						
							|  |  |  |     Py_CLEAR(escapechar); | 
					
						
							|  |  |  |     Py_CLEAR(lineterminator); | 
					
						
							|  |  |  |     Py_CLEAR(quotechar); | 
					
						
							|  |  |  |     Py_CLEAR(quoting); | 
					
						
							|  |  |  |     Py_CLEAR(skipinitialspace); | 
					
						
							|  |  |  |     Py_CLEAR(strict); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     return ret; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  | /* Since dialect is now a heap type, it inherits pickling method for
 | 
					
						
							| 
									
										
										
										
											2021-10-07 10:34:42 +02:00
										 |  |  |  * protocol 0 and 1 from object, therefore it needs to be overridden */ | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | PyDoc_STRVAR(dialect_reduce_doc, "raises an exception to avoid pickling"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | Dialect_reduce(PyObject *self, PyObject *args) { | 
					
						
							|  |  |  |     PyErr_Format(PyExc_TypeError, | 
					
						
							|  |  |  |         "cannot pickle '%.100s' instances", _PyType_Name(Py_TYPE(self))); | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct PyMethodDef dialect_methods[] = { | 
					
						
							|  |  |  |     {"__reduce__", Dialect_reduce, METH_VARARGS, dialect_reduce_doc}, | 
					
						
							|  |  |  |     {"__reduce_ex__", Dialect_reduce, METH_VARARGS, dialect_reduce_doc}, | 
					
						
							|  |  |  |     {NULL, NULL} | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  | PyDoc_STRVAR(Dialect_Type_doc, | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | "CSV dialect\n" | 
					
						
							|  |  |  | "\n" | 
					
						
							|  |  |  | "The Dialect type records CSV parsing and generation options.\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-12 20:18:58 +02:00
										 |  |  | static int | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  | Dialect_clear(PyObject *op) | 
					
						
							| 
									
										
										
										
											2021-05-12 20:18:58 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  |     DialectObj *self = _DialectObj_CAST(op); | 
					
						
							| 
									
										
										
										
											2021-05-12 20:18:58 +02:00
										 |  |  |     Py_CLEAR(self->lineterminator); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  | Dialect_traverse(PyObject *op, visitproc visit, void *arg) | 
					
						
							| 
									
										
										
										
											2021-05-12 20:18:58 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  |     DialectObj *self = _DialectObj_CAST(op); | 
					
						
							| 
									
										
										
										
											2021-05-12 20:18:58 +02:00
										 |  |  |     Py_VISIT(self->lineterminator); | 
					
						
							|  |  |  |     Py_VISIT(Py_TYPE(self)); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  | static PyType_Slot Dialect_Type_slots[] = { | 
					
						
							|  |  |  |     {Py_tp_doc, (char*)Dialect_Type_doc}, | 
					
						
							|  |  |  |     {Py_tp_members, Dialect_memberlist}, | 
					
						
							|  |  |  |     {Py_tp_getset, Dialect_getsetlist}, | 
					
						
							|  |  |  |     {Py_tp_new, dialect_new}, | 
					
						
							|  |  |  |     {Py_tp_methods, dialect_methods}, | 
					
						
							|  |  |  |     {Py_tp_dealloc, Dialect_dealloc}, | 
					
						
							| 
									
										
										
										
											2021-05-12 20:18:58 +02:00
										 |  |  |     {Py_tp_clear, Dialect_clear}, | 
					
						
							|  |  |  |     {Py_tp_traverse, Dialect_traverse}, | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     {0, NULL} | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  | PyType_Spec Dialect_Type_spec = { | 
					
						
							|  |  |  |     .name = "_csv.Dialect", | 
					
						
							|  |  |  |     .basicsize = sizeof(DialectObj), | 
					
						
							| 
									
										
										
										
											2021-06-17 12:06:09 +02:00
										 |  |  |     .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | | 
					
						
							|  |  |  |               Py_TPFLAGS_IMMUTABLETYPE), | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     .slots = Dialect_Type_slots, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-01-11 01:07:23 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Return an instance of the dialect type, given a Python instance or kwarg | 
					
						
							|  |  |  |  * description of the dialect | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  | _call_dialect(_csvstate *module_state, PyObject *dialect_inst, PyObject *kwargs) | 
					
						
							| 
									
										
										
										
											2005-01-11 01:07:23 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     PyObject *type = (PyObject *)module_state->dialect_type; | 
					
						
							| 
									
										
										
										
											2016-08-23 00:21:34 +02:00
										 |  |  |     if (dialect_inst) { | 
					
						
							| 
									
										
										
										
											2020-02-11 17:46:57 +01:00
										 |  |  |         return PyObject_VectorcallDict(type, &dialect_inst, 1, kwargs); | 
					
						
							| 
									
										
										
										
											2016-08-23 00:21:34 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							| 
									
										
										
										
											2020-02-11 17:46:57 +01:00
										 |  |  |         return PyObject_VectorcallDict(type, NULL, 0, kwargs); | 
					
						
							| 
									
										
										
										
											2016-08-23 00:21:34 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-01-11 01:07:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-01-13 11:30:54 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * READER | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2005-01-12 09:45:18 +00:00
										 |  |  | static int | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | parse_save_field(ReaderObj *self) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-01-30 14:21:12 +02:00
										 |  |  |     int quoting = self->dialect->quoting; | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     PyObject *field; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-30 14:21:12 +02:00
										 |  |  |     if (self->unquoted_field && | 
					
						
							|  |  |  |         self->field_len == 0 && | 
					
						
							|  |  |  |         (quoting == QUOTE_NOTNULL || quoting == QUOTE_STRINGS)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         field = Py_NewRef(Py_None); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         field = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, | 
					
						
							|  |  |  |                                         (void *) self->field, self->field_len); | 
					
						
							|  |  |  |         if (field == NULL) { | 
					
						
							| 
									
										
										
										
											2011-10-07 04:26:55 +02:00
										 |  |  |             return -1; | 
					
						
							| 
									
										
										
										
											2024-01-30 14:21:12 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |         if (self->unquoted_field && | 
					
						
							|  |  |  |             self->field_len != 0 && | 
					
						
							|  |  |  |             (quoting == QUOTE_NONNUMERIC || quoting == QUOTE_STRINGS)) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             PyObject *tmp = PyNumber_Float(field); | 
					
						
							|  |  |  |             Py_DECREF(field); | 
					
						
							|  |  |  |             if (tmp == NULL) { | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             field = tmp; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         self->field_len = 0; | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-11-14 21:29:34 +01:00
										 |  |  |     if (PyList_Append(self->fields, field) < 0) { | 
					
						
							|  |  |  |         Py_DECREF(field); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     Py_DECREF(field); | 
					
						
							|  |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | parse_grow_buff(ReaderObj *self) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-08-16 09:27:50 +05:00
										 |  |  |     assert((size_t)self->field_size <= PY_SSIZE_T_MAX / sizeof(Py_UCS4)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Py_ssize_t field_size_new = self->field_size ? 2 * self->field_size : 4096; | 
					
						
							|  |  |  |     Py_UCS4 *field_new = self->field; | 
					
						
							|  |  |  |     PyMem_Resize(field_new, Py_UCS4, field_size_new); | 
					
						
							|  |  |  |     if (field_new == NULL) { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         PyErr_NoMemory(); | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-08-16 09:27:50 +05:00
										 |  |  |     self->field = field_new; | 
					
						
							|  |  |  |     self->field_size = field_size_new; | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     return 1; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-01-11 07:32:02 +00:00
										 |  |  | static int | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  | parse_add_char(ReaderObj *self, _csvstate *module_state, Py_UCS4 c) | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-10-12 01:55:36 +08:00
										 |  |  |     Py_ssize_t field_limit = FT_ATOMIC_LOAD_SSIZE_RELAXED(module_state->field_limit); | 
					
						
							|  |  |  |     if (self->field_len >= field_limit) { | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |         PyErr_Format(module_state->error_obj, | 
					
						
							| 
									
										
										
										
											2024-10-12 01:55:36 +08:00
										 |  |  |                      "field larger than field limit (%zd)", | 
					
						
							|  |  |  |                      field_limit); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (self->field_len == self->field_size && !parse_grow_buff(self)) | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     self->field[self->field_len++] = c; | 
					
						
							|  |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-01-11 07:32:02 +00:00
										 |  |  | static int | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  | parse_process_char(ReaderObj *self, _csvstate *module_state, Py_UCS4 c) | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     DialectObj *dialect = self->dialect; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (self->state) { | 
					
						
							|  |  |  |     case START_RECORD: | 
					
						
							|  |  |  |         /* start of record */ | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  |         if (c == EOL) | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             /* empty line - return [] */ | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         else if (c == '\n' || c == '\r') { | 
					
						
							|  |  |  |             self->state = EAT_CRNL; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         /* normal character - handle as START_FIELD */ | 
					
						
							|  |  |  |         self->state = START_FIELD; | 
					
						
							| 
									
										
										
										
											2024-06-27 11:58:44 +02:00
										 |  |  |         _Py_FALLTHROUGH; | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     case START_FIELD: | 
					
						
							|  |  |  |         /* expecting field */ | 
					
						
							| 
									
										
										
										
											2024-01-30 14:21:12 +02:00
										 |  |  |         self->unquoted_field = true; | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  |         if (c == '\n' || c == '\r' || c == EOL) { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             /* save empty field - return [fields] */ | 
					
						
							|  |  |  |             if (parse_save_field(self) < 0) | 
					
						
							|  |  |  |                 return -1; | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  |             self->state = (c == EOL ? START_RECORD : EAT_CRNL); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         else if (c == dialect->quotechar && | 
					
						
							|  |  |  |                  dialect->quoting != QUOTE_NONE) { | 
					
						
							|  |  |  |             /* start quoted field */ | 
					
						
							| 
									
										
										
										
											2024-01-30 14:21:12 +02:00
										 |  |  |             self->unquoted_field = false; | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             self->state = IN_QUOTED_FIELD; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (c == dialect->escapechar) { | 
					
						
							|  |  |  |             /* possible escaped character */ | 
					
						
							|  |  |  |             self->state = ESCAPED_CHAR; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (c == ' ' && dialect->skipinitialspace) | 
					
						
							| 
									
										
										
										
											2022-10-07 11:15:34 -07:00
										 |  |  |             /* ignore spaces at start of field */ | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             ; | 
					
						
							|  |  |  |         else if (c == dialect->delimiter) { | 
					
						
							|  |  |  |             /* save empty field */ | 
					
						
							|  |  |  |             if (parse_save_field(self) < 0) | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  |             /* begin new unquoted field */ | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |             if (parse_add_char(self, module_state, c) < 0) | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |                 return -1; | 
					
						
							|  |  |  |             self->state = IN_FIELD; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case ESCAPED_CHAR: | 
					
						
							| 
									
										
										
										
											2013-03-20 00:15:20 -04:00
										 |  |  |         if (c == '\n' || c=='\r') { | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |             if (parse_add_char(self, module_state, c) < 0) | 
					
						
							| 
									
										
										
										
											2013-03-19 22:41:47 -04:00
										 |  |  |                 return -1; | 
					
						
							|  |  |  |             self->state = AFTER_ESCAPED_CRNL; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  |         if (c == EOL) | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             c = '\n'; | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |         if (parse_add_char(self, module_state, c) < 0) | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             return -1; | 
					
						
							|  |  |  |         self->state = IN_FIELD; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-19 22:41:47 -04:00
										 |  |  |     case AFTER_ESCAPED_CRNL: | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  |         if (c == EOL) | 
					
						
							| 
									
										
										
										
											2013-03-19 22:41:47 -04:00
										 |  |  |             break; | 
					
						
							| 
									
										
										
										
											2024-06-27 11:58:44 +02:00
										 |  |  |         _Py_FALLTHROUGH; | 
					
						
							| 
									
										
										
										
											2013-03-19 22:41:47 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     case IN_FIELD: | 
					
						
							|  |  |  |         /* in unquoted field */ | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  |         if (c == '\n' || c == '\r' || c == EOL) { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             /* end of line - return [fields] */ | 
					
						
							|  |  |  |             if (parse_save_field(self) < 0) | 
					
						
							|  |  |  |                 return -1; | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  |             self->state = (c == EOL ? START_RECORD : EAT_CRNL); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         else if (c == dialect->escapechar) { | 
					
						
							|  |  |  |             /* possible escaped character */ | 
					
						
							|  |  |  |             self->state = ESCAPED_CHAR; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (c == dialect->delimiter) { | 
					
						
							|  |  |  |             /* save field - wait for new field */ | 
					
						
							|  |  |  |             if (parse_save_field(self) < 0) | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |             self->state = START_FIELD; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  |             /* normal character - save in field */ | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |             if (parse_add_char(self, module_state, c) < 0) | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |                 return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case IN_QUOTED_FIELD: | 
					
						
							|  |  |  |         /* in quoted field */ | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  |         if (c == EOL) | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             ; | 
					
						
							|  |  |  |         else if (c == dialect->escapechar) { | 
					
						
							|  |  |  |             /* Possible escape character */ | 
					
						
							|  |  |  |             self->state = ESCAPE_IN_QUOTED_FIELD; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (c == dialect->quotechar && | 
					
						
							|  |  |  |                  dialect->quoting != QUOTE_NONE) { | 
					
						
							|  |  |  |             if (dialect->doublequote) { | 
					
						
							|  |  |  |                 /* doublequote; " represented by "" */ | 
					
						
							|  |  |  |                 self->state = QUOTE_IN_QUOTED_FIELD; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else { | 
					
						
							|  |  |  |                 /* end of quote part of field */ | 
					
						
							|  |  |  |                 self->state = IN_FIELD; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  |             /* normal character - save in field */ | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |             if (parse_add_char(self, module_state, c) < 0) | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |                 return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case ESCAPE_IN_QUOTED_FIELD: | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  |         if (c == EOL) | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             c = '\n'; | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |         if (parse_add_char(self, module_state, c) < 0) | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             return -1; | 
					
						
							|  |  |  |         self->state = IN_QUOTED_FIELD; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case QUOTE_IN_QUOTED_FIELD: | 
					
						
							| 
									
										
										
										
											2016-04-17 08:32:47 +03:00
										 |  |  |         /* doublequote - seen a quote in a quoted field */ | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         if (dialect->quoting != QUOTE_NONE && | 
					
						
							|  |  |  |             c == dialect->quotechar) { | 
					
						
							|  |  |  |             /* save "" as " */ | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |             if (parse_add_char(self, module_state, c) < 0) | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |                 return -1; | 
					
						
							|  |  |  |             self->state = IN_QUOTED_FIELD; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (c == dialect->delimiter) { | 
					
						
							|  |  |  |             /* save field - wait for new field */ | 
					
						
							|  |  |  |             if (parse_save_field(self) < 0) | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |             self->state = START_FIELD; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  |         else if (c == '\n' || c == '\r' || c == EOL) { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             /* end of line - return [fields] */ | 
					
						
							|  |  |  |             if (parse_save_field(self) < 0) | 
					
						
							|  |  |  |                 return -1; | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  |             self->state = (c == EOL ? START_RECORD : EAT_CRNL); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         else if (!dialect->strict) { | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |             if (parse_add_char(self, module_state, c) < 0) | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |                 return -1; | 
					
						
							|  |  |  |             self->state = IN_FIELD; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  |             /* illegal */ | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |             PyErr_Format(module_state->error_obj, "'%c' expected after '%c'", | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |                             dialect->delimiter, | 
					
						
							|  |  |  |                             dialect->quotechar); | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case EAT_CRNL: | 
					
						
							|  |  |  |         if (c == '\n' || c == '\r') | 
					
						
							|  |  |  |             ; | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  |         else if (c == EOL) | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             self->state = START_RECORD; | 
					
						
							|  |  |  |         else { | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |             PyErr_Format(module_state->error_obj, | 
					
						
							| 
									
										
										
										
											2024-01-10 14:52:29 +02:00
										 |  |  |                          "new-line character seen in unquoted field - " | 
					
						
							|  |  |  |                          "do you need to open the file with newline=''?"); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-01-13 11:30:54 +00:00
										 |  |  | static int | 
					
						
							|  |  |  | parse_reset(ReaderObj *self) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-04-06 09:45:48 +03:00
										 |  |  |     Py_XSETREF(self->fields, PyList_New(0)); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     if (self->fields == NULL) | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     self->field_len = 0; | 
					
						
							|  |  |  |     self->state = START_RECORD; | 
					
						
							| 
									
										
										
										
											2024-01-30 14:21:12 +02:00
										 |  |  |     self->unquoted_field = false; | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2005-01-13 11:30:54 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  | Reader_iternext(PyObject *op) | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  |     ReaderObj *self = _ReaderObj_CAST(op); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     PyObject *fields = NULL; | 
					
						
							| 
									
										
										
										
											2011-10-07 04:26:55 +02:00
										 |  |  |     Py_UCS4 c; | 
					
						
							|  |  |  |     Py_ssize_t pos, linelen; | 
					
						
							| 
									
										
										
										
											2022-05-13 12:41:05 +02:00
										 |  |  |     int kind; | 
					
						
							| 
									
										
										
										
											2020-04-11 10:48:40 +03:00
										 |  |  |     const void *data; | 
					
						
							| 
									
										
										
										
											2011-10-07 04:26:55 +02:00
										 |  |  |     PyObject *lineobj; | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     _csvstate *module_state = _csv_state_from_type(Py_TYPE(self), | 
					
						
							|  |  |  |                                                    "Reader.__next__"); | 
					
						
							|  |  |  |     if (module_state == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     if (parse_reset(self) < 0) | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     do { | 
					
						
							|  |  |  |         lineobj = PyIter_Next(self->input_iter); | 
					
						
							|  |  |  |         if (lineobj == NULL) { | 
					
						
							|  |  |  |             /* End of input OR exception */ | 
					
						
							| 
									
										
										
										
											2012-09-25 02:30:27 -07:00
										 |  |  |             if (!PyErr_Occurred() && (self->field_len != 0 || | 
					
						
							|  |  |  |                                       self->state == IN_QUOTED_FIELD)) { | 
					
						
							|  |  |  |                 if (self->dialect->strict) | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |                     PyErr_SetString(module_state->error_obj, | 
					
						
							| 
									
										
										
										
											2012-09-25 02:37:20 -07:00
										 |  |  |                                     "unexpected end of data"); | 
					
						
							| 
									
										
										
										
											2012-09-25 02:30:27 -07:00
										 |  |  |                 else if (parse_save_field(self) >= 0) | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             return NULL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (!PyUnicode_Check(lineobj)) { | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |             PyErr_Format(module_state->error_obj, | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |                          "iterator should return strings, " | 
					
						
							|  |  |  |                          "not %.200s " | 
					
						
							| 
									
										
										
										
											2020-06-05 23:56:06 +03:00
										 |  |  |                          "(the file should be opened in text mode)", | 
					
						
							| 
									
										
										
										
											2020-02-07 03:37:06 +01:00
										 |  |  |                          Py_TYPE(lineobj)->tp_name | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |                 ); | 
					
						
							|  |  |  |             Py_DECREF(lineobj); | 
					
						
							|  |  |  |             return NULL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         ++self->line_num; | 
					
						
							| 
									
										
										
										
											2011-10-07 04:26:55 +02:00
										 |  |  |         kind = PyUnicode_KIND(lineobj); | 
					
						
							|  |  |  |         data = PyUnicode_DATA(lineobj); | 
					
						
							|  |  |  |         pos = 0; | 
					
						
							|  |  |  |         linelen = PyUnicode_GET_LENGTH(lineobj); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         while (linelen--) { | 
					
						
							| 
									
										
										
										
											2011-10-07 04:26:55 +02:00
										 |  |  |             c = PyUnicode_READ(kind, data, pos); | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |             if (parse_process_char(self, module_state, c) < 0) { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |                 Py_DECREF(lineobj); | 
					
						
							|  |  |  |                 goto err; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2011-10-07 04:26:55 +02:00
										 |  |  |             pos++; | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         Py_DECREF(lineobj); | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  |         if (parse_process_char(self, module_state, EOL) < 0) | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             goto err; | 
					
						
							|  |  |  |     } while (self->state != START_RECORD); | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     fields = self->fields; | 
					
						
							|  |  |  |     self->fields = NULL; | 
					
						
							| 
									
										
										
										
											2005-01-13 11:30:54 +00:00
										 |  |  | err: | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     return fields; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  | Reader_dealloc(PyObject *op) | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  |     ReaderObj *self = _ReaderObj_CAST(op); | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     PyTypeObject *tp = Py_TYPE(self); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     PyObject_GC_UnTrack(self); | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  |     (void)tp->tp_clear(op); | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     if (self->field != NULL) { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         PyMem_Free(self->field); | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |         self->field = NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     PyObject_GC_Del(self); | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     Py_DECREF(tp); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-04-14 02:20:55 +00:00
										 |  |  | static int | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  | Reader_traverse(PyObject *op, visitproc visit, void *arg) | 
					
						
							| 
									
										
										
										
											2003-04-14 02:20:55 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  |     ReaderObj *self = _ReaderObj_CAST(op); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     Py_VISIT(self->dialect); | 
					
						
							|  |  |  |     Py_VISIT(self->input_iter); | 
					
						
							|  |  |  |     Py_VISIT(self->fields); | 
					
						
							| 
									
										
										
										
											2021-05-12 20:18:58 +02:00
										 |  |  |     Py_VISIT(Py_TYPE(self)); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2003-04-14 02:20:55 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  | Reader_clear(PyObject *op) | 
					
						
							| 
									
										
										
										
											2003-04-14 02:20:55 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  |     ReaderObj *self = _ReaderObj_CAST(op); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     Py_CLEAR(self->dialect); | 
					
						
							|  |  |  |     Py_CLEAR(self->input_iter); | 
					
						
							|  |  |  |     Py_CLEAR(self->fields); | 
					
						
							|  |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyDoc_STRVAR(Reader_Type_doc, | 
					
						
							|  |  |  | "CSV reader\n" | 
					
						
							|  |  |  | "\n" | 
					
						
							|  |  |  | "Reader objects are responsible for reading and parsing tabular data\n" | 
					
						
							|  |  |  | "in CSV format.\n" | 
					
						
							|  |  |  | ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct PyMethodDef Reader_methods[] = { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     { NULL, NULL } | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2005-01-13 11:30:54 +00:00
										 |  |  | #define R_OFF(x) offsetof(ReaderObj, x)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct PyMemberDef Reader_memberlist[] = { | 
					
						
							| 
									
										
										
										
											2023-07-25 15:28:30 +02:00
										 |  |  |     { "dialect", _Py_T_OBJECT, R_OFF(dialect), Py_READONLY }, | 
					
						
							|  |  |  |     { "line_num", Py_T_ULONG, R_OFF(line_num), Py_READONLY }, | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     { NULL } | 
					
						
							| 
									
										
										
										
											2005-01-13 11:30:54 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-07 20:35:56 +03:00
										 |  |  | #undef R_OFF
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  | static PyType_Slot Reader_Type_slots[] = { | 
					
						
							|  |  |  |     {Py_tp_doc, (char*)Reader_Type_doc}, | 
					
						
							|  |  |  |     {Py_tp_traverse, Reader_traverse}, | 
					
						
							|  |  |  |     {Py_tp_iter, PyObject_SelfIter}, | 
					
						
							|  |  |  |     {Py_tp_iternext, Reader_iternext}, | 
					
						
							|  |  |  |     {Py_tp_methods, Reader_methods}, | 
					
						
							|  |  |  |     {Py_tp_members, Reader_memberlist}, | 
					
						
							| 
									
										
										
										
											2021-05-12 20:18:58 +02:00
										 |  |  |     {Py_tp_clear, Reader_clear}, | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     {Py_tp_dealloc, Reader_dealloc}, | 
					
						
							|  |  |  |     {0, NULL} | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  | PyType_Spec Reader_Type_spec = { | 
					
						
							|  |  |  |     .name = "_csv.reader", | 
					
						
							|  |  |  |     .basicsize = sizeof(ReaderObj), | 
					
						
							| 
									
										
										
										
											2021-06-17 12:06:09 +02:00
										 |  |  |     .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | | 
					
						
							| 
									
										
										
										
											2023-05-08 00:15:44 +03:00
										 |  |  |               Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION), | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     .slots = Reader_Type_slots | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | static PyObject * | 
					
						
							|  |  |  | csv_reader(PyObject *module, PyObject *args, PyObject *keyword_args) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     PyObject * iterator, * dialect = NULL; | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     _csvstate *module_state = get_csv_state(module); | 
					
						
							|  |  |  |     ReaderObj * self = PyObject_GC_New( | 
					
						
							|  |  |  |         ReaderObj, | 
					
						
							|  |  |  |         module_state->reader_type); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (!self) | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     self->dialect = NULL; | 
					
						
							|  |  |  |     self->fields = NULL; | 
					
						
							|  |  |  |     self->input_iter = NULL; | 
					
						
							|  |  |  |     self->field = NULL; | 
					
						
							|  |  |  |     self->field_size = 0; | 
					
						
							|  |  |  |     self->line_num = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (parse_reset(self) < 0) { | 
					
						
							|  |  |  |         Py_DECREF(self); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-29 11:12:37 +03:00
										 |  |  |     if (!PyArg_UnpackTuple(args, "reader", 1, 2, &iterator, &dialect)) { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         Py_DECREF(self); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     self->input_iter = PyObject_GetIter(iterator); | 
					
						
							|  |  |  |     if (self->input_iter == NULL) { | 
					
						
							|  |  |  |         Py_DECREF(self); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     self->dialect = (DialectObj *)_call_dialect(module_state, dialect, | 
					
						
							|  |  |  |                                                 keyword_args); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     if (self->dialect == NULL) { | 
					
						
							|  |  |  |         Py_DECREF(self); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PyObject_GC_Track(self); | 
					
						
							|  |  |  |     return (PyObject *)self; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * WRITER | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | /* ---------------------------------------------------------------- */ | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | join_reset(WriterObj *self) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     self->rec_len = 0; | 
					
						
							|  |  |  |     self->num_fields = 0; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define MEM_INCR 32768
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Calculate new record length or append field to record.  Return new
 | 
					
						
							|  |  |  |  * record length. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2010-08-15 18:51:10 +00:00
										 |  |  | static Py_ssize_t | 
					
						
							| 
									
										
										
										
											2022-05-13 12:41:05 +02:00
										 |  |  | join_append_data(WriterObj *self, int field_kind, const void *field_data, | 
					
						
							| 
									
										
										
										
											2015-03-30 09:09:54 +03:00
										 |  |  |                  Py_ssize_t field_len, int *quoted, | 
					
						
							| 
									
										
										
										
											2011-10-07 04:26:55 +02:00
										 |  |  |                  int copy_phase) | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     DialectObj *dialect = self->dialect; | 
					
						
							| 
									
										
										
										
											2025-01-29 16:45:47 +05:30
										 |  |  |     Py_ssize_t i; | 
					
						
							| 
									
										
										
										
											2010-08-15 18:51:10 +00:00
										 |  |  |     Py_ssize_t rec_len; | 
					
						
							| 
									
										
										
										
											2005-01-12 07:44:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-13 17:17:06 -07:00
										 |  |  | #define INCLEN \
 | 
					
						
							|  |  |  |     do {\ | 
					
						
							|  |  |  |         if (!copy_phase && rec_len == PY_SSIZE_T_MAX) {    \ | 
					
						
							|  |  |  |             goto overflow; \ | 
					
						
							|  |  |  |         } \ | 
					
						
							|  |  |  |         rec_len++; \ | 
					
						
							|  |  |  |     } while(0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define ADDCH(c)                                \
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     do {\ | 
					
						
							|  |  |  |         if (copy_phase) \ | 
					
						
							|  |  |  |             self->rec[rec_len] = c;\ | 
					
						
							| 
									
										
										
										
											2016-08-13 17:17:06 -07:00
										 |  |  |         INCLEN;\ | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     } while(0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rec_len = self->rec_len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* If this is not the first field we need a field separator */ | 
					
						
							|  |  |  |     if (self->num_fields > 0) | 
					
						
							|  |  |  |         ADDCH(dialect->delimiter); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Handle preceding quote */ | 
					
						
							|  |  |  |     if (copy_phase && *quoted) | 
					
						
							|  |  |  |         ADDCH(dialect->quotechar); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Copy/count field data */ | 
					
						
							|  |  |  |     /* If field is null just pass over */ | 
					
						
							| 
									
										
										
										
											2011-10-07 04:26:55 +02:00
										 |  |  |     for (i = 0; field_data && (i < field_len); i++) { | 
					
						
							|  |  |  |         Py_UCS4 c = PyUnicode_READ(field_kind, field_data, i); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         int want_escape = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (c == dialect->delimiter || | 
					
						
							|  |  |  |             c == dialect->escapechar || | 
					
						
							|  |  |  |             c == dialect->quotechar  || | 
					
						
							| 
									
										
										
										
											2024-02-23 22:25:09 +02:00
										 |  |  |             c == '\n'  || | 
					
						
							|  |  |  |             c == '\r'  || | 
					
						
							| 
									
										
										
										
											2011-11-01 18:42:23 +01:00
										 |  |  |             PyUnicode_FindChar( | 
					
						
							|  |  |  |                 dialect->lineterminator, c, 0, | 
					
						
							|  |  |  |                 PyUnicode_GET_LENGTH(dialect->lineterminator), 1) >= 0) { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             if (dialect->quoting == QUOTE_NONE) | 
					
						
							|  |  |  |                 want_escape = 1; | 
					
						
							|  |  |  |             else { | 
					
						
							|  |  |  |                 if (c == dialect->quotechar) { | 
					
						
							|  |  |  |                     if (dialect->doublequote) | 
					
						
							|  |  |  |                         ADDCH(dialect->quotechar); | 
					
						
							|  |  |  |                     else | 
					
						
							|  |  |  |                         want_escape = 1; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2020-09-20 09:38:07 +03:00
										 |  |  |                 else if (c == dialect->escapechar) { | 
					
						
							|  |  |  |                     want_escape = 1; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |                 if (!want_escape) | 
					
						
							|  |  |  |                     *quoted = 1; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (want_escape) { | 
					
						
							| 
									
										
										
										
											2021-10-09 19:17:43 +03:00
										 |  |  |                 if (dialect->escapechar == NOT_SET) { | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |                     PyErr_Format(self->error_obj, | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |                                  "need to escape, but no escapechar set"); | 
					
						
							|  |  |  |                     return -1; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 ADDCH(dialect->escapechar); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         /* Copy field character into record buffer.
 | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         ADDCH(c); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (*quoted) { | 
					
						
							|  |  |  |         if (copy_phase) | 
					
						
							|  |  |  |             ADDCH(dialect->quotechar); | 
					
						
							| 
									
										
										
										
											2016-08-13 17:17:06 -07:00
										 |  |  |         else { | 
					
						
							|  |  |  |             INCLEN; /* starting quote */ | 
					
						
							|  |  |  |             INCLEN; /* ending quote */ | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |     return rec_len; | 
					
						
							| 
									
										
										
										
											2016-08-13 17:17:06 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   overflow: | 
					
						
							|  |  |  |     PyErr_NoMemory(); | 
					
						
							|  |  |  |     return -1; | 
					
						
							| 
									
										
										
										
											2005-01-12 07:44:42 +00:00
										 |  |  | #undef ADDCH
 | 
					
						
							| 
									
										
										
										
											2016-08-13 17:17:06 -07:00
										 |  |  | #undef INCLEN
 | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2010-08-15 18:51:10 +00:00
										 |  |  | join_check_rec_size(WriterObj *self, Py_ssize_t rec_len) | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-08-16 09:27:50 +05:00
										 |  |  |     assert(rec_len >= 0); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (rec_len > self->rec_size) { | 
					
						
							| 
									
										
										
										
											2018-08-16 09:27:50 +05:00
										 |  |  |         size_t rec_size_new = (size_t)(rec_len / MEM_INCR + 1) * MEM_INCR; | 
					
						
							|  |  |  |         Py_UCS4 *rec_new = self->rec; | 
					
						
							|  |  |  |         PyMem_Resize(rec_new, Py_UCS4, rec_size_new); | 
					
						
							|  |  |  |         if (rec_new == NULL) { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             PyErr_NoMemory(); | 
					
						
							|  |  |  |             return 0; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-08-16 09:27:50 +05:00
										 |  |  |         self->rec = rec_new; | 
					
						
							|  |  |  |         self->rec_size = (Py_ssize_t)rec_size_new; | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |     return 1; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2015-03-30 09:09:54 +03:00
										 |  |  | join_append(WriterObj *self, PyObject *field, int quoted) | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-02-20 18:09:50 +02:00
										 |  |  |     DialectObj *dialect = self->dialect; | 
					
						
							| 
									
										
										
										
											2022-05-13 12:41:05 +02:00
										 |  |  |     int field_kind = -1; | 
					
						
							| 
									
										
										
										
											2020-04-11 10:48:40 +03:00
										 |  |  |     const void *field_data = NULL; | 
					
						
							| 
									
										
										
										
											2011-10-07 04:26:55 +02:00
										 |  |  |     Py_ssize_t field_len = 0; | 
					
						
							| 
									
										
										
										
											2010-08-15 18:51:10 +00:00
										 |  |  |     Py_ssize_t rec_len; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-07 04:26:55 +02:00
										 |  |  |     if (field != NULL) { | 
					
						
							|  |  |  |         field_kind = PyUnicode_KIND(field); | 
					
						
							|  |  |  |         field_data = PyUnicode_DATA(field); | 
					
						
							|  |  |  |         field_len = PyUnicode_GET_LENGTH(field); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-02-20 18:09:50 +02:00
										 |  |  |     if (!field_len && dialect->delimiter == ' ' && dialect->skipinitialspace) { | 
					
						
							|  |  |  |         if (dialect->quoting == QUOTE_NONE || | 
					
						
							|  |  |  |             (field == NULL && | 
					
						
							|  |  |  |              (dialect->quoting == QUOTE_STRINGS || | 
					
						
							|  |  |  |               dialect->quoting == QUOTE_NOTNULL))) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             PyErr_Format(self->error_obj, | 
					
						
							|  |  |  |                          "empty field must be quoted if delimiter is a space " | 
					
						
							|  |  |  |                          "and skipinitialspace is true"); | 
					
						
							|  |  |  |             return 0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         quoted = 1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-10-07 04:26:55 +02:00
										 |  |  |     rec_len = join_append_data(self, field_kind, field_data, field_len, | 
					
						
							| 
									
										
										
										
											2015-03-30 09:09:54 +03:00
										 |  |  |                                "ed, 0); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     if (rec_len < 0) | 
					
						
							|  |  |  |         return 0; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     /* grow record buffer if necessary */ | 
					
						
							|  |  |  |     if (!join_check_rec_size(self, rec_len)) | 
					
						
							|  |  |  |         return 0; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-07 04:26:55 +02:00
										 |  |  |     self->rec_len = join_append_data(self, field_kind, field_data, field_len, | 
					
						
							| 
									
										
										
										
											2015-03-30 09:09:54 +03:00
										 |  |  |                                      "ed, 1); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     self->num_fields++; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     return 1; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | join_append_lineterminator(WriterObj *self) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-07 04:26:55 +02:00
										 |  |  |     Py_ssize_t terminator_len, i; | 
					
						
							| 
									
										
										
										
											2022-05-13 12:41:05 +02:00
										 |  |  |     int term_kind; | 
					
						
							| 
									
										
										
										
											2020-04-11 10:48:40 +03:00
										 |  |  |     const void *term_data; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-07 04:26:55 +02:00
										 |  |  |     terminator_len = PyUnicode_GET_LENGTH(self->dialect->lineterminator); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     if (terminator_len == -1) | 
					
						
							|  |  |  |         return 0; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     /* grow record buffer if necessary */ | 
					
						
							|  |  |  |     if (!join_check_rec_size(self, self->rec_len + terminator_len)) | 
					
						
							|  |  |  |         return 0; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-07 04:26:55 +02:00
										 |  |  |     term_kind = PyUnicode_KIND(self->dialect->lineterminator); | 
					
						
							|  |  |  |     term_data = PyUnicode_DATA(self->dialect->lineterminator); | 
					
						
							|  |  |  |     for (i = 0; i < terminator_len; i++) | 
					
						
							|  |  |  |         self->rec[self->rec_len + i] = PyUnicode_READ(term_kind, term_data, i); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     self->rec_len += terminator_len; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     return 1; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyDoc_STRVAR(csv_writerow_doc, | 
					
						
							| 
									
										
										
										
											2015-03-30 09:09:54 +03:00
										 |  |  | "writerow(iterable)\n" | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | "\n" | 
					
						
							| 
									
										
										
										
											2015-03-30 09:09:54 +03:00
										 |  |  | "Construct and write a CSV record from an iterable of fields.  Non-string\n" | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | "elements will be converted to string."); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  | csv_writerow(PyObject *op, PyObject *seq) | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  |     WriterObj *self = _WriterObj_CAST(op); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     DialectObj *dialect = self->dialect; | 
					
						
							| 
									
										
										
										
											2015-03-30 09:09:54 +03:00
										 |  |  |     PyObject *iter, *field, *line, *result; | 
					
						
							| 
									
										
										
										
											2024-02-20 18:09:50 +02:00
										 |  |  |     bool null_field = false; | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-30 09:09:54 +03:00
										 |  |  |     iter = PyObject_GetIter(seq); | 
					
						
							| 
									
										
										
										
											2020-06-22 11:21:59 +03:00
										 |  |  |     if (iter == NULL) { | 
					
						
							|  |  |  |         if (PyErr_ExceptionMatches(PyExc_TypeError)) { | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |             PyErr_Format(self->error_obj, | 
					
						
							| 
									
										
										
										
											2020-06-22 11:21:59 +03:00
										 |  |  |                          "iterable expected, not %.200s", | 
					
						
							|  |  |  |                          Py_TYPE(seq)->tp_name); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* Join all fields in internal buffer.
 | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     join_reset(self); | 
					
						
							| 
									
										
										
										
											2015-03-30 09:09:54 +03:00
										 |  |  |     while ((field = PyIter_Next(iter))) { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         int append_ok; | 
					
						
							|  |  |  |         int quoted; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         switch (dialect->quoting) { | 
					
						
							|  |  |  |         case QUOTE_NONNUMERIC: | 
					
						
							|  |  |  |             quoted = !PyNumber_Check(field); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case QUOTE_ALL: | 
					
						
							|  |  |  |             quoted = 1; | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2023-04-12 17:32:30 -05:00
										 |  |  |         case QUOTE_STRINGS: | 
					
						
							|  |  |  |             quoted = PyUnicode_Check(field); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case QUOTE_NOTNULL: | 
					
						
							|  |  |  |             quoted = field != Py_None; | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         default: | 
					
						
							|  |  |  |             quoted = 0; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 18:09:50 +02:00
										 |  |  |         null_field = (field == Py_None); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         if (PyUnicode_Check(field)) { | 
					
						
							| 
									
										
										
										
											2015-03-30 09:09:54 +03:00
										 |  |  |             append_ok = join_append(self, field, quoted); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             Py_DECREF(field); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-02-20 18:09:50 +02:00
										 |  |  |         else if (null_field) { | 
					
						
							| 
									
										
										
										
											2015-03-30 09:09:54 +03:00
										 |  |  |             append_ok = join_append(self, NULL, quoted); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             Py_DECREF(field); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  |             PyObject *str; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             str = PyObject_Str(field); | 
					
						
							|  |  |  |             Py_DECREF(field); | 
					
						
							| 
									
										
										
										
											2015-03-30 09:09:54 +03:00
										 |  |  |             if (str == NULL) { | 
					
						
							|  |  |  |                 Py_DECREF(iter); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |                 return NULL; | 
					
						
							| 
									
										
										
										
											2015-03-30 09:09:54 +03:00
										 |  |  |             } | 
					
						
							|  |  |  |             append_ok = join_append(self, str, quoted); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             Py_DECREF(str); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2015-03-30 09:09:54 +03:00
										 |  |  |         if (!append_ok) { | 
					
						
							|  |  |  |             Py_DECREF(iter); | 
					
						
							|  |  |  |             return NULL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     Py_DECREF(iter); | 
					
						
							|  |  |  |     if (PyErr_Occurred()) | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-12 18:57:06 +09:00
										 |  |  |     if (self->num_fields > 0 && self->rec_len == 0) { | 
					
						
							| 
									
										
										
										
											2024-02-20 18:09:50 +02:00
										 |  |  |         if (dialect->quoting == QUOTE_NONE || | 
					
						
							|  |  |  |             (null_field && | 
					
						
							|  |  |  |              (dialect->quoting == QUOTE_STRINGS || | 
					
						
							|  |  |  |               dialect->quoting == QUOTE_NOTNULL))) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |             PyErr_Format(self->error_obj, | 
					
						
							| 
									
										
										
										
											2015-03-30 09:09:54 +03:00
										 |  |  |                 "single empty field record must be quoted"); | 
					
						
							|  |  |  |             return NULL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         self->num_fields--; | 
					
						
							|  |  |  |         if (!join_append(self, NULL, 1)) | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Add line terminator.
 | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2019-05-14 15:45:14 +02:00
										 |  |  |     if (!join_append_lineterminator(self)) { | 
					
						
							| 
									
										
										
										
											2015-03-30 09:09:54 +03:00
										 |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2019-05-14 15:45:14 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-07 04:35:30 +02:00
										 |  |  |     line = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, | 
					
						
							|  |  |  |                                      (void *) self->rec, self->rec_len); | 
					
						
							| 
									
										
										
										
											2019-05-14 15:45:14 +02:00
										 |  |  |     if (line == NULL) { | 
					
						
							| 
									
										
										
										
											2011-10-07 04:35:30 +02:00
										 |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2019-05-14 15:45:14 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-02-11 17:46:57 +01:00
										 |  |  |     result = PyObject_CallOneArg(self->write, line); | 
					
						
							| 
									
										
										
										
											2011-10-07 04:35:30 +02:00
										 |  |  |     Py_DECREF(line); | 
					
						
							|  |  |  |     return result; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-04-12 18:57:52 +00:00
										 |  |  | PyDoc_STRVAR(csv_writerows_doc, | 
					
						
							| 
									
										
										
										
											2015-03-30 09:09:54 +03:00
										 |  |  | "writerows(iterable of iterables)\n" | 
					
						
							| 
									
										
										
										
											2003-04-12 18:57:52 +00:00
										 |  |  | "\n" | 
					
						
							| 
									
										
										
										
											2015-03-30 09:09:54 +03:00
										 |  |  | "Construct and write a series of iterables to a csv file.  Non-string\n" | 
					
						
							| 
									
										
										
										
											2003-04-12 18:57:52 +00:00
										 |  |  | "elements will be converted to string."); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  | csv_writerows(PyObject *self, PyObject *seqseq) | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     PyObject *row_iter, *row_obj, *result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     row_iter = PyObject_GetIter(seqseq); | 
					
						
							|  |  |  |     if (row_iter == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     while ((row_obj = PyIter_Next(row_iter))) { | 
					
						
							|  |  |  |         result = csv_writerow(self, row_obj); | 
					
						
							|  |  |  |         Py_DECREF(row_obj); | 
					
						
							|  |  |  |         if (!result) { | 
					
						
							|  |  |  |             Py_DECREF(row_iter); | 
					
						
							|  |  |  |             return NULL; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         else | 
					
						
							|  |  |  |              Py_DECREF(result); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     Py_DECREF(row_iter); | 
					
						
							|  |  |  |     if (PyErr_Occurred()) | 
					
						
							|  |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2017-01-23 09:47:21 +02:00
										 |  |  |     Py_RETURN_NONE; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct PyMethodDef Writer_methods[] = { | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  |     {"writerow", csv_writerow, METH_O, csv_writerow_doc}, | 
					
						
							|  |  |  |     {"writerows", csv_writerows, METH_O, csv_writerows_doc}, | 
					
						
							|  |  |  |     {NULL, NULL, 0, NULL}  /* sentinel */ | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define W_OFF(x) offsetof(WriterObj, x)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct PyMemberDef Writer_memberlist[] = { | 
					
						
							| 
									
										
										
										
											2023-07-25 15:28:30 +02:00
										 |  |  |     { "dialect", _Py_T_OBJECT, W_OFF(dialect), Py_READONLY }, | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     { NULL } | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-07 20:35:56 +03:00
										 |  |  | #undef W_OFF
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-04-14 02:20:55 +00:00
										 |  |  | static int | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  | Writer_traverse(PyObject *op, visitproc visit, void *arg) | 
					
						
							| 
									
										
										
										
											2003-04-14 02:20:55 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  |     WriterObj *self = _WriterObj_CAST(op); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     Py_VISIT(self->dialect); | 
					
						
							| 
									
										
										
										
											2019-05-14 15:45:14 +02:00
										 |  |  |     Py_VISIT(self->write); | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     Py_VISIT(self->error_obj); | 
					
						
							| 
									
										
										
										
											2021-05-12 20:18:58 +02:00
										 |  |  |     Py_VISIT(Py_TYPE(self)); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2003-04-14 02:20:55 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  | Writer_clear(PyObject *op) | 
					
						
							| 
									
										
										
										
											2003-04-14 02:20:55 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  |     WriterObj *self = _WriterObj_CAST(op); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     Py_CLEAR(self->dialect); | 
					
						
							| 
									
										
										
										
											2019-05-14 15:45:14 +02:00
										 |  |  |     Py_CLEAR(self->write); | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     Py_CLEAR(self->error_obj); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  | static void | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  | Writer_dealloc(PyObject *op) | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  |     WriterObj *self = _WriterObj_CAST(op); | 
					
						
							| 
									
										
										
										
											2021-05-12 20:18:58 +02:00
										 |  |  |     PyTypeObject *tp = Py_TYPE(self); | 
					
						
							|  |  |  |     PyObject_GC_UnTrack(self); | 
					
						
							| 
									
										
										
										
											2025-01-03 15:04:33 +01:00
										 |  |  |     tp->tp_clear(op); | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     if (self->rec != NULL) { | 
					
						
							|  |  |  |         PyMem_Free(self->rec); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-05-12 20:18:58 +02:00
										 |  |  |     PyObject_GC_Del(self); | 
					
						
							|  |  |  |     Py_DECREF(tp); | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  | PyDoc_STRVAR(Writer_Type_doc, | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | "CSV writer\n" | 
					
						
							|  |  |  | "\n" | 
					
						
							|  |  |  | "Writer objects are responsible for generating tabular data\n" | 
					
						
							|  |  |  | "in CSV format from sequence input.\n" | 
					
						
							|  |  |  | ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  | static PyType_Slot Writer_Type_slots[] = { | 
					
						
							|  |  |  |     {Py_tp_doc, (char*)Writer_Type_doc}, | 
					
						
							|  |  |  |     {Py_tp_traverse, Writer_traverse}, | 
					
						
							|  |  |  |     {Py_tp_clear, Writer_clear}, | 
					
						
							| 
									
										
										
										
											2021-05-12 20:18:58 +02:00
										 |  |  |     {Py_tp_dealloc, Writer_dealloc}, | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     {Py_tp_methods, Writer_methods}, | 
					
						
							|  |  |  |     {Py_tp_members, Writer_memberlist}, | 
					
						
							|  |  |  |     {0, NULL} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyType_Spec Writer_Type_spec = { | 
					
						
							|  |  |  |     .name = "_csv.writer", | 
					
						
							|  |  |  |     .basicsize = sizeof(WriterObj), | 
					
						
							| 
									
										
										
										
											2021-06-17 12:06:09 +02:00
										 |  |  |     .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | | 
					
						
							| 
									
										
										
										
											2023-05-08 00:15:44 +03:00
										 |  |  |               Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION), | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     .slots = Writer_Type_slots, | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | static PyObject * | 
					
						
							|  |  |  | csv_writer(PyObject *module, PyObject *args, PyObject *keyword_args) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     PyObject * output_file, * dialect = NULL; | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     _csvstate *module_state = get_csv_state(module); | 
					
						
							|  |  |  |     WriterObj * self = PyObject_GC_New(WriterObj, module_state->writer_type); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (!self) | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     self->dialect = NULL; | 
					
						
							| 
									
										
										
										
											2019-05-14 15:45:14 +02:00
										 |  |  |     self->write = NULL; | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     self->rec = NULL; | 
					
						
							|  |  |  |     self->rec_size = 0; | 
					
						
							|  |  |  |     self->rec_len = 0; | 
					
						
							|  |  |  |     self->num_fields = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     self->error_obj = Py_NewRef(module_state->error_obj); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-29 11:12:37 +03:00
										 |  |  |     if (!PyArg_UnpackTuple(args, "writer", 1, 2, &output_file, &dialect)) { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         Py_DECREF(self); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-07-12 08:57:10 +03:00
										 |  |  |     if (PyObject_GetOptionalAttr(output_file, | 
					
						
							| 
									
										
										
										
											2022-02-17 00:24:03 +09:00
										 |  |  |                              module_state->str_write, | 
					
						
							|  |  |  |                              &self->write) < 0) { | 
					
						
							| 
									
										
										
										
											2019-09-01 12:03:39 +03:00
										 |  |  |         Py_DECREF(self); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-05-14 15:45:14 +02:00
										 |  |  |     if (self->write == NULL || !PyCallable_Check(self->write)) { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         PyErr_SetString(PyExc_TypeError, | 
					
						
							|  |  |  |                         "argument 1 must have a \"write\" method"); | 
					
						
							|  |  |  |         Py_DECREF(self); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     self->dialect = (DialectObj *)_call_dialect(module_state, dialect, | 
					
						
							|  |  |  |                                                 keyword_args); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     if (self->dialect == NULL) { | 
					
						
							|  |  |  |         Py_DECREF(self); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     PyObject_GC_Track(self); | 
					
						
							|  |  |  |     return (PyObject *)self; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * DIALECT REGISTRY | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2022-04-16 10:34:23 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | _csv.list_dialects | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Return a list of all known dialect names. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     names = csv.list_dialects() | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2022-04-16 10:34:23 -07:00
										 |  |  | _csv_list_dialects_impl(PyObject *module) | 
					
						
							|  |  |  | /*[clinic end generated code: output=a5b92b215b006a6d input=8953943eb17d98ab]*/ | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     return PyDict_Keys(get_csv_state(module)->dialects); | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2005-01-11 01:28:33 +00:00
										 |  |  | csv_register_dialect(PyObject *module, PyObject *args, PyObject *kwargs) | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     PyObject *name_obj, *dialect_obj = NULL; | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     _csvstate *module_state = get_csv_state(module); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     PyObject *dialect; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-29 11:12:37 +03:00
										 |  |  |     if (!PyArg_UnpackTuple(args, "register_dialect", 1, 2, &name_obj, &dialect_obj)) | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2012-11-02 14:44:20 +01:00
										 |  |  |     if (!PyUnicode_Check(name_obj)) { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         PyErr_SetString(PyExc_TypeError, | 
					
						
							| 
									
										
										
										
											2012-11-02 14:44:20 +01:00
										 |  |  |                         "dialect name must be a string"); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     dialect = _call_dialect(module_state, dialect_obj, kwargs); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     if (dialect == NULL) | 
					
						
							|  |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     if (PyDict_SetItem(module_state->dialects, name_obj, dialect) < 0) { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         Py_DECREF(dialect); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     Py_DECREF(dialect); | 
					
						
							| 
									
										
										
										
											2017-01-23 09:47:21 +02:00
										 |  |  |     Py_RETURN_NONE; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-16 10:34:23 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | _csv.unregister_dialect | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     name: object | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Delete the name/dialect mapping associated with a string name. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     csv.unregister_dialect(name) | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2022-04-16 10:34:23 -07:00
										 |  |  | _csv_unregister_dialect_impl(PyObject *module, PyObject *name) | 
					
						
							|  |  |  | /*[clinic end generated code: output=0813ebca6c058df4 input=6b5c1557bf60c7e7]*/ | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     _csvstate *module_state = get_csv_state(module); | 
					
						
							| 
									
										
										
										
											2024-03-07 11:21:08 +02:00
										 |  |  |     int rc = PyDict_Pop(module_state->dialects, name, NULL); | 
					
						
							|  |  |  |     if (rc < 0) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (rc == 0) { | 
					
						
							|  |  |  |         PyErr_Format(module_state->error_obj, "unknown dialect"); | 
					
						
							| 
									
										
										
										
											2019-02-25 17:59:46 +02:00
										 |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-01-23 09:47:21 +02:00
										 |  |  |     Py_RETURN_NONE; | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-16 10:34:23 -07:00
										 |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | _csv.get_dialect | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     name: object | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Return the dialect instance associated with name. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     dialect = csv.get_dialect(name) | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2022-04-16 10:34:23 -07:00
										 |  |  | _csv_get_dialect_impl(PyObject *module, PyObject *name) | 
					
						
							|  |  |  | /*[clinic end generated code: output=aa988cd573bebebb input=edf9ddab32e448fb]*/ | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-04-16 10:34:23 -07:00
										 |  |  |     return get_dialect_from_registry(name, get_csv_state(module)); | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-16 10:34:23 -07:00
										 |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | _csv.field_size_limit | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     new_limit: object = NULL | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Sets an upper limit on parsed fields. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     csv.field_size_limit([limit]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Returns old limit. If limit is not given, no new limit is set and | 
					
						
							|  |  |  | the old limit is returned | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-01-11 07:32:02 +00:00
										 |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2022-04-16 10:34:23 -07:00
										 |  |  | _csv_field_size_limit_impl(PyObject *module, PyObject *new_limit) | 
					
						
							|  |  |  | /*[clinic end generated code: output=f2799ecd908e250b input=cec70e9226406435]*/ | 
					
						
							| 
									
										
										
										
											2005-01-11 07:32:02 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     _csvstate *module_state = get_csv_state(module); | 
					
						
							| 
									
										
										
										
											2024-10-12 01:55:36 +08:00
										 |  |  |     Py_ssize_t old_limit = FT_ATOMIC_LOAD_SSIZE_RELAXED(module_state->field_limit); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     if (new_limit != NULL) { | 
					
						
							|  |  |  |         if (!PyLong_CheckExact(new_limit)) { | 
					
						
							|  |  |  |             PyErr_Format(PyExc_TypeError, | 
					
						
							|  |  |  |                          "limit must be an integer"); | 
					
						
							|  |  |  |             return NULL; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-10-12 01:55:36 +08:00
										 |  |  |         Py_ssize_t new_limit_value = PyLong_AsSsize_t(new_limit); | 
					
						
							|  |  |  |         if (new_limit_value == -1 && PyErr_Occurred()) { | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |             return NULL; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-10-12 01:55:36 +08:00
										 |  |  |         FT_ATOMIC_STORE_SSIZE_RELAXED(module_state->field_limit, new_limit_value); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-10-12 01:55:36 +08:00
										 |  |  |     return PyLong_FromSsize_t(old_limit); | 
					
						
							| 
									
										
										
										
											2005-01-11 07:32:02 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  | static PyType_Slot error_slots[] = { | 
					
						
							|  |  |  |     {0, NULL}, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyType_Spec error_spec = { | 
					
						
							|  |  |  |     .name = "_csv.Error", | 
					
						
							| 
									
										
										
										
											2021-05-12 21:47:11 +08:00
										 |  |  |     .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     .slots = error_slots, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * MODULE | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-18 16:18:42 -06:00
										 |  |  | PyDoc_STRVAR(csv_module_doc, "CSV parsing and writing.\n"); | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | PyDoc_STRVAR(csv_reader_doc, | 
					
						
							|  |  |  | "    csv_reader = reader(iterable [, dialect='excel']\n" | 
					
						
							|  |  |  | "                        [optional keyword args])\n" | 
					
						
							|  |  |  | "    for row in csv_reader:\n" | 
					
						
							|  |  |  | "        process(row)\n" | 
					
						
							|  |  |  | "\n" | 
					
						
							|  |  |  | "The \"iterable\" argument can be any object that returns a line\n" | 
					
						
							|  |  |  | "of input for each iteration, such as a file object or a list.  The\n" | 
					
						
							|  |  |  | "optional \"dialect\" parameter is discussed below.  The function\n" | 
					
						
							|  |  |  | "also accepts optional keyword arguments which override settings\n" | 
					
						
							|  |  |  | "provided by the dialect.\n" | 
					
						
							|  |  |  | "\n" | 
					
						
							|  |  |  | "The returned object is an iterator.  Each iteration returns a row\n" | 
					
						
							| 
									
										
										
										
											2015-10-02 19:25:32 +03:00
										 |  |  | "of the CSV file (which can span multiple input lines).\n"); | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | PyDoc_STRVAR(csv_writer_doc, | 
					
						
							|  |  |  | "    csv_writer = csv.writer(fileobj [, dialect='excel']\n" | 
					
						
							|  |  |  | "                            [optional keyword args])\n" | 
					
						
							| 
									
										
										
										
											2006-04-21 10:40:58 +00:00
										 |  |  | "    for row in sequence:\n" | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | "        csv_writer.writerow(row)\n" | 
					
						
							|  |  |  | "\n" | 
					
						
							|  |  |  | "    [or]\n" | 
					
						
							|  |  |  | "\n" | 
					
						
							|  |  |  | "    csv_writer = csv.writer(fileobj [, dialect='excel']\n" | 
					
						
							|  |  |  | "                            [optional keyword args])\n" | 
					
						
							|  |  |  | "    csv_writer.writerows(rows)\n" | 
					
						
							|  |  |  | "\n" | 
					
						
							|  |  |  | "The \"fileobj\" argument can be any object that supports the file API.\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyDoc_STRVAR(csv_register_dialect_doc, | 
					
						
							|  |  |  | "Create a mapping from a string name to a dialect class.\n" | 
					
						
							| 
									
										
										
										
											2015-06-05 15:17:51 +03:00
										 |  |  | "    dialect = csv.register_dialect(name[, dialect[, **fmtparams]])"); | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | static struct PyMethodDef csv_methods[] = { | 
					
						
							| 
									
										
										
										
											2022-05-03 21:42:14 +02:00
										 |  |  |     { "reader", _PyCFunction_CAST(csv_reader), | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         METH_VARARGS | METH_KEYWORDS, csv_reader_doc}, | 
					
						
							| 
									
										
										
										
											2022-05-03 21:42:14 +02:00
										 |  |  |     { "writer", _PyCFunction_CAST(csv_writer), | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         METH_VARARGS | METH_KEYWORDS, csv_writer_doc}, | 
					
						
							| 
									
										
										
										
											2022-05-03 21:42:14 +02:00
										 |  |  |     { "register_dialect", _PyCFunction_CAST(csv_register_dialect), | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |         METH_VARARGS | METH_KEYWORDS, csv_register_dialect_doc}, | 
					
						
							| 
									
										
										
										
											2022-04-16 10:34:23 -07:00
										 |  |  |     _CSV_LIST_DIALECTS_METHODDEF | 
					
						
							|  |  |  |     _CSV_UNREGISTER_DIALECT_METHODDEF | 
					
						
							|  |  |  |     _CSV_GET_DIALECT_METHODDEF | 
					
						
							|  |  |  |     _CSV_FIELD_SIZE_LIMIT_METHODDEF | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     { NULL, NULL } | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  | static int | 
					
						
							|  |  |  | csv_exec(PyObject *module) { | 
					
						
							| 
									
										
										
										
											2015-12-25 19:53:18 +02:00
										 |  |  |     const StyleDesc *style; | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     PyObject *temp; | 
					
						
							|  |  |  |     _csvstate *module_state = get_csv_state(module); | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     temp = PyType_FromModuleAndSpec(module, &Dialect_Type_spec, NULL); | 
					
						
							|  |  |  |     module_state->dialect_type = (PyTypeObject *)temp; | 
					
						
							|  |  |  |     if (PyModule_AddObjectRef(module, "Dialect", temp) < 0) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     temp = PyType_FromModuleAndSpec(module, &Reader_Type_spec, NULL); | 
					
						
							|  |  |  |     module_state->reader_type = (PyTypeObject *)temp; | 
					
						
							|  |  |  |     if (PyModule_AddObjectRef(module, "Reader", temp) < 0) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     temp = PyType_FromModuleAndSpec(module, &Writer_Type_spec, NULL); | 
					
						
							|  |  |  |     module_state->writer_type = (PyTypeObject *)temp; | 
					
						
							|  |  |  |     if (PyModule_AddObjectRef(module, "Writer", temp) < 0) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-16 11:33:08 +02:00
										 |  |  |     /* Set the field limit */ | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     module_state->field_limit = 128 * 1024; | 
					
						
							| 
									
										
										
										
											2012-05-16 11:33:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     /* Add _dialects dictionary */ | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     module_state->dialects = PyDict_New(); | 
					
						
							|  |  |  |     if (PyModule_AddObjectRef(module, "_dialects", module_state->dialects) < 0) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* Add quote styles into dictionary */ | 
					
						
							|  |  |  |     for (style = quote_styles; style->name; style++) { | 
					
						
							|  |  |  |         if (PyModule_AddIntConstant(module, style->name, | 
					
						
							|  |  |  |                                     style->style) == -1) | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |             return -1; | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     /* Add the CSV exception object to the module. */ | 
					
						
							|  |  |  |     PyObject *bases = PyTuple_Pack(1, PyExc_Exception); | 
					
						
							|  |  |  |     if (bases == NULL) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     module_state->error_obj = PyType_FromModuleAndSpec(module, &error_spec, | 
					
						
							|  |  |  |                                                        bases); | 
					
						
							|  |  |  |     Py_DECREF(bases); | 
					
						
							|  |  |  |     if (module_state->error_obj == NULL) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (PyModule_AddType(module, (PyTypeObject *)module_state->error_obj) != 0) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							| 
									
										
										
											
												bpo-40024: Update C extension modules to use PyModule_AddType() (GH-19119)
Update _asyncio, _bz2, _csv, _curses, _datetime,
_io, _operator, _pickle, _queue, blake2,
multibytecodec and overlapped C extension modules
to use PyModule_AddType().
											
										 
											2020-03-25 07:08:51 +09:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-05-09 15:52:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-17 00:24:03 +09:00
										 |  |  |     module_state->str_write = PyUnicode_InternFromString("write"); | 
					
						
							|  |  |  |     if (module_state->str_write == NULL) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyModuleDef_Slot csv_slots[] = { | 
					
						
							|  |  |  |     {Py_mod_exec, csv_exec}, | 
					
						
							| 
									
										
										
										
											2023-05-05 15:11:27 -06:00
										 |  |  |     {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, | 
					
						
							| 
									
										
										
										
											2024-05-03 08:30:55 -07:00
										 |  |  |     {Py_mod_gil, Py_MOD_GIL_NOT_USED}, | 
					
						
							| 
									
										
										
										
											2020-12-15 15:14:35 +01:00
										 |  |  |     {0, NULL} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct PyModuleDef _csvmodule = { | 
					
						
							|  |  |  |     PyModuleDef_HEAD_INIT, | 
					
						
							|  |  |  |     "_csv", | 
					
						
							|  |  |  |     csv_module_doc, | 
					
						
							|  |  |  |     sizeof(_csvstate), | 
					
						
							|  |  |  |     csv_methods, | 
					
						
							|  |  |  |     csv_slots, | 
					
						
							|  |  |  |     _csv_traverse, | 
					
						
							|  |  |  |     _csv_clear, | 
					
						
							|  |  |  |     _csv_free | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyMODINIT_FUNC | 
					
						
							|  |  |  | PyInit__csv(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return PyModuleDef_Init(&_csvmodule); | 
					
						
							| 
									
										
										
										
											2003-03-20 23:29:12 +00:00
										 |  |  | } |