LCOV - code coverage report
Current view: | top level - Modules - _csv.c (source / functions) |  |  | Hit | Total | Coverage
Test: | CPython 3.12 LCOV report [commit 5e6661bce9] |  | Lines: | 52 | 757 | 6.9 %
Date: | 2023-03-20 08:15:36 |  | Functions: | 6 | 52 | 11.5 %
|  |  | Branches: | 34 | 635 | 5.4 %

               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                 :            :                                      &quotechar,
         417                 :            :                                      &quoting,
         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                 :            :                                &quoted, 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                 :            :                                      &quoted, 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                 :            : }

Generated by: LCOV version 1.14