bzip2-ruby 0.2.6 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
  */