Branch data Line data Source code
1 : : /* csv module */
2 : :
3 : : /*
4 : :
5 : : This module provides the low-level underpinnings of a CSV reading/writing
6 : : module. Users should not use this module directly, but import the csv.py
7 : : module instead.
8 : :
9 : : */
10 : :
11 : : #define MODULE_VERSION "1.0"
12 : :
13 : : #include "Python.h"
14 : : #include "structmember.h" // PyMemberDef
15 : : #include <stdbool.h>
16 : :
17 : : /*[clinic input]
18 : : module _csv
19 : : [clinic start generated code]*/
20 : : /*[clinic end generated code: output=da39a3ee5e6b4b0d input=385118b71aa43706]*/
21 : :
22 : : #include "clinic/_csv.c.h"
23 : : #define NOT_SET ((Py_UCS4)-1)
24 : : #define EOL ((Py_UCS4)-2)
25 : :
26 : :
27 : : typedef struct {
28 : : PyObject *error_obj; /* CSV exception */
29 : : PyObject *dialects; /* Dialect registry */
30 : : PyTypeObject *dialect_type;
31 : : PyTypeObject *reader_type;
32 : : PyTypeObject *writer_type;
33 : : long field_limit; /* max parsed field size */
34 : : PyObject *str_write;
35 : : } _csvstate;
36 : :
37 : : static struct PyModuleDef _csvmodule;
38 : :
39 : : static inline _csvstate*
40 : 1 : get_csv_state(PyObject *module)
41 : : {
42 : 1 : void *state = PyModule_GetState(module);
43 : : assert(state != NULL);
44 : 1 : return (_csvstate *)state;
45 : : }
46 : :
47 : : static int
48 : 2 : _csv_clear(PyObject *module)
49 : : {
50 : 2 : _csvstate *module_state = PyModule_GetState(module);
51 [ + + ]: 2 : Py_CLEAR(module_state->error_obj);
52 [ + + ]: 2 : Py_CLEAR(module_state->dialects);
53 [ + + ]: 2 : Py_CLEAR(module_state->dialect_type);
54 [ + + ]: 2 : Py_CLEAR(module_state->reader_type);
55 [ + + ]: 2 : Py_CLEAR(module_state->writer_type);
56 [ + + ]: 2 : Py_CLEAR(module_state->str_write);
57 : 2 : return 0;
58 : : }
59 : :
60 : : static int
61 : 8 : _csv_traverse(PyObject *module, visitproc visit, void *arg)
62 : : {
63 : 8 : _csvstate *module_state = PyModule_GetState(module);
64 [ + - - + ]: 8 : Py_VISIT(module_state->error_obj);
65 [ + - - + ]: 8 : Py_VISIT(module_state->dialects);
66 [ + - - + ]: 8 : Py_VISIT(module_state->dialect_type);
67 [ + - - + ]: 8 : Py_VISIT(module_state->reader_type);
68 [ + - - + ]: 8 : Py_VISIT(module_state->writer_type);
69 : 8 : return 0;
70 : : }
71 : :
72 : : static void
73 : 1 : _csv_free(void *module)
74 : : {
75 : 1 : _csv_clear((PyObject *)module);
76 : 1 : }
77 : :
78 : : typedef enum {
79 : : START_RECORD, START_FIELD, ESCAPED_CHAR, IN_FIELD,
80 : : IN_QUOTED_FIELD, ESCAPE_IN_QUOTED_FIELD, QUOTE_IN_QUOTED_FIELD,
81 : : EAT_CRNL,AFTER_ESCAPED_CRNL
82 : : } ParserState;
83 : :
84 : : typedef enum {
85 : : QUOTE_MINIMAL, QUOTE_ALL, QUOTE_NONNUMERIC, QUOTE_NONE
86 : : } QuoteStyle;
87 : :
88 : : typedef struct {
89 : : QuoteStyle style;
90 : : const char *name;
91 : : } StyleDesc;
92 : :
93 : : static const StyleDesc quote_styles[] = {
94 : : { QUOTE_MINIMAL, "QUOTE_MINIMAL" },
95 : : { QUOTE_ALL, "QUOTE_ALL" },
96 : : { QUOTE_NONNUMERIC, "QUOTE_NONNUMERIC" },
97 : : { QUOTE_NONE, "QUOTE_NONE" },
98 : : { 0 }
99 : : };
100 : :
101 : : typedef struct {
102 : : PyObject_HEAD
103 : :
104 : : char doublequote; /* is " represented by ""? */
105 : : char skipinitialspace; /* ignore spaces following delimiter? */
106 : : char strict; /* raise exception on bad CSV */
107 : : int quoting; /* style of quoting to write */
108 : : Py_UCS4 delimiter; /* field separator */
109 : : Py_UCS4 quotechar; /* quote character */
110 : : Py_UCS4 escapechar; /* escape character */
111 : : PyObject *lineterminator; /* string to write between records */
112 : :
113 : : } DialectObj;
114 : :
115 : : typedef struct {
116 : : PyObject_HEAD
117 : :
118 : : PyObject *input_iter; /* iterate over this for input lines */
119 : :
120 : : DialectObj *dialect; /* parsing dialect */
121 : :
122 : : PyObject *fields; /* field list for current record */
123 : : ParserState state; /* current CSV parse state */
124 : : Py_UCS4 *field; /* temporary buffer */
125 : : Py_ssize_t field_size; /* size of allocated buffer */
126 : : Py_ssize_t field_len; /* length of current field */
127 : : int numeric_field; /* treat field as numeric */
128 : : unsigned long line_num; /* Source-file line number */
129 : : } ReaderObj;
130 : :
131 : : typedef struct {
132 : : PyObject_HEAD
133 : :
134 : : PyObject *write; /* write output lines to this file */
135 : :
136 : : DialectObj *dialect; /* parsing dialect */
137 : :
138 : : Py_UCS4 *rec; /* buffer for parser.join */
139 : : Py_ssize_t rec_size; /* size of allocated record */
140 : : Py_ssize_t rec_len; /* length of record */
141 : : int num_fields; /* number of fields in record */
142 : :
143 : : PyObject *error_obj; /* cached error object */
144 : : } WriterObj;
145 : :
146 : : /*
147 : : * DIALECT class
148 : : */
149 : :
150 : : static PyObject *
151 : 0 : get_dialect_from_registry(PyObject *name_obj, _csvstate *module_state)
152 : : {
153 : : PyObject *dialect_obj;
154 : :
155 : 0 : dialect_obj = PyDict_GetItemWithError(module_state->dialects, name_obj);
156 [ # # ]: 0 : if (dialect_obj == NULL) {
157 [ # # ]: 0 : if (!PyErr_Occurred())
158 : 0 : PyErr_Format(module_state->error_obj, "unknown dialect");
159 : : }
160 : : else
161 : 0 : Py_INCREF(dialect_obj);
162 : :
163 : 0 : return dialect_obj;
164 : : }
165 : :
166 : : static PyObject *
167 : 0 : get_char_or_None(Py_UCS4 c)
168 : : {
169 [ # # ]: 0 : if (c == NOT_SET) {
170 : 0 : Py_RETURN_NONE;
171 : : }
172 : : else
173 : 0 : return PyUnicode_FromOrdinal(c);
174 : : }
175 : :
176 : : static PyObject *
177 : 0 : Dialect_get_lineterminator(DialectObj *self, void *Py_UNUSED(ignored))
178 : : {
179 : 0 : return Py_XNewRef(self->lineterminator);
180 : : }
181 : :
182 : : static PyObject *
183 : 0 : Dialect_get_delimiter(DialectObj *self, void *Py_UNUSED(ignored))
184 : : {
185 : 0 : return get_char_or_None(self->delimiter);
186 : : }
187 : :
188 : : static PyObject *
189 : 0 : Dialect_get_escapechar(DialectObj *self, void *Py_UNUSED(ignored))
190 : : {
191 : 0 : return get_char_or_None(self->escapechar);
192 : : }
193 : :
194 : : static PyObject *
195 : 0 : Dialect_get_quotechar(DialectObj *self, void *Py_UNUSED(ignored))
196 : : {
197 : 0 : return get_char_or_None(self->quotechar);
198 : : }
199 : :
200 : : static PyObject *
201 : 0 : Dialect_get_quoting(DialectObj *self, void *Py_UNUSED(ignored))
202 : : {
203 : 0 : return PyLong_FromLong(self->quoting);
204 : : }
205 : :
206 : : static int
207 : 0 : _set_bool(const char *name, char *target, PyObject *src, bool dflt)
208 : : {
209 [ # # ]: 0 : if (src == NULL)
210 : 0 : *target = dflt;
211 : : else {
212 : 0 : int b = PyObject_IsTrue(src);
213 [ # # ]: 0 : if (b < 0)
214 : 0 : return -1;
215 : 0 : *target = (char)b;
216 : : }
217 : 0 : return 0;
218 : : }
219 : :
220 : : static int
221 : 0 : _set_int(const char *name, int *target, PyObject *src, int dflt)
222 : : {
223 [ # # ]: 0 : if (src == NULL)
224 : 0 : *target = dflt;
225 : : else {
226 : : int value;
227 [ # # ]: 0 : if (!PyLong_CheckExact(src)) {
228 : 0 : PyErr_Format(PyExc_TypeError,
229 : : "\"%s\" must be an integer", name);
230 : 0 : return -1;
231 : : }
232 : 0 : value = _PyLong_AsInt(src);
233 [ # # # # ]: 0 : if (value == -1 && PyErr_Occurred()) {
234 : 0 : return -1;
235 : : }
236 : 0 : *target = value;
237 : : }
238 : 0 : return 0;
239 : : }
240 : :
241 : : static int
242 : 0 : _set_char_or_none(const char *name, Py_UCS4 *target, PyObject *src, Py_UCS4 dflt)
243 : : {
244 [ # # ]: 0 : if (src == NULL) {
245 : 0 : *target = dflt;
246 : : }
247 : : else {
248 : 0 : *target = NOT_SET;
249 [ # # ]: 0 : if (src != Py_None) {
250 [ # # ]: 0 : if (!PyUnicode_Check(src)) {
251 : 0 : PyErr_Format(PyExc_TypeError,
252 : : "\"%s\" must be string or None, not %.200s", name,
253 : 0 : Py_TYPE(src)->tp_name);
254 : 0 : return -1;
255 : : }
256 : 0 : Py_ssize_t len = PyUnicode_GetLength(src);
257 [ # # ]: 0 : if (len < 0) {
258 : 0 : return -1;
259 : : }
260 [ # # ]: 0 : if (len != 1) {
261 : 0 : PyErr_Format(PyExc_TypeError,
262 : : "\"%s\" must be a 1-character string",
263 : : name);
264 : 0 : return -1;
265 : : }
266 : : /* PyUnicode_READY() is called in PyUnicode_GetLength() */
267 : 0 : *target = PyUnicode_READ_CHAR(src, 0);
268 : : }
269 : : }
270 : 0 : return 0;
271 : : }
272 : :
273 : : static int
274 : 0 : _set_char(const char *name, Py_UCS4 *target, PyObject *src, Py_UCS4 dflt)
275 : : {
276 [ # # ]: 0 : if (src == NULL) {
277 : 0 : *target = dflt;
278 : : }
279 : : else {
280 [ # # ]: 0 : if (!PyUnicode_Check(src)) {
281 : 0 : PyErr_Format(PyExc_TypeError,
282 : : "\"%s\" must be string, not %.200s", name,
283 : 0 : Py_TYPE(src)->tp_name);
284 : 0 : return -1;
285 : : }
286 : 0 : Py_ssize_t len = PyUnicode_GetLength(src);
287 [ # # ]: 0 : if (len < 0) {
288 : 0 : return -1;
289 : : }
290 [ # # ]: 0 : if (len != 1) {
291 : 0 : PyErr_Format(PyExc_TypeError,
292 : : "\"%s\" must be a 1-character string",
293 : : name);
294 : 0 : return -1;
295 : : }
296 : : /* PyUnicode_READY() is called in PyUnicode_GetLength() */
297 : 0 : *target = PyUnicode_READ_CHAR(src, 0);
298 : : }
299 : 0 : return 0;
300 : : }
301 : :
302 : : static int
303 : 0 : _set_str(const char *name, PyObject **target, PyObject *src, const char *dflt)
304 : : {
305 [ # # ]: 0 : if (src == NULL)
306 : 0 : *target = PyUnicode_DecodeASCII(dflt, strlen(dflt), NULL);
307 : : else {
308 [ # # ]: 0 : if (src == Py_None)
309 : 0 : *target = NULL;
310 [ # # ]: 0 : else if (!PyUnicode_Check(src)) {
311 : 0 : PyErr_Format(PyExc_TypeError,
312 : : "\"%s\" must be a string", name);
313 : 0 : return -1;
314 : : }
315 : : else {
316 [ # # ]: 0 : if (PyUnicode_READY(src) == -1)
317 : 0 : return -1;
318 : 0 : Py_XSETREF(*target, Py_NewRef(src));
319 : : }
320 : : }
321 : 0 : return 0;
322 : : }
323 : :
324 : : static int
325 : 0 : dialect_check_quoting(int quoting)
326 : : {
327 : : const StyleDesc *qs;
328 : :
329 [ # # ]: 0 : for (qs = quote_styles; qs->name; qs++) {
330 [ # # ]: 0 : if ((int)qs->style == quoting)
331 : 0 : return 0;
332 : : }
333 : 0 : PyErr_Format(PyExc_TypeError, "bad \"quoting\" value");
334 : 0 : return -1;
335 : : }
336 : :
337 : : #define D_OFF(x) offsetof(DialectObj, x)
338 : :
339 : : static struct PyMemberDef Dialect_memberlist[] = {
340 : : { "skipinitialspace", T_BOOL, D_OFF(skipinitialspace), READONLY },
341 : : { "doublequote", T_BOOL, D_OFF(doublequote), READONLY },
342 : : { "strict", T_BOOL, D_OFF(strict), READONLY },
343 : : { NULL }
344 : : };
345 : :
346 : : static PyGetSetDef Dialect_getsetlist[] = {
347 : : { "delimiter", (getter)Dialect_get_delimiter},
348 : : { "escapechar", (getter)Dialect_get_escapechar},
349 : : { "lineterminator", (getter)Dialect_get_lineterminator},
350 : : { "quotechar", (getter)Dialect_get_quotechar},
351 : : { "quoting", (getter)Dialect_get_quoting},
352 : : {NULL},
353 : : };
354 : :
355 : : static void
356 : 0 : Dialect_dealloc(DialectObj *self)
357 : : {
358 : 0 : PyTypeObject *tp = Py_TYPE(self);
359 : 0 : PyObject_GC_UnTrack(self);
360 : 0 : tp->tp_clear((PyObject *)self);
361 : 0 : PyObject_GC_Del(self);
362 : 0 : Py_DECREF(tp);
363 : 0 : }
364 : :
365 : : static char *dialect_kws[] = {
366 : : "dialect",
367 : : "delimiter",
368 : : "doublequote",
369 : : "escapechar",
370 : : "lineterminator",
371 : : "quotechar",
372 : : "quoting",
373 : : "skipinitialspace",
374 : : "strict",
375 : : NULL
376 : : };
377 : :
378 : : static _csvstate *
379 : 0 : _csv_state_from_type(PyTypeObject *type, const char *name)
380 : : {
381 : 0 : PyObject *module = PyType_GetModuleByDef(type, &_csvmodule);
382 [ # # ]: 0 : if (module == NULL) {
383 : 0 : return NULL;
384 : : }
385 : 0 : _csvstate *module_state = PyModule_GetState(module);
386 [ # # ]: 0 : if (module_state == NULL) {
387 : 0 : PyErr_Format(PyExc_SystemError,
388 : : "%s: No _csv module state found", name);
389 : 0 : return NULL;
390 : : }
391 : 0 : return module_state;
392 : : }
393 : :
394 : : static PyObject *
395 : 0 : dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
396 : : {
397 : : DialectObj *self;
398 : 0 : PyObject *ret = NULL;
399 : 0 : PyObject *dialect = NULL;
400 : 0 : PyObject *delimiter = NULL;
401 : 0 : PyObject *doublequote = NULL;
402 : 0 : PyObject *escapechar = NULL;
403 : 0 : PyObject *lineterminator = NULL;
404 : 0 : PyObject *quotechar = NULL;
405 : 0 : PyObject *quoting = NULL;
406 : 0 : PyObject *skipinitialspace = NULL;
407 : 0 : PyObject *strict = NULL;
408 : :
409 [ # # ]: 0 : if (!PyArg_ParseTupleAndKeywords(args, kwargs,
410 : : "|OOOOOOOOO", dialect_kws,
411 : : &dialect,
412 : : &delimiter,
413 : : &doublequote,
414 : : &escapechar,
415 : : &lineterminator,
416 : : "echar,
417 : : "ing,
418 : : &skipinitialspace,
419 : : &strict))
420 : 0 : return NULL;
421 : :
422 : 0 : _csvstate *module_state = _csv_state_from_type(type, "dialect_new");
423 [ # # ]: 0 : if (module_state == NULL) {
424 : 0 : return NULL;
425 : : }
426 : :
427 [ # # ]: 0 : if (dialect != NULL) {
428 [ # # ]: 0 : if (PyUnicode_Check(dialect)) {
429 : 0 : dialect = get_dialect_from_registry(dialect, module_state);
430 [ # # ]: 0 : if (dialect == NULL)
431 : 0 : return NULL;
432 : : }
433 : : else
434 : 0 : Py_INCREF(dialect);
435 : : /* Can we reuse this instance? */
436 [ # # ]: 0 : if (PyObject_TypeCheck(dialect, module_state->dialect_type) &&
437 [ # # ]: 0 : delimiter == NULL &&
438 [ # # ]: 0 : doublequote == NULL &&
439 [ # # ]: 0 : escapechar == NULL &&
440 [ # # ]: 0 : lineterminator == NULL &&
441 [ # # ]: 0 : quotechar == NULL &&
442 [ # # ]: 0 : quoting == NULL &&
443 [ # # ]: 0 : skipinitialspace == NULL &&
444 [ # # ]: 0 : strict == NULL)
445 : 0 : return dialect;
446 : : }
447 : :
448 : 0 : self = (DialectObj *)type->tp_alloc(type, 0);
449 [ # # ]: 0 : if (self == NULL) {
450 [ # # ]: 0 : Py_CLEAR(dialect);
451 : 0 : return NULL;
452 : : }
453 : 0 : self->lineterminator = NULL;
454 : :
455 : 0 : Py_XINCREF(delimiter);
456 : 0 : Py_XINCREF(doublequote);
457 : 0 : Py_XINCREF(escapechar);
458 : 0 : Py_XINCREF(lineterminator);
459 : 0 : Py_XINCREF(quotechar);
460 : 0 : Py_XINCREF(quoting);
461 : 0 : Py_XINCREF(skipinitialspace);
462 : 0 : Py_XINCREF(strict);
463 [ # # ]: 0 : if (dialect != NULL) {
464 : : #define DIALECT_GETATTR(v, n) \
465 : : do { \
466 : : if (v == NULL) { \
467 : : v = PyObject_GetAttrString(dialect, n); \
468 : : if (v == NULL) \
469 : : PyErr_Clear(); \
470 : : } \
471 : : } while (0)
472 [ # # # # ]: 0 : DIALECT_GETATTR(delimiter, "delimiter");
473 [ # # # # ]: 0 : DIALECT_GETATTR(doublequote, "doublequote");
474 [ # # # # ]: 0 : DIALECT_GETATTR(escapechar, "escapechar");
475 [ # # # # ]: 0 : DIALECT_GETATTR(lineterminator, "lineterminator");
476 [ # # # # ]: 0 : DIALECT_GETATTR(quotechar, "quotechar");
477 [ # # # # ]: 0 : DIALECT_GETATTR(quoting, "quoting");
478 [ # # # # ]: 0 : DIALECT_GETATTR(skipinitialspace, "skipinitialspace");
479 [ # # # # ]: 0 : DIALECT_GETATTR(strict, "strict");
480 : : }
481 : :
482 : : /* check types and convert to C values */
483 : : #define DIASET(meth, name, target, src, dflt) \
484 : : if (meth(name, target, src, dflt)) \
485 : : goto err
486 [ # # ]: 0 : DIASET(_set_char, "delimiter", &self->delimiter, delimiter, ',');
487 [ # # ]: 0 : DIASET(_set_bool, "doublequote", &self->doublequote, doublequote, true);
488 [ # # ]: 0 : DIASET(_set_char_or_none, "escapechar", &self->escapechar, escapechar, NOT_SET);
489 [ # # ]: 0 : DIASET(_set_str, "lineterminator", &self->lineterminator, lineterminator, "\r\n");
490 [ # # ]: 0 : DIASET(_set_char_or_none, "quotechar", &self->quotechar, quotechar, '"');
491 [ # # ]: 0 : DIASET(_set_int, "quoting", &self->quoting, quoting, QUOTE_MINIMAL);
492 [ # # ]: 0 : DIASET(_set_bool, "skipinitialspace", &self->skipinitialspace, skipinitialspace, false);
493 [ # # ]: 0 : DIASET(_set_bool, "strict", &self->strict, strict, false);
494 : :
495 : : /* validate options */
496 [ # # ]: 0 : if (dialect_check_quoting(self->quoting))
497 : 0 : goto err;
498 [ # # ]: 0 : if (self->delimiter == NOT_SET) {
499 : 0 : PyErr_SetString(PyExc_TypeError,
500 : : "\"delimiter\" must be a 1-character string");
501 : 0 : goto err;
502 : : }
503 [ # # # # ]: 0 : if (quotechar == Py_None && quoting == NULL)
504 : 0 : self->quoting = QUOTE_NONE;
505 [ # # # # ]: 0 : if (self->quoting != QUOTE_NONE && self->quotechar == NOT_SET) {
506 : 0 : PyErr_SetString(PyExc_TypeError,
507 : : "quotechar must be set if quoting enabled");
508 : 0 : goto err;
509 : : }
510 [ # # ]: 0 : if (self->lineterminator == NULL) {
511 : 0 : PyErr_SetString(PyExc_TypeError, "lineterminator must be set");
512 : 0 : goto err;
513 : : }
514 : :
515 : 0 : ret = Py_NewRef(self);
516 : 0 : err:
517 [ # # ]: 0 : Py_CLEAR(self);
518 [ # # ]: 0 : Py_CLEAR(dialect);
519 [ # # ]: 0 : Py_CLEAR(delimiter);
520 [ # # ]: 0 : Py_CLEAR(doublequote);
521 [ # # ]: 0 : Py_CLEAR(escapechar);
522 [ # # ]: 0 : Py_CLEAR(lineterminator);
523 [ # # ]: 0 : Py_CLEAR(quotechar);
524 [ # # ]: 0 : Py_CLEAR(quoting);
525 [ # # ]: 0 : Py_CLEAR(skipinitialspace);
526 [ # # ]: 0 : Py_CLEAR(strict);
527 : 0 : return ret;
528 : : }
529 : :
530 : : /* Since dialect is now a heap type, it inherits pickling method for
531 : : * protocol 0 and 1 from object, therefore it needs to be overridden */
532 : :
533 : : PyDoc_STRVAR(dialect_reduce_doc, "raises an exception to avoid pickling");
534 : :
535 : : static PyObject *
536 : 0 : Dialect_reduce(PyObject *self, PyObject *args) {
537 : 0 : PyErr_Format(PyExc_TypeError,
538 : : "cannot pickle '%.100s' instances", _PyType_Name(Py_TYPE(self)));
539 : 0 : return NULL;
540 : : }
541 : :
542 : : static struct PyMethodDef dialect_methods[] = {
543 : : {"__reduce__", Dialect_reduce, METH_VARARGS, dialect_reduce_doc},
544 : : {"__reduce_ex__", Dialect_reduce, METH_VARARGS, dialect_reduce_doc},
545 : : {NULL, NULL}
546 : : };
547 : :
548 : : PyDoc_STRVAR(Dialect_Type_doc,
549 : : "CSV dialect\n"
550 : : "\n"
551 : : "The Dialect type records CSV parsing and generation options.\n");
552 : :
553 : : static int
554 : 0 : Dialect_clear(DialectObj *self)
555 : : {
556 [ # # ]: 0 : Py_CLEAR(self->lineterminator);
557 : 0 : return 0;
558 : : }
559 : :
560 : : static int
561 : 0 : Dialect_traverse(DialectObj *self, visitproc visit, void *arg)
562 : : {
563 [ # # # # ]: 0 : Py_VISIT(self->lineterminator);
564 [ # # # # ]: 0 : Py_VISIT(Py_TYPE(self));
565 : 0 : return 0;
566 : : }
567 : :
568 : : static PyType_Slot Dialect_Type_slots[] = {
569 : : {Py_tp_doc, (char*)Dialect_Type_doc},
570 : : {Py_tp_members, Dialect_memberlist},
571 : : {Py_tp_getset, Dialect_getsetlist},
572 : : {Py_tp_new, dialect_new},
573 : : {Py_tp_methods, dialect_methods},
574 : : {Py_tp_dealloc, Dialect_dealloc},
575 : : {Py_tp_clear, Dialect_clear},
576 : : {Py_tp_traverse, Dialect_traverse},
577 : : {0, NULL}
578 : : };
579 : :
580 : : PyType_Spec Dialect_Type_spec = {
581 : : .name = "_csv.Dialect",
582 : : .basicsize = sizeof(DialectObj),
583 : : .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
584 : : Py_TPFLAGS_IMMUTABLETYPE),
585 : : .slots = Dialect_Type_slots,
586 : : };
587 : :
588 : :
589 : : /*
590 : : * Return an instance of the dialect type, given a Python instance or kwarg
591 : : * description of the dialect
592 : : */
593 : : static PyObject *
594 : 0 : _call_dialect(_csvstate *module_state, PyObject *dialect_inst, PyObject *kwargs)
595 : : {
596 : 0 : PyObject *type = (PyObject *)module_state->dialect_type;
597 [ # # ]: 0 : if (dialect_inst) {
598 : 0 : return PyObject_VectorcallDict(type, &dialect_inst, 1, kwargs);
599 : : }
600 : : else {
601 : 0 : return PyObject_VectorcallDict(type, NULL, 0, kwargs);
602 : : }
603 : : }
604 : :
605 : : /*
606 : : * READER
607 : : */
608 : : static int
609 : 0 : parse_save_field(ReaderObj *self)
610 : : {
611 : : PyObject *field;
612 : :
613 : 0 : field = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND,
614 : 0 : (void *) self->field, self->field_len);
615 [ # # ]: 0 : if (field == NULL)
616 : 0 : return -1;
617 : 0 : self->field_len = 0;
618 [ # # ]: 0 : if (self->numeric_field) {
619 : : PyObject *tmp;
620 : :
621 : 0 : self->numeric_field = 0;
622 : 0 : tmp = PyNumber_Float(field);
623 : 0 : Py_DECREF(field);
624 [ # # ]: 0 : if (tmp == NULL)
625 : 0 : return -1;
626 : 0 : field = tmp;
627 : : }
628 [ # # ]: 0 : if (PyList_Append(self->fields, field) < 0) {
629 : 0 : Py_DECREF(field);
630 : 0 : return -1;
631 : : }
632 : 0 : Py_DECREF(field);
633 : 0 : return 0;
634 : : }
635 : :
636 : : static int
637 : 0 : parse_grow_buff(ReaderObj *self)
638 : : {
639 : : assert((size_t)self->field_size <= PY_SSIZE_T_MAX / sizeof(Py_UCS4));
640 : :
641 [ # # ]: 0 : Py_ssize_t field_size_new = self->field_size ? 2 * self->field_size : 4096;
642 : 0 : Py_UCS4 *field_new = self->field;
643 [ # # ]: 0 : PyMem_Resize(field_new, Py_UCS4, field_size_new);
644 [ # # ]: 0 : if (field_new == NULL) {
645 : 0 : PyErr_NoMemory();
646 : 0 : return 0;
647 : : }
648 : 0 : self->field = field_new;
649 : 0 : self->field_size = field_size_new;
650 : 0 : return 1;
651 : : }
652 : :
653 : : static int
654 : 0 : parse_add_char(ReaderObj *self, _csvstate *module_state, Py_UCS4 c)
655 : : {
656 [ # # ]: 0 : if (self->field_len >= module_state->field_limit) {
657 : 0 : PyErr_Format(module_state->error_obj,
658 : : "field larger than field limit (%ld)",
659 : : module_state->field_limit);
660 : 0 : return -1;
661 : : }
662 [ # # # # ]: 0 : if (self->field_len == self->field_size && !parse_grow_buff(self))
663 : 0 : return -1;
664 : 0 : self->field[self->field_len++] = c;
665 : 0 : return 0;
666 : : }
667 : :
668 : : static int
669 : 0 : parse_process_char(ReaderObj *self, _csvstate *module_state, Py_UCS4 c)
670 : : {
671 : 0 : DialectObj *dialect = self->dialect;
672 : :
673 [ # # # # : 0 : switch (self->state) {
# # # # #
# ]
674 : 0 : case START_RECORD:
675 : : /* start of record */
676 [ # # ]: 0 : if (c == EOL)
677 : : /* empty line - return [] */
678 : 0 : break;
679 [ # # # # ]: 0 : else if (c == '\n' || c == '\r') {
680 : 0 : self->state = EAT_CRNL;
681 : 0 : break;
682 : : }
683 : : /* normal character - handle as START_FIELD */
684 : 0 : self->state = START_FIELD;
685 : : /* fallthru */
686 : 0 : case START_FIELD:
687 : : /* expecting field */
688 [ # # # # : 0 : if (c == '\n' || c == '\r' || c == EOL) {
# # ]
689 : : /* save empty field - return [fields] */
690 [ # # ]: 0 : if (parse_save_field(self) < 0)
691 : 0 : return -1;
692 [ # # ]: 0 : self->state = (c == EOL ? START_RECORD : EAT_CRNL);
693 : : }
694 [ # # ]: 0 : else if (c == dialect->quotechar &&
695 [ # # ]: 0 : dialect->quoting != QUOTE_NONE) {
696 : : /* start quoted field */
697 : 0 : self->state = IN_QUOTED_FIELD;
698 : : }
699 [ # # ]: 0 : else if (c == dialect->escapechar) {
700 : : /* possible escaped character */
701 : 0 : self->state = ESCAPED_CHAR;
702 : : }
703 [ # # # # ]: 0 : else if (c == ' ' && dialect->skipinitialspace)
704 : : /* ignore spaces at start of field */
705 : : ;
706 [ # # ]: 0 : else if (c == dialect->delimiter) {
707 : : /* save empty field */
708 [ # # ]: 0 : if (parse_save_field(self) < 0)
709 : 0 : return -1;
710 : : }
711 : : else {
712 : : /* begin new unquoted field */
713 [ # # ]: 0 : if (dialect->quoting == QUOTE_NONNUMERIC)
714 : 0 : self->numeric_field = 1;
715 [ # # ]: 0 : if (parse_add_char(self, module_state, c) < 0)
716 : 0 : return -1;
717 : 0 : self->state = IN_FIELD;
718 : : }
719 : 0 : break;
720 : :
721 : 0 : case ESCAPED_CHAR:
722 [ # # # # ]: 0 : if (c == '\n' || c=='\r') {
723 [ # # ]: 0 : if (parse_add_char(self, module_state, c) < 0)
724 : 0 : return -1;
725 : 0 : self->state = AFTER_ESCAPED_CRNL;
726 : 0 : break;
727 : : }
728 [ # # ]: 0 : if (c == EOL)
729 : 0 : c = '\n';
730 [ # # ]: 0 : if (parse_add_char(self, module_state, c) < 0)
731 : 0 : return -1;
732 : 0 : self->state = IN_FIELD;
733 : 0 : break;
734 : :
735 : 0 : case AFTER_ESCAPED_CRNL:
736 [ # # ]: 0 : if (c == EOL)
737 : 0 : break;
738 : : /*fallthru*/
739 : :
740 : : case IN_FIELD:
741 : : /* in unquoted field */
742 [ # # # # : 0 : if (c == '\n' || c == '\r' || c == EOL) {
# # ]
743 : : /* end of line - return [fields] */
744 [ # # ]: 0 : if (parse_save_field(self) < 0)
745 : 0 : return -1;
746 [ # # ]: 0 : self->state = (c == EOL ? START_RECORD : EAT_CRNL);
747 : : }
748 [ # # ]: 0 : else if (c == dialect->escapechar) {
749 : : /* possible escaped character */
750 : 0 : self->state = ESCAPED_CHAR;
751 : : }
752 [ # # ]: 0 : else if (c == dialect->delimiter) {
753 : : /* save field - wait for new field */
754 [ # # ]: 0 : if (parse_save_field(self) < 0)
755 : 0 : return -1;
756 : 0 : self->state = START_FIELD;
757 : : }
758 : : else {
759 : : /* normal character - save in field */
760 [ # # ]: 0 : if (parse_add_char(self, module_state, c) < 0)
761 : 0 : return -1;
762 : : }
763 : 0 : break;
764 : :
765 : 0 : case IN_QUOTED_FIELD:
766 : : /* in quoted field */
767 [ # # ]: 0 : if (c == EOL)
768 : : ;
769 [ # # ]: 0 : else if (c == dialect->escapechar) {
770 : : /* Possible escape character */
771 : 0 : self->state = ESCAPE_IN_QUOTED_FIELD;
772 : : }
773 [ # # ]: 0 : else if (c == dialect->quotechar &&
774 [ # # ]: 0 : dialect->quoting != QUOTE_NONE) {
775 [ # # ]: 0 : if (dialect->doublequote) {
776 : : /* doublequote; " represented by "" */
777 : 0 : self->state = QUOTE_IN_QUOTED_FIELD;
778 : : }
779 : : else {
780 : : /* end of quote part of field */
781 : 0 : self->state = IN_FIELD;
782 : : }
783 : : }
784 : : else {
785 : : /* normal character - save in field */
786 [ # # ]: 0 : if (parse_add_char(self, module_state, c) < 0)
787 : 0 : return -1;
788 : : }
789 : 0 : break;
790 : :
791 : 0 : case ESCAPE_IN_QUOTED_FIELD:
792 [ # # ]: 0 : if (c == EOL)
793 : 0 : c = '\n';
794 [ # # ]: 0 : if (parse_add_char(self, module_state, c) < 0)
795 : 0 : return -1;
796 : 0 : self->state = IN_QUOTED_FIELD;
797 : 0 : break;
798 : :
799 : 0 : case QUOTE_IN_QUOTED_FIELD:
800 : : /* doublequote - seen a quote in a quoted field */
801 [ # # ]: 0 : if (dialect->quoting != QUOTE_NONE &&
802 [ # # ]: 0 : c == dialect->quotechar) {
803 : : /* save "" as " */
804 [ # # ]: 0 : if (parse_add_char(self, module_state, c) < 0)
805 : 0 : return -1;
806 : 0 : self->state = IN_QUOTED_FIELD;
807 : : }
808 [ # # ]: 0 : else if (c == dialect->delimiter) {
809 : : /* save field - wait for new field */
810 [ # # ]: 0 : if (parse_save_field(self) < 0)
811 : 0 : return -1;
812 : 0 : self->state = START_FIELD;
813 : : }
814 [ # # # # : 0 : else if (c == '\n' || c == '\r' || c == EOL) {
# # ]
815 : : /* end of line - return [fields] */
816 [ # # ]: 0 : if (parse_save_field(self) < 0)
817 : 0 : return -1;
818 [ # # ]: 0 : self->state = (c == EOL ? START_RECORD : EAT_CRNL);
819 : : }
820 [ # # ]: 0 : else if (!dialect->strict) {
821 [ # # ]: 0 : if (parse_add_char(self, module_state, c) < 0)
822 : 0 : return -1;
823 : 0 : self->state = IN_FIELD;
824 : : }
825 : : else {
826 : : /* illegal */
827 : 0 : PyErr_Format(module_state->error_obj, "'%c' expected after '%c'",
828 : : dialect->delimiter,
829 : : dialect->quotechar);
830 : 0 : return -1;
831 : : }
832 : 0 : break;
833 : :
834 : 0 : case EAT_CRNL:
835 [ # # # # ]: 0 : if (c == '\n' || c == '\r')
836 : : ;
837 [ # # ]: 0 : else if (c == EOL)
838 : 0 : self->state = START_RECORD;
839 : : else {
840 : 0 : PyErr_Format(module_state->error_obj,
841 : : "new-line character seen in unquoted field - do you need to open the file in universal-newline mode?");
842 : 0 : return -1;
843 : : }
844 : 0 : break;
845 : :
846 : : }
847 : 0 : return 0;
848 : : }
849 : :
850 : : static int
851 : 0 : parse_reset(ReaderObj *self)
852 : : {
853 : 0 : Py_XSETREF(self->fields, PyList_New(0));
854 [ # # ]: 0 : if (self->fields == NULL)
855 : 0 : return -1;
856 : 0 : self->field_len = 0;
857 : 0 : self->state = START_RECORD;
858 : 0 : self->numeric_field = 0;
859 : 0 : return 0;
860 : : }
861 : :
862 : : static PyObject *
863 : 0 : Reader_iternext(ReaderObj *self)
864 : : {
865 : 0 : PyObject *fields = NULL;
866 : : Py_UCS4 c;
867 : : Py_ssize_t pos, linelen;
868 : : int kind;
869 : : const void *data;
870 : : PyObject *lineobj;
871 : :
872 : 0 : _csvstate *module_state = _csv_state_from_type(Py_TYPE(self),
873 : : "Reader.__next__");
874 [ # # ]: 0 : if (module_state == NULL) {
875 : 0 : return NULL;
876 : : }
877 : :
878 [ # # ]: 0 : if (parse_reset(self) < 0)
879 : 0 : return NULL;
880 : : do {
881 : 0 : lineobj = PyIter_Next(self->input_iter);
882 [ # # ]: 0 : if (lineobj == NULL) {
883 : : /* End of input OR exception */
884 [ # # # # ]: 0 : if (!PyErr_Occurred() && (self->field_len != 0 ||
885 [ # # ]: 0 : self->state == IN_QUOTED_FIELD)) {
886 [ # # ]: 0 : if (self->dialect->strict)
887 : 0 : PyErr_SetString(module_state->error_obj,
888 : : "unexpected end of data");
889 [ # # ]: 0 : else if (parse_save_field(self) >= 0)
890 : 0 : break;
891 : : }
892 : 0 : return NULL;
893 : : }
894 [ # # ]: 0 : if (!PyUnicode_Check(lineobj)) {
895 : 0 : PyErr_Format(module_state->error_obj,
896 : : "iterator should return strings, "
897 : : "not %.200s "
898 : : "(the file should be opened in text mode)",
899 : 0 : Py_TYPE(lineobj)->tp_name
900 : : );
901 : 0 : Py_DECREF(lineobj);
902 : 0 : return NULL;
903 : : }
904 [ # # ]: 0 : if (PyUnicode_READY(lineobj) == -1) {
905 : 0 : Py_DECREF(lineobj);
906 : 0 : return NULL;
907 : : }
908 : 0 : ++self->line_num;
909 : 0 : kind = PyUnicode_KIND(lineobj);
910 : 0 : data = PyUnicode_DATA(lineobj);
911 : 0 : pos = 0;
912 : 0 : linelen = PyUnicode_GET_LENGTH(lineobj);
913 [ # # ]: 0 : while (linelen--) {
914 : 0 : c = PyUnicode_READ(kind, data, pos);
915 [ # # ]: 0 : if (parse_process_char(self, module_state, c) < 0) {
916 : 0 : Py_DECREF(lineobj);
917 : 0 : goto err;
918 : : }
919 : 0 : pos++;
920 : : }
921 : 0 : Py_DECREF(lineobj);
922 [ # # ]: 0 : if (parse_process_char(self, module_state, EOL) < 0)
923 : 0 : goto err;
924 [ # # ]: 0 : } while (self->state != START_RECORD);
925 : :
926 : 0 : fields = self->fields;
927 : 0 : self->fields = NULL;
928 : 0 : err:
929 : 0 : return fields;
930 : : }
931 : :
932 : : static void
933 : 0 : Reader_dealloc(ReaderObj *self)
934 : : {
935 : 0 : PyTypeObject *tp = Py_TYPE(self);
936 : 0 : PyObject_GC_UnTrack(self);
937 : 0 : tp->tp_clear((PyObject *)self);
938 [ # # ]: 0 : if (self->field != NULL) {
939 : 0 : PyMem_Free(self->field);
940 : 0 : self->field = NULL;
941 : : }
942 : 0 : PyObject_GC_Del(self);
943 : 0 : Py_DECREF(tp);
944 : 0 : }
945 : :
946 : : static int
947 : 0 : Reader_traverse(ReaderObj *self, visitproc visit, void *arg)
948 : : {
949 [ # # # # ]: 0 : Py_VISIT(self->dialect);
950 [ # # # # ]: 0 : Py_VISIT(self->input_iter);
951 [ # # # # ]: 0 : Py_VISIT(self->fields);
952 [ # # # # ]: 0 : Py_VISIT(Py_TYPE(self));
953 : 0 : return 0;
954 : : }
955 : :
956 : : static int
957 : 0 : Reader_clear(ReaderObj *self)
958 : : {
959 [ # # ]: 0 : Py_CLEAR(self->dialect);
960 [ # # ]: 0 : Py_CLEAR(self->input_iter);
961 [ # # ]: 0 : Py_CLEAR(self->fields);
962 : 0 : return 0;
963 : : }
964 : :
965 : : PyDoc_STRVAR(Reader_Type_doc,
966 : : "CSV reader\n"
967 : : "\n"
968 : : "Reader objects are responsible for reading and parsing tabular data\n"
969 : : "in CSV format.\n"
970 : : );
971 : :
972 : : static struct PyMethodDef Reader_methods[] = {
973 : : { NULL, NULL }
974 : : };
975 : : #define R_OFF(x) offsetof(ReaderObj, x)
976 : :
977 : : static struct PyMemberDef Reader_memberlist[] = {
978 : : { "dialect", T_OBJECT, R_OFF(dialect), READONLY },
979 : : { "line_num", T_ULONG, R_OFF(line_num), READONLY },
980 : : { NULL }
981 : : };
982 : :
983 : :
984 : : static PyType_Slot Reader_Type_slots[] = {
985 : : {Py_tp_doc, (char*)Reader_Type_doc},
986 : : {Py_tp_traverse, Reader_traverse},
987 : : {Py_tp_iter, PyObject_SelfIter},
988 : : {Py_tp_iternext, Reader_iternext},
989 : : {Py_tp_methods, Reader_methods},
990 : : {Py_tp_members, Reader_memberlist},
991 : : {Py_tp_clear, Reader_clear},
992 : : {Py_tp_dealloc, Reader_dealloc},
993 : : {0, NULL}
994 : : };
995 : :
996 : : PyType_Spec Reader_Type_spec = {
997 : : .name = "_csv.reader",
998 : : .basicsize = sizeof(ReaderObj),
999 : : .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
1000 : : Py_TPFLAGS_IMMUTABLETYPE),
1001 : : .slots = Reader_Type_slots
1002 : : };
1003 : :
1004 : :
1005 : : static PyObject *
1006 : 0 : csv_reader(PyObject *module, PyObject *args, PyObject *keyword_args)
1007 : : {
1008 : 0 : PyObject * iterator, * dialect = NULL;
1009 : 0 : _csvstate *module_state = get_csv_state(module);
1010 : 0 : ReaderObj * self = PyObject_GC_New(
1011 : : ReaderObj,
1012 : : module_state->reader_type);
1013 : :
1014 [ # # ]: 0 : if (!self)
1015 : 0 : return NULL;
1016 : :
1017 : 0 : self->dialect = NULL;
1018 : 0 : self->fields = NULL;
1019 : 0 : self->input_iter = NULL;
1020 : 0 : self->field = NULL;
1021 : 0 : self->field_size = 0;
1022 : 0 : self->line_num = 0;
1023 : :
1024 [ # # ]: 0 : if (parse_reset(self) < 0) {
1025 : 0 : Py_DECREF(self);
1026 : 0 : return NULL;
1027 : : }
1028 : :
1029 [ # # ]: 0 : if (!PyArg_UnpackTuple(args, "", 1, 2, &iterator, &dialect)) {
1030 : 0 : Py_DECREF(self);
1031 : 0 : return NULL;
1032 : : }
1033 : 0 : self->input_iter = PyObject_GetIter(iterator);
1034 [ # # ]: 0 : if (self->input_iter == NULL) {
1035 : 0 : Py_DECREF(self);
1036 : 0 : return NULL;
1037 : : }
1038 : 0 : self->dialect = (DialectObj *)_call_dialect(module_state, dialect,
1039 : : keyword_args);
1040 [ # # ]: 0 : if (self->dialect == NULL) {
1041 : 0 : Py_DECREF(self);
1042 : 0 : return NULL;
1043 : : }
1044 : :
1045 : 0 : PyObject_GC_Track(self);
1046 : 0 : return (PyObject *)self;
1047 : : }
1048 : :
1049 : : /*
1050 : : * WRITER
1051 : : */
1052 : : /* ---------------------------------------------------------------- */
1053 : : static void
1054 : 0 : join_reset(WriterObj *self)
1055 : : {
1056 : 0 : self->rec_len = 0;
1057 : 0 : self->num_fields = 0;
1058 : 0 : }
1059 : :
1060 : : #define MEM_INCR 32768
1061 : :
1062 : : /* Calculate new record length or append field to record. Return new
1063 : : * record length.
1064 : : */
1065 : : static Py_ssize_t
1066 : 0 : join_append_data(WriterObj *self, int field_kind, const void *field_data,
1067 : : Py_ssize_t field_len, int *quoted,
1068 : : int copy_phase)
1069 : : {
1070 : 0 : DialectObj *dialect = self->dialect;
1071 : : int i;
1072 : : Py_ssize_t rec_len;
1073 : :
1074 : : #define INCLEN \
1075 : : do {\
1076 : : if (!copy_phase && rec_len == PY_SSIZE_T_MAX) { \
1077 : : goto overflow; \
1078 : : } \
1079 : : rec_len++; \
1080 : : } while(0)
1081 : :
1082 : : #define ADDCH(c) \
1083 : : do {\
1084 : : if (copy_phase) \
1085 : : self->rec[rec_len] = c;\
1086 : : INCLEN;\
1087 : : } while(0)
1088 : :
1089 : 0 : rec_len = self->rec_len;
1090 : :
1091 : : /* If this is not the first field we need a field separator */
1092 [ # # ]: 0 : if (self->num_fields > 0)
1093 [ # # # # : 0 : ADDCH(dialect->delimiter);
# # ]
1094 : :
1095 : : /* Handle preceding quote */
1096 [ # # # # ]: 0 : if (copy_phase && *quoted)
1097 [ # # # # : 0 : ADDCH(dialect->quotechar);
# # ]
1098 : :
1099 : : /* Copy/count field data */
1100 : : /* If field is null just pass over */
1101 [ # # # # ]: 0 : for (i = 0; field_data && (i < field_len); i++) {
1102 : 0 : Py_UCS4 c = PyUnicode_READ(field_kind, field_data, i);
1103 : 0 : int want_escape = 0;
1104 : :
1105 [ # # ]: 0 : if (c == dialect->delimiter ||
1106 [ # # ]: 0 : c == dialect->escapechar ||
1107 [ # # # # ]: 0 : c == dialect->quotechar ||
1108 : 0 : PyUnicode_FindChar(
1109 : : dialect->lineterminator, c, 0,
1110 : : PyUnicode_GET_LENGTH(dialect->lineterminator), 1) >= 0) {
1111 [ # # ]: 0 : if (dialect->quoting == QUOTE_NONE)
1112 : 0 : want_escape = 1;
1113 : : else {
1114 [ # # ]: 0 : if (c == dialect->quotechar) {
1115 [ # # ]: 0 : if (dialect->doublequote)
1116 [ # # # # : 0 : ADDCH(dialect->quotechar);
# # ]
1117 : : else
1118 : 0 : want_escape = 1;
1119 : : }
1120 [ # # ]: 0 : else if (c == dialect->escapechar) {
1121 : 0 : want_escape = 1;
1122 : : }
1123 [ # # ]: 0 : if (!want_escape)
1124 : 0 : *quoted = 1;
1125 : : }
1126 [ # # ]: 0 : if (want_escape) {
1127 [ # # ]: 0 : if (dialect->escapechar == NOT_SET) {
1128 : 0 : PyErr_Format(self->error_obj,
1129 : : "need to escape, but no escapechar set");
1130 : 0 : return -1;
1131 : : }
1132 [ # # # # : 0 : ADDCH(dialect->escapechar);
# # ]
1133 : : }
1134 : : }
1135 : : /* Copy field character into record buffer.
1136 : : */
1137 [ # # # # : 0 : ADDCH(c);
# # ]
1138 : : }
1139 : :
1140 [ # # ]: 0 : if (*quoted) {
1141 [ # # ]: 0 : if (copy_phase)
1142 [ # # # # : 0 : ADDCH(dialect->quotechar);
# # ]
1143 : : else {
1144 [ # # # # ]: 0 : INCLEN; /* starting quote */
1145 [ # # # # ]: 0 : INCLEN; /* ending quote */
1146 : : }
1147 : : }
1148 : 0 : return rec_len;
1149 : :
1150 : 0 : overflow:
1151 : 0 : PyErr_NoMemory();
1152 : 0 : return -1;
1153 : : #undef ADDCH
1154 : : #undef INCLEN
1155 : : }
1156 : :
1157 : : static int
1158 : 0 : join_check_rec_size(WriterObj *self, Py_ssize_t rec_len)
1159 : : {
1160 : : assert(rec_len >= 0);
1161 : :
1162 [ # # ]: 0 : if (rec_len > self->rec_size) {
1163 : 0 : size_t rec_size_new = (size_t)(rec_len / MEM_INCR + 1) * MEM_INCR;
1164 : 0 : Py_UCS4 *rec_new = self->rec;
1165 [ # # ]: 0 : PyMem_Resize(rec_new, Py_UCS4, rec_size_new);
1166 [ # # ]: 0 : if (rec_new == NULL) {
1167 : 0 : PyErr_NoMemory();
1168 : 0 : return 0;
1169 : : }
1170 : 0 : self->rec = rec_new;
1171 : 0 : self->rec_size = (Py_ssize_t)rec_size_new;
1172 : : }
1173 : 0 : return 1;
1174 : : }
1175 : :
1176 : : static int
1177 : 0 : join_append(WriterObj *self, PyObject *field, int quoted)
1178 : : {
1179 : 0 : int field_kind = -1;
1180 : 0 : const void *field_data = NULL;
1181 : 0 : Py_ssize_t field_len = 0;
1182 : : Py_ssize_t rec_len;
1183 : :
1184 [ # # ]: 0 : if (field != NULL) {
1185 [ # # ]: 0 : if (PyUnicode_READY(field) == -1)
1186 : 0 : return 0;
1187 : 0 : field_kind = PyUnicode_KIND(field);
1188 : 0 : field_data = PyUnicode_DATA(field);
1189 : 0 : field_len = PyUnicode_GET_LENGTH(field);
1190 : : }
1191 : 0 : rec_len = join_append_data(self, field_kind, field_data, field_len,
1192 : : "ed, 0);
1193 [ # # ]: 0 : if (rec_len < 0)
1194 : 0 : return 0;
1195 : :
1196 : : /* grow record buffer if necessary */
1197 [ # # ]: 0 : if (!join_check_rec_size(self, rec_len))
1198 : 0 : return 0;
1199 : :
1200 : 0 : self->rec_len = join_append_data(self, field_kind, field_data, field_len,
1201 : : "ed, 1);
1202 : 0 : self->num_fields++;
1203 : :
1204 : 0 : return 1;
1205 : : }
1206 : :
1207 : : static int
1208 : 0 : join_append_lineterminator(WriterObj *self)
1209 : : {
1210 : : Py_ssize_t terminator_len, i;
1211 : : int term_kind;
1212 : : const void *term_data;
1213 : :
1214 : 0 : terminator_len = PyUnicode_GET_LENGTH(self->dialect->lineterminator);
1215 [ # # ]: 0 : if (terminator_len == -1)
1216 : 0 : return 0;
1217 : :
1218 : : /* grow record buffer if necessary */
1219 [ # # ]: 0 : if (!join_check_rec_size(self, self->rec_len + terminator_len))
1220 : 0 : return 0;
1221 : :
1222 : 0 : term_kind = PyUnicode_KIND(self->dialect->lineterminator);
1223 : 0 : term_data = PyUnicode_DATA(self->dialect->lineterminator);
1224 [ # # ]: 0 : for (i = 0; i < terminator_len; i++)
1225 : 0 : self->rec[self->rec_len + i] = PyUnicode_READ(term_kind, term_data, i);
1226 : 0 : self->rec_len += terminator_len;
1227 : :
1228 : 0 : return 1;
1229 : : }
1230 : :
1231 : : PyDoc_STRVAR(csv_writerow_doc,
1232 : : "writerow(iterable)\n"
1233 : : "\n"
1234 : : "Construct and write a CSV record from an iterable of fields. Non-string\n"
1235 : : "elements will be converted to string.");
1236 : :
1237 : : static PyObject *
1238 : 0 : csv_writerow(WriterObj *self, PyObject *seq)
1239 : : {
1240 : 0 : DialectObj *dialect = self->dialect;
1241 : : PyObject *iter, *field, *line, *result;
1242 : :
1243 : 0 : iter = PyObject_GetIter(seq);
1244 [ # # ]: 0 : if (iter == NULL) {
1245 [ # # ]: 0 : if (PyErr_ExceptionMatches(PyExc_TypeError)) {
1246 : 0 : PyErr_Format(self->error_obj,
1247 : : "iterable expected, not %.200s",
1248 : 0 : Py_TYPE(seq)->tp_name);
1249 : : }
1250 : 0 : return NULL;
1251 : : }
1252 : :
1253 : : /* Join all fields in internal buffer.
1254 : : */
1255 : 0 : join_reset(self);
1256 [ # # ]: 0 : while ((field = PyIter_Next(iter))) {
1257 : : int append_ok;
1258 : : int quoted;
1259 : :
1260 [ # # # ]: 0 : switch (dialect->quoting) {
1261 : 0 : case QUOTE_NONNUMERIC:
1262 : 0 : quoted = !PyNumber_Check(field);
1263 : 0 : break;
1264 : 0 : case QUOTE_ALL:
1265 : 0 : quoted = 1;
1266 : 0 : break;
1267 : 0 : default:
1268 : 0 : quoted = 0;
1269 : 0 : break;
1270 : : }
1271 : :
1272 [ # # ]: 0 : if (PyUnicode_Check(field)) {
1273 : 0 : append_ok = join_append(self, field, quoted);
1274 : 0 : Py_DECREF(field);
1275 : : }
1276 [ # # ]: 0 : else if (field == Py_None) {
1277 : 0 : append_ok = join_append(self, NULL, quoted);
1278 : 0 : Py_DECREF(field);
1279 : : }
1280 : : else {
1281 : : PyObject *str;
1282 : :
1283 : 0 : str = PyObject_Str(field);
1284 : 0 : Py_DECREF(field);
1285 [ # # ]: 0 : if (str == NULL) {
1286 : 0 : Py_DECREF(iter);
1287 : 0 : return NULL;
1288 : : }
1289 : 0 : append_ok = join_append(self, str, quoted);
1290 : 0 : Py_DECREF(str);
1291 : : }
1292 [ # # ]: 0 : if (!append_ok) {
1293 : 0 : Py_DECREF(iter);
1294 : 0 : return NULL;
1295 : : }
1296 : : }
1297 : 0 : Py_DECREF(iter);
1298 [ # # ]: 0 : if (PyErr_Occurred())
1299 : 0 : return NULL;
1300 : :
1301 [ # # # # ]: 0 : if (self->num_fields > 0 && self->rec_len == 0) {
1302 [ # # ]: 0 : if (dialect->quoting == QUOTE_NONE) {
1303 : 0 : PyErr_Format(self->error_obj,
1304 : : "single empty field record must be quoted");
1305 : 0 : return NULL;
1306 : : }
1307 : 0 : self->num_fields--;
1308 [ # # ]: 0 : if (!join_append(self, NULL, 1))
1309 : 0 : return NULL;
1310 : : }
1311 : :
1312 : : /* Add line terminator.
1313 : : */
1314 [ # # ]: 0 : if (!join_append_lineterminator(self)) {
1315 : 0 : return NULL;
1316 : : }
1317 : :
1318 : 0 : line = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND,
1319 : 0 : (void *) self->rec, self->rec_len);
1320 [ # # ]: 0 : if (line == NULL) {
1321 : 0 : return NULL;
1322 : : }
1323 : 0 : result = PyObject_CallOneArg(self->write, line);
1324 : 0 : Py_DECREF(line);
1325 : 0 : return result;
1326 : : }
1327 : :
1328 : : PyDoc_STRVAR(csv_writerows_doc,
1329 : : "writerows(iterable of iterables)\n"
1330 : : "\n"
1331 : : "Construct and write a series of iterables to a csv file. Non-string\n"
1332 : : "elements will be converted to string.");
1333 : :
1334 : : static PyObject *
1335 : 0 : csv_writerows(WriterObj *self, PyObject *seqseq)
1336 : : {
1337 : : PyObject *row_iter, *row_obj, *result;
1338 : :
1339 : 0 : row_iter = PyObject_GetIter(seqseq);
1340 [ # # ]: 0 : if (row_iter == NULL) {
1341 : 0 : return NULL;
1342 : : }
1343 [ # # ]: 0 : while ((row_obj = PyIter_Next(row_iter))) {
1344 : 0 : result = csv_writerow(self, row_obj);
1345 : 0 : Py_DECREF(row_obj);
1346 [ # # ]: 0 : if (!result) {
1347 : 0 : Py_DECREF(row_iter);
1348 : 0 : return NULL;
1349 : : }
1350 : : else
1351 : 0 : Py_DECREF(result);
1352 : : }
1353 : 0 : Py_DECREF(row_iter);
1354 [ # # ]: 0 : if (PyErr_Occurred())
1355 : 0 : return NULL;
1356 : 0 : Py_RETURN_NONE;
1357 : : }
1358 : :
1359 : : static struct PyMethodDef Writer_methods[] = {
1360 : : { "writerow", (PyCFunction)csv_writerow, METH_O, csv_writerow_doc},
1361 : : { "writerows", (PyCFunction)csv_writerows, METH_O, csv_writerows_doc},
1362 : : { NULL, NULL }
1363 : : };
1364 : :
1365 : : #define W_OFF(x) offsetof(WriterObj, x)
1366 : :
1367 : : static struct PyMemberDef Writer_memberlist[] = {
1368 : : { "dialect", T_OBJECT, W_OFF(dialect), READONLY },
1369 : : { NULL }
1370 : : };
1371 : :
1372 : : static int
1373 : 0 : Writer_traverse(WriterObj *self, visitproc visit, void *arg)
1374 : : {
1375 [ # # # # ]: 0 : Py_VISIT(self->dialect);
1376 [ # # # # ]: 0 : Py_VISIT(self->write);
1377 [ # # # # ]: 0 : Py_VISIT(self->error_obj);
1378 [ # # # # ]: 0 : Py_VISIT(Py_TYPE(self));
1379 : 0 : return 0;
1380 : : }
1381 : :
1382 : : static int
1383 : 0 : Writer_clear(WriterObj *self)
1384 : : {
1385 [ # # ]: 0 : Py_CLEAR(self->dialect);
1386 [ # # ]: 0 : Py_CLEAR(self->write);
1387 [ # # ]: 0 : Py_CLEAR(self->error_obj);
1388 : 0 : return 0;
1389 : : }
1390 : :
1391 : : static void
1392 : 0 : Writer_dealloc(WriterObj *self)
1393 : : {
1394 : 0 : PyTypeObject *tp = Py_TYPE(self);
1395 : 0 : PyObject_GC_UnTrack(self);
1396 : 0 : tp->tp_clear((PyObject *)self);
1397 [ # # ]: 0 : if (self->rec != NULL) {
1398 : 0 : PyMem_Free(self->rec);
1399 : : }
1400 : 0 : PyObject_GC_Del(self);
1401 : 0 : Py_DECREF(tp);
1402 : 0 : }
1403 : :
1404 : : PyDoc_STRVAR(Writer_Type_doc,
1405 : : "CSV writer\n"
1406 : : "\n"
1407 : : "Writer objects are responsible for generating tabular data\n"
1408 : : "in CSV format from sequence input.\n"
1409 : : );
1410 : :
1411 : : static PyType_Slot Writer_Type_slots[] = {
1412 : : {Py_tp_doc, (char*)Writer_Type_doc},
1413 : : {Py_tp_traverse, Writer_traverse},
1414 : : {Py_tp_clear, Writer_clear},
1415 : : {Py_tp_dealloc, Writer_dealloc},
1416 : : {Py_tp_methods, Writer_methods},
1417 : : {Py_tp_members, Writer_memberlist},
1418 : : {0, NULL}
1419 : : };
1420 : :
1421 : : PyType_Spec Writer_Type_spec = {
1422 : : .name = "_csv.writer",
1423 : : .basicsize = sizeof(WriterObj),
1424 : : .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
1425 : : Py_TPFLAGS_IMMUTABLETYPE),
1426 : : .slots = Writer_Type_slots,
1427 : : };
1428 : :
1429 : :
1430 : : static PyObject *
1431 : 0 : csv_writer(PyObject *module, PyObject *args, PyObject *keyword_args)
1432 : : {
1433 : 0 : PyObject * output_file, * dialect = NULL;
1434 : 0 : _csvstate *module_state = get_csv_state(module);
1435 : 0 : WriterObj * self = PyObject_GC_New(WriterObj, module_state->writer_type);
1436 : :
1437 [ # # ]: 0 : if (!self)
1438 : 0 : return NULL;
1439 : :
1440 : 0 : self->dialect = NULL;
1441 : 0 : self->write = NULL;
1442 : :
1443 : 0 : self->rec = NULL;
1444 : 0 : self->rec_size = 0;
1445 : 0 : self->rec_len = 0;
1446 : 0 : self->num_fields = 0;
1447 : :
1448 : 0 : self->error_obj = Py_NewRef(module_state->error_obj);
1449 : :
1450 [ # # ]: 0 : if (!PyArg_UnpackTuple(args, "", 1, 2, &output_file, &dialect)) {
1451 : 0 : Py_DECREF(self);
1452 : 0 : return NULL;
1453 : : }
1454 [ # # ]: 0 : if (_PyObject_LookupAttr(output_file,
1455 : : module_state->str_write,
1456 : : &self->write) < 0) {
1457 : 0 : Py_DECREF(self);
1458 : 0 : return NULL;
1459 : : }
1460 [ # # # # ]: 0 : if (self->write == NULL || !PyCallable_Check(self->write)) {
1461 : 0 : PyErr_SetString(PyExc_TypeError,
1462 : : "argument 1 must have a \"write\" method");
1463 : 0 : Py_DECREF(self);
1464 : 0 : return NULL;
1465 : : }
1466 : 0 : self->dialect = (DialectObj *)_call_dialect(module_state, dialect,
1467 : : keyword_args);
1468 [ # # ]: 0 : if (self->dialect == NULL) {
1469 : 0 : Py_DECREF(self);
1470 : 0 : return NULL;
1471 : : }
1472 : 0 : PyObject_GC_Track(self);
1473 : 0 : return (PyObject *)self;
1474 : : }
1475 : :
1476 : : /*
1477 : : * DIALECT REGISTRY
1478 : : */
1479 : :
1480 : : /*[clinic input]
1481 : : _csv.list_dialects
1482 : :
1483 : : Return a list of all known dialect names.
1484 : :
1485 : : names = csv.list_dialects()
1486 : : [clinic start generated code]*/
1487 : :
1488 : : static PyObject *
1489 : 0 : _csv_list_dialects_impl(PyObject *module)
1490 : : /*[clinic end generated code: output=a5b92b215b006a6d input=8953943eb17d98ab]*/
1491 : : {
1492 : 0 : return PyDict_Keys(get_csv_state(module)->dialects);
1493 : : }
1494 : :
1495 : : static PyObject *
1496 : 0 : csv_register_dialect(PyObject *module, PyObject *args, PyObject *kwargs)
1497 : : {
1498 : 0 : PyObject *name_obj, *dialect_obj = NULL;
1499 : 0 : _csvstate *module_state = get_csv_state(module);
1500 : : PyObject *dialect;
1501 : :
1502 [ # # ]: 0 : if (!PyArg_UnpackTuple(args, "", 1, 2, &name_obj, &dialect_obj))
1503 : 0 : return NULL;
1504 [ # # ]: 0 : if (!PyUnicode_Check(name_obj)) {
1505 : 0 : PyErr_SetString(PyExc_TypeError,
1506 : : "dialect name must be a string");
1507 : 0 : return NULL;
1508 : : }
1509 [ # # ]: 0 : if (PyUnicode_READY(name_obj) == -1)
1510 : 0 : return NULL;
1511 : 0 : dialect = _call_dialect(module_state, dialect_obj, kwargs);
1512 [ # # ]: 0 : if (dialect == NULL)
1513 : 0 : return NULL;
1514 [ # # ]: 0 : if (PyDict_SetItem(module_state->dialects, name_obj, dialect) < 0) {
1515 : 0 : Py_DECREF(dialect);
1516 : 0 : return NULL;
1517 : : }
1518 : 0 : Py_DECREF(dialect);
1519 : 0 : Py_RETURN_NONE;
1520 : : }
1521 : :
1522 : :
1523 : : /*[clinic input]
1524 : : _csv.unregister_dialect
1525 : :
1526 : : name: object
1527 : :
1528 : : Delete the name/dialect mapping associated with a string name.
1529 : :
1530 : : csv.unregister_dialect(name)
1531 : : [clinic start generated code]*/
1532 : :
1533 : : static PyObject *
1534 : 0 : _csv_unregister_dialect_impl(PyObject *module, PyObject *name)
1535 : : /*[clinic end generated code: output=0813ebca6c058df4 input=6b5c1557bf60c7e7]*/
1536 : : {
1537 : 0 : _csvstate *module_state = get_csv_state(module);
1538 [ # # ]: 0 : if (PyDict_DelItem(module_state->dialects, name) < 0) {
1539 [ # # ]: 0 : if (PyErr_ExceptionMatches(PyExc_KeyError)) {
1540 : 0 : PyErr_Format(module_state->error_obj, "unknown dialect");
1541 : : }
1542 : 0 : return NULL;
1543 : : }
1544 : 0 : Py_RETURN_NONE;
1545 : : }
1546 : :
1547 : : /*[clinic input]
1548 : : _csv.get_dialect
1549 : :
1550 : : name: object
1551 : :
1552 : : Return the dialect instance associated with name.
1553 : :
1554 : : dialect = csv.get_dialect(name)
1555 : : [clinic start generated code]*/
1556 : :
1557 : : static PyObject *
1558 : 0 : _csv_get_dialect_impl(PyObject *module, PyObject *name)
1559 : : /*[clinic end generated code: output=aa988cd573bebebb input=edf9ddab32e448fb]*/
1560 : : {
1561 : 0 : return get_dialect_from_registry(name, get_csv_state(module));
1562 : : }
1563 : :
1564 : : /*[clinic input]
1565 : : _csv.field_size_limit
1566 : :
1567 : : new_limit: object = NULL
1568 : :
1569 : : Sets an upper limit on parsed fields.
1570 : :
1571 : : csv.field_size_limit([limit])
1572 : :
1573 : : Returns old limit. If limit is not given, no new limit is set and
1574 : : the old limit is returned
1575 : : [clinic start generated code]*/
1576 : :
1577 : : static PyObject *
1578 : 0 : _csv_field_size_limit_impl(PyObject *module, PyObject *new_limit)
1579 : : /*[clinic end generated code: output=f2799ecd908e250b input=cec70e9226406435]*/
1580 : : {
1581 : 0 : _csvstate *module_state = get_csv_state(module);
1582 : 0 : long old_limit = module_state->field_limit;
1583 [ # # ]: 0 : if (new_limit != NULL) {
1584 [ # # ]: 0 : if (!PyLong_CheckExact(new_limit)) {
1585 : 0 : PyErr_Format(PyExc_TypeError,
1586 : : "limit must be an integer");
1587 : 0 : return NULL;
1588 : : }
1589 : 0 : module_state->field_limit = PyLong_AsLong(new_limit);
1590 [ # # # # ]: 0 : if (module_state->field_limit == -1 && PyErr_Occurred()) {
1591 : 0 : module_state->field_limit = old_limit;
1592 : 0 : return NULL;
1593 : : }
1594 : : }
1595 : 0 : return PyLong_FromLong(old_limit);
1596 : : }
1597 : :
1598 : : static PyType_Slot error_slots[] = {
1599 : : {0, NULL},
1600 : : };
1601 : :
1602 : : PyType_Spec error_spec = {
1603 : : .name = "_csv.Error",
1604 : : .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
1605 : : .slots = error_slots,
1606 : : };
1607 : :
1608 : : /*
1609 : : * MODULE
1610 : : */
1611 : :
1612 : : PyDoc_STRVAR(csv_module_doc,
1613 : : "CSV parsing and writing.\n"
1614 : : "\n"
1615 : : "This module provides classes that assist in the reading and writing\n"
1616 : : "of Comma Separated Value (CSV) files, and implements the interface\n"
1617 : : "described by PEP 305. Although many CSV files are simple to parse,\n"
1618 : : "the format is not formally defined by a stable specification and\n"
1619 : : "is subtle enough that parsing lines of a CSV file with something\n"
1620 : : "like line.split(\",\") is bound to fail. The module supports three\n"
1621 : : "basic APIs: reading, writing, and registration of dialects.\n"
1622 : : "\n"
1623 : : "\n"
1624 : : "DIALECT REGISTRATION:\n"
1625 : : "\n"
1626 : : "Readers and writers support a dialect argument, which is a convenient\n"
1627 : : "handle on a group of settings. When the dialect argument is a string,\n"
1628 : : "it identifies one of the dialects previously registered with the module.\n"
1629 : : "If it is a class or instance, the attributes of the argument are used as\n"
1630 : : "the settings for the reader or writer:\n"
1631 : : "\n"
1632 : : " class excel:\n"
1633 : : " delimiter = ','\n"
1634 : : " quotechar = '\"'\n"
1635 : : " escapechar = None\n"
1636 : : " doublequote = True\n"
1637 : : " skipinitialspace = False\n"
1638 : : " lineterminator = '\\r\\n'\n"
1639 : : " quoting = QUOTE_MINIMAL\n"
1640 : : "\n"
1641 : : "SETTINGS:\n"
1642 : : "\n"
1643 : : " * quotechar - specifies a one-character string to use as the\n"
1644 : : " quoting character. It defaults to '\"'.\n"
1645 : : " * delimiter - specifies a one-character string to use as the\n"
1646 : : " field separator. It defaults to ','.\n"
1647 : : " * skipinitialspace - specifies how to interpret spaces which\n"
1648 : : " immediately follow a delimiter. It defaults to False, which\n"
1649 : : " means that spaces immediately following a delimiter is part\n"
1650 : : " of the following field.\n"
1651 : : " * lineterminator - specifies the character sequence which should\n"
1652 : : " terminate rows.\n"
1653 : : " * quoting - controls when quotes should be generated by the writer.\n"
1654 : : " It can take on any of the following module constants:\n"
1655 : : "\n"
1656 : : " csv.QUOTE_MINIMAL means only when required, for example, when a\n"
1657 : : " field contains either the quotechar or the delimiter\n"
1658 : : " csv.QUOTE_ALL means that quotes are always placed around fields.\n"
1659 : : " csv.QUOTE_NONNUMERIC means that quotes are always placed around\n"
1660 : : " fields which do not parse as integers or floating point\n"
1661 : : " numbers.\n"
1662 : : " csv.QUOTE_NONE means that quotes are never placed around fields.\n"
1663 : : " * escapechar - specifies a one-character string used to escape\n"
1664 : : " the delimiter when quoting is set to QUOTE_NONE.\n"
1665 : : " * doublequote - controls the handling of quotes inside fields. When\n"
1666 : : " True, two consecutive quotes are interpreted as one during read,\n"
1667 : : " and when writing, each quote character embedded in the data is\n"
1668 : : " written as two quotes\n");
1669 : :
1670 : : PyDoc_STRVAR(csv_reader_doc,
1671 : : " csv_reader = reader(iterable [, dialect='excel']\n"
1672 : : " [optional keyword args])\n"
1673 : : " for row in csv_reader:\n"
1674 : : " process(row)\n"
1675 : : "\n"
1676 : : "The \"iterable\" argument can be any object that returns a line\n"
1677 : : "of input for each iteration, such as a file object or a list. The\n"
1678 : : "optional \"dialect\" parameter is discussed below. The function\n"
1679 : : "also accepts optional keyword arguments which override settings\n"
1680 : : "provided by the dialect.\n"
1681 : : "\n"
1682 : : "The returned object is an iterator. Each iteration returns a row\n"
1683 : : "of the CSV file (which can span multiple input lines).\n");
1684 : :
1685 : : PyDoc_STRVAR(csv_writer_doc,
1686 : : " csv_writer = csv.writer(fileobj [, dialect='excel']\n"
1687 : : " [optional keyword args])\n"
1688 : : " for row in sequence:\n"
1689 : : " csv_writer.writerow(row)\n"
1690 : : "\n"
1691 : : " [or]\n"
1692 : : "\n"
1693 : : " csv_writer = csv.writer(fileobj [, dialect='excel']\n"
1694 : : " [optional keyword args])\n"
1695 : : " csv_writer.writerows(rows)\n"
1696 : : "\n"
1697 : : "The \"fileobj\" argument can be any object that supports the file API.\n");
1698 : :
1699 : : PyDoc_STRVAR(csv_register_dialect_doc,
1700 : : "Create a mapping from a string name to a dialect class.\n"
1701 : : " dialect = csv.register_dialect(name[, dialect[, **fmtparams]])");
1702 : :
1703 : : static struct PyMethodDef csv_methods[] = {
1704 : : { "reader", _PyCFunction_CAST(csv_reader),
1705 : : METH_VARARGS | METH_KEYWORDS, csv_reader_doc},
1706 : : { "writer", _PyCFunction_CAST(csv_writer),
1707 : : METH_VARARGS | METH_KEYWORDS, csv_writer_doc},
1708 : : { "register_dialect", _PyCFunction_CAST(csv_register_dialect),
1709 : : METH_VARARGS | METH_KEYWORDS, csv_register_dialect_doc},
1710 : : _CSV_LIST_DIALECTS_METHODDEF
1711 : : _CSV_UNREGISTER_DIALECT_METHODDEF
1712 : : _CSV_GET_DIALECT_METHODDEF
1713 : : _CSV_FIELD_SIZE_LIMIT_METHODDEF
1714 : : { NULL, NULL }
1715 : : };
1716 : :
1717 : : static int
1718 : 1 : csv_exec(PyObject *module) {
1719 : : const StyleDesc *style;
1720 : : PyObject *temp;
1721 : 1 : _csvstate *module_state = get_csv_state(module);
1722 : :
1723 : 1 : temp = PyType_FromModuleAndSpec(module, &Dialect_Type_spec, NULL);
1724 : 1 : module_state->dialect_type = (PyTypeObject *)temp;
1725 [ - + ]: 1 : if (PyModule_AddObjectRef(module, "Dialect", temp) < 0) {
1726 : 0 : return -1;
1727 : : }
1728 : :
1729 : 1 : temp = PyType_FromModuleAndSpec(module, &Reader_Type_spec, NULL);
1730 : 1 : module_state->reader_type = (PyTypeObject *)temp;
1731 [ - + ]: 1 : if (PyModule_AddObjectRef(module, "Reader", temp) < 0) {
1732 : 0 : return -1;
1733 : : }
1734 : :
1735 : 1 : temp = PyType_FromModuleAndSpec(module, &Writer_Type_spec, NULL);
1736 : 1 : module_state->writer_type = (PyTypeObject *)temp;
1737 [ - + ]: 1 : if (PyModule_AddObjectRef(module, "Writer", temp) < 0) {
1738 : 0 : return -1;
1739 : : }
1740 : :
1741 : : /* Add version to the module. */
1742 [ - + ]: 1 : if (PyModule_AddStringConstant(module, "__version__",
1743 : : MODULE_VERSION) == -1) {
1744 : 0 : return -1;
1745 : : }
1746 : :
1747 : : /* Set the field limit */
1748 : 1 : module_state->field_limit = 128 * 1024;
1749 : :
1750 : : /* Add _dialects dictionary */
1751 : 1 : module_state->dialects = PyDict_New();
1752 [ - + ]: 1 : if (PyModule_AddObjectRef(module, "_dialects", module_state->dialects) < 0) {
1753 : 0 : return -1;
1754 : : }
1755 : :
1756 : : /* Add quote styles into dictionary */
1757 [ + + ]: 5 : for (style = quote_styles; style->name; style++) {
1758 [ - + ]: 4 : if (PyModule_AddIntConstant(module, style->name,
1759 : 4 : style->style) == -1)
1760 : 0 : return -1;
1761 : : }
1762 : :
1763 : : /* Add the CSV exception object to the module. */
1764 : 1 : PyObject *bases = PyTuple_Pack(1, PyExc_Exception);
1765 [ - + ]: 1 : if (bases == NULL) {
1766 : 0 : return -1;
1767 : : }
1768 : 1 : module_state->error_obj = PyType_FromModuleAndSpec(module, &error_spec,
1769 : : bases);
1770 : 1 : Py_DECREF(bases);
1771 [ - + ]: 1 : if (module_state->error_obj == NULL) {
1772 : 0 : return -1;
1773 : : }
1774 [ - + ]: 1 : if (PyModule_AddType(module, (PyTypeObject *)module_state->error_obj) != 0) {
1775 : 0 : return -1;
1776 : : }
1777 : :
1778 : 1 : module_state->str_write = PyUnicode_InternFromString("write");
1779 [ - + ]: 1 : if (module_state->str_write == NULL) {
1780 : 0 : return -1;
1781 : : }
1782 : 1 : return 0;
1783 : : }
1784 : :
1785 : : static PyModuleDef_Slot csv_slots[] = {
1786 : : {Py_mod_exec, csv_exec},
1787 : : {0, NULL}
1788 : : };
1789 : :
1790 : : static struct PyModuleDef _csvmodule = {
1791 : : PyModuleDef_HEAD_INIT,
1792 : : "_csv",
1793 : : csv_module_doc,
1794 : : sizeof(_csvstate),
1795 : : csv_methods,
1796 : : csv_slots,
1797 : : _csv_traverse,
1798 : : _csv_clear,
1799 : : _csv_free
1800 : : };
1801 : :
1802 : : PyMODINIT_FUNC
1803 : 1 : PyInit__csv(void)
1804 : : {
1805 : 1 : return PyModuleDef_Init(&_csvmodule);
1806 : : }
|