File Coverage

CSV_XS.xs
Criterion Covered Total %
statement 1088 1120 97.1
branch 1556 2792 55.7
condition n/a
subroutine n/a
pod n/a
total 2644 3912 67.5


line stmt bran cond sub pod time code
1             /* Copyright (c) 2007-2026 H.Merijn Brand. All rights reserved.
2             * Copyright (c) 1998-2001 Jochen Wiedmann. All rights reserved.
3             * This program is free software; you can redistribute it and/or
4             * modify it under the same terms as Perl itself.
5             */
6             #define PERL_NO_GET_CONTEXT
7             #include
8             #include
9             #include
10             #define DPPP_PL_parser_NO_DUMMY
11             #define NEED_utf8_to_uvchr_buf
12             #define NEED_my_snprintf
13             #define NEED_pv_escape
14             #define NEED_pv_pretty
15             #ifndef PERLIO_F_UTF8
16             # define PERLIO_F_UTF8 0x00008000
17             # endif
18             #ifndef MAXINT
19             # define MAXINT ((int)(~(unsigned)0 >> 1))
20             # endif
21             #include "ppport.h"
22             #define is_utf8_sv(s) is_utf8_string ((U8 *)SvPV_nolen (s), SvCUR (s))
23              
24             #define MAINT_DEBUG 0
25             #define MAINT_DEBUG_EOL 0
26              
27             #define BUFFER_SIZE 1024
28              
29             #define CSV_XS_TYPE_WARN 1
30             #define CSV_XS_TYPE_PV 0
31             #define CSV_XS_TYPE_IV 1
32             #define CSV_XS_TYPE_NV 2
33              
34             /* maximum length for EOL, SEP, and QUOTE - keep in sync with .pm */
35             #define MAX_ATTR_LEN 16
36              
37             #define CSV_FLAGS_QUO 0x0001
38             #define CSV_FLAGS_BIN 0x0002
39             #define CSV_FLAGS_EIF 0x0004
40             #define CSV_FLAGS_MIS 0x0010
41              
42             #define HOOK_ERROR 0x0001
43             #define HOOK_AFTER_PARSE 0x0002
44             #define HOOK_BEFORE_PRINT 0x0004
45              
46             #ifdef __THW_370__
47             /* EBCDIC on os390 z/OS: IS_EBCDIC reads better than __THW_370__ */
48             #define IS_EBCDIC
49             #endif
50              
51             #define CH_TAB '\t'
52             #define CH_NL '\n'
53             #define CH_CR '\r'
54             #define CH_SPACE ' '
55             #define CH_QUO '"'
56              
57             #ifdef IS_EBCDIC
58             #define CH_DEL '\007'
59             static unsigned char ec, ebcdic2ascii[256] = {
60             0x00, 0x01, 0x02, 0x03, 0x9c, 0x09, 0x86, 0x7f,
61             0x97, 0x8d, 0x8e, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
62             0x10, 0x11, 0x12, 0x13, 0x9d, 0x0a, 0x08, 0x87,
63             0x18, 0x19, 0x92, 0x8f, 0x1c, 0x1d, 0x1e, 0x1f,
64             0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x17, 0x1b,
65             0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x05, 0x06, 0x07,
66             0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
67             0x98, 0x99, 0x9a, 0x9b, 0x14, 0x15, 0x9e, 0x1a,
68             0x20, 0xa0, 0xe2, 0xe4, 0xe0, 0xe1, 0xe3, 0xe5,
69             0xe7, 0xf1, 0xa2, 0x2e, 0x3c, 0x28, 0x2b, 0x7c,
70             0x26, 0xe9, 0xea, 0xeb, 0xe8, 0xed, 0xee, 0xef,
71             0xec, 0xdf, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x5e,
72             0x2d, 0x2f, 0xc2, 0xc4, 0xc0, 0xc1, 0xc3, 0xc5,
73             0xc7, 0xd1, 0xa6, 0x2c, 0x25, 0x5f, 0x3e, 0x3f,
74             0xf8, 0xc9, 0xca, 0xcb, 0xc8, 0xcd, 0xce, 0xcf,
75             0xcc, 0x60, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22,
76             0xd8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
77             0x68, 0x69, 0xab, 0xbb, 0xf0, 0xfd, 0xfe, 0xb1,
78             0xb0, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
79             0x71, 0x72, 0xaa, 0xba, 0xe6, 0xb8, 0xc6, 0xa4,
80             0xb5, 0x7e, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
81             0x79, 0x7a, 0xa1, 0xbf, 0xd0, 0x5b, 0xde, 0xae,
82             0xac, 0xa3, 0xa5, 0xb7, 0xa9, 0xa7, 0xb6, 0xbc,
83             0xbd, 0xbe, 0xdd, 0xa8, 0xaf, 0x5d, 0xb4, 0xd7,
84             0x7b, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
85             /* v this 0xa0 really should be 0xad. Needed for UTF = binary */
86             0x48, 0x49, 0xa0, 0xf4, 0xf6, 0xf2, 0xf3, 0xf5,
87             0x7d, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
88             0x51, 0x52, 0xb9, 0xfb, 0xfc, 0xf9, 0xfa, 0xff,
89             0x5c, 0xf7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
90             0x59, 0x5a, 0xb2, 0xd4, 0xd6, 0xd2, 0xd3, 0xd5,
91             0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
92             0x38, 0x39, 0xb3, 0xdb, 0xdc, 0xd9, 0xda, 0x9f
93             };
94             #define is_csv_binary(ch) ((((ec = ebcdic2ascii[ch]) < 0x20 || ec >= 0x7f) && ch != CH_TAB) || ch == EOF)
95             #else
96             #define CH_DEL '\177'
97             #define is_csv_binary(ch) ((ch < CH_SPACE || ch >= CH_DEL) && ch != CH_TAB)
98             #endif
99             #define CH_EOLX 1215
100             #define CH_EOL *csv->eol
101             #define CH_SEPX 8888
102             #define CH_SEP *csv->sep
103             #define CH_QUOTEX 8889
104             #define CH_QUOTE *csv->quo
105              
106             #define useIO_EOF 0x10
107              
108             #define unless(expr) if (!(expr))
109              
110             #define _is_reftype(f,x) \
111             (f && ((SvGMAGICAL (f) && mg_get (f)) || 1) && SvROK (f) && SvTYPE (SvRV (f)) == x)
112             #define _is_arrayref(f) _is_reftype (f, SVt_PVAV)
113             #define _is_hashref(f) _is_reftype (f, SVt_PVHV)
114             #define _is_coderef(f) _is_reftype (f, SVt_PVCV)
115              
116             #define SvSetUndef(sv) sv_setpvn (sv, NULL, 0)
117             #define SvSetEmpty(sv) sv_setpvn_mg (sv, "", 0)
118              
119             #define CSV_XS_SELF \
120             if (!self || !SvOK (self) || !SvROK (self) || \
121             SvTYPE (SvRV (self)) != SVt_PVHV) \
122             croak ("self is not a hash ref"); \
123             hv = (HV *)SvRV (self)
124              
125             #define undef &PL_sv_undef
126             #define PUT_RETURN(x) \
127             SPAGAIN; \
128             ST (0) = x; \
129             XSRETURN (1)
130              
131             /* Keep in sync with .pm! */
132             #define CACHE_ID_quote_char 0
133             #define CACHE_ID_escape_char 1
134             #define CACHE_ID_sep_char 2
135             #define CACHE_ID_always_quote 4
136             #define CACHE_ID_quote_empty 5
137             #define CACHE_ID_quote_space 6
138             #define CACHE_ID_quote_binary 7
139             #define CACHE_ID_allow_loose_quotes 8
140             #define CACHE_ID_allow_loose_escapes 9
141             #define CACHE_ID_allow_unquoted_escape 10
142             #define CACHE_ID_allow_whitespace 11
143             #define CACHE_ID_blank_is_undef 12
144             #define CACHE_ID_empty_is_undef 13
145             #define CACHE_ID_auto_diag 14
146             #define CACHE_ID_diag_verbose 15
147             #define CACHE_ID_escape_null 16
148             #define CACHE_ID_formula 18
149             #define CACHE_ID_has_error_input 20
150             #define CACHE_ID_decode_utf8 21
151             #define CACHE_ID_verbatim 23
152             #define CACHE_ID_strict_eol 24
153             #define CACHE_ID_eol_is_cr 26
154             #define CACHE_ID_eol_type 27
155             #define CACHE_ID_strict 28
156             #define CACHE_ID_skip_empty_rows 29
157             #define CACHE_ID_binary 30
158             #define CACHE_ID_keep_meta_info 31
159             #define CACHE_ID__has_hooks 32
160             #define CACHE_ID__has_ahead 33
161             #define CACHE_ID_eol_len 36
162             #define CACHE_ID_sep_len 37
163             #define CACHE_ID_quo_len 38
164             #define CACHE_ID__is_bound 44
165             #define CACHE_ID_types 92
166             #define CACHE_ID_eol 100
167             #define CACHE_ID_sep 116
168             #define CACHE_ID_quo 132
169             #define CACHE_ID_undef_str 148
170             #define CACHE_ID_comment_str 156
171              
172             #define EOL_TYPE_UNDEF 0
173             #define EOL_TYPE_NL 1
174             #define EOL_TYPE_CR 2
175             #define EOL_TYPE_CRNL 3
176             #define EOL_TYPE_OTHER 4
177             #define EOL_TYPE(c) ((((char)c) == CH_NL) ? EOL_TYPE_NL : (((char)c) == CH_CR) ? EOL_TYPE_CR : EOL_TYPE_OTHER)
178             #define SET_EOL_TYPE(c,t) { \
179             unless (c->eol_type) { \
180             c->eol_type = t; \
181             c->cache[CACHE_ID_eol_type] = t;\
182             } \
183             }
184              
185             #define byte unsigned char
186             #define ulng unsigned long
187             typedef struct {
188             byte quote_char; /* 0 */
189             byte escape_char; /* 1 */
190             byte _sep_char; /* 2 : reserved for sep_char */
191             byte fld_idx; /* 3 */
192              
193             byte always_quote; /* 4 */
194             byte quote_empty; /* 5 */
195             byte quote_space; /* 6 */
196             byte quote_binary; /* 7 */
197              
198             byte allow_loose_quotes; /* 8 */
199             byte allow_loose_escapes; /* 9 */
200             byte allow_unquoted_escape; /* 10 */
201             byte allow_whitespace; /* 11 */
202              
203             byte blank_is_undef; /* 12 */
204             byte empty_is_undef; /* 13 */
205             byte auto_diag; /* 14 */
206             byte diag_verbose; /* 15 */
207              
208             byte escape_null; /* 16 */
209             byte first_safe_char; /* 17 */
210             byte formula; /* 18 */
211             byte utf8; /* 19 */
212              
213             byte has_error_input; /* 20 */
214             byte decode_utf8; /* 21 */
215             byte useIO; /* 22: Also used to indicate EOF */
216             byte verbatim; /* 23 */
217              
218             byte strict_eol; /* 24 */
219             byte eolx; /* 25 */
220             byte eol_is_cr; /* 26 */
221             byte eol_type; /* 27 */
222              
223             byte strict; /* 28 */
224             byte skip_empty_rows; /* 29 */
225             byte binary; /* 30 */
226             byte keep_meta_info; /* 31 */
227              
228             byte has_hooks; /* 32 */
229             byte has_ahead; /* 33 */
230             byte nyi_1; /* 34 : free */
231             byte nyi_2; /* 35 : free */
232              
233             byte eol_len; /* 36 */
234             byte sep_len; /* 37 */
235             byte quo_len; /* 38 */
236             byte types_len; /* 39 */
237              
238             short strict_n; /* 40.. */
239             long is_bound; /* 44.. */
240             ulng recno; /* 52.. */
241             byte * cache; /* 60.. */
242             SV * pself; /* 68.. PL_self, for error_diag */
243             HV * self; /* 76.. */
244             SV * bound; /* 84.. */
245             char * types; /* 92.. */
246              
247             byte eol[MAX_ATTR_LEN]; /* 100..115 */
248             byte sep[MAX_ATTR_LEN]; /* 116..131 */
249             byte quo[MAX_ATTR_LEN]; /* 132..147 */
250              
251             byte * undef_str; /* 148.. */
252             byte * comment_str; /* 156.. */
253              
254             char * bptr;
255             SV * tmp;
256             int eol_pos;
257             STRLEN size;
258             STRLEN used;
259             byte undef_flg;
260             char buffer[BUFFER_SIZE];
261             /* Likely 1240 bytes */
262             } csv_t;
263              
264             #define bool_opt_def(o,d) \
265             (((svp = hv_fetchs (self, o, FALSE)) && *svp) ? SvTRUE (*svp) : d)
266             #define bool_opt(o) bool_opt_def (o, 0)
267             #define num_opt_def(o,d) \
268             (((svp = hv_fetchs (self, o, FALSE)) && *svp) ? SvIV (*svp) : d)
269             #define num_opt(o) num_opt_def (o, 0)
270              
271             typedef struct {
272             int xs_errno;
273             const char *xs_errstr;
274             } xs_error_t;
275             static const xs_error_t xs_errors[] = {
276              
277             /* Generic errors */
278             { 1000, "INI - constructor failed" },
279             { 1001, "INI - sep_char is equal to quote_char or escape_char" },
280             { 1002, "INI - allow_whitespace with escape_char or quote_char SP or TAB" },
281             { 1003, "INI - \\r or \\n in main attr not allowed" },
282             { 1004, "INI - callbacks should be undef or a hashref" },
283             { 1005, "INI - EOL too long" },
284             { 1006, "INI - SEP too long" },
285             { 1007, "INI - QUOTE too long" },
286             { 1008, "INI - SEP undefined" },
287              
288             { 1010, "INI - the header is empty" },
289             { 1011, "INI - the header contains more than one valid separator" },
290             { 1012, "INI - the header contains an empty field" },
291             { 1013, "INI - the header contains non-unique fields" },
292             { 1014, "INI - header called on undefined stream" },
293              
294             /* Syntax errors */
295             { 1500, "PRM - Invalid/unsupported argument(s)" },
296             { 1501, "PRM - The key attribute is passed as an unsupported type" },
297             { 1502, "PRM - The value attribute is passed without the key attribute" },
298             { 1503, "PRM - The value attribute is passed as an unsupported type" },
299              
300             /* Parse errors */
301             { 2010, "ECR - QUO char inside quotes followed by CR not part of EOL" },
302             { 2011, "ECR - Characters after end of quoted field" },
303             { 2012, "EOF - End of data in parsing input stream" },
304             { 2013, "ESP - Specification error for fragments RFC7111" },
305             { 2014, "ENF - Inconsistent number of fields" },
306             { 2015, "ERW - Empty row" },
307             { 2016, "EOL - Inconsistent EOL" },
308              
309             /* EIQ - Error Inside Quotes */
310             { 2021, "EIQ - NL char inside quotes, binary off" },
311             { 2022, "EIQ - CR char inside quotes, binary off" },
312             { 2023, "EIQ - QUO character not allowed" },
313             { 2024, "EIQ - EOF cannot be escaped, not even inside quotes" },
314             { 2025, "EIQ - Loose unescaped escape" },
315             { 2026, "EIQ - Binary character inside quoted field, binary off" },
316             { 2027, "EIQ - Quoted field not terminated" },
317              
318             /* EIF - Error Inside Field */
319             { 2030, "EIF - NL char inside unquoted verbatim, binary off" },
320             { 2031, "EIF - CR char is first char of field, not part of EOL" },
321             { 2032, "EIF - CR char inside unquoted, not part of EOL" },
322             { 2034, "EIF - Loose unescaped quote" },
323             { 2035, "EIF - Escaped EOF in unquoted field" },
324             { 2036, "EIF - ESC error" },
325             { 2037, "EIF - Binary character in unquoted field, binary off" },
326              
327             /* Combine errors */
328             { 2110, "ECB - Binary character in Combine, binary off" },
329              
330             /* IO errors */
331             { 2200, "EIO - print to IO failed. See errno" },
332              
333             /* Hash-Ref errors */
334             { 3001, "EHR - Unsupported syntax for column_names ()" },
335             { 3002, "EHR - getline_hr () called before column_names ()" },
336             { 3003, "EHR - bind_columns () and column_names () fields count mismatch" },
337             { 3004, "EHR - bind_columns () only accepts refs to scalars" },
338             { 3006, "EHR - bind_columns () did not pass enough refs for parsed fields" },
339             { 3007, "EHR - bind_columns needs refs to writable scalars" },
340             { 3008, "EHR - unexpected error in bound fields" },
341             { 3009, "EHR - print_hr () called before column_names ()" },
342             { 3010, "EHR - print_hr () called with invalid arguments" },
343              
344             { 4001, "PRM - The key does not exist as field in the data" },
345              
346             { 5001, "PRM - The result does not match the output to append to" },
347             { 5002, "PRM - Unsupported output" },
348              
349             { 0, "" },
350             };
351              
352             static int last_error = 0;
353             static SV *m_getline, *m_print;
354              
355             #define is_EOL(c) (c == CH_EOLX)
356              
357             #define __is_SEPX(c) (c == CH_SEP && (csv->sep_len == 0 || (\
358             csv->size - csv->used >= (STRLEN)csv->sep_len - 1 &&\
359             !memcmp (csv->bptr + csv->used, csv->sep + 1, csv->sep_len - 1) &&\
360             (csv->used += csv->sep_len - 1) &&\
361             (c = CH_SEPX))))
362             #if MAINT_DEBUG > 1
363             static byte _is_SEPX (unsigned int c, csv_t *csv, int line) {
364             unsigned int b = __is_SEPX (c);
365             (void)fprintf (stderr, "# %4d - is_SEPX:\t%d (%d)\n", line, b, csv->sep_len);
366             if (csv->sep_len)
367             (void)fprintf (stderr,
368             "# len: %d, siz: %d, usd: %d, c: %03x, *sep: %03x\n",
369             csv->sep_len, csv->size, csv->used, c, CH_SEP);
370             return b;
371             } /* _is_SEPX */
372             #define is_SEP(c) _is_SEPX (c, csv, __LINE__)
373             #else
374             #define is_SEP(c) __is_SEPX (c)
375             #endif
376              
377             #define __is_QUOTEX(c) (CH_QUOTE && c == CH_QUOTE && (csv->quo_len == 0 || (\
378             csv->size - csv->used >= (STRLEN)csv->quo_len - 1 &&\
379             !memcmp (csv->bptr + csv->used, csv->quo + 1, csv->quo_len - 1) &&\
380             (csv->used += csv->quo_len - 1) &&\
381             (c = CH_QUOTEX))))
382             #if MAINT_DEBUG > 1
383             static byte _is_QUOTEX (unsigned int c, csv_t *csv, int line) {
384             unsigned int b = __is_QUOTEX (c);
385             (void)fprintf (stderr, "# %4d - is_QUOTEX:\t%d (%d)\n", line, b, csv->quo_len);
386              
387             if (csv->quo_len)
388             (void)fprintf (stderr,
389             "# len: %d, siz: %d, usd: %d, c: %03x, *quo: %03x\n",
390             csv->quo_len, csv->size, csv->used, c, CH_QUOTE);
391             return b;
392             } /* _is_QUOTEX */
393             #define is_QUOTE(c) _is_QUOTEX (c, csv, __LINE__)
394             #else
395             #define is_QUOTE(c) __is_QUOTEX (c)
396             #endif
397              
398             #define is_whitespace(ch) \
399             ( (ch) != CH_SEP && \
400             (ch) != CH_QUOTE && \
401             (ch) != csv->escape_char && \
402             ( (ch) == CH_SPACE || \
403             (ch) == CH_TAB \
404             ) \
405             )
406              
407             #define _pretty_strl(cp) cx_pretty_str (aTHX_ cp, strlen (cp))
408             #define _pretty_str(cp,xse) cx_pretty_str (aTHX_ cp, xse)
409 9           static char *cx_pretty_str (pTHX_ byte *s, STRLEN l) {
410 9           SV *dsv = newSVpvs_flags ("", SVs_TEMP);
411 9           return (pv_pretty (dsv, (char *)s, l, 0, NULL, NULL,
412             (PERL_PV_PRETTY_DUMP | PERL_PV_ESCAPE_UNI_DETECT)));
413             } /* _pretty_str */
414             #if MAINT_DEBUG > 4
415             #define _pretty_sv(cp) cx_pretty_sv (aTHX_ cp)
416             static char *cx_pretty_sv (pTHX_ SV *sv) {
417             if (SvOK (sv) && SvPOK (sv)) {
418             STRLEN l;
419             char *s = SvPV (sv, l);
420             return _pretty_str ((byte *)s, l);
421             }
422             return ("");
423             } /* _pretty_sv */
424             #endif
425              
426             #define SvDiag(xse) cx_SvDiag (aTHX_ xse)
427 3814           static SV *cx_SvDiag (pTHX_ int xse) {
428 3814           int i = 0;
429             SV *err;
430              
431 78077 100         while (xs_errors[i].xs_errno && xs_errors[i].xs_errno != xse) i++;
    100          
432 3814 50         if ((err = newSVpv (xs_errors[i].xs_errstr, 0))) {
433 3814 50         (void)SvUPGRADE (err, SVt_PVIV);
434 3814           SvIV_set (err, xse);
435 3814           SvIOK_on (err);
436             }
437 3814           return (err);
438             } /* SvDiag */
439              
440             /* This function should be altered to deal with the optional extra argument
441             * that holds the replacement message */
442             #define SetDiag(csv,xse) cx_SetDiag (aTHX_ csv, xse, __LINE__)
443             #define SetDiagL(csv,xse,line) cx_SetDiag (aTHX_ csv, xse, line)
444 1776           static SV *cx_SetDiag (pTHX_ csv_t *csv, int xse, int line) {
445 1776           dSP;
446 1776           SV *err = SvDiag (xse);
447 1776           SV *pself = csv->pself;
448              
449 1776           last_error = xse;
450 1776           (void)hv_store (csv->self, "_ERROR_DIAG", 11, err, 0);
451 1776 100         if (xse == 0) {
452 6           (void)hv_store (csv->self, "_ERROR_POS", 10, newSViv (0), 0);
453 6           (void)hv_store (csv->self, "_ERROR_FLD", 10, newSViv (0), 0);
454 6           (void)hv_store (csv->self, "_ERROR_INPUT", 12, &PL_sv_undef, 0);
455 6           csv->has_error_input = 0;
456             }
457 1776 50         if (line)
458 1776           (void)hv_store (csv->self, "_ERROR_SRC", 10, newSViv (line), 0);
459 1776 100         if (xse == 2012) /* EOF */
460 383           (void)hv_store (csv->self, "_EOF", 4, &PL_sv_yes, 0);
461 1776 100         if (csv->auto_diag) {
462 688 50         unless (_is_hashref (pself))
    50          
    0          
    100          
    50          
463 162           pself = newRV_inc ((SV *)csv->self);
464 344           ENTER;
465 344 50         PUSHMARK (SP);
466 344 50         XPUSHs (pself);
467 344           PUTBACK;
468 344           call_pv ("Text::CSV_XS::error_diag", G_VOID | G_DISCARD);
469 341           LEAVE;
470 341 100         unless (pself == csv->pself)
471 161           sv_free (pself);
472             }
473 1773           return (err);
474             } /* SetDiag */
475              
476             #define xs_cache_get_eolt(hv) cx_xs_cache_get_eolt (aTHX_ hv)
477 32           static char *cx_xs_cache_get_eolt (pTHX_ HV *hv) {
478             SV **svp;
479             csv_t *csvs;
480              
481 32 50         unless ((svp = hv_fetchs (hv, "_CACHE", FALSE)) && *svp)
    50          
482 0           return NULL;
483              
484 32           csvs = (csv_t *)SvPV_nolen (*svp);
485 32 50         if (csvs->eol_type == EOL_TYPE_NL) return "\n";
486 32 50         if (csvs->eol_type == EOL_TYPE_CR) return "\r";
487 32 100         if (csvs->eol_type == EOL_TYPE_CRNL) return "\r\n";
488 11 50         if (csvs->eol_type == EOL_TYPE_OTHER) return (char *)(csvs->eol);
489 11           return NULL;
490             } /* cx_xs_cache_get_eolt */
491              
492             #define xs_cache_set(hv,idx,val) cx_xs_cache_set (aTHX_ hv, idx, val)
493 23355           static void cx_xs_cache_set (pTHX_ HV *hv, int idx, SV *val) {
494             SV **svp;
495             byte *cache;
496              
497             csv_t csvs;
498 23355           csv_t *csv = &csvs;
499              
500             IV iv;
501             byte bv;
502 23355           char *cp = "\0";
503 23355           STRLEN len = 0;
504              
505 23355 100         unless ((svp = hv_fetchs (hv, "_CACHE", FALSE)) && *svp)
    50          
506 766           return;
507              
508 22589           cache = (byte *)SvPV_nolen (*svp);
509 22589           (void)memcpy (csv, cache, sizeof (csv_t));
510              
511 22589 100         if (SvPOK (val))
512 16789           cp = SvPV (val, len);
513 22589 100         if (SvIOK (val))
514 5788           iv = SvIV (val);
515 16801 50         else if (SvNOK (val)) /* Needed for 5.6.x but safe for 5.8.x+ */
516 0           iv = (IV)SvNV (val); /* uncoverable statement ancient perl required */
517             else
518 16801           iv = *cp;
519 22589           bv = (unsigned)iv & 0xff;
520              
521 22589           switch (idx) {
522              
523             /* single char/byte */
524 3122           case CACHE_ID_sep_char:
525 3122           CH_SEP = *cp;
526 3122           csv->sep_len = 0;
527 3122           break;
528              
529 3369           case CACHE_ID_quote_char:
530 3369           CH_QUOTE = *cp;
531 3369           csv->quo_len = 0;
532 3369           break;
533              
534 3478           case CACHE_ID_escape_char: csv->escape_char = *cp; break;
535              
536             /* boolean/numeric */
537 11           case CACHE_ID_binary: csv->binary = bv; break;
538 10           case CACHE_ID_keep_meta_info: csv->keep_meta_info = bv; break;
539 1798           case CACHE_ID_always_quote: csv->always_quote = bv; break;
540 3           case CACHE_ID_quote_empty: csv->quote_empty = bv; break;
541 6           case CACHE_ID_quote_space: csv->quote_space = bv; break;
542 10           case CACHE_ID_escape_null: csv->escape_null = bv; break;
543 6           case CACHE_ID_quote_binary: csv->quote_binary = bv; break;
544 1           case CACHE_ID_decode_utf8: csv->decode_utf8 = bv; break;
545 11           case CACHE_ID_allow_loose_escapes: csv->allow_loose_escapes = bv; break;
546 11           case CACHE_ID_allow_loose_quotes: csv->allow_loose_quotes = bv; break;
547 2           case CACHE_ID_allow_unquoted_escape: csv->allow_unquoted_escape = bv; break;
548 3719           case CACHE_ID_allow_whitespace: csv->allow_whitespace = bv; break;
549 1           case CACHE_ID_blank_is_undef: csv->blank_is_undef = bv; break;
550 1           case CACHE_ID_empty_is_undef: csv->empty_is_undef = bv; break;
551 1           case CACHE_ID_formula: csv->formula = bv; break;
552 1           case CACHE_ID_strict: csv->strict = bv; break;
553 6           case CACHE_ID_verbatim: csv->verbatim = bv; break;
554 1           case CACHE_ID_strict_eol: csv->strict_eol = bv; break;
555 0           case CACHE_ID_eol_type: csv->eol_type = bv; break;
556 4           case CACHE_ID_skip_empty_rows: csv->skip_empty_rows = bv; break;
557 9           case CACHE_ID_auto_diag: csv->auto_diag = bv; break;
558 8           case CACHE_ID_diag_verbose: csv->diag_verbose = bv; break;
559 142           case CACHE_ID__has_ahead: csv->has_ahead = bv; break;
560 12           case CACHE_ID__has_hooks: csv->has_hooks = bv; break;
561 0           case CACHE_ID_has_error_input: csv->has_error_input = bv; break;
562              
563             /* a 4-byte IV */
564 12           case CACHE_ID__is_bound: csv->is_bound = iv; break;
565              
566             /* string */
567 3223           case CACHE_ID_sep:
568 3223           (void)memcpy (csv->sep, cp, len);
569 3223 50         csv->sep_len = len == 1 ? 0 : len;
570 3223           break;
571              
572 3377           case CACHE_ID_quo:
573 3377           (void)memcpy (csv->quo, cp, len);
574 3377 50         csv->quo_len = len == 1 ? 0 : len;
575 3377           break;
576              
577 218           case CACHE_ID_eol:
578 218           (void)memcpy (csv->eol, cp, len);
579 218           csv->eol_len = len;
580 305 100         csv->eol_type = len == 0 ? EOL_TYPE_UNDEF
581 87 100         : len == 1 && *cp == CH_NL ? EOL_TYPE_NL
    100          
582 83 100         : len == 1 && *cp == CH_CR ? EOL_TYPE_CR
    100          
583 8 100         : len == 2 && *cp == CH_CR
    50          
584 4 50         && cp[1] == CH_NL ? EOL_TYPE_CRNL
585             : EOL_TYPE_OTHER;
586 218           csv->strict_eol &= 0x3F;
587 218           csv->eol_is_cr = csv->eol_type == EOL_TYPE_CR ? 1 : 0;
588             #if MAINT_DEBUG_EOL > 0
589             (void)fprintf (stderr, "# %04d cache set eol: '%s'\t(len: %d, is_cr: %d, tp: %02x)\n",
590             __LINE__, _pretty_str (cp, len), len, csv->eol_is_cr, csv->eol_type);
591             #endif
592 218           break;
593              
594 11           case CACHE_ID_undef_str:
595 11 100         if (*cp) {
596 8           csv->undef_str = (byte *)cp;
597 8 100         if (SvUTF8 (val))
598 1           csv->undef_flg = 3;
599             }
600             else {
601 3           csv->undef_str = NULL;
602 3           csv->undef_flg = 0;
603             }
604 11           break;
605              
606 2           case CACHE_ID_comment_str:
607 2 100         csv->comment_str = *cp ? (byte *)cp : NULL;
608 2           break;
609              
610 1           case CACHE_ID_types:
611 1 50         if (cp && len) {
    50          
612 0           csv->types = cp;
613 0           csv->types_len = len;
614             }
615             else {
616 1           csv->types = NULL;
617 1           csv->types_len = 0;
618             }
619 1           break;
620              
621 2           default:
622 2           warn ("Unknown cache index %d ignored\n", idx);
623             }
624              
625 22589           csv->cache = cache;
626 22589           (void)memcpy (cache, csv, sizeof (csv_t));
627             } /* cache_set */
628              
629             #define _cache_show_byte(trim,c) \
630             warn (" %-21s %02x:%3d\n", trim, c, c)
631             #define _cache_show_char(trim,c) \
632             warn (" %-21s %02x:%s\n", trim, c, _pretty_str (&c, 1))
633             #define _cache_show_str(trim,l,str) \
634             warn (" %-21s %3d:%s\n", trim, l, _pretty_str (str, l))
635              
636             #define _csv_diag(csv) _xs_csv_diag (aTHX_ csv)
637 1           static void _xs_csv_diag (pTHX_ csv_t *csv) {
638 1           warn ("CACHE:\n");
639 1           _cache_show_char ("quote_char", CH_QUOTE);
640 1           _cache_show_char ("escape_char", csv->escape_char);
641 1           _cache_show_char ("sep_char", CH_SEP);
642 1           _cache_show_byte ("binary", csv->binary);
643 1           _cache_show_byte ("decode_utf8", csv->decode_utf8);
644              
645 1           _cache_show_byte ("allow_loose_escapes", csv->allow_loose_escapes);
646 1           _cache_show_byte ("allow_loose_quotes", csv->allow_loose_quotes);
647 1           _cache_show_byte ("allow_unquoted_escape", csv->allow_unquoted_escape);
648 1           _cache_show_byte ("allow_whitespace", csv->allow_whitespace);
649 1           _cache_show_byte ("always_quote", csv->always_quote);
650 1           _cache_show_byte ("quote_empty", csv->quote_empty);
651 1           _cache_show_byte ("quote_space", csv->quote_space);
652 1           _cache_show_byte ("escape_null", csv->escape_null);
653 1           _cache_show_byte ("quote_binary", csv->quote_binary);
654 1           _cache_show_byte ("auto_diag", csv->auto_diag);
655 1           _cache_show_byte ("diag_verbose", csv->diag_verbose);
656 1           _cache_show_byte ("formula", csv->formula);
657 1           _cache_show_byte ("strict", csv->strict);
658 1           _cache_show_byte ("strict_n", csv->strict_n);
659 1           _cache_show_byte ("strict_eol", csv->strict_eol);
660 1           _cache_show_byte ("eol_type", csv->eol_type);
661 1           _cache_show_byte ("skip_empty_rows", csv->skip_empty_rows);
662 1           _cache_show_byte ("has_error_input", csv->has_error_input);
663 1           _cache_show_byte ("blank_is_undef", csv->blank_is_undef);
664 1           _cache_show_byte ("empty_is_undef", csv->empty_is_undef);
665 1           _cache_show_byte ("has_ahead", csv->has_ahead);
666 1           _cache_show_byte ("keep_meta_info", csv->keep_meta_info);
667 1           _cache_show_byte ("verbatim", csv->verbatim);
668              
669 1           _cache_show_byte ("useIO", csv->useIO);
670 1           _cache_show_byte ("has_hooks", csv->has_hooks);
671 1           _cache_show_byte ("eol_is_cr", csv->eol_is_cr);
672 1           _cache_show_byte ("eol_len", csv->eol_len);
673 1           _cache_show_str ("eol", csv->eol_len, csv->eol);
674 1           _cache_show_byte ("sep_len", csv->sep_len);
675 1 50         if (csv->sep_len > 1)
676 1           _cache_show_str ("sep", csv->sep_len, csv->sep);
677 1           _cache_show_byte ("quo_len", csv->quo_len);
678 1 50         if (csv->quo_len > 1)
679 1           _cache_show_str ("quote", csv->quo_len, csv->quo);
680 1 50         if (csv->types_len)
681 0           _cache_show_str ("types", csv->types_len, (byte *)csv->types);
682             else
683 1           _cache_show_str ("types", 0, (byte *)"");
684              
685 1 50         if (csv->bptr)
686 1           _cache_show_str ("bptr", (int)strlen (csv->bptr), (byte *)csv->bptr);
687 1 50         if (csv->tmp && SvPOK (csv->tmp)) {
    50          
688 1           char *s = SvPV_nolen (csv->tmp);
689 1           _cache_show_str ("tmp", (int)strlen (s), (byte *)s);
690             }
691 1 50         if (csv->cache)
692 1           warn (" %-20s %4d:0x%08lx\n", "cache", (int)sizeof (csv_t), (unsigned long)csv->cache);
693             else
694 0           warn (" %-22s --:no cache yet\n", "cache");
695 1           } /* _csv_diag */
696              
697             #define xs_cache_diag(hv) cx_xs_cache_diag (aTHX_ hv)
698 2           static void cx_xs_cache_diag (pTHX_ HV *hv) {
699             SV **svp;
700             byte *cache;
701             csv_t csvs;
702 2           csv_t *csv = &csvs;
703              
704 2 100         unless ((svp = hv_fetchs (hv, "_CACHE", FALSE)) && *svp) {
    50          
705 1           warn ("CACHE: invalid\n");
706 1           return;
707             }
708              
709 1           cache = (byte *)SvPV_nolen (*svp);
710 1           (void)memcpy (csv, cache, sizeof (csv_t));
711 1           _csv_diag (csv);
712             } /* xs_cache_diag */
713              
714             #define set_eol_is_cr(csv) cx_set_eol_is_cr (aTHX_ csv)
715 43           static void cx_set_eol_is_cr (pTHX_ csv_t *csv) {
716 43           csv->eol_is_cr = 1;
717 43           csv->eol_len = 1;
718 43           csv->eol[0] = CH_CR;
719 43           csv->eol_type = EOL_TYPE_CR;
720 43           (void)memcpy (csv->cache, csv, sizeof (csv_t));
721              
722 43           (void)hv_store (csv->self, "eol", 3, newSVpvn ((char *)csv->eol, 1), 0);
723             #if MAINT_DEBUG_EOL > 0
724             (void)fprintf (stderr, "# %04d set eol is CR: '%s'\t(len: %d, is_cr: %d, tp: %02x)\n",
725             __LINE__, _pretty_str (csv->eol, csv->eol_len), csv->eol_len, csv->eol_is_cr, csv->eol_type);
726             #endif
727 43           } /* set_eol_is_cr */
728              
729             #define SetupCsv(csv,self,pself) cx_SetupCsv (aTHX_ csv, self, pself)
730 27731           static void cx_SetupCsv (pTHX_ csv_t *csv, HV *self, SV *pself) {
731             SV **svp;
732             STRLEN len;
733             char *ptr;
734              
735 27731           last_error = 0;
736              
737 27731 100         if ((svp = hv_fetchs (self, "_CACHE", FALSE)) && *svp) {
    50          
738 26837           byte *cache = (byte *)SvPVX (*svp);
739 26837           (void)memcpy (csv, cache, sizeof (csv_t));
740             }
741             else {
742             SV *sv_cache;
743              
744 894           (void)memset (csv, 0, sizeof (csv_t)); /* Reset everything */
745              
746 894           csv->self = self;
747 894           csv->pself = pself;
748              
749 894           CH_SEP = ',';
750 894 50         if ((svp = hv_fetchs (self, "sep_char", FALSE)) && *svp && SvOK (*svp))
    50          
    50          
751 894           CH_SEP = *SvPV (*svp, len);
752 894 100         if ((svp = hv_fetchs (self, "sep", FALSE)) && *svp && SvOK (*svp)) {
    50          
    50          
753 224           ptr = SvPV (*svp, len);
754 224           (void)memcpy (csv->sep, ptr, len);
755 224 100         if (len > 1)
756 5           csv->sep_len = len;
757             }
758              
759 894           CH_QUOTE = '"';
760 894 50         if ((svp = hv_fetchs (self, "quote_char", FALSE)) && *svp) {
    50          
761 894 100         if (SvOK (*svp)) {
762 891           ptr = SvPV (*svp, len);
763 891 50         CH_QUOTE = len ? *ptr : (char)0;
764             }
765             else
766 3           CH_QUOTE = (char)0;
767             }
768 894 100         if ((svp = hv_fetchs (self, "quote", FALSE)) && *svp && SvOK (*svp)) {
    50          
    100          
769 5           ptr = SvPV (*svp, len);
770 5           (void)memcpy (csv->quo, ptr, len);
771 5 100         if (len > 1)
772 4           csv->quo_len = len;
773             }
774              
775 894           csv->escape_char = '"';
776 894 50         if ((svp = hv_fetchs (self, "escape_char", FALSE)) && *svp) {
    50          
777 894 100         if (SvOK (*svp)) {
778 888           ptr = SvPV (*svp, len);
779 888 100         csv->escape_char = len ? *ptr : (char)0;
780             }
781             else
782 6           csv->escape_char = (char)0;
783             }
784              
785 894 50         if ((svp = hv_fetchs (self, "eol", FALSE)) && *svp && SvOK (*svp)) {
    50          
    100          
786 889           char *eol = SvPV (*svp, len);
787 889           (void)memcpy (csv->eol, eol, len);
788 889           csv->eol_len = len;
789 889 100         if (len == 1 && *eol == CH_CR) {
    100          
790 42           csv->eol_is_cr = 1;
791 42           csv->eol_type = EOL_TYPE_CR;
792             }
793 847 100         else if (len == 1 && *eol == CH_NL)
    100          
794 54           csv->eol_type = EOL_TYPE_NL;
795 793 100         else if (len == 2 && *eol == CH_CR && eol[1] == CH_NL)
    100          
    50          
796 50           csv->eol_type = EOL_TYPE_CRNL;
797             }
798              
799 894           csv->undef_flg = 0;
800 894 50         if ((svp = hv_fetchs (self, "undef_str", FALSE)) && *svp && SvOK (*svp)) {
    50          
    100          
801             /*if (sv && (SvOK (sv) || (
802             (SvGMAGICAL (sv) && (mg_get (sv), 1) && SvOK (sv))))) {*/
803 1           csv->undef_str = (byte *)SvPV_nolen (*svp);
804 1 50         if (SvUTF8 (*svp))
805 0           csv->undef_flg = 3;
806             }
807             else
808 893           csv->undef_str = NULL;
809              
810 894 50         if ((svp = hv_fetchs (self, "comment_str", FALSE)) && *svp && SvOK (*svp))
    50          
    100          
811 21           csv->comment_str = (byte *)SvPV_nolen (*svp);
812             else
813 873           csv->comment_str = NULL;
814              
815 894 100         if ((svp = hv_fetchs (self, "_types", FALSE)) && *svp && SvOK (*svp)) {
    50          
    50          
816 1           csv->types = SvPV (*svp, len);
817 1           csv->types_len = len;
818             }
819              
820 894 100         if ((svp = hv_fetchs (self, "_is_bound", FALSE)) && *svp && SvOK (*svp))
    50          
    50          
821 12           csv->is_bound = SvIV (*svp);
822 1788 50         if ((svp = hv_fetchs (self, "callbacks", FALSE)) && _is_hashref (*svp)) {
    50          
    50          
    0          
    100          
    50          
823 325           HV *cb = (HV *)SvRV (*svp);
824 341 100         if ((svp = hv_fetchs (cb, "after_parse", FALSE)) && _is_coderef (*svp))
    50          
    50          
    0          
    50          
    50          
825 16           csv->has_hooks |= HOOK_AFTER_PARSE;
826 328 100         if ((svp = hv_fetchs (cb, "before_print", FALSE)) && _is_coderef (*svp))
    50          
    50          
    0          
    50          
    50          
827 3           csv->has_hooks |= HOOK_BEFORE_PRINT;
828             }
829              
830 894 50         csv->binary = bool_opt ("binary");
    50          
831 894 50         csv->decode_utf8 = bool_opt ("decode_utf8");
    50          
832 894 50         csv->always_quote = bool_opt ("always_quote");
    50          
833 894 50         csv->strict = bool_opt ("strict");
    50          
834 894 50         csv->strict_eol = num_opt ("strict_eol");
    50          
835 894 50         csv->quote_empty = bool_opt ("quote_empty");
    50          
836 894 50         csv->quote_space = bool_opt_def ("quote_space", 1);
    50          
837 894 50         csv->escape_null = bool_opt_def ("escape_null", 1);
    50          
838 894 50         csv->quote_binary = bool_opt_def ("quote_binary", 1);
    50          
839 894 50         csv->allow_loose_quotes = bool_opt ("allow_loose_quotes");
    50          
840 894 50         csv->allow_loose_escapes = bool_opt ("allow_loose_escapes");
    50          
841 894 50         csv->allow_unquoted_escape = bool_opt ("allow_unquoted_escape");
    50          
842 894 50         csv->allow_whitespace = bool_opt ("allow_whitespace");
    50          
843 894 50         csv->blank_is_undef = bool_opt ("blank_is_undef");
    50          
844 894 50         csv->empty_is_undef = bool_opt ("empty_is_undef");
    50          
845 894 50         csv->verbatim = bool_opt ("verbatim");
    50          
846              
847 894 50         csv->auto_diag = num_opt ("auto_diag");
    50          
848 894 50         csv->diag_verbose = num_opt ("diag_verbose");
    50          
849 894 50         csv->keep_meta_info = num_opt ("keep_meta_info");
    50          
850 894 50         csv->skip_empty_rows = num_opt ("skip_empty_rows");
    50          
851 894 50         csv->formula = num_opt ("formula");
    50          
852              
853 894 100         unless (csv->escape_char) csv->escape_null = 0;
854              
855 894           sv_cache = newSVpvn ((char *)csv, sizeof (csv_t));
856 894           csv->cache = (byte *)SvPVX (sv_cache);
857 894           SvREADONLY_on (sv_cache);
858              
859 894           (void)memcpy (csv->cache, csv, sizeof (csv_t));
860              
861 894           (void)hv_store (self, "_CACHE", 6, sv_cache, 0);
862             }
863              
864 27731           csv->utf8 = 0;
865 27731           csv->size = 0;
866 27731           csv->used = 0;
867              
868             /* This is EBCDIC-safe, as it is used after translation */
869 27731 100         csv->first_safe_char = csv->quote_space ? 0x21 : 0x20;
870              
871 27731 100         if (csv->is_bound) {
872 224 50         if ((svp = hv_fetchs (self, "_BOUND_COLUMNS", FALSE)) && _is_arrayref (*svp))
    50          
    50          
    0          
    100          
    50          
873 98           csv->bound = *svp;
874             else
875 14           csv->is_bound = 0;
876             }
877              
878 27731           csv->eol_pos = -1;
879 55462           csv->eolx = csv->eol_len
880 1346 100         ? csv->verbatim || csv->eol_len >= 2
881             ? 1
882 894 100         : csv->eol[0] == CH_CR || csv->eol[0] == CH_NL
883             ? 0
884 362 100         : 1
885 29077 100         : 0;
    100          
886 27731 100         if (csv->eol_type > 0 && csv->strict_eol > 0 && !*csv->eol)
    100          
    100          
887 750           csv->eol_is_cr = 0;
888             #if MAINT_DEBUG_EOL > 0
889             (void)fprintf (stderr, "# %04d setup eol: '%s'\t(len: %d, is_cr: %d, x: %d, pos: %d, tp: %02x)\n",
890             __LINE__, _pretty_str (csv->eol, csv->eol_len), csv->eol_len, csv->eol_is_cr, csv->eolx, csv->eol_pos, csv->eol_type);
891             #endif
892 27731 100         if (csv->sep_len > 1 && is_utf8_string ((U8 *)(csv->sep), csv->sep_len))
    50          
893 51           csv->utf8 = 1;
894 27731 100         if (csv->quo_len > 1 && is_utf8_string ((U8 *)(csv->quo), csv->quo_len))
    50          
895 27           csv->utf8 = 1;
896              
897 27731 100         if (csv->strict
898 67 100         && !csv->strict_n
899 27 50         && (svp = hv_fetchs (self, "_COLUMN_NAMES", FALSE))
900 54 50         && _is_arrayref (*svp))
    50          
    0          
    100          
    50          
901 2           csv->strict_n = av_len ((AV *)(SvRV (*svp)));
902 27731           } /* SetupCsv */
903              
904             #define Print(csv,dst) cx_Print (aTHX_ csv, dst)
905 941292           static int cx_Print (pTHX_ csv_t *csv, SV *dst) {
906             int result;
907 941292           int keep = 0;
908              
909 941292 100         if (csv->useIO) {
910 939903           SV *tmp = newSVpvn_flags (csv->buffer, csv->used, SVs_TEMP);
911 939903           dSP;
912 939903 50         PUSHMARK (sp);
913 939903 50         EXTEND (sp, 2);
914 939903           PUSHs ((dst));
915 939903 100         if (csv->utf8) {
916             STRLEN len;
917             char *ptr;
918             int j;
919              
920 939649           ptr = SvPV (tmp, len);
921 1690511 50         while (len > 0 && !is_utf8_sv (tmp) && keep < 16) {
    100          
    50          
922 750862           ptr[--len] = (char)0;
923 750862           SvCUR_set (tmp, len);
924 750862           keep++;
925             }
926 1690511 100         for (j = 0; j < keep; j++)
927 750862           csv->buffer[j] = csv->buffer[csv->used - keep + j];
928 939649           SvUTF8_on (tmp);
929             }
930 939903           PUSHs (tmp);
931 939903           PUTBACK;
932 939903           result = call_sv (m_print, G_METHOD);
933 939903           SPAGAIN;
934 939903 50         if (result) {
935 939903           result = POPi;
936 939903 100         unless (result)
937 1           (void)SetDiag (csv, 2200);
938             }
939 939903           PUTBACK;
940             }
941             else {
942 1389           sv_catpvn (SvRV (dst), csv->buffer, csv->used);
943 1389           result = TRUE;
944             }
945 941292 100         if (csv->utf8 && !csv->useIO && csv->decode_utf8
    100          
    50          
946 25 50         && SvROK (dst) && is_utf8_sv (SvRV (dst)))
    100          
947 24           SvUTF8_on (SvRV (dst));
948 941292           csv->used = keep;
949 941292           return result;
950             } /* Print */
951              
952             #define CSV_PUT(csv,dst,c) { \
953             if ((csv)->used == sizeof ((csv)->buffer) - 1) { \
954             unless (Print ((csv), (dst))) \
955             return FALSE; \
956             } \
957             (csv)->buffer[(csv)->used++] = (c); \
958             }
959              
960             #define bound_field(csv,i,keep) cx_bound_field (aTHX_ csv, i, keep)
961 166           static SV *cx_bound_field (pTHX_ csv_t *csv, SSize_t i, int keep) {
962 166           SV *sv = csv->bound;
963             AV *av;
964              
965             /* fprintf (stderr, "# New bind %d/%d\n", i, csv->is_bound);\ */
966 166 100         if (i >= csv->is_bound) {
967 3           (void)SetDiag (csv, 3006);
968 3           return (NULL);
969             }
970              
971 163 50         if (sv && SvROK (sv)) {
    50          
972 163           av = (AV *)(SvRV (sv));
973             /* fprintf (stderr, "# Bind %d/%d/%d\n", i, csv->is_bound, av_len (av)); */
974 163           sv = *av_fetch (av, i, FALSE);
975 163 50         if (sv && SvROK (sv)) {
    50          
976 163           sv = SvRV (sv);
977 163 100         if (keep)
978 14           return (sv);
979              
980 149 100         unless (SvREADONLY (sv)) {
981 148           SvSetEmpty (sv);
982 148           return (sv);
983             }
984             }
985             }
986 1           (void)SetDiag (csv, 3008);
987 1           return (NULL);
988             } /* bound_field */
989              
990             #define was_quoted(mf,idx) cx_was_quoted (aTHX_ mf, idx)
991 17           static int cx_was_quoted (pTHX_ AV *mf, int idx) {
992 17           SV **x = av_fetch (mf, idx, FALSE);
993 17 50         return (x && SvIOK (*x) && SvIV (*x) & CSV_FLAGS_QUO ? 1 : 0);
    50          
    100          
994             } /* was_quoted */
995              
996             #define _formula(csv,sv,len,f) cx_formula (aTHX_ csv, sv, len, f)
997 37           static char *cx_formula (pTHX_ csv_t *csv, SV *sv, STRLEN *len, int f) {
998              
999 37           int fa = csv->formula;
1000              
1001 37 100         if (fa == 1) die ("Formulas are forbidden\n");
1002 34 100         if (fa == 2) croak ("Formulas are forbidden\n");
1003              
1004 31 100         if (fa == 3) {
1005 6           char *ptr = SvPV_nolen (sv);
1006             char rec[40];
1007             char field[128];
1008             SV **svp;
1009              
1010 6 100         if (csv->recno) (void)sprintf (rec, " in record %lu", csv->recno + 1);
1011 3           else *rec = (char)0;
1012              
1013 6           *field = (char)0;
1014 12 50         if ((svp = hv_fetchs (csv->self, "_COLUMN_NAMES", FALSE)) && _is_arrayref (*svp)) {
    50          
    50          
    0          
    100          
    50          
1015 1           AV *avp = (AV *)SvRV (*svp);
1016 1 50         if (avp && av_len (avp) >= (f - 1)) {
    50          
1017 1           SV **fnm = av_fetch (avp, f - 1, FALSE);
1018 1 50         if (fnm && *fnm && SvOK (*fnm))
    50          
    50          
1019 1           (void)sprintf (field, " (column: '%.100s')", SvPV_nolen (*fnm));
1020             }
1021             }
1022              
1023 6           warn ("Field %d%s%s contains formula '%s'\n", f, field, rec, ptr);
1024 6           return ptr;
1025             }
1026              
1027 25 100         if (len) *len = 0;
1028              
1029 25 100         if (fa == 4) {
1030 5 100         unless (SvREADONLY (sv)) SvSetEmpty (sv);
1031 5           return "";
1032             }
1033              
1034 20 100         if (fa == 5) {
1035 5 100         unless (SvREADONLY (sv)) SvSetUndef (sv);
1036 5           return NULL;
1037             }
1038              
1039 15 50         if (fa == 6) {
1040             int result;
1041 15           SV **svp = hv_fetchs (csv->self, "_FORMULA_CB", FALSE);
1042 30 50         if (svp && _is_coderef (*svp)) {
    50          
    50          
    0          
    50          
    50          
1043 15           dSP;
1044 15           ENTER;
1045 15           SAVE_DEFSV; /* local $_ */
1046 15 50         DEFSV = sv;
1047 15 50         PUSHMARK (SP);
1048 15           PUTBACK;
1049 15           result = call_sv (*svp, G_SCALAR);
1050 15           SPAGAIN;
1051 15 50         if (result)
1052 15           sv_setsv (sv, POPs);
1053 15           PUTBACK;
1054 15           LEAVE;
1055             }
1056 15 50         return len ? SvPV (sv, *len) : SvPV_nolen (sv);
1057             }
1058              
1059             /* So far undefined behavior */
1060 0           return NULL;
1061             } /* _formula */
1062              
1063             #define SkipEmptyRow {\
1064             int ser = csv->skip_empty_rows; \
1065             \
1066             if (ser == 3) { (void)SetDiag (csv, 2015); die ("Empty row"); } \
1067             if (ser == 4) { (void)SetDiag (csv, 2015); croak ("Empty row"); } \
1068             if (ser == 5) { (void)SetDiag (csv, 2015); return FALSE; } \
1069             \
1070             if (ser <= 2) { /* skip & eof */ \
1071             csv->fld_idx = 0; \
1072             c = CSV_GET; \
1073             if (c == EOF || ser == 2) { \
1074             sv_free (sv); \
1075             sv = NULL; \
1076             seenSomething = FALSE; \
1077             if (ser == 2) return FALSE; \
1078             break; \
1079             } \
1080             } \
1081             \
1082             if (ser == 6) { \
1083             int result, n, i; \
1084             SV *rv, **svp = hv_fetchs (csv->self, "_EMPTROW_CB", FALSE); \
1085             AV *avp; \
1086             unless (svp && _is_coderef (*svp)) \
1087             return FALSE; /* A callback is wanted, but none found */ \
1088             \
1089             dSP; \
1090             ENTER; \
1091             SAVE_DEFSV; /* local $_ */ \
1092             DEFSV = sv; \
1093             PUSHMARK (SP); \
1094             PUTBACK; \
1095             result = call_sv (*svp, G_SCALAR); \
1096             SPAGAIN; \
1097             unless (result) { \
1098             /* A false return will stop the parsing */ \
1099             sv_free (sv); \
1100             sv = NULL; \
1101             waitingForField = 0; \
1102             return FALSE; \
1103             } \
1104             \
1105             PUTBACK; \
1106             LEAVE; \
1107             \
1108             rv = POPs; \
1109             /* Result should be a ref to a list. */ \
1110             unless (_is_arrayref (rv)) \
1111             return FALSE; \
1112             \
1113             avp = (AV *)SvRV (rv); \
1114             \
1115             unless (avp) return FALSE; \
1116             n = av_len (avp); \
1117             if (n <= 0) return TRUE; \
1118             \
1119             if (csv->is_bound && csv->is_bound < n) \
1120             n = csv->is_bound - 1; \
1121             \
1122             for (i = 0; i <= n; i++) { \
1123             SV **svp = av_fetch (avp, i, FALSE); \
1124             sv = svp && *svp ? *svp : NULL; \
1125             if (sv) { \
1126             SvREFCNT_inc (sv); \
1127             /* upgrade IV to IVPV if needed */ \
1128             (void)SvPV_nolen (sv); \
1129             } \
1130             AV_PUSH; \
1131             } \
1132             return TRUE; \
1133             } \
1134             }
1135              
1136             #define Combine(csv,dst,fields) cx_Combine (aTHX_ csv, dst, fields)
1137 21673           static int cx_Combine (pTHX_ csv_t *csv, SV *dst, AV *fields) {
1138             SSize_t i, n;
1139 21673           int bound = 0;
1140 21673           int aq = (int)csv->always_quote;
1141 21673           int qe = (int)csv->quote_empty;
1142 21673           int kmi = (int)csv->keep_meta_info;
1143 21673           AV *qm = NULL;
1144              
1145 21673           n = (IV)av_len (fields);
1146 21673 100         if (n < 0 && csv->is_bound) {
    100          
1147 5           n = csv->is_bound - 1;
1148 5           bound = 1;
1149             }
1150              
1151 21673 100         if (kmi >= 10) {
1152             SV **svp;
1153 4 50         if ((svp = hv_fetchs (csv->self, "_FFLAGS", FALSE)) && _is_arrayref (*svp)) {
    50          
    50          
    0          
    50          
    50          
1154 2           AV *avp = (AV *)SvRV (*svp);
1155 2 50         if (avp && av_len (avp) >= n)
    50          
1156 2           qm = avp;
1157             }
1158             }
1159              
1160 75609 100         for (i = 0; i <= n; i++) {
1161             SV *sv;
1162 53947           STRLEN len = 0;
1163 53947           char *ptr = NULL;
1164              
1165 53947 100         if (i > 0) {
1166 32282 50         CSV_PUT (csv, dst, CH_SEP);
    0          
1167 32275 100         if (csv->sep_len) {
1168             int x;
1169 30 100         for (x = 1; x < (int)csv->sep_len; x++)
1170 20 50         CSV_PUT (csv, dst, csv->sep[x]);
    0          
1171             }
1172             }
1173              
1174 53947 100         if (bound)
1175 14           sv = bound_field (csv, i, 1);
1176             else {
1177 53933           SV **svp = av_fetch (fields, i, FALSE);
1178 53933 50         sv = svp && *svp ? *svp : NULL;
    50          
1179             }
1180              
1181 53947 50         if (sv && (SvOK (sv) || (
    100          
1182 53934 50         (SvGMAGICAL (sv) && (mg_get (sv), 1) && SvOK (sv))))) {
    0          
1183              
1184             int quoteMe;
1185              
1186 53894           ptr = SvPV (sv, len);
1187              
1188 53894 100         if (*ptr == '=' && csv->formula) {
    100          
1189 10 100         unless (ptr = _formula (csv, sv, &len, i))
1190 2           continue;
1191             }
1192 53888 100         if (len == 0)
1193 1412 100         quoteMe = aq ? 1 : qe ? 1 : qm ? was_quoted (qm, i) : 0;
    100          
    100          
1194             else {
1195              
1196 52476 100         if (SvUTF8 (sv)) {
1197 20041           csv->utf8 = 1;
1198 20041           csv->binary = 1;
1199             }
1200              
1201 52476 100         quoteMe = aq ? 1 : qm ? was_quoted (qm, i) : 0;
    100          
1202              
1203             /* Do we need quoting? We do quote, if the user requested
1204             * (always_quote), if binary or blank characters are found
1205             * and if the string contains quote or escape characters.
1206             */
1207 52476 100         if (!quoteMe &&
1208 46848 100         ( quoteMe = (!SvIOK (sv) && !SvNOK (sv) && CH_QUOTE))) {
    100          
    100          
    100          
1209             char *ptr2;
1210             STRLEN l;
1211              
1212             #if MAINT_DEBUG > 6
1213             (void)fprintf (stderr, "# %04d Combine:\n", __LINE__);
1214             sv_dump (sv);
1215             #else
1216             #if MAINT_DEBUG > 4
1217             (void)fprintf (stderr, "# %04d Combine: '%s'\n", __LINE__, _pretty_sv (sv));
1218             #endif
1219             #endif
1220 86089 100         for (ptr2 = ptr, l = len; l; ++ptr2, --l) {
1221 83956           byte c = *ptr2;
1222             #ifdef IS_EBCDIC
1223             byte x = ebcdic2ascii[c];
1224             #if MAINT_DEBUG > 4
1225             (void)fprintf (stderr, " %02x", x);
1226             #endif
1227             #else
1228 83956           byte x = c;
1229             #endif
1230              
1231 83956 50         if ((CH_QUOTE && c == CH_QUOTE) ||
    100          
1232 83648 100         (CH_SEP && c == CH_SEP) ||
    100          
1233 166770 100         (csv->escape_char && c == csv->escape_char) ||
    100          
    100          
    100          
1234 146515 100         (csv->quote_binary ? (x >= 0x7f && x <= 0xa0) ||
    100          
    100          
1235 63242 100         x < csv->first_safe_char
1236 20 50         : c == CH_NL || c == CH_CR ||
    50          
1237 10 100         (csv->quote_space && (
    100          
1238 3 50         c == CH_SPACE || c == CH_TAB)))) {
1239             /* Binary character */
1240             break;
1241             }
1242             }
1243             #if defined(IS_EBCDIC) && MAINT_DEBUG > 4
1244             (void)fprintf (stderr, "\n");
1245             #endif
1246 25265           quoteMe = (l > 0);
1247             }
1248             }
1249 53888 100         if (quoteMe) {
1250 29414 50         CSV_PUT (csv, dst, CH_QUOTE);
    0          
1251 29414 100         if (csv->quo_len) {
1252             int x;
1253 51 100         for (x = 1; x < (int)csv->quo_len; x++)
1254 34 50         CSV_PUT (csv, dst, csv->quo[x]);
    0          
1255             }
1256             }
1257 950415535 100         while (len-- > 0) {
1258 950361654           char c = *ptr++;
1259 950361654           int e = 0;
1260              
1261 950361654 100         if (!csv->binary && is_csv_binary (c)) {
    100          
    50          
    100          
1262 7           SvREFCNT_inc (sv);
1263 7           csv->has_error_input = 1;
1264 7 50         unless (hv_store (csv->self, "_ERROR_INPUT", 12, sv, 0))
1265 0           SvREFCNT_dec (sv); /* uncoverable statement memory fail */
1266 7           (void)SetDiag (csv, 2110);
1267 7           return FALSE;
1268             }
1269 950361647 100         if (CH_QUOTE && (byte)c == CH_QUOTE && (csv->quo_len == 0 ||
    100          
    100          
1270 9 100         memcmp (ptr, csv->quo +1, csv->quo_len - 1) == 0))
1271 3217           e = 1;
1272             else
1273 950358430 100         if (c == csv->escape_char && csv->escape_char)
    100          
1274 2163           e = 1;
1275             else
1276 950356267 100         if (c == (char)0 && csv->escape_null) {
    100          
1277 29           e = 1;
1278 29           c = '0';
1279             }
1280 950361647 100         if (e && csv->escape_char)
    50          
1281 5409 50         CSV_PUT (csv, dst, csv->escape_char);
    0          
1282 950361647 100         CSV_PUT (csv, dst, c);
    50          
1283             }
1284 53881 100         if (quoteMe) {
1285 29407 50         CSV_PUT (csv, dst, CH_QUOTE);
    0          
1286 29407 100         if (csv->quo_len) {
1287             int x;
1288 51 100         for (x = 1; x < (int)csv->quo_len; x++)
1289 34 50         CSV_PUT (csv, dst, csv->quo[x]);
    0          
1290             }
1291             }
1292             }
1293             else {
1294 53 100         if (csv->undef_str) {
1295 8           byte *ptr = csv->undef_str;
1296 8           STRLEN len = strlen ((char *)ptr);
1297              
1298 8 100         if (csv->undef_flg) {
1299 3           csv->utf8 = 1;
1300 3           csv->binary = 1;
1301             }
1302              
1303 28 100         while (len--)
1304 20 50         CSV_PUT (csv, dst, *ptr++);
    0          
1305             }
1306             }
1307             }
1308 21662 100         if (csv->eol_len) {
1309 241           STRLEN len = csv->eol_len;
1310 241           byte *ptr = csv->eol;
1311              
1312 680 100         while (len--)
1313 439 50         CSV_PUT (csv, dst, *ptr++);
    0          
1314             }
1315 21662 100         if (csv->used)
1316 21660           return Print (csv, dst);
1317 2           return TRUE;
1318             } /* Combine */
1319              
1320             #if MAINT_DEBUG > 6
1321             #define ErrorDiag(csv) cx_ErrorDiag (aTHX_ csv)
1322             static void cx_ErrorDiag (pTHX_ csv_t *csv) {
1323             SV **svp;
1324              
1325             if ((svp = hv_fetchs (csv->self, "_ERROR_DIAG", FALSE)) && *svp) {
1326             if (SvIOK (*svp)) (void)fprintf (stderr, "ERR: %d\n", SvIV (*svp));
1327             if (SvPOK (*svp)) (void)fprintf (stderr, "ERR: %s\n", SvPV_nolen (*svp));
1328             }
1329             if ((svp = hv_fetchs (csv->self, "_ERROR_POS", FALSE)) && *svp) {
1330             if (SvIOK (*svp)) (void)fprintf (stderr, "POS: %d\n", SvIV (*svp));
1331             }
1332             if ((svp = hv_fetchs (csv->self, "_ERROR_FLD", FALSE)) && *svp) {
1333             if (SvIOK (*svp)) (void)fprintf (stderr, "FLD: %d\n", SvIV (*svp));
1334             }
1335             if ((svp = hv_fetchs (csv->self, "_ERROR_SRC", FALSE)) && *svp) {
1336             if (SvIOK (*svp)) (void)fprintf (stderr, "SRC: XS#%d\n", SvIV (*svp));
1337             }
1338             } /* ErrorDiag */
1339             #endif
1340              
1341             #define ParseError(csv,xse,pos) cx_ParseError (aTHX_ csv, xse, pos, __LINE__)
1342 326           static void cx_ParseError (pTHX_ csv_t *csv, int xse, STRLEN pos, int line) {
1343 326           (void)hv_store (csv->self, "_ERROR_POS", 10, newSViv (pos), 0);
1344 326           (void)hv_store (csv->self, "_ERROR_FLD", 10, newSViv (csv->fld_idx), 0);
1345 326 50         if (csv->tmp) {
1346 326           csv->has_error_input = 1;
1347 326 50         if (hv_store (csv->self, "_ERROR_INPUT", 12, csv->tmp, 0))
1348 326           SvREFCNT_inc (csv->tmp);
1349             }
1350 326           (void)SetDiagL (csv, xse, line);
1351 323           } /* ParseError */
1352              
1353             #define CsvGet(csv,src) cx_CsvGet (aTHX_ csv, src)
1354 5284           static int cx_CsvGet (pTHX_ csv_t *csv, SV *src) {
1355 5284 100         unless (csv->useIO)
1356 1525           return EOF;
1357              
1358 3759 100         if (csv->tmp && csv->eol_pos >= 0) {
    100          
1359 348           csv->eol_pos = -2;
1360 348           sv_setpvn (csv->tmp, (char *)csv->eol, csv->eol_len);
1361 348           csv->bptr = SvPV (csv->tmp, csv->size);
1362 348           csv->used = 0;
1363 348           return CH_EOLX;
1364             }
1365              
1366             { STRLEN result;
1367 3411           dSP;
1368              
1369 3411 50         PUSHMARK (sp);
1370 3411 50         EXTEND (sp, 1);
1371 3411           PUSHs (src);
1372 3411           PUTBACK;
1373 3411           result = call_sv (m_getline, G_METHOD);
1374 3411           SPAGAIN;
1375 3411           csv->eol_pos = -1;
1376 3411 50         csv->tmp = result ? POPs : NULL;
1377 3411           PUTBACK;
1378              
1379             #if MAINT_DEBUG > 6
1380             (void)fprintf (stderr, "# %04d getline () returned:\n", __LINE__);
1381             sv_dump (csv->tmp);
1382             #else
1383             #if MAINT_DEBUG > 4
1384             (void)fprintf (stderr, "# %04d getline () returned: '%s'\n", __LINE__, _pretty_sv (csv->tmp));
1385             #endif
1386             #endif
1387             }
1388 3411 50         if (csv->tmp && SvOK (csv->tmp)) {
    100          
1389             STRLEN tmp_len;
1390 2812           csv->bptr = SvPV (csv->tmp, tmp_len);
1391 2812           csv->used = 0;
1392 2812           csv->size = tmp_len;
1393 2812 100         if (csv->eolx && csv->size >= csv->eol_len) {
    50          
1394 358           int i, match = 1;
1395 1817 100         for (i = 1; i <= (int)csv->eol_len; i++) {
1396 1463 100         unless (csv->bptr[csv->size - i] == csv->eol[csv->eol_len - i]) {
1397 4           match = 0;
1398 4           break;
1399             }
1400             }
1401 358 100         if (match) {
1402             #if MAINT_DEBUG > 4 || MAIN_DEBUG_EOL > 0
1403             (void)fprintf (stderr, "# %04d EOLX match, size: %d\n", __LINE__, csv->size);
1404             #endif
1405 354           csv->size -= csv->eol_len;
1406 354 100         unless (csv->verbatim)
1407 351           csv->eol_pos = csv->size;
1408 354           csv->bptr[csv->size] = (char)0;
1409 354           SvCUR_set (csv->tmp, csv->size);
1410 354 100         unless (csv->verbatim || csv->size)
    100          
1411 2812           return CH_EOLX;
1412             }
1413             }
1414 2806 100         if (SvUTF8 (csv->tmp)) csv->utf8 = 1;
1415 2806 50         if (tmp_len)
1416 2806           return ((byte)csv->bptr[csv->used++]);
1417             }
1418 599           csv->useIO |= useIO_EOF;
1419 599           return EOF;
1420             } /* CsvGet */
1421              
1422             #define ERROR_INSIDE_QUOTES(diag_code) { \
1423             unless (csv->is_bound) SvREFCNT_dec (sv); \
1424             ParseError (csv, diag_code, csv->used - 1); \
1425             return FALSE; \
1426             }
1427             #define ERROR_INSIDE_FIELD(diag_code) { \
1428             unless (csv->is_bound) SvREFCNT_dec (sv); \
1429             ParseError (csv, diag_code, csv->used - 1); \
1430             return FALSE; \
1431             }
1432             #define ERROR_EOL { \
1433             unless (csv->strict_eol & 0x40) \
1434             ParseError (csv, 2016, csv->used - 1); \
1435             if (csv->strict_eol & 0x0e) { \
1436             if (!csv->is_bound) SvREFCNT_dec (sv); \
1437             return FALSE; \
1438             } \
1439             csv->strict_eol |= 0x40; \
1440             }
1441              
1442             #if MAINT_DEBUG > 4
1443             #define PUT_RPT (void)fprintf (stderr, "# %04d CSV_PUT: 0x%02x '%c'\n", __LINE__, c, isprint (c) ? c : '?')
1444             #define PUT_SEPX_RPT1 (void)fprintf (stderr, "# %04d PUT SEPX\n", __LINE__)
1445             #define PUT_SEPX_RPT2 (void)fprintf (stderr, "# %04d Done putting SEPX\n")
1446             #define PUT_QUOX_RPT1 (void)fprintf (stderr, "# %04d PUT QUOX\n", __LINE__)
1447             #define PUT_QUOX_RPT2 (void)fprintf (stderr, "# %04d Done putting QUOX\n")
1448             #define PUT_EOLX_RPT1 (void)fprintf (stderr, "# %04d PUT EOLX\n", __LINE__)
1449             #define PUT_EOLX_RPT2 (void)fprintf (stderr, "# %04d Done putting EOLX\n")
1450             #if MAINT_DEBUG > 6
1451             #define PUSH_RPT (void)fprintf (stderr, "# %04d AV_PUSHd\n", __LINE__); sv_dump (sv)
1452             #else
1453             #define PUSH_RPT (void)fprintf (stderr, "# %04d AV_PUSHd '%s'\n", __LINE__, _pretty_sv (sv))
1454             #endif
1455             #else
1456             #define PUT_RPT
1457             #define PUT_SEPX_RPT1
1458             #define PUT_SEPX_RPT2
1459             #define PUT_QUOX_RPT1
1460             #define PUT_QUOX_RPT2
1461             #define PUT_EOLX_RPT1
1462             #define PUT_EOLX_RPT2
1463             #define PUSH_RPT
1464             #endif
1465             #define CSV_PUT_SV1(c) { \
1466             len = SvCUR ((sv)); \
1467             SvGROW ((sv), len + 2); \
1468             *SvEND ((sv)) = c; \
1469             PUT_RPT; \
1470             SvCUR_set ((sv), len + 1); \
1471             }
1472             #define CSV_PUT_SV(c) { \
1473             if (c == CH_EOLX) { \
1474             int x; PUT_EOLX_RPT1; \
1475             if (csv->eol_pos == -2) \
1476             csv->size = 0; \
1477             for (x = 0; x < (int)csv->eol_len; x++) \
1478             CSV_PUT_SV1 (csv->eol[x]); \
1479             csv->eol_pos = -1; \
1480             PUT_EOLX_RPT2; \
1481             } \
1482             else if (c == CH_SEPX) { \
1483             int x; PUT_SEPX_RPT1; \
1484             for (x = 0; x < (int)csv->sep_len; x++) \
1485             CSV_PUT_SV1 (csv->sep[x]); \
1486             PUT_SEPX_RPT2; \
1487             } \
1488             else if (c == CH_QUOTEX) { \
1489             int x; PUT_QUOX_RPT1; \
1490             for (x = 0; x < (int)csv->quo_len; x++) \
1491             CSV_PUT_SV1 (csv->quo[x]); \
1492             PUT_QUOX_RPT2; \
1493             } \
1494             else \
1495             CSV_PUT_SV1 (c); \
1496             }
1497              
1498             #define CSV_GET1 \
1499             (csv->used < csv->size ? (byte)csv->bptr[csv->used++] : CsvGet (csv, src))
1500              
1501             #if MAINT_DEBUG > 3
1502             int CSV_GET_ (pTHX_ csv_t *csv, SV *src, int l) {
1503             int c;
1504             (void)fprintf (stderr, "# %04d 1-CSV_GET: (used: %d, size: %d, eol_pos: %d, eolx = %d)\n", l, csv->used, csv->size, csv->eol_pos, csv->eolx);
1505             c = CSV_GET1;
1506             (void)fprintf (stderr, "# %04d 2-CSV_GET: 0x%02x '%c'\n", l, c, isprint (c) ? c : '?');
1507             return (c);
1508             } /* CSV_GET_ */
1509             #define CSV_GET CSV_GET_ (aTHX_ csv, src, __LINE__)
1510             #else
1511             #define CSV_GET CSV_GET1
1512             #endif
1513              
1514             #define AV_PUSH { \
1515             int svc; \
1516             *SvEND (sv) = (char)0; \
1517             svc = SvCUR (sv); \
1518             SvUTF8_off (sv); \
1519             if (svc && csv->formula && *(SvPV_nolen (sv)) == '=') \
1520             (void)_formula (csv, sv, NULL, fnum); \
1521             if (svc == 0 && ( \
1522             csv->empty_is_undef || \
1523             (!(f & CSV_FLAGS_QUO) && csv->blank_is_undef))) \
1524             SvSetUndef (sv); \
1525             else { \
1526             if (csv->allow_whitespace && ! (f & CSV_FLAGS_QUO)) \
1527             strip_trail_whitespace (sv); \
1528             if (f & CSV_FLAGS_BIN && csv->decode_utf8 \
1529             && (csv->utf8 || is_utf8_sv (sv))) \
1530             SvUTF8_on (sv); \
1531             } \
1532             SvSETMAGIC (sv); \
1533             unless (csv->is_bound) av_push (fields, sv); \
1534             PUSH_RPT; \
1535             sv = NULL; \
1536             if (csv->keep_meta_info && fflags) \
1537             av_push (fflags, newSViv (f)); \
1538             waitingForField = 1; \
1539             }
1540              
1541             #define strip_trail_whitespace(sv) cx_strip_trail_whitespace (aTHX_ sv)
1542 1745           static void cx_strip_trail_whitespace (pTHX_ SV *sv) {
1543             STRLEN len;
1544 1745           char *s = SvPV (sv, len);
1545 1745 50         unless (s && len) return;
    50          
1546 1931 100         while (s[len - 1] == CH_SPACE || s[len - 1] == CH_TAB)
    50          
1547 186           s[--len] = (char)0;
1548 1745           SvCUR_set (sv, len);
1549             } /* strip_trail_whitespace */
1550              
1551             #define NewField \
1552             unless (sv) { \
1553             if (csv->is_bound) \
1554             sv = bound_field (csv, fnum, 0); \
1555             else \
1556             sv = newSVpvs (""); \
1557             fnum++; \
1558             unless (sv) return FALSE; \
1559             f = 0; csv->fld_idx++; c0 = 0; \
1560             }
1561              
1562             #if MAINT_DEBUG
1563             static char str_parsed[40];
1564             #endif
1565              
1566             #if MAINT_DEBUG > 1
1567             static char _sep[64];
1568             static char *_sep_string (csv_t *csv) {
1569             if (csv->sep_len) {
1570             int x;
1571             for (x = 0; x < csv->sep_len; x++)
1572             (void)sprintf (_sep + x * x, "%02x ", csv->sep[x]);
1573             }
1574             else
1575             (void)sprintf (_sep, "'%c' (0x%02x)", CH_SEP, CH_SEP);
1576             return _sep;
1577             } /* _sep_string */
1578             #endif
1579              
1580             #define Parse(csv,src,fields,fflags) cx_Parse (aTHX_ csv, src, fields, fflags)
1581 4982           static int cx_Parse (pTHX_ csv_t *csv, SV *src, AV *fields, AV *fflags) {
1582 4982           int c, c0, f = 0;
1583 4982           int waitingForField = 1;
1584 4982           SV *sv = NULL;
1585             STRLEN len;
1586 4982           int seenSomething = FALSE;
1587 4982           int fnum = 0;
1588 4982           int spl = -1;
1589             #if MAINT_DEBUG
1590             (void)memset (str_parsed, 0, 40);
1591             #endif
1592              
1593 4982           csv->fld_idx = 0;
1594              
1595 191473 100         while ((c = CSV_GET) != EOF) {
    100          
1596              
1597 190689 100         NewField;
    100          
    100          
1598              
1599 190685           seenSomething = TRUE;
1600 190685           spl++;
1601             #if MAINT_DEBUG
1602             if (spl < 39) str_parsed[spl] = c;
1603             #endif
1604 11576           restart:
1605             #if MAINT_DEBUG > 9
1606             (void)fprintf (stderr, "# %04d at restart: %d/%d/%03x pos %d = 0x%02x\n",
1607             __LINE__, waitingForField ? 1 : 0, sv ? 1 : 0, f, spl, c);
1608             #endif
1609 202261 100         if (is_SEP (c)) {
    100          
    50          
    100          
    50          
1610             #if MAINT_DEBUG > 1
1611             (void)fprintf (stderr, "# %04d %d/%d/%03x pos %d = SEP %s\t%s\n",
1612             __LINE__, waitingForField ? 1 : 0, sv ? 1 : 0, f, spl,
1613             _sep_string (csv), _pretty_strl (csv->bptr + csv->used));
1614             #endif
1615 12518 100         if (waitingForField) {
1616             /* ,1,"foo, 3",,bar,
1617             * ^ ^
1618             */
1619 1304 100         if (csv->blank_is_undef || csv->empty_is_undef)
    100          
1620 50           SvSetUndef (sv);
1621             else
1622 1254           SvSetEmpty (sv);
1623 1304 50         unless (csv->is_bound)
1624 1304           av_push (fields, sv);
1625 1304           sv = NULL;
1626 1304 100         if (csv->keep_meta_info && fflags)
    50          
1627 8           av_push (fflags, newSViv (f));
1628             }
1629             else
1630 11214 100         if (f & CSV_FLAGS_QUO) {
1631             /* ,1,"foo, 3",,bar,
1632             * ^
1633             */
1634 2194 50         CSV_PUT_SV (c)
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    50          
1635             }
1636             else {
1637             /* ,1,"foo, 3",,bar,
1638             * ^ ^ ^
1639             */
1640 9020 100         AV_PUSH;
    100          
    100          
    100          
    50          
    50          
    50          
    100          
    50          
    100          
    50          
    100          
    100          
    100          
    100          
    100          
    50          
1641             }
1642             } /* SEP char */
1643             else
1644 189743 100         if (is_QUOTE (c)) {
    100          
    100          
    50          
    100          
    50          
1645             #if MAINT_DEBUG > 1
1646             (void)fprintf (stderr, "# %04d %d/%d/%03x pos %d = QUO '%c'\t\t%s\n",
1647             __LINE__, waitingForField ? 1 : 0, sv ? 1 : 0, f, spl, c,
1648             _pretty_strl (csv->bptr + csv->used));
1649             #endif
1650 23060 100         if (waitingForField) {
1651             /* ,1,"foo, 3",,bar,\r\n
1652             * ^
1653             */
1654 11021           f |= CSV_FLAGS_QUO;
1655 11021           waitingForField = 0;
1656 11021           continue;
1657             }
1658              
1659 12039 100         if (f & CSV_FLAGS_QUO) {
1660              
1661             /* ,1,"foo, 3",,bar,\r\n
1662             * ^
1663             */
1664              
1665 11971           int quoesc = 0;
1666 11971 100         int c2 = CSV_GET;
1667              
1668 11971 100         if (csv->allow_whitespace) {
1669             /* , 1 , "foo, 3" , , bar , \r\n
1670             * ^
1671             */
1672 4330 100         while (is_whitespace (c2)) {
    100          
    50          
    100          
    100          
1673 90 100         if (csv->allow_loose_quotes &&
1674 1 50         !(csv->escape_char && c2 == csv->escape_char)) {
    0          
1675             /* This feels like a brittle fix for RT115953, where
1676             * ["foo "bar" baz"] got parsed as [foo "bar"baz]
1677             * when both allow_whitespace and allow_loose_quotes
1678             * are true and escape does not equal quote
1679             */
1680 1 50         CSV_PUT_SV (c);
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    50          
1681 1           c = c2;
1682             }
1683 90 100         c2 = CSV_GET;
1684             }
1685             }
1686              
1687 11971 100         if (is_SEP (c2)) {
    100          
    50          
    50          
    50          
1688             /* ,1,"foo, 3",,bar,\r\n
1689             * ^
1690             */
1691 9027 100         AV_PUSH;
    50          
    0          
    100          
    100          
    50          
    0          
    100          
    50          
    100          
    50          
    100          
    100          
    50          
    100          
    100          
    50          
1692 9027           continue;
1693             }
1694              
1695 2944 100         if (c2 == CH_NL || c2 == CH_EOLX) {
    100          
1696 214 100         unsigned short eolt = EOL_TYPE (c2);
    50          
1697             /* ,1,"foo, 3",,"bar"\n
1698             * ^
1699             */
1700             #if MAINT_DEBUG_EOL > 0
1701             (void)fprintf (stderr, "# %04d parse eol NL/EOLX: '%s'\t(len: %d, is_cr: %d, x: %d, pos: %d, tp: %02x, c: %d, c2: %d)\n",
1702             __LINE__, _pretty_str (csv->eol, csv->eol_len), csv->eol_len, csv->eol_is_cr, csv->eolx, csv->eol_pos, csv->eol_type, c, c2);
1703             #endif
1704 214 100         if (csv->strict_eol && csv->eol_type && csv->eol_type != eolt)
    100          
    100          
1705 6 100         ERROR_EOL;
    100          
    50          
1706 212 100         SET_EOL_TYPE (csv, eolt);
1707              
1708 212 100         AV_PUSH;
    50          
    0          
    100          
    50          
    50          
    0          
    100          
    50          
    100          
    50          
    100          
    100          
    50          
    100          
    100          
    50          
1709 212           return TRUE;
1710             }
1711              
1712             /* ---
1713             * if QUOTE eq ESCAPE
1714             * AND ( c2 eq QUOTE 1,"abc""def",2
1715             * OR c2 eq ESCAPE 1,"abc""def",2 (QUO eq ESC)
1716             * OR c2 eq NULL ) 1,"abc"0def",2
1717             * ---
1718             */
1719 2730 100         if (csv->escape_char && c == csv->escape_char) {
    100          
1720              
1721 1633           quoesc = 1;
1722 1633 100         if (c2 == '0') {
1723             /* ,1,"foo, 3"056",,bar,\r\n
1724             * ^
1725             */
1726 25 50         CSV_PUT_SV (0)
    50          
1727 25           continue;
1728             }
1729              
1730 1608 50         if (is_QUOTE (c2)) {
    100          
    50          
    0          
    0          
    0          
1731             /* ,1,"foo, 3""56",,bar,\r\n
1732             * ^
1733             */
1734 1060 100         if (csv->utf8)
1735 1           f |= CSV_FLAGS_BIN;
1736 1060 50         CSV_PUT_SV (c2)
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    100          
1737 1060           continue;
1738             }
1739              
1740 548 100         if (csv->allow_loose_escapes && c2 != CH_CR) {
    100          
1741             /* ,1,"foo, 3"56",,bar,\r\n
1742             * ^
1743             */
1744 2 50         CSV_PUT_SV (c);
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    50          
1745 2           c = c2;
1746 2           goto restart;
1747             }
1748             }
1749              
1750 1643 100         if (c2 == CH_CR) {
1751             int c3;
1752              
1753 280 100         if (csv->eol_is_cr) {
1754             /* ,1,"foo, 3"\r
1755             * ^
1756             */
1757             #if MAINT_DEBUG_EOL > 0
1758             (void)fprintf (stderr, "# %04d parse eol CR: '%s'\t(len: %d, is_cr: %d, x: %d, pos: %d, tp: %02x, c: %d, c2: %d, c3: %d)\n",
1759             __LINE__, _pretty_str (csv->eol, csv->eol_len), csv->eol_len, csv->eol_is_cr, csv->eolx, csv->eol_pos, csv->eol_type, c, c2);
1760             #endif
1761 109 100         AV_PUSH;
    50          
    0          
    100          
    50          
    50          
    0          
    100          
    50          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
1762 109           return TRUE;
1763             }
1764              
1765 171 100         c3 = CSV_GET;
1766              
1767 171 100         if (c3 == CH_NL) { /* \r is not optional before EOLX! */
1768             /* ,1,"foo, 3"\r\n
1769             * ^
1770             */
1771             #if MAINT_DEBUG_EOL > 0
1772             (void)fprintf (stderr, "# %04d parse eol CRNL: '%s'\t(len: %d, is_cr: %d, x: %d, pos: %d, tp: %02x, c: %d, c2: %d, c3: %d)\n",
1773             __LINE__, _pretty_str (csv->eol, csv->eol_len), csv->eol_len, csv->eol_is_cr, csv->eolx, csv->eol_pos, csv->eol_type, c, c2, c3);
1774             #endif
1775 139 100         if (csv->strict_eol && csv->eol_type && csv->eol_type != EOL_TYPE_CRNL)
    100          
    50          
1776 0 0         ERROR_EOL;
    0          
    0          
1777 139 100         SET_EOL_TYPE (csv, EOL_TYPE_CRNL);
1778              
1779 139 100         AV_PUSH;
    50          
    0          
    100          
    50          
    50          
    0          
    100          
    50          
    100          
    50          
    100          
    50          
    50          
    50          
    50          
    0          
1780 139           return TRUE;
1781             }
1782              
1783 32 100         if (csv->useIO && csv->eol_len == 0) {
    50          
1784 19 100         if (c3 == CH_CR) { /* \r followed by an empty line */
1785             /* ,1,"foo, 3"\r\r
1786             * ^
1787             */
1788             #if MAINT_DEBUG_EOL > 0
1789             (void)fprintf (stderr, "# %04d parse set CR: '%s'\t(len: %d, is_cr: %d, x: %d, pos: %d, tp: %02x, c: %d, c2: %d, c3: %d)\n",
1790             __LINE__, _pretty_str (csv->eol, csv->eol_len), csv->eol_len, csv->eol_is_cr, csv->eolx, csv->eol_pos, csv->eol_type, c, c2, c3);
1791             #endif
1792 8 100         if (csv->strict_eol && csv->eol_type) {
    100          
1793 2 50         unless (csv->eol_type == EOL_TYPE_CR)
1794 2 50         ERROR_EOL;
    50          
    0          
1795 2           csv->used--;
1796 2           csv->has_ahead++;
1797 2 50         AV_PUSH;
    50          
    0          
    50          
    0          
    0          
    0          
    50          
    0          
    50          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
1798 2           return TRUE;
1799             }
1800              
1801 6           set_eol_is_cr (csv);
1802 6 50         if (f & CSV_FLAGS_QUO) f ^= CSV_FLAGS_QUO;
1803 6           c = c0 = CH_CR;
1804 6           goto EOLX;
1805             }
1806              
1807 11 50         if (!is_csv_binary (c3)) {
    50          
    0          
1808             /* ,1,"foo\n 3",,"bar"\r
1809             * baz,4
1810             * ^
1811             */
1812             #if MAINT_DEBUG_EOL > 0
1813             (void)fprintf (stderr, "# %04d parse set CR/BIN: '%s'\t(len: %d, is_cr: %d, x: %d, pos: %d, tp: %02x, c: %d, c2: %d, c3: %d)\n",
1814             __LINE__, _pretty_str (csv->eol, csv->eol_len), csv->eol_len, csv->eol_is_cr, csv->eolx, csv->eol_pos, csv->eol_type, c, c2, c3);
1815             #endif
1816 11 100         if (csv->strict_eol && csv->eol_type) {
    100          
1817 2 50         unless (csv->eol_type == EOL_TYPE_CR)
1818 2 50         ERROR_EOL;
    50          
    0          
1819 2           csv->eol_is_cr = 1;
1820             }
1821             else
1822 9           set_eol_is_cr (csv);
1823 11           csv->used--;
1824 11           csv->has_ahead++;
1825 11 50         AV_PUSH;
    50          
    0          
    50          
    0          
    0          
    0          
    50          
    0          
    50          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
1826 11           return TRUE;
1827             }
1828             }
1829              
1830 13 100         ParseError (csv, quoesc ? 2023 : 2010, csv->used - 2);
1831 13           return FALSE;
1832             }
1833              
1834 1363 100         if (c2 == EOF) {
1835             /* ,1,"foo, 3"
1836             * ^
1837             */
1838 1306 100         AV_PUSH;
    50          
    0          
    100          
    50          
    50          
    0          
    100          
    50          
    100          
    50          
    100          
    100          
    50          
    50          
    100          
    50          
1839 1306           return TRUE;
1840             }
1841              
1842 57 100         if (csv->allow_loose_quotes && !quoesc) {
    100          
1843             /* ,1,"foo, 3"456",,bar,\r\n
1844             * ^
1845             */
1846 10 50         CSV_PUT_SV (c);
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    50          
1847 10           c = c2;
1848 10           goto restart;
1849             }
1850              
1851             /* 1,"foo" ",3
1852             * ^
1853             */
1854 47 100         if (quoesc) {
1855 39           csv->used--;
1856 39 50         ERROR_INSIDE_QUOTES (2023);
1857             }
1858              
1859 8 50         ERROR_INSIDE_QUOTES (2011);
1860             }
1861              
1862             /* !waitingForField, !InsideQuotes */
1863 68 100         if (csv->allow_loose_quotes) { /* 1,foo "boo" d'uh,1 */
1864 16           f |= CSV_FLAGS_EIF; /* Mark as error-in-field */
1865 16 50         CSV_PUT_SV (c);
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    50          
1866             }
1867             else
1868 52 100         ERROR_INSIDE_FIELD (2034);
1869             } /* QUO char */
1870             else
1871 166683 100         if (c == csv->escape_char && csv->escape_char) {
    100          
1872             #if MAINT_DEBUG > 1
1873             (void)fprintf (stderr, "# %04d %d/%d/%03x pos %d = ESC '%c'\t%s\n",
1874             __LINE__, waitingForField ? 1 : 0, sv ? 1 : 0, f, spl, c,
1875             _pretty_strl (csv->bptr + csv->used));
1876             #endif
1877             /* This means quote_char != escape_char */
1878 4651 100         if (waitingForField) {
1879 33           waitingForField = 0;
1880 33 100         if (csv->allow_unquoted_escape) {
1881             /* The escape character is the first character of an
1882             * unquoted field */
1883             /* ... get and store next character */
1884 3 100         int c2 = CSV_GET;
1885              
1886 3           SvSetEmpty (sv);
1887              
1888 3 100         if (c2 == EOF) {
1889 1           csv->used--;
1890 1 50         ERROR_INSIDE_FIELD (2035);
1891             }
1892              
1893 2 100         if (c2 == '0')
1894 1 50         CSV_PUT_SV (0)
    50          
1895             else
1896 1 50         if ( is_QUOTE (c2) || is_SEP (c2) ||
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
1897 0 0         c2 == csv->escape_char || csv->allow_loose_escapes) {
    0          
1898 1 50         if (csv->utf8)
1899 0           f |= CSV_FLAGS_BIN;
1900 1 50         CSV_PUT_SV (c2)
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    50          
1901             }
1902             else {
1903 0           csv->used--;
1904 0 0         ERROR_INSIDE_QUOTES (2025);
1905             }
1906             }
1907             }
1908             else
1909 4618 100         if (f & CSV_FLAGS_QUO) {
1910 4610 100         int c2 = CSV_GET;
1911              
1912 4610 100         if (c2 == EOF) {
1913 3           csv->used--;
1914 3 50         ERROR_INSIDE_QUOTES (2024);
1915             }
1916              
1917 4607 100         if (c2 == '0')
1918 2 50         CSV_PUT_SV (0)
    50          
1919             else
1920 4605 50         if ( is_QUOTE (c2) || is_SEP (c2) ||
    100          
    100          
    50          
    50          
    50          
    100          
    50          
    0          
    0          
    0          
1921 2193 100         c2 == csv->escape_char || csv->allow_loose_escapes) {
    100          
1922 4579 100         if (csv->utf8)
1923 1           f |= CSV_FLAGS_BIN;
1924 4582 50         CSV_PUT_SV (c2)
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    100          
    50          
    50          
    100          
    50          
    50          
1925             }
1926             else {
1927 26           csv->used--;
1928 26 50         ERROR_INSIDE_QUOTES (2025);
1929             }
1930             }
1931             else
1932 8 50         if (sv) {
1933 8 100         int c2 = CSV_GET;
1934              
1935 8 100         if (c2 == EOF) {
1936 4           csv->used--;
1937 4 50         ERROR_INSIDE_FIELD (2035);
1938             }
1939              
1940 4 50         CSV_PUT_SV (c2);
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    50          
1941             }
1942             else
1943 0 0         ERROR_INSIDE_FIELD (2036); /* uncoverable statement I think there's no way to get here */
1944             } /* ESC char */
1945             else
1946 162771 100         if (c == CH_NL || is_EOL (c)) {
    100          
1947             unsigned short eolt;
1948 2283           EOLX:
1949 2925 100         eolt = ((c == CH_NL || c == CH_CR) && c0 == CH_CR) ? EOL_TYPE_CRNL : EOL_TYPE (c);
    100          
    100          
    100          
    50          
1950             #if MAINT_DEBUG > 1 || MAINT_DEBUG_EOL > 0
1951             (void)fprintf (stderr, "# %04d EOLX: %d/%d/%03x pos %d = NL, eolx = %d, eol_pos = %d, tp: %02x/%02x\t%s (eol = %s, strict_eol = %d, c = 0x%04x, c0 = 0x%04x)\n",
1952             __LINE__, waitingForField ? 1 : 0, sv ? 1 : 0, f, spl, csv->eolx, csv->eol_pos, csv->eol_type, eolt,
1953             _pretty_strl (csv->bptr + csv->used), _pretty_strl (csv->eol), csv->strict_eol, c, c0);
1954             #endif
1955 2925           c0 = 0;
1956 2925 100         unless (f & CSV_FLAGS_QUO) {
1957 2175 100         if (csv->strict_eol && csv->eol_type && csv->eol_type != eolt)
    100          
    100          
1958 37 100         ERROR_EOL;
    100          
    50          
1959 2170 100         SET_EOL_TYPE (csv, eolt);
1960             }
1961              
1962 2920 100         if (fnum == 1 && f == 0 && SvCUR (sv) == 0 && csv->skip_empty_rows) {
    100          
    100          
    100          
1963 143 100         SkipEmptyRow;
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    100          
    50          
    50          
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    0          
    50          
    0          
    0          
    0          
    50          
    0          
    50          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    100          
1964 65           goto restart;
1965             }
1966              
1967 2829 100         if (waitingForField) {
1968             /* ,1,"foo, 3",,bar,
1969             * ^
1970             */
1971 263 100         if (csv->blank_is_undef || csv->empty_is_undef)
    100          
1972 16           SvSetUndef (sv);
1973             else
1974 247           SvSetEmpty (sv);
1975 263 50         unless (csv->is_bound)
1976 263           av_push (fields, sv);
1977 263 100         if (csv->keep_meta_info && fflags)
    50          
1978 14           av_push (fflags, newSViv (f));
1979 263           return TRUE;
1980             }
1981              
1982 2566 100         if (f & CSV_FLAGS_QUO) {
1983             /* ,1,"foo\n 3",,bar,
1984             * ^
1985             */
1986 750           f |= CSV_FLAGS_BIN;
1987 750 100         unless (csv->binary)
1988 19 50         ERROR_INSIDE_QUOTES (2021);
1989              
1990 805 100         CSV_PUT_SV (c);
    100          
    50          
    50          
    100          
    50          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    50          
1991             }
1992             else
1993 1816 100         if (csv->verbatim) {
1994             /* ,1,foo\n 3,,bar,
1995             * This feature should be deprecated
1996             */
1997 9           f |= CSV_FLAGS_BIN;
1998 9 100         unless (csv->binary)
1999 1 50         ERROR_INSIDE_FIELD (2030);
2000              
2001 14 100         CSV_PUT_SV (c);
    50          
    50          
    100          
    100          
    50          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    100          
2002             }
2003             else {
2004             /* sep=,
2005             * ^
2006             */
2007 1807 100         if (csv->recno == 0 && csv->fld_idx == 1 && csv->useIO &&
    100          
    50          
2008 29 100         (csv->bptr[0] == 's' || csv->bptr[0] == 'S') &&
    50          
2009 5 50         (csv->bptr[1] == 'e' || csv->bptr[1] == 'E') &&
    0          
2010 5 50         (csv->bptr[2] == 'p' || csv->bptr[2] == 'P') &&
    0          
2011 5 50         csv->bptr[3] == '=') {
2012 5           char *sep = csv->bptr + 4;
2013 5           int lnu = csv->used - 5;
2014 5 100         if (lnu <= MAX_ATTR_LEN) {
2015 4           sep[lnu] = (char)0;
2016 4           (void)memcpy (csv->sep, sep, lnu);
2017 4 100         csv->sep_len = lnu == 1 ? 0 : lnu;
2018 4           return Parse (csv, src, fields, fflags);
2019             }
2020             }
2021              
2022             /* ,1,"foo\n 3",,bar
2023             * ^
2024             */
2025 1803 100         AV_PUSH;
    100          
    100          
    100          
    50          
    50          
    50          
    100          
    50          
    100          
    50          
    100          
    100          
    100          
    100          
    100          
    50          
2026 1803           return TRUE;
2027             }
2028             } /* CH_NL */
2029             else
2030 159749 100         if (c == CH_CR && !(csv->verbatim)) {
    100          
2031             #if MAINT_DEBUG > 1 || MAINT_DEBUG_EOL > 0
2032             (void)fprintf (stderr, "# %04d %d/%d/%03x pos %d = CR, eolx = %d, eol_pos = %d, tp: %02x (cr: %d)\t%s (eol = %s)\n",
2033             __LINE__, waitingForField ? 1 : 0, sv ? 1 : 0, f, spl, csv->eolx, csv->eol_pos, csv->eol_type, csv->eol_is_cr,
2034             _pretty_strl (csv->bptr + csv->used), _pretty_strl (csv->eol));
2035             #endif
2036 1329           c0 = CH_CR;
2037 1329 100         if (waitingForField) {
2038             int c2;
2039              
2040 169 100         if (csv->eol_is_cr) {
2041             /* ,1,"foo\n 3",,bar,\r
2042             * ^
2043             */
2044 46           c = CH_NL;
2045 46           goto EOLX;
2046             }
2047              
2048 123 100         c2 = CSV_GET;
2049              
2050 123 100         if (c2 == EOF) {
2051             /* ,1,"foo\n 3",,bar,\r
2052             * ^
2053             */
2054 5           c = EOF;
2055              
2056             #if MAINT_DEBUG > 9
2057             (void)fprintf (stderr, "# %04d (%d) ... CR EOF 0x%x\n",
2058             __LINE__, seenSomething, c);
2059             #endif
2060 5 50         unless (seenSomething)
2061 0           break;
2062 5           goto restart;
2063             }
2064              
2065 118 100         if (c2 == CH_NL) { /* \r is not optional before EOLX! */
2066             /* ,1,"foo\n 3",,bar,\r\n
2067             * ^
2068             */
2069 97 100         if (csv->strict_eol && csv->eol_type && csv->eol_type != EOL_TYPE_CRNL)
    100          
    50          
2070 0 0         ERROR_EOL;
    0          
    0          
2071 97 100         SET_EOL_TYPE (csv, EOL_TYPE_CRNL);
2072              
2073             #if MAINT_DEBUG > 1 || MAINT_DEBUG_EOL > 0
2074             (void)fprintf (stderr, "# %04d %d/%d/%03x pos %d = CRNL, eolx = %d, eol_pos = %d, tp: %02x (cr: %d, c0: %d)\t%s (eol = %s)\n",
2075             __LINE__, waitingForField ? 1 : 0, sv ? 1 : 0, f, spl, csv->eolx, csv->eol_pos, csv->eol_type, csv->eol_is_cr, c0,
2076             _pretty_strl (csv->bptr + csv->used), _pretty_strl (csv->eol));
2077             #endif
2078 97           c = c2;
2079 97           goto EOLX;
2080             }
2081              
2082 21 100         if (csv->useIO && csv->eol_len == 0) {
    50          
2083 16 50         if (c2 == CH_CR) { /* \r followed by an empty line */
2084             /* ,1,"foo\n 3",,bar,\r\r
2085             * ^
2086             */
2087 0 0         if (csv->strict_eol && csv->eol_type) {
    0          
2088 0 0         unless (csv->eol_type == EOL_TYPE_CR)
2089 0 0         ERROR_EOL;
    0          
    0          
2090 0           csv->eol_is_cr = 1;
2091             }
2092             else
2093 0           set_eol_is_cr (csv);
2094 0           goto EOLX;
2095             }
2096              
2097 16           waitingForField = 0;
2098              
2099 16 100         if (!is_csv_binary (c2)) {
    50          
    50          
2100             /* ,1,"foo\n 3",,bar,\r
2101             * baz,4
2102             * ^
2103             */
2104 13 100         if (csv->strict_eol && csv->eol_type) {
    100          
2105 4 50         unless (csv->eol_type == EOL_TYPE_CR)
2106 4 50         ERROR_EOL;
    50          
    0          
2107             }
2108             else
2109 9           set_eol_is_cr (csv);
2110 13           csv->used--;
2111 13           csv->has_ahead++;
2112 13 100         if (fnum == 1 && f == 0 && SvCUR (sv) == 0 && csv->skip_empty_rows) {
    50          
    50          
    100          
2113 6 50         SkipEmptyRow;
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
2114 6           goto restart;
2115             }
2116 7 50         AV_PUSH;
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    0          
    50          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
2117 7           return TRUE;
2118             }
2119             }
2120              
2121             /* ,1,"foo\n 3",,bar,\r\t
2122             * ^
2123             */
2124 8           csv->used--;
2125 8 50         ERROR_INSIDE_FIELD (2031);
2126             }
2127              
2128 1160 100         if (f & CSV_FLAGS_QUO) {
2129             /* ,1,"foo\r 3",,bar,\r\t
2130             * ^
2131             */
2132 641           f |= CSV_FLAGS_BIN;
2133 641 100         unless (csv->binary)
2134 70 50         ERROR_INSIDE_QUOTES (2022);
2135              
2136 571 50         CSV_PUT_SV (c);
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    100          
2137             }
2138             else {
2139             int c2;
2140              
2141 519 100         if (csv->eol_is_cr) {
2142             /* ,1,"foo\n 3",,bar\r
2143             * ^
2144             */
2145 192           goto EOLX;
2146             }
2147              
2148 327 100         c2 = CSV_GET;
2149              
2150 327 100         if (c2 == CH_NL) { /* \r is not optional before EOLX! */
2151             /* ,1,"foo\n 3",,bar\r\n
2152             * ^
2153             */
2154 293 100         if (csv->strict_eol && csv->eol_type && csv->eol_type != EOL_TYPE_CRNL)
    100          
    100          
2155 10 100         ERROR_EOL;
    50          
    0          
2156 293 100         SET_EOL_TYPE (csv, EOL_TYPE_CRNL);
2157              
2158             #if MAINT_DEBUG > 1 || MAINT_DEBUG_EOL > 0
2159             (void)fprintf (stderr, "# %04d %d/%d/%03x pos %d = CRNL, eolx = %d, eol_pos = %d, tp: %02x (cr: %d, c0: %d)\t%s (eol = %s)\n",
2160             __LINE__, waitingForField ? 1 : 0, sv ? 1 : 0, f, spl, csv->eolx, csv->eol_pos, csv->eol_type, csv->eol_is_cr, c0,
2161             _pretty_strl (csv->bptr + csv->used), _pretty_strl (csv->eol));
2162             #endif
2163 293           goto EOLX;
2164             }
2165              
2166 34 100         if (csv->useIO && csv->eol_len == 0) {
    50          
2167 29 100         if (!is_csv_binary (c2)
    50          
    50          
2168             /* ,1,"foo\n 3",,bar\r
2169             * baz,4
2170             * ^
2171             */
2172 15 100         || c2 == CH_CR) {
2173             /* ,1,"foo\n 3",,bar,\r\r
2174             * ^
2175             */
2176             #if MAINT_DEBUG_EOL > 0
2177             (void)fprintf (stderr, "# %04d parse eol CR/IO: '%s'\t(len: %d, is_cr: %d, x: %d, pos: %d, tp: %02x, c: %d, c2: %d)\n",
2178             __LINE__, _pretty_str (csv->eol, csv->eol_len), csv->eol_len, csv->eol_is_cr, csv->eolx, csv->eol_pos, csv->eol_type, c, c2);
2179             #endif
2180 23 100         if (csv->strict_eol && csv->eol_type) {
    100          
2181 4 50         unless (csv->eol_type == EOL_TYPE_CR)
2182 4 50         ERROR_EOL;
    50          
    0          
2183             }
2184             else
2185 19           set_eol_is_cr (csv);
2186 23           csv->used--;
2187 23           csv->has_ahead++;
2188 23 50         if (fnum == 1 && f == 0 && SvCUR (sv) == 0 && csv->skip_empty_rows) {
    0          
    0          
    0          
2189 0 0         SkipEmptyRow;
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
2190 0           goto restart;
2191             }
2192 23 50         AV_PUSH;
    50          
    0          
    50          
    0          
    0          
    0          
    50          
    0          
    50          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
2193 23           return TRUE;
2194             }
2195             }
2196              
2197             /* ,1,"foo\n 3",,bar\r\t
2198             * ^
2199             */
2200 11 50         ERROR_INSIDE_FIELD (2032);
2201             }
2202             } /* CH_CR */
2203             else {
2204             #if MAINT_DEBUG > 1
2205             (void)fprintf (stderr, "# %04d %d/%d/%03x pos %d = CCC '%c'\t\t%s\n",
2206             __LINE__, waitingForField ? 1 : 0, sv ? 1 : 0, f, spl, c,
2207             _pretty_strl (csv->bptr + csv->used));
2208             #endif
2209             /* Needed for non-IO parse, where EOL is not set during read */
2210 158420 100         if (csv->eolx && c == CH_EOL &&
    100          
2211 8 50         csv->size - csv->used >= (STRLEN)csv->eol_len - 1 &&
2212 8 50         !memcmp (csv->bptr + csv->used, csv->eol + 1, csv->eol_len - 1) &&
2213 8 50         (csv->used += csv->eol_len - 1)) {
2214 8           c = CH_EOLX;
2215             #if MAINT_DEBUG > 5 || MAINT_DEBUG_EOL > 0
2216             (void)fprintf (stderr, "# %04d -> EOLX (0x%x)\n", __LINE__, c);
2217             #endif
2218 8           goto EOLX;
2219             }
2220              
2221 158412 100         if (waitingForField) {
2222 11493 100         if (csv->comment_str && !f && !spl && c == *csv->comment_str) {
    50          
    100          
    100          
2223 35           STRLEN cl = strlen ((char *)csv->comment_str);
2224              
2225             #if MAINT_DEBUG > 5
2226             (void)fprintf (stderr,
2227             "# %04d COMMENT? cl = %d, size = %d, used = %d\n",
2228             __LINE__, cl, csv->size, csv->used);
2229             #endif
2230 35 100         if (cl == 1 || (
2231 18 50         (csv->size - csv->used >= cl - 1 &&
2232 18 50         !memcmp (csv->bptr + csv->used, csv->comment_str + 1, cl - 1) &&
2233 18 50         (csv->used += cl - 1)))) {
2234 35           csv->used = csv->size;
2235 35 100         csv->fld_idx = csv->strict_n ? csv->strict_n - 1 : 0;
2236 35 50         c = CSV_GET;
2237 35           seenSomething = FALSE;
2238             #if MAINT_DEBUG > 5
2239             (void)fprintf (stderr, "# %04d COMMENT, SKIPPED\n", __LINE__);
2240             #endif
2241 35 100         unless (csv->useIO)
2242 1           csv->has_ahead = 214; /* abuse */
2243 35 100         if (c == EOF)
2244 4           break;
2245 31           goto restart;
2246             }
2247             }
2248              
2249 11458 100         if (csv->allow_whitespace && is_whitespace (c)) {
    50          
    50          
    50          
    100          
    50          
2250             do {
2251 321 100         c = CSV_GET;
2252             #if MAINT_DEBUG > 5
2253             (void)fprintf (stderr, "# %04d WS next got (0x%x)\n", __LINE__, c);
2254             #endif
2255 321 100         } while (is_whitespace (c));
    100          
    50          
    100          
    50          
2256 211 100         if (c == EOF)
2257 1           break;
2258 210           goto restart;
2259             }
2260 11247           waitingForField = 0;
2261 11247           goto restart;
2262             }
2263              
2264             #if MAINT_DEBUG > 5
2265             (void)fprintf (stderr, "# %04d %sc 0x%x is%s binary %s utf8\n",
2266             __LINE__, f & CSV_FLAGS_QUO ? "quoted " : "", c,
2267             is_csv_binary (c) ? "" : " not",
2268             csv->utf8 ? "is" : "not");
2269             #endif
2270 146919 100         if (f & CSV_FLAGS_QUO) {
2271 111602 100         if (is_csv_binary (c)) {
    100          
    100          
2272 3454           f |= CSV_FLAGS_BIN;
2273 3454 100         unless (csv->binary || csv->utf8)
    100          
2274 5 50         ERROR_INSIDE_QUOTES (2026);
2275             }
2276 111597 50         CSV_PUT_SV (c);
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    100          
2277             }
2278             else {
2279 35317 100         if (is_csv_binary (c)) {
    100          
    100          
2280 453 100         if (csv->useIO && c == EOF)
    100          
2281 3           break;
2282 450           f |= CSV_FLAGS_BIN;
2283 450 100         unless (csv->binary || csv->utf8)
    50          
2284 9 50         ERROR_INSIDE_FIELD (2037);
2285             }
2286 35305 50         CSV_PUT_SV (c);
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    100          
2287             }
2288             }
2289              
2290             /* continue */
2291 165361 100         if (csv->verbatim && csv->useIO && csv->used == csv->size)
    100          
    100          
2292 3           break;
2293             }
2294              
2295 801 100         if (waitingForField) {
2296 418 100         unless (csv->useIO) {
2297 27 100         if (csv->has_ahead == 214)
2298 1           return TRUE;
2299 26           seenSomething++;
2300             }
2301 417 100         if (seenSomething) {
2302 35 100         NewField;
    100          
    50          
2303 35 100         if (csv->blank_is_undef || csv->empty_is_undef)
    100          
2304 8           SvSetUndef (sv);
2305             else
2306 27           SvSetEmpty (sv);
2307 35 100         unless (csv->is_bound)
2308 34           av_push (fields, sv);
2309 35 100         if (csv->keep_meta_info && fflags)
    50          
2310 3           av_push (fflags, newSViv (f));
2311 35           return TRUE;
2312             }
2313              
2314 382           (void)SetDiag (csv, 2012);
2315 382           return FALSE;
2316             }
2317              
2318 383 100         if (f & CSV_FLAGS_QUO)
2319 24 50         ERROR_INSIDE_QUOTES (2027);
2320              
2321 359 50         if (sv) {
2322 359 100         AV_PUSH;
    100          
    100          
    100          
    50          
    50          
    50          
    100          
    50          
    100          
    50          
    100          
    100          
    100          
    100          
    100          
    50          
2323             }
2324 0 0         else if (f == 0 && fnum == 1 && csv->skip_empty_rows == 1)
    0          
    0          
2325 0           return FALSE;
2326 359           return TRUE;
2327             } /* Parse */
2328              
2329 154           static int hook (pTHX_ HV *hv, const char *cb_name, AV *av) {
2330             SV **svp;
2331             HV *cb;
2332             int res;
2333              
2334             #if MAINT_DEBUG > 1
2335             (void)fprintf (stderr, "# %04d HOOK %s %x\n", __LINE__, cb_name, av);
2336             #endif
2337 308 50         unless ((svp = hv_fetchs (hv, "callbacks", FALSE)) && _is_hashref (*svp))
    50          
    50          
    0          
    50          
    50          
2338 0           return 0; /* uncoverable statement defensive programming */
2339              
2340 154           cb = (HV *)SvRV (*svp);
2341 154           svp = hv_fetch (cb, cb_name, strlen (cb_name), FALSE);
2342 308 50         unless (svp && _is_coderef (*svp))
    50          
    50          
    0          
    50          
    50          
2343 0           return 0;
2344              
2345 154           { dSP;
2346 154           ENTER;
2347 154           SAVETMPS;
2348 154 50         PUSHMARK (SP);
2349 154 50         mXPUSHs (newRV_inc ((SV *)hv));
2350 154 50         mXPUSHs (newRV_inc ((SV *)av));
2351 154           PUTBACK;
2352 154           res = call_sv (*svp, G_SCALAR);
2353 154           SPAGAIN;
2354 154 50         if (res) {
2355 154           SV *rv = POPs;
2356 154 100         if (SvROK (rv) && (rv = SvRV (rv)) && SvPOK (rv)) {
    50          
    50          
2357 65 50         if (strcmp (SvPV_nolen (rv), "skip") == 0)
2358 65           res = 0;
2359             }
2360             }
2361 154           PUTBACK;
2362 154 50         FREETMPS;
2363 154           LEAVE;
2364             }
2365 154           return res;
2366             } /* hook */
2367              
2368             #define c_xsParse(csv,hv,av,avf,src,useIO) cx_c_xsParse (aTHX_ csv, hv, av, avf, src, useIO)
2369 4978           static int cx_c_xsParse (pTHX_ csv_t csv, HV *hv, AV *av, AV *avf, SV *src, bool useIO) {
2370 4978           int result, ahead = 0;
2371 4978           SV *pos = NULL;
2372              
2373 4978           ENTER;
2374 4978 100         if (csv.eolx || csv.eol_is_cr) {
    100          
2375             /* local $/ = $eol */
2376             #if MAINT_DEBUG_EOL > 0
2377             (void)fprintf (stderr, "# %04d Parse EOLX/RS: '%s'\t(len: %d, is_cr: %d, x: %d, pos: %d, tp: %02x)\n",
2378             __LINE__, _pretty_str (csv.eol, csv.eol_len), csv.eol_len, csv.eol_is_cr, csv.eolx, csv.eol_pos, csv.eol_type);
2379             #endif
2380 894           SAVEGENERICSV (PL_rs);
2381 894           PL_rs = newSVpvn ((char *)csv.eol, csv.eol_len);
2382             }
2383              
2384 4978 100         if ((csv.useIO = useIO)) {
2385 3041           csv.tmp = NULL;
2386              
2387 3041 100         if ((ahead = csv.has_ahead)) {
2388             SV **svp;
2389 232 50         if ((svp = hv_fetchs (hv, "_AHEAD", FALSE)) && *svp) {
    50          
2390 232           csv.bptr = SvPV (csv.tmp = *svp, csv.size);
2391 232           csv.used = 0;
2392 232 50         if (pos && SvIV (pos) > (IV)csv.size)
    0          
2393 0           sv_setiv (pos, SvIV (pos) - csv.size);
2394             }
2395             }
2396             }
2397             else {
2398 1937           csv.tmp = src;
2399 1937           csv.utf8 = SvUTF8 (src) ? 1 : 0;
2400 1937           csv.bptr = SvPV (src, csv.size);
2401             }
2402 4978 100         if (csv.has_error_input) {
2403 227           (void)hv_store (hv, "_ERROR_INPUT", 12, &PL_sv_undef, 0);
2404 227           csv.has_error_input = 0;
2405             }
2406              
2407 4978           result = Parse (&csv, src, av, avf);
2408 4967           (void)hv_store (hv, "_RECNO", 6, newSViv (++csv.recno), 0);
2409 4967           (void)hv_store (hv, "_EOF", 4, &PL_sv_no, 0);
2410              
2411 4967 100         if (csv.strict) {
2412 60 100         STRLEN nf = csv.is_bound ? csv.fld_idx ? csv.fld_idx - 1 : 0 : av_len (av);
    50          
2413             #if MAINT_DEBUG > 6
2414             (void)fprintf (stderr, "# %04d Strict nf = %2d, n = %2d, idx = %2d, recno = %2d, res = %d\n",
2415             __LINE__, nf, csv.strict_n, csv.fld_idx, csv.recno, result);
2416             #endif
2417              
2418 60 100         if (nf && !csv.strict_n) csv.strict_n = (short)nf;
    100          
2419 60 50         if (csv.strict_n > 0 && nf != (STRLEN)csv.strict_n) {
    100          
2420 25 100         unless (csv.useIO & useIO_EOF) {
2421             #if MAINT_DEBUG > 6
2422             ErrorDiag (&csv);
2423             #endif
2424 18 100         unless (last_error || (!csv.useIO && csv.has_ahead))
    100          
    100          
2425 16           ParseError (&csv, 2014, csv.used);
2426             }
2427 25 100         if (last_error) /* an error callback can reset and accept */
2428 20           result = FALSE;
2429             }
2430             }
2431              
2432 4967 100         if (csv.useIO) {
2433 3127 50         if (csv.tmp && csv.used < csv.size && csv.has_ahead) {
    100          
    100          
2434 94           SV *sv = newSVpvn (csv.bptr + csv.used, csv.size - csv.used);
2435 94           (void)hv_store (hv, "_AHEAD", 6, sv, 0);
2436             }
2437             else {
2438 2939           csv.has_ahead = 0;
2439 2939 100         if (csv.useIO & useIO_EOF)
2440 599           (void)hv_store (hv, "_EOF", 4, &PL_sv_yes, 0);
2441             }
2442             /* csv.cache[CACHE_ID__has_ahead] = csv.has_ahead; */
2443 3033           (void)memcpy (csv.cache, &csv, sizeof (csv_t));
2444              
2445 3033 100         if (avf) {
2446 1918 100         if (csv.keep_meta_info)
2447 11           (void)hv_store (hv, "_FFLAGS", 7, newRV_noinc ((SV *)avf), 0);
2448             else {
2449 1907           av_undef (avf);
2450 1907           sv_free ((SV *)avf);
2451             }
2452             }
2453             }
2454             else { /* just copy to the cache */
2455 1934           SV **svp = hv_fetchs (hv, "_CACHE", FALSE);
2456              
2457 1934 50         if (svp && *svp)
    50          
2458 1934           csv.cache = (byte *)SvPV_nolen (*svp);
2459 1934           (void)memcpy (csv.cache, &csv, sizeof (csv_t));
2460             }
2461              
2462 4967 100         if (result && csv.types) {
    100          
2463             STRLEN i;
2464 2           STRLEN len = av_len (av);
2465             SV **svp;
2466              
2467 8 100         for (i = 0; i <= len && i <= csv.types_len; i++) {
    50          
2468 6 50         if ((svp = av_fetch (av, i, FALSE)) && *svp && SvOK (*svp)) {
    50          
    50          
2469 6           switch (csv.types[i]) {
2470 2           case CSV_XS_TYPE_IV:
2471             #ifdef CSV_XS_TYPE_WARN
2472 2           sv_setiv (*svp, SvIV (*svp));
2473             #else
2474             if (SvTRUE (*svp))
2475             sv_setiv (*svp, SvIV (*svp));
2476             else
2477             sv_setiv (*svp, 0);
2478             #endif
2479 2           break;
2480              
2481 2           case CSV_XS_TYPE_NV:
2482             #ifdef CSV_XS_TYPE_WARN
2483 2           sv_setnv (*svp, SvNV (*svp));
2484             #else
2485             if (SvTRUE (*svp))
2486             sv_setnv (*svp, SvNV (*svp));
2487             else
2488             sv_setnv (*svp, 0.0);
2489             #endif
2490 2           break;
2491              
2492 2           default:
2493 2           break;
2494             }
2495             }
2496             }
2497             }
2498              
2499 4967           LEAVE;
2500              
2501 4967           return result;
2502             } /* c_xsParse */
2503              
2504             #define xsParse(self,hv,av,avf,src,useIO) cx_xsParse (aTHX_ self, hv, av, avf, src, useIO)
2505 3857           static int cx_xsParse (pTHX_ SV *self, HV *hv, AV *av, AV *avf, SV *src, bool useIO) {
2506             csv_t csv;
2507             int state;
2508 3857           SetupCsv (&csv, hv, self);
2509 3857           state = c_xsParse (csv, hv, av, avf, src, useIO);
2510 3852 100         if (state && csv.has_hooks & HOOK_AFTER_PARSE)
    100          
2511 5           (void)hook (aTHX_ hv, "after_parse", av);
2512 3852 100         return (state || !last_error);
    100          
2513             } /* xsParse */
2514              
2515             /* API also offers av_clear and av_undef, but they have more overhead */
2516             #define av_empty(av) cx_av_empty (aTHX_ av)
2517 84           static void cx_av_empty (pTHX_ AV *av) {
2518 337 100         while (av_len (av) >= 0)
2519 253           sv_free (av_pop (av));
2520 84           } /* av_empty */
2521              
2522             #define xsParse_all(self,hv,io,off,len) cx_xsParse_all (aTHX_ self, hv, io, off, len)
2523 357           static SV *cx_xsParse_all (pTHX_ SV *self, HV *hv, SV *io, SV *off, SV *len) {
2524             csv_t csv;
2525 357           int n = 0, skip = 0, length = MAXINT, tail = MAXINT;
2526 357           AV *avr = newAV ();
2527 357           AV *row = newAV ();
2528              
2529 357           SetupCsv (&csv, hv, self);
2530              
2531 357 100         if (SvOK (off)) {
2532 56           skip = SvIV (off);
2533 56 100         if (skip < 0) {
2534 12           tail = -skip;
2535 12           skip = -1;
2536             }
2537             }
2538 357 100         if (SvOK (len))
2539 44           length = SvIV (len);
2540              
2541 1121 100         while (c_xsParse (csv, hv, row, NULL, io, 1)) {
2542              
2543 796           SetupCsv (&csv, hv, self);
2544              
2545 796 100         if (skip > 0) {
2546 20           skip--;
2547 20           av_empty (row); /* re-use */
2548 20           continue;
2549             }
2550              
2551 776 100         if (n++ >= tail) {
2552 12           SvREFCNT_dec (av_shift (avr));
2553 12           n--;
2554             }
2555              
2556 776 100         if (csv.has_hooks & HOOK_AFTER_PARSE) {
2557 140 100         unless (hook (aTHX_ hv, "after_parse", row)) {
2558 64           av_empty (row); /* re-use */
2559 64           continue;
2560             }
2561             }
2562 712           av_push (avr, newRV_noinc ((SV *)row));
2563              
2564 712 100         if (n >= length && skip >= 0)
    100          
2565 32           break; /* We have enough */
2566              
2567 680           row = newAV ();
2568             }
2569 359 100         while (n > length) {
2570 8           SvREFCNT_dec (av_pop (avr));
2571 8           n--;
2572             }
2573              
2574 351           return (SV *)sv_2mortal (newRV_noinc ((SV *)avr));
2575             } /* xsParse_all */
2576              
2577             #define xsCombine(self,hv,av,io,useIO) cx_xsCombine (aTHX_ self, hv, av, io, useIO)
2578 21673           static int cx_xsCombine (pTHX_ SV *self, HV *hv, AV *av, SV *io, bool useIO) {
2579             csv_t csv;
2580             int result;
2581             #if (PERL_BCDVERSION >= 0x5008000)
2582 21673           SV *ors = PL_ors_sv;
2583             #endif
2584              
2585 21673           SetupCsv (&csv, hv, self);
2586 21673           csv.useIO = useIO;
2587             #if (PERL_BCDVERSION >= 0x5008000)
2588 21673 100         if (*csv.eol)
2589 251           PL_ors_sv = NULL;
2590             #endif
2591 21673 100         if (useIO && csv.has_hooks & HOOK_BEFORE_PRINT)
    100          
2592 9           (void)hook (aTHX_ hv, "before_print", av);
2593 21673           result = Combine (&csv, io, av);
2594             #if (PERL_BCDVERSION >= 0x5008000)
2595 21669           PL_ors_sv = ors;
2596             #endif
2597 21669 100         if (result && !useIO && csv.utf8)
    100          
    100          
2598 25           sv_utf8_upgrade (io);
2599 21669           return result;
2600             } /* xsCombine */
2601              
2602             MODULE = Text::CSV_XS PACKAGE = Text::CSV_XS
2603              
2604             PROTOTYPES: DISABLE
2605              
2606             BOOT:
2607 34           m_getline = newSVpvs ("getline");
2608 34           m_print = newSVpvs ("print");
2609 34           Perl_load_module (aTHX_ PERL_LOADMOD_NOIMPORT, newSVpvs ("IO::Handle"), NULL, NULL, NULL);
2610              
2611             void
2612             SetDiag (SV *self, int xse, SV *line = undef)
2613              
2614             PPCODE:
2615             HV *hv;
2616             csv_t csv;
2617              
2618 3086 50         if (SvOK (self) && SvROK (self)) {
    100          
2619 1048 50         CSV_XS_SELF;
    50          
    50          
    50          
2620 1048           SetupCsv (&csv, hv, self);
2621 1048           ST (0) = SetDiag (&csv, xse);
2622             }
2623             else {
2624 2038           last_error = xse;
2625 2038           ST (0) = sv_2mortal (SvDiag (xse));
2626             }
2627              
2628 3086 100         if (xse && SvPOK (line)) {
    100          
2629 1012           sv_setpvn (ST (0), SvPVX (line), SvCUR (line));
2630 1012           SvIOK_on (ST (0));
2631             }
2632              
2633 3086           XSRETURN (1);
2634             /* XS SetDiag */
2635              
2636             void
2637             error_input (SV *self)
2638              
2639             PPCODE:
2640 12 50         if (self && SvOK (self) && SvROK (self) && SvTYPE (SvRV (self)) == SVt_PVHV) {
    100          
    100          
    100          
2641 4           HV *hv = (HV *)SvRV (self);
2642 4           SV **sv = hv_fetchs (hv, "_ERROR_INPUT", FALSE);
2643 4 100         if (SvOK (*sv))
2644 3           ST (0) = *sv;
2645             else
2646 1           ST (0) = newSV (0);
2647             }
2648             else
2649 4           ST (0) = newSV (0);
2650              
2651 8           XSRETURN (1);
2652             /* XS error_input */
2653              
2654             void
2655             Combine (SV *self, SV *dst, SV *fields, bool useIO)
2656              
2657             PPCODE:
2658             HV *hv;
2659             AV *av;
2660              
2661 1396 50         CSV_XS_SELF;
    50          
    50          
    50          
