LCOV - code coverage report
Current view: top level - Modules - _csv.c (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit acb105a7c1f] Lines: 678 757 89.6 %
Date: 2022-07-20 13:12:14 Functions: 50 52 96.2 %
Branches: 482 635 75.9 %

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

Generated by: LCOV version 1.14