bzip2-ruby 0.2.6 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,8 @@
1
+ _10lines_
2
+ doc
3
+ ext/Makefile
4
+ ext/*.o
5
+ ext/*.so
6
+ ext/*.bundle
7
+ pkg
8
+ .bundle
@@ -0,0 +1 @@
1
+ --no-private
@@ -1,8 +1,28 @@
1
+ == 0.2.7 2010-11-16
2
+
3
+ * Add documentation for an overview of the Bzip2 module
4
+ * Document the class methods on Bzip2 and get them to show up in yarddoc
5
+ * Remove the ConfigError class because searching for it showed no instances of its usage
6
+ * Add a Usage section to the README and a bit about adding it to a Gemfile
7
+ * Improve the reader_spec.rb by making it more resilient in lots of places and a bit more descriptive/terse in
8
+ * Add a lot more documentation for the Reader class and also touch up the Writer class a bit
9
+ * Make the Writer specs more descriptive by giving them some doc strings.
10
+ * Wrap up documentation of the Bzip2::Writer class.
11
+ * Add lib/bzip2-ruby.rb so it's not always necessary to specify to require 'bzip2' in Gemfiles and such
12
+ * Start documenting the Bzip2::Writer class
13
+ * Fix a few compiler warnings
14
+ * Removed some dead code
15
+ * Fix for ruby 1.9 compatibility.
16
+ * Fix segfault when exiting in ruby 1.9
17
+ * Follow the newer conventions of rspec
18
+ * Migrate to using Bundler instead of Jeweler
19
+ * use malloc/free instead of ruby_xmalloc/ruby_xfree
20
+
1
21
  == 0.2.6 2009-10-6
2
22
 
3
23
  * Updated to support Ruby 1.8.5
4
24
 
5
- == 0.2.5 ???
25
+ == 0.2.5 2009-06-07
6
26
 
7
27
  * initial conversion of original tests over to rspec
8
28
 
@@ -23,3 +43,52 @@
23
43
  * 1 major enhancement:
24
44
  * Gemify bz2 library from http://moulon.inra.fr/ruby/bz2.html
25
45
  * All credit goes to Guy Decoux <ts@moulon.inra.fr>
46
+
47
+ === 0.2.1
48
+
49
+ * replaced rb_proc_new() with bz_proc_new() for 1.6
50
+ (Thanks "Akinori MUSHA" <knu@iDaemons.org>)
51
+
52
+ === 0.1.9
53
+
54
+ * corrected BZ_FINISH_OK (Thanks Rudi Cilibrasi <Rudi.Cilibrasi@cwi.nl>)
55
+
56
+ === 0.1.6
57
+
58
+ * adapted for 1.8.0 (ihi)
59
+ * modified ::new
60
+ * BZ2::Writer#finish (same than #flush)
61
+
62
+ === 0.1.5
63
+
64
+ * corrected extconf.rb
65
+ * added close!
66
+ * replaced close(false) by #finish
67
+ * corrected #flush
68
+
69
+ === 0.1.4
70
+
71
+ * corrected bz_iv
72
+ * #to_io
73
+ * corrected ::Reader#close
74
+
75
+ === 0.1.3
76
+
77
+ * corrected #lineno
78
+ * corrected ::Writer::new(nil)
79
+ * taint result
80
+
81
+ === 0.1.2
82
+
83
+ * better (???) interface for #read
84
+ * finalize for objects which respond to #closed?
85
+
86
+ === 0.1.1
87
+
88
+ * better interface for T_FILE
89
+ * corrected bug with gc (buf)
90
+ * Reader#lineno, Reader#lineno=, Reader#ungets
91
+ * corrected Reader#unused
92
+ * taint check in #initialize
93
+ * BZ2::bzip2, BZ2::bunzip2
94
+ * too many exceptions
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :gemcutter
2
+
3
+ gemspec
@@ -0,0 +1,26 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ bzip2-ruby (0.2.6)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.1.2)
10
+ rspec (2.0.0)
11
+ rspec-core (= 2.0.0)
12
+ rspec-expectations (= 2.0.0)
13
+ rspec-mocks (= 2.0.0)
14
+ rspec-core (2.0.0)
15
+ rspec-expectations (2.0.0)
16
+ diff-lcs (>= 1.1.2)
17
+ rspec-mocks (2.0.0)
18
+ rspec-core (= 2.0.0)
19
+ rspec-expectations (= 2.0.0)
20
+
21
+ PLATFORMS
22
+ ruby
23
+
24
+ DEPENDENCIES
25
+ bzip2-ruby!
26
+ rspec (>= 2.0.0)
@@ -2,14 +2,55 @@
2
2
 
3
3
  == Installation
4
4
 
5
- sudo gem install brianmario-bzip2-ruby -s http://gems.github.com/
6
-
5
+ First make sure you’ve got Gemcutter in your sources list:
6
+
7
+ gem sources -a http://gemcutter.org
8
+
9
+ Then go ahead and install it as usual:
10
+
11
+ sudo gem install bzip2-ruby
12
+
7
13
  You may need to specify:
8
14
 
9
15
  --with-bz2-dir=<include file directory for libbzip2>
10
16
 
17
+ Or in a Gemfile
18
+
19
+ gem 'bzip2-ruby'
20
+
21
+ == Usage
22
+
23
+ The full documentation is hosted on {rdoc.info}[http://rdoc.info/github/brianmario/bzip2-ruby/master/frames].
24
+
25
+ Here's a quick overview, hower:
26
+
27
+ require 'bzip2'
28
+
29
+ # Quick shortcuts
30
+ data = Bzip2.compress 'string'
31
+ Bzip2.uncompress data
32
+
33
+ # Creating a bz2 compressed file
34
+ writer = Bzip2::Writer.new File.open('file')
35
+ writer << 'data1'
36
+ writer.puts 'data2'
37
+ writer.print 'data3'
38
+ writer.printf '%s', 'data4'
39
+ writer.close
40
+
41
+ Bzip2::Writer.open('file'){ |f| f << data }
42
+
43
+ # Reading a bz2 compressed file
44
+ reader = Bzip2::Reader.new File.open('file')
45
+ reader.gets # => "data1data2\n"
46
+ reader.read # => 'data3data4'
47
+
48
+ reader.readline # => raises Bzip2::EOZError
49
+
50
+ Bzip2::Reader.open('file'){ |f| puts f.read }
51
+
11
52
  == Copying
12
-
53
+
13
54
  This extension module is copyrighted free software by Guy Decoux
14
55
  You can redistribute it and/or modify it under the same term as Ruby.
15
56
  Guy Decoux <ts@moulon.inra.fr>
data/Rakefile CHANGED
@@ -1,19 +1,2 @@
1
- # encoding: UTF-8
2
- begin
3
- require 'jeweler'
4
- Jeweler::Tasks.new do |gem|
5
- gem.name = "bzip2-ruby"
6
- gem.summary = "Ruby C bindings to libbzip2."
7
- gem.email = "seniorlopez@gmail.com"
8
- gem.homepage = "http://github.com/brianmario/bzip2-ruby"
9
- gem.authors = ["Guy Decoux", "Brian Lopez"]
10
- gem.require_paths = ["lib", "ext"]
11
- gem.extra_rdoc_files = `git ls-files *.rdoc`.split("\n")
12
- gem.files = `git ls-files`.split("\n")
13
- gem.extensions = ["ext/extconf.rb"]
14
- gem.files.include %w(lib/jeweler/templates/.document lib/jeweler/templates/.gitignore)
15
- # gem.rubyforge_project = "bzip2-ruby"
16
- end
17
- rescue LoadError
18
- puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
19
- end
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -1,54 +1,20 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
1
  # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'bzip2/version'
5
4
 
6
5
  Gem::Specification.new do |s|
7
- s.name = %q{bzip2-ruby}
8
- s.version = "0.2.6"
6
+ s.name = 'bzip2-ruby'
7
+ s.version = Bzip2::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ['Guy Decoux', 'Brian Lopezs']
10
+ s.email = ['seniorlopez@gmail.com']
11
+ s.homepage = 'http://github.com/brianmario/bzip2-ruby'
12
+ s.summary = 'Ruby C bindings to libbzip2.'
9
13
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Guy Decoux", "Brian Lopez"]
12
- s.date = %q{2009-10-06}
13
- s.email = %q{seniorlopez@gmail.com}
14
- s.extensions = ["ext/extconf.rb"]
15
- s.extra_rdoc_files = [
16
- "CHANGELOG.rdoc",
17
- "README.rdoc"
18
- ]
19
- s.files = [
20
- "CHANGELOG.rdoc",
21
- "README.rdoc",
22
- "Rakefile",
23
- "VERSION.yml",
24
- "bzip2-ruby.gemspec",
25
- "ext/bzip2.c",
26
- "ext/extconf.rb",
27
- "lib/bzip2.rb",
28
- "spec/reader_spec.rb",
29
- "spec/spec_helper.rb",
30
- "spec/writer_spec.rb",
31
- "tasks/extconf.rake",
32
- "tasks/extconf/bz2.rake"
33
- ]
34
- s.homepage = %q{http://github.com/brianmario/bzip2-ruby}
35
- s.rdoc_options = ["--charset=UTF-8"]
36
- s.require_paths = ["lib", "ext"]
37
- s.rubygems_version = %q{1.3.5}
38
- s.summary = %q{Ruby C bindings to libbzip2.}
39
- s.test_files = [
40
- "spec/reader_spec.rb",
41
- "spec/spec_helper.rb",
42
- "spec/writer_spec.rb"
43
- ]
14
+ s.extensions = ['ext/extconf.rb']
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- spec/*`.split("\n")
17
+ s.require_paths = ['lib', 'ext']
44
18
 
45
- if s.respond_to? :specification_version then
46
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
47
- s.specification_version = 3
48
-
49
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
50
- else
51
- end
52
- else
53
- end
19
+ s.add_development_dependency 'rspec', '>= 2.0.0'
54
20
  end
@@ -1,5 +1,6 @@
1
1
  #include <ruby.h>
2
2
  #include <bzlib.h>
3
+ #include <unistd.h>
3
4
  #ifndef RUBY_19_COMPATIBILITY
4
5
  #include <rubyio.h>
5
6
  #include <version.h>
@@ -8,7 +9,7 @@
8
9
  #endif
9
10
 
10
11
  static VALUE bz_cWriter, bz_cReader, bz_cInternal;
11
- static VALUE bz_eError, bz_eConfigError, bz_eEOZError;
12
+ static VALUE bz_eError, bz_eEOZError;
12
13
 
13
14
  static VALUE bz_internal_ary;
14
15
 
@@ -36,7 +37,7 @@ struct bz_file {
36
37
  bz_stream bzs;
37
38
  VALUE in, io;
38
39
  char *buf;
39
- int buflen;
40
+ unsigned int buflen;
40
41
  int blocks, work, small;
41
42
  int flags, lineno, state;
42
43
  };
@@ -51,150 +52,123 @@ struct bz_iv {
51
52
  void (*finalize)();
52
53
  };
53
54
 
54
- #define Get_BZ2(obj, bzf) \
55
- rb_io_taint_check(obj); \
55
+ #define Get_BZ2(obj, bzf) \
56
+ rb_io_taint_check(obj); \
56
57
  Data_Get_Struct(obj, struct bz_file, bzf); \
57
- if (!RTEST(bzf->io)) { \
58
- rb_raise(rb_eIOError, "closed IO"); \
58
+ if (!RTEST(bzf->io)) { \
59
+ rb_raise(rb_eIOError, "closed IO"); \
59
60
  }
60
61
 
61
- static VALUE
62
- bz_raise(error)
63
- int error;
64
- {
62
+ static VALUE bz_raise(int error) {
65
63
  VALUE exc;
66
- char *msg;
64
+ const char *msg;
67
65
 
68
66
  exc = bz_eError;
69
67
  switch (error) {
70
- case BZ_SEQUENCE_ERROR:
71
- msg = "incorrect sequence";
72
- break;
73
- case BZ_PARAM_ERROR:
74
- msg = "parameter out of range";
75
- break;
76
- case BZ_MEM_ERROR:
77
- msg = "not enough memory is available";
78
- break;
79
- case BZ_DATA_ERROR:
80
- msg = "data integrity error is detected";
81
- break;
82
- case BZ_DATA_ERROR_MAGIC:
83
- msg = "compressed stream does not start with the correct magic bytes";
84
- break;
85
- case BZ_IO_ERROR:
86
- msg = "error reading or writing";
87
- break;
88
- case BZ_UNEXPECTED_EOF:
89
- exc = bz_eEOZError;
90
- msg = "compressed file finishes before the logical end of stream is detected";
91
- break;
92
- case BZ_OUTBUFF_FULL:
93
- msg = "output buffer full";
94
- break;
95
- case BZ_CONFIG_ERROR:
96
- exc = bz_eConfigError;
97
- msg = "library has been improperly compiled on your platform";
98
- break;
99
- default:
100
- msg = "unknown error";
101
- exc = bz_eError;
68
+ case BZ_SEQUENCE_ERROR:
69
+ msg = "incorrect sequence";
70
+ break;
71
+ case BZ_PARAM_ERROR:
72
+ msg = "parameter out of range";
73
+ break;
74
+ case BZ_MEM_ERROR:
75
+ msg = "not enough memory is available";
76
+ break;
77
+ case BZ_DATA_ERROR:
78
+ msg = "data integrity error is detected";
79
+ break;
80
+ case BZ_DATA_ERROR_MAGIC:
81
+ msg = "compressed stream does not start with the correct magic bytes";
82
+ break;
83
+ case BZ_IO_ERROR:
84
+ msg = "error reading or writing";
85
+ break;
86
+ case BZ_UNEXPECTED_EOF:
87
+ exc = bz_eEOZError;
88
+ msg = "compressed file finishes before the logical end of stream is detected";
89
+ break;
90
+ case BZ_OUTBUFF_FULL:
91
+ msg = "output buffer full";
92
+ break;
93
+ default:
94
+ msg = "unknown error";
95
+ exc = bz_eError;
102
96
  }
103
- rb_raise(exc, msg);
97
+ rb_raise(exc, "%s", msg);
104
98
  }
105
-
106
- static void
107
- bz_str_mark(bzs)
108
- struct bz_str *bzs;
109
- {
99
+
100
+ static void bz_str_mark(struct bz_str *bzs) {
110
101
  rb_gc_mark(bzs->str);
111
102
  }
112
103
 
113
- static void
114
- bz_file_mark(bzf)
115
- struct bz_file *bzf;
116
- {
104
+ static void bz_file_mark(struct bz_file * bzf) {
117
105
  rb_gc_mark(bzf->io);
118
106
  rb_gc_mark(bzf->in);
119
107
  }
120
108
 
121
- static struct bz_iv *
122
- bz_find_struct(obj, ptr, posp)
123
- VALUE obj;
124
- void *ptr;
125
- int *posp;
126
- {
109
+ static struct bz_iv * bz_find_struct(VALUE obj, void *ptr, int *posp) {
127
110
  struct bz_iv *bziv;
128
111
  int i;
129
112
 
130
113
  for (i = 0; i < RARRAY_LEN(bz_internal_ary); i++) {
131
- Data_Get_Struct(RARRAY_PTR(bz_internal_ary)[i], struct bz_iv, bziv);
132
- if (ptr) {
114
+ Data_Get_Struct(RARRAY_PTR(bz_internal_ary)[i], struct bz_iv, bziv);
115
+ if (ptr) {
133
116
  #ifndef RUBY_19_COMPATIBILITY
134
- if (TYPE(bziv->io) == T_FILE && RFILE(bziv->io)->fptr == (OpenFile *)ptr) {
117
+ if (TYPE(bziv->io) == T_FILE && RFILE(bziv->io)->fptr == (OpenFile *)ptr) {
135
118
  #else
136
- if (TYPE(bziv->io) == T_FILE && RFILE(bziv->io)->fptr == (rb_io_t *)ptr) {
119
+ if (TYPE(bziv->io) == T_FILE && RFILE(bziv->io)->fptr == (rb_io_t *)ptr) {
137
120
  #endif
121
+ if (posp) {
122
+ *posp = i;
123
+ }
124
+ return bziv;
125
+ } else if (TYPE(bziv->io) == T_DATA && DATA_PTR(bziv->io) == ptr) {
126
+ if (posp) *posp = i;
127
+ return bziv;
128
+ }
129
+ } else if (bziv->io == obj) {
138
130
  if (posp) *posp = i;
139
131
  return bziv;
140
132
  }
141
- else if (TYPE(bziv->io) == T_DATA && DATA_PTR(bziv->io) == ptr) {
142
- if (posp) *posp = i;
143
- return bziv;
144
- }
145
- }
146
- else if (bziv->io == obj) {
147
- if (posp) *posp = i;
148
- return bziv;
149
- }
150
133
  }
151
134
  if (posp) *posp = -1;
152
135
  return 0;
153
136
  }
154
137
 
155
- static VALUE
156
- bz_writer_internal_flush(bzf)
157
- struct bz_file *bzf;
158
- {
138
+ static VALUE bz_writer_internal_flush(struct bz_file *bzf) {
159
139
  int closed = 1;
160
140
 
161
141
  if (rb_respond_to(bzf->io, id_closed)) {
162
- closed = RTEST(rb_funcall2(bzf->io, id_closed, 0, 0));
142
+ closed = RTEST(rb_funcall2(bzf->io, id_closed, 0, 0));
163
143
  }
164
144
  if (bzf->buf) {
165
- if (!closed && bzf->state == BZ_OK) {
166
- bzf->bzs.next_in = NULL;
167
- bzf->bzs.avail_in = 0;
168
- do {
169
- bzf->bzs.next_out = bzf->buf;
170
- bzf->bzs.avail_out = bzf->buflen;
171
- bzf->state = BZ2_bzCompress(&(bzf->bzs), BZ_FINISH);
172
- if (bzf->state != BZ_FINISH_OK &&
173
- bzf->state != BZ_STREAM_END) {
174
- break;
145
+ if (!closed && bzf->state == BZ_OK) {
146
+ bzf->bzs.next_in = NULL;
147
+ bzf->bzs.avail_in = 0;
148
+ do {
149
+ bzf->bzs.next_out = bzf->buf;
150
+ bzf->bzs.avail_out = bzf->buflen;
151
+ bzf->state = BZ2_bzCompress(&(bzf->bzs), BZ_FINISH);
152
+ if (bzf->state != BZ_FINISH_OK && bzf->state != BZ_STREAM_END) {
153
+ break;
154
+ }
155
+ if (bzf->bzs.avail_out < bzf->buflen) {
156
+ rb_funcall(bzf->io, id_write, 1, rb_str_new(bzf->buf, bzf->buflen - bzf->bzs.avail_out));
157
+ }
158
+ } while (bzf->state != BZ_STREAM_END);
175
159
  }
176
- if (bzf->bzs.avail_out < bzf->buflen) {
177
- rb_funcall(bzf->io, id_write, 1,
178
- rb_str_new(bzf->buf,
179
- bzf->buflen - bzf->bzs.avail_out));
160
+ free(bzf->buf);
161
+ bzf->buf = 0;
162
+ BZ2_bzCompressEnd(&(bzf->bzs));
163
+ bzf->state = BZ_OK;
164
+ if (!closed && rb_respond_to(bzf->io, id_flush)) {
165
+ rb_funcall2(bzf->io, id_flush, 0, 0);
180
166
  }
181
- } while (bzf->state != BZ_STREAM_END);
182
- }
183
- free(bzf->buf);
184
- bzf->buf = 0;
185
- BZ2_bzCompressEnd(&(bzf->bzs));
186
- bzf->state = BZ_OK;
187
- if (!closed && rb_respond_to(bzf->io, id_flush)) {
188
- rb_funcall2(bzf->io, id_flush, 0, 0);
189
- }
190
167
  }
191
168
  return closed;
192
169
  }
193
170
 
194
- static VALUE
195
- bz_writer_internal_close(bzf)
196
- struct bz_file *bzf;
197
- {
171
+ static VALUE bz_writer_internal_close(struct bz_file *bzf) {
198
172
  struct bz_iv *bziv;
199
173
  int pos, closed;
200
174
  VALUE res;
@@ -202,82 +176,87 @@ bz_writer_internal_close(bzf)
202
176
  closed = bz_writer_internal_flush(bzf);
203
177
  bziv = bz_find_struct(bzf->io, 0, &pos);
204
178
  if (bziv) {
205
- if (TYPE(bzf->io) == T_FILE) {
206
- RFILE(bzf->io)->fptr->finalize = bziv->finalize;
207
- }
208
- else if (TYPE(bziv->io) == T_DATA) {
209
- RDATA(bziv->io)->dfree = bziv->finalize;
210
- }
211
- RDATA(bziv->bz2)->dfree = ruby_xfree;
212
- bziv->bz2 = 0;
213
- rb_ary_delete_at(bz_internal_ary, pos);
179
+ if (TYPE(bzf->io) == T_FILE) {
180
+ RFILE(bzf->io)->fptr->finalize = bziv->finalize;
181
+ } else if (TYPE(bziv->io) == T_DATA) {
182
+ RDATA(bziv->io)->dfree = bziv->finalize;
183
+ }
184
+ RDATA(bziv->bz2)->dfree = free;
185
+ bziv->bz2 = 0;
186
+ rb_ary_delete_at(bz_internal_ary, pos);
214
187
  }
215
188
  if (bzf->flags & BZ2_RB_CLOSE) {
216
- bzf->flags &= ~BZ2_RB_CLOSE;
217
- if (!closed && rb_respond_to(bzf->io, id_close)) {
218
- rb_funcall2(bzf->io, id_close, 0, 0);
219
- }
220
- res = Qnil;
221
- }
222
- else {
223
- res = bzf->io;
189
+ bzf->flags &= ~BZ2_RB_CLOSE;
190
+ if (!closed && rb_respond_to(bzf->io, id_close)) {
191
+ rb_funcall2(bzf->io, id_close, 0, 0);
192
+ }
193
+ res = Qnil;
194
+ } else {
195
+ res = bzf->io;
224
196
  }
225
197
  bzf->io = Qnil;
226
198
  return res;
227
199
  }
228
200
 
229
- static VALUE
230
- bz_internal_finalize(ary, obj)
231
- VALUE ary, obj;
232
- {
201
+ static void bz_internal_finalize(VALUE data) {
233
202
  VALUE elem;
234
203
  int closed, i;
235
204
  struct bz_iv *bziv;
236
205
  struct bz_file *bzf;
237
206
 
238
207
  for (i = 0; i < RARRAY_LEN(bz_internal_ary); i++) {
239
- elem = RARRAY_PTR(bz_internal_ary)[i];
240
- Data_Get_Struct(elem, struct bz_iv, bziv);
241
- if (bziv->bz2) {
242
- RDATA(bziv->bz2)->dfree = ruby_xfree;
243
- if (TYPE(bziv->io) == T_FILE) {
244
- RFILE(bziv->io)->fptr->finalize = bziv->finalize;
245
- }
246
- else if (TYPE(bziv->io) == T_DATA) {
247
- RDATA(bziv->io)->dfree = bziv->finalize;
248
- }
249
- Data_Get_Struct(bziv->bz2, struct bz_file, bzf);
250
- closed = bz_writer_internal_flush(bzf);
251
- if (bzf->flags & BZ2_RB_CLOSE) {
252
- bzf->flags &= ~BZ2_RB_CLOSE;
253
- if (!closed && rb_respond_to(bzf->io, id_close)) {
254
- rb_funcall2(bzf->io, id_close, 0, 0);
255
- }
208
+ elem = RARRAY_PTR(bz_internal_ary)[i];
209
+ Data_Get_Struct(elem, struct bz_iv, bziv);
210
+ if (bziv->bz2) {
211
+ RDATA(bziv->bz2)->dfree = free;
212
+ if (TYPE(bziv->io) == T_FILE) {
213
+ RFILE(bziv->io)->fptr->finalize = bziv->finalize;
214
+ } else if (TYPE(bziv->io) == T_DATA) {
215
+ RDATA(bziv->io)->dfree = bziv->finalize;
216
+ }
217
+ Data_Get_Struct(bziv->bz2, struct bz_file, bzf);
218
+ closed = bz_writer_internal_flush(bzf);
219
+ if (bzf->flags & BZ2_RB_CLOSE) {
220
+ bzf->flags &= ~BZ2_RB_CLOSE;
221
+ if (!closed && rb_respond_to(bzf->io, id_close)) {
222
+ rb_funcall2(bzf->io, id_close, 0, 0);
223
+ }
224
+ }
256
225
  }
257
226
  }
258
- }
259
- return Qnil;
260
227
  }
261
228
 
262
- static VALUE
263
- bz_writer_close(obj)
264
- VALUE obj;
265
- {
229
+ /*
230
+ * Closes this writer for further use. The remaining data is compressed and
231
+ * flushed.
232
+ *
233
+ * If the writer was constructed with an io object, that object is returned.
234
+ * Otherwise, the actual compressed data is returned
235
+ *
236
+ * writer = Bzip2::Writer.new File.open('path', 'w')
237
+ * writer << 'a'
238
+ * writer.close # => #<File:path>
239
+ *
240
+ * writer = Bzip2::Writer.new
241
+ * writer << 'a'
242
+ * writer.close # => "BZh91AY&SY...
243
+ */
244
+ static VALUE bz_writer_close(VALUE obj) {
266
245
  struct bz_file *bzf;
267
246
  VALUE res;
268
247
 
269
248
  Get_BZ2(obj, bzf);
270
249
  res = bz_writer_internal_close(bzf);
271
250
  if (!NIL_P(res) && (bzf->flags & BZ2_RB_INTERNAL)) {
272
- RBASIC(res)->klass = rb_cString;
251
+ RBASIC(res)->klass = rb_cString;
273
252
  }
274
253
  return res;
275
254
  }