2662 1396           av = (AV *)SvRV (fields);
2663 1396 100         ST (0) = xsCombine (self, hv, av, dst, useIO) ? &PL_sv_yes : &PL_sv_undef;
2664 1392           XSRETURN (1);
2665             /* XS Combine */
2666              
2667             void
2668             Parse (SV *self, SV *src, SV *fields, SV *fflags)
2669              
2670             PPCODE:
2671             HV *hv;
2672             AV *av;
2673             AV *avf;
2674             int r;
2675              
2676 1937 50         CSV_XS_SELF;
    50          
    50          
    50          
2677 1937           av = (AV *)SvRV (fields);
2678 1937           avf = (AV *)SvRV (fflags);
2679              
2680 1937           r = xsParse (self, hv, av, avf, src, 0);
2681 1934 100         PUT_RETURN (r ? &PL_sv_yes : &PL_sv_no);
2682             /* XS Parse */
2683              
2684             void
2685             print (SV *self, SV *io, SV *fields)
2686              
2687             PPCODE:
2688             HV *hv;
2689             AV *av;
2690             int r;
2691              
2692 20282 50         CSV_XS_SELF;
    50          
    50          
    50          
2693 20282 100         if (fields == &PL_sv_undef)
2694 5           av = newAV ();
2695             else {
2696 40554 50         unless (_is_arrayref (fields))
    100          
    50          
    100          
    100          
2697 5           croak ("Expected fields to be an array ref");
2698              
2699 20272           av = (AV *)SvRV (fields);
2700             }
2701              
2702 20277           r = xsCombine (self, hv, av, io, 1);
2703 20277 100         PUT_RETURN (r ? &PL_sv_yes : &PL_sv_no);
2704             /* XS print */
2705              
2706             void
2707             getline (SV *self, SV *io)
2708              
2709             PPCODE:
2710             HV *hv;
2711             AV *av;
2712             AV *avf;
2713             int r;
2714              
2715 1920 50         CSV_XS_SELF;
    50          
    50          
    50          
