rubex 0.0.1 → 0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +4 -0
- data/.travis.yml +14 -0
- data/CONTRIBUTING.md +101 -0
- data/HISTORY.md +3 -0
- data/README.md +112 -297
- data/REFERENCE.md +753 -0
- data/Rakefile +4 -1
- data/TUTORIAL.md +234 -0
- data/bin/rubex +1 -1
- data/docs/_config.yml +1 -0
- data/docs/index.html +1 -0
- data/examples/c_struct_interface/c_struct_interface.rb +6 -0
- data/examples/c_struct_interface/c_struct_interface.rubex +47 -0
- data/examples/linked_list/linked_list.rubex +39 -0
- data/examples/linked_list/rb_linked_list.rb +8 -0
- data/examples/rcsv wrapper/rcsv/README.md +1 -0
- data/examples/rcsv wrapper/rcsv/Rakefile +7 -0
- data/examples/rcsv wrapper/rcsv/ext/rcsv/extconf.rb +3 -0
- data/examples/rcsv wrapper/rcsv/ext/rcsv/rcsv.c +302 -0
- data/examples/rcsv wrapper/rcsv/ext/rcsv/rcsv.rubex +124 -0
- data/examples/rcsv wrapper/rcsv/lib/rcsv.rb +8 -0
- data/examples/rcsv wrapper/rcsv/lib/rcsv.so +0 -0
- data/examples/rcsv wrapper/rcsv/lib/rcsv/version.rb +1 -0
- data/examples/rcsv wrapper/rcsv/rcsv.gemspec +27 -0
- data/examples/rcsv wrapper/rcsv/spec/rcsv.csv +5 -0
- data/examples/rcsv wrapper/rcsv/spec/rcsv_spec.rb +17 -0
- data/examples/rcsv wrapper/rcsv/spec/spec_helper.rb +6 -0
- data/{spec/fixtures/basic_ruby_method/Makefile → examples/rcsv wrapper/rcsv/tmp/x86_64-linux/rcsv/2.3.3/Makefile } +20 -20
- data/examples/rcsv wrapper/rcsv/tmp/x86_64-linux/rcsv/2.3.3/rcsv.o +0 -0
- data/examples/rcsv wrapper/rcsv/tmp/x86_64-linux/rcsv/2.3.3/rcsv.so +0 -0
- data/examples/rcsv wrapper/rcsv/tmp/x86_64-linux/stage/lib/rcsv.so +0 -0
- data/lib/rubex.rb +6 -50
- data/lib/rubex/ast.rb +1 -3
- data/lib/rubex/ast/expression.rb +1257 -8
- data/lib/rubex/ast/node.rb +226 -28
- data/lib/rubex/ast/statement.rb +1162 -35
- data/lib/rubex/ast/top_statement.rb +815 -0
- data/lib/rubex/code_writer.rb +103 -26
- data/lib/rubex/compiler.rb +72 -0
- data/lib/rubex/compiler_config.rb +19 -0
- data/lib/rubex/constants.rb +145 -8
- data/lib/rubex/data_type.rb +667 -4
- data/lib/rubex/error.rb +15 -0
- data/lib/rubex/helpers.rb +154 -0
- data/lib/rubex/lexer.rex +186 -22
- data/lib/rubex/lexer.rex.rb +261 -35
- data/lib/rubex/parser.racc +876 -28
- data/lib/rubex/parser.racc.rb +2845 -90
- data/lib/rubex/rake_task.rb +34 -0
- data/lib/rubex/symbol_table/entry.rb +17 -3
- data/lib/rubex/symbol_table/scope.rb +298 -25
- data/lib/rubex/version.rb +1 -1
- data/rubex.gemspec +11 -3
- data/spec/basic_ruby_method_spec.rb +15 -21
- data/spec/binding_ptr_args_spec.rb +33 -0
- data/spec/bitwise_operators_spec.rb +40 -0
- data/spec/blocks_spec.rb +35 -0
- data/spec/c_bindings_spec.rb +36 -0
- data/spec/c_constants_spec.rb +33 -0
- data/spec/c_function_ptrs_spec.rb +38 -0
- data/spec/c_functions_spec.rb +35 -0
- data/spec/c_struct_interface_spec.rb +38 -0
- data/spec/call_by_reference_spec.rb +33 -0
- data/spec/class_methods_spec.rb +33 -0
- data/spec/class_spec.rb +40 -0
- data/spec/comments_spec.rb +33 -0
- data/spec/default_args_spec.rb +37 -0
- data/spec/error_handling_spec.rb +42 -0
- data/spec/examples_spec.rb +52 -0
- data/spec/expressions_spec.rb +33 -0
- data/spec/fixtures/basic_ruby_method/basic_ruby_method.rubex +2 -0
- data/spec/fixtures/binding_ptr_args/binding_ptr_args.rubex +30 -0
- data/spec/fixtures/bitwise_operators/bitwise_operators.rubex +40 -0
- data/spec/fixtures/blocks/blocks.rubex +11 -0
- data/spec/fixtures/c_bindings/c_bindings.rubex +58 -0
- data/spec/fixtures/c_constants/c_constants.rubex +7 -0
- data/spec/fixtures/c_function_ptrs/c_function_ptrs.rubex +52 -0
- data/spec/fixtures/c_functions/c_functions.rubex +25 -0
- data/spec/fixtures/c_struct_interface/c_struct_interface.rubex +34 -0
- data/spec/fixtures/call_by_reference/call_by_reference.rubex +30 -0
- data/spec/fixtures/class/class.rubex +20 -0
- data/spec/fixtures/class_methods/class_methods.rubex +12 -0
- data/spec/fixtures/comments/comments.rubex +9 -0
- data/spec/fixtures/default_args/default_args.rubex +11 -0
- data/spec/fixtures/error_handling/error_handling.rubex +54 -0
- data/spec/fixtures/examples/array_to_hash.rubex +14 -0
- data/spec/fixtures/examples/rcsv.csv +5 -0
- data/spec/fixtures/examples/rcsv.rubex +329 -0
- data/spec/fixtures/expressions/expressions.rubex +10 -0
- data/spec/fixtures/if_else/if_else.rubex +77 -0
- data/spec/fixtures/implicit_lib_include/implicit_lib_include.rubex +15 -0
- data/spec/fixtures/init_ruby_objects_with_literal_syntax/init_ruby_objects_with_literal_syntax.rubex +17 -0
- data/spec/fixtures/loops/loops.rubex +33 -0
- data/spec/fixtures/recursion/recursion.rubex +9 -0
- data/spec/fixtures/ruby_constant_method_calls/ruby_constant_method_calls.rubex +17 -0
- data/spec/fixtures/ruby_operators/ruby_operators.rubex +29 -0
- data/spec/fixtures/ruby_raise/ruby_raise.rubex +13 -0
- data/spec/fixtures/ruby_strings/ruby_strings.rubex +19 -0
- data/spec/fixtures/ruby_strings/string_blank_bm.rb +37 -0
- data/spec/fixtures/ruby_symbols/ruby_symbols.rubex +12 -0
- data/spec/fixtures/ruby_types/ruby_types.rubex +15 -0
- data/spec/fixtures/statement_expression/statement_expression.rubex +23 -0
- data/spec/fixtures/static_array/static_array.rubex +20 -0
- data/spec/fixtures/string_literals/string_literals.rubex +15 -0
- data/spec/fixtures/struct/struct.rubex +82 -0
- data/spec/fixtures/typecasting/typecasting.rubex +23 -0
- data/spec/fixtures/var_declarations/var_declarations.rubex +39 -0
- data/spec/if_else_spec.rb +39 -0
- data/spec/implicit_lib_include_spec.rb +33 -0
- data/spec/init_ruby_objects_with_literal_syntax_spec.rb +39 -0
- data/spec/loops_spec.rb +34 -0
- data/spec/recursion_spec.rb +35 -0
- data/spec/ruby_constant_method_calls_spec.rb +35 -0
- data/spec/ruby_operators_spec.rb +40 -0
- data/spec/ruby_raise_spec.rb +35 -0
- data/spec/ruby_strings_spec.rb +33 -0
- data/spec/ruby_symbols_spec.rb +37 -0
- data/spec/ruby_types_spec.rb +35 -0
- data/spec/spec_helper.rb +54 -1
- data/spec/statement_expression_spec.rb +34 -0
- data/spec/static_array_spec.rb +33 -0
- data/spec/string_literals_spec.rb +34 -0
- data/spec/struct_spec.rb +36 -0
- data/spec/typecasting_spec.rb +38 -0
- data/spec/var_declarions_spec.rb +35 -0
- metadata +255 -29
- data/lib/rubex/ast/argument_list.rb +0 -20
- data/lib/rubex/ast/c_base_type.rb +0 -11
- data/lib/rubex/ast/ruby_method_def.rb +0 -84
- data/spec/fixtures/basic_ruby_method/basic.rb +0 -3
- data/spec/fixtures/basic_ruby_method/basic_ruby_method.c +0 -16
- data/spec/fixtures/basic_ruby_method/basic_ruby_method.o +0 -0
- data/spec/fixtures/basic_ruby_method/basic_ruby_method.so +0 -0
- data/spec/fixtures/basic_ruby_method/extconf.rb +0 -3
@@ -0,0 +1,30 @@
|
|
1
|
+
struct attribs
|
2
|
+
int a, b
|
3
|
+
float c
|
4
|
+
end
|
5
|
+
|
6
|
+
class CallByReference
|
7
|
+
def ref_call
|
8
|
+
attribs a
|
9
|
+
int b_flat = 1
|
10
|
+
int *i
|
11
|
+
a.a = 1
|
12
|
+
a.b = 1
|
13
|
+
|
14
|
+
i = &b_flat
|
15
|
+
c_function(&a, b_flat, i)
|
16
|
+
add(&a)
|
17
|
+
|
18
|
+
b_flat = a.c + i[0]
|
19
|
+
|
20
|
+
return b_flat
|
21
|
+
end
|
22
|
+
|
23
|
+
cfunc void c_function(attribs *a, int b, int *i)
|
24
|
+
a[0].a = b + i[0]
|
25
|
+
end
|
26
|
+
|
27
|
+
cfunc void add(attribs *a)
|
28
|
+
a[0].c = a[0].a + a[0].b
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Kustom
|
2
|
+
def bye
|
3
|
+
prelude
|
4
|
+
return "Bye world!"
|
5
|
+
end
|
6
|
+
|
7
|
+
def prelude
|
8
|
+
return "This is a prelude."
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Kustom2 < Kustom
|
13
|
+
def hello
|
14
|
+
a = prelude
|
15
|
+
return a.concat("Hello world!")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class RandomRubyError < StandardError
|
20
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class Handler
|
2
|
+
def error_test(num)
|
3
|
+
int i = num
|
4
|
+
int j = 0
|
5
|
+
|
6
|
+
begin
|
7
|
+
raise(ArgumentError, "Horrible error.") if i == 1
|
8
|
+
raise(LoadError, "Bad error.") if i == 2
|
9
|
+
raise(SyntaxError, "Disgusting error.") if i == 3
|
10
|
+
rescue ArgumentError
|
11
|
+
j = 1
|
12
|
+
rescue LoadError
|
13
|
+
j = 2
|
14
|
+
rescue SyntaxError
|
15
|
+
j = 3
|
16
|
+
else
|
17
|
+
j = 4
|
18
|
+
ensure
|
19
|
+
j += 5
|
20
|
+
end
|
21
|
+
|
22
|
+
return j
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_uncaught_error
|
26
|
+
begin
|
27
|
+
raise ArgumentError
|
28
|
+
rescue SyntaxError
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_without_rescue
|
33
|
+
int i = 1
|
34
|
+
begin
|
35
|
+
raise ArgumentError
|
36
|
+
ensure
|
37
|
+
return i
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_decl_inside_begin
|
42
|
+
int i
|
43
|
+
string = "hello world"
|
44
|
+
|
45
|
+
begin
|
46
|
+
char* s = string
|
47
|
+
raise(ArgumentError) if s[0] == 'h'
|
48
|
+
rescue ArgumentError
|
49
|
+
i = 44
|
50
|
+
end
|
51
|
+
|
52
|
+
return i
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,329 @@
|
|
1
|
+
lib "rubex/ruby"; end
|
2
|
+
lib "rubex/ruby/encoding"; end
|
3
|
+
lib "rubex/stdlib"; end
|
4
|
+
|
5
|
+
lib "csv.h", link: "csv"
|
6
|
+
struct csv_parser
|
7
|
+
end
|
8
|
+
|
9
|
+
struct FILE
|
10
|
+
end
|
11
|
+
|
12
|
+
int CSV_STRICT_FINI
|
13
|
+
int CSV_APPEND_NULL
|
14
|
+
int CSV_EPARSE
|
15
|
+
int CSV_ENOMEM
|
16
|
+
int CSV_ETOOBIG
|
17
|
+
int CSV_EINVALID
|
18
|
+
int CSV_STRICT
|
19
|
+
int CSV_EMPTY_IS_NULL
|
20
|
+
|
21
|
+
int csv_init(csv_parser, unsigned char)
|
22
|
+
int csv_fini(csv_parser, void (*cb1)(void *, size_t, void *), void (*cb2)(int, void *), void *)
|
23
|
+
void csv_free(csv_parser *)
|
24
|
+
int csv_error(csv_parser *)
|
25
|
+
char * csv_strerror(int)
|
26
|
+
size_t csv_parse(csv_parser *p, void *, size_t, void (*cb1)(void *, size_t, void *), void (*cb2)(int, void *), void *)
|
27
|
+
size_t csv_write(void *, size_t, void *, size_t)
|
28
|
+
int csv_fwrite(FILE *, void *, size_t)
|
29
|
+
size_t csv_write2(void *, size_t, void *, size_t, unsigned char)
|
30
|
+
int csv_fwrite2(FILE *, void *, size_t, unsigned char)
|
31
|
+
int csv_get_opts(csv_parser *)
|
32
|
+
int csv_set_opts(csv_parser *, unsigned char)
|
33
|
+
void csv_set_delim(csv_parser *, unsigned char)
|
34
|
+
void csv_set_quote(csv_parser *, unsigned char)
|
35
|
+
unsigned char csv_get_delim(csv_parser *)
|
36
|
+
unsigned char csv_get_quote(csv_parser *)
|
37
|
+
void csv_set_space_func(csv_parser *, int (*f)(unsigned char))
|
38
|
+
void csv_set_term_func(csv_parser *, int (*f)(unsigned char))
|
39
|
+
void csv_set_realloc_func(csv_parser *, void *(*cb)(void *, size_t))
|
40
|
+
void csv_set_free_func(csv_parser *, void (*cb)(void *))
|
41
|
+
void csv_set_blk_size(csv_parser *, size_t)
|
42
|
+
size_t csv_get_buffer_size(csv_parser *)
|
43
|
+
end
|
44
|
+
|
45
|
+
struct rcsv_metadata
|
46
|
+
# Derived from user-specified options
|
47
|
+
bool row_as_hash # Used to return array of hashes rather than array of arrays
|
48
|
+
bool empty_field_is_nil # Do we convert empty fields to nils?
|
49
|
+
size_t offset_rows # Number of rows to skip before parsing
|
50
|
+
int encoding_index # If available, the encoding index of the original input
|
51
|
+
|
52
|
+
char * row_conversions # A pointer to string/array of row conversions char specifiers
|
53
|
+
object * only_rows # A pointer to array of row filters
|
54
|
+
object * except_rows # A pointer to array of negative row filters
|
55
|
+
object * row_defaults # A pointer to array of row defaults
|
56
|
+
object * column_names # A pointer to array of column names to be used with hashes
|
57
|
+
|
58
|
+
# Pointer options lengths
|
59
|
+
size_t num_row_conversions # Number of converter types in row_conversions array
|
60
|
+
size_t num_only_rows # Number of items in only_rows filter
|
61
|
+
size_t num_except_rows # Number of items in except_rows filter
|
62
|
+
size_t num_row_defaults # Number of default values in row_defaults array
|
63
|
+
size_t num_columns # Number of columns detected from column_names.size
|
64
|
+
|
65
|
+
# Internal state
|
66
|
+
bool skip_current_row # Used by only_rows and except_rows filters to skip parsing of the row remainder
|
67
|
+
size_t current_col # Current column's index
|
68
|
+
size_t current_row # Current row's index
|
69
|
+
|
70
|
+
object last_entry # A pointer to the last entry that's going to be appended to result
|
71
|
+
object result # A pointer to the parsed data
|
72
|
+
end
|
73
|
+
|
74
|
+
class RcsvParseError < StandardError
|
75
|
+
end
|
76
|
+
|
77
|
+
class Rcsv
|
78
|
+
cfunc object validate_filter_row(row)
|
79
|
+
if row == nil
|
80
|
+
return nil
|
81
|
+
elsif row.is_a?(Array)
|
82
|
+
size_t j
|
83
|
+
int r_size = row.size
|
84
|
+
int type
|
85
|
+
for (0 <= j < r_size) do
|
86
|
+
type = TYPE(row[i])
|
87
|
+
|
88
|
+
if type == T_NIL || type == T_TRUE || type == T_FALSE || type == T_FLOAT || type == T_FLOAT || type == T_FIXNUM || type == T_STRING
|
89
|
+
break
|
90
|
+
else
|
91
|
+
raise(RcsvParseError, "Wrong type passed.")
|
92
|
+
end
|
93
|
+
end
|
94
|
+
return row
|
95
|
+
else
|
96
|
+
raise(RcsvParseError, "Wrong type passed.")
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
cfunc void end_of_field_callback(void* field, size_t field_size, void* data)
|
102
|
+
char* field_str = <char *>field
|
103
|
+
rcsv_metadata* meta_p = <rcsv_metadata*>data
|
104
|
+
rcsv_metadata meta = meta_p[0]
|
105
|
+
char row_conversion = 0
|
106
|
+
object parsed_field
|
107
|
+
|
108
|
+
# No need to parse anything until the end of the line if skip_current_row is set */
|
109
|
+
# return if meta.skip_current_row
|
110
|
+
|
111
|
+
# Skip the row if its position is less than specifed offset
|
112
|
+
if (meta.current_row < meta.offset_rows)
|
113
|
+
meta_p[0].skip_current_row = true
|
114
|
+
return
|
115
|
+
end
|
116
|
+
|
117
|
+
parsed_field = ENCODED_STR_NEW(field_str, field_size, meta.encoding_index)
|
118
|
+
|
119
|
+
# Filter by row values listed in meta->only_rows */
|
120
|
+
if ((meta.only_rows != NULL) && (meta.current_col < meta.num_only_rows) && (meta.only_rows[meta.current_col] != nil) && (!rb_ary_includes(meta.only_rows[meta.current_col], parsed_field)))
|
121
|
+
meta_p[0].skip_current_row = true
|
122
|
+
return
|
123
|
+
end
|
124
|
+
# Filter out by row values listed in meta->except_rows
|
125
|
+
if ((meta.except_rows != NULL) && (meta.current_col < meta.num_except_rows) && (meta.except_rows[meta.current_col] != nil) && (rb_ary_includes(meta.except_rows[meta.current_col], parsed_field)))
|
126
|
+
meta.skip_current_row = true
|
127
|
+
return
|
128
|
+
end
|
129
|
+
|
130
|
+
# Assign the value to appropriate hash key if parsing into Hash */
|
131
|
+
if meta.row_as_hash
|
132
|
+
if meta.current_col >= meta.num_columns
|
133
|
+
raise_with_location(meta.current_row, meta.current_col, field_str)
|
134
|
+
else
|
135
|
+
meta_p[0].last_entry[meta.column_names[meta.current_col]] = parsed_field
|
136
|
+
end
|
137
|
+
else # Parse into Array
|
138
|
+
meta_p[0].last_entry.push(parsed_field) # /* last_entry << field */
|
139
|
+
end
|
140
|
+
|
141
|
+
# Increment column counter */
|
142
|
+
meta_p[0].current_col += 1
|
143
|
+
return
|
144
|
+
end
|
145
|
+
|
146
|
+
cfunc void raise_with_location(size_t current_row, size_t current_col, char* string)
|
147
|
+
end
|
148
|
+
|
149
|
+
cfunc void end_of_line_callback(int last_char, void* data)
|
150
|
+
rcsv_metadata* meta_p = <rcsv_metadata *> data
|
151
|
+
rcsv_metadata meta = meta_p[0]
|
152
|
+
|
153
|
+
# If filters didn't match, current row parsing is reverted */
|
154
|
+
if meta.skip_current_row
|
155
|
+
meta.skip_current_row = false
|
156
|
+
else
|
157
|
+
if block_given? # STREAMING
|
158
|
+
yield(meta.last_entry)
|
159
|
+
else
|
160
|
+
meta_p[0].result.push(meta.last_entry)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# /* Re-initialize last_entry unless EOF reached */
|
165
|
+
if last_char != -1
|
166
|
+
if meta.row_as_hash
|
167
|
+
meta.last_entry = {}
|
168
|
+
else
|
169
|
+
meta_p[0].last_entry = []
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# Resetting column counter
|
174
|
+
meta.current_col = 0
|
175
|
+
|
176
|
+
# Incrementing row counter
|
177
|
+
meta.current_row += 1
|
178
|
+
end
|
179
|
+
|
180
|
+
cfunc object ENCODED_STR_NEW(char* string, int length, int enc_index)
|
181
|
+
_string = rb_str_new(string, length)
|
182
|
+
if (enc_index != -1)
|
183
|
+
rb_enc_associate_index(_string, enc_index)
|
184
|
+
end
|
185
|
+
return _string
|
186
|
+
end
|
187
|
+
|
188
|
+
cfunc void free_all_memory(csv_parser *p_cp, rcsv_metadata *p_meta)
|
189
|
+
if p_cp
|
190
|
+
csv_free(p_cp)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
cfunc void setup_rcsv_metadata_defaults(rcsv_metadata *p_meta)
|
195
|
+
p_meta[0].row_as_hash = 0
|
196
|
+
p_meta[0].empty_field_is_nil = 0
|
197
|
+
p_meta[0].skip_current_row = 0
|
198
|
+
p_meta[0].encoding_index = -1
|
199
|
+
p_meta[0].num_columns = 0
|
200
|
+
p_meta[0].current_col = 0
|
201
|
+
p_meta[0].current_row = 0
|
202
|
+
p_meta[0].offset_rows = 0
|
203
|
+
p_meta[0].num_only_rows = 0
|
204
|
+
p_meta[0].num_except_rows = 0
|
205
|
+
p_meta[0].num_row_defaults = 0
|
206
|
+
p_meta[0].num_row_conversions = 0
|
207
|
+
p_meta[0].only_rows = NULL
|
208
|
+
p_meta[0].except_rows = NULL
|
209
|
+
p_meta[0].row_defaults = NULL
|
210
|
+
p_meta[0].row_conversions = NULL
|
211
|
+
p_meta[0].column_names = NULL
|
212
|
+
p_meta[0].result = []
|
213
|
+
end
|
214
|
+
|
215
|
+
def self.parse(file_name, opts)
|
216
|
+
rcsv_metadata meta
|
217
|
+
object csvio, options, option
|
218
|
+
csv_parser cp
|
219
|
+
ensure_container = []
|
220
|
+
unsigned char csv_options = CSV_STRICT_FINI | CSV_APPEND_NULL
|
221
|
+
int csv_string_len
|
222
|
+
|
223
|
+
setup_rcsv_metadata_defaults(&meta)
|
224
|
+
csvio = StringIO.new(file_name)
|
225
|
+
|
226
|
+
if !opts[:nostrict]
|
227
|
+
csv_options |= CSV_STRICT
|
228
|
+
end
|
229
|
+
|
230
|
+
option = opts[:parse_empty_fields_as]
|
231
|
+
|
232
|
+
if option == nil || option == :nil_or_string
|
233
|
+
csv_options |= CSV_EMPTY_IS_NULL
|
234
|
+
elsif option.nil?
|
235
|
+
meta.empty_field_is_nil = 1
|
236
|
+
elsif option == :string
|
237
|
+
meta.empty_field_is_nil = 0
|
238
|
+
else
|
239
|
+
raise(RcsvParseError, "The only valid options for :parse_empty_fields_as are :nil, :string and :nil_or_string.")
|
240
|
+
end
|
241
|
+
|
242
|
+
if csv_init(&cp, csv_options) == -1
|
243
|
+
raise(RcsvParseError, "Failed to initialize libcsv.")
|
244
|
+
end
|
245
|
+
|
246
|
+
buffer_size = opts[:buffer_size]
|
247
|
+
meta.row_as_hash = 1 if opts[:row_as_hash]
|
248
|
+
|
249
|
+
csv_set_delim(&cp, col_sep) if opts[:col_sep]
|
250
|
+
csv_set_quote(&cp, quote_char) if opts[:quote_char]
|
251
|
+
|
252
|
+
meta.offset_rows = opts[:offset_rows] if opts[:offset_rows]
|
253
|
+
|
254
|
+
# Specify character encoding
|
255
|
+
option = opts[:output_encoding]
|
256
|
+
meta.encoding_index = rb_enc_find_index(<char*>option) if option != nil
|
257
|
+
|
258
|
+
# :only_rows is a list of values where row is only parsed
|
259
|
+
# if its fields match those in the passed array.
|
260
|
+
option = opts[:only_rows]
|
261
|
+
if option
|
262
|
+
meta.num_only_rows = option.size
|
263
|
+
meta.only_rows = <object*>xmalloc(meta.num_only_rows * sizeof(object))
|
264
|
+
|
265
|
+
int i = 0
|
266
|
+
|
267
|
+
for 0 <= i < meta.num_only_rows do
|
268
|
+
only_row = option[i]
|
269
|
+
meta.only_rows[i] = validate_filter_row(only_row)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
# TODO: row_defaults, row_conversions, column name declaration when parsing
|
273
|
+
# fields as Hashes,
|
274
|
+
|
275
|
+
# :row_conversions specifies Ruby types that CSV field values should be
|
276
|
+
# converted into. Each char of row_conversions string represents Ruby
|
277
|
+
# type for CSV field with matching position.
|
278
|
+
row_conversions = opts[:row_conversions]
|
279
|
+
if row_conversions
|
280
|
+
meta.num_row_conversions = row_conversions.size
|
281
|
+
meta.row_conversions = row_conversions
|
282
|
+
end
|
283
|
+
|
284
|
+
if meta.row_as_hash
|
285
|
+
column_names = opts[:column_names]
|
286
|
+
|
287
|
+
if column_names.nil?
|
288
|
+
# raise RcsvParseError, ":row_as_hash requires :column_names to be set."
|
289
|
+
else
|
290
|
+
meta.last_entry = {}
|
291
|
+
meta.num_columns = column_names.size
|
292
|
+
meta.column_names = column_names
|
293
|
+
end
|
294
|
+
else
|
295
|
+
meta.last_entry = []
|
296
|
+
end
|
297
|
+
|
298
|
+
while true do
|
299
|
+
csvstr = csvio.read
|
300
|
+
# print csvstr
|
301
|
+
if csvstr.nil? || csvstr.size == 0
|
302
|
+
break
|
303
|
+
end
|
304
|
+
|
305
|
+
char* csv_string = csvstr
|
306
|
+
csv_string_len = csvstr.size
|
307
|
+
|
308
|
+
if csv_string_len != csv_parse(&cp, csv_string, csv_string_len, &end_of_field_callback, &end_of_line_callback, &meta)
|
309
|
+
int error = csv_error(&cp)
|
310
|
+
|
311
|
+
if error == CSV_EPARSE
|
312
|
+
raise(RcsvParseError, "Error when parsing malformed data.")
|
313
|
+
elsif error == CSV_ENOMEM
|
314
|
+
raise(RcsvParseError, "No memory.")
|
315
|
+
elsif error == CSV_ETOOBIG
|
316
|
+
raise(RcsvParseError, "Field data data is too large.")
|
317
|
+
elsif error == CSV_EINVALID
|
318
|
+
raise(RcsvParseError, "#{csv_strerror(error)}")
|
319
|
+
else
|
320
|
+
raise(RcsvParseError, "Something went wrong.")
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
csv_fini(&cp, &end_of_field_callback, &end_of_line_callback, &meta)
|
326
|
+
free_all_memory(&cp, &meta)
|
327
|
+
return meta.result
|
328
|
+
end
|
329
|
+
end
|