File Coverage

CSV_XS.xs
Criterion Covered Total %
statement 1090 1124 96.9
branch 1561 2798 55.7
condition n/a
subroutine n/a
pod n/a
total 2651 3922 67.5


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