2716 1920           av = newAV ();
2717 1920           avf = newAV ();
2718 1920           r = xsParse (self, hv, av, avf, io, 1);
2719 1918 100         PUT_RETURN (r ? sv_2mortal (newRV_noinc ((SV *)av)) : undef);
2720             /* XS getline */
2721              
2722             void
2723             getline_all (SV *self, SV *io, SV *offset = undef, SV *length = undef)
2724              
2725             PPCODE:
2726             HV *hv;
2727             SV *rv;
2728              
2729 357 50         CSV_XS_SELF;
    50          
    50          
    50          
2730              
2731 357           rv = xsParse_all (self, hv, io, offset, length);
2732 351           PUT_RETURN (rv);
2733             /* XS getline_all */
2734              
2735             void
2736             _cache_get_eolt (SV *self)
2737              
2738             PPCODE:
2739             HV *hv;
2740             SV *sve;
2741             char *eol;
2742              
2743 32 50         CSV_XS_SELF;
    50          
    50          
    50          
2744 32           sve = newSVpvs_flags ("", SVs_TEMP);
2745 32           eol = xs_cache_get_eolt (hv);
2746 32 100         if (eol)
2747 21           sv_setpvn (sve, eol, strlen (eol));
2748             else
2749 11           sv_setpvn (sve, NULL, 0);
2750 32           ST (0) = sve;
2751 32           XSRETURN (1);
2752             /* XS _cache_get_eolt */
2753              
2754             void
2755             _cache_set (SV *self, int idx, SV *val)
2756              
2757             PPCODE:
2758             HV *hv;
2759              
2760 23355 50         CSV_XS_SELF;
    50          
    50          
    50          
2761 23355           xs_cache_set (hv, idx, val);
2762 23355           XSRETURN (1);
2763             /* XS _cache_set */
2764              
2765             void
2766             _cache_diag (SV *self)
2767              
2768             PPCODE:
2769             HV *hv;
2770              
2771 2 50         CSV_XS_SELF;
    50          
    50          
    50          
2772 2           xs_cache_diag (hv);
2773 2           XSRETURN (1);
2774             /* XS _cache_diag */