1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
#!/usr/bin/perl -s
use v5.16;
use Test2::V0;
use warnings FATAL => 'all';
use experimental 'signatures';
our ($tests, $examples);
run_tests() if $tests || $examples; # does not return
die <<EOS unless @ARGV > 1;
usage: $0 [-examples] [-tests] [file1 c11... fileN cN1...]
-examples
run examples from the challenge
-tests
run some tests
fileX (not numeric)
select file for following read operation(s)
cij (numeric)
number of characters to read from selected file
Operations on different files may be interleaved. The file position is
kept separately for each filename.
Example:
ch-1_A.txt: 1234567890
ch-1_B.txt: abcdefghij
./ch-1.pl ch-1_A.txt 4 3 ch-1_B.txt 1 2 ch-1_A.txt 2 1 ch-1_B.txt 3 4
Output:
1234
567
a
bc
89
0
def
ghij
EOS
### Input and Output
binmode STDOUT, ':utf8';
/^\d+$/ and say readN($a, $_) or $a = $_ for @ARGV;
### Implementation
# Read up to $n characters from named file at current position. Will
# start over from the beginning after eof was detected for the named
# file.
sub readN ($file, $n) {
# Track filehandles for named files.
state %fh;
# Open filehandle for reading characters, not bytes.
open $fh{$file}, '<:encoding(utf8)', $file or die "$file: $!"
unless $fh{$file};
my $nchar = read $fh{$file}, (my $read), $n;
die "$file: $!" unless defined $nchar;
# Close filehandle if eof was detected.
delete $fh{$file} if $nchar < $n;
$read;
}
### Examples and tests
sub run_tests {
SKIP: {
skip 'examples' unless $examples;
is readN('ch-1_A.txt', 4), '1234', 'example: first chunk';
is readN('ch-1_A.txt', 4), '5678', 'example: second chunk';
is readN('ch-1_A.txt', 4), '90', 'example: third chunk';
}
SKIP: {
skip 'tests' unless $tests;
is readN('ch-1_A.txt', 10), '1234567890', 'read all';
is readN('ch-1_A.txt', 1), '', 'at eof';
is readN('ch-1_A.txt', 1), '1', 'file reopened';
ok readN('ch-1_A.txt', 10), 'seek eof';
is readN('ch-1_A.txt', 11), '1234567890', 'read all, hit eof';
is readN('ch-1_A.txt', 1), '1', 'file reopened';
is readN('ch-1_C.txt', 3), 'Bär', 'multibyte character';
}
done_testing;
exit;
}
|