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