1. my class IO::Path { ... }
  2. my class IO::Special { ... }
  3. my class Proc { ... }
  4. my class IO::Handle does IO {
  5. has $.path;
  6. has $!PIO;
  7. has $.chomp is rw = Bool::True;
  8. has $.nl-in = ["\x0A", "\r\n"];
  9. has Str:D $.nl-out is rw = "\n";
  10. has str $!encoding = 'utf8';
  11. method open(IO::Handle:D:
  12. :$r, :$w, :$x, :$a, :$update,
  13. :$rw, :$rx, :$ra,
  14. :$mode is copy,
  15. :$create is copy,
  16. :$append is copy,
  17. :$truncate is copy,
  18. :$exclusive is copy,
  19. :$bin,
  20. :$chomp = True,
  21. :$enc = 'utf8',
  22. :$nl-in is copy = ["\x0A", "\r\n"],
  23. Str:D :$nl-out is copy = "\n",
  24. ) {
  25. $mode = nqp::if(
  26. $mode,
  27. nqp::if(nqp::istype($mode, Str), $mode, $mode.Str),
  28. nqp::if(
  29. nqp::unless(nqp::if($r, $w), $rw), # $r && $w || $rw
  30. nqp::stmts(($create = True), 'rw'),
  31. nqp::if(
  32. nqp::unless(nqp::if($r, $x), $rx),
  33. nqp::stmts(($create = $exclusive = True), 'rw'),
  34. nqp::if(
  35. nqp::unless(nqp::if($r, $a), $ra),
  36. nqp::stmts(($create = $append = True), 'rw'),
  37. nqp::if(
  38. $r, 'ro',
  39. nqp::if(
  40. $w,
  41. nqp::stmts(($create = $truncate = True), 'wo'),
  42. nqp::if(
  43. $x,
  44. nqp::stmts(($create = $exclusive = True), 'wo'),
  45. nqp::if(
  46. $a,
  47. nqp::stmts(($create = $append = True), 'wo'),
  48. nqp::if(
  49. $update, 'rw',
  50. 'ro'
  51. ),
  52. ),
  53. ),
  54. ),
  55. ),
  56. ),
  57. ),
  58. ),
  59. );
  60. nqp::if(
  61. nqp::iseq_s($!path.Str, '-'),
  62. nqp::stmts(
  63. nqp::if(
  64. nqp::iseq_s($mode, 'ro'),
  65. (return $*IN),
  66. nqp::if(
  67. nqp::iseq_s($mode, 'wo'),
  68. (return $*OUT),
  69. die("Cannot open standard stream in mode '$mode'"),
  70. ),
  71. ),
  72. ),
  73. );
  74. if nqp::istype($!path, IO::Special) {
  75. my $what := $!path.what;
  76. if $what eq '<STDIN>' {
  77. $!PIO := nqp::getstdin();
  78. }
  79. elsif $what eq '<STDOUT>' {
  80. $!PIO := nqp::getstdout();
  81. }
  82. elsif $what eq '<STDERR>' {
  83. $!PIO := nqp::getstderr();
  84. }
  85. else {
  86. die "Don't know how to open '$_' especially";
  87. }
  88. $!chomp = $chomp;
  89. $!nl-out = $nl-out;
  90. Rakudo::Internals.SET_LINE_ENDING_ON_HANDLE($!PIO, $!nl-in = $nl-in);
  91. nqp::if( $bin,
  92. ($!encoding = 'bin'),
  93. nqp::setencoding($!PIO,
  94. $!encoding = Rakudo::Internals.NORMALIZE_ENCODING($enc),
  95. )
  96. );
  97. return self;
  98. }
  99. fail X::IO::Directory.new(:$!path, :trying<open>) if $!path.d;
  100. {
  101. CATCH { .fail }
  102. $!PIO := nqp::open(
  103. $!path.abspath,
  104. nqp::concat(
  105. nqp::if(
  106. nqp::iseq_s($mode, 'ro'), 'r',
  107. nqp::if(
  108. nqp::iseq_s($mode, 'wo'), '-',
  109. nqp::if(
  110. nqp::iseq_s($mode, 'rw'), '+',
  111. die("Unknown mode '$mode'")
  112. ),
  113. ),
  114. ),
  115. nqp::concat(
  116. nqp::if($create, 'c', ''),
  117. nqp::concat(
  118. nqp::if($append, 'a', ''),
  119. nqp::concat(
  120. nqp::if($truncate, 't', ''),
  121. nqp::if($exclusive, 'x', ''),
  122. ),
  123. ),
  124. )
  125. ),
  126. );
  127. }
  128. $!chomp = $chomp;
  129. $!nl-out = $nl-out;
  130. Rakudo::Internals.SET_LINE_ENDING_ON_HANDLE($!PIO, $!nl-in = $nl-in);
  131. nqp::if( $bin,
  132. ($!encoding = 'bin'),
  133. nqp::setencoding($!PIO,
  134. $!encoding = Rakudo::Internals.NORMALIZE_ENCODING($enc),
  135. )
  136. );
  137. self;
  138. }
  139. method nl-in is rw {
  140. Proxy.new(
  141. FETCH => {
  142. $!nl-in
  143. },
  144. STORE => -> $, $nl-in {
  145. Rakudo::Internals.SET_LINE_ENDING_ON_HANDLE($!PIO, $!nl-in = $nl-in);
  146. }
  147. );
  148. }
  149. method close(IO::Handle:D: --> True) {
  150. # TODO: catch errors
  151. nqp::closefh($!PIO) if nqp::defined($!PIO);
  152. $!PIO := nqp::null;
  153. }
  154. method eof(IO::Handle:D:) {
  155. nqp::p6bool(nqp::eoffh($!PIO));
  156. }
  157. method get(IO::Handle:D:) {
  158. nqp::if(
  159. $!chomp,
  160. nqp::if(
  161. nqp::chars(my str $str = nqp::readlinechompfh($!PIO))
  162. # loses last empty line because EOF is set too early, RT #126598
  163. || nqp::not_i(nqp::eoffh($!PIO)),
  164. $str,
  165. Nil
  166. ),
  167. # not chomping, no need to check EOF
  168. nqp::if(nqp::chars($str = nqp::readlinefh($!PIO)),$str,Nil)
  169. )
  170. }
  171. method getc(IO::Handle:D:) {
  172. nqp::if(nqp::chars(my str $c = nqp::getcfh($!PIO)),$c,Nil)
  173. }
  174. proto method comb(|) { * }
  175. multi method comb(IO::Handle:D: :$close = False) {
  176. self.split(:$close,:COMB)
  177. }
  178. multi method comb(IO::Handle:D: Int:D $size, :$close = False) {
  179. return self.split(:$close,:COMB) if $size <= 1;
  180. Seq.new(class :: does Iterator {
  181. has Mu $!handle;
  182. has int $!size;
  183. has int $!close;
  184. method !SET-SELF(\handle, \size, \close) {
  185. $!handle := handle;
  186. $!size = size.Int;
  187. $!close = close;
  188. self
  189. }
  190. method new(\handle, \size, \close) {
  191. nqp::create(self)!SET-SELF(handle, size, close);
  192. }
  193. method pull-one() {
  194. nqp::if(
  195. nqp::chars(my str $str = $!handle.readchars($!size)),
  196. nqp::p6box_s($str),
  197. nqp::stmts(
  198. nqp::if(
  199. $!close,
  200. $!handle.close
  201. ),
  202. IterationEnd
  203. )
  204. )
  205. }
  206. method push-all($target --> IterationEnd) {
  207. my str $str = $!handle.readchars($!size);
  208. nqp::while(
  209. nqp::iseq_i(nqp::chars($str),$!size),
  210. nqp::stmts(
  211. $target.push(nqp::p6box_s($str)),
  212. ($str = $!handle.readchars($!size))
  213. )
  214. );
  215. $target.push(nqp::p6box_s($str)) if nqp::chars($str);
  216. $!handle.close if $!close;
  217. }
  218. }.new(self, $size, +$close));
  219. }
  220. multi method comb(IO::Handle:D: $comber, :$close = False) {
  221. return self.split(:$close,:COMB)
  222. if nqp::istype($comber,Cool) && $comber.Str.chars == 0;
  223. Seq.new(class :: does Iterator {
  224. has Mu $!handle;
  225. has Mu $!regex;
  226. has str $!comber;
  227. has int $!close;
  228. has str $!str;
  229. has str $!left;
  230. has Mu $!strings;
  231. has int $!elems;
  232. has int $!done;
  233. method !SET-SELF(\handle, \comber, \close) {
  234. $!handle := handle;
  235. nqp::istype(comber,Regex)
  236. ?? ($!regex := comber)
  237. !! ($!comber = nqp::unbox_s(comber.Str));
  238. $!close = close;
  239. $!left = '';
  240. self!next-chunk until $!elems || $!done;
  241. self
  242. }
  243. method new(\handle, \comber, \close) {
  244. nqp::create(self)!SET-SELF(handle, comber, close);
  245. }
  246. method !next-chunk(--> Nil) {
  247. my int $chars = nqp::chars($!left);
  248. $!str = nqp::concat($!left,$!handle.readchars);
  249. if nqp::chars($!str) == $chars { # nothing read anymore
  250. $!done = 1;
  251. }
  252. else {
  253. $!strings := nqp::list_s;
  254. with $!regex {
  255. my \matches = $!str.match($!regex, :g);
  256. $!elems = matches.elems;
  257. nqp::setelems($!strings,$!elems);
  258. my int $i;
  259. my int $from;
  260. my int $to;
  261. my Mu $match;
  262. while $i < $!elems {
  263. $match := matches[$i];
  264. $from = $match.from;
  265. $to = $match.to;
  266. nqp::bindpos_s($!strings,$i,
  267. nqp::substr($!str,$from,$to - $from));
  268. $i = $i + 1;
  269. }
  270. $!left = nqp::substr($!str,$to);
  271. }
  272. else {
  273. my int $pos;
  274. my int $found;
  275. my int $extra = nqp::chars($!comber);
  276. while ($found = nqp::index($!str,$!comber,$pos)) >= 0 {
  277. nqp::push_s($!strings,$!comber);
  278. $pos = $found + $extra;
  279. }
  280. $!left = nqp::substr($!str,$pos);
  281. $!elems = nqp::elems($!strings);
  282. }
  283. }
  284. }
  285. method pull-one() {
  286. if $!elems {
  287. $!elems = $!elems - 1;
  288. nqp::p6box_s(nqp::shift_s($!strings));
  289. }
  290. else {
  291. self!next-chunk until $!elems || $!done;
  292. if $!elems {
  293. $!elems = $!elems - 1;
  294. nqp::p6box_s(nqp::shift_s($!strings));
  295. }
  296. else {
  297. $!handle.close if $!close;
  298. IterationEnd;
  299. }
  300. }
  301. }
  302. method push-all($target --> IterationEnd) {
  303. while $!elems {
  304. while $!elems {
  305. $target.push(nqp::p6box_s(nqp::shift_s($!strings)));
  306. $!elems = $!elems - 1;
  307. }
  308. self!next-chunk until $!elems || $!done;
  309. }
  310. $!handle.close if $!close;
  311. }
  312. }.new(self, $comber, +$close));
  313. }
  314. multi method split(IO::Handle:D: :$close = False, :$COMB) {
  315. Seq.new(class :: does Iterator {
  316. has Mu $!handle;
  317. has int $!close;
  318. has int $!COMB;
  319. has str $!str;
  320. has int $!first;
  321. has int $!last;
  322. has int $index;
  323. has int $chars;
  324. method !SET-SELF(\handle, \close, \COMB) {
  325. $!handle := handle;
  326. $!close = close;
  327. $!COMB = ?COMB;
  328. self!next-chunk();
  329. $!first = $!last = 1 if $!chars && !$!COMB;
  330. self
  331. }
  332. method new(\handle, \close, \COMB) {
  333. nqp::create(self)!SET-SELF(handle, close, COMB);
  334. }
  335. method !next-chunk(--> Nil) {
  336. $!str = $!handle.readchars;
  337. $!index = 0;
  338. $!chars = nqp::chars($!str);
  339. }
  340. method pull-one() {
  341. self!next-chunk if !$!index == $!chars;
  342. if $!first {
  343. $!first = 0;
  344. ''
  345. }
  346. elsif $!index < $!chars {
  347. nqp::p6box_s(nqp::substr($!str,$!index++,1))
  348. }
  349. elsif $!last {
  350. $!last = 0;
  351. ''
  352. }
  353. else {
  354. $!handle.close if $!close;
  355. IterationEnd;
  356. }
  357. }
  358. method push-all($target --> IterationEnd) {
  359. $target.push('') if $!first;
  360. while $!index < $!chars {
  361. $target.push(
  362. nqp::p6box_s(nqp::substr($!str,$!index++,1)))
  363. while $!index < $!chars;
  364. self!next-chunk();
  365. }
  366. $target.push('') if $!last;
  367. $!handle.close if $!close;
  368. }
  369. }.new(self, +$close, $COMB));
  370. }
  371. multi method split(IO::Handle:D: $splitter, :$close = False, :$COMB) {
  372. return self.split(:$close,:$COMB)
  373. if nqp::istype($splitter,Cool) && $splitter.Str.chars == 0;
  374. Seq.new(class :: does Iterator {
  375. has Mu $!handle;
  376. has Mu $!regex;
  377. has str $!splitter;
  378. has int $!close;
  379. has str $!str;
  380. has str $!left;
  381. has Mu $!strings;
  382. has int $!elems;
  383. has int $!done;
  384. method !SET-SELF(\handle, \splitter, \close) {
  385. $!handle := handle;
  386. nqp::istype(splitter,Regex)
  387. ?? ($!regex := splitter)
  388. !! ($!splitter = nqp::unbox_s(splitter.Str));
  389. $!close = close;
  390. $!left = '';
  391. self!next-chunk until $!elems || $!done;
  392. self
  393. }
  394. method new(\handle, \splitter, \close) {
  395. nqp::create(self)!SET-SELF(handle, splitter, close);
  396. }
  397. method !next-chunk(--> Nil) {
  398. my int $chars = nqp::chars($!left);
  399. $!str = nqp::concat($!left,$!handle.readchars);
  400. if nqp::chars($!str) == $chars { # nothing read anymore
  401. $!done = 2;
  402. }
  403. else {
  404. with $!regex {
  405. my \matches = $!str.match($!regex, :g);
  406. my int $elems = matches.elems;
  407. my Mu $strings := nqp::list();
  408. nqp::setelems($strings,$elems);
  409. my int $i;
  410. my Mu $match;
  411. my int $from;
  412. while $i < $elems {
  413. $match := matches[$i];
  414. nqp::bindpos($strings,$i,
  415. nqp::substr($!str,$from,$match.from - $from));
  416. $from = $match.to;
  417. $i = $i + 1;
  418. }
  419. $!left = nqp::substr(
  420. $!str,$from,nqp::chars($!str) - $from);
  421. $!strings := $strings; # lexical natives faster
  422. }
  423. else {
  424. $!strings := nqp::split($!splitter,$!str);
  425. $!left =
  426. nqp::elems($!strings) ?? nqp::pop($!strings) !! '';
  427. }
  428. $!elems = nqp::elems($!strings);
  429. }
  430. }
  431. method pull-one() {
  432. if $!elems {
  433. $!elems = $!elems - 1;
  434. nqp::p6box_s(nqp::shift($!strings));
  435. }
  436. else {
  437. self!next-chunk until $!elems || $!done;
  438. if $!elems {
  439. $!elems = $!elems - 1;
  440. nqp::p6box_s(nqp::shift($!strings));
  441. }
  442. elsif $!done == 2 {
  443. $!done = 1;
  444. nqp::p6box_s($!str);
  445. }
  446. else {
  447. $!handle.close if $!close;
  448. IterationEnd;
  449. }
  450. }
  451. }
  452. method push-all($target --> IterationEnd) {
  453. while $!elems {
  454. while $!elems {
  455. $target.push(nqp::p6box_s(nqp::shift($!strings)));
  456. $!elems = $!elems - 1;
  457. }
  458. self!next-chunk until $!elems || $!done;
  459. }
  460. $target.push(nqp::p6box_s($!str));
  461. $!handle.close if $!close;
  462. }
  463. }.new(self, $splitter, +$close));
  464. }
  465. proto method words (|) { * }
  466. multi method words(IO::Handle:D: :$close) {
  467. Seq.new(class :: does Iterator {
  468. has $!handle;
  469. has $!close;
  470. has str $!str;
  471. has int $!pos;
  472. has int $!searching;
  473. method !SET-SELF(\handle, $!close) {
  474. $!handle := handle;
  475. $!searching = 1;
  476. $!str = ""; # RT #126492
  477. self!next-chunk;
  478. self
  479. }
  480. method new(\handle, \close) {
  481. nqp::create(self)!SET-SELF(handle, close);
  482. }
  483. method !next-chunk() {
  484. my int $chars = nqp::chars($!str);
  485. $!str = $!pos < $chars ?? nqp::substr($!str,$!pos) !! "";
  486. $chars = nqp::chars($!str);
  487. while $!searching {
  488. $!str = nqp::concat($!str,$!handle.readchars);
  489. my int $new = nqp::chars($!str);
  490. $!searching = 0 if $new == $chars; # end
  491. $!pos = ($chars = $new)
  492. ?? nqp::findnotcclass(
  493. nqp::const::CCLASS_WHITESPACE, $!str, 0, $chars)
  494. !! 0;
  495. last if $!pos < $chars;
  496. }
  497. }
  498. method pull-one() {
  499. my int $chars;
  500. my int $left;
  501. my int $nextpos;
  502. while ($chars = nqp::chars($!str)) && $!searching {
  503. while ($left = $chars - $!pos) > 0 {
  504. $nextpos = nqp::findcclass(
  505. nqp::const::CCLASS_WHITESPACE,$!str,$!pos,$left);
  506. last unless $left = $chars - $nextpos; # broken word
  507. my str $found =
  508. nqp::substr($!str, $!pos, $nextpos - $!pos);
  509. $!pos = nqp::findnotcclass(
  510. nqp::const::CCLASS_WHITESPACE,$!str,$nextpos,$left);
  511. return nqp::p6box_s($found);
  512. }
  513. self!next-chunk;
  514. }
  515. if $!pos < $chars {
  516. my str $found = nqp::substr($!str,$!pos);
  517. $!pos = $chars;
  518. nqp::p6box_s($found)
  519. }
  520. else {
  521. $!handle.close if $!close;
  522. IterationEnd
  523. }
  524. }
  525. method push-all($target --> IterationEnd) {
  526. my int $chars;
  527. my int $left;
  528. my int $nextpos;
  529. while ($chars = nqp::chars($!str)) && $!searching {
  530. while ($left = $chars - $!pos) > 0 {
  531. $nextpos = nqp::findcclass(
  532. nqp::const::CCLASS_WHITESPACE,$!str,$!pos,$left);
  533. last unless $left = $chars - $nextpos; # broken word
  534. $target.push(nqp::p6box_s(
  535. nqp::substr($!str, $!pos, $nextpos - $!pos)
  536. ));
  537. $!pos = nqp::findnotcclass(
  538. nqp::const::CCLASS_WHITESPACE,$!str,$nextpos,$left);
  539. }
  540. self!next-chunk;
  541. }
  542. $target.push(nqp::p6box_s(nqp::substr($!str,$!pos)))
  543. if $!pos < $chars;
  544. $!handle.close if $close;
  545. }
  546. }.new(self, $close));
  547. }
  548. my role PIOIterator does Iterator {
  549. has $!PIO;
  550. method new(\handle) {
  551. nqp::p6bindattrinvres(
  552. nqp::create(self),self.WHAT,'$!PIO',
  553. nqp::getattr(handle,IO::Handle,'$!PIO')
  554. )
  555. }
  556. method sink-all(--> IterationEnd) {
  557. nqp::seekfh($!PIO,0,2) # seek to end
  558. }
  559. }
  560. multi method iterator(IO::Handle:D:) {
  561. nqp::if(
  562. nqp::eqaddr(self.WHAT,IO::Handle),
  563. nqp::if(
  564. $!chomp,
  565. class :: does PIOIterator { # shortcircuit .get, chomping
  566. method pull-one() {
  567. nqp::if(
  568. nqp::chars(my str $line = nqp::readlinechompfh($!PIO))
  569. # loses last empty line because EOF is set too early
  570. # RT #126598
  571. || nqp::not_i(nqp::eoffh($!PIO)),
  572. $line,
  573. IterationEnd
  574. )
  575. }
  576. method push-all($target --> IterationEnd) {
  577. nqp::while(
  578. nqp::chars(my str $line = nqp::readlinechompfh($!PIO))
  579. # loses last empty line because EOF is set too early
  580. # RT #126598
  581. || nqp::not_i(nqp::eoffh($!PIO)),
  582. $target.push(nqp::p6box_s($line))
  583. )
  584. }
  585. },
  586. class :: does PIOIterator { # shortcircuit .get, *NOT* chomping
  587. method pull-one() {
  588. nqp::if(
  589. # not chomping, no need to check EOF
  590. nqp::chars(my str $line = nqp::readlinefh($!PIO)),
  591. $line,
  592. IterationEnd
  593. )
  594. }
  595. method push-all($target --> IterationEnd) {
  596. nqp::while(
  597. # not chomping, no need to check EOF
  598. nqp::chars(my str $line = nqp::readlinefh($!PIO)),
  599. $target.push(nqp::p6box_s($line))
  600. )
  601. }
  602. }
  603. ),
  604. class :: does Iterator { # can *NOT* shortcircuit .get
  605. has $!handle;
  606. method new(\handle) {
  607. nqp::p6bindattrinvres(
  608. nqp::create(self),self.WHAT,'$!handle',handle)
  609. }
  610. method pull-one() {
  611. nqp::if(
  612. (my $line := $!handle.get).DEFINITE,
  613. $line,
  614. IterationEnd
  615. )
  616. }
  617. method push-all($target --> IterationEnd) {
  618. nqp::while(
  619. (my $line := $!handle.get).DEFINITE,
  620. $target.push($line)
  621. )
  622. }
  623. method sink-all(--> IterationEnd) {
  624. # can't seek pipes, so need the `try`
  625. try $!handle.seek(0,SeekFromEnd) # seek to end
  626. }
  627. }
  628. ).new(self)
  629. }
  630. proto method lines (|) { * }
  631. multi method lines(IO::Handle:D: $limit) {
  632. # we should probably deprecate this feature
  633. nqp::istype($limit,Whatever) || $limit == Inf
  634. ?? self.lines
  635. !! self.lines.head($limit.Int)
  636. }
  637. multi method lines(IO::Handle:D:) { Seq.new(self.iterator) }
  638. method read(IO::Handle:D: Int(Cool:D) $bytes) {
  639. nqp::readfh($!PIO,buf8.new,nqp::unbox_i($bytes))
  640. }
  641. method readchars(Int(Cool:D) $chars = $*DEFAULT-READ-ELEMS) {
  642. nqp::readcharsfh($!PIO, nqp::unbox_i($chars));
  643. }
  644. method Supply(IO::Handle:D: :$size = $*DEFAULT-READ-ELEMS, :$bin --> Supply:D) {
  645. if $bin {
  646. supply {
  647. my $buf := self.read($size);
  648. nqp::while(
  649. nqp::elems($buf),
  650. nqp::stmts(
  651. (emit $buf),
  652. ($buf := self.read($size))
  653. )
  654. );
  655. done;
  656. }
  657. }
  658. else {
  659. supply {
  660. my int $chars = $size;
  661. my str $str = self.readchars($chars);
  662. nqp::while(
  663. nqp::chars($str),
  664. nqp::stmts(
  665. (emit nqp::p6box_s($str)),
  666. ($str = self.readchars($chars))
  667. )
  668. );
  669. done;
  670. }
  671. }
  672. }
  673. proto method seek(|) { * }
  674. multi method seek(IO::Handle:D: Int:D $offset, SeekType:D $whence = SeekFromBeginning) {
  675. nqp::seekfh($!PIO, $offset, +$whence);
  676. }
  677. method tell(IO::Handle:D: --> Int:D) {
  678. nqp::p6box_i(nqp::tellfh($!PIO));
  679. }
  680. method write(IO::Handle:D: Blob:D $buf --> True) {
  681. nqp::writefh($!PIO, nqp::decont($buf));
  682. }
  683. method opened(IO::Handle:D:) {
  684. nqp::p6bool(nqp::istrue($!PIO));
  685. }
  686. method t(IO::Handle:D:) {
  687. self.opened && nqp::p6bool(nqp::isttyfh($!PIO))
  688. }
  689. method lock(IO::Handle:D: Int:D $flag) {
  690. nqp::lockfh($!PIO, $flag)
  691. }
  692. method unlock(IO::Handle:D: --> True) {
  693. nqp::unlockfh($!PIO);
  694. }
  695. method printf(IO::Handle:D: |c) {
  696. nqp::printfh($!PIO, sprintf |c);
  697. }
  698. proto method print(|) { * }
  699. multi method print(IO::Handle:D: str:D \x --> True) {
  700. nqp::printfh($!PIO,x);
  701. }
  702. multi method print(IO::Handle:D: Str:D \x --> True) {
  703. nqp::printfh($!PIO, nqp::unbox_s(x));
  704. }
  705. multi method print(IO::Handle:D: *@list is raw --> True) { # is raw gives List, which is cheaper
  706. nqp::printfh($!PIO, nqp::unbox_s(.Str)) for @list;
  707. }
  708. proto method put(|) { * }
  709. multi method put(IO::Handle:D: str:D \x --> True) {
  710. nqp::printfh($!PIO,x);
  711. nqp::printfh($!PIO, nqp::unbox_s($!nl-out));
  712. }
  713. multi method put(IO::Handle:D: Str:D \x --> True) {
  714. nqp::printfh($!PIO, nqp::unbox_s(x));
  715. nqp::printfh($!PIO, nqp::unbox_s($!nl-out));
  716. }
  717. multi method put(IO::Handle:D: *@list is raw --> True) { # is raw gives List, which is cheaper
  718. nqp::printfh($!PIO, nqp::unbox_s(.Str)) for @list;
  719. nqp::printfh($!PIO, nqp::unbox_s($!nl-out));
  720. }
  721. multi method say(IO::Handle:D: |) {
  722. my Mu $args := nqp::p6argvmarray();
  723. nqp::shift($args);
  724. self.print: nqp::shift($args).gist while $args;
  725. self.print-nl;
  726. }
  727. method print-nl(IO::Handle:D: --> True) {
  728. nqp::printfh($!PIO, nqp::unbox_s($!nl-out));
  729. }
  730. proto method slurp-rest(|) { * }
  731. multi method slurp-rest(IO::Handle:D: :$bin! where *.so, :$close --> Buf:D) {
  732. LEAVE self.close if $close;
  733. my $res := buf8.new;
  734. loop {
  735. my $buf := nqp::readfh($!PIO,buf8.new,0x100000);
  736. nqp::elems($buf)
  737. ?? $res.append($buf)
  738. !! return $res
  739. }
  740. }
  741. multi method slurp-rest(IO::Handle:D: :$enc, :$bin, :$close --> Str:D) {
  742. LEAVE self.close if $close;
  743. self.encoding($enc) if $enc.defined;
  744. nqp::p6box_s(nqp::readallfh($!PIO));
  745. }
  746. method chmod(IO::Handle:D: Int $mode) { $!path.chmod($mode) }
  747. method IO(IO::Handle:D: |c) { $!path.IO(|c) }
  748. method path(IO::Handle:D:) { $!path.IO }
  749. multi method Str(IO::Handle:D:) { $!path }
  750. multi method gist(IO::Handle:D:) {
  751. self.opened
  752. ?? self.^name ~ "<$!path.gist()>(opened, at octet {$.tell})"
  753. !! self.^name ~ "<$!path.gist()>(closed)"
  754. }
  755. multi method perl(IO::Handle:D:) {
  756. self.^name ~ ".new({:$!path.perl},{$!chomp ?? :$!chomp.perl !! ''})"
  757. }
  758. method flush(IO::Handle:D: --> True) {
  759. fail("File handle not open, so cannot flush")
  760. unless nqp::defined($!PIO);
  761. nqp::flushfh($!PIO);
  762. }
  763. proto method encoding(|) { * }
  764. multi method encoding(IO::Handle:D:) { $!encoding }
  765. multi method encoding(IO::Handle:D: $enc) {
  766. $enc eq 'bin'
  767. ?? ($!encoding = 'bin')
  768. !! nqp::setencoding($!PIO,
  769. $!encoding = Rakudo::Internals.NORMALIZE_ENCODING($enc))
  770. }
  771. submethod DESTROY(IO::Handle:D:) {
  772. self.close;
  773. }
  774. # setting cannot do "handles", so it's done by hand here
  775. method e(IO::Handle:D:) { $!path.e }
  776. method d(IO::Handle:D:) { $!path.d }
  777. method f(IO::Handle:D:) { $!path.f }
  778. method s(IO::Handle:D:) { $!path.s }
  779. method l(IO::Handle:D:) { $!path.l }
  780. method r(IO::Handle:D:) { $!path.r }
  781. method w(IO::Handle:D:) { $!path.w }
  782. method x(IO::Handle:D:) { $!path.x }
  783. method modified(IO::Handle:D:) { $!path.modified }
  784. method accessed(IO::Handle:D:) { $!path.accessed }
  785. method changed(IO::Handle:D:) { $!path.changed }
  786. method mode(IO::Handle:D:) { $!path.mode }
  787. method watch(IO::Handle:D:) {
  788. IO::Notification.watch-path($!path);
  789. }
  790. method native-descriptor(IO::Handle:D:) {
  791. nqp::filenofh($!PIO)
  792. }
  793. }
  794. Rakudo::Internals.REGISTER-DYNAMIC: '$*DEFAULT-READ-ELEMS', {
  795. PROCESS::<$DEFAULT-READ-ELEMS> := %*ENV<RAKUDO_DEFAULT_READ_ELEMS> // 65536;
  796. }