chugalug 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ v0.0.1. First version.
data/LICENSE ADDED
@@ -0,0 +1,184 @@
1
+ Academic Free License (AFL) v. 3.0
2
+
3
+ This Academic Free License (the "License") applies to any original work
4
+ of authorship (the "Original Work") whose owner (the "Licensor") has
5
+ placed the following licensing notice adjacent to the copyright notice
6
+ for the Original Work:
7
+
8
+ Licensed under the Academic Free License version 3.0
9
+
10
+ 1) Grant of Copyright License. Licensor grants You a worldwide,
11
+ royalty-free, non-exclusive, sublicensable license, for the duration of
12
+ the copyright, to do the following:
13
+
14
+ a) to reproduce the Original Work in copies, either alone or as part of
15
+ a collective work;
16
+
17
+ b) to translate, adapt, alter, transform, modify, or arrange the
18
+ Original Work, thereby creating derivative works ("Derivative Works")
19
+ based upon the Original Work;
20
+
21
+ c) to distribute or communicate copies of the Original Work and
22
+ Derivative Works to the public, under any license of your choice that
23
+ does not contradict the terms and conditions, including Licensor's
24
+ reserved rights and remedies, in this Academic Free License;
25
+
26
+ d) to perform the Original Work publicly; and
27
+
28
+ e) to display the Original Work publicly.
29
+
30
+ 2) Grant of Patent License. Licensor grants You a worldwide,
31
+ royalty-free, non-exclusive, sublicensable license, under patent claims
32
+ owned or controlled by the Licensor that are embodied in the Original
33
+ Work as furnished by the Licensor, for the duration of the patents, to
34
+ make, use, sell, offer for sale, have made, and import the Original Work
35
+ and Derivative Works.
36
+
37
+ 3) Grant of Source Code License. The term "Source Code" means the
38
+ preferred form of the Original Work for making modifications to it and
39
+ all available documentation describing how to modify the Original Work.
40
+ Licensor agrees to provide a machine-readable copy of the Source Code of
41
+ the Original Work along with each copy of the Original Work that
42
+ Licensor distributes. Licensor reserves the right to satisfy this
43
+ obligation by placing a machine-readable copy of the Source Code in an
44
+ information repository reasonably calculated to permit inexpensive and
45
+ convenient access by You for as long as Licensor continues to distribute
46
+ the Original Work.
47
+
48
+ 4) Exclusions From License Grant. Neither the names of Licensor, nor the
49
+ names of any contributors to the Original Work, nor any of their
50
+ trademarks or service marks, may be used to endorse or promote products
51
+ derived from this Original Work without express prior permission of the
52
+ Licensor. Except as expressly stated herein, nothing in this License
53
+ grants any license to Licensor's trademarks, copyrights, patents, trade
54
+ secrets or any other intellectual property. No patent license is granted
55
+ to make, use, sell, offer for sale, have made, or import embodiments of
56
+ any patent claims other than the licensed claims defined in Section 2.
57
+ No license is granted to the trademarks of Licensor even if such marks
58
+ are included in the Original Work. Nothing in this License shall be
59
+ interpreted to prohibit Licensor from licensing under terms different
60
+ from this License any Original Work that Licensor otherwise would have a
61
+ right to license.
62
+
63
+ 5) External Deployment. The term "External Deployment" means the use,
64
+ distribution, or communication of the Original Work or Derivative Works
65
+ in any way such that the Original Work or Derivative Works may be used
66
+ by anyone other than You, whether those works are distributed or
67
+ communicated to those persons or made available as an application
68
+ intended for use over a network. As an express condition for the grants
69
+ of license hereunder, You must treat any External Deployment by You of
70
+ the Original Work or a Derivative Work as a distribution under section
71
+ 1(c).
72
+
73
+ 6) Attribution Rights. You must retain, in the Source Code of any
74
+ Derivative Works that You create, all copyright, patent, or trademark
75
+ notices from the Source Code of the Original Work, as well as any
76
+ notices of licensing and any descriptive text identified therein as an
77
+ "Attribution Notice." You must cause the Source Code for any Derivative
78
+ Works that You create to carry a prominent Attribution Notice reasonably
79
+ calculated to inform recipients that You have modified the Original
80
+ Work.
81
+
82
+ 7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants
83
+ that the copyright in and to the Original Work and the patent rights
84
+ granted herein by Licensor are owned by the Licensor or are sublicensed
85
+ to You under the terms of this License with the permission of the
86
+ contributor(s) of those copyrights and patent rights. Except as
87
+ expressly stated in the immediately preceding sentence, the Original
88
+ Work is provided under this License on an "AS IS" BASIS and WITHOUT
89
+ WARRANTY, either express or implied, including, without limitation, the
90
+ warranties of non-infringement, merchantability or fitness for a
91
+ particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL
92
+ WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential
93
+ part of this License. No license to the Original Work is granted by this
94
+ License except under this disclaimer.
95
+
96
+ 8) Limitation of Liability. Under no circumstances and under no legal
97
+ theory, whether in tort (including negligence), contract, or otherwise,
98
+ shall the Licensor be liable to anyone for any indirect, special,
99
+ incidental, or consequential damages of any character arising as a
100
+ result of this License or the use of the Original Work including,
101
+ without limitation, damages for loss of goodwill, work stoppage,
102
+ computer failure or malfunction, or any and all other commercial damages
103
+ or losses. This limitation of liability shall not apply to the extent
104
+ applicable law prohibits such limitation.
105
+
106
+ 9) Acceptance and Termination. If, at any time, You expressly assented
107
+ to this License, that assent indicates your clear and irrevocable
108
+ acceptance of this License and all of its terms and conditions. If You
109
+ distribute or communicate copies of the Original Work or a Derivative
110
+ Work, You must make a reasonable effort under the circumstances to
111
+ obtain the express assent of recipients to the terms of this License.
112
+ This License conditions your rights to undertake the activities listed
113
+ in Section 1, including your right to create Derivative Works based upon
114
+ the Original Work, and doing so without honoring these terms and
115
+ conditions is prohibited by copyright law and international treaty.
116
+ Nothing in this License is intended to affect copyright exceptions and
117
+ limitations (including "fair use" or "fair dealing"). This License shall
118
+ terminate immediately and You may no longer exercise any of the rights
119
+ granted to You by this License upon your failure to honor the conditions
120
+ in Section 1(c).
121
+
122
+ 10) Termination for Patent Action. This License shall terminate
123
+ automatically and You may no longer exercise any of the rights granted
124
+ to You by this License as of the date You commence an action, including
125
+ a cross-claim or counterclaim, against Licensor or any licensee alleging
126
+ that the Original Work infringes a patent. This termination provision
127
+ shall not apply for an action alleging patent infringement by
128
+ combinations of the Original Work with other software or hardware.
129
+
130
+ 11) Jurisdiction, Venue and Governing Law. Any action or suit relating
131
+ to this License may be brought only in the courts of a jurisdiction
132
+ wherein the Licensor resides or in which Licensor conducts its primary
133
+ business, and under the laws of that jurisdiction excluding its
134
+ conflict-of-law provisions. The application of the United Nations
135
+ Convention on Contracts for the International Sale of Goods is expressly
136
+ excluded. Any use of the Original Work outside the scope of this License
137
+ or after its termination shall be subject to the requirements and
138
+ penalties of copyright or patent law in the appropriate jurisdiction.
139
+ This section shall survive the termination of this License.
140
+
141
+ 12) Attorneys' Fees. In any action to enforce the terms of this License
142
+ or seeking damages relating thereto, the prevailing party shall be
143
+ entitled to recover its costs and expenses, including, without
144
+ limitation, reasonable attorneys' fees and costs incurred in connection
145
+ with such action, including any appeal of such action. This section
146
+ shall survive the termination of this License.
147
+
148
+ 13) Miscellaneous. If any provision of this License is held to be
149
+ unenforceable, such provision shall be reformed only to the extent
150
+ necessary to make it enforceable.
151
+
152
+ 14) Definition of "You" in This License. "You" throughout this License,
153
+ whether in upper or lower case, means an individual or a legal entity
154
+ exercising rights under, and complying with all of the terms of, this
155
+ License. For legal entities, "You" includes any entity that controls, is
156
+ controlled by, or is under common control with you. For purposes of this
157
+ definition, "control" means (i) the power, direct or indirect, to cause
158
+ the direction or management of such entity, whether by contract or
159
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
160
+ outstanding shares, or (iii) beneficial ownership of such entity.
161
+
162
+ 15) Right to Use. You may use the Original Work in all ways not
163
+ otherwise restricted or conditioned by this License or by law, and
164
+ Licensor promises not to interfere with or be responsible for such uses
165
+ by You.
166
+
167
+ 16) Modification of This License. This License is Copyright (c) 2005
168
+ Lawrence Rosen. Permission is granted to copy, distribute, or
169
+ communicate this License without modification. Nothing in this License
170
+ permits You to modify this License as applied to the Original Work or to
171
+ Derivative Works. However, You may modify the text of this License and
172
+ copy, distribute or communicate your modified version (the "Modified
173
+ License") and apply it to other original works of authorship subject to
174
+ the following conditions: (i) You may not indicate in any way that your
175
+ Modified License is the "Academic Free License" or "AFL" and you may not
176
+ use those names in the name of your Modified License; (ii) You must
177
+ replace the notice specified in the first paragraph above with the
178
+ notice "Licensed under <insert your license name here>" or with a notice
179
+ of your own that is not confusingly similar to the notice in this
180
+ License; and (iii) You may not claim that your original works are open
181
+ source software unless your Modified License has been approved by Open
182
+ Source Initiative (OSI) and You comply with its license review and
183
+ certification process.
184
+
@@ -0,0 +1,15 @@
1
+ CHANGELOG
2
+ LICENSE
3
+ Manifest
4
+ README
5
+ Rakefile
6
+ ext/chugalug.c
7
+ ext/csv.h
8
+ ext/extconf.rb
9
+ ext/libcsv.c
10
+ test/data.csv
11
+ test/data_small.csv
12
+ test/easy.csv
13
+ test/messages.csv
14
+ test/quoted_values.csv
15
+ test/unit/test_chugalug.rb
data/README ADDED
@@ -0,0 +1,12 @@
1
+
2
+ Ccsv
3
+
4
+ A pure-C CSV parser.
5
+
6
+ == License
7
+
8
+ Copyright 2010 Josh Ferguson, based off of Ccsv with the License Below:
9
+
10
+ == Attribution
11
+
12
+ Copyright 2007, 2008 Cloudburst, LLC. Licensed under the AFL 3. See the included LICENSE file.
@@ -0,0 +1,9 @@
1
+ require 'echoe'
2
+
3
+ Echoe.new("chugalug") do |p|
4
+ p.author = "Josh Ferguson"
5
+ p.email = "josh@besquared.net"
6
+ p.project = "Besquared"
7
+ p.summary = "A wrapper around libcsv."
8
+ p.url = "http://www.github.com/besquared/chugalug/"
9
+ end
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{chugalug}
5
+ s.version = "0.0.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Josh Ferguson"]
9
+ s.date = %q{2010-05-15}
10
+ s.description = %q{A wrapper around libcsv.}
11
+ s.email = %q{josh@besquared.net}
12
+ s.extensions = ["ext/extconf.rb"]
13
+ s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README", "ext/chugalug.c", "ext/csv.h", "ext/extconf.rb", "ext/libcsv.c"]
14
+ s.files = ["CHANGELOG", "LICENSE", "Manifest", "README", "Rakefile", "ext/chugalug.c", "ext/csv.h", "ext/extconf.rb", "ext/libcsv.c", "test/data.csv", "test/data_small.csv", "test/easy.csv", "test/messages.csv", "test/quoted_values.csv", "test/unit/test_chugalug.rb", "chugalug.gemspec"]
15
+ s.homepage = %q{http://www.github.com/besquared/chugalug/}
16
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Chugalug", "--main", "README"]
17
+ s.require_paths = ["lib", "ext"]
18
+ s.rubyforge_project = %q{Besquared}
19
+ s.rubygems_version = %q{1.3.6}
20
+ s.summary = %q{A wrapper around libcsv.}
21
+ s.test_files = ["test/unit/test_chugalug.rb"]
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 3
26
+
27
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
+ else
29
+ end
30
+ else
31
+ end
32
+ end
@@ -0,0 +1,79 @@
1
+ #include <ruby.h>
2
+ #include <stdio.h>
3
+ #include <stdlib.h>
4
+ #include <string.h>
5
+ #include <errno.h>
6
+
7
+ #include "csv.h"
8
+
9
+ struct rowdata {
10
+ VALUE ary;
11
+ };
12
+
13
+ void fieldcb(void* str, size_t len, void* data) {
14
+ VALUE ary = ((struct rowdata *)data)->ary;
15
+ rb_ary_store(ary, RARRAY_LEN(ary), rb_str_new(str, len));
16
+ }
17
+
18
+ void rowcb(int c, void* data) {
19
+ rb_yield(((struct rowdata *)data)->ary);
20
+ ((struct rowdata *)data)->ary = rb_ary_new();
21
+ }
22
+
23
+ static int is_space(unsigned char c) {
24
+ if (c == CSV_SPACE || c == CSV_TAB) return 1;
25
+ return 0;
26
+ }
27
+
28
+ static int is_term(unsigned char c) {
29
+ if (c == CSV_CR || c == CSV_LF) return 1;
30
+ return 0;
31
+ }
32
+
33
+ static VALUE foreach(VALUE self, VALUE filename) {
34
+ FILE *file = fopen(StringValueCStr(filename), "r");
35
+
36
+ if (file == NULL) {
37
+ rb_raise(rb_eRuntimeError, "File not found");
38
+ }
39
+
40
+ char buf[1024];
41
+ size_t bytes_read;
42
+ struct csv_parser p;
43
+ unsigned char options = 0;
44
+
45
+ struct rowdata data;
46
+ data.ary = rb_ary_new();
47
+
48
+ if(csv_init(&p, options) != 0) {
49
+ rb_raise(rb_eRuntimeError, "Failed to initialize csv parser");
50
+ exit(EXIT_FAILURE);
51
+ }
52
+
53
+ csv_set_space_func(&p, is_space);
54
+ csv_set_term_func(&p, is_term);
55
+
56
+ while((bytes_read = fread(buf, 1, 1024, file)) > 0) {
57
+ if(csv_parse(&p, buf, bytes_read, fieldcb, rowcb, &data) != bytes_read) {
58
+ rb_raise(rb_eRuntimeError, "Error while parsing file"); //, csv_strerror(csv_error(&p)));
59
+ }
60
+ }
61
+
62
+ csv_fini(&p, fieldcb, rowcb, &data);
63
+ csv_free(&p);
64
+
65
+ if(ferror(file)) {
66
+ fclose(file);
67
+ rb_raise(rb_eRuntimeError, "Error while reading file");
68
+ } else {
69
+ fclose(file);
70
+ }
71
+
72
+ return Qnil;
73
+ }
74
+
75
+ static VALUE rb_cC;
76
+ void Init_chugalug() {
77
+ rb_cC = rb_define_class("Chugalug", rb_cObject);
78
+ rb_define_singleton_method(rb_cC, "foreach", foreach, 1);
79
+ }
@@ -0,0 +1,86 @@
1
+ #ifndef LIBCSV_H__
2
+ #define LIBCSV_H__
3
+ #include <stdlib.h>
4
+ #include <stdio.h>
5
+
6
+ #ifdef __cplusplus
7
+ extern "C" {
8
+ #endif
9
+
10
+ #define CSV_MAJOR 3
11
+ #define CSV_MINOR 0
12
+ #define CSV_RELEASE 0
13
+
14
+ /* Error Codes */
15
+ #define CSV_SUCCESS 0
16
+ #define CSV_EPARSE 1 /* Parse error in strict mode */
17
+ #define CSV_ENOMEM 2 /* Out of memory while increasing buffer size */
18
+ #define CSV_ETOOBIG 3 /* Buffer larger than SIZE_MAX needed */
19
+ #define CSV_EINVALID 4 /* Invalid code,should never be received from csv_error*/
20
+
21
+
22
+ /* parser options */
23
+ #define CSV_STRICT 1 /* enable strict mode */
24
+ #define CSV_REPALL_NL 2 /* report all unquoted carriage returns and linefeeds */
25
+ #define CSV_STRICT_FINI 4 /* causes csv_fini to return CSV_EPARSE if last
26
+ field is quoted and doesn't containg ending
27
+ quote */
28
+ #define CSV_APPEND_NULL 8 /* Ensure that all fields are null-ternimated */
29
+
30
+
31
+ /* Character values */
32
+ #define CSV_TAB 0x09
33
+ #define CSV_SPACE 0x20
34
+ #define CSV_CR 0x0d
35
+ #define CSV_LF 0x0a
36
+ #define CSV_COMMA 0x2c
37
+ #define CSV_QUOTE 0x22
38
+
39
+ struct csv_parser {
40
+ int pstate; /* Parser state */
41
+ int quoted; /* Is the current field a quoted field? */
42
+ size_t spaces; /* Number of continious spaces after quote or in a non-quoted field */
43
+ unsigned char * entry_buf; /* Entry buffer */
44
+ size_t entry_pos; /* Current position in entry_buf (and current size of entry) */
45
+ size_t entry_size; /* Size of entry buffer */
46
+ int status; /* Operation status */
47
+ unsigned char options;
48
+ unsigned char quote_char;
49
+ unsigned char delim_char;
50
+ int (*is_space)(unsigned char);
51
+ int (*is_term)(unsigned char);
52
+ size_t blk_size;
53
+ void *(*malloc_func)(size_t);
54
+ void *(*realloc_func)(void *, size_t);
55
+ void (*free_func)(void *);
56
+ };
57
+
58
+ /* Function Prototypes */
59
+ int csv_init(struct csv_parser *p, unsigned char options);
60
+ int csv_fini(struct csv_parser *p, void (*cb1)(void *, size_t, void *), void (*cb2)(int, void *), void *data);
61
+ void csv_free(struct csv_parser *p);
62
+ int csv_error(struct csv_parser *p);
63
+ char * csv_strerror(int error);
64
+ size_t csv_parse(struct csv_parser *p, const void *s, size_t len, void (*cb1)(void *, size_t, void *), void (*cb2)(int, void *), void *data);
65
+ size_t csv_write(void *dest, size_t dest_size, const void *src, size_t src_size);
66
+ int csv_fwrite(FILE *fp, const void *src, size_t src_size);
67
+ size_t csv_write2(void *dest, size_t dest_size, const void *src, size_t src_size, unsigned char quote);
68
+ int csv_fwrite2(FILE *fp, const void *src, size_t src_size, unsigned char quote);
69
+ int csv_get_opts(struct csv_parser *p);
70
+ int csv_set_opts(struct csv_parser *p, unsigned char options);
71
+ void csv_set_delim(struct csv_parser *p, unsigned char c);
72
+ void csv_set_quote(struct csv_parser *p, unsigned char c);
73
+ unsigned char csv_get_delim(struct csv_parser *p);
74
+ unsigned char csv_get_quote(struct csv_parser *p);
75
+ void csv_set_space_func(struct csv_parser *p, int (*f)(unsigned char));
76
+ void csv_set_term_func(struct csv_parser *p, int (*f)(unsigned char));
77
+ void csv_set_realloc_func(struct csv_parser *p, void *(*)(void *, size_t));
78
+ void csv_set_free_func(struct csv_parser *p, void (*)(void *));
79
+ void csv_set_blk_size(struct csv_parser *p, size_t);
80
+ size_t csv_get_buffer_size(struct csv_parser *p);
81
+
82
+ #ifdef __cplusplus
83
+ }
84
+ #endif
85
+
86
+ #endif
@@ -0,0 +1,3 @@
1
+ require 'mkmf'
2
+ dir_config('chugalug')
3
+ create_makefile('chugalug')
@@ -0,0 +1,579 @@
1
+ /*
2
+ libcsv - parse and write csv data
3
+ Copyright (C) 2008 Robert Gamble
4
+
5
+ This library is free software; you can redistribute it and/or
6
+ modify it under the terms of the GNU Lesser General Public
7
+ License as published by the Free Software Foundation; either
8
+ version 2.1 of the License, or (at your option) any later version.
9
+
10
+ This library is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ Lesser General Public License for more details.
14
+
15
+ You should have received a copy of the GNU Lesser General Public
16
+ License along with this library; if not, write to the Free Software
17
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+ */
19
+
20
+ #if ___STDC_VERSION__ >= 199901L
21
+ # include <stdint.h>
22
+ #else
23
+ # define SIZE_MAX ((size_t)-1) /* C89 doesn't have stdint.h or SIZE_MAX */
24
+ #endif
25
+
26
+ #include "csv.h"
27
+
28
+ #define VERSION "3.0.0"
29
+
30
+ #define ROW_NOT_BEGUN 0
31
+ #define FIELD_NOT_BEGUN 1
32
+ #define FIELD_BEGUN 2
33
+ #define FIELD_MIGHT_HAVE_ENDED 3
34
+
35
+ /*
36
+ Explanation of states
37
+ ROW_NOT_BEGUN There have not been any fields encountered for this row
38
+ FIELD_NOT_BEGUN There have been fields but we are currently not in one
39
+ FIELD_BEGUN We are in a field
40
+ FIELD_MIGHT_HAVE_ENDED
41
+ We encountered a double quote inside a quoted field, the
42
+ field is either ended or the quote is literal
43
+ */
44
+
45
+ #define MEM_BLK_SIZE 128
46
+
47
+ #define SUBMIT_FIELD(p) \
48
+ do { \
49
+ if (!quoted) \
50
+ entry_pos -= spaces; \
51
+ if (p->options & CSV_APPEND_NULL) \
52
+ ((p)->entry_buf[entry_pos+1]) = '\0'; \
53
+ if (cb1) \
54
+ cb1(p->entry_buf, entry_pos, data); \
55
+ pstate = FIELD_NOT_BEGUN; \
56
+ entry_pos = quoted = spaces = 0; \
57
+ } while (0)
58
+
59
+ #define SUBMIT_ROW(p, c) \
60
+ do { \
61
+ if (cb2) \
62
+ cb2(c, data); \
63
+ pstate = ROW_NOT_BEGUN; \
64
+ entry_pos = quoted = spaces = 0; \
65
+ } while (0)
66
+
67
+ #define SUBMIT_CHAR(p, c) ((p)->entry_buf[entry_pos++] = (c))
68
+
69
+ static char *csv_errors[] = {"success",
70
+ "error parsing data while strict checking enabled",
71
+ "memory exhausted while increasing buffer size",
72
+ "data size too large",
73
+ "invalid status code"};
74
+
75
+ int
76
+ csv_error(struct csv_parser *p)
77
+ {
78
+ /* Return the current status of the parser */
79
+ return p->status;
80
+ }
81
+
82
+ char *
83
+ csv_strerror(int status)
84
+ {
85
+ /* Return a textual description of status */
86
+ if (status >= CSV_EINVALID || status < 0)
87
+ return csv_errors[CSV_EINVALID];
88
+ else
89
+ return csv_errors[status];
90
+ }
91
+
92
+ int
93
+ csv_get_opts(struct csv_parser *p)
94
+ {
95
+ /* Return the currently set options of parser */
96
+ if (p == NULL)
97
+ return -1;
98
+
99
+ return p->options;
100
+ }
101
+
102
+ int
103
+ csv_set_opts(struct csv_parser *p, unsigned char options)
104
+ {
105
+ /* Set the options */
106
+ if (p == NULL)
107
+ return -1;
108
+
109
+ p->options = options;
110
+ return 0;
111
+ }
112
+
113
+ int
114
+ csv_init(struct csv_parser *p, unsigned char options)
115
+ {
116
+ /* Initialize a csv_parser object returns 0 on success, -1 on error */
117
+ if (p == NULL)
118
+ return -1;
119
+
120
+ p->entry_buf = NULL;
121
+ p->pstate = ROW_NOT_BEGUN;
122
+ p->quoted = 0;
123
+ p->spaces = 0;
124
+ p->entry_pos = 0;
125
+ p->entry_size = 0;
126
+ p->status = 0;
127
+ p->options = options;
128
+ p->quote_char = CSV_QUOTE;
129
+ p->delim_char = CSV_COMMA;
130
+ p->is_space = NULL;
131
+ p->is_term = NULL;
132
+ p->blk_size = MEM_BLK_SIZE;
133
+ p->malloc_func = NULL;
134
+ p->realloc_func = realloc;
135
+ p->free_func = free;
136
+
137
+ return 0;
138
+ }
139
+
140
+ void
141
+ csv_free(struct csv_parser *p)
142
+ {
143
+ /* Free the entry_buffer of csv_parser object */
144
+ if (p == NULL)
145
+ return;
146
+
147
+ if (p->entry_buf)
148
+ p->free_func(p->entry_buf);
149
+
150
+ p->entry_buf = NULL;
151
+ p->entry_size = 0;
152
+
153
+ return;
154
+ }
155
+
156
+ int
157
+ csv_fini(struct csv_parser *p, void (*cb1)(void *, size_t, void *), void (*cb2)(int c, void *), void *data)
158
+ {
159
+ /* Finalize parsing. Needed, for example, when file does not end in a newline */
160
+ int quoted = p->quoted;
161
+ int pstate = p->pstate;
162
+ size_t spaces = p->spaces;
163
+ size_t entry_pos = p->entry_pos;
164
+
165
+ if (p == NULL)
166
+ return -1;
167
+
168
+
169
+ if (p->pstate == FIELD_BEGUN && p->quoted && p->options & CSV_STRICT && p->options & CSV_STRICT_FINI) {
170
+ /* Current field is quoted, no end-quote was seen, and CSV_STRICT_FINI is set */
171
+ p->status = CSV_EPARSE;
172
+ return -1;
173
+ }
174
+
175
+ switch (p->pstate) {
176
+ case FIELD_MIGHT_HAVE_ENDED:
177
+ p->entry_pos -= p->spaces + 1; /* get rid of spaces and original quote */
178
+ /* Fall-through */
179
+ case FIELD_NOT_BEGUN:
180
+ case FIELD_BEGUN:
181
+ quoted = p->quoted, pstate = p->pstate;
182
+ spaces = p->spaces, entry_pos = p->entry_pos;
183
+ SUBMIT_FIELD(p);
184
+ SUBMIT_ROW(p, -1);
185
+ case ROW_NOT_BEGUN: /* Already ended properly */
186
+ ;
187
+ }
188
+
189
+ /* Reset parser */
190
+ p->spaces = p->quoted = p->entry_pos = p->status = 0;
191
+ p->pstate = ROW_NOT_BEGUN;
192
+
193
+ return 0;
194
+ }
195
+
196
+ void
197
+ csv_set_delim(struct csv_parser *p, unsigned char c)
198
+ {
199
+ /* Set the delimiter */
200
+ if (p) p->delim_char = c;
201
+ }
202
+
203
+ void
204
+ csv_set_quote(struct csv_parser *p, unsigned char c)
205
+ {
206
+ /* Set the quote character */
207
+ if (p) p->quote_char = c;
208
+ }
209
+
210
+ unsigned char
211
+ csv_get_delim(struct csv_parser *p)
212
+ {
213
+ /* Get the delimiter */
214
+ return p->delim_char;
215
+ }
216
+
217
+ unsigned char
218
+ csv_get_quote(struct csv_parser *p)
219
+ {
220
+ /* Get the quote character */
221
+ return p->quote_char;
222
+ }
223
+
224
+ void
225
+ csv_set_space_func(struct csv_parser *p, int (*f)(unsigned char))
226
+ {
227
+ /* Set the space function */
228
+ if (p) p->is_space = f;
229
+ }
230
+
231
+ void
232
+ csv_set_term_func(struct csv_parser *p, int (*f)(unsigned char))
233
+ {
234
+ /* Set the term function */
235
+ if (p) p->is_term = f;
236
+ }
237
+
238
+ void
239
+ csv_set_realloc_func(struct csv_parser *p, void *(*f)(void *, size_t))
240
+ {
241
+ /* Set the realloc function used to increase buffer size */
242
+ if (p && f) p->realloc_func = f;
243
+ }
244
+
245
+ void
246
+ csv_set_free_func(struct csv_parser *p, void (*f)(void *))
247
+ {
248
+ /* Set the free function used to free the buffer */
249
+ if (p && f) p->free_func = f;
250
+ }
251
+
252
+ void
253
+ csv_set_blk_size(struct csv_parser *p, size_t size)
254
+ {
255
+ /* Set the block size used to increment buffer size */
256
+ if (p) p->blk_size = size;
257
+ }
258
+
259
+ size_t
260
+ csv_get_buffer_size(struct csv_parser *p)
261
+ {
262
+ /* Get the size of the entry buffer */
263
+ if (p)
264
+ return p->entry_size;
265
+ return 0;
266
+ }
267
+
268
+ static int
269
+ csv_increase_buffer(struct csv_parser *p)
270
+ {
271
+ /* Increase the size of the entry buffer. Attempt to increase size by
272
+ * p->blk_size, if this is larger than SIZE_MAX try to increase current
273
+ * buffer size to SIZE_MAX. If allocation fails, try to allocate halve
274
+ * the size and try again until successful or increment size is zero.
275
+ */
276
+
277
+ size_t to_add = p->blk_size;
278
+ void *vp;
279
+
280
+ if ( p->entry_size >= SIZE_MAX - to_add )
281
+ to_add = SIZE_MAX - p->entry_size;
282
+
283
+ if (!to_add) {
284
+ p->status = CSV_ETOOBIG;
285
+ return -1;
286
+ }
287
+
288
+ while ((vp = p->realloc_func(p->entry_buf, p->entry_size + to_add)) == NULL) {
289
+ to_add /= 2;
290
+ if (!to_add) {
291
+ p->status = CSV_ENOMEM;
292
+ return -1;
293
+ }
294
+ }
295
+
296
+ /* Update entry buffer pointer and entry_size if successful */
297
+ p->entry_buf = vp;
298
+ p->entry_size += to_add;
299
+ return 0;
300
+ }
301
+
302
+ size_t
303
+ csv_parse(struct csv_parser *p, const void *s, size_t len, void (*cb1)(void *, size_t, void *), void (*cb2)(int c, void *), void *data)
304
+ {
305
+ unsigned const char *us = s; /* Access input data as array of unsigned char */
306
+ unsigned char c; /* The character we are currently processing */
307
+ size_t pos = 0; /* The number of characters we have processed in this call */
308
+
309
+ /* Store key fields into local variables for performance */
310
+ unsigned char delim = p->delim_char;
311
+ unsigned char quote = p->quote_char;
312
+ int (*is_space)(unsigned char) = p->is_space;
313
+ int (*is_term)(unsigned char) = p->is_term;
314
+ int quoted = p->quoted;
315
+ int pstate = p->pstate;
316
+ size_t spaces = p->spaces;
317
+ size_t entry_pos = p->entry_pos;
318
+
319
+
320
+ if (!p->entry_buf && pos < len) {
321
+ /* Buffer hasn't been allocated yet and len > 0 */
322
+ if (csv_increase_buffer(p) != 0) {
323
+ p->quoted = quoted, p->pstate = pstate, p->spaces = spaces, p->entry_pos = entry_pos;
324
+ return pos;
325
+ }
326
+ }
327
+
328
+ while (pos < len) {
329
+ /* Check memory usage, increase buffer if neccessary */
330
+ if (entry_pos == ((p->options & CSV_APPEND_NULL) ? p->entry_size - 1 : p->entry_size) ) {
331
+ if (csv_increase_buffer(p) != 0) {
332
+ p->quoted = quoted, p->pstate = pstate, p->spaces = spaces, p->entry_pos = entry_pos;
333
+ return pos;
334
+ }
335
+ }
336
+
337
+ c = us[pos++];
338
+
339
+ switch (pstate) {
340
+ case ROW_NOT_BEGUN:
341
+ case FIELD_NOT_BEGUN:
342
+ if (is_space ? is_space(c) : c == CSV_SPACE || c == CSV_TAB) { /* Space or Tab */
343
+ continue;
344
+ } else if (is_term ? is_term(c) : c == CSV_CR || c == CSV_LF) { /* Carriage Return or Line Feed */
345
+ if (pstate == FIELD_NOT_BEGUN) {
346
+ SUBMIT_FIELD(p);
347
+ SUBMIT_ROW(p, (unsigned char)c);
348
+ } else { /* ROW_NOT_BEGUN */
349
+ /* Don't submit empty rows by default */
350
+ if (p->options & CSV_REPALL_NL) {
351
+ SUBMIT_ROW(p, (unsigned char)c);
352
+ }
353
+ }
354
+ continue;
355
+ } else if (c == delim) { /* Comma */
356
+ SUBMIT_FIELD(p);
357
+ break;
358
+ } else if (c == quote) { /* Quote */
359
+ pstate = FIELD_BEGUN;
360
+ quoted = 1;
361
+ } else { /* Anything else */
362
+ pstate = FIELD_BEGUN;
363
+ quoted = 0;
364
+ SUBMIT_CHAR(p, c);
365
+ }
366
+ break;
367
+ case FIELD_BEGUN:
368
+ if (c == quote) { /* Quote */
369
+ if (quoted) {
370
+ SUBMIT_CHAR(p, c);
371
+ pstate = FIELD_MIGHT_HAVE_ENDED;
372
+ } else {
373
+ /* STRICT ERROR - double quote inside non-quoted field */
374
+ if (p->options & CSV_STRICT) {
375
+ p->status = CSV_EPARSE;
376
+ p->quoted = quoted, p->pstate = pstate, p->spaces = spaces, p->entry_pos = entry_pos;
377
+ return pos-1;
378
+ }
379
+ SUBMIT_CHAR(p, c);
380
+ spaces = 0;
381
+ }
382
+ } else if (c == delim) { /* Comma */
383
+ if (quoted) {
384
+ SUBMIT_CHAR(p, c);
385
+ } else {
386
+ SUBMIT_FIELD(p);
387
+ }
388
+ } else if (is_term ? is_term(c) : c == CSV_CR || c == CSV_LF) { /* Carriage Return or Line Feed */
389
+ if (!quoted) {
390
+ SUBMIT_FIELD(p);
391
+ SUBMIT_ROW(p, (unsigned char)c);
392
+ } else {
393
+ SUBMIT_CHAR(p, c);
394
+ }
395
+ } else if (!quoted && (is_space? is_space(c) : c == CSV_SPACE || c == CSV_TAB)) { /* Tab or space for non-quoted field */
396
+ SUBMIT_CHAR(p, c);
397
+ spaces++;
398
+ } else { /* Anything else */
399
+ SUBMIT_CHAR(p, c);
400
+ spaces = 0;
401
+ }
402
+ break;
403
+ case FIELD_MIGHT_HAVE_ENDED:
404
+ /* This only happens when a quote character is encountered in a quoted field */
405
+ if (c == delim) { /* Comma */
406
+ entry_pos -= spaces + 1; /* get rid of spaces and original quote */
407
+ SUBMIT_FIELD(p);
408
+ } else if (is_term ? is_term(c) : c == CSV_CR || c == CSV_LF) { /* Carriage Return or Line Feed */
409
+ entry_pos -= spaces + 1; /* get rid of spaces and original quote */
410
+ SUBMIT_FIELD(p);
411
+ SUBMIT_ROW(p, (unsigned char)c);
412
+ } else if (is_space ? is_space(c) : c == CSV_SPACE || c == CSV_TAB) { /* Space or Tab */
413
+ SUBMIT_CHAR(p, c);
414
+ spaces++;
415
+ } else if (c == quote) { /* Quote */
416
+ if (spaces) {
417
+ /* STRICT ERROR - unescaped double quote */
418
+ if (p->options & CSV_STRICT) {
419
+ p->status = CSV_EPARSE;
420
+ p->quoted = quoted, p->pstate = pstate, p->spaces = spaces, p->entry_pos = entry_pos;
421
+ return pos-1;
422
+ }
423
+ spaces = 0;
424
+ SUBMIT_CHAR(p, c);
425
+ } else {
426
+ /* Two quotes in a row */
427
+ pstate = FIELD_BEGUN;
428
+ }
429
+ } else { /* Anything else */
430
+ /* STRICT ERROR - unescaped double quote */
431
+ if (p->options & CSV_STRICT) {
432
+ p->status = CSV_EPARSE;
433
+ p->quoted = quoted, p->pstate = pstate, p->spaces = spaces, p->entry_pos = entry_pos;
434
+ return pos-1;
435
+ }
436
+ pstate = FIELD_BEGUN;
437
+ spaces = 0;
438
+ SUBMIT_CHAR(p, c);
439
+ }
440
+ break;
441
+ default:
442
+ break;
443
+ }
444
+ }
445
+ p->quoted = quoted, p->pstate = pstate, p->spaces = spaces, p->entry_pos = entry_pos;
446
+ return pos;
447
+ }
448
+
449
+ size_t
450
+ csv_write (void *dest, size_t dest_size, const void *src, size_t src_size)
451
+ {
452
+ unsigned char *cdest = dest;
453
+ const unsigned char *csrc = src;
454
+ size_t chars = 0;
455
+
456
+ if (src == NULL)
457
+ return 0;
458
+
459
+ if (cdest == NULL)
460
+ dest_size = 0;
461
+
462
+ if (dest_size > 0)
463
+ *cdest++ = '"';
464
+ chars++;
465
+
466
+ while (src_size) {
467
+ if (*csrc == '"') {
468
+ if (dest_size > chars)
469
+ *cdest++ = '"';
470
+ if (chars < SIZE_MAX) chars++;
471
+ }
472
+ if (dest_size > chars)
473
+ *cdest++ = *csrc;
474
+ if (chars < SIZE_MAX) chars++;
475
+ src_size--;
476
+ csrc++;
477
+ }
478
+
479
+ if (dest_size > chars)
480
+ *cdest = '"';
481
+ if (chars < SIZE_MAX) chars++;
482
+
483
+ return chars;
484
+ }
485
+
486
+ int
487
+ csv_fwrite (FILE *fp, const void *src, size_t src_size)
488
+ {
489
+ const unsigned char *csrc = src;
490
+
491
+ if (fp == NULL || src == NULL)
492
+ return 0;
493
+
494
+ if (fputc('"', fp) == EOF)
495
+ return EOF;
496
+
497
+ while (src_size) {
498
+ if (*csrc == '"') {
499
+ if (fputc('"', fp) == EOF)
500
+ return EOF;
501
+ }
502
+ if (fputc(*csrc, fp) == EOF)
503
+ return EOF;
504
+ src_size--;
505
+ csrc++;
506
+ }
507
+
508
+ if (fputc('"', fp) == EOF) {
509
+ return EOF;
510
+ }
511
+
512
+ return 0;
513
+ }
514
+
515
+ size_t
516
+ csv_write2 (void *dest, size_t dest_size, const void *src, size_t src_size, unsigned char quote)
517
+ {
518
+ unsigned char *cdest = dest;
519
+ const unsigned char *csrc = src;
520
+ size_t chars = 0;
521
+
522
+ if (src == NULL)
523
+ return 0;
524
+
525
+ if (dest == NULL)
526
+ dest_size = 0;
527
+
528
+ if (dest_size > 0)
529
+ *cdest++ = quote;
530
+ chars++;
531
+
532
+ while (src_size) {
533
+ if (*csrc == quote) {
534
+ if (dest_size > chars)
535
+ *cdest++ = quote;
536
+ if (chars < SIZE_MAX) chars++;
537
+ }
538
+ if (dest_size > chars)
539
+ *cdest++ = *csrc;
540
+ if (chars < SIZE_MAX) chars++;
541
+ src_size--;
542
+ csrc++;
543
+ }
544
+
545
+ if (dest_size > chars)
546
+ *cdest = quote;
547
+ if (chars < SIZE_MAX) chars++;
548
+
549
+ return chars;
550
+ }
551
+
552
+ int
553
+ csv_fwrite2 (FILE *fp, const void *src, size_t src_size, unsigned char quote)
554
+ {
555
+ const unsigned char *csrc = src;
556
+
557
+ if (fp == NULL || src == NULL)
558
+ return 0;
559
+
560
+ if (fputc(quote, fp) == EOF)
561
+ return EOF;
562
+
563
+ while (src_size) {
564
+ if (*csrc == quote) {
565
+ if (fputc(quote, fp) == EOF)
566
+ return EOF;
567
+ }
568
+ if (fputc(*csrc, fp) == EOF)
569
+ return EOF;
570
+ src_size--;
571
+ csrc++;
572
+ }
573
+
574
+ if (fputc(quote, fp) == EOF) {
575
+ return EOF;
576
+ }
577
+
578
+ return 0;
579
+ }