1. my class IO::ArgFiles is IO::Handle {
  2. has $.args;
  3. has $.filename;
  4. has $!io;
  5. has Int $.ins = 0;
  6. has $!nl-in = ["\x0A", "\r\n"];
  7. has $!has-args;
  8. # returns True only if at the end of all input files
  9. method eof() {
  10. # make sure $!has-args is in the proper state since !next-io() may not have been called
  11. $!has-args = ?$!args unless $!has-args.defined;
  12. if $!has-args {
  13. # if there are files left it can't be the end
  14. if $!args {
  15. False
  16. }
  17. # $!io might be opened to the last file so ask it
  18. elsif $!io.defined && $!io.opened {
  19. $!io.eof
  20. }
  21. # $!args must have been exhausted
  22. else {
  23. True
  24. }
  25. }
  26. # TODO should probably get the STDIN filehandle the same way as !next-io()
  27. elsif $*IN.opened {
  28. # ask $*IN because there was no args
  29. $*IN.eof
  30. }
  31. else {
  32. # there is no input available
  33. True
  34. }
  35. }
  36. method !next-io($close) {
  37. $!io.close if $close;
  38. unless $!has-args.defined {
  39. $!has-args = ?$!args;
  40. }
  41. unless $!io.defined && $!io.opened {
  42. if $!has-args {
  43. return Nil unless $!args;
  44. $!filename = $!args.shift;
  45. } else {
  46. $!filename = '-';
  47. }
  48. $!io = open($!filename, :r, :$!nl-in) ||
  49. fail "Unable to open file '$!filename'";
  50. }
  51. return Nil unless $!io.defined and $!io.opened;
  52. $!io;
  53. }
  54. method get() {
  55. unless $!io.defined and $!io.opened {
  56. (return $_ unless .defined) given self!next-io(False);
  57. }
  58. my $line;
  59. repeat {
  60. $line = $!io.get;
  61. unless $line.defined {
  62. $!io.close;
  63. $!io = IO::Handle;
  64. (return $_ unless .defined) given self!next-io(True);
  65. }
  66. } until $line.defined;
  67. $!ins++;
  68. $line;
  69. }
  70. proto method lines(|) {*}
  71. multi method lines() {
  72. Seq.new(class :: does Iterator {
  73. has $!args;
  74. has $!iter;
  75. has $!next-io;
  76. has Int $!ins;
  77. method new(\args, \ins, \next-io) {
  78. my \iter = nqp::create(self);
  79. nqp::bindattr(iter, self, '$!args', args);
  80. nqp::bindattr(iter, self, '$!ins', ins);
  81. nqp::bindattr(iter, self, '$!next-io', next-io);
  82. my $io = next-io.(False);
  83. if $io.defined {
  84. nqp::bindattr(iter, self, '$!iter', $io.iterator);
  85. }
  86. else {
  87. return $io if nqp::istype($io, Failure);
  88. }
  89. iter
  90. }
  91. method pull-one() {
  92. nqp::stmts(
  93. (nqp::unless(nqp::defined($!iter), return IterationEnd)),
  94. (my \value = $!iter.pull-one),
  95. nqp::if(nqp::eqaddr(value, IterationEnd),
  96. nqp::stmts(
  97. (my $io = $!next-io.(True)),
  98. nqp::if(nqp::istype($io, Failure), return $io),
  99. nqp::unless(nqp::defined($io), return IterationEnd),
  100. ($!iter := $io.iterator),
  101. self.pull-one),
  102. nqp::stmts(
  103. ($!ins = nqp::add_I(nqp::decont($!ins), 1, Int)),
  104. value)))
  105. }
  106. }.new(self, $!ins, -> $close { self!next-io($close) }));
  107. }
  108. multi method lines($limit) {
  109. nqp::istype($limit,Whatever) || $limit == Inf
  110. ?? self.lines
  111. !! self.lines[ lazy 0 .. $limit.Int - 1 ]
  112. }
  113. method slurp(IO::ArgFiles:D: |c) {
  114. # NOTE: $.filename and $.ins will be incorrect after this is called
  115. # make sure $!has-args is in the proper state since !next-io() may not have been called
  116. $!has-args = ?$!args unless $!has-args.defined;
  117. # TODO should probably get the STDIN filehandle the same way as !next-io()
  118. return $*IN.slurp-rest(|c) unless $!has-args;
  119. my @chunks;
  120. if $!io.defined && $!io.opened {
  121. @chunks.push: $!io.slurp-rest(:close, |c);
  122. }
  123. while $!args {
  124. @chunks.push: slurp $!args.shift, |c;
  125. }
  126. # TODO Should this be a failure?
  127. return Nil unless @chunks;
  128. [~] @chunks;
  129. }
  130. method nl-in is rw {
  131. Proxy.new(
  132. FETCH => {
  133. $!nl-in
  134. },
  135. STORE => -> $, $nl-in {
  136. if $!io.defined {
  137. Rakudo::Internals.SET_LINE_ENDING_ON_HANDLE($!io, $nl-in);
  138. }
  139. $!nl-in = $nl-in;
  140. }
  141. );
  142. }
  143. }