File Coverage

blib/lib/IO/String.pm
Criterion Covered Total %
statement 174 206 84.4
branch 78 108 72.2
condition 10 18 55.5
subroutine 26 33 78.7
pod 5 24 20.8
total 293 389 75.3


line stmt bran cond sub pod time code
1             package IO::String;
2              
3             # Copyright 1998-2005 Gisle Aas.
4             #
5             # This library is free software; you can redistribute it and/or
6             # modify it under the same terms as Perl itself.
7              
8             require 5.005_03;
9 6     6   9007 use strict;
  6         11  
  6         242  
10 6     6   32 use vars qw($VERSION $DEBUG $IO_CONSTANTS);
  6         10  
  6         599  
11             $VERSION = "1.08"; # $Date: 2005/12/05 12:00:47 $
12              
13 6     6   6750 use Symbol ();
  6         6684  
  6         18179  
14              
15             sub new
16             {
17 12     12 1 1568 my $class = shift;
18 12   33     55 my $self = bless Symbol::gensym(), ref($class) || $class;
19 12         307 tie *$self, $self;
20 12         51 $self->open(@_);
21 12         30 return $self;
22             }
23              
24             sub open
25             {
26 12     12 1 17 my $self = shift;
27 12 50       36 return $self->new(@_) unless ref($self);
28              
29 12 100       33 if (@_) {
30 11 50       28 my $bufref = ref($_[0]) ? $_[0] : \$_[0];
31 11 100       34 $$bufref = "" unless defined $$bufref;
32 11         32 *$self->{buf} = $bufref;
33             }
34             else {
35 1         2 my $buf = "";
36 1         4 *$self->{buf} = \$buf;
37             }
38 12         29 *$self->{pos} = 0;
39 12         21 *$self->{lno} = 0;
40 12         19 return $self;
41             }
42              
43             sub pad
44             {
45 4     4 1 8 my $self = shift;
46 4         9 my $old = *$self->{pad};
47 4 100       14 *$self->{pad} = substr($_[0], 0, 1) if @_;
48 4 100 66     26 return "\0" unless defined($old) && length($old);
49 1         3 return $old;
50             }
51              
52             sub dump
53             {
54 0     0 0 0 require Data::Dumper;
55 0         0 my $self = shift;
56 0         0 print Data::Dumper->Dump([$self], ['*self']);
57 0         0 print Data::Dumper->Dump([*$self{HASH}], ['$self{HASH}']);
58 0         0 return;
59             }
60              
61             sub TIEHANDLE
62             {
63 12 50   12   39 print "TIEHANDLE @_\n" if $DEBUG;
64 12 50       65 return $_[0] if ref($_[0]);
65 0         0 my $class = shift;
66 0         0 my $self = bless Symbol::gensym(), $class;
67 0         0 $self->open(@_);
68 0         0 return $self;
69             }
70              
71             sub DESTROY
72             {
73 3 50   3   245 print "DESTROY @_\n" if $DEBUG;
74             }
75              
76             sub close
77             {
78 5     5 0 24 my $self = shift;
79 5         25 delete *$self->{buf};
80 5         7 delete *$self->{pos};
81 5         7 delete *$self->{lno};
82 5 50       12 undef *$self if $] eq "5.008"; # workaround for some bug
83 5         9 return 1;
84             }
85              
86             sub opened
87             {
88 0     0 0 0 my $self = shift;
89 0         0 return defined *$self->{buf};
90             }
91              
92             sub binmode
93             {
94 0     0 0 0 my $self = shift;
95 0 0       0 return 1 unless @_;
96             # XXX don't know much about layers yet :-(
97 0         0 return 0;
98             }
99              
100             sub getc
101             {
102 98     98 0 97 my $self = shift;
103 98         72 my $buf;
104 98 100       163 return $buf if $self->read($buf, 1);
105 4         12 return undef;
106             }
107              
108             sub ungetc
109             {
110 4     4 0 7 my $self = shift;
111 4         10 $self->setpos($self->getpos() - 1);
112 4         5 return 1;
113             }
114              
115             sub eof
116             {
117 2     2 0 7 my $self = shift;
118 2         2 return length(${*$self->{buf}}) <= *$self->{pos};
  2         5  
119             }
120              
121             sub print
122             {
123 7     7 0 45 my $self = shift;
124 7 100       20 if (defined $\) {
125 2 100       4 if (defined $,) {
126 1         6 $self->write(join($,, @_).$\);
127             }
128             else {
129 1         6 $self->write(join("",@_).$\);
130             }
131             }
132             else {
133 5 50       26 if (defined $,) {
134 0         0 $self->write(join($,, @_));
135             }
136             else {
137 5         20 $self->write(join("",@_));
138             }
139             }
140 7         17 return 1;
141             }
142             *printflush = \*print;
143              
144             sub printf
145             {
146 6     6 0 29 my $self = shift;
147 6 50       13 print "PRINTF(@_)\n" if $DEBUG;
148 6         8 my $fmt = shift;
149 6         19 $self->write(sprintf($fmt, @_));
150 6         12 return 1;
151             }
152              
153              
154             my($SEEK_SET, $SEEK_CUR, $SEEK_END);
155              
156             sub _init_seek_constants
157             {
158 2 50   2   9 if ($IO_CONSTANTS) {
159 0         0 require IO::Handle;
160 0         0 $SEEK_SET = &IO::Handle::SEEK_SET;
161 0         0 $SEEK_CUR = &IO::Handle::SEEK_CUR;
162 0         0 $SEEK_END = &IO::Handle::SEEK_END;
163             }
164             else {
165 2         3 $SEEK_SET = 0;
166 2         2 $SEEK_CUR = 1;
167 2         4 $SEEK_END = 2;
168             }
169             }
170              
171              
172             sub seek
173             {
174 18     18 0 77 my($self,$off,$whence) = @_;
175 18   50     44 my $buf = *$self->{buf} || return 0;
176 18         22 my $len = length($$buf);
177 18         25 my $pos = *$self->{pos};
178              
179 18 100       35 _init_seek_constants() unless defined $SEEK_SET;
180              
181 18 100       43 if ($whence == $SEEK_SET) { $pos = $off }
  3 100       5  
    50          
182 13         18 elsif ($whence == $SEEK_CUR) { $pos += $off }
183 2         4 elsif ($whence == $SEEK_END) { $pos = $len + $off }
184 0         0 else { die "Bad whence ($whence)" }
185 18 50       30 print "SEEK(POS=$pos,OFF=$off,LEN=$len)\n" if $DEBUG;
186              
187 18 50       39 $pos = 0 if $pos < 0;
188 18 100       34 $self->truncate($pos) if $pos > $len; # extend file
189 18         27 *$self->{pos} = $pos;
190 18         39 return 1;
191             }
192              
193             sub pos
194             {
195 49     49 1 151 my $self = shift;
196 49         70 my $old = *$self->{pos};
197 49 100       347 if (@_) {
198 14   100     48 my $pos = shift || 0;
199 14         21 my $buf = *$self->{buf};
200 14 50       34 my $len = $buf ? length($$buf) : 0;
201 14 100       34 $pos = $len if $pos > $len;
202 14         28 *$self->{pos} = $pos;
203             }
204 49         93 return $old;
205             }
206              
207 26     26 0 115 sub getpos { shift->pos; }
208              
209             *sysseek = \&seek;
210             *setpos = \&pos;
211             *tell = \&getpos;
212              
213              
214              
215             sub getline
216             {
217 32     32 0 56 my $self = shift;
218 32   50     79 my $buf = *$self->{buf} || return;
219 32         34 my $len = length($$buf);
220 32         40 my $pos = *$self->{pos};
221 32 100       84 return if $pos >= $len;
222              
223 22 100       46 unless (defined $/) { # slurp
224 2         4 *$self->{pos} = $len;
225 2         10 return substr($$buf, $pos);
226             }
227              
228 20 100       40 unless (length $/) { # paragraph mode
229             # XXX slow&lazy implementation using getc()
230 7         9 my $para = "";
231 7         7 my $eol = 0;
232 7         8 my $c;
233 7         14 while (defined($c = $self->getc)) {
234 94 100       209 if ($c eq "\n") {
    100          
235 28         28 $eol++;
236 28 100       51 next if $eol > 2;
237             }
238             elsif ($eol > 1) {
239 4         92 $self->ungetc($c);
240 4         5 last;
241             }
242             else {
243 62         66 $eol = 0;
244             }
245 83         142 $para .= $c;
246             }
247 7         35 return $para; # XXX wantarray
248             }
249              
250 13         29 my $idx = index($$buf,$/,$pos);
251 13 100       30 if ($idx < 0) {
252             # return rest of it
253 6         11 *$self->{pos} = $len;
254 6         11 $. = ++ *$self->{lno};
255 6         21 return substr($$buf, $pos);
256             }
257 7         11 $len = $idx - $pos + length($/);
258 7         10 *$self->{pos} += $len;
259 7         12 $. = ++ *$self->{lno};
260 7         33 return substr($$buf, $pos, $len);
261             }
262              
263             sub getlines
264             {
265 4 50   4 0 26 die "getlines() called in scalar context\n" unless wantarray;
266 4         6 my $self = shift;
267 4         3 my($line, @lines);
268 4         9 push(@lines, $line) while defined($line = $self->getline);
269 4         16 return @lines;
270             }
271              
272             sub READLINE
273             {
274 16 100   16   72 goto &getlines if wantarray;
275 14         44 goto &getline;
276             }
277              
278             sub input_line_number
279             {
280 1     1 0 6 my $self = shift;
281 1         3 my $old = *$self->{lno};
282 1 50       4 *$self->{lno} = shift if @_;
283 1         4 return $old;
284             }
285              
286             sub truncate
287             {
288 5     5 0 19 my $self = shift;
289 5   100     33 my $len = shift || 0;
290 5         9 my $buf = *$self->{buf};
291 5 100       16 if (length($$buf) >= $len) {
292 2         6 substr($$buf, $len) = '';
293 2 50       6 *$self->{pos} = $len if $len < *$self->{pos};
294             }
295             else {
296 3         13 $$buf .= ($self->pad x ($len - length($$buf)));
297             }
298 5         11 return 1;
299             }
300              
301             sub read
302             {
303 110     110 0 158 my $self = shift;
304 110         122 my $buf = *$self->{buf};
305 110 50       181 return undef unless $buf;
306              
307 110         114 my $pos = *$self->{pos};
308 110         122 my $rem = length($$buf) - $pos;
309 110         92 my $len = $_[1];
310 110 100       186 $len = $rem if $len > $rem;
311 110 100       165 return undef if $len < 0;
312 108 100       158 if (@_ > 2) { # read offset
313 1         3 substr($_[0],$_[2]) = substr($$buf, $pos, $len);
314             }
315             else {
316 107         145 $_[0] = substr($$buf, $pos, $len);
317             }
318 108         118 *$self->{pos} += $len;
319 108         368 return $len;
320             }
321              
322             sub write
323             {
324 18     18 0 46 my $self = shift;
325 18         26 my $buf = *$self->{buf};
326 18 50       35 return unless $buf;
327              
328 18         21 my $pos = *$self->{pos};
329 18         23 my $slen = length($_[0]);
330 18         17 my $len = $slen;
331 18         19 my $off = 0;
332 18 100       37 if (@_ > 1) {
333 4 50       7 $len = $_[1] if $_[1] < $len;
334 4 100       10 if (@_ > 2) {
335 2   50     6 $off = $_[2] || 0;
336 2 50       5 die "Offset outside string" if $off > $slen;
337 2 100       5 if ($off < 0) {
338 1         2 $off += $slen;
339 1 50       4 die "Offset outside string" if $off < 0;
340             }
341 2         3 my $rem = $slen - $off;
342 2 50       5 $len = $rem if $rem < $len;
343             }
344             }
345 18         36 substr($$buf, $pos, $len) = substr($_[0], $off, $len);
346 18         24 *$self->{pos} += $len;
347 18         35 return $len;
348             }
349              
350             *sysread = \&read;
351             *syswrite = \&write;
352              
353             sub stat
354             {
355 0     0 0 0 my $self = shift;
356 0 0       0 return unless $self->opened;
357 0 0       0 return 1 unless wantarray;
358 0         0 my $len = length ${*$self->{buf}};
  0         0  
359              
360             return (
361             undef, undef, # dev, ino
362 0         0 0666, # filemode
363             1, # links
364             $>, # user id
365             $), # group id
366             undef, # device id
367             $len, # size
368             undef, # atime
369             undef, # mtime
370             undef, # ctime
371             512, # blksize
372             int(($len+511)/512) # blocks
373             );
374             }
375              
376             sub FILENO {
377 0     0   0 return undef; # XXX perlfunc says this means the file is closed
378             }
379              
380             sub blocking {
381 0     0 0 0 my $self = shift;
382 0   0     0 my $old = *$self->{blocking} || 0;
383 0 0       0 *$self->{blocking} = shift if @_;
384 0         0 return $old;
385             }
386              
387 0     0   0 my $notmuch = sub { return };
388              
389             *fileno = $notmuch;
390             *error = $notmuch;
391             *clearerr = $notmuch;
392             *sync = $notmuch;
393             *flush = $notmuch;
394             *setbuf = $notmuch;
395             *setvbuf = $notmuch;
396              
397             *untaint = $notmuch;
398             *autoflush = $notmuch;
399             *fcntl = $notmuch;
400             *ioctl = $notmuch;
401              
402             *GETC = \&getc;
403             *PRINT = \&print;
404             *PRINTF = \&printf;
405             *READ = \&read;
406             *WRITE = \&write;
407             *SEEK = \&seek;
408             *TELL = \&getpos;
409             *EOF = \&eof;
410             *CLOSE = \&close;
411             *BINMODE = \&binmode;
412              
413              
414             sub string_ref
415             {
416 1     1 1 6 my $self = shift;
417 1         3 return *$self->{buf};
418             }
419             *sref = \&string_ref;
420              
421             1;
422              
423             __END__
424              
425             =head1 NAME
426              
427             IO::String - Emulate file interface for in-core strings
428              
429             =head1 SYNOPSIS
430              
431             use IO::String;
432             $io = IO::String->new;
433             $io = IO::String->new($var);
434             tie *IO, 'IO::String';
435              
436             # read data
437             <$io>;
438             $io->getline;
439             read($io, $buf, 100);
440              
441             # write data
442             print $io "string\n";
443             $io->print(@data);
444             syswrite($io, $buf, 100);
445              
446             select $io;
447             printf "Some text %s\n", $str;
448              
449             # seek
450             $pos = $io->getpos;
451             $io->setpos(0); # rewind
452             $io->seek(-30, -1);
453             seek($io, 0, 0);
454              
455             =head1 DESCRIPTION
456              
457             The C<IO::String> module provides the C<IO::File> interface for in-core
458             strings. An C<IO::String> object can be attached to a string, and
459             makes it possible to use the normal file operations for reading or
460             writing data, as well as for seeking to various locations of the string.
461             This is useful when you want to use a library module that only
462             provides an interface to file handles on data that you have in a string
463             variable.
464              
465             Note that perl-5.8 and better has built-in support for "in memory"
466             files, which are set up by passing a reference instead of a filename
467             to the open() call. The reason for using this module is that it
468             makes the code backwards compatible with older versions of Perl.
469              
470             The C<IO::String> module provides an interface compatible with
471             C<IO::File> as distributed with F<IO-1.20>, but the following methods
472             are not available: new_from_fd, fdopen, format_write,
473             format_page_number, format_lines_per_page, format_lines_left,
474             format_name, format_top_name.
475              
476             The following methods are specific to the C<IO::String> class:
477              
478             =over 4
479              
480             =item $io = IO::String->new
481              
482             =item $io = IO::String->new( $string )
483              
484             The constructor returns a newly-created C<IO::String> object. It
485             takes an optional argument, which is the string to read from or write
486             into. If no $string argument is given, then an internal buffer
487             (initially empty) is allocated.
488              
489             The C<IO::String> object returned is tied to itself. This means
490             that you can use most Perl I/O built-ins on it too: readline, <>, getc,
491             print, printf, syswrite, sysread, close.
492              
493             =item $io->open
494              
495             =item $io->open( $string )
496              
497             Attaches an existing IO::String object to some other $string, or
498             allocates a new internal buffer (if no argument is given). The
499             position is reset to 0.
500              
501             =item $io->string_ref
502              
503             Returns a reference to the string that is attached to
504             the C<IO::String> object. Most useful when you let the C<IO::String>
505             create an internal buffer to write into.
506              
507             =item $io->pad
508              
509             =item $io->pad( $char )
510              
511             Specifies the padding to use if
512             the string is extended by either the seek() or truncate() methods. It
513             is a single character and defaults to "\0".
514              
515             =item $io->pos
516              
517             =item $io->pos( $newpos )
518              
519             Yet another interface for reading and setting the current read/write
520             position within the string (the normal getpos/setpos/tell/seek
521             methods are also available). The pos() method always returns the
522             old position, and if you pass it an argument it sets the new
523             position.
524              
525             There is (deliberately) a difference between the setpos() and seek()
526             methods in that seek() extends the string (with the specified
527             padding) if you go to a location past the end, whereas setpos()
528             just snaps back to the end. If truncate() is used to extend the string,
529             then it works as seek().
530              
531             =back
532              
533             =head1 BUGS
534              
535             In Perl versions < 5.6, the TIEHANDLE interface was incomplete.
536             If you use such a Perl, then seek(), tell(), eof(), fileno(), binmode() will
537             not do anything on an C<IO::String> handle. See L<perltie> for
538             details.
539              
540             =head1 SEE ALSO
541              
542             L<IO::File>, L<IO::Stringy>, L<perlfunc/open>
543              
544             =head1 COPYRIGHT
545              
546             Copyright 1998-2005 Gisle Aas.
547              
548             This library is free software; you can redistribute it and/or
549             modify it under the same terms as Perl itself.
550              
551             =cut