File Coverage

blib/lib/PDL/IO/Misc.pm
Criterion Covered Total %
statement 19 21 90.4
branch 7 10 70.0
condition 1 3 33.3
subroutine 4 5 80.0
pod 1 2 50.0
total 32 41 78.0


line stmt bran cond sub pod time code
1             #
2             # GENERATED WITH PDL::PP from lib/PDL/IO/Misc.pd! Don't modify!
3             #
4             package PDL::IO::Misc;
5              
6             our @EXPORT_OK = qw(rcols wcols swcols rgrep bswap2 bswap4 bswap8 bswap12 bswap16 bswap24 bswap32 isbigendian rcube rasc );
7             our %EXPORT_TAGS = (Func=>\@EXPORT_OK);
8              
9 22     22   696 use PDL::Core;
  22         46  
  22         307  
10 22     22   171 use PDL::Exporter;
  22         48  
  22         849  
11 22     22   113 use DynaLoader;
  22         51  
  22         11604  
12              
13              
14            
15             our @ISA = ( 'PDL::Exporter','DynaLoader' );
16             push @PDL::Core::PP, __PACKAGE__;
17             bootstrap PDL::IO::Misc ;
18              
19              
20              
21              
22              
23              
24              
25              
26             #line 7 "lib/PDL/IO/Misc.pd"
27              
28             use strict;
29             use warnings;
30              
31             =head1 NAME
32              
33             PDL::IO::Misc - misc IO routines for PDL
34              
35             =head1 DESCRIPTION
36              
37             Some basic I/O functionality: tables, byte-swapping
38              
39             =head1 SYNOPSIS
40              
41             use PDL::IO::Misc;
42              
43             =cut
44             #line 45 "lib/PDL/IO/Misc.pm"
45              
46              
47             =head1 FUNCTIONS
48              
49             =cut
50              
51              
52              
53              
54              
55             #line 47 "lib/PDL/IO/Misc.pd"
56              
57             use PDL::Primitive;
58             use PDL::Types;
59             use PDL::Options;
60             use PDL::Bad;
61             use Carp;
62             use Symbol qw/ gensym /;
63             use List::Util;
64             #line 65 "lib/PDL/IO/Misc.pm"
65              
66              
67             =head2 bswap2
68              
69             =for sig
70              
71             Signature: ([io] x())
72             Types: (sbyte byte short ushort long ulong indx ulonglong longlong
73             float double ldouble)
74              
75             =for usage
76              
77             bswap2($x); # all arguments given
78             $x->bswap2; # method call
79              
80             =for ref
81              
82             Swaps pairs of bytes in argument x()
83              
84             =pod
85              
86             Broadcasts over its inputs.
87              
88             =for bad
89              
90             C does not process bad values.
91             It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.
92              
93             =cut
94              
95              
96              
97              
98             *bswap2 = \&PDL::bswap2;
99              
100              
101              
102              
103              
104              
105             =head2 bswap4
106              
107             =for sig
108              
109             Signature: ([io] x())
110             Types: (sbyte byte short ushort long ulong indx ulonglong longlong
111             float double ldouble)
112              
113             =for usage
114              
115             bswap4($x); # all arguments given
116             $x->bswap4; # method call
117              
118             =for ref
119              
120             Swaps quads of bytes in argument x()
121              
122             =pod
123              
124             Broadcasts over its inputs.
125              
126             =for bad
127              
128             C does not process bad values.
129             It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.
130              
131             =cut
132              
133              
134              
135              
136             *bswap4 = \&PDL::bswap4;
137              
138              
139              
140              
141              
142              
143             =head2 bswap8
144              
145             =for sig
146              
147             Signature: ([io] x())
148             Types: (sbyte byte short ushort long ulong indx ulonglong longlong
149             float double ldouble)
150              
151             =for usage
152              
153             bswap8($x); # all arguments given
154             $x->bswap8; # method call
155              
156             =for ref
157              
158             Swaps octets of bytes in argument x()
159              
160             =pod
161              
162             Broadcasts over its inputs.
163              
164             =for bad
165              
166             C does not process bad values.
167             It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.
168              
169             =cut
170              
171              
172              
173              
174             *bswap8 = \&PDL::bswap8;
175              
176              
177              
178              
179              
180              
181             =head2 bswap12
182              
183             =for sig
184              
185             Signature: ([io] x())
186             Types: (sbyte byte short ushort long ulong indx ulonglong longlong
187             float double ldouble)
188              
189             =for usage
190              
191             bswap12($x); # all arguments given
192             $x->bswap12; # method call
193              
194             =for ref
195              
196             Swaps 12s of bytes in argument x()
197              
198             =pod
199              
200             Broadcasts over its inputs.
201              
202             =for bad
203              
204             C does not process bad values.
205             It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.
206              
207             =cut
208              
209              
210              
211              
212             *bswap12 = \&PDL::bswap12;
213              
214              
215              
216              
217              
218              
219             =head2 bswap16
220              
221             =for sig
222              
223             Signature: ([io] x())
224             Types: (sbyte byte short ushort long ulong indx ulonglong longlong
225             float double ldouble)
226              
227             =for usage
228              
229             bswap16($x); # all arguments given
230             $x->bswap16; # method call
231              
232             =for ref
233              
234             Swaps 16s of bytes in argument x()
235              
236             =pod
237              
238             Broadcasts over its inputs.
239              
240             =for bad
241              
242             C does not process bad values.
243             It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.
244              
245             =cut
246              
247              
248              
249              
250             *bswap16 = \&PDL::bswap16;
251              
252              
253              
254              
255              
256              
257             =head2 bswap24
258              
259             =for sig
260              
261             Signature: ([io] x())
262             Types: (sbyte byte short ushort long ulong indx ulonglong longlong
263             float double ldouble)
264              
265             =for usage
266              
267             bswap24($x); # all arguments given
268             $x->bswap24; # method call
269              
270             =for ref
271              
272             Swaps 24s of bytes in argument x()
273              
274             =pod
275              
276             Broadcasts over its inputs.
277              
278             =for bad
279              
280             C does not process bad values.
281             It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.
282              
283             =cut
284              
285              
286              
287              
288             *bswap24 = \&PDL::bswap24;
289              
290              
291              
292              
293              
294              
295             =head2 bswap32
296              
297             =for sig
298              
299             Signature: ([io] x())
300             Types: (sbyte byte short ushort long ulong indx ulonglong longlong
301             float double ldouble)
302              
303             =for usage
304              
305             bswap32($x); # all arguments given
306             $x->bswap32; # method call
307              
308             =for ref
309              
310             Swaps 32s of bytes in argument x()
311              
312             =pod
313              
314             Broadcasts over its inputs.
315              
316             =for bad
317              
318             C does not process bad values.
319             It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.
320              
321             =cut
322              
323              
324              
325              
326             *bswap32 = \&PDL::bswap32;
327              
328              
329              
330              
331              
332             #line 91 "lib/PDL/IO/Misc.pd"
333              
334             # Internal routine to extend PDL array by size $n along last dimension
335             # - Would be nice to have a proper extend function rather than hack
336             # - Is a NO-OP when handed a perl ARRAY ref rather than an ndarray arg
337             sub _ext_lastD { # Called by rcols and rgrep
338             my ($x,$n) = @_;
339             if (ref($_[0]) ne 'ARRAY') {
340             my @nold = $x->dims;
341             my @nnew = @nold;
342             $nnew[-1] += $n; # add $n to the last dimension
343             my $y = zeroes($x->type,@nnew); # New pdl
344             my $yy = $y->mv(-1,0)->slice("0:".($nold[-1]-1))->mv(0,-1);
345             $yy .= $x;
346             $_[0] = $y;
347             }
348             1;
349             }
350              
351             # Implements PDL->at() for either 1D PDL or ARRAY arguments
352             # TODO: Need to add support for multidim ndarrays parallel to rcols
353             sub _at_1D ($$) { # Called by wcols and swcols
354             my $data = $_[0];
355             my $index = $_[1];
356             if (ref $data eq 'ARRAY') {
357             return $data->[$index];
358             } else {
359             return $data->at($index);
360             }
361             }
362              
363             # squeezes "fluffy" perl list values into column data type
364             sub _burp_1D {
365             my $data = $_[0][0];
366             my $databox = $_[0][1];
367             my $index = $_[1];
368             my $start = $index - @{$databox} + 1;
369             if (ref $data eq 'ARRAY') {
370             push @{$data}, @{$databox};
371             } elsif ( ref($databox->[0]) eq "ARRAY" ) {
372             # could add POSIX::strtol for hex and octal support but
373             # can't break float conversions (how?)
374             $data->slice(":,$start:$index") .= pdl($data->type, $databox);
375             } else {
376             # could add POSIX::strtol for hex and octal support but
377             # can't break float conversions (how?)
378             $data->slice("$start:$index") .= pdl($data->type, $databox);
379             }
380             $_[0] = [ $data, [] ];
381             }
382              
383             # taken outside of rcols() to avoid clutter
384             sub _handle_types ($$$) {
385             my $ncols = shift;
386             my $deftype = shift;
387             my $types = shift;
388              
389             barf "Unknown PDL type given for DEFTYPE.\n"
390             unless ref($deftype) eq "PDL::Type";
391              
392             my @cols = ref($types) eq "ARRAY" ? @$types : ();
393              
394             if ( $#cols > -1 ) {
395             # truncate if required
396             $#cols = $ncols if $#cols > $ncols;
397              
398             # check input values are sensible
399             for ( 0 .. $#cols ) {
400             barf "Unknown value '$cols[$_]' in TYPES array.\n"
401             unless ref($cols[$_]) eq "PDL::Type";
402             }
403             }
404              
405             # fill in any missing columns
406             for ( ($#cols+1) .. $ncols ) { push @cols, $deftype; }
407              
408             return @cols;
409             } # sub: _handle_types
410              
411             # Whether an object is an IO handle
412             use Scalar::Util;
413             sub _is_io_handle {
414             my $h = shift;
415             # reftype catches almost every handle, except: *MYHANDLE
416             # fileno catches *MYHANDLE, but doesn't catch handles that aren't files
417             my $reftype = Scalar::Util::reftype($h);
418             return defined(fileno($h)) || (defined($reftype) && $reftype eq 'GLOB');
419             }
420              
421             =head2 rcols
422              
423             =for ref
424              
425             Read specified ASCII cols from a file into ndarrays and perl
426             arrays (also see L).
427              
428             =for usage
429              
430             Usage:
431             ($x,$y,...) = rcols( *HANDLE|"filename", { EXCLUDE => '/^!/' }, $col1, $col2, ... )
432             $x = rcols( *HANDLE|"filename", { EXCLUDE => '/^!/' }, [] )
433             ($x,$y,...) = rcols( *HANDLE|"filename", $col1, $col2, ..., { EXCLUDE => '/^!/' } )
434             ($x,$y,...) = rcols( *HANDLE|"filename", "/foo/", $col1, $col2, ... )
435              
436             For each column number specified, a 1D output PDL will be
437             generated. Anonymous arrays of column numbers generate
438             2D output ndarrays with dim0 for the column data and dim1
439             equal to the number of columns in the anonymous array(s).
440              
441             An empty anonymous array as column specification will
442             produce a single output data ndarray with dim(1) equal
443             to the number of columns available.
444              
445             There are two calling conventions - the old version, where a
446             pattern can be specified after the filename/handle, and the
447             new version where options are given as as hash reference.
448             This reference can be given as either the second or last
449             argument.
450              
451             The default behaviour is to ignore lines beginning with
452             a # character and lines that only consist of whitespace.
453             Options exist to only read from lines that match, or do
454             not match, supplied patterns, and to set the types of the
455             created ndarrays.
456              
457             Can take file name or *HANDLE, and if no explicit column
458             numbers are specified, all are assumed. For the allowed types,
459             see L.
460              
461             Options (case insensitive):
462              
463             EXCLUDE or IGNORE
464             - ignore lines matching this pattern (default B<'/^#/'>).
465              
466             INCLUDE or KEEP
467             - only use lines which match this pattern (default B<''>).
468              
469             LINES
470             - a string pattern specifying which line numbers to use.
471             Line numbers start at 0 and the syntax is 'a:b:c' to use
472             every c'th matching line between a and b (default B<''>).
473              
474             DEFTYPE
475             - default data type for stored data (if not specified, use the type
476             stored in C<$PDL::IO::Misc::deftype>, which starts off as B).
477              
478             TYPES
479             - reference to an array of data types, one element for each column
480             to be read in. Any missing columns use the DEFTYPE value (default B<[]>).
481              
482             COLSEP
483             - splits on this string/pattern/qr{} between columns of data. Defaults to
484             $PDL::IO::Misc::defcolsep.
485              
486             PERLCOLS
487             - an array of column numbers which are to be read into perl arrays
488             rather than ndarrays. Any columns not specified in the explicit list
489             of columns to read will be returned after the explicit columns.
490             (default B).
491              
492             COLIDS
493             - if defined to an array reference, it will be assigned the column
494             ID values obtained by splitting the first line of the file in the
495             identical fashion to the column data.
496              
497             CHUNKSIZE
498             - the number of input data elements to batch together before appending
499             to each output data ndarray (Default value is 100). If CHUNKSIZE is
500             greater than the number of lines of data to read, the entire file is
501             slurped in, lines split, and perl lists of column data are generated.
502             At the end, effectively pdl(@column_data) produces any result ndarrays.
503              
504             VERBOSE
505             - be verbose about IO processing (default C<$PDL::vebose>)
506              
507             =for example
508              
509             For example:
510              
511             $x = PDL->rcols 'file1'; # file1 has only one column of data
512             $x = PDL->rcols 'file2', []; # file2 can have multiple columns, still 1 ndarray output
513             # (empty array ref spec means all possible data fields)
514              
515             ($x,$y) = rcols 'table.csv', { COLSEP => ',' }; # read CSV data file
516             ($x,$y) = rcols *STDOUT; # default separator for lines like '32 24'
517              
518             # read in lines containing the string foo, where the first
519             # example also ignores lines that begin with a # character.
520             ($x,$y,$z) = rcols 'file2', 0,4,5, { INCLUDE => '/foo/' };
521             ($x,$y,$z) = rcols 'file2', 0,4,5, { INCLUDE => '/foo/', EXCLUDE => '' };
522              
523             # ignore the first 27 lines of the file, reading in as ushort's
524             ($x,$y) = rcols 'file3', { LINES => '27:-1', DEFTYPE => ushort };
525             ($x,$y) = rcols 'file3', { LINES => '27:', TYPES => [ ushort, ushort ] };
526              
527             # read in the first column as a perl array and the next two as ndarrays
528             # with the perl column returned after the ndarray outputs
529             ($x,$y,$name) = rcols 'file4', 1, 2 , { PERLCOLS => [ 0 ] };
530             printf "Number of names read in = %d\n", 1 + $#$name;
531              
532             # read in the first column as a perl array and the next two as ndarrays
533             # with PERLCOLS changing the type of the first returned value to perl list ref
534             ($name,$x,$y) = rcols 'file4', 0, 1, 2, { PERLCOLS => [ 0 ] };
535              
536             # read in the first column as a perl array returned first followed by the
537             # the next two data columns in the file as a single Nx2 ndarray
538             ($name,$xy) = rcols 'file4', 0, [1, 2], { PERLCOLS => [ 0 ] };
539              
540             NOTES:
541              
542             1. Quotes are required on patterns or use the qr{} quote regexp syntax.
543              
544             2. Columns are separated by whitespace by default, use the COLSEP option
545             separator to specify an alternate split pattern or string or specify an
546             alternate default separator by setting C<$PDL::IO::Misc::defcolsep> .
547              
548             3. Legacy support is present to use C<$PDL::IO::Misc::colsep> to set the
549             column separator but C<$PDL::IO::Misc::colsep> is not defined by default.
550             If you set the variable to a defined value it will get picked up.
551              
552             4. LINES => '-1:0:3' may not work as you expect, since lines are skipped
553             when read in, then the whole array reversed.
554              
555             5. For consistency with wcols and rcols 1D usage, column data is loaded
556             into the rows of the pdls (i.e., dim(0) is the elements read per column
557             in the file and dim(1) is the number of columns of data read.
558              
559             =cut
560              
561             use vars qw/ $colsep $defcolsep $deftype /;
562              
563             $defcolsep = ' '; # Default column separator
564             $deftype = double; # Default type for ndarrays
565              
566             my $defchunksize = 100; # Number of perl list items to append to ndarray
567             my $usecolsep; # This is the colsep value that is actually used
568              
569             # NOTE: XXX
570             # need to look at the line-selection code. For instance, if want
571             # lines => '-1:0:3',
572             # read in all lines, reverse, then apply the step
573             # -> fix point 4 above
574             #
575             # perhaps should just simplify the LINES option - ie remove
576             # support for reversed arrays?
577              
578             sub rcols{ PDL->rcols(@_) }
579              
580             sub PDL::rcols {
581             my $class = shift;
582             barf 'Usage ($x,$y,...) = rcols( *HANDLE|"filename", ["/pattern/" or \%options], $col1, $col2, ..., [ \%options] )'
583             if $#_<0;
584              
585             my $is_handle = _is_io_handle $_[0];
586             my $fh = $is_handle ? $_[0] : gensym;
587             open $fh, $_[0] or die "File $_[0] not found\n" unless $is_handle;
588             shift;
589              
590             # set up default options
591             my $opt = PDL::Options->new( {
592             CHUNKSIZE => undef,
593             COLIDS => undef,
594             COLSEP => undef,
595             DEFTYPE => $deftype,
596             EXCLUDE => '/^#/',
597             INCLUDE => undef,
598             LINES => '',
599             PERLCOLS => undef,
600             TYPES => [],
601             VERBOSE=> $PDL::verbose,
602             } );
603             $opt->synonyms( { IGNORE => 'EXCLUDE', KEEP => 'INCLUDE' } );
604              
605             # has the user supplied any options
606             if ( defined($_[0]) ) {
607             # ensure the old-style behaviour by setting the exclude pattern to undef
608             if ( $_[0] =~ m|^/.*/$| ) { $opt->options( { EXCLUDE => undef, INCLUDE => shift } ); }
609             elsif ( ref($_[0]) eq "Regexp" ) { $opt->options( { EXCLUDE => undef, INCLUDE => shift } ); }
610             elsif ( ref($_[0]) eq "HASH" ) { $opt->options( shift ); }
611             }
612              
613             # maybe the last element is a hash array as well
614             $opt->options( pop ) if defined($_[-1]) and ref($_[-1]) eq "HASH";
615              
616             # a reference to a hash array
617             my $options = $opt->current();
618              
619             # handle legacy colsep variable
620             $usecolsep = (defined $colsep) ? qr{$colsep} : undef;
621             $usecolsep = qr{$options->{COLSEP}} if $options->{COLSEP};
622              
623             # what are the patterns?
624             foreach my $pattern ( qw( INCLUDE EXCLUDE ) ) {
625             if ( $options->{$pattern} and ref($options->{$pattern}) ne "Regexp" ) {
626             if ( $options->{$pattern} =~ m|^/.*/$| ) {
627             $options->{$pattern} =~ s|^/(.*)/$|$1|;
628             $options->{$pattern} = qr($options->{$pattern});
629             } else {
630             barf "rcols() - unable to process $pattern value.\n";
631             }
632             }
633             }
634              
635             # CHUNKSIZE controls memory/time tradeoff of ndarray IO
636             my $chunksize = $options->{CHUNKSIZE} || $defchunksize;
637             my $nextburpindex = -1;
638              
639             # which columns are to be read into ndarrays and which into perl arrays?
640             my @end_perl_cols = (); # unique perl cols to return at end
641              
642             my @perl_cols = (); # perl cols index list from PERLCOLS option
643             @perl_cols = @{ $$options{PERLCOLS} } if $$options{PERLCOLS};
644              
645             my @is_perl_col; # true if index corresponds to a perl column
646             for (@perl_cols) { $is_perl_col[$_] = 1; };
647             # print STDERR "rcols: \@is_perl_col is @is_perl_col\n";
648              
649             my ( @explicit_cols ) = @_; # call specified columns to read
650             # print STDERR "rcols: \@explicit_cols is @explicit_cols\n";
651              
652             # work out which line numbers are required
653             # - the regexp's are a bit over the top
654             my ( $x, $y, $c );
655             if ( $$options{LINES} ne '' ) {
656             if ( $$options{LINES} =~ /^\s*([+-]?\d*)\s*:\s*([+-]?\d*)\s*$/ ) {
657             $x = $1; $y = $2;
658             } elsif ( $$options{LINES} =~ /^\s*([+-]?\d*)\s*:\s*([+-]?\d*)\s*:\s*([+]?\d*)\s*$/ ) {
659             $x = $1; $y = $2; $c = $3;
660             } else {
661             barf "rcols() - unable to parse LINES option.\n";
662             }
663             }
664              
665             # Since we do not know how many lines there are in advance, things get a bit messy
666             my ( $index_start, $index_end ) = ( 0, -1 );
667             $index_start = $x if defined($x) and $x ne '';
668             $index_end = $y if defined($y) and $y ne '';
669             my $line_step = $c || 1;
670              
671             # $line_rev = 0/1 for normal order/reversed
672             # $line_start/_end refer to the first and last line numbers that we want
673             # (the values of which we may not know until we've read in all the file)
674             my ( $line_start, $line_end, $line_rev );
675             if ( ($index_start >= 0 and $index_end < 0) ) {
676             # eg 0:-1
677             $line_rev = 0; $line_start = $index_start;
678             } elsif ( $index_end >= 0 and $index_start < 0 ) {
679             # eg -1:0
680             $line_rev = 1; $line_start = $index_end;
681             } elsif ( $index_end >= $index_start and $index_start >= 0 ) {
682             # eg 0:10
683             $line_rev = 0; $line_start = $index_start; $line_end = $index_end;
684             } elsif ( $index_start > $index_end and $index_end >= 0 ) {
685             # eg 10:0
686             $line_rev = 1; $line_start = $index_end; $line_end = $index_start;
687             } elsif ( $index_start <= $index_end ) {
688             # eg -5:-1
689             $line_rev = 0;
690             } else {
691             # eg -1:-5
692             $line_rev = 1;
693             }
694              
695             my @ret;
696              
697             my ($k,$fhline);
698              
699             my $line_num = -1;
700             my $line_ctr = $line_step - 1; # ensure first line is always included
701             my $index = -1;
702             my $pdlsize = 0;
703             my $extend = 10000;
704              
705             my $line_store; # line numbers of saved data
706              
707             RCOLS_IO: {
708              
709             if ($options->{COLIDS}) {
710             print STDERR "rcols: processing COLIDS option\n" if $options->{VERBOSE};
711             undef $!;
712             if (defined($fhline = <$fh>) ) { # grab first line's fields for column IDs
713             $fhline =~ s/\r?\n$//; # handle DOS on unix files better
714             my @v = defined($usecolsep) ? split($usecolsep,$fhline) : split(' ',$fhline);
715             @{$options->{COLIDS}} = @v;
716             } else {
717             die "rcols: reading COLIDS info, $!" if $!;
718             last RCOLS_IO;
719             }
720             }
721              
722             while( defined($fhline = <$fh>) ) {
723              
724             # chomp $fhline;
725             $fhline =~ s/\r?\n$//; # handle DOS on unix files better
726              
727             $line_num++;
728              
729             # the order of these checks is important, particularly whether we
730             # check for line_ctr before or after the pattern matching
731             # Prior to PDL 2.003 the line checks were done BEFORE the
732             # pattern matching
733             #
734             # need this first check, even with it almost repeated at end of loop,
735             # incase the pattern matching excludes $line_num == $line_end, say
736             last if defined($line_end) and $line_num > $line_end;
737             next if defined($line_start) and $line_num < $line_start;
738             next if $options->{EXCLUDE} and $fhline =~ /$options->{EXCLUDE}/;
739             next if $options->{INCLUDE} and not $fhline =~ /$options->{INCLUDE}/;
740             next unless ++$line_ctr == $line_step;
741             $line_ctr = 0;
742              
743             $index++;
744             my @v = defined($usecolsep) ? split($usecolsep,$fhline) : split(' ',$fhline);
745              
746             # map empty fields '' to undef value
747             @v = map { $_ eq '' ? undef : $_ } @v;
748              
749             # if the first line, set up the output ndarrays using all the columns
750             # if the user doesn't specify anything
751             if ( $index == 0 ) {
752              
753             # Handle implicit multicolumns in command line
754             if ($#explicit_cols < 0) { # implicit single col data
755             @explicit_cols = ( 0 .. $#v );
756             }
757             if (scalar(@explicit_cols)==1 and ref($explicit_cols[0]) eq "ARRAY") {
758             if ( !scalar(@{$explicit_cols[0]}) ) { # implicit multi-col data
759             @explicit_cols = ( [ 0 .. $#v ] );
760             }
761             }
762             my $implicit_pdls = 0;
763             my $is_explicit = {};
764             foreach my $col (@explicit_cols) {
765             if (ref($col) eq "ARRAY") {
766             $implicit_pdls++ if !scalar(@$col);
767             } else {
768             $is_explicit->{$col} = 1;
769             }
770             }
771             if ($implicit_pdls > 1) {
772             die "rcols: only one implicit multicolumn ndarray spec allowed, found $implicit_pdls!\n";
773             }
774             foreach my $col (@explicit_cols) {
775             if (ref($col) eq "ARRAY" and !scalar(@$col)) {
776             @$col = grep { !$is_explicit->{$_} } ( 0 .. $#v );
777             }
778             }
779              
780             # remove declared perl columns from pdl data list
781             $k = 0;
782             my @pdl_cols = ();
783             foreach my $col (@explicit_cols) {
784             # strip out declared perl cols so they won't be read into ndarrays
785             if ( ref($col) eq "ARRAY" ) {
786             @$col = grep { !$is_perl_col[$_] } @{$col};
787             push @pdl_cols, [ @{$col} ];
788             } elsif (!$is_perl_col[$col]) {
789             push @pdl_cols, $col;
790             }
791             }
792             # strip out perl cols in explicit col list for return at end
793             @end_perl_cols = @perl_cols;
794             foreach my $col (@explicit_cols) {
795             if ( ref($col) ne "ARRAY" and defined($is_perl_col[$col]) ) {
796             @end_perl_cols = grep { $_ != $col } @end_perl_cols;
797             }
798             };
799              
800             # sort out the types of the ndarrays
801             my @types = _handle_types( $#pdl_cols, $$options{DEFTYPE}, $$options{TYPES} );
802             if ( $options->{VERBOSE} ) { # dbg aid
803             print "Reading data into ndarrays of type: [ ";
804             foreach my $t ( @types ) {
805             print $t->shortctype() . " ";
806             }
807             print "]\n";
808             }
809              
810             $k = 0;
811             for (@explicit_cols) {
812             # Using mixed list+ndarray data structure for performance tradeoff
813             # between memory usage (perl list) and speed of IO (PDL operations)
814             if (ref($_) eq "ARRAY") {
815             # use multicolumn ndarray here
816             push @ret, [ $class->zeroes($types[$k++],scalar(@{$_}),1), [] ];
817             } else {
818             push @ret, ($is_perl_col[$_] ? [ [], [] ] : [ $class->zeroes($types[$k],1), [] ]);
819             $k++ unless $is_perl_col[$_];
820             }
821             }
822             for (@end_perl_cols) { push @ret, [ [], [] ]; }
823              
824             $line_store = [ $class->zeroes(long,1), [] ]; # only need to store integers
825             }
826              
827             # if necessary, extend PDL in buffered manner
828             $k = 0;
829             if ( $pdlsize < $index ) {
830             for (@ret, $line_store) { _ext_lastD( $_->[0], $extend ); }
831             $pdlsize += $extend;
832             }
833              
834             # - stick perl arrays onto end of $ret
835             $k = 0;
836             for (@explicit_cols, @end_perl_cols) {
837             if (ref($_) eq "ARRAY") {
838             push @{ $ret[$k++]->[1] }, [ @v[ @$_ ] ];
839             } else {
840             push @{ $ret[$k++]->[1] }, $v[$_];
841             }
842             }
843              
844             # store the line number
845             push @{$line_store->[1]}, $line_num;
846              
847             # need to burp out list if needed
848             if ( $index >= $nextburpindex ) {
849             for (@ret, $line_store) { _burp_1D($_,$index); }
850             $nextburpindex = $index + $chunksize;
851             }
852              
853             # Thanks to Frank Samuelson for this
854             last if defined($line_end) and $line_num == $line_end;
855             }
856              
857             }
858              
859             close($fh) unless $is_handle;
860              
861             # burp one final time if needed and
862             # clean out additional ARRAY ref level for @ret
863             for (@ret, $line_store) {
864             _burp_1D($_,$index) if defined $_ and scalar @{$_->[1]};
865             $_ = $_->[0];
866             }
867              
868             # have we read anything in? if not, return empty ndarrays
869             if ( $index == -1 ) {
870             print "Warning: rcols() did not read in any data.\n" if $options->{VERBOSE};
871             if ( wantarray ) {
872             foreach ( 0 .. $#explicit_cols ) {
873             if ( $is_perl_col[$_] ) {
874             $ret[$_] = PDL->null;
875             } else {
876             $ret[$_] = [];
877             }
878             }
879             for ( @end_perl_cols ) { push @ret, []; }
880             return ( @ret );
881             } else {
882             return PDL->null;
883             }
884             }
885              
886             # if the user has asked for lines => 0:-1 or 0:10 or 1:10 or 1:-1,
887             # - ie not reversed and the last line number is known -
888             # then we can skip the following nastiness
889             if ( $line_rev == 0 and $index_start >= 0 and $index_end >= -1 ) {
890             for (@ret) {
891             ## $_ = $_->mv(-1,0)->slice("0:${index}")->mv(0,-1) unless ref($_) eq 'ARRAY';
892             $_ = $_->mv(-1,0)->slice("0:${index}") unless ref($_) eq 'ARRAY'; # cols are dim(0)
893             };
894             if ( $options->{VERBOSE} ) {
895             if ( ref($ret[0]) eq 'ARRAY' ) {
896             print "Read in ", scalar( @{ $ret[0] } ), " elements.\n";
897             } else {
898             print "Read in ", $ret[0]->nelem, " elements.\n";
899             }
900             }
901             wantarray ? return(@ret) : return $ret[0];
902             }
903              
904             # Work out which line numbers we want. First we clean up the ndarray
905             # containing the line numbers that have been read in
906             $line_store = $line_store->slice("0:${index}");
907              
908             # work out the min/max line numbers required
909             if ( $line_rev ) {
910             if ( defined($line_start) and defined($line_end) ) {
911             my $dummy = $line_start;
912             $line_start = $line_end;
913             $line_end = $dummy;
914             } elsif ( defined($line_start) ) {
915             $line_end = $line_start;
916             } else {
917             $line_start = $line_end;
918             }
919             }
920             $line_start = $line_num + 1 + $index_start if $index_start < 0;
921             $line_end = $line_num + 1 + $index_end if $index_end < 0;
922              
923             my $indices;
924              
925             { no warnings 'precedence';
926             if ( $line_rev ) {
927             $indices = which( $line_store >= $line_end & $line_store <= $line_start )->slice('-1:0');
928             } else {
929             $indices = which( $line_store >= $line_start & $line_store <= $line_end );
930             }
931             }
932              
933             # truncate the ndarrays
934             for my $col ( @explicit_cols ) {
935             if ( ref($col) eq "ARRAY" ) {
936             for ( @$col ) {
937             $ret[$_] = $ret[$_]->index($indices);
938             }
939             } else {
940             $ret[$col] = $ret[$col]->index($indices) unless $is_perl_col[$col] };
941             }
942              
943             # truncate/reverse/etc the perl arrays
944             my @indices_array = list $indices;
945             foreach ( @explicit_cols, @end_perl_cols ) {
946             if ( $is_perl_col[$_] ) {
947             my @temp = @{ $ret[$_] };
948             $ret[$_] = [];
949             foreach my $i ( @indices_array ) { push @{ $ret[$_] }, $temp[$i] };
950             }
951             }
952              
953             # print some diagnostics
954             if ( $options->{VERBOSE} ) {
955             my $done = 0;
956             foreach my $col (@explicit_cols) {
957             last if $done;
958             next if $is_perl_col[$col];
959             print "Read in ", $ret[$col]->nelem, " elements.\n";
960             $done = 1;
961             }
962             foreach my $col (@explicit_cols, @end_perl_cols) {
963             last if $done;
964             print "Read in ", $ret[$col]->nelem, " elements.\n";
965             $done = 1;
966             }
967             }
968              
969             # fix 2D pdls to match what wcols generates
970             foreach my $col (@ret) {
971             next if ref($col) eq "ARRAY";
972             $col = $col->transpose if $col->ndims == 2;
973             }
974              
975             wantarray ? return(@ret) : return $ret[0];
976             }
977              
978             =head2 wcols
979              
980             =for ref
981              
982             Write ASCII columns into file from 1D or 2D ndarrays and/or 1D listrefs efficiently.
983              
984             Can take file name or *HANDLE, and if no file/filehandle is given defaults to STDOUT.
985              
986             Options (case insensitive):
987              
988             HEADER - prints this string before the data. If the string
989             is not terminated by a newline, one is added. (default B<''>).
990              
991             COLSEP - prints this string between columns of data. Defaults to
992             $PDL::IO::Misc::defcolsep.
993              
994             FORMAT - A printf-style format string that is cycled through
995             column output for user controlled formatting.
996              
997             =for usage
998              
999             Usage: wcols $data1, $data2, $data3,..., *HANDLE|"outfile", [\%options]; # or
1000             wcols $format_string, $data1, $data2, $data3,..., *HANDLE|"outfile", [\%options];
1001              
1002             where the $dataN args are either 1D ndarrays, 1D perl array refs,
1003             or 2D ndarrays (as might be returned from rcols() with the [] column
1004             syntax and/or using the PERLCOLS option). dim(0) of all ndarrays
1005             written must be the same size. The printf-style $format_string,
1006             if given, overrides any FORMAT key settings in the option hash.
1007              
1008             e.g.,
1009              
1010             =for example
1011              
1012             $x = random(4); $y = ones(4);
1013             wcols $x, $y+2, 'foo.dat';
1014             wcols $x, $y+2, *STDERR;
1015             wcols $x, $y+2, '|wc';
1016              
1017             $x = sequence(3); $y = zeros(3); $c = random(3);
1018             wcols $x,$y,$c; # Orthogonal version of 'print $x,$y,$c' :-)
1019              
1020             wcols "%10.3f", $x,$y; # Formatted
1021             wcols "%10.3f %10.5g", $x,$y; # Individual column formatting
1022              
1023             $x = sequence(3); $y = zeros(3); $units = [ 'm/sec', 'kg', 'MPH' ];
1024             wcols $x,$y, { HEADER => "# x y" };
1025             wcols $x,$y, { Header => "# x y", Colsep => ', ' }; # case insensitive option names!
1026             wcols " %4.1f %4.1f %s",$x,$y,$units, { header => "# Day Time Units" };
1027              
1028             $a52 = sequence(5,2); $y = ones(5); $c = [ 1, 2, 4 ];
1029             wcols $a52; # now can write out 2D pdls (2 columns data in output)
1030             wcols $y, $a52, $c # ...and mix and match with 1D listrefs as well
1031              
1032             NOTES:
1033              
1034             1. Columns are separated by whitespace by default, use
1035             C<$PDL::IO::Misc::defcolsep> to modify the default value or
1036             the COLSEP option
1037              
1038             2. Support for the C<$PDL::IO::Misc::colsep> global value
1039             of PDL-2.4.6 and earlier is maintained but the initial value
1040             of the global is undef until you set it. The value will be
1041             then be picked up and used as if defcolsep were specified.
1042              
1043             3. Dim 0 corresponds to the column data dimension for both
1044             rcols and wcols. This makes wcols the reverse operation
1045             of rcols.
1046              
1047             =cut
1048              
1049             *wcols = \&PDL::wcols;
1050              
1051             sub PDL::wcols {
1052             barf 'Usage: wcols($optional_format_string, 1_or_2D_pdls, *HANDLE|"filename", [\%options])' if @_<1;
1053              
1054             # handle legacy colsep variable
1055             $usecolsep = (defined $colsep) ? $colsep : $defcolsep;
1056              
1057             # if last argument is a reference to a hash, parse the options
1058             my ($format_string, $step, $fh);
1059             my $header;
1060             if ( ref( $_[-1] ) eq "HASH" ) {
1061             my $opt = pop;
1062             foreach my $key ( sort keys %$opt ) {
1063             if ( $key =~ /^H/i ) { $header = $opt->{$key}; } # option: HEADER
1064             elsif ( $key =~ /^COLSEP/i ) { $usecolsep = $opt->{$key}; } # option: COLSEP
1065             elsif ( $key =~ /^FORMAT/i ) { $format_string = $opt->{$key}; } # option: FORMAT
1066             else {
1067             print "Warning: wcols does not understand option <$key>.\n";
1068             }
1069             }
1070             }
1071             if (ref(\$_[0]) eq "SCALAR" || $format_string) {
1072             $format_string = shift if (ref(\$_[0]) eq "SCALAR");
1073             # 1st arg not ndarray, explicit format string overrides option hash FORMAT
1074             $step = $format_string;
1075             $step =~ s/(%%|[^%])//g; # use step to count number of format items
1076             $step = length ($step);
1077             }
1078             my $file = $_[-1];
1079             my $file_opened;
1080             my $is_handle = !UNIVERSAL::isa($file,'PDL') &&
1081             !UNIVERSAL::isa($file,'ARRAY') &&
1082             _is_io_handle $file;
1083             if ($is_handle) { # file handle passed directly
1084             $fh = $file; pop;
1085             }
1086             else{
1087             if (ref(\$file) eq "SCALAR") { # Must be a file name
1088             $fh = gensym;
1089             if (!$is_handle) {
1090             $file = ">$file" unless $file =~ /^\|/ or $file =~ /^\>/;
1091             open $fh, $file or barf "File $file can not be opened for writing\n";
1092             }
1093             pop;
1094             $file_opened = 1;
1095             }
1096             else{ # Not a filehandle or filename, assume something else
1097             # (probably ndarray) and send to STDOUT
1098             $fh = *STDOUT;
1099             }
1100             }
1101              
1102             my @p = @_;
1103             my $n = (ref $p[0] eq 'ARRAY') ? $#{$p[0]}+1 : $p[0]->dim(0);
1104             my @dogp = (); # need to break 2D pdls into a their 1D pdl components
1105             for (@p) {
1106             if ( ref $_ eq 'ARRAY' ) {
1107             barf "wcols: 1D args must have same number of elements\n" if scalar(@{$_}) != $n;
1108             push @dogp, $_;
1109             } else {
1110             barf "wcols: 1D args must have same number of elements\n" if $_->dim(0) != $n or $_->getndims > 2;
1111             if ( $_->getndims == 2 ) {
1112             push @dogp, $_->dog;
1113             } else {
1114             push @dogp, $_;
1115             }
1116             }
1117             }
1118             if ( defined $header ) {
1119             $header .= "\n" unless $header =~ m/\n$/;
1120             print $fh $header;
1121             }
1122             my $i;
1123             my $pcnt = scalar @dogp;
1124             for ($i=0; $i<$n; $i++) {
1125             if ($format_string) {
1126             my @d;
1127             my $pdone = 0;
1128             for (@dogp) {
1129             push @d,_at_1D($_,$i); $pdone++;
1130             if (@d == $step) {
1131             printf $fh $format_string,@d;
1132             printf $fh $usecolsep unless $pdone==$pcnt;
1133             $#d = -1;
1134             }
1135             }
1136             if (@d && !$i) {
1137             my $str;
1138             if ($#dogp>0) {
1139             $str = ($#dogp+1).' columns don\'t';
1140             } else {
1141             $str = '1 column doesn\'t';
1142             }
1143             $str .= " fit in $step column format ".
1144             '(even repeated) -- discarding surplus';
1145             carp $str;
1146             # printf $fh $format_string,@d;
1147             # printf $fh $usecolsep;
1148             }
1149             } else {
1150             my $pdone = 0;
1151             for (@dogp) {
1152             $pdone++;
1153             print $fh _at_1D($_,$i) . ( ($pdone==$pcnt) ? '' : $usecolsep );
1154             }
1155             }
1156             print $fh "\n";
1157             }
1158             close($fh) if $file_opened;
1159             return 1;
1160             }
1161              
1162             =head2 swcols
1163              
1164             =for ref
1165              
1166             generate string list from C format specifier and a list of ndarrays
1167              
1168             C takes an (optional) format specifier of the printf
1169             sort and a list of 1D ndarrays as input. It returns a perl
1170             array (or array reference if called in scalar context)
1171             where each element of the array is the string generated by
1172             printing the corresponding element of the ndarray(s) using
1173             the format specified. If no format is specified it uses the
1174             default print format.
1175              
1176             =for usage
1177              
1178             Usage: @str = swcols format, pdl1,pdl2,pdl3,...;
1179             or $str = swcols format, pdl1,pdl2,pdl3,...;
1180              
1181             =cut
1182              
1183             *swcols = \&PDL::swcols;
1184              
1185             sub PDL::swcols{
1186             my ($format_string,$step);
1187              
1188             my @outlist;
1189              
1190             if (ref(\$_[0]) eq "SCALAR") {
1191             $step = $format_string = shift; # 1st arg not ndarray
1192             $step =~ s/(%%|[^%])//g; # use step to count number of format items
1193             $step = length ($step);
1194             }
1195              
1196             my @p = @_;
1197             my $n = (ref $p[0] eq 'ARRAY') ? $#{$p[0]}+1 : $p[0]->nelem;
1198             for (@p) {
1199             if ( ref $_ eq 'ARRAY' ) {
1200             barf "swcols: 1D args must have same number of elements\n" if scalar(@{$_}) != $n;
1201             } else {
1202             barf "swcols: 1D args must have same number of elements\n" if $_->nelem != $n or $_->getndims!=1;
1203             }
1204             }
1205              
1206             my $i;
1207             for ($i=0; $i<$n; $i++) {
1208             if ($format_string) {
1209             my @d;
1210             for (@p) {
1211             push @d,_at_1D($_,$i);
1212             if (@d == $step) {
1213             push @outlist,sprintf $format_string,@d;
1214             $#d = -1;
1215             }
1216             }
1217             if (@d && !$i) {
1218             my $str;
1219             if ($#p>0) {
1220             $str = ($#p+1).' columns don\'t';
1221             } else {
1222             $str = '1 column doesn\'t';
1223             }
1224             $str .= " fit in $step column format ".
1225             '(even repeated) -- discarding surplus';
1226             carp $str;
1227             # printf $fh $format_string,@d;
1228             # printf $fh $usecolsep;
1229             }
1230             } else {
1231             for (@p) {
1232             push @outlist,sprintf _at_1D($_,$i),$usecolsep;
1233             }
1234             }
1235             }
1236             wantarray ? return @outlist: return \@outlist;
1237             }
1238              
1239             =head2 rgrep
1240              
1241             =for ref
1242              
1243             Read columns into ndarrays using full regexp pattern matching.
1244              
1245             Options:
1246              
1247             =for options
1248              
1249             UNDEFINED: This option determines what will be done for undefined
1250             values. For instance when reading a comma-separated file of the type
1251             C<1,2,,4> where the C<,,> indicates a missing value.
1252             The default value is to assign C<$PDL::undefval> to undefined values,
1253             but if C is set this is used instead. This would normally
1254             be set to a number, but if it is set to C and PDL is compiled
1255             with Badvalue support (see L) then undefined values are set to
1256             the appropriate badvalue and the column is marked as bad.
1257             DEFTYPE: Sets the default type of the columns - see the documentation for
1258             L
1259             TYPES: A reference to a Perl array with types for each column - see
1260             the documentation for L
1261             BUFFERSIZE: The number of lines to extend the ndarray by. It might speed
1262             up the reading a little bit by setting this to the number of lines in the
1263             file, but in general L is a better choice
1264              
1265             Usage
1266              
1267             =for usage
1268              
1269             ($x,$y,...) = rgrep(sub, *HANDLE|"filename")
1270              
1271             e.g.
1272              
1273             =for example
1274              
1275             ($x,$y) = rgrep {/Foo (.*) Bar (.*) Mumble/} $file;
1276              
1277             i.e. the vectors C<$x> and C<$y> get the progressive values
1278             of C<$1>, C<$2> etc.
1279              
1280             =cut
1281              
1282             sub rgrep (&@) {
1283             barf 'Usage ($x,$y,...) = rgrep(sub, *HANDLE|"filename", [{OPTIONS}])'
1284             if $#_ > 2;
1285              
1286             my (@ret,@v,$nret); my ($m,$n)=(-1,0); # Count/PDL size
1287             my $pattern = shift;
1288              
1289             my $is_handle = _is_io_handle $_[0];
1290             my $fh = $is_handle ? $_[0] : gensym;
1291             open $fh, $_[0] or die "File $_[0] not found\n" unless $is_handle;
1292              
1293             if (ref($pattern) ne "CODE") {
1294             die "Got a ".ref($pattern)." for rgrep?!";
1295             }
1296              
1297             # set up default options
1298             my $opt = PDL::Options->new( {
1299             DEFTYPE => $deftype,
1300             TYPES => [],
1301             UNDEFINED => $PDL::undefval,
1302             BUFFERSIZE => 10000
1303             } );
1304             # Check if the user specified options
1305             my $u_opt = $_[1] || {};
1306             $opt->options( $u_opt);
1307              
1308             my $options = $opt->current();
1309              
1310             # If UNDEFINED is set to .*bad.* then undefined are set to
1311             # bad - unless we have a Perl that is not compiled with Bad support
1312             my $undef_is_bad = ($$options{UNDEFINED} =~ /bad/i);
1313             barf "Unknown PDL type given for DEFTYPE.\n"
1314             unless ref($$options{DEFTYPE}) eq "PDL::Type";
1315              
1316             while(<$fh>) {
1317             next unless @v = &$pattern;
1318              
1319             $m++; # Count got
1320             if ($m==0) {
1321             $nret = $#v; # Last index of values to return
1322              
1323             # Handle various columns as in rcols - added 18/04/05
1324             my @types = _handle_types( $nret, $$options{DEFTYPE}, $$options{TYPES} );
1325             for (0..$nret) {
1326             # Modified 18/04/05 to use specified precision.
1327             $ret[$_] = [ PDL->zeroes($types[$_], 1), [] ];
1328             }
1329             } else { # perhaps should only carp once...
1330             carp "Non-rectangular rgrep" if $nret != $#v;
1331             }
1332             if ($n<$m) {
1333             for (0..$nret) {
1334             _ext_lastD( $ret[$_]->[0], $$options{BUFFERSIZE} ); # Extend PDL in buffered manner
1335             }
1336             $n += $$options{BUFFERSIZE};
1337             }
1338             for(0..$nret) {
1339             # Set values - '1*' is to ensure numeric
1340             # We now (JB - 18/04/05) also check for defined values or not
1341             # Ideally this should include Badvalue support..
1342             if ($v[$_] eq '') {
1343             # Missing value - let us treat this specially
1344             if ($undef_is_bad) {
1345             set $ret[$_]->[0], $m, $$options{DEFTYPE}->badvalue();
1346             # And set bad flag on $ref[$_]!
1347             $ret[$_]->[0]->badflag(1);
1348             } else {
1349             set $ret[$_]->[0], $m, $$options{UNDEFINED};
1350             }
1351             } else {
1352             set $ret[$_]->[0], $m, 1*$v[$_];
1353             }
1354             }
1355             }
1356              
1357             close($fh) unless $is_handle;
1358             for (@ret) { $_ = $_->[0]->slice("0:$m")->copy; }; # Truncate
1359             wantarray ? return(@ret) : return $ret[0];
1360             }
1361              
1362             =head2 isbigendian
1363              
1364             =for ref
1365              
1366             Determine endianness of machine - returns 0 or 1 accordingly
1367              
1368             =cut
1369              
1370             #line 1138 "lib/PDL/IO/Misc.pd"
1371             sub PDL::isbigendian { return 0; };
1372             *isbigendian = \&PDL::isbigendian;
1373              
1374             #line 1144 "lib/PDL/IO/Misc.pd"
1375              
1376             =head2 rcube
1377              
1378             =for ref
1379              
1380             Read list of files directly into a large data cube (for efficiency)
1381              
1382             =for usage
1383              
1384             $cube = rcube \&reader_function, @files;
1385              
1386             =for example
1387              
1388             $cube = rcube \&rfits, glob("*.fits");
1389              
1390             This IO function allows direct reading of files into a large data cube,
1391             Obviously one could use cat() but this is more memory efficient.
1392              
1393             The reading function (e.g. rfits, readfraw) (passed as a reference)
1394             and files are the arguments.
1395              
1396             The cube is created as the same X,Y dims and datatype as the first
1397             image specified. The Z dim is simply the number of images.
1398              
1399             =cut
1400              
1401             sub rcube {
1402              
1403             my $reader = shift;
1404              
1405             barf "Usage: blah" unless ref($reader) eq "CODE";
1406              
1407             my $k=0;
1408             my ($im,$cube,$nx,$ny);
1409             my $nz = scalar(@_);
1410              
1411             for my $file (@_) {
1412             print "Slice ($k) - reading file $file...\n" if $PDL::verbose;
1413             $im = &$reader($file);
1414             ($nx, $ny) = dims $im;
1415             if ($k == 0) {
1416             print "Creating $nx x $ny x $nz cube...\n" if $PDL::verbose;
1417             $cube = $im->zeroes($im->type,$nx,$ny,$nz);
1418             }
1419             else {
1420             barf "Dimensions do not match for file $file!\n" if
1421             $im->getdim(0) != $nx or $im->getdim(1) != $ny ;
1422              
1423             }
1424             $cube->slice(":,:,($k)") .= $im;
1425             $k++;
1426             }
1427              
1428             return $cube;
1429             }
1430             #line 1431 "lib/PDL/IO/Misc.pm"
1431              
1432              
1433             =head2 rasc
1434              
1435             =for sig
1436              
1437             Signature: ([o] nums(n); int [o] ierr(n); PerlIO *fp; IV num => n)
1438             Types: (float double)
1439              
1440             =for ref
1441              
1442             Simple function to slurp in ASCII numbers quite quickly,
1443             although error handling is marginal (to nonexistent).
1444              
1445             =for usage
1446              
1447             $pdl->rasc("filename"|FILEHANDLE [,$noElements]);
1448              
1449             Where:
1450             filename is the name of the ASCII file to read or open file handle
1451             $noElements is the optional number of elements in the file to read.
1452             (If not present, all of the file will be read to fill up $pdl).
1453             $pdl can be of type float or double (for more precision).
1454              
1455             =for example
1456              
1457             # (test.num is an ascii file with 20 numbers. One number per line.)
1458             $in = PDL->null;
1459             $num = 20;
1460             $in->rasc('test.num',20);
1461             $imm = zeroes(float,20,2);
1462             $imm->rasc('test.num');
1463              
1464             =pod
1465              
1466             Broadcasts over its inputs.
1467              
1468             =for bad
1469              
1470             C does not process bad values.
1471             It will set the bad-value flag of all output ndarrays if the flag is set for any of the input ndarrays.
1472              
1473             =cut
1474              
1475              
1476              
1477              
1478 0     0 1 0 sub rasc {PDL->rasc(@_)}
1479             sub PDL::rasc {
1480 3     3 0 21 my ($pdl, $file, $num) = @_;
1481 3 100       9 $num = -1 unless defined $num;
1482 3         16 my $is_openhandle = defined fileno $file;
1483 3         4 my $fi;
1484 3 50       7 if ($is_openhandle) {
1485 0         0 $fi = $file;
1486             } else {
1487 3 50 33     13 barf 'usage: rasc $pdl, "filename"|FILEHANDLE, [$num_to_read]'
1488             if !defined $file || ref $file;
1489 3 100       159 open $fi, "<", $file or barf "Can't open $file";
1490             }
1491 2         7 $pdl->_rasc_int(my $ierr=null,$fi,$num);
1492 2 50       23 close $fi unless $is_openhandle;
1493 2         9 return all $ierr > 0;
1494             }
1495              
1496              
1497              
1498              
1499              
1500              
1501              
1502              
1503              
1504              
1505             #line 27 "lib/PDL/IO/Misc.pd"
1506              
1507             =head1 AUTHOR
1508              
1509             Copyright (C) Karl Glazebrook 1997, Craig DeForest 2001,
1510             2003, and Chris Marshall 2010. All rights reserved. There is
1511             no warranty. You are allowed to redistribute this software
1512             / documentation under certain conditions. For details, see
1513             the file COPYING in the PDL distribution. If this file is
1514             separated from the PDL distribution, the copyright notice
1515             should be included in the file.
1516              
1517             =cut
1518             #line 1519 "lib/PDL/IO/Misc.pm"
1519              
1520             # Exit with OK status
1521              
1522             1;