| 141 | } |
| 142 | |
| 143 | int csv_fini(struct csv_parser *p, void (*cb1)(void *, size_t, void *), |
| 144 | void (*cb2)(int c, void *), void *data) { |
| 145 | /* Finalize parsing. Needed, for example, when file does not end in a newline |
| 146 | */ |
| 147 | int quoted = p->quoted; |
| 148 | int pstate = p->pstate; |
| 149 | size_t spaces = p->spaces; |
| 150 | size_t entry_pos = p->entry_pos; |
| 151 | |
| 152 | if (p == NULL) return -1; |
| 153 | |
| 154 | if (p->pstate == FIELD_BEGUN && p->quoted && p->options & CSV_STRICT && |
| 155 | p->options & CSV_STRICT_FINI) { |
| 156 | /* Current field is quoted, no end-quote was seen, and CSV_STRICT_FINI is |
| 157 | * set */ |
| 158 | p->status = CSV_EPARSE; |
| 159 | return -1; |
| 160 | } |
| 161 | |
| 162 | switch (p->pstate) { |
| 163 | case FIELD_MIGHT_HAVE_ENDED: |
| 164 | p->entry_pos -= p->spaces + 1; /* get rid of spaces and original quote */ |
| 165 | /* Fall-through */ |
| 166 | case FIELD_NOT_BEGUN: |
| 167 | case FIELD_BEGUN: |
| 168 | quoted = p->quoted, pstate = p->pstate; |
| 169 | spaces = p->spaces, entry_pos = p->entry_pos; |
| 170 | SUBMIT_FIELD(p); |
| 171 | SUBMIT_ROW(p, -1); |
| 172 | case ROW_NOT_BEGUN: /* Already ended properly */ |
| 173 | ; |
| 174 | } |
| 175 | |
| 176 | /* Reset parser */ |
| 177 | p->spaces = p->quoted = p->entry_pos = p->status = 0; |
| 178 | p->pstate = ROW_NOT_BEGUN; |
| 179 | |
| 180 | return 0; |
| 181 | } |
| 182 | |
| 183 | void csv_set_delim(struct csv_parser *p, unsigned char c) { |
| 184 | /* Set the delimiter */ |