276
255
 
277
- static VALUE
278
- bz_writer_close_bang(obj)
279
- VALUE obj;
280
- {
256
+ /*
257
+ * Calls Bzip2::Writer#close and then does some more stuff...
258
+ */
259
+ static VALUE bz_writer_close_bang(VALUE obj) {
281
260
  struct bz_file *bzf;
282
261
  int closed;
283
262
 
@@ -285,28 +264,22 @@ bz_writer_close_bang(obj)
285
264
  closed = bzf->flags & (BZ2_RB_INTERNAL|BZ2_RB_CLOSE);
286
265
  bz_writer_close(obj);
287
266
  if (!closed && rb_respond_to(bzf->io, id_close)) {
288
- if (rb_respond_to(bzf->io, id_closed)) {
289
- closed = RTEST(rb_funcall2(bzf->io, id_closed, 0, 0));
290
- }
291
- if (!closed) {
292
- rb_funcall2(bzf->io, id_close, 0, 0);
293
- }
267
+ if (rb_respond_to(bzf->io, id_closed)) {
268
+ closed = RTEST(rb_funcall2(bzf->io, id_closed, 0, 0));
269
+ }
270
+ if (!closed) {
271
+ rb_funcall2(bzf->io, id_close, 0, 0);
272
+ }
294
273
  }
295
274
  return Qnil;
296
275
  }
297
276
 
298
- static void
299
- bz_writer_free(bzf)
300
- struct bz_file *bzf;
301
- {
277
+ static void bz_writer_free(struct bz_file *bzf) {
302
278
  bz_writer_internal_close(bzf);
303
- ruby_xfree(bzf);
279
+ free(bzf);
304
280
  }
305
281
 
306
- static void
307
- bz_io_data_finalize(ptr)
308
- void *ptr;
309
- {
282
+ static void bz_io_data_finalize(void *ptr) {
310
283
  struct bz_file *bzf;
311
284
  struct bz_iv *bziv;
312
285
  int pos;
@@ -315,8 +288,8 @@ bz_io_data_finalize(ptr)
315
288
  if (bziv) {
316
289
  rb_ary_delete_at(bz_internal_ary, pos);
317
290
  Data_Get_Struct(bziv->bz2, struct bz_file, bzf);
318
- rb_protect(bz_writer_internal_flush, (VALUE)bzf, 0);
319
- RDATA(bziv->bz2)->dfree = ruby_xfree;
291
+ rb_protect((VALUE (*)(VALUE))bz_writer_internal_flush, (VALUE)bzf, 0);
292
+ RDATA(bziv->bz2)->dfree = free;
320
293
  if (bziv->finalize) {
321
294
  (*bziv->finalize)(ptr);
322
295
  } else if (TYPE(bzf->io) == T_FILE) {
@@ -333,7 +306,8 @@ bz_io_data_finalize(ptr)
333
306
  #else
334
307
  rb_io_t *file = (rb_io_t *)ptr;
335
308
  if (file->fd) {
336
- fclose(file->fd);
309
+ close(file->fd);
310
+
337
311
  file->fd = 0;
338
312
  }
339
313
  if (file->stdio_file) {
@@ -343,33 +317,27 @@ bz_io_data_finalize(ptr)
343
317
  #endif
344
318
  }
345
319
  }
320
+
346
321
  }
347
322
 
348
- static void *
349
- bz_malloc(opaque, m, n)
350
- void *opaque;
351
- int m, n;
352
- {
353
- return ruby_xmalloc(m * n);
323
+ static void * bz_malloc(void *opaque, int m, int n) {
324
+ return malloc(m * n);
354
325
  }
355
326
 
356
- static void
357
- bz_free(opaque, p)
358
- void *opaque, *p;
359
- {
360
- ruby_xfree(p);
327
+ static void bz_free(void *opaque, void *p) {
328
+ free(p);
361
329
  }
362
330
 
363
331
  #define DEFAULT_BLOCKS 9
364
332
 
365
- static VALUE
366
- bz_writer_s_alloc(obj)
367
- VALUE obj;
368
- {
333
+ /*
334
+ * Internally allocates information about a new writer
335
+ * @private
336
+ */
337
+ static VALUE bz_writer_s_alloc(VALUE obj) {
369
338
  struct bz_file *bzf;
370
339
  VALUE res;
371
- res = Data_Make_Struct(obj, struct bz_file, bz_file_mark,
372
- bz_writer_free, bzf);
340
+ res = Data_Make_Struct(obj, struct bz_file, bz_file_mark, bz_writer_free, bzf);
373
341
  bzf->bzs.bzalloc = bz_malloc;
374
342
  bzf->bzs.bzfree = bz_free;
375
343
  bzf->blocks = DEFAULT_BLOCKS;
@@ -377,139 +345,171 @@ bz_writer_s_alloc(obj)
377
345
  return res;
378
346
  }
379
347
 
380
- static VALUE
381
- bz_writer_flush(obj)
382
- VALUE obj;
383
- {
348
+ /*
349
+ * Flushes all of the data in this stream to the underlying IO.
350
+ *
351
+ * If this writer was constructed with no underlying io object, the compressed
352
+ * data is returned as a string.
353
+ *
354
+ * @return [String, nil]
355
+ * @raise [IOError] if the stream has been closed
356
+ */
357
+ static VALUE bz_writer_flush(VALUE obj) {
384
358
  struct bz_file *bzf;
385
359
 
386
360
  Get_BZ2(obj, bzf);
387
361
  if (bzf->flags & BZ2_RB_INTERNAL) {
388
- return bz_writer_close(obj);
362
+ return bz_writer_close(obj);
389
363
  }
390
364
  bz_writer_internal_flush(bzf);
391
365
  return Qnil;
392
366
  }
393
367
 
394
- static VALUE
395
- bz_writer_s_open(argc, argv, obj)
396
- int argc;
397
- VALUE obj, *argv;
398
- {
368
+ /*
369
+ * call-seq:
370
+ * open(filename, mode='wb', &block=nil) -> Bzip2::Writer
371
+ *
372
+ * @param [String] filename the name of the file to write to
373
+ * @param [String] mode a mode string passed to Kernel#open
374
+ * @yieldparam [Bzip2::Writer] writer the Bzip2::Writer instance
375
+ *
376
+ * If a block is given, the created Bzip2::Writer instance is yielded to the
377
+ * block and will be closed when the block completes. It is guaranteed via
378
+ * +ensure+ that the writer is closed
379
+ *
380
+ * If a block is not given, a Bzip2::Writer instance will be returned
381
+ *
382
+ * Bzip2::Writer.open('file') { |f| f << data }
383
+ *
384
+ * writer = Bzip2::Writer.open('file')
385
+ * writer << data
386
+ * writer.close
387
+ *
388
+ * @return [Bzip2::Writer, nil]
389
+ */
390
+ static VALUE bz_writer_s_open(int argc, VALUE *argv, VALUE obj) {
399
391
  VALUE res;
400
392
  struct bz_file *bzf;
401
393
 
402
394
  if (argc < 1) {
403
- rb_raise(rb_eArgError, "invalid number of arguments");
395
+ rb_raise(rb_eArgError, "invalid number of arguments");
404
396
  }
405
397
  if (argc == 1) {
406
- argv[0] = rb_funcall(rb_mKernel, id_open, 2, argv[0],
407
- rb_str_new2("wb"));
408
- }
409
- else {
410
- argv[1] = rb_funcall2(rb_mKernel, id_open, 2, argv);
411
- argv += 1;
412
- argc -= 1;
398
+ argv[0] = rb_funcall(rb_mKernel, id_open, 2, argv[0],
399
+ rb_str_new2("wb"));
400
+ } else {
401
+ argv[1] = rb_funcall2(rb_mKernel, id_open, 2, argv);
402
+ argv += 1;
403
+ argc -= 1;
413
404
  }
414
405
  res = rb_funcall2(obj, id_new, argc, argv);
415
406
  Data_Get_Struct(res, struct bz_file, bzf);
416
407
  bzf->flags |= BZ2_RB_CLOSE;
417
408
  if (rb_block_given_p()) {
418
- return rb_ensure(rb_yield, res, bz_writer_close, res);
409
+ return rb_ensure(rb_yield, res, bz_writer_close, res);
419
410
  }
420
411
  return res;
421
412
  }
422
413
 
423
- static VALUE
424
- bz_str_write(obj, str)
425
- VALUE obj, str;
426
- {
414
+ static VALUE bz_str_write(VALUE obj, VALUE str) {
427
415
  if (TYPE(str) != T_STRING) {
428
- rb_raise(rb_eArgError, "expected a String");
416
+ rb_raise(rb_eArgError, "expected a String");
429
417
  }
430
418
  if (RSTRING_LEN(str)) {
431
- rb_str_cat(obj, RSTRING_PTR(str), RSTRING_LEN(str));
419
+ rb_str_cat(obj, RSTRING_PTR(str), RSTRING_LEN(str));
432
420
  }
433
421
  return str;
434
422
  }
435
423
 
436
- static VALUE
437
- bz_str_closed(obj)
438
- VALUE obj;
439
- {
424
+ static VALUE bz_str_closed(VALUE obj) {
440
425
  return Qfalse;
441
426
  }
442
427
 
443
- static VALUE
444
- bz_writer_init(argc, argv, obj)
445
- int argc;
446
- VALUE obj, *argv;
447
- {
428
+ /*
429
+ * call-seq:
430
+ * initialize(io = nil)
431
+ *
432
+ * @param [File] io the file which to write compressed data to
433
+ *
434
+ * Creates a new Bzip2::Writer for compressing a stream of data. An optional
435
+ * io object (something responding to +write+) can be supplied which data
436
+ * will be written to.
437
+ *
438
+ * If nothing is given, the Bzip2::Writer#flush method can be called to retrieve
439
+ * the compressed stream so far.
440
+ *
441
+ * writer = Bzip2::Writer.new File.open('files.bz2')
442
+ * writer << 'a'
443
+ * writer << 'b'
444
+ * writer.close
445
+ *
446
+ * writer = Bzip2::Writer.new
447
+ * writer << 'abcde'
448
+ * writer.flush # => 'abcde' compressed
449
+ */
450
+ static VALUE bz_writer_init(int argc, VALUE *argv, VALUE obj) {
448
451
  struct bz_file *bzf;
449
452
  int blocks = DEFAULT_BLOCKS;
450
453
  int work = 0;
451
454
  VALUE a, b, c;
452
455
 
453
456
  switch(rb_scan_args(argc, argv, "03", &a, &b, &c)) {
454
- case 3:
455
- work = NUM2INT(c);
457
+ case 3:
458
+ work = NUM2INT(c);
456
459
  /* ... */
457
- case 2:
458
- blocks = NUM2INT(b);
460
+ case 2:
461
+ blocks = NUM2INT(b);
459
462
  }
460
463
  Data_Get_Struct(obj, struct bz_file, bzf);
461
464
  if (NIL_P(a)) {
462
- a = rb_str_new(0, 0);
463
- rb_define_method(rb_singleton_class(a), "write", bz_str_write, 1);
464
- rb_define_method(rb_singleton_class(a), "closed?", bz_str_closed, 0);
465
- bzf->flags |= BZ2_RB_INTERNAL;
466
- }
467
- else {
468
- VALUE iv;
469
- struct bz_iv *bziv;
465
+ a = rb_str_new(0, 0);
466
+ rb_define_method(rb_singleton_class(a), "write", bz_str_write, 1);
467
+ rb_define_method(rb_singleton_class(a), "closed?", bz_str_closed, 0);
468
+ bzf->flags |= BZ2_RB_INTERNAL;
469
+ } else {
470
+ VALUE iv;
471
+ struct bz_iv *bziv;
470
472
  #ifndef RUBY_19_COMPATIBILITY
471
- OpenFile *fptr;
473
+ OpenFile *fptr;
472
474
  #else
473
- rb_io_t *fptr;
475
+ rb_io_t *fptr;
474
476
  #endif
475
477
 
476
- rb_io_taint_check(a);
477
- if (!rb_respond_to(a, id_write)) {
478
- rb_raise(rb_eArgError, "first argument must respond to #write");
479
- }
480
- if (TYPE(a) == T_FILE) {
481
- GetOpenFile(a, fptr);
482
- rb_io_check_writable(fptr);
483
- }
484
- else if (rb_respond_to(a, id_closed)) {
485
- iv = rb_funcall2(a, id_closed, 0, 0);
486
- if (RTEST(iv)) {
487
- rb_raise(rb_eArgError, "closed object");
478
+ rb_io_taint_check(a);
479
+ if (!rb_respond_to(a, id_write)) {
480
+ rb_raise(rb_eArgError, "first argument must respond to #write");
488
481
  }
489
- }
490
- bziv = bz_find_struct(a, 0, 0);
491
- if (bziv) {
492
- if (RTEST(bziv->bz2)) {
493
- rb_raise(rb_eArgError, "invalid data type");
482
+ if (TYPE(a) == T_FILE) {
483
+ GetOpenFile(a, fptr);
484
+ rb_io_check_writable(fptr);
485
+ } else if (rb_respond_to(a, id_closed)) {
486
+ iv = rb_funcall2(a, id_closed, 0, 0);
487
+ if (RTEST(iv)) {
488
+ rb_raise(rb_eArgError, "closed object");
489
+ }
490
+ }
491
+ bziv = bz_find_struct(a, 0, 0);
492
+ if (bziv) {
493
+ if (RTEST(bziv->bz2)) {
494
+ rb_raise(rb_eArgError, "invalid data type");
495
+ }
496
+ bziv->bz2 = obj;
497
+ } else {
498
+ iv = Data_Make_Struct(rb_cData, struct bz_iv, 0, free, bziv);
499
+ bziv->io = a;
500
+ bziv->bz2 = obj;
501
+ rb_ary_push(bz_internal_ary, iv);
502
+ }
503
+ switch (TYPE(a)) {
504
+ case T_FILE:
505
+ bziv->finalize = RFILE(a)->fptr->finalize;
506
+ RFILE(a)->fptr->finalize = (void (*)(struct rb_io_t *, int))bz_io_data_finalize;
507
+ break;
508
+ case T_DATA:
509
+ bziv->finalize = RDATA(a)->dfree;
510
+ RDATA(a)->dfree = bz_io_data_finalize;
511
+ break;
494
512
  }
495
- bziv->bz2 = obj;
496
- }
497
- else {
498
- iv = Data_Make_Struct(rb_cData, struct bz_iv, 0, free, bziv);
499
- bziv->io = a;
500
- bziv->bz2 = obj;
501
- rb_ary_push(bz_internal_ary, iv);
502
- }
503
- switch (TYPE(a)) {
504
- case T_FILE:
505
- bziv->finalize = RFILE(a)->fptr->finalize;
506
- RFILE(a)->fptr->finalize = bz_io_data_finalize;
507
- break;
508
- case T_DATA:
509
- bziv->finalize = RDATA(a)->dfree;
510
- RDATA(a)->dfree = bz_io_data_finalize;
511
- break;
512
- }
513
513
  }
514
514
  bzf->io = a;
515
515
  bzf->blocks = blocks;
@@ -519,86 +519,105 @@ bz_writer_init(argc, argv, obj)
519
519
 
520
520
  #define BZ_RB_BLOCKSIZE 4096
521
521
 
522
- static VALUE
523
- bz_writer_write(obj, a)
524
- VALUE obj, a;
525
- {
522
+ /*
523
+ * call-seq:
524
+ * write(data)
525
+ * Actually writes some data into this stream.
526
+ *
527
+ * @param [String] data the data to write
528
+ * @return [Integer] the length of the data which was written (uncompressed)
529
+ * @raise [IOError] if the stream has been closed
530
+ */
531
+ static VALUE bz_writer_write(VALUE obj, VALUE a) {
526
532
  struct bz_file *bzf;
527
533
  int n;
528
534
 
529
535
  a = rb_obj_as_string(a);
530
536
  Get_BZ2(obj, bzf);
531
537
  if (!bzf->buf) {
532
- if (bzf->state != BZ_OK) {
533
- bz_raise(bzf->state);
534
- }
535
- bzf->state = BZ2_bzCompressInit(&(bzf->bzs), bzf->blocks,
536
- 0, bzf->work);
537
- if (bzf->state != BZ_OK) {
538
- bz_writer_internal_flush(bzf);
539
- bz_raise(bzf->state);
540
- }
541
- bzf->buf = ALLOC_N(char, BZ_RB_BLOCKSIZE + 1);
542
- bzf->buflen = BZ_RB_BLOCKSIZE;
543
- bzf->buf[0] = bzf->buf[bzf->buflen] = '\0';
538
+ if (bzf->state != BZ_OK) {
539
+ bz_raise(bzf->state);
540
+ }
541
+ bzf->state = BZ2_bzCompressInit(&(bzf->bzs), bzf->blocks,
542
+ 0, bzf->work);
543
+ if (bzf->state != BZ_OK) {
544
+ bz_writer_internal_flush(bzf);
545
+ bz_raise(bzf->state);
546
+ }
547
+ bzf->buf = ALLOC_N(char, BZ_RB_BLOCKSIZE + 1);
548
+ bzf->buflen = BZ_RB_BLOCKSIZE;
549
+ bzf->buf[0] = bzf->buf[bzf->buflen] = '\0';
544
550
  }
545
551
  bzf->bzs.next_in = RSTRING_PTR(a);
546
552
  bzf->bzs.avail_in = RSTRING_LEN(a);
547
553
  while (bzf->bzs.avail_in) {
548
- bzf->bzs.next_out = bzf->buf;
549
- bzf->bzs.avail_out = bzf->buflen;
550
- bzf->state = BZ2_bzCompress(&(bzf->bzs), BZ_RUN);
551
- if (bzf->state == BZ_SEQUENCE_ERROR || bzf->state == BZ_PARAM_ERROR) {
552
- bz_writer_internal_flush(bzf);
553
- bz_raise(bzf->state);
554
- }
555
- bzf->state = BZ_OK;
556
- if (bzf->bzs.avail_out < bzf->buflen) {
557
- n = bzf->buflen - bzf->bzs.avail_out;
558
- rb_funcall(bzf->io, id_write, 1, rb_str_new(bzf->buf, n));
559
- }
554
+ bzf->bzs.next_out = bzf->buf;
555
+ bzf->bzs.avail_out = bzf->buflen;
556
+ bzf->state = BZ2_bzCompress(&(bzf->bzs), BZ_RUN);
557
+ if (bzf->state == BZ_SEQUENCE_ERROR || bzf->state == BZ_PARAM_ERROR) {
558
+ bz_writer_internal_flush(bzf);
559
+ bz_raise(bzf->state);
560
+ }
561
+ bzf->state = BZ_OK;
562
+ if (bzf->bzs.avail_out < bzf->buflen) {
563
+ n = bzf->buflen - bzf->bzs.avail_out;
564
+ rb_funcall(bzf->io, id_write, 1, rb_str_new(bzf->buf, n));
565
+ }
560
566
  }
561
567
  return INT2NUM(RSTRING_LEN(a));
562
568
  }
563
569
 
564
- static VALUE
565
- bz_writer_putc(obj, a)
566
- VALUE obj, a;
567
- {
570
+ /*
571
+ * call-seq:
572
+ * putc(num)
573
+ *
574
+ * Write one byte into this stream.
575
+ * @param [Integer] num the number value of the character to write
576
+ * @return [Integer] always 1
577
+ * @raise [IOError] if the stream has been closed
578
+ */
579
+ static VALUE bz_writer_putc(VALUE obj, VALUE a) {
568
580
  char c = NUM2CHR(a);
569
581
  return bz_writer_write(obj, rb_str_new(&c, 1));
570
582
  }
571
583
 
572
- static VALUE
573
- bz_compress(argc, argv, obj)
574
- int argc;
575
- VALUE obj, *argv;
576
- {
584
+ /*
585
+ * call-seq:
586
+ * compress(str)
587
+ *
588
+ * Shortcut for compressing just a string.
589
+ *
590
+ * Bzip2.uncompress Bzip2.compress('data') # => 'data'
591
+ *
592
+ * @param [String] str the string to compress
593
+ * @return [String] +str+ compressed with bz2
594
+ */
595
+ static VALUE bz_compress(int argc, VALUE *argv, VALUE obj) {
577
596
  VALUE bz2, str;
578
597
 
579
598
  if (!argc) {
580
- rb_raise(rb_eArgError, "need a String to compress");
599
+ rb_raise(rb_eArgError, "need a String to compress");
581
600
  }
582
601
  str = rb_str_to_str(argv[0]);
583
602
  argv[0] = Qnil;
584
603
  bz2 = rb_funcall2(bz_cWriter, id_new, argc, argv);
585
604
  if (OBJ_TAINTED(str)) {
586
- struct bz_file *bzf;
587
- Data_Get_Struct(bz2, struct bz_file, bzf);
588
- OBJ_TAINT(bzf->io);
605
+ struct bz_file *bzf;
606
+ Data_Get_Struct(bz2, struct bz_file, bzf);
607
+ OBJ_TAINT(bzf->io);
589
608
  }
590
609
  bz_writer_write(bz2, str);
591
610
  return bz_writer_close(bz2);
592
611
  }
593
612
 
594
- static VALUE
595
- bz_reader_s_alloc(obj)
596
- VALUE obj;
597
- {
613
+ /*
614
+ * Internally allocates data for a new Reader
615
+ * @private
616
+ */
617
+ static VALUE bz_reader_s_alloc(VALUE obj) {
598
618
  struct bz_file *bzf;
599
619
  VALUE res;
600
- res = Data_Make_Struct(obj, struct bz_file, bz_file_mark,
601
- ruby_xfree, bzf);
620
+ res = Data_Make_Struct(obj, struct bz_file, bz_file_mark, free, bzf);
602
621
  bzf->bzs.bzalloc = bz_malloc;
603
622
  bzf->bzs.bzfree = bz_free;
604
623
  bzf->blocks = DEFAULT_BLOCKS;
@@ -608,79 +627,103 @@ bz_reader_s_alloc(obj)
608
627
 
609
628
  static VALUE bz_reader_close __((VALUE));
610
629
 
611
- static VALUE
612
- bz_reader_s_open(argc, argv, obj)
613
- int argc;
614
- VALUE obj, *argv;
615
- {
630
+ /*
631
+ * call-seq:
632
+ * open(filename, &block=nil) -> Bzip2::Reader
633
+ *
634
+ * @param [String] filename the name of the file to read from
635
+ * @yieldparam [Bzip2::Reader] reader the Bzip2::Reader instance
636
+ *
637
+ * If a block is given, the created Bzip2::Reader instance is yielded to the
638
+ * block and will be closed when the block completes. It is guaranteed via
639
+ * +ensure+ that the reader is closed
640
+ *
641
+ * If a block is not given, a Bzip2::Reader instance will be returned
642
+ *
643
+ * Bzip2::Reader.open('file') { |f| puts f.gets }
644
+ *
645
+ * reader = Bzip2::Reader.open('file')
646
+ * puts reader.gets
647
+ * reader.close
648
+ *
649
+ * @return [Bzip2::Reader, nil]
650
+ */
651
+ static VALUE bz_reader_s_open(int argc, VALUE *argv, VALUE obj) {
616
652
  VALUE res;
617
653
  struct bz_file *bzf;
618
654
 
619
655
  if (argc < 1) {
620
- rb_raise(rb_eArgError, "invalid number of arguments");
656
+ rb_raise(rb_eArgError, "invalid number of arguments");
621
657
  }
622
658
  argv[0] = rb_funcall2(rb_mKernel, id_open, 1, argv);
623
- if (NIL_P(argv[0])) return Qnil;
659
+ if (NIL_P(argv[0])) {
660
+ return Qnil;
661
+ }
624
662
  res = rb_funcall2(obj, id_new, argc, argv);
625
663
  Data_Get_Struct(res, struct bz_file, bzf);
626
664
  bzf->flags |= BZ2_RB_CLOSE;
627
665
  if (rb_block_given_p()) {
628
- return rb_ensure(rb_yield, res, bz_reader_close, res);
666
+ return rb_ensure(rb_yield, res, bz_reader_close, res);
629
667
  }
630
668
  return res;
631
669
  }
632
670
 
633
- static VALUE
634
- bz_reader_init(argc, argv, obj)
635
- int argc;
636
- VALUE obj, *argv;
637
- {
671
+ /*
672
+ * call-seq:
673
+ * initialize(io)
674
+ *
675
+ * Creates a new stream for reading a bzip file or string
676
+ *
677
+ * @param [File, string, #read] io the source for input data. If the source is
678
+ * a file or something responding to #read, then data will be read via #read,
679
+ * otherwise if the input is a string it will be taken as the literal data
680
+ * to decompress
681
+ */
682
+ static VALUE bz_reader_init(int argc, VALUE *argv, VALUE obj) {
638
683
  struct bz_file *bzf;
639
684
  int small = 0;
640
685
  VALUE a, b;
641
686
  int internal = 0;
642
687
 
643
688
  if (rb_scan_args(argc, argv, "11", &a, &b) == 2) {
644
- small = RTEST(b);
689
+ small = RTEST(b);
645
690
  }
646
691
  rb_io_taint_check(a);
647
692
  if (OBJ_TAINTED(a)) {
648
- OBJ_TAINT(obj);
693
+ OBJ_TAINT(obj);
649
694
  }
650
695
  if (rb_respond_to(a, id_read)) {
651
- if (TYPE(a) == T_FILE) {
696
+ if (TYPE(a) == T_FILE) {
652
697
  #ifndef RUBY_19_COMPATIBILITY
653
- OpenFile *fptr;
698
+ OpenFile *fptr;
654
699
  #else
655
- rb_io_t *fptr;
700
+ rb_io_t *fptr;
656
701
  #endif
657
702
 
658
- GetOpenFile(a, fptr);
659
- rb_io_check_readable(fptr);
660
- }
661
- else if (rb_respond_to(a, id_closed)) {
662
- VALUE iv = rb_funcall2(a, id_closed, 0, 0);
663
- if (RTEST(iv)) {
664
- rb_raise(rb_eArgError, "closed object");
703
+ GetOpenFile(a, fptr);
704
+ rb_io_check_readable(fptr);
705
+ } else if (rb_respond_to(a, id_closed)) {
706
+ VALUE iv = rb_funcall2(a, id_closed, 0, 0);
707
+ if (RTEST(iv)) {
708
+ rb_raise(rb_eArgError, "closed object");
709
+ }
665
710
  }
666
- }
667
- }
668
- else {
669
- struct bz_str *bzs;
670
- VALUE res;
711
+ } else {
712
+ struct bz_str *bzs;
713
+ VALUE res;
671
714
 
672
- if (!rb_respond_to(a, id_str)) {
673
- rb_raise(rb_eArgError, "first argument must respond to #read");
674
- }
675
- a = rb_funcall2(a, id_str, 0, 0);
676
- if (TYPE(a) != T_STRING) {
677
- rb_raise(rb_eArgError, "#to_str must return a String");
678
- }
679
- res = Data_Make_Struct(bz_cInternal, struct bz_str,
680
- bz_str_mark, ruby_xfree, bzs);
681
- bzs->str = a;
682
- a = res;
683
- internal = BZ2_RB_INTERNAL;
715
+ if (!rb_respond_to(a, id_str)) {
716
+ rb_raise(rb_eArgError, "first argument must respond to #read");
717
+ }
718
+ a = rb_funcall2(a, id_str, 0, 0);
719
+ if (TYPE(a) != T_STRING) {
720
+ rb_raise(rb_eArgError, "#to_str must return a String");
721
+ }
722
+ res = Data_Make_Struct(bz_cInternal, struct bz_str,
723
+ bz_str_mark, free, bzs);
724
+ bzs->str = a;
725
+ a = res;
726
+ internal = BZ2_RB_INTERNAL;
684
727
  }
685
728
  Data_Get_Struct(obj, struct bz_file, bzf);
686
729
  bzf->io = a;
@@ -689,70 +732,63 @@ bz_reader_init(argc, argv, obj)
689
732
  return obj;
690
733
  }
691
734
 
692
- static struct bz_file *
693
- bz_get_bzf(obj)
694
- VALUE obj;
695
- {
735
+ static struct bz_file * bz_get_bzf(VALUE obj) {
696
736
  struct bz_file *bzf;
697
737
 
698
738
  Get_BZ2(obj, bzf);
699
739
  if (!bzf->buf) {
700
- if (bzf->state != BZ_OK) {
701
- bz_raise(bzf->state);
702
- }
703
- bzf->state = BZ2_bzDecompressInit(&(bzf->bzs), 0, bzf->small);
704
- if (bzf->state != BZ_OK) {
705
- BZ2_bzDecompressEnd(&(bzf->bzs));
706
- bz_raise(bzf->state);
707
- }
708
- bzf->buf = ALLOC_N(char, BZ_RB_BLOCKSIZE + 1);
709
- bzf->buflen = BZ_RB_BLOCKSIZE;
710
- bzf->buf[0] = bzf->buf[bzf->buflen] = '\0';
711
- bzf->bzs.total_out_hi32 = bzf->bzs.total_out_lo32 = 0;
712
- bzf->bzs.next_out = bzf->buf;
713
- bzf->bzs.avail_out = 0;
740
+ if (bzf->state != BZ_OK) {
741
+ bz_raise(bzf->state);
742
+ }
743
+ bzf->state = BZ2_bzDecompressInit(&(bzf->bzs), 0, bzf->small);
744
+ if (bzf->state != BZ_OK) {
745
+ BZ2_bzDecompressEnd(&(bzf->bzs));
746
+ bz_raise(bzf->state);
747
+ }
748
+ bzf->buf = ALLOC_N(char, BZ_RB_BLOCKSIZE + 1);
749
+ bzf->buflen = BZ_RB_BLOCKSIZE;
750
+ bzf->buf[0] = bzf->buf[bzf->buflen] = '\0';
751
+ bzf->bzs.total_out_hi32 = bzf->bzs.total_out_lo32 = 0;
752
+ bzf->bzs.next_out = bzf->buf;
753
+ bzf->bzs.avail_out = 0;
714
754
  }
715
755
  if (bzf->state == BZ_STREAM_END && !bzf->bzs.avail_out) {
716
- return 0;
756
+ return 0;
717
757
  }
718
758
  return bzf;
719
759
  }
720
760
 
721
- static int
722
- bz_next_available(bzf, in)
723
- struct bz_file *bzf;
724
- int in;
725
- {
761
+ static int bz_next_available(struct bz_file *bzf, int in){
726
762
  bzf->bzs.next_out = bzf->buf;
727
763
  bzf->bzs.avail_out = 0;
728
764
  if (bzf->state == BZ_STREAM_END) {
729
- return BZ_STREAM_END;
765
+ return BZ_STREAM_END;
730
766
  }
731
767
  if (!bzf->bzs.avail_in) {
732
- bzf->in = rb_funcall(bzf->io, id_read, 1, INT2FIX(1024));
733
- if (TYPE(bzf->in) != T_STRING || RSTRING_LEN(bzf->in) == 0) {
734
- BZ2_bzDecompressEnd(&(bzf->bzs));
735
- bzf->bzs.avail_out = 0;
736
- bzf->state = BZ_UNEXPECTED_EOF;
737
- bz_raise(bzf->state);
738
- }
739
- bzf->bzs.next_in = RSTRING_PTR(bzf->in);
740
- bzf->bzs.avail_in = RSTRING_LEN(bzf->in);
768
+ bzf->in = rb_funcall(bzf->io, id_read, 1, INT2FIX(1024));
769
+ if (TYPE(bzf->in) != T_STRING || RSTRING_LEN(bzf->in) == 0) {
770
+ BZ2_bzDecompressEnd(&(bzf->bzs));
771
+ bzf->bzs.avail_out = 0;
772
+ bzf->state = BZ_UNEXPECTED_EOF;
773
+ bz_raise(bzf->state);
774
+ }
775
+ bzf->bzs.next_in = RSTRING_PTR(bzf->in);
776
+ bzf->bzs.avail_in = RSTRING_LEN(bzf->in);
741
777
  }
742
778
  if ((bzf->buflen - in) < (BZ_RB_BLOCKSIZE / 2)) {
743
- bzf->buf = REALLOC_N(bzf->buf, char, bzf->buflen+BZ_RB_BLOCKSIZE+1);
744
- bzf->buflen += BZ_RB_BLOCKSIZE;
745
- bzf->buf[bzf->buflen] = '\0';
779
+ bzf->buf = REALLOC_N(bzf->buf, char, bzf->buflen+BZ_RB_BLOCKSIZE+1);
780
+ bzf->buflen += BZ_RB_BLOCKSIZE;
781
+ bzf->buf[bzf->buflen] = '\0';
746
782
  }
747
783
  bzf->bzs.avail_out = bzf->buflen - in;
748
784
  bzf->bzs.next_out = bzf->buf + in;
749
785
  bzf->state = BZ2_bzDecompress(&(bzf->bzs));
750
786
  if (bzf->state != BZ_OK) {
751
- BZ2_bzDecompressEnd(&(bzf->bzs));
752
- if (bzf->state != BZ_STREAM_END) {
753
- bzf->bzs.avail_out = 0;
754
- bz_raise(bzf->state);
755
- }
787
+ BZ2_bzDecompressEnd(&(bzf->bzs));
788
+ if (bzf->state != BZ_STREAM_END) {
789
+ bzf->bzs.avail_out = 0;
790
+ bz_raise(bzf->state);
791
+ }
756
792
  }
757
793
  bzf->bzs.avail_out = bzf->buflen - bzf->bzs.avail_out;
758
794
  bzf->bzs.next_out = bzf->buf;
@@ -761,101 +797,99 @@ bz_next_available(bzf, in)
761
797
 
762
798
  #define ASIZE (1 << CHAR_BIT)
763
799
 
764
- static VALUE
765
- bz_read_until(bzf, str, len, td1)
766
- struct bz_file *bzf;
767
- char *str;
768
- int len;
769
- int *td1;
770
- {
800
+ static VALUE bz_read_until(struct bz_file *bzf, const char *str, int len, int *td1) {
771
801
  VALUE res;
772
802
  int total, i, nex = 0;
773
- char *p, *t, *tx, *end, *pend = str + len;
803
+ char *p, *t, *tx, *end, *pend = ((char*) str) + len;
774
804
 
775
805
  res = rb_str_new(0, 0);
776
806
  while (1) {
777
- total = bzf->bzs.avail_out;
778
- if (len == 1) {
779
- tx = memchr(bzf->bzs.next_out, *str, bzf->bzs.avail_out);
780
- if (tx) {
781
- i = tx - bzf->bzs.next_out + len;
782
- res = rb_str_cat(res, bzf->bzs.next_out, i);
783
- bzf->bzs.next_out += i;
784
- bzf->bzs.avail_out -= i;
785
- return res;
786
- }
787
- }
788
- else {
789
- tx = bzf->bzs.next_out;
790
- end = bzf->bzs.next_out + bzf->bzs.avail_out;
791
- while (tx + len <= end) {
792
- for (p = str, t = tx; p != pend; ++p, ++t) {
793
- if (*p != *t) break;
794
- }
795
- if (p == pend) {
796
- i = tx - bzf->bzs.next_out + len;
797
- res = rb_str_cat(res, bzf->bzs.next_out, i);
798
- bzf->bzs.next_out += i;
799
- bzf->bzs.avail_out -= i;
800
- return res;
801
- }
802
- if (td1) {
803
- tx += td1[(int)*(tx + len)];
804
- }
805
- else {
806
- tx += 1;
807
- }
808
- }
809
- }
810
- nex = 0;
811
- if (total) {
812
- nex = len - 1;
813
- res = rb_str_cat(res, bzf->bzs.next_out, total - nex);
814
- if (nex) {
815
- MEMMOVE(bzf->buf, bzf->bzs.next_out + total - nex, char, nex);
807
+ total = bzf->bzs.avail_out;
808
+ if (len == 1) {
809
+ tx = memchr(bzf->bzs.next_out, *str, bzf->bzs.avail_out);
810
+ if (tx) {
811
+ i = tx - bzf->bzs.next_out + len;
812
+ res = rb_str_cat(res, bzf->bzs.next_out, i);
813
+ bzf->bzs.next_out += i;
814
+ bzf->bzs.avail_out -= i;
815
+ return res;
816
+ }
817
+ } else {
818
+ tx = bzf->bzs.next_out;
819
+ end = bzf->bzs.next_out + bzf->bzs.avail_out;
820
+ while (tx + len <= end) {
821
+ for (p = (char*) str, t = tx; p != pend; ++p, ++t) {
822
+ if (*p != *t) break;
823
+ }
824
+ if (p == pend) {
825
+ i = tx - bzf->bzs.next_out + len;
826
+ res = rb_str_cat(res, bzf->bzs.next_out, i);
827
+ bzf->bzs.next_out += i;
828
+ bzf->bzs.avail_out -= i;
829
+ return res;
830
+ }
831
+ if (td1) {
832
+ tx += td1[(int)*(tx + len)];
833
+ } else {
834
+ tx += 1;
835
+ }
836
+ }
816
837
  }
817
- }
818
- if (bz_next_available(bzf, nex) == BZ_STREAM_END) {
819
- if (nex) {
820
- res = rb_str_cat(res, bzf->buf, nex);
838
+ nex = 0;
839
+ if (total) {
840
+ nex = len - 1;
841
+ res = rb_str_cat(res, bzf->bzs.next_out, total - nex);
842
+ if (nex) {
843
+ MEMMOVE(bzf->buf, bzf->bzs.next_out + total - nex, char, nex);
844
+ }
821
845
  }
822
- if (RSTRING_LEN(res)) {
823
- return res;
846
+ if (bz_next_available(bzf, nex) == BZ_STREAM_END) {
847
+ if (nex) {
848
+ res = rb_str_cat(res, bzf->buf, nex);
849
+ }
850
+ if (RSTRING_LEN(res)) {
851
+ return res;
852
+ }
853
+ return Qnil;
824
854
  }
825
- return Qnil;
826
- }
827
855
  }
828
856
  return Qnil;
829
857
  }
830
858
 
831
- static int
832
- bz_read_while(bzf, c)
833
- struct bz_file *bzf;
834
- char c;
835
- {
859
+ static int bz_read_while(struct bz_file *bzf, char c) {
836
860
  char *end;
837
861
 
838
862
  while (1) {
839
- end = bzf->bzs.next_out + bzf->bzs.avail_out;
840
- while (bzf->bzs.next_out < end) {
841
- if (c != *bzf->bzs.next_out) {
842
- bzf->bzs.avail_out = end - bzf->bzs.next_out;
843
- return *bzf->bzs.next_out;
863
+ end = bzf->bzs.next_out + bzf->bzs.avail_out;
864
+ while (bzf->bzs.next_out < end) {
865
+ if (c != *bzf->bzs.next_out) {
866
+ bzf->bzs.avail_out = end - bzf->bzs.next_out;
867
+ return *bzf->bzs.next_out;
868
+ }
869
+ ++bzf->bzs.next_out;
870
+ }
871
+ if (bz_next_available(bzf, 0) == BZ_STREAM_END) {
872
+ return EOF;
844
873
  }
845
- ++bzf->bzs.next_out;
846
- }
847
- if (bz_next_available(bzf, 0) == BZ_STREAM_END) {
848
- return EOF;
849
- }
850
874
  }
851
875
  return EOF;
852
876
  }
853
877
 
854
- static VALUE
855
- bz_reader_read(argc, argv, obj)
856
- int argc;
857
- VALUE obj, *argv;
858
- {
878
+ /*
879
+ * call-seq:
880
+ * read(len = nil)
881
+ *
882
+ * Read decompressed data from the stream.
883
+ *
884
+ * Bzip2::Reader.new(Bzip2.compress('ab')).read # => "ab"
885
+ * Bzip2::Reader.new(Bzip2.compress('ab')).read(1) # => "a"
886
+ *
887
+ * @return [String, nil] the decompressed data read or +nil+ if eoz has been
888
+ * reached
889
+ * @param [Integer] len the number of decompressed bytes which should be read.
890
+ * If nothing is specified, the entire stream is read
891
+ */
892
+ static VALUE bz_reader_read(int argc, VALUE *argv, VALUE obj) {
859
893
  struct bz_file *bzf;
860
894
  VALUE res, length;
861
895
  int total;
@@ -863,449 +897,552 @@ bz_reader_read(argc, argv, obj)
863
897
 
864
898
  rb_scan_args(argc, argv, "01", &length);
865
899
  if (NIL_P(length)) {
866
- n = -1;
867
- }
868
- else {
869
- n = NUM2INT(length);
870
- if (n < 0) {
871
- rb_raise(rb_eArgError, "negative length %d given", n);
872
- }
900
+ n = -1;
901
+ } else {
902
+ n = NUM2INT(length);
903
+ if (n < 0) {
904
+ rb_raise(rb_eArgError, "negative length %d given", n);
905
+ }
873
906
  }
874
907
  bzf = bz_get_bzf(obj);
875
908
  if (!bzf) {
876
- return Qnil;
909
+ return Qnil;
877
910
  }
878
911
  res = rb_str_new(0, 0);
879
912
  if (OBJ_TAINTED(obj)) {
880
- OBJ_TAINT(res);
913
+ OBJ_TAINT(res);
881
914
  }
882
915
  if (n == 0) {
883
- return res;
884
- }
885
- while (1) {
886
- total = bzf->bzs.avail_out;
887
- if (n != -1 && (RSTRING_LEN(res) + total) >= n) {
888
- n -= RSTRING_LEN(res);
889
- res = rb_str_cat(res, bzf->bzs.next_out, n);
890
- bzf->bzs.next_out += n;
891
- bzf->bzs.avail_out -= n;
892
- return res;
893
- }
894
- if (total) {
895
- res = rb_str_cat(res, bzf->bzs.next_out, total);
896
- }
897
- if (bz_next_available(bzf, 0) == BZ_STREAM_END) {
898
916
  return res;
899
917
  }
918
+ while (1) {
919
+ total = bzf->bzs.avail_out;
920
+ if (n != -1 && (RSTRING_LEN(res) + total) >= n) {
921
+ n -= RSTRING_LEN(res);
922
+ res = rb_str_cat(res, bzf->bzs.next_out, n);
923
+ bzf->bzs.next_out += n;
924
+ bzf->bzs.avail_out -= n;
925
+ return res;
926
+ }
927
+ if (total) {
928
+ res = rb_str_cat(res, bzf->bzs.next_out, total);
929
+ }
930
+ if (bz_next_available(bzf, 0) == BZ_STREAM_END) {
931
+ return res;
932
+ }
900
933
  }
901
934
  return Qnil;
902
935
  }
903
936
 
904
- static int
905
- bz_getc(obj)
906
- VALUE obj;
907
- {
937
+ static int bz_getc(VALUE obj) {
908
938
  VALUE length = INT2FIX(1);
909
939
  VALUE res = bz_reader_read(1, &length, obj);
910
940
  if (NIL_P(res) || RSTRING_LEN(res) == 0) {
911
- return EOF;
941
+ return EOF;
912
942
  }
913
943
  return RSTRING_PTR(res)[0];
914
944
  }
915
945
 
916
- static VALUE
917
- bz_reader_ungetc(obj, a)
918
- VALUE obj, a;
919
- {
946
+ /*
947
+ * call-seq:
948
+ * ungetc(byte)
949
+ *
950
+ * "Ungets" a character/byte. This rewinds the stream by 1 character and inserts
951
+ * the given character into that position. The next read will return the given
952
+ * character as the first one read
953
+ *
954
+ * reader = Bzip2::Reader.new Bzip2.compress('abc')
955
+ * reader.getc # => 97
956
+ * reader.ungetc 97 # => nil
957
+ * reader.getc # => 97
958
+ * reader.ungetc 42 # => nil
959
+ * reader.getc # => 42
960
+ * reader.getc # => 98
961
+ * reader.getc # => 99
962
+ * reader.ungetc 100 # => nil
963
+ * reader.getc # => 100
964
+ *
965
+ * @param [Integer] byte the byte to 'unget'
966
+ * @return [nil] always
967
+ */
968
+ static VALUE bz_reader_ungetc(VALUE obj, VALUE a) {
920
969
  struct bz_file *bzf;
921
970
  int c = NUM2INT(a);
922
971
 
923
972
  Get_BZ2(obj, bzf);
924
973
  if (!bzf->buf) {
925
- bz_raise(BZ_SEQUENCE_ERROR);
974
+ bz_raise(BZ_SEQUENCE_ERROR);
926
975
  }
927
976
  if (bzf->bzs.avail_out < bzf->buflen) {
928
- bzf->bzs.next_out -= 1;
929
- bzf->bzs.next_out[0] = c;
930
- bzf->bzs.avail_out += 1;
931
- }
932
- else {
933
- bzf->buf = REALLOC_N(bzf->buf, char, bzf->buflen + 2);
934
- bzf->buf[bzf->buflen++] = c;
935
- bzf->buf[bzf->buflen] = '\0';
936
- bzf->bzs.next_out = bzf->buf;
937
- bzf->bzs.avail_out = bzf->buflen;
977
+ bzf->bzs.next_out -= 1;
978
+ bzf->bzs.next_out[0] = c;
979
+ bzf->bzs.avail_out += 1;
980
+ } else {
981
+ bzf->buf = REALLOC_N(bzf->buf, char, bzf->buflen + 2);
982
+ bzf->buf[bzf->buflen++] = c;
983
+ bzf->buf[bzf->buflen] = '\0';
984
+ bzf->bzs.next_out = bzf->buf;
985
+ bzf->bzs.avail_out = bzf->buflen;
938
986
  }
939
987
  return Qnil;
940
988
  }
941
989
 
942
- static VALUE
943
- bz_reader_ungets(obj, a)
944
- VALUE obj, a;
945
- {
990
+ /*
991
+ * call-seq:
992
+ * ungets(str)
993
+ *
994
+ * Equivalently "unget" a string. When called on a string that was just read
995
+ * from the stream, this inserts the string back into the stream to br read
996
+ * again.
997
+ *
998
+ * When called with a string which hasn't been read from the stream, it does
999
+ * the same thing, and the next read line/data will start from the beginning
1000
+ * of the given data and the continue on with the rest of the stream.
1001
+ *
1002
+ * reader = Bzip2::Reader.new Bzip2.compress("a\nb")
1003
+ * reader.gets # => "a\n"
1004
+ * reader.ungets "a\n" # => nil
1005
+ * reader.gets # => "a\n"
1006
+ * reader.ungets "foo" # => nil
1007
+ * reader.gets # => "foob"
1008
+ *
1009
+ * @param [String] str the string to insert back into the stream
1010
+ * @return [nil] always
1011
+ */
1012
+ static VALUE bz_reader_ungets(VALUE obj, VALUE a) {
946
1013
  struct bz_file *bzf;
947
1014
 
948
1015
  Check_Type(a, T_STRING);
949
1016
  Get_BZ2(obj, bzf);
950
1017
  if (!bzf->buf) {
951
- bz_raise(BZ_SEQUENCE_ERROR);
1018
+ bz_raise(BZ_SEQUENCE_ERROR);
952
1019
  }
953
1020
  if ((bzf->bzs.avail_out + RSTRING_LEN(a)) < bzf->buflen) {
954
- bzf->bzs.next_out -= RSTRING_LEN(a);
955
- MEMCPY(bzf->bzs.next_out, RSTRING_PTR(a), char, RSTRING_LEN(a));
956
- bzf->bzs.avail_out += RSTRING_LEN(a);
957
- }
958
- else {
959
- bzf->buf = REALLOC_N(bzf->buf, char, bzf->buflen + RSTRING_LEN(a) + 1);
960
- MEMCPY(bzf->buf + bzf->buflen, RSTRING_PTR(a), char,RSTRING_LEN(a));
961
- bzf->buflen += RSTRING_LEN(a);
962
- bzf->buf[bzf->buflen] = '\0';
963
- bzf->bzs.next_out = bzf->buf;
964
- bzf->bzs.avail_out = bzf->buflen;
1021
+ bzf->bzs.next_out -= RSTRING_LEN(a);
1022
+ MEMCPY(bzf->bzs.next_out, RSTRING_PTR(a), char, RSTRING_LEN(a));
1023
+ bzf->bzs.avail_out += RSTRING_LEN(a);
1024
+ } else {
1025
+ bzf->buf = REALLOC_N(bzf->buf, char, bzf->buflen + RSTRING_LEN(a) + 1);
1026
+ MEMCPY(bzf->buf + bzf->buflen, RSTRING_PTR(a), char,RSTRING_LEN(a));
1027
+ bzf->buflen += RSTRING_LEN(a);
1028
+ bzf->buf[bzf->buflen] = '\0';
1029
+ bzf->bzs.next_out = bzf->buf;
1030
+ bzf->bzs.avail_out = bzf->buflen;
965
1031
  }
966
1032
  return Qnil;
967
1033
  }
968
1034
 
969
- VALUE
970
- bz_reader_gets(obj)
971
- VALUE obj;
972
- {
1035
+ VALUE bz_reader_gets(VALUE obj) {
973
1036
  struct bz_file *bzf;
974
1037
  VALUE str = Qnil;
975
1038
 
976
1039
  bzf = bz_get_bzf(obj);
977
1040
  if (bzf) {
978
- str = bz_read_until(bzf, "\n", 1, 0);
979
- if (!NIL_P(str)) {
980
- bzf->lineno++;
981
- OBJ_TAINT(str);
982
- }
1041
+ str = bz_read_until(bzf, "\n", 1, 0);
1042
+ if (!NIL_P(str)) {
1043
+ bzf->lineno++;
1044
+ OBJ_TAINT(str);
1045
+ }
983
1046
  }
984
1047
  return str;
985
1048
  }
986
1049
 
987
- static VALUE
988
- bz_reader_gets_internal(argc, argv, obj, td, init)
989
- int argc;
990
- VALUE obj, *argv;
991
- int *td, init;
992
- {
1050
+ static VALUE bz_reader_gets_internal(int argc, VALUE *argv, VALUE obj, int *td, int init) {
993
1051
  struct bz_file *bzf;
994
1052
  VALUE rs, res;
995
- char *rsptr;
1053
+ const char *rsptr;
996
1054
  int rslen, rspara, *td1;
997
1055
 
998
1056
  rs = rb_rs;
999
1057
  if (argc) {
1000
- rb_scan_args(argc, argv, "1", &rs);
1001
- if (!NIL_P(rs)) {
1002
- Check_Type(rs, T_STRING);
1003
- }
1058
+ rb_scan_args(argc, argv, "1", &rs);
1059
+ if (!NIL_P(rs)) {
1060
+ Check_Type(rs, T_STRING);
1061
+ }
1004
1062
  }
1005
1063
  if (NIL_P(rs)) {
1006
- return bz_reader_read(1, &rs, obj);
1064
+ return bz_reader_read(1, &rs, obj);
1007
1065
  }
1008
1066
  rslen = RSTRING_LEN(rs);
1009
1067
  if (rs == rb_default_rs || (rslen == 1 && RSTRING_PTR(rs)[0] == '\n')) {
1010
- return bz_reader_gets(obj);
1068
+ return bz_reader_gets(obj);
1011
1069
  }
1012
1070
 
1013
1071
  if (rslen == 0) {
1014
- rsptr = "\n\n";
1015
- rslen = 2;
1016
- rspara = 1;
1017
- }
1018
- else {
1019
- rsptr = RSTRING_PTR(rs);
1020
- rspara = 0;
1072
+ rsptr = "\n\n";
1073
+ rslen = 2;
1074
+ rspara = 1;
1075
+ } else {
1076
+ rsptr = RSTRING_PTR(rs);
1077
+ rspara = 0;
1021
1078
  }
1022
1079
 
1023
1080
  bzf = bz_get_bzf(obj);
1024
1081
  if (!bzf) {
1025
- return Qnil;
1082
+ return Qnil;
1026
1083
  }
1027
1084
  if (rspara) {
1028
- bz_read_while(bzf, '\n');
1085
+ bz_read_while(bzf, '\n');
1029
1086
  }
1030
1087
  td1 = 0;
1031
1088
  if (rslen != 1) {
1032
- if (init) {
1033
- int i;
1089
+ if (init) {
1090
+ int i;
1034
1091
 
1035
- for (i = 0; i < ASIZE; i++) {
1036
- td[i] = rslen + 1;
1037
- }
1038
- for (i = 0; i < rslen; i++) {
1039
- td[(int)*(rsptr + i)] = rslen - i;
1092
+ for (i = 0; i < ASIZE; i++) {
1093
+ td[i] = rslen + 1;
1094
+ }
1095
+ for (i = 0; i < rslen; i++) {
1096
+ td[(int)*(rsptr + i)] = rslen - i;
1097
+ }
1040
1098
  }
1041
- }
1042
- td1 = td;
1099
+ td1 = td;
1043
1100
  }
1044
1101
 
1045
1102
  res = bz_read_until(bzf, rsptr, rslen, td1);
1046
1103
  if (rspara) {
1047
- bz_read_while(bzf, '\n');
1104
+ bz_read_while(bzf, '\n');
1048
1105
  }
1049
1106
 
1050
1107
  if (!NIL_P(res)) {
1051
- bzf->lineno++;
1052
- OBJ_TAINT(res);
1108
+ bzf->lineno++;
1109
+ OBJ_TAINT(res);
1053
1110
  }
1054
1111
  return res;
1055
1112
  }
1056
1113
 
1057
- static VALUE
1058
- bz_reader_set_unused(obj, a)
1059
- VALUE obj, a;
1060
- {
1114
+ /*
1115
+ * Specs were missing for this method originally and playing around with it
1116
+ * gave some very odd results, so unless you know what you're doing, I wouldn't
1117
+ * mess around with this...
1118
+ */
1119
+ static VALUE bz_reader_set_unused(VALUE obj, VALUE a) {
1061
1120
  struct bz_file *bzf;
1062
1121
 
1063
1122
  Check_Type(a, T_STRING);
1064
1123
  Get_BZ2(obj, bzf);
1065
1124
  if (!bzf->in) {
1066
- bzf->in = rb_str_new(RSTRING_PTR(a), RSTRING_LEN(a));
1067
- }
1068
- else {
1069
- bzf->in = rb_str_cat(bzf->in, RSTRING_PTR(a), RSTRING_LEN(a));
1125
+ bzf->in = rb_str_new(RSTRING_PTR(a), RSTRING_LEN(a));
1126
+ } else {
1127
+ bzf->in = rb_str_cat(bzf->in, RSTRING_PTR(a), RSTRING_LEN(a));
1070
1128
  }
1071
1129
  bzf->bzs.next_in = RSTRING_PTR(bzf->in);
1072
1130
  bzf->bzs.avail_in = RSTRING_LEN(bzf->in);
1073
1131
  return Qnil;
1074
1132
  }
1075
1133
 
1076
- static VALUE
1077
- bz_reader_getc(obj)
1078
- VALUE obj;
1079
- {
1134
+ /*
1135
+ * Reads one character from the stream, returning the byte read.
1136
+ *
1137
+ * reader = Bzip2::Reader.new Bzip2.compress('ab')
1138
+ * reader.getc # => 97
1139
+ * reader.getc # => 98
1140
+ * reader.getc # => nil
1141
+ *
1142
+ * @return [Integer, nil] the byte value of the character read or +nil+ if eoz
1143
+ * has been reached
1144
+ */
1145
+ static VALUE bz_reader_getc(VALUE obj) {
1080
1146
  VALUE str;
1081
1147
  VALUE len = INT2FIX(1);
1082
1148
 
1083
1149
  str = bz_reader_read(1, &len, obj);
1084
1150
  if (NIL_P(str) || RSTRING_LEN(str) == 0) {
1085
- return Qnil;
1151
+ return Qnil;
1086
1152
  }
1087
1153
  return INT2FIX(RSTRING_PTR(str)[0] & 0xff);
1088
1154
  }
1089
1155
 
1090
- static void
1091
- bz_eoz_error()
1092
- {
1156
+ static void bz_eoz_error() {
1093
1157
  rb_raise(bz_eEOZError, "End of Zip component reached");
1094
1158
  }
1095
1159
 
1096
- static VALUE
1097
- bz_reader_readchar(obj)
1098
- VALUE obj;
1099
- {
1160
+ /*
1161
+ * Performs the same as Bzip2::Reader#getc except Bzip2::EOZError is raised if
1162
+ * eoz has been readhed
1163
+ *
1164
+ * @raise [Bzip2::EOZError] if eoz has been reached
1165
+ */
1166
+ static VALUE bz_reader_readchar(VALUE obj) {
1100
1167
  VALUE res = bz_reader_getc(obj);
1101
1168
 
1102
1169
  if (NIL_P(res)) {
1103
- bz_eoz_error();
1170
+ bz_eoz_error();
1104
1171
  }
1105
1172
  return res;
1106
1173
  }
1107
1174
 
1108
- static VALUE
1109
- bz_reader_gets_m(argc, argv, obj)
1110
- int argc;
1111
- VALUE obj, *argv;
1112
- {
1175
+ /*
1176
+ * call-seq:
1177
+ * gets(sep = "\n")
1178
+ *
1179
+ * Reads a line from the stream until the separator is reached. This does not
1180
+ * throw an exception, but rather returns nil if an eoz/eof error occurs
1181
+ *
1182
+ * reader = Bzip2::Reader.new Bzip2.compress("a\nb")
1183
+ * reader.gets # => "a\n"
1184
+ * reader.gets # => "b"
1185
+ * reader.gets # => nil
1186
+ *
1187
+ * @return [String, nil] the read data or nil if eoz has been reached
1188
+ * @see Bzip2::Reader#readline
1189
+ */
1190
+ static VALUE bz_reader_gets_m(int argc, VALUE *argv, VALUE obj) {
1113
1191
  int td[ASIZE];
1114
1192
  VALUE str = bz_reader_gets_internal(argc, argv, obj, td, Qtrue);
1115
1193
 
1116
1194
  if (!NIL_P(str)) {
1117
- rb_lastline_set(str);
1195
+ rb_lastline_set(str);
1118
1196
  }
1119
1197
  return str;
1120
1198
  }
1121
1199
 
1122
- static VALUE
1123
- bz_reader_readline(argc, argv, obj)
1124
- int argc;
1125
- VALUE obj, *argv;
1126
- {
1200
+ /*
1201
+ * call-seq:
1202
+ * readline(sep = "\n")
1203
+ *
1204
+ * Reads one line from the stream and returns it (including the separator)
1205
+ *
1206
+ * reader = Bzip2::Reader.new Bzip2.compress("a\nb")
1207
+ * reader.readline # => "a\n"
1208
+ * reader.readline # => "b"
1209
+ * reader.readline # => raises Bzip2::EOZError
1210
+ *
1211
+ *
1212
+ * @param [String] sep the newline separator character
1213
+ * @return [String] the read line
1214
+ * @see Bzip2::Reader.readlines
1215
+ * @raise [Bzip2::EOZError] if the stream has reached its end
1216
+ */
1217
+ static VALUE bz_reader_readline(int argc, VALUE *argv, VALUE obj) {
1127
1218
  VALUE res = bz_reader_gets_m(argc, argv, obj);
1128
1219
 
1129
1220
  if (NIL_P(res)) {
1130
- bz_eoz_error();
1221
+ bz_eoz_error();
1131
1222
  }
1132
1223
  return res;
1133
1224
  }
1134
1225
 
1135
- static VALUE
1136
- bz_reader_readlines(argc, argv, obj)
1137
- int argc;
1138
- VALUE obj, *argv;
1139
- {
1226
+ /*
1227
+ * call-seq:
1228
+ * readlines(sep = "\n")
1229
+ *
1230
+ * Reads the lines of the files and returns the result as an array.
1231
+ *
1232
+ * If the stream has reached eoz, then an empty array is returned
1233
+ *
1234
+ * @param [String] sep the newline separator character
1235
+ * @return [Array] an array of lines read
1236
+ * @see Bzip2::Reader.readlines
1237
+ */
1238
+ static VALUE bz_reader_readlines(int argc, VALUE *argv, VALUE obj) {
1140
1239
  VALUE line, ary;
1141
1240
  int td[ASIZE], in;
1142
1241
 
1143
1242
  in = Qtrue;
1144
1243
  ary = rb_ary_new();
1145
1244
  while (!NIL_P(line = bz_reader_gets_internal(argc, argv, obj, td, in))) {
1146
- in = Qfalse;
1147
- rb_ary_push(ary, line);
1245
+ in = Qfalse;
1246
+ rb_ary_push(ary, line);
1148
1247
  }
1149
1248
  return ary;
1150
1249
  }
1151
1250
 
1152
- static VALUE
1153
- bz_reader_each_line(argc, argv, obj)
1154
- int argc;
1155
- VALUE obj, *argv;
1156
- {
1251
+ /*
1252
+ * call-seq:
1253
+ * each(sep = "\n", &block)
1254
+ *
1255
+ * Iterates over the lines of the stream.
1256
+ *
1257
+ * @param [String] sep the byte which separates lines
1258
+ * @yieldparam [String] line the next line of the file (including the separator
1259
+ * character)
1260
+ * @see Bzip2::Reader.foreach
1261
+ */
1262
+ static VALUE bz_reader_each_line(int argc, VALUE *argv, VALUE obj) {
1157
1263
  VALUE line;
1158
1264
  int td[ASIZE], in;
1159
1265
 
1160
1266
  in = Qtrue;
1161
1267
  while (!NIL_P(line = bz_reader_gets_internal(argc, argv, obj, td, in))) {
1162
- in = Qfalse;
1163
- rb_yield(line);
1268
+ in = Qfalse;
1269
+ rb_yield(line);
1164
1270
  }
1165
1271
  return obj;
1166
1272
  }
1167
1273
 
1168
- static VALUE
1169
- bz_reader_each_byte(obj)
1170
- VALUE obj;
1171
- {
1274
+ /*
1275
+ * call-seq:
1276
+ * each_byte(&block)
1277
+ *
1278
+ * Iterates over the decompressed bytes of the file.
1279
+ *
1280
+ * Bzip2::Writer.open('file'){ |f| f << 'asdf' }
1281
+ * reader = Bzip2::Reader.new File.open('file')
1282
+ * reader.each_byte{ |b| puts "#{b} #{b.chr}" }
1283
+ *
1284
+ * # Output:
1285
+ * # 97 a
1286
+ * # 115 s
1287
+ * # 100 d
1288
+ * # 102 f
1289
+ *
1290
+ * @yieldparam [Integer] byte the decompressed bytes of the file
1291
+ */
1292
+ static VALUE bz_reader_each_byte(VALUE obj) {
1172
1293
  int c;
1173
1294
 
1174
1295
  while ((c = bz_getc(obj)) != EOF) {
1175
- rb_yield(INT2FIX(c & 0xff));
1296
+ rb_yield(INT2FIX(c & 0xff));
1176
1297
  }
1177
1298
  return obj;
1178
1299
  }
1179
1300
 
1180
- static VALUE
1181
- bz_reader_unused(obj)
1182
- VALUE obj;
1183
- {
1301
+ /*
1302
+ * Specs were missing for this method originally and playing around with it
1303
+ * gave some very odd results, so unless you know what you're doing, I wouldn't
1304
+ * mess around with this...
1305
+ */
1306
+ static VALUE bz_reader_unused(VALUE obj) {
1184
1307
  struct bz_file *bzf;
1185
1308
  VALUE res;
1186
1309
 
1187
1310
  Get_BZ2(obj, bzf);
1188
1311
  if (!bzf->in || bzf->state != BZ_STREAM_END) {
1189
- return Qnil;
1312
+ return Qnil;
1190
1313
  }
1191
1314
  if (bzf->bzs.avail_in) {
1192
- res = rb_tainted_str_new(bzf->bzs.next_in, bzf->bzs.avail_in);
1193
- bzf->bzs.avail_in = 0;
1194
- }
1195
- else {
1196
- res = rb_tainted_str_new(0, 0);
1315
+ res = rb_tainted_str_new(bzf->bzs.next_in, bzf->bzs.avail_in);
1316
+ bzf->bzs.avail_in = 0;
1317
+ } else {
1318
+ res = rb_tainted_str_new(0, 0);
1197
1319
  }
1198
1320
  return res;
1199
1321
  }
1200
1322
 
1201
- static VALUE
1202
- bz_reader_eoz(obj)
1203
- VALUE obj;
1204
- {
1323
+ /*
1324
+ * Test whether the end of the bzip stream has been reached
1325
+ *
1326
+ * @return [Boolean] +true+ if the reader is at the end of the bz stream or
1327
+ * +false+ otherwise
1328
+ */
1329
+ static VALUE bz_reader_eoz(VALUE obj) {
1205
1330
  struct bz_file *bzf;
1206
1331
 
1207
1332
  Get_BZ2(obj, bzf);
1208
1333
  if (!bzf->in || !bzf->buf) {
1209
- return Qnil;
1334
+ return Qnil;
1210
1335
  }
1211
1336
  if (bzf->state == BZ_STREAM_END && !bzf->bzs.avail_out) {
1212
- return Qtrue;
1337
+ return Qtrue;
1213
1338
  }
1214
1339
  return Qfalse;
1215
1340
  }
1216
1341
 
1217
- static VALUE
1218
- bz_reader_eof(obj)
1219
- VALUE obj;
1220
- {
1342
+ /*
1343
+ * Test whether the bzip stream has reached its end (see Bzip2::Reader#eoz?)
1344
+ * and then tests that the undlerying IO has also reached an eof
1345
+ *
1346
+ * @return [Boolean] +true+ if the stream has reached or +false+ otherwise.
1347
+ */
1348
+ static VALUE bz_reader_eof(VALUE obj) {
1221
1349
  struct bz_file *bzf;
1222
1350
  VALUE res;
1223
1351
 
1224
1352
  res = bz_reader_eoz(obj);
1225
1353
  if (RTEST(res)) {
1226
- Get_BZ2(obj, bzf);
1227
- if (bzf->bzs.avail_in) {
1228
- res = Qfalse;
1229
- }
1230
- else {
1231
- res = bz_reader_getc(obj);
1232
- if (NIL_P(res)) {
1233
- res = Qtrue;
1234
- }
1235
- else {
1236
- bz_reader_ungetc(res);
1237
- res = Qfalse;
1354
+ Get_BZ2(obj, bzf);
1355
+ if (bzf->bzs.avail_in) {
1356
+ res = Qfalse;
1357
+ } else {
1358
+ res = bz_reader_getc(obj);
1359
+ if (NIL_P(res)) {
1360
+ res = Qtrue;
1361
+ } else {
1362
+ bz_reader_ungetc(obj, res);
1363
+ res = Qfalse;
1364
+ }
1238
1365
  }
1239
1366
  }
1240
- }
1241
1367
  return res;
1242
1368
  }
1243
1369
 
1244
- static VALUE
1245
- bz_reader_closed(obj)
1246
- VALUE obj;
1247
- {
1370
+ /*
1371
+ * Tests whether this reader has be closed.
1372
+ *
1373
+ * @return [Boolean] +true+ if it is or +false+ otherwise.
1374
+ */
1375
+ static VALUE bz_reader_closed(VALUE obj) {
1248
1376
  struct bz_file *bzf;
1249
1377
 
1250
1378
  Data_Get_Struct(obj, struct bz_file, bzf);
1251
1379
  return RTEST(bzf->io)?Qfalse:Qtrue;
1252
1380
  }
1253
1381
 
1254
- static VALUE
1255
- bz_reader_close(obj)
1256
- VALUE obj;
1257
- {
1382
+ /*
1383
+ * Closes this reader to disallow further reads.
1384
+ *
1385
+ * reader = Bzip2::Reader.new File.open('file')
1386
+ * reader.close
1387
+ *
1388
+ * reader.closed? # => true
1389
+ *
1390
+ * @return [File] the io with which the reader was created.
1391
+ * @raise [IOError] if the stream has already been closed
1392
+ */
1393
+ static VALUE bz_reader_close(VALUE obj) {
1258
1394
  struct bz_file *bzf;
1259
1395
  VALUE res;
1260
1396
 
1261
1397
  Get_BZ2(obj, bzf);
1262
1398
  if (bzf->buf) {
1263
- free(bzf->buf);
1264
- bzf->buf = 0;
1399
+ free(bzf->buf);
1400
+ bzf->buf = 0;
1265
1401
  }
1266
1402
  if (bzf->state == BZ_OK) {
1267
- BZ2_bzDecompressEnd(&(bzf->bzs));
1403
+ BZ2_bzDecompressEnd(&(bzf->bzs));
1268
1404
  }
1269
1405
  if (bzf->flags & BZ2_RB_CLOSE) {
1270
- int closed = 0;
1271
- if (rb_respond_to(bzf->io, id_closed)) {
1272
- VALUE iv = rb_funcall2(bzf->io, id_closed, 0, 0);
1273
- closed = RTEST(iv);
1274
- }
1275
- if (!closed && rb_respond_to(bzf->io, id_close)) {
1276
- rb_funcall2(bzf->io, id_close, 0, 0);
1277
- }
1406
+ int closed = 0;
1407
+ if (rb_respond_to(bzf->io, id_closed)) {
1408
+ VALUE iv = rb_funcall2(bzf->io, id_closed, 0, 0);
1409
+ closed = RTEST(iv);
1410
+ }
1411
+ if (!closed && rb_respond_to(bzf->io, id_close)) {
1412
+ rb_funcall2(bzf->io, id_close, 0, 0);
1413
+ }
1278
1414
  }
1279
1415
  if (bzf->flags & (BZ2_RB_CLOSE|BZ2_RB_INTERNAL)) {
1280
- res = Qnil;
1281
- }
1282
- else {
1283
- res = bzf->io;
1416
+ res = Qnil;
1417
+ } else {
1418
+ res = bzf->io;
1284
1419
  }
1285
1420
  bzf->io = 0;
1286
1421
  return res;
1287
1422
  }
1288
1423
 
1289
- static VALUE
1290
- bz_reader_finish(obj)
1291
- VALUE obj;
1292
- {
1424
+ /*
1425
+ * Originally undocument and had no sepcs. Appears to call Bzip2::Reader#read
1426
+ * and then mark the stream as finished, but this didn't work for me...
1427
+ */
1428
+ static VALUE bz_reader_finish(VALUE obj) {
1293
1429
  struct bz_file *bzf;
1294
1430
 
1295
1431
  Get_BZ2(obj, bzf);
1296
1432
  if (bzf->buf) {
1297
- rb_funcall2(obj, id_read, 0, 0);
1298
- free(bzf->buf);
1433
+ rb_funcall2(obj, id_read, 0, 0);
1434
+ free(bzf->buf);
1299
1435
  }
1300
1436
  bzf->buf = 0;
1301
1437
  bzf->state = BZ_OK;
1302
1438
  return Qnil;
1303
1439
  }
1304
1440
 
1305
- static VALUE
1306
- bz_reader_close_bang(obj)
1307
- VALUE obj;
1308
- {
1441
+ /*
1442
+ * Originally undocument and had no sepcs. Appears to work nearly the same
1443
+ * as Bzip2::Reader#close...
1444
+ */
1445
+ static VALUE bz_reader_close_bang(VALUE obj) {
1309
1446
  struct bz_file *bzf;
1310
1447
  int closed;
1311
1448
 
@@ -1313,12 +1450,12 @@ bz_reader_close_bang(obj)
1313
1450
  closed = bzf->flags & (BZ2_RB_CLOSE|BZ2_RB_INTERNAL);
1314
1451
  bz_reader_close(obj);
1315
1452
  if (!closed && rb_respond_to(bzf->io, id_close)) {
1316
- if (rb_respond_to(bzf->io, id_closed)) {
1317
- closed = RTEST(rb_funcall2(bzf->io, id_closed, 0, 0));
1318
- }
1319
- if (!closed) {
1320
- rb_funcall2(bzf->io, id_close, 0, 0);
1321
- }
1453
+ if (rb_respond_to(bzf->io, id_closed)) {
1454
+ closed = RTEST(rb_funcall2(bzf->io, id_closed, 0, 0));
1455
+ }
1456
+ if (!closed) {
1457
+ rb_funcall2(bzf->io, id_close, 0, 0);
1458
+ }
1322
1459
  }
1323
1460
  return Qnil;
1324
1461
  }
@@ -1329,98 +1466,158 @@ struct foreach_arg {
1329
1466
  VALUE obj;
1330
1467
  };
1331
1468
 
1332
- static VALUE
1333
- bz_reader_foreach_line(arg)
1334
- struct foreach_arg *arg;
1335
- {
1469
+ static VALUE bz_reader_foreach_line(struct foreach_arg *arg) {
1336
1470
  VALUE str;
1337
1471
  int td[ASIZE], in;
1338
1472
 
1339
1473
  in = Qtrue;
1340
- while (!NIL_P(str = bz_reader_gets_internal(arg->argc, &arg->sep,
1341
- arg->obj, td, in))) {
1342
- in = Qfalse;
1343
- rb_yield(str);
1474
+ while (!NIL_P(str = bz_reader_gets_internal(arg->argc, &arg->sep, arg->obj, td, in))) {
1475
+ in = Qfalse;
1476
+ rb_yield(str);
1344
1477
  }
1345
1478
  return Qnil;
1346
1479
  }
1347
1480
 
1348
- static VALUE
1349
- bz_reader_s_foreach(argc, argv, obj)
1350
- int argc;
1351
- VALUE obj, *argv;
1352
- {
1481
+ /*
1482
+ * call-seq:
1483
+ * foreach(filename, &block)
1484
+ *
1485
+ * Reads a bz2 compressed file and yields each line to the block
1486
+ *
1487
+ * Bzip2::Writer.open('file'){ |f| f << "a\n" << "b\n" << "c\n\nd" }
1488
+ * Bzip2::Reader.foreach('file'){ |l| p l }
1489
+ *
1490
+ * # Output:
1491
+ * # "a\n"
1492
+ * # "b\n"
1493
+ * # "c\n"
1494
+ * # "\n"
1495
+ * # "d"
1496
+ *
1497
+ * @param [String] filename the path to the file to open
1498
+ * @yieldparam [String] each line of the file
1499
+ */
1500
+ static VALUE bz_reader_s_foreach(int argc, VALUE *argv, VALUE obj) {
1353
1501
  VALUE fname, sep;
1354
1502
  struct foreach_arg arg;
1355
1503
  struct bz_file *bzf;
1356
1504
 
1357
1505
  if (!rb_block_given_p()) {
1358
- rb_raise(rb_eArgError, "call out of a block");
1506
+ rb_raise(rb_eArgError, "call out of a block");
1359
1507
  }
1360
1508
  rb_scan_args(argc, argv, "11", &fname, &sep);
1509
+ #ifdef SafeStringValue
1510
+ SafeStringValue(fname);
1511
+ #else
1361
1512
  Check_SafeStr(fname);
1513
+ #endif
1362
1514
  arg.argc = argc - 1;
1363
1515
  arg.sep = sep;
1364
1516
  arg.obj = rb_funcall2(rb_mKernel, id_open, 1, &fname);
1365
- if (NIL_P(arg.obj)) return Qnil;
1517
+ if (NIL_P(arg.obj)) {
1518
+ return Qnil;
1519
+ }
1366
1520
  arg.obj = rb_funcall2(obj, id_new, 1, &arg.obj);
1367
1521
  Data_Get_Struct(arg.obj, struct bz_file, bzf);
1368
1522
  bzf->flags |= BZ2_RB_CLOSE;
1369
1523
  return rb_ensure(bz_reader_foreach_line, (VALUE)&arg, bz_reader_close, arg.obj);
1370
1524
  }
1371
1525
 
1372
- static VALUE
1373
- bz_reader_i_readlines(arg)
1374
- struct foreach_arg *arg;
1375
- {
1526
+ static VALUE bz_reader_i_readlines(struct foreach_arg *arg) {
1376
1527
  VALUE str, res;
1377
1528
  int td[ASIZE], in;
1378
1529
 
1379
1530
  in = Qtrue;
1380
1531
  res = rb_ary_new();
1381
- while (!NIL_P(str = bz_reader_gets_internal(arg->argc, &arg->sep,
1382
- arg->obj, td, in))) {
1383
- in = Qfalse;
1384
- rb_ary_push(res, str);
1532
+ while (!NIL_P(str = bz_reader_gets_internal(arg->argc, &arg->sep, arg->obj, td, in))) {
1533
+ in = Qfalse;
1534
+ rb_ary_push(res, str);
1385
1535
  }
1386
1536
  return res;
1387
1537
  }
1388
1538
 
1389
- static VALUE
1390
- bz_reader_s_readlines(argc, argv, obj)
1391
- int argc;
1392
- VALUE obj, *argv;
1393
- {
1539
+ /*
1540
+ * call-seq:
1541
+ * readlines(filename, separator="\n")
1542
+ *
1543
+ * Opens the given bz2 compressed file for reading and decompresses the file,
1544
+ * returning an array of the lines of the file. A line is denoted by the
1545
+ * separator argument.
1546
+ *
1547
+ * Bzip2::Writer.open('file'){ |f| f << "a\n" << "b\n" << "c\n\nd" }
1548
+ *
1549
+ * Bzip2::Reader.readlines('file') # => ["a\n", "b\n", "c\n", "\n", "d"]
1550
+ * Bzip2::Reader.readlines('file', 'c') # => ["a\nb\nc", "\n\nd"]
1551
+ *
1552
+ * @param [String] filename the path to the file to read
1553
+ * @param [String] separator the character to denote a newline in the file
1554
+ * @see Bzip2::Reader#readlines
1555
+ * @return [Array] an array of lines for the file
1556
+ * @raise [Bzip2::Error] if the file is not a valid bz2 compressed file
1557
+ */
1558
+ static VALUE bz_reader_s_readlines(int argc, VALUE *argv, VALUE obj) {
1394
1559
  VALUE fname, sep;
1395
1560
  struct foreach_arg arg;
1396
1561
  struct bz_file *bzf;
1397
1562
 
1398
1563
  rb_scan_args(argc, argv, "11", &fname, &sep);
1564
+ #ifdef SafeStringValue
1565
+ SafeStringValue(fname);
1566
+ #else
1399
1567
  Check_SafeStr(fname);
1568
+ #endif
1400
1569
  arg.argc = argc - 1;
1401
1570
  arg.sep = sep;
1402
1571
  arg.obj = rb_funcall2(rb_mKernel, id_open, 1, &fname);
1403
- if (NIL_P(arg.obj)) return Qnil;
1572
+ if (NIL_P(arg.obj)) {
1573
+ return Qnil;
1574
+ }
1404
1575
  arg.obj = rb_funcall2(obj, id_new, 1, &arg.obj);
1405
1576
  Data_Get_Struct(arg.obj, struct bz_file, bzf);
1406
1577
  bzf->flags |= BZ2_RB_CLOSE;
1407
1578
  return rb_ensure(bz_reader_i_readlines, (VALUE)&arg, bz_reader_close, arg.obj);
1408
1579
  }
1409
1580
 
1410
- static VALUE
1411
- bz_reader_lineno(obj)
1412
- VALUE obj;
1413
- {
1581
+ /*
1582
+ * Returns the current line number that the stream is at. This number is based
1583
+ * on the newline separator being "\n"
1584
+ *
1585
+ * reader = Bzip2::Reader.new Bzip2.compress("a\nb")
1586
+ * reader.lineno # => 0
1587
+ * reader.readline # => "a\n"
1588
+ * reader.lineno # => 1
1589
+ * reader.readline # => "b"
1590
+ * reader.lineno # => 2
1591
+
1592
+ * @return [Integer] the current line number
1593
+ */
1594
+ static VALUE bz_reader_lineno(VALUE obj) {
1414
1595
  struct bz_file *bzf;
1415
1596
 
1416
1597
  Get_BZ2(obj, bzf);
1417
1598
  return INT2NUM(bzf->lineno);
1418
1599
  }
1419
1600
 
1420
- static VALUE
1421
- bz_reader_set_lineno(obj, lineno)
1422
- VALUE obj, lineno;
1423
- {
1601
+ /*
1602
+ * call-seq:
1603
+ * lineno=(num)
1604
+ *
1605
+ * Sets the internal line number count that this stream should be set at
1606
+ *
1607
+ * reader = Bzip2::Reader.new Bzip2.compress("a\nb")
1608
+ * reader.lineno # => 0
1609
+ * reader.readline # => "a\n"
1610
+ * reader.lineno # => 1
1611
+ * reader.lineno = 0
1612
+ * reader.readline # => "b"
1613
+ * reader.lineno # => 1
1614
+ *
1615
+ * @note This does not actually rewind or move the stream forward
1616
+ * @param [Integer] lineno the line number which the stream should consider
1617
+ * being set at
1618
+ * @return [Integer] the line number provided
1619
+ */
1620
+ static VALUE bz_reader_set_lineno(VALUE obj, VALUE lineno) {
1424
1621
  struct bz_file *bzf;
1425
1622
 
1426
1623
  Get_BZ2(obj, bzf);
@@ -1428,121 +1625,111 @@ bz_reader_set_lineno(obj, lineno)
1428
1625
  return lineno;
1429
1626
  }
1430
1627
 
1431
- static VALUE
1432
- bz_to_io(obj)
1433
- VALUE obj;
1434
- {
1628
+ /*
1629
+ * Returns the io stream underlying this stream. If the strem was constructed
1630
+ * with a file, that is returned. Otherwise, an empty string is returned.
1631
+ *
1632
+ * @return [File, String] similar to whatever the stream was constructed with
1633
+ * @raise [IOError] if the stream has been closed
1634
+ */
1635
+ static VALUE bz_to_io(VALUE obj) {
1435
1636
  struct bz_file *bzf;
1436
1637
 
1437
1638
  Get_BZ2(obj, bzf);
1438
1639
  return bzf->io;
1439
1640
  }
1440
1641
 
1441
- static VALUE
1442
- bz_str_read(argc, argv, obj)
1443
- int argc;
1444
- VALUE obj, *argv;
1445
- {
1642
+ static VALUE bz_str_read(int argc, VALUE *argv, VALUE obj) {
1446
1643
  struct bz_str *bzs;
1447
1644
  VALUE res, len;
1448
1645
  int count;
1449
-
1646
+
1450
1647
  Data_Get_Struct(obj, struct bz_str, bzs);
1451
1648
  rb_scan_args(argc, argv, "01", &len);
1452
1649
  if (NIL_P(len)) {
1453
- count = RSTRING_LEN(bzs->str);
1454
- }
1455
- else {
1456
- count = NUM2INT(len);
1457
- if (count < 0) {
1458
- rb_raise(rb_eArgError, "negative length %d given", count);
1459
- }
1650
+ count = RSTRING_LEN(bzs->str);
1651
+ } else {
1652
+ count = NUM2INT(len);
1653
+ if (count < 0) {
1654
+ rb_raise(rb_eArgError, "negative length %d given", count);
1655
+ }
1460
1656
  }
1461
1657
  if (!count || bzs->pos == -1) {
1462
- return Qnil;
1658
+ return Qnil;
1463
1659
  }
1464
1660
  if ((bzs->pos + count) >= RSTRING_LEN(bzs->str)) {
1465
- res = rb_str_new(RSTRING_PTR(bzs->str) + bzs->pos,
1466
- RSTRING_LEN(bzs->str) - bzs->pos);
1467
- bzs->pos = -1;
1468
- }
1469
- else {
1470
- res = rb_str_new(RSTRING_PTR(bzs->str) + bzs->pos, count);
1471
- bzs->pos += count;
1661
+ res = rb_str_new(RSTRING_PTR(bzs->str) + bzs->pos,
1662
+ RSTRING_LEN(bzs->str) - bzs->pos);
1663
+ bzs->pos = -1;
1664
+ } else {
1665
+ res = rb_str_new(RSTRING_PTR(bzs->str) + bzs->pos, count);
1666
+ bzs->pos += count;
1472
1667
  }
1473
1668
  return res;
1474
1669
  }
1475
1670
 
1476
- static VALUE
1477
- bz_uncompress(argc, argv, obj)
1478
- int argc;
1479
- VALUE obj, *argv;
1480
- {
1671
+ /*
1672
+ * call-seq:
1673
+ * uncompress(data)
1674
+ * Decompress a string of bz2 compressed data.
1675
+ *
1676
+ * Bzip2.uncompress Bzip2.compress('asdf') # => 'asdf'
1677
+ *
1678
+ * @param [String] data bz2 compressed data
1679
+ * @return [String] +data+ as uncompressed bz2 data
1680
+ * @raise [Bzip2::Error] if +data+ is not valid bz2 data
1681
+ */
1682
+ static VALUE bz_uncompress(int argc, VALUE *argv, VALUE obj) {
1481
1683
  VALUE bz2, nilv = Qnil;
1482
1684
 
1483
1685
  if (!argc) {
1484
- rb_raise(rb_eArgError, "need a String to Uncompress");
1686
+ rb_raise(rb_eArgError, "need a String to Uncompress");
1485
1687
  }
1486
1688
  argv[0] = rb_str_to_str(argv[0]);
1487
1689
  bz2 = rb_funcall2(bz_cReader, id_new, argc, argv);
1488
1690
  return bz_reader_read(1, &nilv, bz2);
1489
1691
  }
1490
1692
 
1491
- static VALUE
1492
- bz_s_new(argc, argv, obj)
1493
- int argc;
1494
- VALUE obj, *argv;
1495
- {
1693
+ /*
1694
+ * Internally allocates data,
1695
+ *
1696
+ * @see Bzip2::Writer#initialize
1697
+ * @see Bzip2::Reader#initialize
1698
+ * @private
1699
+ */
1700
+ static VALUE bz_s_new(int argc, VALUE *argv, VALUE obj) {
1496
1701
  VALUE res = rb_funcall2(obj, rb_intern("allocate"), 0, 0);
1497
1702
  rb_obj_call_init(res, argc, argv);
1498
1703
  return res;
1499
1704
  }
1500
1705
 
1501
- static VALUE
1502
- bz_proc_new(func, val)
1503
- VALUE (*func)(ANYARGS);
1504
- VALUE val;
1505
- {
1506
- VALUE tmp = Data_Wrap_Struct(rb_cData, 0, 0, 0);
1507
- rb_define_singleton_method(tmp, "tmp_proc", func, 1);
1508
- return rb_funcall2(rb_funcall(tmp, rb_intern("method"), 1,
1509
- ID2SYM(rb_intern("tmp_proc"))),
1510
- rb_intern("to_proc"), 0, 0);
1511
- }
1512
-
1513
- void Init_bzip2_ext()
1514
- {
1706
+ void Init_bzip2_ext() {
1515
1707
  VALUE bz_mBzip2;
1516
1708
 
1517
- if (rb_const_defined_at(rb_cObject, rb_intern("Bzip2"))) {
1518
- rb_raise(rb_eNameError, "module already defined");
1519
- }
1520
-
1521
1709
  bz_internal_ary = rb_ary_new();
1522
1710
  rb_global_variable(&bz_internal_ary);
1523
- rb_funcall(rb_const_get(rb_cObject, rb_intern("ObjectSpace")),
1524
- rb_intern("define_finalizer"), 2, bz_internal_ary,
1525
- bz_proc_new(bz_internal_finalize, 0));
1526
-
1527
- id_new = rb_intern("new");
1528
- id_write = rb_intern("write");
1529
- id_open = rb_intern("open");
1530
- id_flush = rb_intern("flush");
1531
- id_read = rb_intern("read");
1532
- id_close = rb_intern("close");
1711
+ rb_set_end_proc(bz_internal_finalize, Qnil);
1712
+
1713
+ id_new = rb_intern("new");
1714
+ id_write = rb_intern("write");
1715
+ id_open = rb_intern("open");
1716
+ id_flush = rb_intern("flush");
1717
+ id_read = rb_intern("read");
1718
+ id_close = rb_intern("close");
1533
1719
  id_closed = rb_intern("closed?");
1534
- id_str = rb_intern("to_str");
1535
-
1536
- bz_mBzip2 = rb_define_module("Bzip2");
1537
- bz_eConfigError = rb_define_class_under(bz_mBzip2, "ConfigError", rb_eFatal);
1538
- bz_eError = rb_define_class_under(bz_mBzip2, "Error", rb_eIOError);
1539
- bz_eEOZError = rb_define_class_under(bz_mBzip2, "EOZError", bz_eError);
1540
-
1541
- rb_define_module_function(bz_mBzip2, "compress", bz_compress, -1);
1542
- rb_define_module_function(bz_mBzip2, "uncompress", bz_uncompress, -1);
1543
- rb_define_module_function(bz_mBzip2, "decompress", bz_uncompress, -1);
1544
- rb_define_module_function(bz_mBzip2, "bzip2", bz_compress, -1);
1545
- rb_define_module_function(bz_mBzip2, "bunzip2", bz_uncompress, -1);
1720
+ id_str = rb_intern("to_str");
1721
+
1722
+ bz_mBzip2 = rb_define_module("Bzip2");
1723
+ bz_eError = rb_define_class_under(bz_mBzip2, "Error", rb_eIOError);
1724
+ bz_eEOZError = rb_define_class_under(bz_mBzip2, "EOZError", bz_eError);
1725
+
1726
+ VALUE bz_mBzip2Singleton = rb_singleton_class(bz_mBzip2);
1727
+ rb_define_singleton_method(bz_mBzip2, "compress", bz_compress, -1);
1728
+ rb_define_singleton_method(bz_mBzip2, "uncompress", bz_uncompress, -1);
1729
+ rb_define_alias(bz_mBzip2Singleton, "bzip2", "compress");
1730
+ rb_define_alias(bz_mBzip2Singleton, "decompress", "uncompress");
1731
+ rb_define_alias(bz_mBzip2Singleton, "bunzip2", "uncompress");
1732
+
1546
1733
  /*
1547
1734
  Writer
1548
1735
  */
@@ -1551,7 +1738,7 @@ void Init_bzip2_ext()
1551
1738
  rb_define_alloc_func(bz_cWriter, bz_writer_s_alloc);
1552
1739
  #else
1553
1740
  rb_define_singleton_method(bz_cWriter, "allocate", bz_writer_s_alloc, 0);
1554
- #endif
1741
+ #endif
1555
1742
  rb_define_singleton_method(bz_cWriter, "new", bz_s_new, -1);
1556
1743
  rb_define_singleton_method(bz_cWriter, "open", bz_writer_s_open, -1);
1557
1744
  rb_define_method(bz_cWriter, "initialize", bz_writer_init, -1);
@@ -1562,10 +1749,11 @@ void Init_bzip2_ext()
1562
1749
  rb_define_method(bz_cWriter, "printf", rb_io_printf, -1);
1563
1750
  rb_define_method(bz_cWriter, "<<", rb_io_addstr, 1);
1564
1751
  rb_define_method(bz_cWriter, "flush", bz_writer_flush, 0);
1565
- rb_define_method(bz_cWriter, "finish", bz_writer_flush, 0);
1566
1752
  rb_define_method(bz_cWriter, "close", bz_writer_close, 0);
1567
1753
  rb_define_method(bz_cWriter, "close!", bz_writer_close_bang, 0);
1568
1754
  rb_define_method(bz_cWriter, "to_io", bz_to_io, 0);
1755
+ rb_define_alias(bz_cWriter, "finish", "flush");
1756
+
1569
1757
  /*
1570
1758
  Reader
1571
1759
  */
@@ -1592,20 +1780,21 @@ void Init_bzip2_ext()
1592
1780
  rb_define_method(bz_cReader, "readline", bz_reader_readline, -1);
1593
1781
  rb_define_method(bz_cReader, "readlines", bz_reader_readlines, -1);
1594
1782
  rb_define_method(bz_cReader, "each", bz_reader_each_line, -1);
1595
- rb_define_method(bz_cReader, "each_line", bz_reader_each_line, -1);
1596
1783
  rb_define_method(bz_cReader, "each_byte", bz_reader_each_byte, 0);
1597
1784
  rb_define_method(bz_cReader, "close", bz_reader_close, 0);
1598
1785
  rb_define_method(bz_cReader, "close!", bz_reader_close_bang, 0);
1599
1786
  rb_define_method(bz_cReader, "finish", bz_reader_finish, 0);
1600
- rb_define_method(bz_cReader, "closed", bz_reader_closed, 0);
1601
1787
  rb_define_method(bz_cReader, "closed?", bz_reader_closed, 0);
1602
1788
  rb_define_method(bz_cReader, "eoz?", bz_reader_eoz, 0);
1603
- rb_define_method(bz_cReader, "eoz", bz_reader_eoz, 0);
1604
1789
  rb_define_method(bz_cReader, "eof?", bz_reader_eof, 0);
1605
- rb_define_method(bz_cReader, "eof", bz_reader_eof, 0);
1606
1790
  rb_define_method(bz_cReader, "lineno", bz_reader_lineno, 0);
1607
1791
  rb_define_method(bz_cReader, "lineno=", bz_reader_set_lineno, 1);
1608
1792
  rb_define_method(bz_cReader, "to_io", bz_to_io, 0);
1793
+ rb_define_alias(bz_cReader, "each_line", "each");
1794
+ rb_define_alias(bz_cReader, "closed", "closed?");
1795
+ rb_define_alias(bz_cReader, "eoz", "eoz?");
1796
+ rb_define_alias(bz_cReader, "eof", "eof?");
1797
+
1609
1798
  /*
1610
1799
  Internal
1611
1800
  */