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