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